From 48be65825870651758586223d3fc260d125168cb Mon Sep 17 00:00:00 2001 From: Niraj Kamdar Date: Sat, 3 Jun 2023 14:10:26 +0530 Subject: [PATCH 01/47] refactor: polywrap-msgpack package --- packages/polywrap-msgpack/polywrap_msgpack/__init__.py | 7 ++++++- packages/polywrap-msgpack/polywrap_msgpack/decoder.py | 4 ++-- packages/polywrap-msgpack/polywrap_msgpack/encoder.py | 8 ++++++-- packages/polywrap-msgpack/polywrap_msgpack/sanitize.py | 2 +- 4 files changed, 15 insertions(+), 6 deletions(-) diff --git a/packages/polywrap-msgpack/polywrap_msgpack/__init__.py b/packages/polywrap-msgpack/polywrap_msgpack/__init__.py index fbf10d10..096032d9 100644 --- a/packages/polywrap-msgpack/polywrap_msgpack/__init__.py +++ b/packages/polywrap-msgpack/polywrap_msgpack/__init__.py @@ -14,13 +14,18 @@ from .sanitize import * __all__ = [ + # Serializer "msgpack_decode", "msgpack_encode", + # Extensions "decode_ext_hook", "encode_ext_hook", - "sanitize", "ExtensionTypes", + # Sanitizers + "sanitize", + # Extention types "GenericMap", + # Errors "MsgpackError", "MsgpackDecodeError", "MsgpackEncodeError", diff --git a/packages/polywrap-msgpack/polywrap_msgpack/decoder.py b/packages/polywrap-msgpack/polywrap_msgpack/decoder.py index 9d78a9d7..a768be9b 100644 --- a/packages/polywrap-msgpack/polywrap_msgpack/decoder.py +++ b/packages/polywrap-msgpack/polywrap_msgpack/decoder.py @@ -43,8 +43,8 @@ def msgpack_decode(val: bytes) -> Any: Any: any python object """ try: - return msgpack.unpackb( + return msgpack.unpackb( # pyright: ignore[reportUnknownMemberType] val, ext_hook=decode_ext_hook - ) # pyright: reportUnknownMemberType=false + ) except Exception as e: raise MsgpackDecodeError("Failed to decode msgpack data") from e diff --git a/packages/polywrap-msgpack/polywrap_msgpack/encoder.py b/packages/polywrap-msgpack/polywrap_msgpack/encoder.py index a74642b1..71ea9c16 100644 --- a/packages/polywrap-msgpack/polywrap_msgpack/encoder.py +++ b/packages/polywrap-msgpack/polywrap_msgpack/encoder.py @@ -28,8 +28,12 @@ def encode_ext_hook(obj: Any) -> ExtType: return ExtType( ExtensionTypes.GENERIC_MAP.value, # pylint: disable=protected-access - msgpack_encode(cast(GenericMap[Any, Any], obj)._map), - ) # pyright: reportPrivateUsage=false + msgpack_encode( + cast( + GenericMap[Any, Any], obj + )._map # pyright: ignore[reportPrivateUsage] + ), + ) raise MsgpackExtError(f"Object of type {type(obj)} is not supported") diff --git a/packages/polywrap-msgpack/polywrap_msgpack/sanitize.py b/packages/polywrap-msgpack/polywrap_msgpack/sanitize.py index e2982e36..93d8ba1b 100644 --- a/packages/polywrap-msgpack/polywrap_msgpack/sanitize.py +++ b/packages/polywrap-msgpack/polywrap_msgpack/sanitize.py @@ -22,7 +22,7 @@ def sanitize(value: Any) -> Any: if isinstance(value, GenericMap): dictionary: Dict[Any, Any] = cast( GenericMap[Any, Any], value - )._map # pyright: reportPrivateUsage=false + )._map # pyright: ignore[reportPrivateUsage] new_map: GenericMap[str, Any] = GenericMap({}) for key, val in dictionary.items(): if not isinstance(key, str): From a83969a8fa2632a502bbf5e9c6aa842963767050 Mon Sep 17 00:00:00 2001 From: Niraj Kamdar Date: Sat, 3 Jun 2023 14:12:44 +0530 Subject: [PATCH 02/47] refactor: polywrap-manifest package --- .../polywrap_manifest/deserialize.py | 3 ++ .../polywrap_manifest/errors.py | 3 ++ .../polywrap_manifest/manifest.py | 32 ++++++++++++------- 3 files changed, 27 insertions(+), 11 deletions(-) diff --git a/packages/polywrap-manifest/polywrap_manifest/deserialize.py b/packages/polywrap-manifest/polywrap_manifest/deserialize.py index 1f2f169e..d8996505 100644 --- a/packages/polywrap-manifest/polywrap_manifest/deserialize.py +++ b/packages/polywrap-manifest/polywrap_manifest/deserialize.py @@ -53,3 +53,6 @@ def deserialize_wrap_manifest( raise NotImplementedError( f"Version {manifest_version.value} is not implemented" ) + + +__all__ = ["deserialize_wrap_manifest"] diff --git a/packages/polywrap-manifest/polywrap_manifest/errors.py b/packages/polywrap-manifest/polywrap_manifest/errors.py index 0bdbff49..19015dde 100644 --- a/packages/polywrap-manifest/polywrap_manifest/errors.py +++ b/packages/polywrap-manifest/polywrap_manifest/errors.py @@ -7,3 +7,6 @@ class ManifestError(Exception): class DeserializeManifestError(ManifestError): """Raised when a manifest cannot be deserialized.""" + + +__all__ = ["ManifestError", "DeserializeManifestError"] diff --git a/packages/polywrap-manifest/polywrap_manifest/manifest.py b/packages/polywrap-manifest/polywrap_manifest/manifest.py index 29268c31..d0be947c 100644 --- a/packages/polywrap-manifest/polywrap_manifest/manifest.py +++ b/packages/polywrap-manifest/polywrap_manifest/manifest.py @@ -22,17 +22,6 @@ class DeserializeManifestOptions: no_validate: Optional[bool] = None -@dataclass(slots=True, kw_only=True) -class SerializeManifestOptions: - """Options for serializing a manifest to msgpack encoded bytes. - - Attributes: - no_validate: If true, do not validate the manifest. - """ - - no_validate: Optional[bool] = None - - class WrapManifestVersions(Enum): """The versions of the Wrap manifest.""" @@ -68,3 +57,24 @@ class WrapAbiVersions(Enum): LATEST_WRAP_MANIFEST_VERSION = "0.1" LATEST_WRAP_ABI_VERSION = "0.1" + +__all__ = [ + # Options + "DeserializeManifestOptions", + # Enums + "WrapManifestVersions", + "WrapManifestAbiVersions", + "WrapAbiVersions", + # Concrete Versions + "WrapManifest_0_1", + "WrapAbi_0_1_0_1", + # Any Versions + "AnyWrapManifest", + "AnyWrapAbi", + # Latest Versions + "WrapManifest", + "WrapAbi", + # Latest Version constants + "LATEST_WRAP_MANIFEST_VERSION", + "LATEST_WRAP_ABI_VERSION", +] From f8d7853ef52ff1f2e44abf7ff5c601e133ef8ed5 Mon Sep 17 00:00:00 2001 From: Niraj Kamdar Date: Sat, 3 Jun 2023 15:18:49 +0530 Subject: [PATCH 03/47] refactor: polywrap-core package --- packages/polywrap-core/poetry.lock | 98 +++++-------------- .../polywrap_core/types/__init__.py | 4 - .../polywrap_core/types/client.py | 47 ++++----- .../polywrap_core/types/config.py | 10 +- .../polywrap-core/polywrap_core/types/env.py | 4 - .../polywrap_core/types/errors.py | 80 ++++++++++++--- .../polywrap_core/types/file_reader.py | 11 ++- .../polywrap_core/types/invocable.py | 45 ++++++--- .../polywrap_core/types/invoke_args.py | 4 - .../polywrap_core/types/invoke_options.py | 34 +++++++ .../polywrap_core/types/invoker.py | 55 ++++++----- .../polywrap_core/types/invoker_client.py | 10 +- .../polywrap_core/types/options/__init__.py | 5 - .../types/options/file_options.py | 18 ---- .../types/options/invoke_options.py | 32 ------ .../types/options/manifest_options.py | 11 --- .../types/options/uri_resolver_options.py | 24 ----- .../polywrap-core/polywrap_core/types/uri.py | 33 ++++++- .../polywrap_core/types/uri_like.py | 64 ------------ .../polywrap_core/types/uri_package.py | 30 ++---- .../types/uri_package_wrapper.py | 6 +- .../types/uri_resolution_context.py | 90 +++++++++++------ .../types/uri_resolution_step.py | 23 ++--- .../polywrap_core/types/uri_resolver.py | 17 ++-- .../types/uri_resolver_handler.py | 28 +++--- .../polywrap_core/types/uri_wrapper.py | 26 ++--- .../polywrap_core/types/wrap_package.py | 26 ++--- .../polywrap_core/types/wrapper.py | 39 +++----- .../polywrap_core/utils/__init__.py | 7 +- .../utils/build_clean_uri_history.py | 73 ++++++++++++++ .../utils/get_env_from_resolution_path.py | 22 +++++ .../utils/get_implementations.py | 49 ++++++++++ .../polywrap_core/utils/instance_of.py | 16 --- .../polywrap_core/utils/maybe_async.py | 18 ---- packages/polywrap-core/pyproject.toml | 14 +-- .../tests/test_build_clean_uri_history.py | 46 +++++++++ .../tests/test_env_from_resolution_path.py | 40 ++++++++ .../tests/test_get_implementations.py | 79 +++++++++++++++ .../polywrap-core/tests/test_maybe_async.py | 27 ----- 39 files changed, 714 insertions(+), 551 deletions(-) delete mode 100644 packages/polywrap-core/polywrap_core/types/env.py delete mode 100644 packages/polywrap-core/polywrap_core/types/invoke_args.py create mode 100644 packages/polywrap-core/polywrap_core/types/invoke_options.py delete mode 100644 packages/polywrap-core/polywrap_core/types/options/__init__.py delete mode 100644 packages/polywrap-core/polywrap_core/types/options/file_options.py delete mode 100644 packages/polywrap-core/polywrap_core/types/options/invoke_options.py delete mode 100644 packages/polywrap-core/polywrap_core/types/options/manifest_options.py delete mode 100644 packages/polywrap-core/polywrap_core/types/options/uri_resolver_options.py delete mode 100644 packages/polywrap-core/polywrap_core/types/uri_like.py create mode 100644 packages/polywrap-core/polywrap_core/utils/build_clean_uri_history.py create mode 100644 packages/polywrap-core/polywrap_core/utils/get_env_from_resolution_path.py create mode 100644 packages/polywrap-core/polywrap_core/utils/get_implementations.py delete mode 100644 packages/polywrap-core/polywrap_core/utils/instance_of.py delete mode 100644 packages/polywrap-core/polywrap_core/utils/maybe_async.py create mode 100644 packages/polywrap-core/tests/test_build_clean_uri_history.py create mode 100644 packages/polywrap-core/tests/test_env_from_resolution_path.py create mode 100644 packages/polywrap-core/tests/test_get_implementations.py delete mode 100644 packages/polywrap-core/tests/test_maybe_async.py diff --git a/packages/polywrap-core/poetry.lock b/packages/polywrap-core/poetry.lock index 97622e7a..80d92f84 100644 --- a/packages/polywrap-core/poetry.lock +++ b/packages/polywrap-core/poetry.lock @@ -1,15 +1,15 @@ -# This file is automatically @generated by Poetry 1.4.2 and should not be changed by hand. +# This file is automatically @generated by Poetry and should not be changed by hand. [[package]] name = "astroid" -version = "2.15.4" +version = "2.15.5" description = "An abstract syntax tree for Python with inference support." category = "dev" optional = false python-versions = ">=3.7.2" files = [ - {file = "astroid-2.15.4-py3-none-any.whl", hash = "sha256:a1b8543ef9d36ea777194bc9b17f5f8678d2c56ee6a45b2c2f17eec96f242347"}, - {file = "astroid-2.15.4.tar.gz", hash = "sha256:c81e1c7fbac615037744d067a9bb5f9aeb655edf59b63ee8b59585475d6f80d8"}, + {file = "astroid-2.15.5-py3-none-any.whl", hash = "sha256:078e5212f9885fa85fbb0cf0101978a336190aadea6e13305409d099f71b2324"}, + {file = "astroid-2.15.5.tar.gz", hash = "sha256:1039262575027b441137ab4a62a793a9b43defb42c32d5670f38686207cd780f"}, ] [package.dependencies] @@ -455,14 +455,14 @@ files = [ [[package]] name = "nodeenv" -version = "1.7.0" +version = "1.8.0" description = "Node.js virtual environment builder" category = "dev" optional = false python-versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*" files = [ - {file = "nodeenv-1.7.0-py2.py3-none-any.whl", hash = "sha256:27083a7b96a25f2f5e1d8cb4b6317ee8aeda3bdd121394e5ac54e498028a042e"}, - {file = "nodeenv-1.7.0.tar.gz", hash = "sha256:e0e7f7dfb85fc5394c6fe1e8fa98131a2473e04311a45afb6508f7cf1836fa2b"}, + {file = "nodeenv-1.8.0-py2.py3-none-any.whl", hash = "sha256:df865724bb3c3adc86b3876fa209771517b0cfe596beff01a92700e0e8be4cec"}, + {file = "nodeenv-1.8.0.tar.gz", hash = "sha256:d51e0c37e64fbf47d017feac3145cdbb58836d7eee8c6f6d3b6880c5456227d2"}, ] [package.dependencies] @@ -506,18 +506,18 @@ files = [ [[package]] name = "platformdirs" -version = "3.5.0" +version = "3.5.1" description = "A small Python package for determining appropriate platform-specific dirs, e.g. a \"user data dir\"." category = "dev" optional = false python-versions = ">=3.7" files = [ - {file = "platformdirs-3.5.0-py3-none-any.whl", hash = "sha256:47692bc24c1958e8b0f13dd727307cff1db103fca36399f457da8e05f222fdc4"}, - {file = "platformdirs-3.5.0.tar.gz", hash = "sha256:7954a68d0ba23558d753f73437c55f89027cf8f5108c19844d4b82e5af396335"}, + {file = "platformdirs-3.5.1-py3-none-any.whl", hash = "sha256:e2378146f1964972c03c085bb5662ae80b2b8c06226c54b2ff4aa9483e8a13a5"}, + {file = "platformdirs-3.5.1.tar.gz", hash = "sha256:412dae91f52a6f84830f39a8078cecd0e866cb72294a5c66808e74d5e88d251f"}, ] [package.extras] -docs = ["furo (>=2023.3.27)", "proselint (>=0.13)", "sphinx (>=6.1.3)", "sphinx-autodoc-typehints (>=1.23,!=1.23.4)"] +docs = ["furo (>=2023.3.27)", "proselint (>=0.13)", "sphinx (>=6.2.1)", "sphinx-autodoc-typehints (>=1.23,!=1.23.4)"] test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=7.3.1)", "pytest-cov (>=4)", "pytest-mock (>=3.10)"] [[package]] @@ -655,21 +655,6 @@ typing-extensions = ">=4.2.0" dotenv = ["python-dotenv (>=0.10.4)"] email = ["email-validator (>=1.0.3)"] -[[package]] -name = "pydeps" -version = "1.12.3" -description = "Display module dependencies" -category = "dev" -optional = false -python-versions = "*" -files = [ - {file = "pydeps-1.12.3-py3-none-any.whl", hash = "sha256:d828ab178244f147119a4aa3757a0ffa062e2069b1ac3c244f3013bfdfe0aa5e"}, - {file = "pydeps-1.12.3.tar.gz", hash = "sha256:3f14f2d5ef04df050317a6ed4747e7fefd14399f9decfe5114271541b1b8ffe7"}, -] - -[package.dependencies] -stdlib-list = "*" - [[package]] name = "pydocstyle" version = "6.3.0" @@ -734,14 +719,14 @@ testutils = ["gitpython (>3)"] [[package]] name = "pyright" -version = "1.1.306" +version = "1.1.309" description = "Command line wrapper for pyright" category = "dev" optional = false python-versions = ">=3.7" files = [ - {file = "pyright-1.1.306-py3-none-any.whl", hash = "sha256:008eb2a29584ae274a154d749cf81476a3073fb562a462eac8d43a753378b9db"}, - {file = "pyright-1.1.306.tar.gz", hash = "sha256:16d5d198be64de497d5f9002000a271176c381e21b977ca5566cf779b643c9ed"}, + {file = "pyright-1.1.309-py3-none-any.whl", hash = "sha256:a8b052c1997f7334e80074998ea0f93bd149550e8cf27ccb5481d3b2e1aad161"}, + {file = "pyright-1.1.309.tar.gz", hash = "sha256:1abcfa83814d792a5d70b38621cc6489acfade94ebb2279e55ba1f394d54296c"}, ] [package.dependencies] @@ -774,24 +759,6 @@ tomli = {version = ">=1.0.0", markers = "python_version < \"3.11\""} [package.extras] testing = ["argcomplete", "attrs (>=19.2.0)", "hypothesis (>=3.56)", "mock", "nose", "pygments (>=2.7.2)", "requests", "xmlschema"] -[[package]] -name = "pytest-asyncio" -version = "0.19.0" -description = "Pytest support for asyncio" -category = "dev" -optional = false -python-versions = ">=3.7" -files = [ - {file = "pytest-asyncio-0.19.0.tar.gz", hash = "sha256:ac4ebf3b6207259750bc32f4c1d8fcd7e79739edbc67ad0c58dd150b1d072fed"}, - {file = "pytest_asyncio-0.19.0-py3-none-any.whl", hash = "sha256:7a97e37cfe1ed296e2e84941384bdd37c376453912d397ed39293e0916f521fa"}, -] - -[package.dependencies] -pytest = ">=6.1.0" - -[package.extras] -testing = ["coverage (>=6.2)", "flaky (>=3.5.0)", "hypothesis (>=5.7.1)", "mypy (>=0.931)", "pytest-trio (>=0.7.0)"] - [[package]] name = "pyyaml" version = "6.0" @@ -863,19 +830,19 @@ jupyter = ["ipywidgets (>=7.5.1,<9)"] [[package]] name = "setuptools" -version = "67.7.2" +version = "67.8.0" description = "Easily download, build, install, upgrade, and uninstall Python packages" category = "dev" optional = false python-versions = ">=3.7" files = [ - {file = "setuptools-67.7.2-py3-none-any.whl", hash = "sha256:23aaf86b85ca52ceb801d32703f12d77517b2556af839621c641fca11287952b"}, - {file = "setuptools-67.7.2.tar.gz", hash = "sha256:f104fa03692a2602fa0fec6c6a9e63b6c8a968de13e17c026957dd1f53d80990"}, + {file = "setuptools-67.8.0-py3-none-any.whl", hash = "sha256:5df61bf30bb10c6f756eb19e7c9f3b473051f48db77fddbe06ff2ca307df9a6f"}, + {file = "setuptools-67.8.0.tar.gz", hash = "sha256:62642358adc77ffa87233bc4d2354c4b2682d214048f500964dbe760ccedf102"}, ] [package.extras] docs = ["furo", "jaraco.packaging (>=9)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-favicon", "sphinx-hoverxref (<2)", "sphinx-inline-tabs", "sphinx-lint", "sphinx-notfound-page (==0.8.3)", "sphinx-reredirects", "sphinxcontrib-towncrier"] -testing = ["build[virtualenv]", "filelock (>=3.4.0)", "flake8 (<5)", "flake8-2020", "ini2toml[lite] (>=0.9)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "pip (>=19.1)", "pip-run (>=8.8)", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=1.3)", "pytest-flake8", "pytest-mypy (>=0.9.1)", "pytest-perf", "pytest-timeout", "pytest-xdist", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel"] +testing = ["build[virtualenv]", "filelock (>=3.4.0)", "flake8-2020", "ini2toml[lite] (>=0.9)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "pip (>=19.1)", "pip-run (>=8.8)", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=1.3)", "pytest-mypy (>=0.9.1)", "pytest-perf", "pytest-ruff", "pytest-timeout", "pytest-xdist", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel"] testing-integration = ["build[virtualenv]", "filelock (>=3.4.0)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "pytest", "pytest-enabler", "pytest-xdist", "tomli", "virtualenv (>=13.0.0)", "wheel"] [[package]] @@ -914,31 +881,16 @@ files = [ {file = "snowballstemmer-2.2.0.tar.gz", hash = "sha256:09b16deb8547d3412ad7b590689584cd0fe25ec8db3be37788be3810cbf19cb1"}, ] -[[package]] -name = "stdlib-list" -version = "0.8.0" -description = "A list of Python Standard Libraries (2.6-7, 3.2-9)." -category = "dev" -optional = false -python-versions = "*" -files = [ - {file = "stdlib-list-0.8.0.tar.gz", hash = "sha256:a1e503719720d71e2ed70ed809b385c60cd3fb555ba7ec046b96360d30b16d9f"}, - {file = "stdlib_list-0.8.0-py3-none-any.whl", hash = "sha256:2ae0712a55b68f3fbbc9e58d6fa1b646a062188f49745b495f94d3310a9fdd3e"}, -] - -[package.extras] -develop = ["sphinx"] - [[package]] name = "stevedore" -version = "5.0.0" +version = "5.1.0" description = "Manage dynamic plugins for Python applications" category = "dev" optional = false python-versions = ">=3.8" files = [ - {file = "stevedore-5.0.0-py3-none-any.whl", hash = "sha256:bd5a71ff5e5e5f5ea983880e4a1dd1bb47f8feebbb3d95b592398e2f02194771"}, - {file = "stevedore-5.0.0.tar.gz", hash = "sha256:2c428d2338976279e8eb2196f7a94910960d9f7ba2f41f3988511e95ca447021"}, + {file = "stevedore-5.1.0-py3-none-any.whl", hash = "sha256:8cc040628f3cea5d7128f2e76cf486b2251a4e543c7b938f58d9a377f6694a2d"}, + {file = "stevedore-5.1.0.tar.gz", hash = "sha256:a54534acf9b89bc7ed264807013b505bf07f74dbe4bcfa37d32bd063870b087c"}, ] [package.dependencies] @@ -1049,14 +1001,14 @@ test = ["black (>=22.3.0,<23.0.0)", "coverage (>=6.2,<7.0)", "isort (>=5.0.6,<6. [[package]] name = "typing-extensions" -version = "4.5.0" +version = "4.6.0" description = "Backported and Experimental Type Hints for Python 3.7+" category = "main" optional = false python-versions = ">=3.7" files = [ - {file = "typing_extensions-4.5.0-py3-none-any.whl", hash = "sha256:fb33085c39dd998ac16d1431ebc293a8b3eedd00fd4a32de0ff79002c19511b4"}, - {file = "typing_extensions-4.5.0.tar.gz", hash = "sha256:5cb5f4a79139d699607b3ef622a1dedafa84e115ab0024e0d9c044a9479ca7cb"}, + {file = "typing_extensions-4.6.0-py3-none-any.whl", hash = "sha256:6ad00b63f849b7dcc313b70b6b304ed67b2b2963b3098a33efe18056b1a9a223"}, + {file = "typing_extensions-4.6.0.tar.gz", hash = "sha256:ff6b238610c747e44c268aa4bb23c8c735d665a63726df3f9431ce707f2aa768"}, ] [[package]] @@ -1184,4 +1136,4 @@ files = [ [metadata] lock-version = "2.0" python-versions = "^3.10" -content-hash = "60e51d986fcb9814b054fb0b6c5a6eea0c84829dc8db4e5cf3c592ade9f5353c" +content-hash = "bd0557df35270b1dcdb727e3505fbd3bdd1afaed488458de3346783456248e00" diff --git a/packages/polywrap-core/polywrap_core/types/__init__.py b/packages/polywrap-core/polywrap_core/types/__init__.py index 219b5d5f..1ce2c342 100644 --- a/packages/polywrap-core/polywrap_core/types/__init__.py +++ b/packages/polywrap-core/polywrap_core/types/__init__.py @@ -1,16 +1,12 @@ """This module contains all the core types used in the various polywrap packages.""" from .client import * from .config import * -from .env import * from .errors import * from .file_reader import * from .invocable import * -from .invoke_args import * from .invoker import * from .invoker_client import * -from .options import * from .uri import * -from .uri_like import * from .uri_package import * from .uri_package_wrapper import * from .uri_resolution_context import * diff --git a/packages/polywrap-core/polywrap_core/types/client.py b/packages/polywrap-core/polywrap_core/types/client.py index b73fa72c..eecdfda9 100644 --- a/packages/polywrap-core/polywrap_core/types/client.py +++ b/packages/polywrap-core/polywrap_core/types/client.py @@ -1,25 +1,19 @@ """This module contains the Client interface.""" from __future__ import annotations -from abc import abstractmethod -from typing import Dict, List, Optional, Union +from typing import Any, Dict, List, Optional, Protocol, Union -from polywrap_manifest import AnyWrapManifest +from polywrap_manifest import AnyWrapManifest, DeserializeManifestOptions -from .env import Env from .invoker_client import InvokerClient -from .options.file_options import GetFileOptions -from .options.manifest_options import GetManifestOptions from .uri import Uri -from .uri_package_wrapper import UriPackageOrWrapper from .uri_resolver import UriResolver -class Client(InvokerClient[UriPackageOrWrapper]): +class Client(InvokerClient, Protocol): """Client interface defines core set of functionalities\ for interacting with a wrapper.""" - @abstractmethod def get_interfaces(self) -> Dict[Uri, List[Uri]]: """Get dictionary of interfaces and their implementations. @@ -27,57 +21,64 @@ def get_interfaces(self) -> Dict[Uri, List[Uri]]: Dict[Uri, List[Uri]]: Dictionary of interfaces and their implementations where\ key is interface URI and value is list of implementation uris. """ + ... - @abstractmethod - def get_envs(self) -> Dict[Uri, Env]: + def get_envs(self) -> Dict[Uri, Any]: """Get dictionary of environments. Returns: - Dict[Uri, Env]: Dictionary of environments where key is URI and value is env. + Dict[Uri, Any]: Dictionary of environments where key is URI and value is env. """ + ... - @abstractmethod - def get_env_by_uri(self, uri: Uri) -> Union[Env, None]: + def get_env_by_uri(self, uri: Uri) -> Union[Any, None]: """Get environment by URI. Args: uri (Uri): URI of the Wrapper. Returns: - Union[Env, None]: env if found, otherwise None. + Union[Any, None]: env if found, otherwise None. """ + ... - @abstractmethod def get_uri_resolver(self) -> UriResolver: """Get URI resolver. Returns: IUriResolver: URI resolver. """ + ... - @abstractmethod - async def get_file(self, uri: Uri, options: GetFileOptions) -> Union[bytes, str]: + def get_file( + self, uri: Uri, path: str, encoding: Optional[str] = "utf-8" + ) -> Union[bytes, str]: """Get file from URI. Args: uri (Uri): URI of the wrapper. - options (GetFileOptions): Options for getting file from the wrapper. + path (str): Path to the file. + encoding (Optional[str]): Encoding of the file. Returns: Union[bytes, str]]: file contents. """ + ... - @abstractmethod - async def get_manifest( - self, uri: Uri, options: Optional[GetManifestOptions] = None + def get_manifest( + self, uri: Uri, options: Optional[DeserializeManifestOptions] = None ) -> AnyWrapManifest: """Get manifest from URI. Args: uri (Uri): URI of the wrapper. - options (Optional[GetManifestOptions]): \ + options (Optional[DeserializeManifestOptions]): \ Options for getting manifest from the wrapper. Returns: AnyWrapManifest: Manifest of the wrapper. """ + ... + + +__all__ = ["Client"] diff --git a/packages/polywrap-core/polywrap_core/types/config.py b/packages/polywrap-core/polywrap_core/types/config.py index 97afe12c..4b124877 100644 --- a/packages/polywrap-core/polywrap_core/types/config.py +++ b/packages/polywrap-core/polywrap_core/types/config.py @@ -2,9 +2,8 @@ from __future__ import annotations from dataclasses import dataclass, field -from typing import Dict, List +from typing import Any, Dict, List -from .env import Env from .uri import Uri from .uri_resolver import UriResolver @@ -14,7 +13,7 @@ class ClientConfig: """Client configuration. Attributes: - envs (Dict[Uri, Env]): Dictionary of environments \ + envs (Dict[Uri, Any]): Dictionary of environments \ where key is URI and value is env. interfaces (Dict[Uri, List[Uri]]): Dictionary of interfaces \ and their implementations where key is interface URI \ @@ -22,6 +21,9 @@ class ClientConfig: resolver (UriResolver): URI resolver. """ - envs: Dict[Uri, Env] = field(default_factory=dict) + envs: Dict[Uri, Any] = field(default_factory=dict) interfaces: Dict[Uri, List[Uri]] = field(default_factory=dict) resolver: UriResolver + + +__all__ = ["ClientConfig"] diff --git a/packages/polywrap-core/polywrap_core/types/env.py b/packages/polywrap-core/polywrap_core/types/env.py deleted file mode 100644 index 7949d5eb..00000000 --- a/packages/polywrap-core/polywrap_core/types/env.py +++ /dev/null @@ -1,4 +0,0 @@ -"""This module defines Env type.""" -from typing import Any, Dict - -Env = Dict[str, Any] diff --git a/packages/polywrap-core/polywrap_core/types/errors.py b/packages/polywrap-core/polywrap_core/types/errors.py index f445b191..e89e9ea0 100644 --- a/packages/polywrap-core/polywrap_core/types/errors.py +++ b/packages/polywrap-core/polywrap_core/types/errors.py @@ -1,22 +1,31 @@ """This module contains the core wrap errors.""" +# pylint: disable=too-many-arguments + +from __future__ import annotations import json from textwrap import dedent -from typing import Generic, TypeVar +from typing import Any, Optional, cast + +from polywrap_msgpack import GenericMap, msgpack_decode -from polywrap_msgpack import msgpack_decode +from .invoke_options import InvokeOptions +from .uri import Uri -from .options.invoke_options import InvokeOptions -from .uri_like import UriLike -TUriLike = TypeVar("TUriLike", bound=UriLike) +def _default_encoder(obj: Any) -> Any: + if isinstance(obj, bytes): + return list(obj) + if isinstance(obj, (Uri, GenericMap)): + return repr(cast(Any, obj)) + raise TypeError(f"Object of type '{type(obj).__name__}' is not JSON serializable") class WrapError(Exception): """Base class for all exceptions related to wrappers.""" -class WrapAbortError(Generic[TUriLike], WrapError): +class WrapAbortError(WrapError): """Raises when a wrapper aborts execution. Attributes: @@ -25,35 +34,40 @@ class WrapAbortError(Generic[TUriLike], WrapError): message: The message provided by the wrapper. """ - invoke_options: InvokeOptions[TUriLike] + uri: Uri + method: str message: str + invoke_args: Optional[str] = None + invoke_env: Optional[str] = None - # pylint: disable=too-many-arguments def __init__( self, - invoke_options: InvokeOptions[TUriLike], + invoke_options: InvokeOptions, message: str, ): """Initialize a new instance of WasmAbortError.""" - self.invoke_options = invoke_options + self.uri = invoke_options.uri + self.method = invoke_options.method self.message = message - invoke_args = ( + self.invoke_args = ( json.dumps( msgpack_decode(invoke_options.args) if isinstance(invoke_options.args, bytes) else invoke_options.args, indent=2, + default=_default_encoder, ) if invoke_options.args is not None else None ) - invoke_env = ( + self.invoke_env = ( json.dumps( msgpack_decode(invoke_options.env) if isinstance(invoke_options.env, bytes) else invoke_options.env, indent=2, + default=_default_encoder, ) if invoke_options.env is not None else None @@ -65,15 +79,15 @@ def __init__( WrapAbortError: The following wrapper aborted execution with the given message: URI: {invoke_options.uri} Method: {invoke_options.method} - Args: {invoke_args} - env: {invoke_env} + Args: {self.invoke_args} + env: {self.invoke_env} Message: {message} """ ) ) -class WrapInvocationError(WrapAbortError[TUriLike]): +class WrapInvocationError(WrapAbortError): """Raises when there is an error invoking a wrapper. Attributes: @@ -81,3 +95,39 @@ class WrapInvocationError(WrapAbortError[TUriLike]): that was aborted. message: The message provided by the wrapper. """ + + +class WrapGetImplementationsError(WrapError): + """Raises when there is an error getting implementations of an interface. + + Attributes: + uri (Uri): URI of the interface. + message: The message provided by the wrapper. + """ + + uri: Uri + message: str + + def __init__(self, uri: Uri, message: str): + """Initialize a new instance of WrapGetImplementationsError.""" + self.uri = uri + self.message = message + + super().__init__( + dedent( + f""" + WrapGetImplementationsError: Failed to get implementations of \ + the following interface URI with the given message: + URI: {uri} + Message: {message} + """ + ) + ) + + +__all__ = [ + "WrapError", + "WrapAbortError", + "WrapInvocationError", + "WrapGetImplementationsError", +] diff --git a/packages/polywrap-core/polywrap_core/types/file_reader.py b/packages/polywrap-core/polywrap_core/types/file_reader.py index 6067d0cf..848c69fd 100644 --- a/packages/polywrap-core/polywrap_core/types/file_reader.py +++ b/packages/polywrap-core/polywrap_core/types/file_reader.py @@ -1,14 +1,13 @@ """This module contains file reader interface.""" from __future__ import annotations -from abc import ABC, abstractmethod +from typing import Protocol -class FileReader(ABC): +class FileReader(Protocol): """File reader interface.""" - @abstractmethod - async def read_file(self, file_path: str) -> bytes: + def read_file(self, file_path: str) -> bytes: """Read a file from the given file path. Args: @@ -20,3 +19,7 @@ async def read_file(self, file_path: str) -> bytes: Returns: bytes: The file contents. """ + ... + + +__all__ = ["FileReader"] diff --git a/packages/polywrap-core/polywrap_core/types/invocable.py b/packages/polywrap-core/polywrap_core/types/invocable.py index 12c3d44f..847cfdae 100644 --- a/packages/polywrap-core/polywrap_core/types/invocable.py +++ b/packages/polywrap-core/polywrap_core/types/invocable.py @@ -1,15 +1,14 @@ """This module contains the interface for invoking any invocables.""" +# pylint: disable=too-many-arguments + from __future__ import annotations -from abc import ABC, abstractmethod from dataclasses import dataclass -from typing import Any, Generic, Optional, TypeVar - -from .invoker import Invoker -from .options.invoke_options import InvokeOptions -from .uri_like import UriLike +from typing import Any, Optional, Protocol -TUriLike = TypeVar("TUriLike", bound=UriLike) +from .invoker_client import InvokerClient +from .uri import Uri +from .uri_resolution_context import UriResolutionContext @dataclass(slots=True, kw_only=True) @@ -17,29 +16,43 @@ class InvocableResult: """Result of a wrapper invocation. Args: - result (Optional[Any]): Invocation result. The type of this value is \ + result (Any): Invocation result. The type of this value is \ the return type of the method. encoded (Optional[bool]): It will be set true if result is encoded """ - result: Optional[Any] = None + result: Any encoded: Optional[bool] = None -class Invocable(ABC, Generic[TUriLike]): +class Invocable(Protocol): """Invocable interface.""" - @abstractmethod - async def invoke( - self, options: InvokeOptions[TUriLike], invoker: Invoker[TUriLike] + def invoke( + self, + uri: Uri, + method: str, + args: Optional[Any] = None, + env: Optional[Any] = None, + resolution_context: Optional[UriResolutionContext] = None, + client: Optional[InvokerClient] = None, ) -> InvocableResult: """Invoke the Wrapper based on the provided InvokeOptions. Args: - options (InvokeOptions): InvokeOptions for this invocation. - invoker (Invoker): The invoker instance requesting this invocation.\ - This invoker will be used for any subinvocation that may occur. + uri (Uri): Uri of the wrapper + method (str): Method to be executed + args (Optional[Any]) : Arguments for the method, structured as a dictionary + env (Optional[Any]): Override the client's config for all invokes within this invoke. + resolution_context (Optional[UriResolutionContext]): A URI resolution context + client (Optional[InvokerClient]): The invoker client instance requesting\ + this invocation. This invoker client will be used for any subinvocation\ + that may occur. Returns: InvocableResult: Result of the invocation. """ + ... + + +__all__ = ["Invocable", "InvocableResult"] diff --git a/packages/polywrap-core/polywrap_core/types/invoke_args.py b/packages/polywrap-core/polywrap_core/types/invoke_args.py deleted file mode 100644 index d0d074e3..00000000 --- a/packages/polywrap-core/polywrap_core/types/invoke_args.py +++ /dev/null @@ -1,4 +0,0 @@ -"""This module defines InvokeArgs type.""" -from typing import Any, Dict, Union - -InvokeArgs = Union[Dict[str, Any], bytes, None] diff --git a/packages/polywrap-core/polywrap_core/types/invoke_options.py b/packages/polywrap-core/polywrap_core/types/invoke_options.py new file mode 100644 index 00000000..8cab91d6 --- /dev/null +++ b/packages/polywrap-core/polywrap_core/types/invoke_options.py @@ -0,0 +1,34 @@ +"""This module defines the InvokeOptions protocol.""" +from typing import Any, Optional, Protocol + +from .uri import Uri +from .uri_resolution_context import UriResolutionContext + + +class InvokeOptions(Protocol): + """InvokeOptions holds the options for an invocation.""" + + @property + def uri(self) -> Uri: + """The URI of the wrapper.""" + ... + + @property + def method(self) -> str: + """The method to invoke.""" + ... + + @property + def args(self) -> Any: + """The arguments to pass to the method.""" + ... + + @property + def env(self) -> Any: + """The environment variables to set for the invocation.""" + ... + + @property + def resolution_context(self) -> Optional[UriResolutionContext]: + """A URI resolution context.""" + ... diff --git a/packages/polywrap-core/polywrap_core/types/invoker.py b/packages/polywrap-core/polywrap_core/types/invoker.py index b81cb2ca..16083a5c 100644 --- a/packages/polywrap-core/polywrap_core/types/invoker.py +++ b/packages/polywrap-core/polywrap_core/types/invoker.py @@ -1,49 +1,54 @@ """This module contains the interface for invoking any invocables.""" +# pylint: disable=too-many-arguments + from __future__ import annotations -from abc import ABC, abstractmethod -from dataclasses import dataclass -from typing import Any, Generic, List, Optional, TypeVar, Union +from typing import Any, List, Optional, Protocol -from .options.invoke_options import InvokeOptions from .uri import Uri -from .uri_like import UriLike - -TUriLike = TypeVar("TUriLike", bound=UriLike) - - -@dataclass(slots=True, kw_only=True) -class InvokerOptions(Generic[TUriLike], InvokeOptions[TUriLike]): - """Options for invoking a wrapper using an invoker. +from .uri_resolution_context import UriResolutionContext - Attributes: - encode_result (Optional[bool]): If true, the result will be encoded. - """ - encode_result: Optional[bool] = False - - -class Invoker(ABC, Generic[TUriLike]): +class Invoker(Protocol): """Invoker interface defines the methods for invoking a wrapper.""" - @abstractmethod - async def invoke(self, options: InvokerOptions[TUriLike]) -> Any: + def invoke( + self, + uri: Uri, + method: str, + args: Optional[Any] = None, + env: Optional[Any] = None, + resolution_context: Optional[UriResolutionContext] = None, + encode_result: Optional[bool] = False, + ) -> Any: """Invoke the Wrapper based on the provided InvokerOptions. Args: - options (InvokerOptions): InvokerOptions for this invocation. + uri (Uri): Uri of the wrapper + method (str): Method to be executed + args (Optional[Any]) : Arguments for the method, structured as a dictionary + env (Optional[Any]): Override the client's config for all invokes within this invoke. + resolution_context (Optional[UriResolutionContext]): A URI resolution context + encode_result (Optional[bool]): If True, the result will be encoded Returns: Any: invocation result. """ + ... - @abstractmethod - def get_implementations(self, uri: Uri) -> Union[List[Uri], None]: + def get_implementations( + self, uri: Uri, apply_resolution: bool = True + ) -> Optional[List[Uri]]: """Get implementations of an interface with its URI. Args: uri (Uri): URI of the interface. + apply_resolution (bool): If True, apply resolution to the URI and interfaces. Returns: - Union[List[Uri], None]: List of implementations or None if not found. + Optional[List[Uri]]: List of implementations or None if not found. """ + ... + + +__all__ = ["Invoker"] diff --git a/packages/polywrap-core/polywrap_core/types/invoker_client.py b/packages/polywrap-core/polywrap_core/types/invoker_client.py index 245e3af4..66d3eaff 100644 --- a/packages/polywrap-core/polywrap_core/types/invoker_client.py +++ b/packages/polywrap-core/polywrap_core/types/invoker_client.py @@ -1,15 +1,15 @@ """This module contains the InvokerClient interface.""" from __future__ import annotations -from typing import Generic, TypeVar +from typing import Protocol from .invoker import Invoker -from .uri_like import UriLike from .uri_resolver_handler import UriResolverHandler -TUriLike = TypeVar("TUriLike", bound=UriLike) - -class InvokerClient(Generic[TUriLike], Invoker[TUriLike], UriResolverHandler[TUriLike]): +class InvokerClient(Invoker, UriResolverHandler, Protocol): """InvokerClient interface defines core set of functionalities\ for resolving and invoking a wrapper.""" + + +__all__ = ["InvokerClient"] diff --git a/packages/polywrap-core/polywrap_core/types/options/__init__.py b/packages/polywrap-core/polywrap_core/types/options/__init__.py deleted file mode 100644 index 1c08b389..00000000 --- a/packages/polywrap-core/polywrap_core/types/options/__init__.py +++ /dev/null @@ -1,5 +0,0 @@ -"""This module contains the options for various client methods.""" -from .file_options import * -from .invoke_options import * -from .manifest_options import * -from .uri_resolver_options import * diff --git a/packages/polywrap-core/polywrap_core/types/options/file_options.py b/packages/polywrap-core/polywrap_core/types/options/file_options.py deleted file mode 100644 index 614fc3e8..00000000 --- a/packages/polywrap-core/polywrap_core/types/options/file_options.py +++ /dev/null @@ -1,18 +0,0 @@ -"""This module contains GetFileOptions type.""" -from __future__ import annotations - -from dataclasses import dataclass -from typing import Optional - - -@dataclass(slots=True, kw_only=True) -class GetFileOptions: - """Options for getting a file from a wrapper. - - Attributes: - path (str): Path to the file. - encoding (Optional[str]): Encoding of the file. - """ - - path: str - encoding: Optional[str] = "utf-8" diff --git a/packages/polywrap-core/polywrap_core/types/options/invoke_options.py b/packages/polywrap-core/polywrap_core/types/options/invoke_options.py deleted file mode 100644 index afe3a1d3..00000000 --- a/packages/polywrap-core/polywrap_core/types/options/invoke_options.py +++ /dev/null @@ -1,32 +0,0 @@ -"""This module contains the interface for invoking any invocables.""" -from __future__ import annotations - -from dataclasses import dataclass, field -from typing import Generic, Optional, TypeVar - -from ..env import Env -from ..invoke_args import InvokeArgs -from ..uri import Uri -from ..uri_like import UriLike -from ..uri_resolution_context import IUriResolutionContext - -TUriLike = TypeVar("TUriLike", bound=UriLike) - - -@dataclass(slots=True, kw_only=True) -class InvokeOptions(Generic[TUriLike]): - """Options required for a wrapper invocation. - - Args: - uri (Uri): Uri of the wrapper - method (str): Method to be executed - args (Optional[InvokeArgs]) : Arguments for the method, structured as a dictionary - env (Optional[Env]): Override the client's config for all invokes within this invoke. - resolution_context (Optional[IUriResolutionContext]): A URI resolution context - """ - - uri: Uri - method: str - args: Optional[InvokeArgs] = field(default_factory=dict) - env: Optional[Env] = None - resolution_context: Optional[IUriResolutionContext[TUriLike]] = None diff --git a/packages/polywrap-core/polywrap_core/types/options/manifest_options.py b/packages/polywrap-core/polywrap_core/types/options/manifest_options.py deleted file mode 100644 index 521218df..00000000 --- a/packages/polywrap-core/polywrap_core/types/options/manifest_options.py +++ /dev/null @@ -1,11 +0,0 @@ -"""This module contains GetManifestOptions type.""" -from __future__ import annotations - -from dataclasses import dataclass - -from polywrap_manifest import DeserializeManifestOptions - - -@dataclass(slots=True, kw_only=True) -class GetManifestOptions(DeserializeManifestOptions): - """Options for getting a manifest from a wrapper.""" diff --git a/packages/polywrap-core/polywrap_core/types/options/uri_resolver_options.py b/packages/polywrap-core/polywrap_core/types/options/uri_resolver_options.py deleted file mode 100644 index 9d897d0d..00000000 --- a/packages/polywrap-core/polywrap_core/types/options/uri_resolver_options.py +++ /dev/null @@ -1,24 +0,0 @@ -"""This module contains the TryResolveUriOptions type.""" -from __future__ import annotations - -from dataclasses import dataclass -from typing import Generic, Optional, TypeVar - -from ..uri import Uri -from ..uri_like import UriLike -from ..uri_resolution_context import IUriResolutionContext - -TUriLike = TypeVar("TUriLike", bound=UriLike) - - -@dataclass(slots=True, kw_only=True) -class TryResolveUriOptions(Generic[TUriLike]): - """Options for resolving a uri. - - Args: - uri (Uri): Uri of the wrapper to resolve. - resolution_context (Optional[IUriResolutionContext]): A URI resolution context - """ - - uri: Uri - resolution_context: Optional[IUriResolutionContext[TUriLike]] = None diff --git a/packages/polywrap-core/polywrap_core/types/uri.py b/packages/polywrap-core/polywrap_core/types/uri.py index f6390bf2..ba97e2d1 100644 --- a/packages/polywrap-core/polywrap_core/types/uri.py +++ b/packages/polywrap-core/polywrap_core/types/uri.py @@ -2,12 +2,12 @@ from __future__ import annotations import re +from functools import total_ordering from typing import Union -from .uri_like import UriLike - -class Uri(UriLike): +@total_ordering +class Uri: """Defines a wrapper URI and provides utilities for parsing and validating them. wrapper URIs are used to identify and resolve Polywrap wrappers. They are \ @@ -54,6 +54,7 @@ class Uri(UriLike): r"^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?" ) # https://www.rfc-editor.org/rfc/rfc3986#appendix-B + scheme = "wrap" _authority: str _path: str @@ -150,3 +151,29 @@ def from_str(cls, uri: str) -> Uri: raise ValueError("The provided URI has an invalid path") return cls(authority, path) + + def __str__(self) -> str: + """Return the URI as a string.""" + return self.uri + + def __repr__(self) -> str: + """Return the string URI representation.""" + return f'Uri("{self._authority}", "{self._path}")' + + def __hash__(self) -> int: + """Return the hash of the URI.""" + return hash(self.uri) + + def __eq__(self, obj: object) -> bool: + """Return true if the provided object is a Uri and has the same URI.""" + return self.uri == obj.uri if isinstance(obj, Uri) else False + + def __lt__(self, uri: object) -> bool: + """Return true if the provided Uri has a URI that is lexicographically\ + less than this Uri.""" + if not isinstance(uri, Uri): + raise TypeError(f"Cannot compare Uri to {type(uri)}") + return self.uri < uri.uri + + +__all__ = ["Uri"] diff --git a/packages/polywrap-core/polywrap_core/types/uri_like.py b/packages/polywrap-core/polywrap_core/types/uri_like.py deleted file mode 100644 index 39014221..00000000 --- a/packages/polywrap-core/polywrap_core/types/uri_like.py +++ /dev/null @@ -1,64 +0,0 @@ -"""This module contains the utility for sanitizing and parsing Wrapper URIs.""" -from __future__ import annotations - -from abc import ABC, abstractmethod -from functools import total_ordering - - -@total_ordering -class UriLike(ABC): - """Defines the interface for a URI-like object. - - Examples: - - Uri - - UriWrapper - - UriPackage - """ - - @property - def scheme(self) -> str: - """Return the scheme of the URI.""" - return "wrap" - - @property - @abstractmethod - def authority(self) -> str: - """Return the authority of the URI.""" - - @property - @abstractmethod - def path(self) -> str: - """Return the path of the URI.""" - - @property - @abstractmethod - def uri(self) -> str: - """Return the URI as a string.""" - - @staticmethod - @abstractmethod - def is_canonical_uri(uri: str) -> bool: - """Return true if the provided URI is canonical.""" - - def __str__(self) -> str: - """Return the URI as a string.""" - return self.uri - - def __repr__(self) -> str: - """Return the string URI representation.""" - return f"Uri({self.uri})" - - def __hash__(self) -> int: - """Return the hash of the URI.""" - return hash(self.uri) - - def __eq__(self, obj: object) -> bool: - """Return true if the provided object is a Uri and has the same URI.""" - return self.uri == obj.uri if isinstance(obj, UriLike) else False - - def __lt__(self, uri: object) -> bool: - """Return true if the provided Uri has a URI that is lexicographically\ - less than this Uri.""" - if not isinstance(uri, UriLike): - raise TypeError(f"Cannot compare Uri to {type(uri)}") - return self.uri < uri.uri diff --git a/packages/polywrap-core/polywrap_core/types/uri_package.py b/packages/polywrap-core/polywrap_core/types/uri_package.py index 8d84f5d3..c512861b 100644 --- a/packages/polywrap-core/polywrap_core/types/uri_package.py +++ b/packages/polywrap-core/polywrap_core/types/uri_package.py @@ -1,35 +1,23 @@ """This module contains the UriPackage type.""" from __future__ import annotations -from typing import Generic, TypeVar +from dataclasses import dataclass from .uri import Uri -from .uri_like import UriLike from .wrap_package import WrapPackage -TUriLike = TypeVar("TUriLike", bound=UriLike) - -class UriPackage(Generic[TUriLike], Uri): - """UriPackage is a dataclass that contains a URI and a wrap package. +@dataclass(slots=True, kw_only=True) +class UriPackage: + """UriPackage is a dataclass that contains a URI and a package. Attributes: - package (WrapPackage): The wrap package. + uri: The URI. + package: The package. """ - _package: WrapPackage[TUriLike] - - def __init__(self, uri: Uri, package: WrapPackage[TUriLike]) -> None: - """Initialize a new instance of UriPackage. + uri: Uri + package: WrapPackage - Args: - uri (Uri): The URI. - package (WrapPackage): The wrap package. - """ - super().__init__(uri.authority, uri.path) - self._package = package - @property - def package(self) -> WrapPackage[TUriLike]: - """Return the wrap package.""" - return self._package +__all__ = ["UriPackage"] diff --git a/packages/polywrap-core/polywrap_core/types/uri_package_wrapper.py b/packages/polywrap-core/polywrap_core/types/uri_package_wrapper.py index 8351aac8..a4c3e5da 100644 --- a/packages/polywrap-core/polywrap_core/types/uri_package_wrapper.py +++ b/packages/polywrap-core/polywrap_core/types/uri_package_wrapper.py @@ -7,6 +7,6 @@ from .uri_package import UriPackage from .uri_wrapper import UriWrapper -UriPackageOrWrapper = Union[ - Uri, UriWrapper["UriPackageOrWrapper"], UriPackage["UriPackageOrWrapper"] -] +UriPackageOrWrapper = Union[Uri, UriWrapper, UriPackage] + +__all__ = ["UriPackageOrWrapper"] diff --git a/packages/polywrap-core/polywrap_core/types/uri_resolution_context.py b/packages/polywrap-core/polywrap_core/types/uri_resolution_context.py index 3909a36e..7b3e9f94 100644 --- a/packages/polywrap-core/polywrap_core/types/uri_resolution_context.py +++ b/packages/polywrap-core/polywrap_core/types/uri_resolution_context.py @@ -1,88 +1,120 @@ -"""This module contains the interface for a URI resolution context.""" -from __future__ import annotations - -from abc import ABC, abstractmethod -from typing import Generic, List, TypeVar +"""This module contains implementation of IUriResolutionContext interface.""" +from typing import List, Optional, Set from .uri import Uri -from .uri_like import UriLike -from .uri_resolution_step import IUriResolutionStep +from .uri_resolution_step import UriResolutionStep + + +class UriResolutionContext: + """Represents the context of a uri resolution. -TUriLike = TypeVar("TUriLike", bound=UriLike) + Attributes: + resolving_uri_set: A set of uris that are currently being resolved. + resolution_path: A list of uris in the order that they are being resolved. + history: A list of steps that have been taken to resolve the uri. + """ + resolving_uri_set: Set[Uri] + resolution_path: List[Uri] + history: List[UriResolutionStep] -class IUriResolutionContext(ABC, Generic[TUriLike]): - """Defines the interface for a URI resolution context.""" + __slots__ = ("resolving_uri_set", "resolution_path", "history") + + def __init__( + self, + resolving_uri_set: Optional[Set[Uri]] = None, + resolution_path: Optional[List[Uri]] = None, + history: Optional[List[UriResolutionStep]] = None, + ): + """Initialize a new instance of UriResolutionContext. + + Args: + resolving_uri_set: A set of uris that are currently being resolved. + resolution_path: A list of uris in the order that they are being resolved. + history: A list of steps that have been taken to resolve the uri. + """ + self.resolving_uri_set = resolving_uri_set or set() + self.resolution_path = resolution_path or [] + self.history = history or [] - @abstractmethod def is_resolving(self, uri: Uri) -> bool: """Check if the given uri is currently being resolved. Args: - uri (Uri): The uri to check. + uri: The uri to check. Returns: bool: True if the uri is currently being resolved, otherwise False. """ + return uri in self.resolving_uri_set - @abstractmethod def start_resolving(self, uri: Uri) -> None: """Start resolving the given uri. Args: - uri (Uri): The uri to start resolving. + uri: The uri to start resolving. Returns: None """ + self.resolving_uri_set.add(uri) + self.resolution_path.append(uri) - @abstractmethod def stop_resolving(self, uri: Uri) -> None: """Stop resolving the given uri. Args: - uri (Uri): The uri to stop resolving. + uri: The uri to stop resolving. Returns: None """ + self.resolving_uri_set.remove(uri) - @abstractmethod - def track_step(self, step: IUriResolutionStep[TUriLike]) -> None: + def track_step(self, step: UriResolutionStep) -> None: """Track the given step in the resolution history. Args: - step (IUriResolutionStep): The step to track. + step: The step to track. Returns: None """ + self.history.append(step) - @abstractmethod - def get_history(self) -> List[IUriResolutionStep[TUriLike]]: + def get_history(self) -> List[UriResolutionStep]: """Get the resolution history. Returns: - List[IUriResolutionStep]: The resolution history. + List[UriResolutionStep]: The resolution history. """ + return self.history - @abstractmethod def get_resolution_path(self) -> List[Uri]: """Get the resolution path. Returns: List[Uri]: The ordered list of URI resolution path. """ + return self.resolution_path - @abstractmethod - def create_sub_history_context(self) -> "IUriResolutionContext[TUriLike]": + def create_sub_history_context(self) -> "UriResolutionContext": """Create a new sub context that shares the same resolution path. Returns: - IUriResolutionContext: The new context. + UriResolutionContext: The new context. """ + return UriResolutionContext( + resolving_uri_set=self.resolving_uri_set, + resolution_path=self.resolution_path, + ) - @abstractmethod - def create_sub_context(self) -> "IUriResolutionContext[TUriLike]": + def create_sub_context(self) -> "UriResolutionContext": """Create a new sub context that shares the same resolution history. Returns: - IUriResolutionContext: The new context. + UriResolutionContext: The new context. """ + return UriResolutionContext( + resolving_uri_set=self.resolving_uri_set, history=self.history + ) + + +__all__ = ["UriResolutionContext"] diff --git a/packages/polywrap-core/polywrap_core/types/uri_resolution_step.py b/packages/polywrap-core/polywrap_core/types/uri_resolution_step.py index ed75a331..4ababc33 100644 --- a/packages/polywrap-core/polywrap_core/types/uri_resolution_step.py +++ b/packages/polywrap-core/polywrap_core/types/uri_resolution_step.py @@ -1,27 +1,28 @@ -"""This module contains the uri resolution step interface.""" +"""This module contains implementation of IUriResolutionStep interface.""" from __future__ import annotations from dataclasses import dataclass -from typing import Generic, List, Optional, TypeVar +from typing import Any, List, Optional from .uri import Uri -from .uri_like import UriLike - -TUriLike = TypeVar("TUriLike", bound=UriLike) @dataclass(slots=True, kw_only=True) -class IUriResolutionStep(Generic[TUriLike]): +class UriResolutionStep: """Represents a single step in the resolution of a uri. Attributes: source_uri (Uri): The uri that was resolved. - result (T): The result of the resolution. must be a UriLike. - description: A description of the resolution step. - sub_history: A list of sub steps that were taken to resolve the uri. + result (Any): The result of the resolution. + description (Optional[str]): A description of the resolution step. + sub_history (Optional[List[UriResolutionStep]]): A list of sub steps\ + that were taken to resolve the uri. """ source_uri: Uri - result: TUriLike + result: Any description: Optional[str] = None - sub_history: Optional[List["IUriResolutionStep[TUriLike]"]] = None + sub_history: Optional[List[UriResolutionStep]] = None + + +__all__ = ["UriResolutionStep"] diff --git a/packages/polywrap-core/polywrap_core/types/uri_resolver.py b/packages/polywrap-core/polywrap_core/types/uri_resolver.py index 66463d1c..f80534a8 100644 --- a/packages/polywrap-core/polywrap_core/types/uri_resolver.py +++ b/packages/polywrap-core/polywrap_core/types/uri_resolver.py @@ -1,23 +1,22 @@ """This module contains the uri resolver interface.""" from __future__ import annotations -from abc import ABC, abstractmethod +from typing import Protocol from .invoker_client import InvokerClient from .uri import Uri from .uri_package_wrapper import UriPackageOrWrapper -from .uri_resolution_context import IUriResolutionContext +from .uri_resolution_context import UriResolutionContext -class UriResolver(ABC): +class UriResolver(Protocol): """Defines interface for wrapper uri resolver.""" - @abstractmethod - async def try_resolve_uri( + def try_resolve_uri( self, uri: Uri, - client: InvokerClient[UriPackageOrWrapper], - resolution_context: IUriResolutionContext[UriPackageOrWrapper], + client: InvokerClient, + resolution_context: UriResolutionContext, ) -> UriPackageOrWrapper: """Try to resolve a uri. @@ -29,3 +28,7 @@ async def try_resolve_uri( Returns: UriPackageOrWrapper: result of the URI resolution. """ + ... + + +__all__ = ["UriResolver"] diff --git a/packages/polywrap-core/polywrap_core/types/uri_resolver_handler.py b/packages/polywrap-core/polywrap_core/types/uri_resolver_handler.py index 3c56687a..ca1140b5 100644 --- a/packages/polywrap-core/polywrap_core/types/uri_resolver_handler.py +++ b/packages/polywrap-core/polywrap_core/types/uri_resolver_handler.py @@ -1,27 +1,29 @@ """This module contains uri resolver handler interface.""" from __future__ import annotations -from abc import ABC, abstractmethod -from typing import Generic, TypeVar +from typing import Any, Optional, Protocol -from .options.uri_resolver_options import TryResolveUriOptions -from .uri_like import UriLike +from .uri import Uri +from .uri_resolution_context import UriResolutionContext -TUriLike = TypeVar("TUriLike", bound=UriLike) - -class UriResolverHandler(ABC, Generic[TUriLike]): +class UriResolverHandler(Protocol): """Uri resolver handler interface.""" - @abstractmethod - async def try_resolve_uri( - self, options: TryResolveUriOptions[TUriLike] - ) -> TUriLike: + def try_resolve_uri( + self, uri: Uri, resolution_context: Optional[UriResolutionContext] = None + ) -> Any: """Try to resolve a uri. Args: - options: The options for resolving the uri. + uri (Uri): Uri of the wrapper to resolve. + resolution_context (Optional[IUriResolutionContext]):\ + A URI resolution context Returns: - T: result of the URI resolution. Must be a UriLike. + Any: result of the URI resolution. """ + ... + + +__all__ = ["UriResolverHandler"] diff --git a/packages/polywrap-core/polywrap_core/types/uri_wrapper.py b/packages/polywrap-core/polywrap_core/types/uri_wrapper.py index 56749816..44c83b07 100644 --- a/packages/polywrap-core/polywrap_core/types/uri_wrapper.py +++ b/packages/polywrap-core/polywrap_core/types/uri_wrapper.py @@ -1,35 +1,23 @@ """This module contains the UriWrapper type.""" from __future__ import annotations -from typing import Generic, TypeVar +from dataclasses import dataclass from .uri import Uri -from .uri_like import UriLike from .wrapper import Wrapper -TUriLike = TypeVar("TUriLike", bound=UriLike) - -class UriWrapper(Generic[TUriLike], Uri): +@dataclass(slots=True, kw_only=True) +class UriWrapper: """UriWrapper is a dataclass that contains a URI and a wrapper. Attributes: + uri: The URI. wrapper: The wrapper. """ - _wrapper: Wrapper[TUriLike] - - def __init__(self, uri: Uri, wrapper: Wrapper[TUriLike]) -> None: - """Initialize a new instance of UriWrapper. + uri: Uri + wrapper: Wrapper - Args: - uri: The URI. - wrapper: The wrapper. - """ - super().__init__(uri.authority, uri.path) - self._wrapper = wrapper - @property - def wrapper(self) -> Wrapper[TUriLike]: - """Return the wrapper.""" - return self._wrapper +__all__ = ["UriWrapper"] diff --git a/packages/polywrap-core/polywrap_core/types/wrap_package.py b/packages/polywrap-core/polywrap_core/types/wrap_package.py index 4ce160d1..648087c3 100644 --- a/packages/polywrap-core/polywrap_core/types/wrap_package.py +++ b/packages/polywrap-core/polywrap_core/types/wrap_package.py @@ -1,30 +1,26 @@ """This module contains the IWrapPackage interface.""" -from abc import ABC, abstractmethod -from typing import Generic, Optional, TypeVar +from __future__ import annotations -from polywrap_manifest import AnyWrapManifest +from typing import Optional, Protocol -from .options import GetManifestOptions -from .uri_like import UriLike -from .wrapper import Wrapper +from polywrap_manifest import AnyWrapManifest, DeserializeManifestOptions -TUriLike = TypeVar("TUriLike", bound=UriLike) +from .wrapper import Wrapper -class WrapPackage(ABC, Generic[TUriLike]): +class WrapPackage(Protocol): """Wrapper package interface.""" - @abstractmethod - async def create_wrapper(self) -> Wrapper[TUriLike]: + def create_wrapper(self) -> Wrapper: """Create a new wrapper instance from the wrapper package. Returns: Wrapper: The newly created wrapper instance. """ + ... - @abstractmethod - async def get_manifest( - self, options: Optional[GetManifestOptions] = None + def get_manifest( + self, options: Optional[DeserializeManifestOptions] = None ) -> AnyWrapManifest: """Get the manifest from the wrapper package. @@ -34,3 +30,7 @@ async def get_manifest( Returns: AnyWrapManifest: The manifest of the wrapper. """ + ... + + +__all__ = ["WrapPackage"] diff --git a/packages/polywrap-core/polywrap_core/types/wrapper.py b/packages/polywrap-core/polywrap_core/types/wrapper.py index d92fe87c..303893e6 100644 --- a/packages/polywrap-core/polywrap_core/types/wrapper.py +++ b/packages/polywrap-core/polywrap_core/types/wrapper.py @@ -1,52 +1,37 @@ """This module contains the Wrapper interface.""" -from abc import abstractmethod -from typing import Any, Dict, Generic, TypeVar, Union +from __future__ import annotations + +from typing import Optional, Protocol, Union from polywrap_manifest import AnyWrapManifest from .invocable import Invocable -from .invoker import InvokeOptions, Invoker -from .options import GetFileOptions -from .uri_like import UriLike - -TUriLike = TypeVar("TUriLike", bound=UriLike) -class Wrapper(Generic[TUriLike], Invocable[TUriLike]): +class Wrapper(Invocable, Protocol): """Defines the interface for a wrapper.""" - @abstractmethod - async def invoke( - self, options: InvokeOptions[TUriLike], invoker: Invoker[TUriLike] - ) -> Any: - """Invoke the wrapper. - - Args: - options: The options for invoking the wrapper. - invoker: The invoker to use for invoking the wrapper. - - Returns: - Any: The result of the wrapper invocation. - """ - - @abstractmethod - async def get_file(self, options: GetFileOptions) -> Union[str, bytes]: + def get_file( + self, path: str, encoding: Optional[str] = "utf-8" + ) -> Union[str, bytes]: """Get a file from the wrapper. Args: - options: The options for getting the file. + path (str): Path to the file. + encoding (Optional[str]): Encoding of the file. Returns: Union[str, bytes]: The file contents """ + ... - @abstractmethod def get_manifest(self) -> AnyWrapManifest: """Get the manifest of the wrapper. Returns: AnyWrapManifest: The manifest of the wrapper. """ + ... -WrapperCache = Dict[str, Wrapper[TUriLike]] +__all__ = ["Wrapper"] diff --git a/packages/polywrap-core/polywrap_core/utils/__init__.py b/packages/polywrap-core/polywrap_core/utils/__init__.py index 0d6a3b67..abd549d8 100644 --- a/packages/polywrap-core/polywrap_core/utils/__init__.py +++ b/packages/polywrap-core/polywrap_core/utils/__init__.py @@ -1,3 +1,4 @@ -"""This module contains the core utility functions.""" -from .instance_of import * -from .maybe_async import * +"""This package contains the utilities used by the polywrap-uri-resolvers package.""" +from .build_clean_uri_history import * +from .get_env_from_resolution_path import * +from .get_implementations import * diff --git a/packages/polywrap-core/polywrap_core/utils/build_clean_uri_history.py b/packages/polywrap-core/polywrap_core/utils/build_clean_uri_history.py new file mode 100644 index 00000000..a22dd0f1 --- /dev/null +++ b/packages/polywrap-core/polywrap_core/utils/build_clean_uri_history.py @@ -0,0 +1,73 @@ +"""This module contains an utility function for building a clean history of URI resolution steps.""" +from typing import List, Optional, Union + +from ..types import UriPackage, UriResolutionStep, UriWrapper + +CleanResolutionStep = List[Union[str, "CleanResolutionStep"]] + + +def build_clean_uri_history( + history: List[UriResolutionStep], depth: Optional[int] = None +) -> CleanResolutionStep: + """Build a clean history of the URI resolution steps. + + Args: + history: A list of URI resolution steps. + depth: The depth of the history to build. + + Returns: + CleanResolutionStep: A clean history of the URI resolution steps. + """ + clean_history: CleanResolutionStep = [] + + if depth is not None: + depth -= 1 + + if not history: + return clean_history + + for step in history: + clean_history.append(_build_clean_history_step(step)) + + if ( + not step.sub_history + or len(step.sub_history) == 0 + or (depth is not None and depth < 0) + ): + continue + + sub_history = build_clean_uri_history(step.sub_history, depth) + if len(sub_history) > 0: + clean_history.append(sub_history) + + return clean_history + + +def _build_clean_history_step(step: UriResolutionStep) -> str: + uri_package_or_wrapper = step.result + + match uri_package_or_wrapper: + case UriPackage(uri=uri): + return ( + f"{step.source_uri} => {step.description} => package ({uri})" + if step.description + else f"{step.source_uri} => package ({uri})" + ) + case UriWrapper(uri=uri): + return ( + f"{step.source_uri} => {step.description} => wrapper ({uri})" + if step.description + else f"{step.source_uri} => wrapper ({uri})" + ) + case uri: + if step.source_uri == uri: + return ( + f"{step.source_uri} => {step.description}" + if step.description + else f"{step.source_uri}" + ) + return ( + f"{step.source_uri} => {step.description} => uri ({uri})" + if step.description + else f"{step.source_uri} => uri ({uri})" + ) diff --git a/packages/polywrap-core/polywrap_core/utils/get_env_from_resolution_path.py b/packages/polywrap-core/polywrap_core/utils/get_env_from_resolution_path.py new file mode 100644 index 00000000..33bc4ac2 --- /dev/null +++ b/packages/polywrap-core/polywrap_core/utils/get_env_from_resolution_path.py @@ -0,0 +1,22 @@ +"""This module contains the utility function for getting the env from the URI history.""" +from typing import Any, List, Union + +from ..types import Client, Uri + + +def get_env_from_resolution_path( + uri_history: List[Uri], client: Client +) -> Union[Any, None]: + """Get environment variable from URI resolution history. + + Args: + uri_history: List of URIs from the URI resolution history + client: Polywrap client instance to use for getting the env by URI + + Returns: + env if found, None otherwise + """ + for uri in uri_history: + if env := client.get_env_by_uri(uri): + return env + return None diff --git a/packages/polywrap-core/polywrap_core/utils/get_implementations.py b/packages/polywrap-core/polywrap_core/utils/get_implementations.py new file mode 100644 index 00000000..e8657129 --- /dev/null +++ b/packages/polywrap-core/polywrap_core/utils/get_implementations.py @@ -0,0 +1,49 @@ +"""This module contains the get_implementations utility.""" +from typing import Dict, List, Optional, Set + +from ..types import InvokerClient, Uri, UriResolutionContext +from ..types.errors import WrapGetImplementationsError + + +def _get_final_uri( + uri: Uri, + client: Optional[InvokerClient] = None, + resolution_context: Optional[UriResolutionContext] = None, +) -> Uri: + if client: + try: + return client.try_resolve_uri(uri, resolution_context) + except Exception as e: + raise WrapGetImplementationsError(uri, "Failed to resolve redirects") from e + return uri + + +def get_implementations( + interface_uri: Uri, + interfaces: Dict[Uri, List[Uri]], + client: Optional[InvokerClient] = None, + resolution_context: Optional[UriResolutionContext] = None, +) -> Optional[List[Uri]]: + """Get implementations of an interface with its URI. + + Args: + interface_uri (Uri): URI of the interface. + interfaces (Dict[Uri, List[Uri]]): Dictionary of interfaces and their implementations. + client (Optional[InvokerClient]): The client to use for resolving the URI. + resolution_context (Optional[UriResolutionContext]): The resolution context to use. + + Returns: + Optional[List[Uri]]: List of implementations or None if not found. + """ + final_interface_uri = _get_final_uri(interface_uri, client, resolution_context) + final_implementations: Set[Uri] = set() + + for interface in interfaces: + final_current_interface_uri = _get_final_uri( + interface, client, resolution_context + ) + if final_current_interface_uri == final_interface_uri: + impls = set(interfaces.get(interface, [])) + final_implementations = final_implementations.union(impls) + + return list(final_implementations) if final_implementations else None diff --git a/packages/polywrap-core/polywrap_core/utils/instance_of.py b/packages/polywrap-core/polywrap_core/utils/instance_of.py deleted file mode 100644 index 3772179d..00000000 --- a/packages/polywrap-core/polywrap_core/utils/instance_of.py +++ /dev/null @@ -1,16 +0,0 @@ -"""This module contains the instance_of utility function.""" -import inspect -from typing import Any - - -def instance_of(obj: Any, cls: Any): - """Check if an object is an instance of a class or any of its parent classes. - - Args: - obj (Any): any object instance - cls (Any): class to check against - - Returns: - bool: True if obj is an instance of cls or any of its parent classes, False otherwise - """ - return cls in inspect.getmro(obj.__class__) diff --git a/packages/polywrap-core/polywrap_core/utils/maybe_async.py b/packages/polywrap-core/polywrap_core/utils/maybe_async.py deleted file mode 100644 index 913182f2..00000000 --- a/packages/polywrap-core/polywrap_core/utils/maybe_async.py +++ /dev/null @@ -1,18 +0,0 @@ -"""This module contains the utility function for executing a function that may be async.""" -from __future__ import annotations - -import inspect -from typing import Any, Awaitable, Callable, Optional, Union - - -def is_coroutine(test: Optional[Union[Awaitable[Any], Any]] = None) -> bool: - """Check if the given object is a coroutine.""" - return test is not None and inspect.iscoroutine(test) - - -async def execute_maybe_async_function(func: Callable[..., Any], *args: Any) -> Any: - """Execute a function that may be async.""" - result = func(*args) - if is_coroutine(result): - result = await result - return result diff --git a/packages/polywrap-core/pyproject.toml b/packages/polywrap-core/pyproject.toml index dc73c351..5097c49e 100644 --- a/packages/polywrap-core/pyproject.toml +++ b/packages/polywrap-core/pyproject.toml @@ -12,9 +12,10 @@ authors = ["Cesar ", "Niraj "] python = "^3.10" polywrap-msgpack = {path = "../polywrap-msgpack", develop = true} polywrap-manifest = {path = "../polywrap-manifest", develop = true} -[tool.poetry.dev-dependencies] + +[tool.poetry.group.dev.dependencies] +pycln = "^2.1.3" pytest = "^7.1.2" -pytest-asyncio = "^0.19.0" pylint = "^2.15.4" black = "^22.10.0" bandit = { version = "^1.7.4", extras = ["toml"]} @@ -24,13 +25,6 @@ isort = "^5.10.1" pyright = "^1.1.275" pydocstyle = "^6.1.1" -[tool.poetry.group.temp.dependencies] -pydeps = "^1.11.1" - - -[tool.poetry.group.dev.dependencies] -pycln = "^2.1.3" - [tool.bandit] exclude_dirs = ["tests"] @@ -42,7 +36,6 @@ typeCheckingMode = "strict" reportShadowedImports = false [tool.pytest.ini_options] -asyncio_mode = "auto" testpaths = [ "tests" ] @@ -52,6 +45,7 @@ disable = [ "invalid-name", "too-many-return-statements", "too-few-public-methods", + "unnecessary-ellipsis" ] ignore = [ "tests/" diff --git a/packages/polywrap-core/tests/test_build_clean_uri_history.py b/packages/polywrap-core/tests/test_build_clean_uri_history.py new file mode 100644 index 00000000..e5da523d --- /dev/null +++ b/packages/polywrap-core/tests/test_build_clean_uri_history.py @@ -0,0 +1,46 @@ +from polywrap_core import ( + CleanResolutionStep, + Uri, + build_clean_uri_history, + UriResolutionStep, +) +import pytest + + +@pytest.fixture +def history() -> list[UriResolutionStep]: + return [ + UriResolutionStep( + source_uri=Uri.from_str("test/1"), + result=Uri.from_str("test/2"), + description="AggreagatorResolver", + sub_history=[ + UriResolutionStep( + source_uri=Uri.from_str("test/1"), + result=Uri.from_str("test/2"), + description="ExtensionRedirectResolver", + ), + ], + ), + UriResolutionStep( + source_uri=Uri.from_str("test/2"), + result=Uri.from_str("test/3"), + description="SimpleRedirectResolver", + ), + ] + + +@pytest.fixture +def expected() -> CleanResolutionStep: + return [ + "wrap://test/1 => AggreagatorResolver => uri (wrap://test/2)", + ["wrap://test/1 => ExtensionRedirectResolver => uri (wrap://test/2)"], + "wrap://test/2 => SimpleRedirectResolver => uri (wrap://test/3)", + ] + + +def test_build_clean_uri_history( + history: list[UriResolutionStep], expected: CleanResolutionStep +): + print(build_clean_uri_history(history)) + assert build_clean_uri_history(history) == expected diff --git a/packages/polywrap-core/tests/test_env_from_resolution_path.py b/packages/polywrap-core/tests/test_env_from_resolution_path.py new file mode 100644 index 00000000..5c832372 --- /dev/null +++ b/packages/polywrap-core/tests/test_env_from_resolution_path.py @@ -0,0 +1,40 @@ +from typing import Any +from polywrap_core import ( + Client, + Uri, + get_env_from_resolution_path, +) +import pytest + + +@pytest.fixture +def resolution_path() -> list[Any]: + return [ + Uri.from_str("test/1"), + Uri.from_str("test/2"), + Uri.from_str("test/3"), + ] + + +@pytest.fixture +def client() -> Any: + class MockClient: + def get_env_by_uri(self, uri: Uri) -> Any: + if uri.uri == "wrap://test/3": + return { + "arg1": "arg1", + "arg2": "arg2", + } + + return MockClient() + + +def test_get_env_from_resolution_path(resolution_path: list[Any], client: Client): + assert get_env_from_resolution_path(resolution_path, client) == { + "arg1": "arg1", + "arg2": "arg2", + } + + +def test_get_env_from_resolution_path_empty(client: Client): + assert get_env_from_resolution_path([], client) is None diff --git a/packages/polywrap-core/tests/test_get_implementations.py b/packages/polywrap-core/tests/test_get_implementations.py new file mode 100644 index 00000000..b8e3cd84 --- /dev/null +++ b/packages/polywrap-core/tests/test_get_implementations.py @@ -0,0 +1,79 @@ +from polywrap_core import ( + Any, + Client, + Uri, + get_implementations, +) +import pytest + +interface_1 = Uri.from_str("wrap://ens/interface-1.eth") +interface_2 = Uri.from_str("wrap://ens/interface-2.eth") +interface_3 = Uri.from_str("wrap://ens/interface-3.eth") + +implementation_1 = Uri.from_str("wrap://ens/implementation-1.eth") +implementation_2 = Uri.from_str("wrap://ens/implementation-2.eth") +implementation_3 = Uri.from_str("wrap://ens/implementation-3.eth") + + +redirects = { + interface_1: interface_2, + implementation_1: implementation_2, + implementation_2: implementation_3, +} + +interfaces = { + interface_1: [implementation_1, implementation_2], + interface_2: [implementation_3], + interface_3: [implementation_3], +} + + +@pytest.fixture +def client() -> Any: + class MockClient: + def try_resolve_uri(self, uri: Uri, *args: Any) -> Uri: + return redirects.get(uri, uri) + + return MockClient() + + +def test_get_implementations_1(client: Client): + result = get_implementations(interface_1, interfaces, client) + + assert result + assert set(result) == { + implementation_1, + implementation_2, + implementation_3, + } + + +def test_get_implementations_2(client: Client): + result = get_implementations(interface_2, interfaces, client) + + assert result + assert set(result) == { + implementation_1, + implementation_2, + implementation_3, + } + + +def test_get_implementations_3(client: Client): + result = get_implementations(interface_3, interfaces, client) + + assert result + assert set(result) == { + implementation_3, + } + + +def test_implementations_not_redirected(client: Client): + result = get_implementations(interface_1, { + interface_1: [implementation_1], + }, client) + + assert result + assert set(result) == { + implementation_1, + } \ No newline at end of file diff --git a/packages/polywrap-core/tests/test_maybe_async.py b/packages/polywrap-core/tests/test_maybe_async.py deleted file mode 100644 index 6e3323f9..00000000 --- a/packages/polywrap-core/tests/test_maybe_async.py +++ /dev/null @@ -1,27 +0,0 @@ -import inspect - -import pytest - -from polywrap_core import execute_maybe_async_function, is_coroutine - - -@pytest.mark.asyncio -async def test_sanity(): - async def coroutine(): - pass - - def test_function(): - pass - - async def test_function_return_promise(): - pass - - test_coroutine_resp = coroutine() - test_function_resp = execute_maybe_async_function(test_function) - test_function_return_promise_resp = execute_maybe_async_function(test_function_return_promise) - assert is_coroutine(test_coroutine_resp) - assert inspect.iscoroutine(test_function_resp) - assert inspect.iscoroutine(test_function_return_promise_resp) - await test_coroutine_resp - await test_function_resp - await test_function_return_promise_resp From 011ebf991d28bc1538b31c0799fb9c6360f38ff4 Mon Sep 17 00:00:00 2001 From: Niraj Kamdar Date: Tue, 6 Jun 2023 02:29:00 +0530 Subject: [PATCH 04/47] refactor: polywrap-core docs --- .../polywrap_core/types/client.py | 2 +- .../polywrap-core/polywrap_core/types/uri.py | 4 +-- .../polywrap_core/types/uri_package.py | 4 +-- .../types/uri_resolution_context.py | 26 ++++++++++++------- .../polywrap_core/types/uri_resolver.py | 8 +++--- .../polywrap_core/types/uri_wrapper.py | 4 +-- .../polywrap_core/types/wrap_package.py | 2 +- 7 files changed, 29 insertions(+), 21 deletions(-) diff --git a/packages/polywrap-core/polywrap_core/types/client.py b/packages/polywrap-core/polywrap_core/types/client.py index eecdfda9..5df1f119 100644 --- a/packages/polywrap-core/polywrap_core/types/client.py +++ b/packages/polywrap-core/polywrap_core/types/client.py @@ -46,7 +46,7 @@ def get_uri_resolver(self) -> UriResolver: """Get URI resolver. Returns: - IUriResolver: URI resolver. + UriResolver: URI resolver. """ ... diff --git a/packages/polywrap-core/polywrap_core/types/uri.py b/packages/polywrap-core/polywrap_core/types/uri.py index ba97e2d1..425b7a9a 100644 --- a/packages/polywrap-core/polywrap_core/types/uri.py +++ b/packages/polywrap-core/polywrap_core/types/uri.py @@ -62,8 +62,8 @@ def __init__(self, authority: str, path: str): """Initialize a new instance of a wrapper URI. Args: - authority: The authority of the URI. - path: The path of the URI. + authority (str): The authority of the URI. + path (str): The path of the URI. """ self._authority = authority self._path = path diff --git a/packages/polywrap-core/polywrap_core/types/uri_package.py b/packages/polywrap-core/polywrap_core/types/uri_package.py index c512861b..63b61948 100644 --- a/packages/polywrap-core/polywrap_core/types/uri_package.py +++ b/packages/polywrap-core/polywrap_core/types/uri_package.py @@ -12,8 +12,8 @@ class UriPackage: """UriPackage is a dataclass that contains a URI and a package. Attributes: - uri: The URI. - package: The package. + uri (Uri): The URI. + package (Package): The package. """ uri: Uri diff --git a/packages/polywrap-core/polywrap_core/types/uri_resolution_context.py b/packages/polywrap-core/polywrap_core/types/uri_resolution_context.py index 7b3e9f94..4b852595 100644 --- a/packages/polywrap-core/polywrap_core/types/uri_resolution_context.py +++ b/packages/polywrap-core/polywrap_core/types/uri_resolution_context.py @@ -9,9 +9,12 @@ class UriResolutionContext: """Represents the context of a uri resolution. Attributes: - resolving_uri_set: A set of uris that are currently being resolved. - resolution_path: A list of uris in the order that they are being resolved. - history: A list of steps that have been taken to resolve the uri. + resolving_uri_set (Set[Uri]): A set of uris that\ + are currently being resolved. + resolution_path (List[Uri]): A list of uris in the order that\ + they are being resolved. + history (List[UriResolutionStep]): A list of steps \ + that have been taken to resolve the uri. """ resolving_uri_set: Set[Uri] @@ -29,9 +32,12 @@ def __init__( """Initialize a new instance of UriResolutionContext. Args: - resolving_uri_set: A set of uris that are currently being resolved. - resolution_path: A list of uris in the order that they are being resolved. - history: A list of steps that have been taken to resolve the uri. + resolving_uri_set (Optional[Set[Uri]]): A set of uris that\ + are currently being resolved. + resolution_path (Optional[List[Uri]]): A list of uris in the order that\ + they are being resolved. + history (Optional[List[UriResolutionStep]]): A list of steps \ + that have been taken to resolve the uri. """ self.resolving_uri_set = resolving_uri_set or set() self.resolution_path = resolution_path or [] @@ -41,7 +47,7 @@ def is_resolving(self, uri: Uri) -> bool: """Check if the given uri is currently being resolved. Args: - uri: The uri to check. + uri (Uri): The uri to check. Returns: bool: True if the uri is currently being resolved, otherwise False. @@ -52,7 +58,7 @@ def start_resolving(self, uri: Uri) -> None: """Start resolving the given uri. Args: - uri: The uri to start resolving. + uri (Uri): The uri to start resolving. Returns: None """ @@ -63,7 +69,7 @@ def stop_resolving(self, uri: Uri) -> None: """Stop resolving the given uri. Args: - uri: The uri to stop resolving. + uri (Uri): The uri to stop resolving. Returns: None """ @@ -73,7 +79,7 @@ def track_step(self, step: UriResolutionStep) -> None: """Track the given step in the resolution history. Args: - step: The step to track. + step (UriResolutionStep): The step to track. Returns: None """ diff --git a/packages/polywrap-core/polywrap_core/types/uri_resolver.py b/packages/polywrap-core/polywrap_core/types/uri_resolver.py index f80534a8..0de1f60a 100644 --- a/packages/polywrap-core/polywrap_core/types/uri_resolver.py +++ b/packages/polywrap-core/polywrap_core/types/uri_resolver.py @@ -21,9 +21,11 @@ def try_resolve_uri( """Try to resolve a uri. Args: - uri: The uri to resolve. - client: The minimal invoker client to use for resolving the uri. - resolution_context: The context for resolving the uri. + uri (Uri): The uri to resolve. + client (InvokerClient): The minimal invoker client \ + to use for resolving the uri. + resolution_context (UriResolutionContext): The context \ + for resolving the uri. Returns: UriPackageOrWrapper: result of the URI resolution. diff --git a/packages/polywrap-core/polywrap_core/types/uri_wrapper.py b/packages/polywrap-core/polywrap_core/types/uri_wrapper.py index 44c83b07..8930220e 100644 --- a/packages/polywrap-core/polywrap_core/types/uri_wrapper.py +++ b/packages/polywrap-core/polywrap_core/types/uri_wrapper.py @@ -12,8 +12,8 @@ class UriWrapper: """UriWrapper is a dataclass that contains a URI and a wrapper. Attributes: - uri: The URI. - wrapper: The wrapper. + uri (Uri): The URI. + wrapper (Wrapper): The wrapper. """ uri: Uri diff --git a/packages/polywrap-core/polywrap_core/types/wrap_package.py b/packages/polywrap-core/polywrap_core/types/wrap_package.py index 648087c3..e9f4b30e 100644 --- a/packages/polywrap-core/polywrap_core/types/wrap_package.py +++ b/packages/polywrap-core/polywrap_core/types/wrap_package.py @@ -25,7 +25,7 @@ def get_manifest( """Get the manifest from the wrapper package. Args: - options: The options for getting the manifest. + options (DeserializeManifestOptions): The options for getting the manifest. Returns: AnyWrapManifest: The manifest of the wrapper. From 773f10b336d8110cc1ba8517ac4427ba71a3c50c Mon Sep 17 00:00:00 2001 From: Niraj Kamdar Date: Tue, 6 Jun 2023 02:11:03 +0530 Subject: [PATCH 05/47] refactor: polywrap-wasm package --- .../polywrap-wasm/polywrap_wasm/__init__.py | 3 - .../polywrap-wasm/polywrap_wasm/constants.py | 2 + .../polywrap-wasm/polywrap_wasm/errors.py | 7 ++ .../imports/get_implementations.py | 15 ++++- .../polywrap_wasm/imports/subinvoke.py | 30 ++++----- .../imports/types/base_wrap_imports.py | 5 +- .../polywrap_wasm/imports/utils/__init__.py | 2 - .../imports/utils/unsync_invoke.py | 13 ---- .../polywrap_wasm/imports/wrap_imports.py | 6 +- .../polywrap_wasm/inmemory_file_reader.py | 7 +- .../polywrap-wasm/polywrap_wasm/instance.py | 6 +- .../polywrap_wasm/types/state.py | 25 ++++++- .../polywrap_wasm/wasm_package.py | 33 ++++----- .../polywrap_wasm/wasm_wrapper.py | 67 +++++++++++-------- .../polywrap-wasm/tests/test_wasm_wrapper.py | 60 +++++++++++------ 15 files changed, 169 insertions(+), 112 deletions(-) delete mode 100644 packages/polywrap-wasm/polywrap_wasm/imports/utils/__init__.py delete mode 100644 packages/polywrap-wasm/polywrap_wasm/imports/utils/unsync_invoke.py diff --git a/packages/polywrap-wasm/polywrap_wasm/__init__.py b/packages/polywrap-wasm/polywrap_wasm/__init__.py index efc5276d..978aa2e1 100644 --- a/packages/polywrap-wasm/polywrap_wasm/__init__.py +++ b/packages/polywrap-wasm/polywrap_wasm/__init__.py @@ -1,8 +1,5 @@ """This module contains the runtime for executing Wasm wrappers.""" -from .buffer import * from .errors import * -from .exports import * -from .imports import * from .inmemory_file_reader import * from .wasm_package import * from .wasm_wrapper import * diff --git a/packages/polywrap-wasm/polywrap_wasm/constants.py b/packages/polywrap-wasm/polywrap_wasm/constants.py index 7645df03..3fcc99cd 100644 --- a/packages/polywrap-wasm/polywrap_wasm/constants.py +++ b/packages/polywrap-wasm/polywrap_wasm/constants.py @@ -1,3 +1,5 @@ """This module contains the constants used by polywrap-wasm package.""" WRAP_MANIFEST_PATH = "wrap.info" WRAP_MODULE_PATH = "wrap.wasm" + +__all__ = ["WRAP_MANIFEST_PATH", "WRAP_MODULE_PATH"] diff --git a/packages/polywrap-wasm/polywrap_wasm/errors.py b/packages/polywrap-wasm/polywrap_wasm/errors.py index 31b9bae9..07a6b58f 100644 --- a/packages/polywrap-wasm/polywrap_wasm/errors.py +++ b/packages/polywrap-wasm/polywrap_wasm/errors.py @@ -12,3 +12,10 @@ class WasmExportNotFoundError(WasmError): class WasmMemoryError(WasmError): """Raises when the Wasm memory is not found.""" + + +__all__ = [ + "WasmError", + "WasmExportNotFoundError", + "WasmMemoryError", +] diff --git a/packages/polywrap-wasm/polywrap_wasm/imports/get_implementations.py b/packages/polywrap-wasm/polywrap_wasm/imports/get_implementations.py index 3ecd35f6..994ff671 100644 --- a/packages/polywrap-wasm/polywrap_wasm/imports/get_implementations.py +++ b/packages/polywrap-wasm/polywrap_wasm/imports/get_implementations.py @@ -24,6 +24,11 @@ def wrap_get_implementations(self, uri_ptr: int, uri_len: int) -> bool: uri_len, ) ) + if not self.invoker: + raise WrapAbortError( + invoke_options=self.state.invoke_options, + message="Expected invoker to be defined got None", + ) try: maybe_implementations = self.invoker.get_implementations(uri=uri) implementations: List[str] = ( @@ -35,8 +40,8 @@ def wrap_get_implementations(self, uri_ptr: int, uri_len: int) -> bool: return len(implementations) > 0 except Exception as err: raise WrapAbortError( - self.state.invoke_options, - f"failed calling invoker.get_implementations({repr(uri)})", + invoke_options=self.state.invoke_options, + message=f"failed calling invoker.get_implementations({repr(uri)})", ) from err def wrap_get_implementations_result_len(self) -> int: @@ -59,6 +64,12 @@ def wrap_get_implementations_result(self, ptr: int) -> None: self.write_bytes(ptr, result) def _get_get_implementations_result(self, export_name: str): + if not self.invoker: + raise WrapAbortError( + invoke_options=self.state.invoke_options, + message="Expected invoker to be defined got None", + ) + if not self.state.get_implementations_result: raise WrapAbortError( self.state.invoke_options, diff --git a/packages/polywrap-wasm/polywrap_wasm/imports/subinvoke.py b/packages/polywrap-wasm/polywrap_wasm/imports/subinvoke.py index 78ecd91f..a1cdd5aa 100644 --- a/packages/polywrap-wasm/polywrap_wasm/imports/subinvoke.py +++ b/packages/polywrap-wasm/polywrap_wasm/imports/subinvoke.py @@ -1,15 +1,10 @@ """This module contains the subinvoke imports for the Wasm module.""" -import asyncio -from concurrent.futures import ThreadPoolExecutor - -from polywrap_core import InvokerOptions, Uri, WrapAbortError +from polywrap_core import Uri, WrapAbortError from polywrap_msgpack import msgpack_encode from ..types import InvokeResult from .types import BaseWrapImports -pool = ThreadPoolExecutor() - class WrapSubinvokeImports(BaseWrapImports): """Defines the subinvoke family of imports for the Wasm module.""" @@ -42,18 +37,19 @@ def wrap_subinvoke( method = self._get_subinvoke_method(method_ptr, method_len) args = self._get_subinvoke_args(args_ptr, args_len) + if not self.invoker: + raise WrapAbortError( + invoke_options=self.state.invoke_options, + message="Expected invoker to be defined got None", + ) + try: - result = pool.submit( - asyncio.run, - self.invoker.invoke( - InvokerOptions( - uri=uri, - method=method, - args=args, - encode_result=True, - ) - ), - ).result() + result = self.invoker.invoke( + uri=uri, + method=method, + args=args, + encode_result=True, + ) if isinstance(result, bytes): self.state.subinvoke_result = InvokeResult(result=result) return True diff --git a/packages/polywrap-wasm/polywrap_wasm/imports/types/base_wrap_imports.py b/packages/polywrap-wasm/polywrap_wasm/imports/types/base_wrap_imports.py index 58d4192e..46e7d9fc 100644 --- a/packages/polywrap-wasm/polywrap_wasm/imports/types/base_wrap_imports.py +++ b/packages/polywrap-wasm/polywrap_wasm/imports/types/base_wrap_imports.py @@ -2,8 +2,9 @@ from __future__ import annotations from abc import ABC +from typing import Optional -from polywrap_core import Invoker, UriPackageOrWrapper +from polywrap_core import Invoker from wasmtime import Memory, Store from ...buffer import read_bytes, read_string, write_bytes, write_string @@ -16,7 +17,7 @@ class BaseWrapImports(ABC): memory: Memory store: Store state: State - invoker: Invoker[UriPackageOrWrapper] + invoker: Optional[Invoker] def read_string(self, ptr: int, length: int) -> str: """Read a UTF-8 encoded string from the memory buffer.""" diff --git a/packages/polywrap-wasm/polywrap_wasm/imports/utils/__init__.py b/packages/polywrap-wasm/polywrap_wasm/imports/utils/__init__.py deleted file mode 100644 index bcc32367..00000000 --- a/packages/polywrap-wasm/polywrap_wasm/imports/utils/__init__.py +++ /dev/null @@ -1,2 +0,0 @@ -"""This module contains utility functions for the Wasm imports.""" -from .unsync_invoke import * diff --git a/packages/polywrap-wasm/polywrap_wasm/imports/utils/unsync_invoke.py b/packages/polywrap-wasm/polywrap_wasm/imports/utils/unsync_invoke.py deleted file mode 100644 index 600a5c59..00000000 --- a/packages/polywrap-wasm/polywrap_wasm/imports/utils/unsync_invoke.py +++ /dev/null @@ -1,13 +0,0 @@ -"""This module contains the unsync_invoke function.""" -from typing import Any - -from polywrap_core import Invoker, InvokerOptions, UriPackageOrWrapper -from unsync import Unfuture, unsync - - -@unsync -async def unsync_invoke( - invoker: Invoker[UriPackageOrWrapper], options: InvokerOptions[UriPackageOrWrapper] -) -> Unfuture[Any]: - """Perform an unsync invoke call.""" - return await invoker.invoke(options) diff --git a/packages/polywrap-wasm/polywrap_wasm/imports/wrap_imports.py b/packages/polywrap-wasm/polywrap_wasm/imports/wrap_imports.py index afefacfa..7246dbf6 100644 --- a/packages/polywrap-wasm/polywrap_wasm/imports/wrap_imports.py +++ b/packages/polywrap-wasm/polywrap_wasm/imports/wrap_imports.py @@ -3,7 +3,9 @@ # pylint: disable=too-many-ancestors from __future__ import annotations -from polywrap_core import Invoker, UriPackageOrWrapper +from typing import Optional + +from polywrap_core import Invoker from wasmtime import Memory, Store from ..types.state import State @@ -39,7 +41,7 @@ def __init__( memory: Memory, store: Store, state: State, - invoker: Invoker[UriPackageOrWrapper], + invoker: Optional[Invoker], ) -> None: """Initialize the WrapImports instance. diff --git a/packages/polywrap-wasm/polywrap_wasm/inmemory_file_reader.py b/packages/polywrap-wasm/polywrap_wasm/inmemory_file_reader.py index ea3d466f..da5c90d5 100644 --- a/packages/polywrap-wasm/polywrap_wasm/inmemory_file_reader.py +++ b/packages/polywrap-wasm/polywrap_wasm/inmemory_file_reader.py @@ -31,7 +31,7 @@ def __init__( self._wasm_manifest = wasm_manifest self._base_file_reader = base_file_reader - async def read_file(self, file_path: str) -> bytes: + def read_file(self, file_path: str) -> bytes: """Read a file from memory. Args: @@ -44,4 +44,7 @@ async def read_file(self, file_path: str) -> bytes: return self._wasm_module if file_path == WRAP_MANIFEST_PATH and self._wasm_manifest: return self._wasm_manifest - return await self._base_file_reader.read_file(file_path=file_path) + return self._base_file_reader.read_file(file_path=file_path) + + +__all__ = ["InMemoryFileReader"] diff --git a/packages/polywrap-wasm/polywrap_wasm/instance.py b/packages/polywrap-wasm/polywrap_wasm/instance.py index 0028cbb1..c1f4de53 100644 --- a/packages/polywrap-wasm/polywrap_wasm/instance.py +++ b/packages/polywrap-wasm/polywrap_wasm/instance.py @@ -1,5 +1,7 @@ """This module contains the imports of the Wasm wrapper module.""" -from polywrap_core import Invoker, UriPackageOrWrapper +from typing import Optional + +from polywrap_core import Invoker from wasmtime import Instance, Linker, Module, Store from .imports import WrapImports @@ -12,7 +14,7 @@ def create_instance( store: Store, module: bytes, state: State, - invoker: Invoker[UriPackageOrWrapper], + invoker: Optional[Invoker], ) -> Instance: """Create a Wasm instance for a Wasm module. diff --git a/packages/polywrap-wasm/polywrap_wasm/types/state.py b/packages/polywrap-wasm/polywrap_wasm/types/state.py index d9e18e5d..a09ecad6 100644 --- a/packages/polywrap-wasm/polywrap_wasm/types/state.py +++ b/packages/polywrap-wasm/polywrap_wasm/types/state.py @@ -1,12 +1,31 @@ """This module contains the State type for holding the state of a Wasm wrapper.""" from dataclasses import dataclass -from typing import Generic, Optional, TypeVar +from typing import Any, Generic, Optional, TypeVar -from polywrap_core import InvokeOptions, UriPackageOrWrapper +from polywrap_core import Uri, UriResolutionContext E = TypeVar("E") +@dataclass(kw_only=True, slots=True) +class InvokeOptions: + """InvokeOptions is a dataclass that holds the options for an invocation. + + Attributes: + uri: The URI of the wrapper. + method: The method to invoke. + args: The arguments to pass to the method. + env: The environment variables to set for the invocation. + resolution_context: A URI resolution context. + """ + + uri: Uri + method: str + args: Optional[dict[str, Any]] = None + env: Optional[dict[str, Any]] = None + resolution_context: Optional[UriResolutionContext] = None + + @dataclass(kw_only=True, slots=True) class InvokeResult(Generic[E]): """InvokeResult is a dataclass that holds the result of an invocation. @@ -39,7 +58,7 @@ class State: get_implementations_result: The result of a get implementations call. """ - invoke_options: InvokeOptions[UriPackageOrWrapper] + invoke_options: InvokeOptions invoke_result: Optional[InvokeResult[str]] = None subinvoke_result: Optional[InvokeResult[Exception]] = None get_implementations_result: Optional[bytes] = None diff --git a/packages/polywrap-wasm/polywrap_wasm/wasm_package.py b/packages/polywrap-wasm/polywrap_wasm/wasm_package.py index 55f43d62..7ab92c74 100644 --- a/packages/polywrap-wasm/polywrap_wasm/wasm_package.py +++ b/packages/polywrap-wasm/polywrap_wasm/wasm_package.py @@ -1,21 +1,19 @@ """This module contains the WasmPackage type for loading a Wasm package.""" from typing import Optional, Union -from polywrap_core import ( - FileReader, - GetManifestOptions, - UriPackageOrWrapper, - WrapPackage, - Wrapper, +from polywrap_core import FileReader, WrapPackage, Wrapper +from polywrap_manifest import ( + AnyWrapManifest, + DeserializeManifestOptions, + deserialize_wrap_manifest, ) -from polywrap_manifest import AnyWrapManifest, deserialize_wrap_manifest from .constants import WRAP_MANIFEST_PATH, WRAP_MODULE_PATH from .inmemory_file_reader import InMemoryFileReader from .wasm_wrapper import WasmWrapper -class WasmPackage(WrapPackage[UriPackageOrWrapper]): +class WasmPackage(WrapPackage): """WasmPackage is a type that represents a Wasm WRAP package. Attributes: @@ -43,8 +41,8 @@ def __init__( else file_reader ) - async def get_manifest( - self, options: Optional[GetManifestOptions] = None + def get_manifest( + self, options: Optional[DeserializeManifestOptions] = None ) -> AnyWrapManifest: """Get the manifest of the wrapper. @@ -54,13 +52,13 @@ async def get_manifest( if isinstance(self.manifest, AnyWrapManifest): return self.manifest - encoded_manifest = self.manifest or await self.file_reader.read_file( + encoded_manifest = self.manifest or self.file_reader.read_file( WRAP_MANIFEST_PATH ) manifest = deserialize_wrap_manifest(encoded_manifest, options) return manifest - async def get_wasm_module(self) -> bytes: + def get_wasm_module(self) -> bytes: """Get the Wasm module of the wrapper if it exists or return an error. Returns: @@ -69,13 +67,16 @@ async def get_wasm_module(self) -> bytes: if isinstance(self.wasm_module, bytes): return self.wasm_module - wasm_module = await self.file_reader.read_file(WRAP_MODULE_PATH) + wasm_module = self.file_reader.read_file(WRAP_MODULE_PATH) self.wasm_module = wasm_module return self.wasm_module - async def create_wrapper(self) -> Wrapper[UriPackageOrWrapper]: + def create_wrapper(self) -> Wrapper: """Create a new WasmWrapper instance.""" - wasm_module = await self.get_wasm_module() - wasm_manifest = await self.get_manifest() + wasm_module = self.get_wasm_module() + wasm_manifest = self.get_manifest() return WasmWrapper(self.file_reader, wasm_module, wasm_manifest) + + +__all__ = ["WasmPackage"] diff --git a/packages/polywrap-wasm/polywrap_wasm/wasm_wrapper.py b/packages/polywrap-wasm/polywrap_wasm/wasm_wrapper.py index 00ad2a12..a15fab67 100644 --- a/packages/polywrap-wasm/polywrap_wasm/wasm_wrapper.py +++ b/packages/polywrap-wasm/polywrap_wasm/wasm_wrapper.py @@ -1,14 +1,14 @@ """This module contains the WasmWrapper class for invoking Wasm wrappers.""" +# pylint: disable=too-many-locals from textwrap import dedent -from typing import Union +from typing import Any, Dict, Optional, Union from polywrap_core import ( FileReader, - GetFileOptions, InvocableResult, - InvokeOptions, Invoker, - UriPackageOrWrapper, + Uri, + UriResolutionContext, WrapAbortError, WrapError, Wrapper, @@ -19,10 +19,10 @@ from .exports import WrapExports from .instance import create_instance -from .types.state import State +from .types.state import InvokeOptions, State -class WasmWrapper(Wrapper[UriPackageOrWrapper]): +class WasmWrapper(Wrapper): """WasmWrapper implements the Wrapper interface for Wasm wrappers. Attributes: @@ -51,7 +51,9 @@ def get_wasm_module(self) -> bytes: """Get the Wasm module of the wrapper.""" return self.wasm_module - async def get_file(self, options: GetFileOptions) -> Union[str, bytes]: + def get_file( + self, path: str, encoding: Optional[str] = "utf-8" + ) -> Union[str, bytes]: """Get a file from the wrapper. Args: @@ -60,59 +62,67 @@ async def get_file(self, options: GetFileOptions) -> Union[str, bytes]: Returns: The file contents as string or bytes according to encoding or an error. """ - data = await self.file_reader.read_file(options.path) - return data.decode(encoding=options.encoding) if options.encoding else data + data = self.file_reader.read_file(path) + return data.decode(encoding=encoding) if encoding else data def create_wasm_instance( - self, - store: Store, - state: State, - invoker: Invoker[UriPackageOrWrapper], - options: InvokeOptions[UriPackageOrWrapper], + self, store: Store, state: State, client: Optional[Invoker] ) -> Instance: """Create a new Wasm instance for the wrapper. Args: store: The Wasm store to use when creating the instance. state: The Wasm wrapper state to use when creating the instance. - invoker: The invoker to use when creating the instance. + client: The client to use when creating the instance. Returns: The Wasm instance of the wrapper Wasm module. """ try: - return create_instance(store, self.wasm_module, state, invoker) + return create_instance(store, self.wasm_module, state, client) except Exception as err: raise WrapAbortError( - options, "Unable to instantiate the wasm module" + state.invoke_options, "Unable to instantiate the wasm module" ) from err - async def invoke( + def invoke( self, - options: InvokeOptions[UriPackageOrWrapper], - invoker: Invoker[UriPackageOrWrapper], + uri: Uri, + method: str, + args: Optional[Dict[str, Any]] = None, + env: Optional[Dict[str, Any]] = None, + resolution_context: Optional[UriResolutionContext] = None, + client: Optional[Invoker] = None, ) -> InvocableResult: """Invoke the wrapper. Args: options: The options to use when invoking the wrapper. - invoker: The invoker to use when invoking the wrapper. + client: The client to use when invoking the wrapper. Returns: The result of the invocation or an error. """ - if not (options.uri and options.method): + if not (uri and method): raise WrapError( dedent( f""" Expected invocation uri and method to be defiened got: - uri: {options.uri} - method: {options.method} + uri: {uri} + method: {method} """ ) ) - state = State(invoke_options=options) + state = State( + invoke_options=InvokeOptions( + uri=uri, + method=method, + args=args, + env=env, + resolution_context=resolution_context, + ) + ) encoded_args = ( state.invoke_options.args @@ -126,7 +136,7 @@ async def invoke( env_length = len(encoded_env) store = Store() - instance = self.create_wasm_instance(store, state, invoker, options) + instance = self.create_wasm_instance(store, state, client) exports = WrapExports(instance, store) result = exports.__wrap_invoke__(method_length, args_length, env_length) @@ -135,6 +145,9 @@ async def invoke( # Note: currently we only return not None result from Wasm module return InvocableResult(result=state.invoke_result.result, encoded=True) raise WrapAbortError( - options, + state.invoke_options, "Expected a result from the Wasm module", ) + + +__all__ = ["WasmWrapper"] diff --git a/packages/polywrap-wasm/tests/test_wasm_wrapper.py b/packages/polywrap-wasm/tests/test_wasm_wrapper.py index fe202feb..0ec2b998 100644 --- a/packages/polywrap-wasm/tests/test_wasm_wrapper.py +++ b/packages/polywrap-wasm/tests/test_wasm_wrapper.py @@ -1,22 +1,27 @@ -from typing import Any, List, cast +from typing import Any, cast import pytest from pathlib import Path from polywrap_msgpack import msgpack_decode -from polywrap_core import Uri, InvokeOptions, Invoker, InvokerOptions, UriPackageOrWrapper -from polywrap_wasm import FileReader, WasmPackage, WasmWrapper, WRAP_MODULE_PATH +from polywrap_core import InvokerClient, Uri, Invoker, FileReader +from polywrap_wasm import WasmPackage, WasmWrapper +from polywrap_wasm.constants import WRAP_MODULE_PATH, WRAP_MANIFEST_PATH from polywrap_manifest import deserialize_wrap_manifest -from polywrap_wasm.constants import WRAP_MANIFEST_PATH + @pytest.fixture def mock_invoker(): - class MockInvoker(Invoker[UriPackageOrWrapper]): - async def invoke(self, options: InvokerOptions[UriPackageOrWrapper]) -> Any: + class MockInvoker(InvokerClient): + + def try_resolve_uri(self, *args: Any, **kwargs: Any) -> Any: raise NotImplementedError() - - def get_implementations(self, uri: Uri) -> List[Uri]: + + def invoke(self, *args: Any, **kwargs: Any) -> Any: + raise NotImplementedError() + + def get_implementations(self, *args: Any, **kwargs: Any) -> Any: raise NotImplementedError() return MockInvoker() @@ -39,7 +44,7 @@ def simple_wrap_manifest(): @pytest.fixture def dummy_file_reader(): class DummyFileReader(FileReader): - async def read_file(self, file_path: str) -> bytes: + def read_file(self, *args: Any, **kwargs: Any) -> bytes: raise NotImplementedError() yield DummyFileReader() @@ -48,7 +53,7 @@ async def read_file(self, file_path: str) -> bytes: @pytest.fixture def simple_file_reader(simple_wrap_module: bytes, simple_wrap_manifest: bytes): class DummyFileReader(FileReader): - async def read_file(self, file_path: str) -> bytes: + def read_file(self, file_path: str) -> bytes: if file_path == WRAP_MODULE_PATH: return simple_wrap_module if file_path == WRAP_MANIFEST_PATH: @@ -58,28 +63,41 @@ async def read_file(self, file_path: str) -> bytes: yield DummyFileReader() -@pytest.mark.asyncio -async def test_invoke_with_wrapper( - dummy_file_reader: FileReader, simple_wrap_module: bytes, simple_wrap_manifest: bytes, mock_invoker: Invoker[UriPackageOrWrapper] +def test_invoke_with_wrapper( + dummy_file_reader: FileReader, + simple_wrap_module: bytes, + simple_wrap_manifest: bytes, + mock_invoker: Invoker, ): - wrapper = WasmWrapper(dummy_file_reader, simple_wrap_module, deserialize_wrap_manifest(simple_wrap_manifest)) + wrapper = WasmWrapper( + dummy_file_reader, + simple_wrap_module, + deserialize_wrap_manifest(simple_wrap_manifest), + ) message = "hey" args = {"arg": message} - options: InvokeOptions[UriPackageOrWrapper] = InvokeOptions(uri=Uri.from_str("fs/./build"), method="simpleMethod", args=args) - result = await wrapper.invoke(options, mock_invoker) + result = wrapper.invoke( + uri=Uri.from_str("fs/./build"), + method="simpleMethod", + args=args, + client=mock_invoker, + ) assert result.encoded is True assert msgpack_decode(cast(bytes, result.result)) == message -@pytest.mark.asyncio -async def test_invoke_with_package(simple_file_reader: FileReader, mock_invoker: Invoker[UriPackageOrWrapper]): +def test_invoke_with_package(simple_file_reader: FileReader, mock_invoker: InvokerClient): package = WasmPackage(simple_file_reader) - wrapper = await package.create_wrapper() + wrapper = package.create_wrapper() message = "hey" args = {"arg": message} - options: InvokeOptions[UriPackageOrWrapper] = InvokeOptions(uri=Uri.from_str("fs/./build"), method="simpleMethod", args=args) - result = await wrapper.invoke(options, mock_invoker) + result = wrapper.invoke( + uri=Uri.from_str("fs/./build"), + method="simpleMethod", + args=args, + client=mock_invoker, + ) assert result.encoded is True assert msgpack_decode(cast(bytes, result.result)) == message From c7a63177327799fd0a9b11ce34777a8d32050fde Mon Sep 17 00:00:00 2001 From: Niraj Kamdar Date: Tue, 6 Jun 2023 02:23:27 +0530 Subject: [PATCH 06/47] refactor: polywrap-plugin package --- .../node_modules/.yarn-integrity | 30 ----- packages/polywrap-plugin/poetry.lock | 111 +++++++++--------- .../polywrap-plugin/polywrap_plugin/module.py | 49 +++++--- .../polywrap_plugin/package.py | 15 ++- .../resolution_context_override_client.py | 84 +++++++++++++ .../polywrap_plugin/wrapper.py | 64 +++++++--- packages/polywrap-plugin/pyproject.toml | 1 + packages/polywrap-plugin/tests/conftest.py | 12 +- .../tests/test_plugin_module.py | 14 +-- .../tests/test_plugin_package.py | 24 ++-- .../tests/test_plugin_wrapper.py | 23 ++-- 11 files changed, 262 insertions(+), 165 deletions(-) delete mode 100644 packages/polywrap-plugin/node_modules/.yarn-integrity create mode 100644 packages/polywrap-plugin/polywrap_plugin/resolution_context_override_client.py diff --git a/packages/polywrap-plugin/node_modules/.yarn-integrity b/packages/polywrap-plugin/node_modules/.yarn-integrity deleted file mode 100644 index 103d87c5..00000000 --- a/packages/polywrap-plugin/node_modules/.yarn-integrity +++ /dev/null @@ -1,30 +0,0 @@ -{ - "systemParams": "darwin-arm64-93", - "modulesFolders": [], - "flags": [], - "linkedModules": [ - "@coordinape/hardhat", - "@polywrap/client-js", - "@polywrap/core-js", - "@polywrap/msgpack-js", - "@polywrap/polywrap-manifest-types-js", - "@polywrap/schema-bind", - "@polywrap/schema-compose", - "@polywrap/schema-parse", - "@polywrap/wrap-manifest-types-js", - "@web3api/cli", - "@web3api/client-js", - "@web3api/core-js", - "@web3api/ethereum-plugin-js", - "@web3api/ipfs-plugin-js", - "@web3api/schema-bind", - "@web3api/schema-compose", - "@web3api/test-env-js", - "@web3api/wasm-as", - "polywrap" - ], - "topLevelPatterns": [], - "lockfileEntries": {}, - "files": [], - "artifacts": {} -} \ No newline at end of file diff --git a/packages/polywrap-plugin/poetry.lock b/packages/polywrap-plugin/poetry.lock index 8a7257a8..97b7dda8 100644 --- a/packages/polywrap-plugin/poetry.lock +++ b/packages/polywrap-plugin/poetry.lock @@ -1,15 +1,15 @@ -# This file is automatically @generated by Poetry 1.4.2 and should not be changed by hand. +# This file is automatically @generated by Poetry and should not be changed by hand. [[package]] name = "astroid" -version = "2.15.4" +version = "2.15.5" description = "An abstract syntax tree for Python with inference support." category = "dev" optional = false python-versions = ">=3.7.2" files = [ - {file = "astroid-2.15.4-py3-none-any.whl", hash = "sha256:a1b8543ef9d36ea777194bc9b17f5f8678d2c56ee6a45b2c2f17eec96f242347"}, - {file = "astroid-2.15.4.tar.gz", hash = "sha256:c81e1c7fbac615037744d067a9bb5f9aeb655edf59b63ee8b59585475d6f80d8"}, + {file = "astroid-2.15.5-py3-none-any.whl", hash = "sha256:078e5212f9885fa85fbb0cf0101978a336190aadea6e13305409d099f71b2324"}, + {file = "astroid-2.15.5.tar.gz", hash = "sha256:1039262575027b441137ab4a62a793a9b43defb42c32d5670f38686207cd780f"}, ] [package.dependencies] @@ -273,42 +273,41 @@ files = [ [[package]] name = "libcst" -version = "0.4.9" +version = "0.4.10" description = "A concrete syntax tree with AST-like properties for Python 3.5, 3.6, 3.7, 3.8, 3.9, and 3.10 programs." category = "dev" optional = false python-versions = ">=3.7" files = [ - {file = "libcst-0.4.9-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:4f9e42085c403e22201e5c41e707ef73e4ea910ad9fc67983ceee2368097f54e"}, - {file = "libcst-0.4.9-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:1266530bf840cc40633a04feb578bb4cac1aa3aea058cc3729e24eab09a8e996"}, - {file = "libcst-0.4.9-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f9679177391ccb9b0cdde3185c22bf366cb672457c4b7f4031fcb3b5e739fbd6"}, - {file = "libcst-0.4.9-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d67bc87e0d8db9434f2ea063734938a320f541f4c6da1074001e372f840f385d"}, - {file = "libcst-0.4.9-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e316da5a126f2a9e1d7680f95f907b575f082a35e2f8bd5620c59b2aaaebfe0a"}, - {file = "libcst-0.4.9-cp310-cp310-win_amd64.whl", hash = "sha256:7415569ab998a85b0fc9af3a204611ea7fadb2d719a12532c448f8fc98f5aca4"}, - {file = "libcst-0.4.9-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:15ded11ff7f4572f91635e02b519ae959f782689fdb4445bbebb7a3cc5c71d75"}, - {file = "libcst-0.4.9-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:5b266867b712a120fad93983de432ddb2ccb062eb5fd2bea748c9a94cb200c36"}, - {file = "libcst-0.4.9-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:045b3b0b06413cdae6e9751b5f417f789ffa410f2cb2815e3e0e0ea6bef10ec0"}, - {file = "libcst-0.4.9-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e799add8fba4976628b9c1a6768d73178bf898f0ed1bd1322930c2d3db9063ba"}, - {file = "libcst-0.4.9-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:10479371d04ee8dc978c889c1774bbf6a83df88fa055fcb0159a606f6679c565"}, - {file = "libcst-0.4.9-cp311-cp311-win_amd64.whl", hash = "sha256:7a98286cbbfa90a42d376900c875161ad02a5a2a6b7c94c0f7afd9075e329ce4"}, - {file = "libcst-0.4.9-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:400166fc4efb9aa06ce44498d443aa78519082695b1894202dd73cd507d2d712"}, - {file = "libcst-0.4.9-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:46123863fba35cc84f7b54dd68826419cabfd9504d8a101c7fe3313ea03776f9"}, - {file = "libcst-0.4.9-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:27be8db54c0e5fe440021a771a38b81a7dbc23cd630eb8b0e9828b7717f9b702"}, - {file = "libcst-0.4.9-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:132bec627b064bd567e7e4cd6c89524d02842151eb0d8f5f3f7ffd2579ec1b09"}, - {file = "libcst-0.4.9-cp37-cp37m-win_amd64.whl", hash = "sha256:596860090aeed3ee6ad1e59c35c6c4110a57e4e896abf51b91cae003ec720a11"}, - {file = "libcst-0.4.9-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:f4487608258109f774300466d4ca97353df29ae6ac23d1502e13e5509423c9d5"}, - {file = "libcst-0.4.9-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:aa53993e9a2853efb3ed3605da39f2e7125df6430f613eb67ef886c1ce4f94b5"}, - {file = "libcst-0.4.9-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f6ce794483d4c605ef0f5b199a49fb6996f9586ca938b7bfef213bd13858d7ab"}, - {file = "libcst-0.4.9-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:786e562b54bbcd17a060d1244deeef466b7ee07fe544074c252c4a169e38f1ee"}, - {file = "libcst-0.4.9-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:794250d2359edd518fb698e5d21c38a5bdfc5e4a75d0407b4c19818271ce6742"}, - {file = "libcst-0.4.9-cp38-cp38-win_amd64.whl", hash = "sha256:76491f67431318c3145442e97dddcead7075b074c59eac51be7cc9e3fffec6ee"}, - {file = "libcst-0.4.9-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:3cf48d7aec6dc54b02aec0b1bb413c5bb3b02d852fd6facf1f05c7213e61a176"}, - {file = "libcst-0.4.9-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:9b3348c6b7711a5235b133bd8e11d22e903c388db42485b8ceb5f2aa0fae9b9f"}, - {file = "libcst-0.4.9-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7e33b66762efaa014c38819efae5d8f726dd823e32d5d691035484411d2a2a69"}, - {file = "libcst-0.4.9-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1350d375d3fb9b20a6cf10c09b2964baca9be753a033dde7c1aced49d8e58387"}, - {file = "libcst-0.4.9-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3822056dc13326082362db35b3f649e0f4a97e36ddb4e487441da8e0fb9db7b3"}, - {file = "libcst-0.4.9-cp39-cp39-win_amd64.whl", hash = "sha256:183636141b839aa35b639e100883813744523bc7c12528906621121731b28443"}, - {file = "libcst-0.4.9.tar.gz", hash = "sha256:01786c403348f76f274dbaf3888ae237ffb73e6ed6973e65eba5c1fc389861dd"}, + {file = "libcst-0.4.10-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:8fa0ec646ed7bce984d0ee9dbf514af278050bdb16a4fb986e916ace534eebc6"}, + {file = "libcst-0.4.10-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:3cb3b7821eac00713844cda079583230c546a589b22ed5f03f2ddc4f985c384b"}, + {file = "libcst-0.4.10-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e7acfa747112ae40b032739661abd7c81aff37191294f7c2dab8bbd72372e78f"}, + {file = "libcst-0.4.10-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1312e293b864ef3cb4b09534ed5f104c2dc45b680233c68bf76237295041c781"}, + {file = "libcst-0.4.10-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:76884b1afe475e8e68e704bf26eb9f9a2867029643e58f2f26a0286e3b6e998e"}, + {file = "libcst-0.4.10-cp310-cp310-win_amd64.whl", hash = "sha256:1069b808a711db5cd47538f27eb2c73206317aa0d8b5a3500b23aab24f86eb2e"}, + {file = "libcst-0.4.10-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:50be085346a35812535c7f876319689e15a7bfd1bd8efae8fd70589281d944b6"}, + {file = "libcst-0.4.10-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:bb9f10e5763e361e8bd8ff765fc0f1bcf744f242ff8b6d3e50ffec4dda3972ac"}, + {file = "libcst-0.4.10-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cfeeabb528b5df7b4be1817b584ce79e9a1a66687bd72f6de9c22272462812f1"}, + {file = "libcst-0.4.10-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5648aeae8c90a2abab1f7b1bf205769a0179ed2cfe1ea7f681f6885e87b8b193"}, + {file = "libcst-0.4.10-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a144f20aff4643b00374facf8409d30c7935db8176e5b2a07e1fd44004db2c1f"}, + {file = "libcst-0.4.10-cp311-cp311-win_amd64.whl", hash = "sha256:a10adc2e8ea2dda2b70eabec631ead2fc4a7a7ab633d6c2b690823c698b8431a"}, + {file = "libcst-0.4.10-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:58fe90458a26a55358207f74abf8a05dff51d662069f070b4bd308a000a80c09"}, + {file = "libcst-0.4.10-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:999fbbe467f61cbce9e6e054f86cd1c5ffa3740fd3dc8ebdd600db379f699256"}, + {file = "libcst-0.4.10-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:83ee7e7be4efac4c140a97d772e1f6b3553f98fa5f46ad78df5dfe51e5a4aa4d"}, + {file = "libcst-0.4.10-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:158478e8f45578fb26621b3dc0fe275f9e004297e9afdcf08936ecda05681174"}, + {file = "libcst-0.4.10-cp37-cp37m-win_amd64.whl", hash = "sha256:5ed101fee1af7abea3684fcff7fab5b170ceea4040756f54c15c870539daec66"}, + {file = "libcst-0.4.10-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:349f2b4ee4b982fe254c65c78d941fc96299f3c422b79f95ef8c7bba2b7f0f90"}, + {file = "libcst-0.4.10-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:7cfa4d4beb84d0d63247aca27f1a15c63984512274c5b23040f8b4ba511036d7"}, + {file = "libcst-0.4.10-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:24582506da24e31f2644f862f11413a6b80fbad68d15194bfcc3f7dfebf2ec5e"}, + {file = "libcst-0.4.10-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8cdf2d0157438d3d52d310b0b6be31ff99bed19de489b2ebd3e2a4cd9946da45"}, + {file = "libcst-0.4.10-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a677103d2f1ab0e50bc3a7cc6c96c7d64bcbac826d785e4cbf5ee9aaa9fcfa25"}, + {file = "libcst-0.4.10-cp38-cp38-win_amd64.whl", hash = "sha256:a8fdfd4a7d301adb785aa4b98e4a7cca45c5ff8cfb460b485d081efcfaaeeab7"}, + {file = "libcst-0.4.10-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:b1569d87536bed4e9c11dd5c94a137dc0bce2a2b05961489c6016bf4521bb7cf"}, + {file = "libcst-0.4.10-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:72dff8783ac79cd10f2bd2fde0b28f262e9a22718ae26990948ba6131b85ca8b"}, + {file = "libcst-0.4.10-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:76adc53660ef094ff83f77a2550a7e00d1cab8e5e63336e071c17c09b5a89fe2"}, + {file = "libcst-0.4.10-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f3e9d9fdd9a9b9b8991936ff1c07527ce7ef396c8233280ba9a7137e72c2e48e"}, + {file = "libcst-0.4.10-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7e1b4cbaf7b1cdad5fa3eababe42d5b46c0d52afe13c5ba4eac2495fc57630ea"}, + {file = "libcst-0.4.10-cp39-cp39-win_amd64.whl", hash = "sha256:bcbd07cec3d7a7be6f0299b0c246e085e3d6cc8af367e2c96059183b97c2e2fe"}, ] [package.dependencies] @@ -317,7 +316,7 @@ typing-extensions = ">=3.7.4.2" typing-inspect = ">=0.4.0" [package.extras] -dev = ["Sphinx (>=5.1.1)", "black (==22.10.0)", "coverage (>=4.5.4)", "fixit (==0.1.1)", "flake8 (>=3.7.8,<5)", "hypothesis (>=4.36.0)", "hypothesmith (>=0.0.4)", "jinja2 (==3.1.2)", "jupyter (>=1.0.0)", "maturin (>=0.8.3,<0.14)", "nbsphinx (>=0.4.2)", "prompt-toolkit (>=2.0.9)", "pyre-check (==0.9.9)", "setuptools-rust (>=1.5.2)", "setuptools-scm (>=6.0.1)", "slotscheck (>=0.7.1)", "sphinx-rtd-theme (>=0.4.3)", "ufmt (==2.0.1)", "usort (==1.0.5)"] +dev = ["Sphinx (>=5.1.1)", "black (==23.1.0)", "build (>=0.10.0)", "coverage (>=4.5.4)", "fixit (==0.1.1)", "flake8 (>=3.7.8,<5)", "hypothesis (>=4.36.0)", "hypothesmith (>=0.0.4)", "jinja2 (==3.1.2)", "jupyter (>=1.0.0)", "maturin (>=0.8.3,<0.14)", "nbsphinx (>=0.4.2)", "prompt-toolkit (>=2.0.9)", "pyre-check (==0.9.10)", "setuptools-rust (>=1.5.2)", "setuptools-scm (>=6.0.1)", "slotscheck (>=0.7.1)", "sphinx-rtd-theme (>=0.4.3)", "ufmt (==2.1.0)", "usort (==1.0.6)"] [[package]] name = "markdown-it-py" @@ -455,14 +454,14 @@ files = [ [[package]] name = "nodeenv" -version = "1.7.0" +version = "1.8.0" description = "Node.js virtual environment builder" category = "dev" optional = false python-versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*" files = [ - {file = "nodeenv-1.7.0-py2.py3-none-any.whl", hash = "sha256:27083a7b96a25f2f5e1d8cb4b6317ee8aeda3bdd121394e5ac54e498028a042e"}, - {file = "nodeenv-1.7.0.tar.gz", hash = "sha256:e0e7f7dfb85fc5394c6fe1e8fa98131a2473e04311a45afb6508f7cf1836fa2b"}, + {file = "nodeenv-1.8.0-py2.py3-none-any.whl", hash = "sha256:df865724bb3c3adc86b3876fa209771517b0cfe596beff01a92700e0e8be4cec"}, + {file = "nodeenv-1.8.0.tar.gz", hash = "sha256:d51e0c37e64fbf47d017feac3145cdbb58836d7eee8c6f6d3b6880c5456227d2"}, ] [package.dependencies] @@ -506,18 +505,18 @@ files = [ [[package]] name = "platformdirs" -version = "3.5.0" +version = "3.5.1" description = "A small Python package for determining appropriate platform-specific dirs, e.g. a \"user data dir\"." category = "dev" optional = false python-versions = ">=3.7" files = [ - {file = "platformdirs-3.5.0-py3-none-any.whl", hash = "sha256:47692bc24c1958e8b0f13dd727307cff1db103fca36399f457da8e05f222fdc4"}, - {file = "platformdirs-3.5.0.tar.gz", hash = "sha256:7954a68d0ba23558d753f73437c55f89027cf8f5108c19844d4b82e5af396335"}, + {file = "platformdirs-3.5.1-py3-none-any.whl", hash = "sha256:e2378146f1964972c03c085bb5662ae80b2b8c06226c54b2ff4aa9483e8a13a5"}, + {file = "platformdirs-3.5.1.tar.gz", hash = "sha256:412dae91f52a6f84830f39a8078cecd0e866cb72294a5c66808e74d5e88d251f"}, ] [package.extras] -docs = ["furo (>=2023.3.27)", "proselint (>=0.13)", "sphinx (>=6.1.3)", "sphinx-autodoc-typehints (>=1.23,!=1.23.4)"] +docs = ["furo (>=2023.3.27)", "proselint (>=0.13)", "sphinx (>=6.2.1)", "sphinx-autodoc-typehints (>=1.23,!=1.23.4)"] test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=7.3.1)", "pytest-cov (>=4)", "pytest-mock (>=3.10)"] [[package]] @@ -737,14 +736,14 @@ testutils = ["gitpython (>3)"] [[package]] name = "pyright" -version = "1.1.306" +version = "1.1.309" description = "Command line wrapper for pyright" category = "dev" optional = false python-versions = ">=3.7" files = [ - {file = "pyright-1.1.306-py3-none-any.whl", hash = "sha256:008eb2a29584ae274a154d749cf81476a3073fb562a462eac8d43a753378b9db"}, - {file = "pyright-1.1.306.tar.gz", hash = "sha256:16d5d198be64de497d5f9002000a271176c381e21b977ca5566cf779b643c9ed"}, + {file = "pyright-1.1.309-py3-none-any.whl", hash = "sha256:a8b052c1997f7334e80074998ea0f93bd149550e8cf27ccb5481d3b2e1aad161"}, + {file = "pyright-1.1.309.tar.gz", hash = "sha256:1abcfa83814d792a5d70b38621cc6489acfade94ebb2279e55ba1f394d54296c"}, ] [package.dependencies] @@ -866,19 +865,19 @@ jupyter = ["ipywidgets (>=7.5.1,<9)"] [[package]] name = "setuptools" -version = "67.7.2" +version = "67.8.0" description = "Easily download, build, install, upgrade, and uninstall Python packages" category = "dev" optional = false python-versions = ">=3.7" files = [ - {file = "setuptools-67.7.2-py3-none-any.whl", hash = "sha256:23aaf86b85ca52ceb801d32703f12d77517b2556af839621c641fca11287952b"}, - {file = "setuptools-67.7.2.tar.gz", hash = "sha256:f104fa03692a2602fa0fec6c6a9e63b6c8a968de13e17c026957dd1f53d80990"}, + {file = "setuptools-67.8.0-py3-none-any.whl", hash = "sha256:5df61bf30bb10c6f756eb19e7c9f3b473051f48db77fddbe06ff2ca307df9a6f"}, + {file = "setuptools-67.8.0.tar.gz", hash = "sha256:62642358adc77ffa87233bc4d2354c4b2682d214048f500964dbe760ccedf102"}, ] [package.extras] docs = ["furo", "jaraco.packaging (>=9)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-favicon", "sphinx-hoverxref (<2)", "sphinx-inline-tabs", "sphinx-lint", "sphinx-notfound-page (==0.8.3)", "sphinx-reredirects", "sphinxcontrib-towncrier"] -testing = ["build[virtualenv]", "filelock (>=3.4.0)", "flake8 (<5)", "flake8-2020", "ini2toml[lite] (>=0.9)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "pip (>=19.1)", "pip-run (>=8.8)", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=1.3)", "pytest-flake8", "pytest-mypy (>=0.9.1)", "pytest-perf", "pytest-timeout", "pytest-xdist", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel"] +testing = ["build[virtualenv]", "filelock (>=3.4.0)", "flake8-2020", "ini2toml[lite] (>=0.9)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "pip (>=19.1)", "pip-run (>=8.8)", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=1.3)", "pytest-mypy (>=0.9.1)", "pytest-perf", "pytest-ruff", "pytest-timeout", "pytest-xdist", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel"] testing-integration = ["build[virtualenv]", "filelock (>=3.4.0)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "pytest", "pytest-enabler", "pytest-xdist", "tomli", "virtualenv (>=13.0.0)", "wheel"] [[package]] @@ -919,14 +918,14 @@ files = [ [[package]] name = "stevedore" -version = "5.0.0" +version = "5.1.0" description = "Manage dynamic plugins for Python applications" category = "dev" optional = false python-versions = ">=3.8" files = [ - {file = "stevedore-5.0.0-py3-none-any.whl", hash = "sha256:bd5a71ff5e5e5f5ea983880e4a1dd1bb47f8feebbb3d95b592398e2f02194771"}, - {file = "stevedore-5.0.0.tar.gz", hash = "sha256:2c428d2338976279e8eb2196f7a94910960d9f7ba2f41f3988511e95ca447021"}, + {file = "stevedore-5.1.0-py3-none-any.whl", hash = "sha256:8cc040628f3cea5d7128f2e76cf486b2251a4e543c7b938f58d9a377f6694a2d"}, + {file = "stevedore-5.1.0.tar.gz", hash = "sha256:a54534acf9b89bc7ed264807013b505bf07f74dbe4bcfa37d32bd063870b087c"}, ] [package.dependencies] @@ -1037,14 +1036,14 @@ test = ["black (>=22.3.0,<23.0.0)", "coverage (>=6.2,<7.0)", "isort (>=5.0.6,<6. [[package]] name = "typing-extensions" -version = "4.5.0" +version = "4.6.0" description = "Backported and Experimental Type Hints for Python 3.7+" category = "main" optional = false python-versions = ">=3.7" files = [ - {file = "typing_extensions-4.5.0-py3-none-any.whl", hash = "sha256:fb33085c39dd998ac16d1431ebc293a8b3eedd00fd4a32de0ff79002c19511b4"}, - {file = "typing_extensions-4.5.0.tar.gz", hash = "sha256:5cb5f4a79139d699607b3ef622a1dedafa84e115ab0024e0d9c044a9479ca7cb"}, + {file = "typing_extensions-4.6.0-py3-none-any.whl", hash = "sha256:6ad00b63f849b7dcc313b70b6b304ed67b2b2963b3098a33efe18056b1a9a223"}, + {file = "typing_extensions-4.6.0.tar.gz", hash = "sha256:ff6b238610c747e44c268aa4bb23c8c735d665a63726df3f9431ce707f2aa768"}, ] [[package]] diff --git a/packages/polywrap-plugin/polywrap_plugin/module.py b/packages/polywrap-plugin/polywrap_plugin/module.py index 8fe6ec06..fea82e2e 100644 --- a/packages/polywrap-plugin/polywrap_plugin/module.py +++ b/packages/polywrap-plugin/polywrap_plugin/module.py @@ -1,21 +1,42 @@ """This module contains the PluginModule class.""" # pylint: disable=invalid-name from abc import ABC -from typing import Any, Generic, TypeVar +from dataclasses import dataclass +from typing import Any, Generic, Optional, TypeVar from polywrap_core import ( - InvokeOptions, - Invoker, - UriPackageOrWrapper, + InvokerClient, + Uri, + UriResolutionContext, WrapAbortError, WrapInvocationError, - execute_maybe_async_function, ) from polywrap_msgpack import msgpack_decode TConfig = TypeVar("TConfig") +@dataclass(kw_only=True, slots=True) +class InvokeOptions: + """InvokeOptions is a dataclass that holds the options for an invocation. + + Attributes: + uri: The URI of the wrapper. + method: The method to invoke. + args: The arguments to pass to the method. + env: The environment variables to set for the invocation. + resolution_context: A URI resolution context. + client: The client to use for subinvocations. + """ + + uri: Uri + method: str + args: Optional[Any] = None + env: Optional[Any] = None + resolution_context: Optional[UriResolutionContext] = None + client: Optional[InvokerClient] = None + + class PluginModule(Generic[TConfig], ABC): """PluginModule is the base class for all plugin modules. @@ -33,20 +54,17 @@ def __init__(self, config: TConfig): """ self.config = config - async def __wrap_invoke__( + def __wrap_invoke__( self, - options: InvokeOptions[UriPackageOrWrapper], - invoker: Invoker[UriPackageOrWrapper], + options: InvokeOptions, ) -> Any: """Invoke a method on the plugin. Args: - method: The name of the method to invoke. - args: The arguments to pass to the method. - invoker: The invoker to use for subinvocations. + options: The options to use when invoking the plugin. Returns: - The result of the plugin method invocation or an error. + The result of the plugin method invocation. """ if not hasattr(self, options.method): raise WrapInvocationError( @@ -61,11 +79,12 @@ async def __wrap_invoke__( if isinstance(options.args, bytes) else options.args ) - return await execute_maybe_async_function( - callable_method, decoded_args, invoker, options.env - ) + return callable_method(decoded_args, options.client, options.env) except Exception as err: raise WrapAbortError(options, repr(err)) from err raise WrapInvocationError( options, f"{options.method} is not a callable method in plugin module" ) + + +__all__ = ["PluginModule"] diff --git a/packages/polywrap-plugin/polywrap_plugin/package.py b/packages/polywrap-plugin/polywrap_plugin/package.py index 609da1ad..4592a348 100644 --- a/packages/polywrap-plugin/polywrap_plugin/package.py +++ b/packages/polywrap-plugin/polywrap_plugin/package.py @@ -2,8 +2,8 @@ # pylint: disable=invalid-name from typing import Generic, Optional, TypeVar -from polywrap_core import GetManifestOptions, UriPackageOrWrapper, WrapPackage, Wrapper -from polywrap_manifest import AnyWrapManifest +from polywrap_core import WrapPackage, Wrapper +from polywrap_manifest import AnyWrapManifest, DeserializeManifestOptions from .module import PluginModule from .wrapper import PluginWrapper @@ -11,7 +11,7 @@ TConfig = TypeVar("TConfig") -class PluginPackage(Generic[TConfig], WrapPackage[UriPackageOrWrapper]): +class PluginPackage(WrapPackage, Generic[TConfig]): """PluginPackage implements IWrapPackage interface for the plugin. Attributes: @@ -32,12 +32,12 @@ def __init__(self, module: PluginModule[TConfig], manifest: AnyWrapManifest): self.module = module self.manifest = manifest - async def create_wrapper(self) -> Wrapper[UriPackageOrWrapper]: + def create_wrapper(self) -> Wrapper: """Create a new plugin wrapper instance.""" return PluginWrapper(module=self.module, manifest=self.manifest) - async def get_manifest( - self, options: Optional[GetManifestOptions] = None + def get_manifest( + self, options: Optional[DeserializeManifestOptions] = None ) -> AnyWrapManifest: """Get the manifest of the plugin. @@ -48,3 +48,6 @@ async def get_manifest( The manifest of the plugin. """ return self.manifest + + +__all__ = ["PluginPackage"] diff --git a/packages/polywrap-plugin/polywrap_plugin/resolution_context_override_client.py b/packages/polywrap-plugin/polywrap_plugin/resolution_context_override_client.py new file mode 100644 index 00000000..3700f72f --- /dev/null +++ b/packages/polywrap-plugin/polywrap_plugin/resolution_context_override_client.py @@ -0,0 +1,84 @@ +"""This module defines the ResolutionContextOverrideClient class.""" +from typing import Any, List, Optional + +from polywrap_core import InvokerClient, Uri, UriResolutionContext + + +class ResolutionContextOverrideClient(InvokerClient): + """A client that overrides the resolution context of the wrapped client. + + Args: + client (InvokerClient): The wrapped client. + resolution_context (Optional[UriResolutionContext]): The resolution context to use. + """ + + client: InvokerClient + resolution_context: Optional[UriResolutionContext] + + __slots__ = ("client", "resolution_context") + + def __init__( + self, client: InvokerClient, resolution_context: Optional[UriResolutionContext] + ): + """Initialize a new ResolutionContextOverrideClient instance.""" + self.client = client + self.resolution_context = resolution_context + + def invoke( + self, + uri: Uri, + method: str, + args: Optional[Any] = None, + env: Optional[Any] = None, + resolution_context: Optional[UriResolutionContext] = None, + encode_result: Optional[bool] = False, + ) -> Any: + """Invoke the Wrapper based on the provided InvokerOptions. + + Args: + uri (Uri): Uri of the wrapper + method (str): Method to be executed + args (Optional[Any]) : Arguments for the method, structured as a dictionary + env (Optional[Any]): Override the client's config for all invokes within this invoke. + resolution_context (Optional[UriResolutionContext]): A URI resolution context + encode_result (Optional[bool]): If True, the result will be encoded + + Returns: + Any: invocation result. + """ + return self.client.invoke( + uri, + method, + args, + env, + self.resolution_context, + encode_result, + ) + + def get_implementations( + self, uri: Uri, apply_resolution: bool = True + ) -> Optional[List[Uri]]: + """Get implementations of an interface with its URI. + + Args: + uri (Uri): URI of the interface. + apply_resolution (bool): If True, apply resolution to the URI and interfaces. + + Returns: + Optional[List[Uri]]: List of implementations or None if not found. + """ + return self.client.get_implementations(uri, apply_resolution) + + def try_resolve_uri( + self, uri: Uri, resolution_context: UriResolutionContext | None = None + ) -> Any: + """Try to resolve a URI to a wrap package, a wrapper, or a URI. + + Args: + uri (Uri): The URI to resolve. + resolution_context (UriResolutionContext): The resolution context. + + Returns: + Any: URI Resolution Result. + """ + return self.client.try_resolve_uri(uri, self.resolution_context) diff --git a/packages/polywrap-plugin/polywrap_plugin/wrapper.py b/packages/polywrap-plugin/polywrap_plugin/wrapper.py index 49604e45..ac947758 100644 --- a/packages/polywrap-plugin/polywrap_plugin/wrapper.py +++ b/packages/polywrap-plugin/polywrap_plugin/wrapper.py @@ -1,24 +1,25 @@ """This module contains the PluginWrapper class.""" # pylint: disable=invalid-name -from typing import Generic, TypeVar, Union +# pylint: disable=too-many-arguments +from typing import Any, Generic, Optional, TypeVar, Union from polywrap_core import ( - GetFileOptions, InvocableResult, - InvokeOptions, - Invoker, - UriPackageOrWrapper, + InvokerClient, + Uri, + UriResolutionContext, Wrapper, ) from polywrap_manifest import AnyWrapManifest -from .module import PluginModule +from .module import InvokeOptions, PluginModule +from .resolution_context_override_client import ResolutionContextOverrideClient TConfig = TypeVar("TConfig") TResult = TypeVar("TResult") -class PluginWrapper(Generic[TConfig], Wrapper[UriPackageOrWrapper]): +class PluginWrapper(Wrapper, Generic[TConfig]): """PluginWrapper implements the Wrapper interface for plugin wrappers. Attributes: @@ -41,31 +42,53 @@ def __init__( self.module = module self.manifest = manifest - async def invoke( + def invoke( self, - options: InvokeOptions[UriPackageOrWrapper], - invoker: Invoker[UriPackageOrWrapper], + uri: Uri, + method: str, + args: Optional[Any] = None, + env: Optional[Any] = None, + resolution_context: Optional[UriResolutionContext] = None, + client: Optional[InvokerClient] = None, ) -> InvocableResult: - """Invoke a method on the plugin. + """Invoke the Wrapper based on the provided InvokeOptions. Args: - options (InvokeOptions): options to use when invoking the plugin. - invoker (Invoker): the invoker to use when invoking the plugin. + uri (Uri): Uri of the wrapper + method (str): Method to be executed + args (Optional[Any]) : Arguments for the method, structured as a dictionary + env (Optional[Any]): Override the client's config for all invokes within this invoke. + resolution_context (Optional[UriResolutionContext]): A URI resolution context + client (Optional[Invoker]): The invoker instance requesting this invocation.\ + This invoker will be used for any subinvocation that may occur. Returns: - Result[InvocableResult]: the result of the invocation. + InvocableResult: Result of the invocation. """ - result = await self.module.__wrap_invoke__(options, invoker) + options = InvokeOptions( + uri=uri, + method=method, + args=args, + env=env, + resolution_context=resolution_context, + client=ResolutionContextOverrideClient(client, resolution_context) + if client + else None, + ) + result = self.module.__wrap_invoke__(options) return InvocableResult(result=result, encoded=False) - async def get_file(self, options: GetFileOptions) -> Union[str, bytes]: - """Get a file from the plugin. + def get_file( + self, path: str, encoding: Optional[str] = "utf-8" + ) -> Union[str, bytes]: + """Get a file from the wrapper. Args: - options (GetFileOptions): options to use when getting the file. + path (str): Path to the file. + encoding (Optional[str]): Encoding of the file. Returns: - Result[Union[str, bytes]]: the file contents or an error. + Union[str, bytes]: The file contents """ raise NotImplementedError("client.get_file(..) is not implemented for plugins") @@ -76,3 +99,6 @@ def get_manifest(self) -> AnyWrapManifest: Result[AnyWrapManifest]: the manifest of the plugin. """ return self.manifest + + +__all__ = ["PluginWrapper"] diff --git a/packages/polywrap-plugin/pyproject.toml b/packages/polywrap-plugin/pyproject.toml index fa462b30..2f579e76 100644 --- a/packages/polywrap-plugin/pyproject.toml +++ b/packages/polywrap-plugin/pyproject.toml @@ -50,6 +50,7 @@ disable = [ "too-many-return-statements", "broad-exception-caught", "too-few-public-methods", + "too-many-arguments", ] ignore = [ "tests/" diff --git a/packages/polywrap-plugin/tests/conftest.py b/packages/polywrap-plugin/tests/conftest.py index 6fc7aa3b..ea51ed7a 100644 --- a/packages/polywrap-plugin/tests/conftest.py +++ b/packages/polywrap-plugin/tests/conftest.py @@ -2,15 +2,15 @@ from typing import Any, Dict, List, Union, Optional from polywrap_plugin import PluginModule -from polywrap_core import Invoker, Uri, InvokerOptions, UriPackageOrWrapper, Env +from polywrap_core import Invoker, Uri @fixture -def invoker() -> Invoker[UriPackageOrWrapper]: - class MockInvoker(Invoker[UriPackageOrWrapper]): - async def invoke(self, options: InvokerOptions[UriPackageOrWrapper]) -> Any: +def invoker() -> Invoker: + class MockInvoker(Invoker): + async def invoke(self, *args: Any) -> Any: raise NotImplementedError() - def get_implementations(self, uri: Uri) -> Union[List[Uri], None]: + def get_implementations(self, *args: Any) -> Union[List[Uri], None]: raise NotImplementedError() return MockInvoker() @@ -22,7 +22,7 @@ class GreetingModule(PluginModule[None]): def __init__(self, config: None): super().__init__(config) - def greeting(self, args: Dict[str, Any], client: Invoker[UriPackageOrWrapper], env: Optional[Env] = None): + def greeting(self, args: Dict[str, Any], client: Invoker, env: Optional[Any] = None): return f"Greetings from: {args['name']}" return GreetingModule(None) \ No newline at end of file diff --git a/packages/polywrap-plugin/tests/test_plugin_module.py b/packages/polywrap-plugin/tests/test_plugin_module.py index ef18454b..575d4275 100644 --- a/packages/polywrap-plugin/tests/test_plugin_module.py +++ b/packages/polywrap-plugin/tests/test_plugin_module.py @@ -1,16 +1,14 @@ -import pytest -from polywrap_core import Invoker, Uri, UriPackageOrWrapper, InvokeOptions +from polywrap_core import Invoker, Uri from polywrap_plugin import PluginModule +from polywrap_plugin.module import InvokeOptions -@pytest.mark.asyncio -async def test_plugin_module( - greeting_module: PluginModule[None], invoker: Invoker[UriPackageOrWrapper] +def test_plugin_module( + greeting_module: PluginModule[None], invoker: Invoker ): - result = await greeting_module.__wrap_invoke__( + result = greeting_module.__wrap_invoke__( InvokeOptions( - uri=Uri.from_str("plugin/greeting"), method="greeting", args={"name": "Joe"} + uri=Uri.from_str("plugin/greeting"), method="greeting", args={"name": "Joe"}, client=invoker ), - invoker, ) assert result, "Greetings from: Joe" diff --git a/packages/polywrap-plugin/tests/test_plugin_package.py b/packages/polywrap-plugin/tests/test_plugin_package.py index aa4dc9f4..01445fc1 100644 --- a/packages/polywrap-plugin/tests/test_plugin_package.py +++ b/packages/polywrap-plugin/tests/test_plugin_package.py @@ -1,24 +1,22 @@ from typing import cast -import pytest -from polywrap_core import InvokeOptions, Uri, Invoker, UriPackageOrWrapper +from polywrap_core import Uri, Invoker from polywrap_manifest import AnyWrapManifest from polywrap_plugin import PluginPackage, PluginModule -@pytest.mark.asyncio -async def test_plugin_package_invoke(greeting_module: PluginModule[None], invoker: Invoker[UriPackageOrWrapper]): +def test_plugin_package_invoke( + greeting_module: PluginModule[None], invoker: Invoker +): manifest = cast(AnyWrapManifest, {}) plugin_package = PluginPackage(greeting_module, manifest) - wrapper = await plugin_package.create_wrapper() - args = { - "name": "Joe" - } - options: InvokeOptions[UriPackageOrWrapper] = InvokeOptions( + wrapper = plugin_package.create_wrapper() + args = {"name": "Joe"} + + result = wrapper.invoke( uri=Uri.from_str("ens/greeting.eth"), method="greeting", - args=args + args=args, + client=invoker, ) - - result = await wrapper.invoke(options, invoker) - assert result, "Greetings from: Joe" \ No newline at end of file + assert result, "Greetings from: Joe" diff --git a/packages/polywrap-plugin/tests/test_plugin_wrapper.py b/packages/polywrap-plugin/tests/test_plugin_wrapper.py index 779b7328..37184ce2 100644 --- a/packages/polywrap-plugin/tests/test_plugin_wrapper.py +++ b/packages/polywrap-plugin/tests/test_plugin_wrapper.py @@ -1,24 +1,23 @@ from typing import cast -import pytest -from polywrap_core import InvokeOptions, Uri, Invoker, UriPackageOrWrapper +from polywrap_core import Uri, Invoker from polywrap_manifest import AnyWrapManifest from polywrap_plugin import PluginWrapper, PluginModule -@pytest.mark.asyncio -async def test_plugin_wrapper_invoke(greeting_module: PluginModule[None], invoker: Invoker[UriPackageOrWrapper]): + +def test_plugin_wrapper_invoke( + greeting_module: PluginModule[None], invoker: Invoker +): manifest = cast(AnyWrapManifest, {}) wrapper = PluginWrapper(greeting_module, manifest) - args = { - "name": "Joe" - } - options: InvokeOptions[UriPackageOrWrapper] = InvokeOptions( + args = {"name": "Joe"} + + result = wrapper.invoke( uri=Uri.from_str("ens/greeting.eth"), method="greeting", - args=args + args=args, + client=invoker, ) - - result = await wrapper.invoke(options, invoker) - assert result, "Greetings from: Joe" \ No newline at end of file + assert result, "Greetings from: Joe" From 5df78c1c11790b067244262a5d75f8ade8475b89 Mon Sep 17 00:00:00 2001 From: Niraj Kamdar Date: Tue, 6 Jun 2023 17:56:29 +0530 Subject: [PATCH 07/47] feat: add unit-tests for remaining functions --- .../tests/test_plugin_wrapper.py | 1 + .../tests/test_wasm_wrapper.py | 0 packages/polywrap-plugin/tests/conftest.py | 8 ++--- .../tests/test_plugin_module.py | 6 ++-- .../tests/test_plugin_package.py | 15 +++++++-- .../tests/test_plugin_wrapper.py | 31 +++++++++++++++++-- 6 files changed, 48 insertions(+), 13 deletions(-) create mode 100644 packages/polywrap-client/tests/test_plugin_wrapper.py create mode 100644 packages/polywrap-client/tests/test_wasm_wrapper.py diff --git a/packages/polywrap-client/tests/test_plugin_wrapper.py b/packages/polywrap-client/tests/test_plugin_wrapper.py new file mode 100644 index 00000000..9906e2b8 --- /dev/null +++ b/packages/polywrap-client/tests/test_plugin_wrapper.py @@ -0,0 +1 @@ +# Encode - Decode need to be tested \ No newline at end of file diff --git a/packages/polywrap-client/tests/test_wasm_wrapper.py b/packages/polywrap-client/tests/test_wasm_wrapper.py new file mode 100644 index 00000000..e69de29b diff --git a/packages/polywrap-plugin/tests/conftest.py b/packages/polywrap-plugin/tests/conftest.py index ea51ed7a..d15900c0 100644 --- a/packages/polywrap-plugin/tests/conftest.py +++ b/packages/polywrap-plugin/tests/conftest.py @@ -2,11 +2,11 @@ from typing import Any, Dict, List, Union, Optional from polywrap_plugin import PluginModule -from polywrap_core import Invoker, Uri +from polywrap_core import InvokerClient, Uri @fixture -def invoker() -> Invoker: - class MockInvoker(Invoker): +def client() -> InvokerClient: + class MockInvoker(InvokerClient): async def invoke(self, *args: Any) -> Any: raise NotImplementedError() @@ -22,7 +22,7 @@ class GreetingModule(PluginModule[None]): def __init__(self, config: None): super().__init__(config) - def greeting(self, args: Dict[str, Any], client: Invoker, env: Optional[Any] = None): + def greeting(self, args: Dict[str, Any], client: InvokerClient, env: Optional[Any] = None): return f"Greetings from: {args['name']}" return GreetingModule(None) \ No newline at end of file diff --git a/packages/polywrap-plugin/tests/test_plugin_module.py b/packages/polywrap-plugin/tests/test_plugin_module.py index 575d4275..a308a276 100644 --- a/packages/polywrap-plugin/tests/test_plugin_module.py +++ b/packages/polywrap-plugin/tests/test_plugin_module.py @@ -1,14 +1,14 @@ -from polywrap_core import Invoker, Uri +from polywrap_core import InvokerClient, Uri from polywrap_plugin import PluginModule from polywrap_plugin.module import InvokeOptions def test_plugin_module( - greeting_module: PluginModule[None], invoker: Invoker + greeting_module: PluginModule[None], client: InvokerClient ): result = greeting_module.__wrap_invoke__( InvokeOptions( - uri=Uri.from_str("plugin/greeting"), method="greeting", args={"name": "Joe"}, client=invoker + uri=Uri.from_str("plugin/greeting"), method="greeting", args={"name": "Joe"}, client=client ), ) assert result, "Greetings from: Joe" diff --git a/packages/polywrap-plugin/tests/test_plugin_package.py b/packages/polywrap-plugin/tests/test_plugin_package.py index 01445fc1..5af64b23 100644 --- a/packages/polywrap-plugin/tests/test_plugin_package.py +++ b/packages/polywrap-plugin/tests/test_plugin_package.py @@ -1,12 +1,12 @@ from typing import cast -from polywrap_core import Uri, Invoker +from polywrap_core import Uri, InvokerClient from polywrap_manifest import AnyWrapManifest from polywrap_plugin import PluginPackage, PluginModule def test_plugin_package_invoke( - greeting_module: PluginModule[None], invoker: Invoker + greeting_module: PluginModule[None], client: InvokerClient ): manifest = cast(AnyWrapManifest, {}) plugin_package = PluginPackage(greeting_module, manifest) @@ -17,6 +17,15 @@ def test_plugin_package_invoke( uri=Uri.from_str("ens/greeting.eth"), method="greeting", args=args, - client=invoker, + client=client, ) assert result, "Greetings from: Joe" + + +def test_plugin_package_get_manifest( + greeting_module: PluginModule[None], client: InvokerClient +): + manifest = cast(AnyWrapManifest, {}) + plugin_package = PluginPackage(greeting_module, manifest) + + assert plugin_package.get_manifest() is manifest diff --git a/packages/polywrap-plugin/tests/test_plugin_wrapper.py b/packages/polywrap-plugin/tests/test_plugin_wrapper.py index 37184ce2..25dcd8cf 100644 --- a/packages/polywrap-plugin/tests/test_plugin_wrapper.py +++ b/packages/polywrap-plugin/tests/test_plugin_wrapper.py @@ -1,13 +1,14 @@ from typing import cast -from polywrap_core import Uri, Invoker +from polywrap_core import Uri, InvokerClient from polywrap_manifest import AnyWrapManifest from polywrap_plugin import PluginWrapper, PluginModule +import pytest def test_plugin_wrapper_invoke( - greeting_module: PluginModule[None], invoker: Invoker + greeting_module: PluginModule[None], client: InvokerClient ): manifest = cast(AnyWrapManifest, {}) @@ -18,6 +19,30 @@ def test_plugin_wrapper_invoke( uri=Uri.from_str("ens/greeting.eth"), method="greeting", args=args, - client=invoker, + client=client, ) assert result, "Greetings from: Joe" + + +def test_plugin_wrapper_get_file( + greeting_module: PluginModule[None], client: InvokerClient +): + manifest = cast(AnyWrapManifest, {}) + + wrapper = PluginWrapper(greeting_module, manifest) + + with pytest.raises(NotImplementedError): + wrapper.get_file( + path="greeting.txt", + encoding="utf-8", + ) + + +def test_plugin_wrapper_manifest( + greeting_module: PluginModule[None], client: InvokerClient +): + manifest = cast(AnyWrapManifest, {}) + + wrapper = PluginWrapper(greeting_module, manifest) + + assert wrapper.manifest is manifest From febebb398b651aad00eafd8f624b9b1c66a504da Mon Sep 17 00:00:00 2001 From: Niraj Kamdar Date: Tue, 6 Jun 2023 02:25:59 +0530 Subject: [PATCH 08/47] feat: add wrap test harness --- packages/polywrap-test-cases/.gitignore | 1 + packages/polywrap-test-cases/README.md | 36 + packages/polywrap-test-cases/poetry.lock | 996 ++++++++++++++++++ .../polywrap_test_cases/__init__.py | 39 + .../polywrap_test_cases/__main__.py | 5 + .../polywrap_test_cases/py.typed | 0 packages/polywrap-test-cases/pyproject.toml | 58 + .../polywrap-test-cases/tests/test_sanity.py | 16 + packages/polywrap-test-cases/tox.ini | 33 + python-monorepo.code-workspace | 4 + 10 files changed, 1188 insertions(+) create mode 100644 packages/polywrap-test-cases/.gitignore create mode 100644 packages/polywrap-test-cases/README.md create mode 100644 packages/polywrap-test-cases/poetry.lock create mode 100644 packages/polywrap-test-cases/polywrap_test_cases/__init__.py create mode 100644 packages/polywrap-test-cases/polywrap_test_cases/__main__.py create mode 100644 packages/polywrap-test-cases/polywrap_test_cases/py.typed create mode 100644 packages/polywrap-test-cases/pyproject.toml create mode 100644 packages/polywrap-test-cases/tests/test_sanity.py create mode 100644 packages/polywrap-test-cases/tox.ini diff --git a/packages/polywrap-test-cases/.gitignore b/packages/polywrap-test-cases/.gitignore new file mode 100644 index 00000000..4faabeff --- /dev/null +++ b/packages/polywrap-test-cases/.gitignore @@ -0,0 +1 @@ +wrappers/ \ No newline at end of file diff --git a/packages/polywrap-test-cases/README.md b/packages/polywrap-test-cases/README.md new file mode 100644 index 00000000..00bdf773 --- /dev/null +++ b/packages/polywrap-test-cases/README.md @@ -0,0 +1,36 @@ +# polywrap-wasm + +Python implementation of the plugin wrapper runtime. + +## Usage + +### Invoke Plugin Wrapper + +```python +from typing import Any, Dict, List, Union, Optional +from polywrap_manifest import AnyWrapManifest +from polywrap_plugin import PluginModule +from polywrap_core import Invoker, Uri, InvokerOptions, UriPackageOrWrapper, Env + +class GreetingModule(PluginModule[None]): + def __init__(self, config: None): + super().__init__(config) + + def greeting(self, args: Dict[str, Any], client: Invoker[UriPackageOrWrapper], env: Optional[Env] = None): + return f"Greetings from: {args['name']}" + +manifest = cast(AnyWrapManifest, {}) +wrapper = PluginWrapper(greeting_module, manifest) +args = { + "name": "Joe" +} +options: InvokeOptions[UriPackageOrWrapper] = InvokeOptions( + uri=Uri.from_str("ens/greeting.eth"), + method="greeting", + args=args +) +invoker: Invoker = ... + +result = await wrapper.invoke(options, invoker) +assert result, "Greetings from: Joe" +``` diff --git a/packages/polywrap-test-cases/poetry.lock b/packages/polywrap-test-cases/poetry.lock new file mode 100644 index 00000000..204c9efd --- /dev/null +++ b/packages/polywrap-test-cases/poetry.lock @@ -0,0 +1,996 @@ +# This file is automatically @generated by Poetry and should not be changed by hand. + +[[package]] +name = "astroid" +version = "2.15.4" +description = "An abstract syntax tree for Python with inference support." +category = "dev" +optional = false +python-versions = ">=3.7.2" +files = [ + {file = "astroid-2.15.4-py3-none-any.whl", hash = "sha256:a1b8543ef9d36ea777194bc9b17f5f8678d2c56ee6a45b2c2f17eec96f242347"}, + {file = "astroid-2.15.4.tar.gz", hash = "sha256:c81e1c7fbac615037744d067a9bb5f9aeb655edf59b63ee8b59585475d6f80d8"}, +] + +[package.dependencies] +lazy-object-proxy = ">=1.4.0" +typing-extensions = {version = ">=4.0.0", markers = "python_version < \"3.11\""} +wrapt = [ + {version = ">=1.11,<2", markers = "python_version < \"3.11\""}, + {version = ">=1.14,<2", markers = "python_version >= \"3.11\""}, +] + +[[package]] +name = "bandit" +version = "1.7.5" +description = "Security oriented static analyser for python code." +category = "dev" +optional = false +python-versions = ">=3.7" +files = [ + {file = "bandit-1.7.5-py3-none-any.whl", hash = "sha256:75665181dc1e0096369112541a056c59d1c5f66f9bb74a8d686c3c362b83f549"}, + {file = "bandit-1.7.5.tar.gz", hash = "sha256:bdfc739baa03b880c2d15d0431b31c658ffc348e907fe197e54e0389dd59e11e"}, +] + +[package.dependencies] +colorama = {version = ">=0.3.9", markers = "platform_system == \"Windows\""} +GitPython = ">=1.0.1" +PyYAML = ">=5.3.1" +rich = "*" +stevedore = ">=1.20.0" +tomli = {version = ">=1.1.0", optional = true, markers = "python_version < \"3.11\" and extra == \"toml\""} + +[package.extras] +test = ["beautifulsoup4 (>=4.8.0)", "coverage (>=4.5.4)", "fixtures (>=3.0.0)", "flake8 (>=4.0.0)", "pylint (==1.9.4)", "stestr (>=2.5.0)", "testscenarios (>=0.5.0)", "testtools (>=2.3.0)", "tomli (>=1.1.0)"] +toml = ["tomli (>=1.1.0)"] +yaml = ["PyYAML"] + +[[package]] +name = "black" +version = "22.12.0" +description = "The uncompromising code formatter." +category = "dev" +optional = false +python-versions = ">=3.7" +files = [ + {file = "black-22.12.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9eedd20838bd5d75b80c9f5487dbcb06836a43833a37846cf1d8c1cc01cef59d"}, + {file = "black-22.12.0-cp310-cp310-win_amd64.whl", hash = "sha256:159a46a4947f73387b4d83e87ea006dbb2337eab6c879620a3ba52699b1f4351"}, + {file = "black-22.12.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d30b212bffeb1e252b31dd269dfae69dd17e06d92b87ad26e23890f3efea366f"}, + {file = "black-22.12.0-cp311-cp311-win_amd64.whl", hash = "sha256:7412e75863aa5c5411886804678b7d083c7c28421210180d67dfd8cf1221e1f4"}, + {file = "black-22.12.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c116eed0efb9ff870ded8b62fe9f28dd61ef6e9ddd28d83d7d264a38417dcee2"}, + {file = "black-22.12.0-cp37-cp37m-win_amd64.whl", hash = "sha256:1f58cbe16dfe8c12b7434e50ff889fa479072096d79f0a7f25e4ab8e94cd8350"}, + {file = "black-22.12.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:77d86c9f3db9b1bf6761244bc0b3572a546f5fe37917a044e02f3166d5aafa7d"}, + {file = "black-22.12.0-cp38-cp38-win_amd64.whl", hash = "sha256:82d9fe8fee3401e02e79767016b4907820a7dc28d70d137eb397b92ef3cc5bfc"}, + {file = "black-22.12.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:101c69b23df9b44247bd88e1d7e90154336ac4992502d4197bdac35dd7ee3320"}, + {file = "black-22.12.0-cp39-cp39-win_amd64.whl", hash = "sha256:559c7a1ba9a006226f09e4916060982fd27334ae1998e7a38b3f33a37f7a2148"}, + {file = "black-22.12.0-py3-none-any.whl", hash = "sha256:436cc9167dd28040ad90d3b404aec22cedf24a6e4d7de221bec2730ec0c97bcf"}, + {file = "black-22.12.0.tar.gz", hash = "sha256:229351e5a18ca30f447bf724d007f890f97e13af070bb6ad4c0a441cd7596a2f"}, +] + +[package.dependencies] +click = ">=8.0.0" +mypy-extensions = ">=0.4.3" +pathspec = ">=0.9.0" +platformdirs = ">=2" +tomli = {version = ">=1.1.0", markers = "python_full_version < \"3.11.0a7\""} + +[package.extras] +colorama = ["colorama (>=0.4.3)"] +d = ["aiohttp (>=3.7.4)"] +jupyter = ["ipython (>=7.8.0)", "tokenize-rt (>=3.2.0)"] +uvloop = ["uvloop (>=0.15.2)"] + +[[package]] +name = "click" +version = "8.1.3" +description = "Composable command line interface toolkit" +category = "dev" +optional = false +python-versions = ">=3.7" +files = [ + {file = "click-8.1.3-py3-none-any.whl", hash = "sha256:bb4d8133cb15a609f44e8213d9b391b0809795062913b383c62be0ee95b1db48"}, + {file = "click-8.1.3.tar.gz", hash = "sha256:7682dc8afb30297001674575ea00d1814d808d6a36af415a82bd481d37ba7b8e"}, +] + +[package.dependencies] +colorama = {version = "*", markers = "platform_system == \"Windows\""} + +[[package]] +name = "colorama" +version = "0.4.6" +description = "Cross-platform colored terminal text." +category = "dev" +optional = false +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" +files = [ + {file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"}, + {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"}, +] + +[[package]] +name = "dill" +version = "0.3.6" +description = "serialize all of python" +category = "dev" +optional = false +python-versions = ">=3.7" +files = [ + {file = "dill-0.3.6-py3-none-any.whl", hash = "sha256:a07ffd2351b8c678dfc4a856a3005f8067aea51d6ba6c700796a4d9e280f39f0"}, + {file = "dill-0.3.6.tar.gz", hash = "sha256:e5db55f3687856d8fbdab002ed78544e1c4559a130302693d839dfe8f93f2373"}, +] + +[package.extras] +graph = ["objgraph (>=1.7.2)"] + +[[package]] +name = "distlib" +version = "0.3.6" +description = "Distribution utilities" +category = "dev" +optional = false +python-versions = "*" +files = [ + {file = "distlib-0.3.6-py2.py3-none-any.whl", hash = "sha256:f35c4b692542ca110de7ef0bea44d73981caeb34ca0b9b6b2e6d7790dda8f80e"}, + {file = "distlib-0.3.6.tar.gz", hash = "sha256:14bad2d9b04d3a36127ac97f30b12a19268f211063d8f8ee4f47108896e11b46"}, +] + +[[package]] +name = "exceptiongroup" +version = "1.1.1" +description = "Backport of PEP 654 (exception groups)" +category = "dev" +optional = false +python-versions = ">=3.7" +files = [ + {file = "exceptiongroup-1.1.1-py3-none-any.whl", hash = "sha256:232c37c63e4f682982c8b6459f33a8981039e5fb8756b2074364e5055c498c9e"}, + {file = "exceptiongroup-1.1.1.tar.gz", hash = "sha256:d484c3090ba2889ae2928419117447a14daf3c1231d5e30d0aae34f354f01785"}, +] + +[package.extras] +test = ["pytest (>=6)"] + +[[package]] +name = "filelock" +version = "3.12.0" +description = "A platform independent file lock." +category = "dev" +optional = false +python-versions = ">=3.7" +files = [ + {file = "filelock-3.12.0-py3-none-any.whl", hash = "sha256:ad98852315c2ab702aeb628412cbf7e95b7ce8c3bf9565670b4eaecf1db370a9"}, + {file = "filelock-3.12.0.tar.gz", hash = "sha256:fc03ae43288c013d2ea83c8597001b1129db351aad9c57fe2409327916b8e718"}, +] + +[package.extras] +docs = ["furo (>=2023.3.27)", "sphinx (>=6.1.3)", "sphinx-autodoc-typehints (>=1.23,!=1.23.4)"] +testing = ["covdefaults (>=2.3)", "coverage (>=7.2.3)", "diff-cover (>=7.5)", "pytest (>=7.3.1)", "pytest-cov (>=4)", "pytest-mock (>=3.10)", "pytest-timeout (>=2.1)"] + +[[package]] +name = "gitdb" +version = "4.0.10" +description = "Git Object Database" +category = "dev" +optional = false +python-versions = ">=3.7" +files = [ + {file = "gitdb-4.0.10-py3-none-any.whl", hash = "sha256:c286cf298426064079ed96a9e4a9d39e7f3e9bf15ba60701e95f5492f28415c7"}, + {file = "gitdb-4.0.10.tar.gz", hash = "sha256:6eb990b69df4e15bad899ea868dc46572c3f75339735663b81de79b06f17eb9a"}, +] + +[package.dependencies] +smmap = ">=3.0.1,<6" + +[[package]] +name = "gitpython" +version = "3.1.31" +description = "GitPython is a Python library used to interact with Git repositories" +category = "dev" +optional = false +python-versions = ">=3.7" +files = [ + {file = "GitPython-3.1.31-py3-none-any.whl", hash = "sha256:f04893614f6aa713a60cbbe1e6a97403ef633103cdd0ef5eb6efe0deb98dbe8d"}, + {file = "GitPython-3.1.31.tar.gz", hash = "sha256:8ce3bcf69adfdf7c7d503e78fd3b1c492af782d58893b650adb2ac8912ddd573"}, +] + +[package.dependencies] +gitdb = ">=4.0.1,<5" + +[[package]] +name = "iniconfig" +version = "2.0.0" +description = "brain-dead simple config-ini parsing" +category = "dev" +optional = false +python-versions = ">=3.7" +files = [ + {file = "iniconfig-2.0.0-py3-none-any.whl", hash = "sha256:b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374"}, + {file = "iniconfig-2.0.0.tar.gz", hash = "sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3"}, +] + +[[package]] +name = "isort" +version = "5.12.0" +description = "A Python utility / library to sort Python imports." +category = "dev" +optional = false +python-versions = ">=3.8.0" +files = [ + {file = "isort-5.12.0-py3-none-any.whl", hash = "sha256:f84c2818376e66cf843d497486ea8fed8700b340f308f076c6fb1229dff318b6"}, + {file = "isort-5.12.0.tar.gz", hash = "sha256:8bef7dde241278824a6d83f44a544709b065191b95b6e50894bdc722fcba0504"}, +] + +[package.extras] +colors = ["colorama (>=0.4.3)"] +pipfile-deprecated-finder = ["pip-shims (>=0.5.2)", "pipreqs", "requirementslib"] +plugins = ["setuptools"] +requirements-deprecated-finder = ["pip-api", "pipreqs"] + +[[package]] +name = "lazy-object-proxy" +version = "1.9.0" +description = "A fast and thorough lazy object proxy." +category = "dev" +optional = false +python-versions = ">=3.7" +files = [ + {file = "lazy-object-proxy-1.9.0.tar.gz", hash = "sha256:659fb5809fa4629b8a1ac5106f669cfc7bef26fbb389dda53b3e010d1ac4ebae"}, + {file = "lazy_object_proxy-1.9.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:b40387277b0ed2d0602b8293b94d7257e17d1479e257b4de114ea11a8cb7f2d7"}, + {file = "lazy_object_proxy-1.9.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e8c6cfb338b133fbdbc5cfaa10fe3c6aeea827db80c978dbd13bc9dd8526b7d4"}, + {file = "lazy_object_proxy-1.9.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:721532711daa7db0d8b779b0bb0318fa87af1c10d7fe5e52ef30f8eff254d0cd"}, + {file = "lazy_object_proxy-1.9.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:66a3de4a3ec06cd8af3f61b8e1ec67614fbb7c995d02fa224813cb7afefee701"}, + {file = "lazy_object_proxy-1.9.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:1aa3de4088c89a1b69f8ec0dcc169aa725b0ff017899ac568fe44ddc1396df46"}, + {file = "lazy_object_proxy-1.9.0-cp310-cp310-win32.whl", hash = "sha256:f0705c376533ed2a9e5e97aacdbfe04cecd71e0aa84c7c0595d02ef93b6e4455"}, + {file = "lazy_object_proxy-1.9.0-cp310-cp310-win_amd64.whl", hash = "sha256:ea806fd4c37bf7e7ad82537b0757999264d5f70c45468447bb2b91afdbe73a6e"}, + {file = "lazy_object_proxy-1.9.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:946d27deaff6cf8452ed0dba83ba38839a87f4f7a9732e8f9fd4107b21e6ff07"}, + {file = "lazy_object_proxy-1.9.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:79a31b086e7e68b24b99b23d57723ef7e2c6d81ed21007b6281ebcd1688acb0a"}, + {file = "lazy_object_proxy-1.9.0-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f699ac1c768270c9e384e4cbd268d6e67aebcfae6cd623b4d7c3bfde5a35db59"}, + {file = "lazy_object_proxy-1.9.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:bfb38f9ffb53b942f2b5954e0f610f1e721ccebe9cce9025a38c8ccf4a5183a4"}, + {file = "lazy_object_proxy-1.9.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:189bbd5d41ae7a498397287c408617fe5c48633e7755287b21d741f7db2706a9"}, + {file = "lazy_object_proxy-1.9.0-cp311-cp311-win32.whl", hash = "sha256:81fc4d08b062b535d95c9ea70dbe8a335c45c04029878e62d744bdced5141586"}, + {file = "lazy_object_proxy-1.9.0-cp311-cp311-win_amd64.whl", hash = "sha256:f2457189d8257dd41ae9b434ba33298aec198e30adf2dcdaaa3a28b9994f6adb"}, + {file = "lazy_object_proxy-1.9.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:d9e25ef10a39e8afe59a5c348a4dbf29b4868ab76269f81ce1674494e2565a6e"}, + {file = "lazy_object_proxy-1.9.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cbf9b082426036e19c6924a9ce90c740a9861e2bdc27a4834fd0a910742ac1e8"}, + {file = "lazy_object_proxy-1.9.0-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9f5fa4a61ce2438267163891961cfd5e32ec97a2c444e5b842d574251ade27d2"}, + {file = "lazy_object_proxy-1.9.0-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:8fa02eaab317b1e9e03f69aab1f91e120e7899b392c4fc19807a8278a07a97e8"}, + {file = "lazy_object_proxy-1.9.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:e7c21c95cae3c05c14aafffe2865bbd5e377cfc1348c4f7751d9dc9a48ca4bda"}, + {file = "lazy_object_proxy-1.9.0-cp37-cp37m-win32.whl", hash = "sha256:f12ad7126ae0c98d601a7ee504c1122bcef553d1d5e0c3bfa77b16b3968d2734"}, + {file = "lazy_object_proxy-1.9.0-cp37-cp37m-win_amd64.whl", hash = "sha256:edd20c5a55acb67c7ed471fa2b5fb66cb17f61430b7a6b9c3b4a1e40293b1671"}, + {file = "lazy_object_proxy-1.9.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:2d0daa332786cf3bb49e10dc6a17a52f6a8f9601b4cf5c295a4f85854d61de63"}, + {file = "lazy_object_proxy-1.9.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9cd077f3d04a58e83d04b20e334f678c2b0ff9879b9375ed107d5d07ff160171"}, + {file = "lazy_object_proxy-1.9.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:660c94ea760b3ce47d1855a30984c78327500493d396eac4dfd8bd82041b22be"}, + {file = "lazy_object_proxy-1.9.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:212774e4dfa851e74d393a2370871e174d7ff0ebc980907723bb67d25c8a7c30"}, + {file = "lazy_object_proxy-1.9.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:f0117049dd1d5635bbff65444496c90e0baa48ea405125c088e93d9cf4525b11"}, + {file = "lazy_object_proxy-1.9.0-cp38-cp38-win32.whl", hash = "sha256:0a891e4e41b54fd5b8313b96399f8b0e173bbbfc03c7631f01efbe29bb0bcf82"}, + {file = "lazy_object_proxy-1.9.0-cp38-cp38-win_amd64.whl", hash = "sha256:9990d8e71b9f6488e91ad25f322898c136b008d87bf852ff65391b004da5e17b"}, + {file = "lazy_object_proxy-1.9.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:9e7551208b2aded9c1447453ee366f1c4070602b3d932ace044715d89666899b"}, + {file = "lazy_object_proxy-1.9.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5f83ac4d83ef0ab017683d715ed356e30dd48a93746309c8f3517e1287523ef4"}, + {file = "lazy_object_proxy-1.9.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7322c3d6f1766d4ef1e51a465f47955f1e8123caee67dd641e67d539a534d006"}, + {file = "lazy_object_proxy-1.9.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:18b78ec83edbbeb69efdc0e9c1cb41a3b1b1ed11ddd8ded602464c3fc6020494"}, + {file = "lazy_object_proxy-1.9.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:09763491ce220c0299688940f8dc2c5d05fd1f45af1e42e636b2e8b2303e4382"}, + {file = "lazy_object_proxy-1.9.0-cp39-cp39-win32.whl", hash = "sha256:9090d8e53235aa280fc9239a86ae3ea8ac58eff66a705fa6aa2ec4968b95c821"}, + {file = "lazy_object_proxy-1.9.0-cp39-cp39-win_amd64.whl", hash = "sha256:db1c1722726f47e10e0b5fdbf15ac3b8adb58c091d12b3ab713965795036985f"}, +] + +[[package]] +name = "libcst" +version = "0.4.9" +description = "A concrete syntax tree with AST-like properties for Python 3.5, 3.6, 3.7, 3.8, 3.9, and 3.10 programs." +category = "dev" +optional = false +python-versions = ">=3.7" +files = [ + {file = "libcst-0.4.9-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:4f9e42085c403e22201e5c41e707ef73e4ea910ad9fc67983ceee2368097f54e"}, + {file = "libcst-0.4.9-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:1266530bf840cc40633a04feb578bb4cac1aa3aea058cc3729e24eab09a8e996"}, + {file = "libcst-0.4.9-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f9679177391ccb9b0cdde3185c22bf366cb672457c4b7f4031fcb3b5e739fbd6"}, + {file = "libcst-0.4.9-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d67bc87e0d8db9434f2ea063734938a320f541f4c6da1074001e372f840f385d"}, + {file = "libcst-0.4.9-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e316da5a126f2a9e1d7680f95f907b575f082a35e2f8bd5620c59b2aaaebfe0a"}, + {file = "libcst-0.4.9-cp310-cp310-win_amd64.whl", hash = "sha256:7415569ab998a85b0fc9af3a204611ea7fadb2d719a12532c448f8fc98f5aca4"}, + {file = "libcst-0.4.9-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:15ded11ff7f4572f91635e02b519ae959f782689fdb4445bbebb7a3cc5c71d75"}, + {file = "libcst-0.4.9-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:5b266867b712a120fad93983de432ddb2ccb062eb5fd2bea748c9a94cb200c36"}, + {file = "libcst-0.4.9-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:045b3b0b06413cdae6e9751b5f417f789ffa410f2cb2815e3e0e0ea6bef10ec0"}, + {file = "libcst-0.4.9-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e799add8fba4976628b9c1a6768d73178bf898f0ed1bd1322930c2d3db9063ba"}, + {file = "libcst-0.4.9-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:10479371d04ee8dc978c889c1774bbf6a83df88fa055fcb0159a606f6679c565"}, + {file = "libcst-0.4.9-cp311-cp311-win_amd64.whl", hash = "sha256:7a98286cbbfa90a42d376900c875161ad02a5a2a6b7c94c0f7afd9075e329ce4"}, + {file = "libcst-0.4.9-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:400166fc4efb9aa06ce44498d443aa78519082695b1894202dd73cd507d2d712"}, + {file = "libcst-0.4.9-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:46123863fba35cc84f7b54dd68826419cabfd9504d8a101c7fe3313ea03776f9"}, + {file = "libcst-0.4.9-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:27be8db54c0e5fe440021a771a38b81a7dbc23cd630eb8b0e9828b7717f9b702"}, + {file = "libcst-0.4.9-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:132bec627b064bd567e7e4cd6c89524d02842151eb0d8f5f3f7ffd2579ec1b09"}, + {file = "libcst-0.4.9-cp37-cp37m-win_amd64.whl", hash = "sha256:596860090aeed3ee6ad1e59c35c6c4110a57e4e896abf51b91cae003ec720a11"}, + {file = "libcst-0.4.9-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:f4487608258109f774300466d4ca97353df29ae6ac23d1502e13e5509423c9d5"}, + {file = "libcst-0.4.9-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:aa53993e9a2853efb3ed3605da39f2e7125df6430f613eb67ef886c1ce4f94b5"}, + {file = "libcst-0.4.9-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f6ce794483d4c605ef0f5b199a49fb6996f9586ca938b7bfef213bd13858d7ab"}, + {file = "libcst-0.4.9-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:786e562b54bbcd17a060d1244deeef466b7ee07fe544074c252c4a169e38f1ee"}, + {file = "libcst-0.4.9-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:794250d2359edd518fb698e5d21c38a5bdfc5e4a75d0407b4c19818271ce6742"}, + {file = "libcst-0.4.9-cp38-cp38-win_amd64.whl", hash = "sha256:76491f67431318c3145442e97dddcead7075b074c59eac51be7cc9e3fffec6ee"}, + {file = "libcst-0.4.9-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:3cf48d7aec6dc54b02aec0b1bb413c5bb3b02d852fd6facf1f05c7213e61a176"}, + {file = "libcst-0.4.9-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:9b3348c6b7711a5235b133bd8e11d22e903c388db42485b8ceb5f2aa0fae9b9f"}, + {file = "libcst-0.4.9-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7e33b66762efaa014c38819efae5d8f726dd823e32d5d691035484411d2a2a69"}, + {file = "libcst-0.4.9-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1350d375d3fb9b20a6cf10c09b2964baca9be753a033dde7c1aced49d8e58387"}, + {file = "libcst-0.4.9-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3822056dc13326082362db35b3f649e0f4a97e36ddb4e487441da8e0fb9db7b3"}, + {file = "libcst-0.4.9-cp39-cp39-win_amd64.whl", hash = "sha256:183636141b839aa35b639e100883813744523bc7c12528906621121731b28443"}, + {file = "libcst-0.4.9.tar.gz", hash = "sha256:01786c403348f76f274dbaf3888ae237ffb73e6ed6973e65eba5c1fc389861dd"}, +] + +[package.dependencies] +pyyaml = ">=5.2" +typing-extensions = ">=3.7.4.2" +typing-inspect = ">=0.4.0" + +[package.extras] +dev = ["Sphinx (>=5.1.1)", "black (==22.10.0)", "coverage (>=4.5.4)", "fixit (==0.1.1)", "flake8 (>=3.7.8,<5)", "hypothesis (>=4.36.0)", "hypothesmith (>=0.0.4)", "jinja2 (==3.1.2)", "jupyter (>=1.0.0)", "maturin (>=0.8.3,<0.14)", "nbsphinx (>=0.4.2)", "prompt-toolkit (>=2.0.9)", "pyre-check (==0.9.9)", "setuptools-rust (>=1.5.2)", "setuptools-scm (>=6.0.1)", "slotscheck (>=0.7.1)", "sphinx-rtd-theme (>=0.4.3)", "ufmt (==2.0.1)", "usort (==1.0.5)"] + +[[package]] +name = "markdown-it-py" +version = "2.2.0" +description = "Python port of markdown-it. Markdown parsing, done right!" +category = "dev" +optional = false +python-versions = ">=3.7" +files = [ + {file = "markdown-it-py-2.2.0.tar.gz", hash = "sha256:7c9a5e412688bc771c67432cbfebcdd686c93ce6484913dccf06cb5a0bea35a1"}, + {file = "markdown_it_py-2.2.0-py3-none-any.whl", hash = "sha256:5a35f8d1870171d9acc47b99612dc146129b631baf04970128b568f190d0cc30"}, +] + +[package.dependencies] +mdurl = ">=0.1,<1.0" + +[package.extras] +benchmarking = ["psutil", "pytest", "pytest-benchmark"] +code-style = ["pre-commit (>=3.0,<4.0)"] +compare = ["commonmark (>=0.9,<1.0)", "markdown (>=3.4,<4.0)", "mistletoe (>=1.0,<2.0)", "mistune (>=2.0,<3.0)", "panflute (>=2.3,<3.0)"] +linkify = ["linkify-it-py (>=1,<3)"] +plugins = ["mdit-py-plugins"] +profiling = ["gprof2dot"] +rtd = ["attrs", "myst-parser", "pyyaml", "sphinx", "sphinx-copybutton", "sphinx-design", "sphinx_book_theme"] +testing = ["coverage", "pytest", "pytest-cov", "pytest-regressions"] + +[[package]] +name = "mccabe" +version = "0.7.0" +description = "McCabe checker, plugin for flake8" +category = "dev" +optional = false +python-versions = ">=3.6" +files = [ + {file = "mccabe-0.7.0-py2.py3-none-any.whl", hash = "sha256:6c2d30ab6be0e4a46919781807b4f0d834ebdd6c6e3dca0bda5a15f863427b6e"}, + {file = "mccabe-0.7.0.tar.gz", hash = "sha256:348e0240c33b60bbdf4e523192ef919f28cb2c3d7d5c7794f74009290f236325"}, +] + +[[package]] +name = "mdurl" +version = "0.1.2" +description = "Markdown URL utilities" +category = "dev" +optional = false +python-versions = ">=3.7" +files = [ + {file = "mdurl-0.1.2-py3-none-any.whl", hash = "sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8"}, + {file = "mdurl-0.1.2.tar.gz", hash = "sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba"}, +] + +[[package]] +name = "mypy-extensions" +version = "1.0.0" +description = "Type system extensions for programs checked with the mypy type checker." +category = "dev" +optional = false +python-versions = ">=3.5" +files = [ + {file = "mypy_extensions-1.0.0-py3-none-any.whl", hash = "sha256:4392f6c0eb8a5668a69e23d168ffa70f0be9ccfd32b5cc2d26a34ae5b844552d"}, + {file = "mypy_extensions-1.0.0.tar.gz", hash = "sha256:75dbf8955dc00442a438fc4d0666508a9a97b6bd41aa2f0ffe9d2f2725af0782"}, +] + +[[package]] +name = "nodeenv" +version = "1.7.0" +description = "Node.js virtual environment builder" +category = "dev" +optional = false +python-versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*" +files = [ + {file = "nodeenv-1.7.0-py2.py3-none-any.whl", hash = "sha256:27083a7b96a25f2f5e1d8cb4b6317ee8aeda3bdd121394e5ac54e498028a042e"}, + {file = "nodeenv-1.7.0.tar.gz", hash = "sha256:e0e7f7dfb85fc5394c6fe1e8fa98131a2473e04311a45afb6508f7cf1836fa2b"}, +] + +[package.dependencies] +setuptools = "*" + +[[package]] +name = "packaging" +version = "23.1" +description = "Core utilities for Python packages" +category = "dev" +optional = false +python-versions = ">=3.7" +files = [ + {file = "packaging-23.1-py3-none-any.whl", hash = "sha256:994793af429502c4ea2ebf6bf664629d07c1a9fe974af92966e4b8d2df7edc61"}, + {file = "packaging-23.1.tar.gz", hash = "sha256:a392980d2b6cffa644431898be54b0045151319d1e7ec34f0cfed48767dd334f"}, +] + +[[package]] +name = "pathspec" +version = "0.10.3" +description = "Utility library for gitignore style pattern matching of file paths." +category = "dev" +optional = false +python-versions = ">=3.7" +files = [ + {file = "pathspec-0.10.3-py3-none-any.whl", hash = "sha256:3c95343af8b756205e2aba76e843ba9520a24dd84f68c22b9f93251507509dd6"}, + {file = "pathspec-0.10.3.tar.gz", hash = "sha256:56200de4077d9d0791465aa9095a01d421861e405b5096955051deefd697d6f6"}, +] + +[[package]] +name = "pbr" +version = "5.11.1" +description = "Python Build Reasonableness" +category = "dev" +optional = false +python-versions = ">=2.6" +files = [ + {file = "pbr-5.11.1-py2.py3-none-any.whl", hash = "sha256:567f09558bae2b3ab53cb3c1e2e33e726ff3338e7bae3db5dc954b3a44eef12b"}, + {file = "pbr-5.11.1.tar.gz", hash = "sha256:aefc51675b0b533d56bb5fd1c8c6c0522fe31896679882e1c4c63d5e4a0fccb3"}, +] + +[[package]] +name = "platformdirs" +version = "3.5.0" +description = "A small Python package for determining appropriate platform-specific dirs, e.g. a \"user data dir\"." +category = "dev" +optional = false +python-versions = ">=3.7" +files = [ + {file = "platformdirs-3.5.0-py3-none-any.whl", hash = "sha256:47692bc24c1958e8b0f13dd727307cff1db103fca36399f457da8e05f222fdc4"}, + {file = "platformdirs-3.5.0.tar.gz", hash = "sha256:7954a68d0ba23558d753f73437c55f89027cf8f5108c19844d4b82e5af396335"}, +] + +[package.extras] +docs = ["furo (>=2023.3.27)", "proselint (>=0.13)", "sphinx (>=6.1.3)", "sphinx-autodoc-typehints (>=1.23,!=1.23.4)"] +test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=7.3.1)", "pytest-cov (>=4)", "pytest-mock (>=3.10)"] + +[[package]] +name = "pluggy" +version = "1.0.0" +description = "plugin and hook calling mechanisms for python" +category = "dev" +optional = false +python-versions = ">=3.6" +files = [ + {file = "pluggy-1.0.0-py2.py3-none-any.whl", hash = "sha256:74134bbf457f031a36d68416e1509f34bd5ccc019f0bcc952c7b909d06b37bd3"}, + {file = "pluggy-1.0.0.tar.gz", hash = "sha256:4224373bacce55f955a878bf9cfa763c1e360858e330072059e10bad68531159"}, +] + +[package.extras] +dev = ["pre-commit", "tox"] +testing = ["pytest", "pytest-benchmark"] + +[[package]] +name = "py" +version = "1.11.0" +description = "library with cross-python path, ini-parsing, io, code, log facilities" +category = "dev" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" +files = [ + {file = "py-1.11.0-py2.py3-none-any.whl", hash = "sha256:607c53218732647dff4acdfcd50cb62615cedf612e72d1724fb1a0cc6405b378"}, + {file = "py-1.11.0.tar.gz", hash = "sha256:51c75c4126074b472f746a24399ad32f6053d1b34b68d2fa41e558e6f4a98719"}, +] + +[[package]] +name = "pycln" +version = "2.1.3" +description = "A formatter for finding and removing unused import statements." +category = "dev" +optional = false +python-versions = ">=3.6.2,<4" +files = [ + {file = "pycln-2.1.3-py3-none-any.whl", hash = "sha256:161142502e4ff9853cd462a38401e29eb56235919856df2cb7fa4c84e463717f"}, + {file = "pycln-2.1.3.tar.gz", hash = "sha256:a33bfc64ded74a623b7cf49eca38b58db4348facc60c35af26d45de149b256f5"}, +] + +[package.dependencies] +libcst = {version = ">=0.3.10,<0.5.0", markers = "python_version >= \"3.7\""} +pathspec = ">=0.9.0,<0.11.0" +pyyaml = ">=5.3.1,<7.0.0" +tomlkit = ">=0.11.1,<0.12.0" +typer = ">=0.4.1,<0.8.0" + +[[package]] +name = "pydocstyle" +version = "6.3.0" +description = "Python docstring style checker" +category = "dev" +optional = false +python-versions = ">=3.6" +files = [ + {file = "pydocstyle-6.3.0-py3-none-any.whl", hash = "sha256:118762d452a49d6b05e194ef344a55822987a462831ade91ec5c06fd2169d019"}, + {file = "pydocstyle-6.3.0.tar.gz", hash = "sha256:7ce43f0c0ac87b07494eb9c0b462c0b73e6ff276807f204d6b53edc72b7e44e1"}, +] + +[package.dependencies] +snowballstemmer = ">=2.2.0" + +[package.extras] +toml = ["tomli (>=1.2.3)"] + +[[package]] +name = "pygments" +version = "2.15.1" +description = "Pygments is a syntax highlighting package written in Python." +category = "dev" +optional = false +python-versions = ">=3.7" +files = [ + {file = "Pygments-2.15.1-py3-none-any.whl", hash = "sha256:db2db3deb4b4179f399a09054b023b6a586b76499d36965813c71aa8ed7b5fd1"}, + {file = "Pygments-2.15.1.tar.gz", hash = "sha256:8ace4d3c1dd481894b2005f560ead0f9f19ee64fe983366be1a21e171d12775c"}, +] + +[package.extras] +plugins = ["importlib-metadata"] + +[[package]] +name = "pylint" +version = "2.17.3" +description = "python code static checker" +category = "dev" +optional = false +python-versions = ">=3.7.2" +files = [ + {file = "pylint-2.17.3-py3-none-any.whl", hash = "sha256:a6cbb4c6e96eab4a3c7de7c6383c512478f58f88d95764507d84c899d656a89a"}, + {file = "pylint-2.17.3.tar.gz", hash = "sha256:761907349e699f8afdcd56c4fe02f3021ab5b3a0fc26d19a9bfdc66c7d0d5cd5"}, +] + +[package.dependencies] +astroid = ">=2.15.4,<=2.17.0-dev0" +colorama = {version = ">=0.4.5", markers = "sys_platform == \"win32\""} +dill = [ + {version = ">=0.2", markers = "python_version < \"3.11\""}, + {version = ">=0.3.6", markers = "python_version >= \"3.11\""}, +] +isort = ">=4.2.5,<6" +mccabe = ">=0.6,<0.8" +platformdirs = ">=2.2.0" +tomli = {version = ">=1.1.0", markers = "python_version < \"3.11\""} +tomlkit = ">=0.10.1" + +[package.extras] +spelling = ["pyenchant (>=3.2,<4.0)"] +testutils = ["gitpython (>3)"] + +[[package]] +name = "pyright" +version = "1.1.305" +description = "Command line wrapper for pyright" +category = "dev" +optional = false +python-versions = ">=3.7" +files = [ + {file = "pyright-1.1.305-py3-none-any.whl", hash = "sha256:147da3aac44ba0516423613cad5fbb7a0abba6b71c53718a1e151f456d4ab12e"}, + {file = "pyright-1.1.305.tar.gz", hash = "sha256:924d554253ecc4fafdfbfa76989d173cc15d426aa808630c0dd669fdc3227ef7"}, +] + +[package.dependencies] +nodeenv = ">=1.6.0" + +[package.extras] +all = ["twine (>=3.4.1)"] +dev = ["twine (>=3.4.1)"] + +[[package]] +name = "pytest" +version = "7.3.1" +description = "pytest: simple powerful testing with Python" +category = "dev" +optional = false +python-versions = ">=3.7" +files = [ + {file = "pytest-7.3.1-py3-none-any.whl", hash = "sha256:3799fa815351fea3a5e96ac7e503a96fa51cc9942c3753cda7651b93c1cfa362"}, + {file = "pytest-7.3.1.tar.gz", hash = "sha256:434afafd78b1d78ed0addf160ad2b77a30d35d4bdf8af234fe621919d9ed15e3"}, +] + +[package.dependencies] +colorama = {version = "*", markers = "sys_platform == \"win32\""} +exceptiongroup = {version = ">=1.0.0rc8", markers = "python_version < \"3.11\""} +iniconfig = "*" +packaging = "*" +pluggy = ">=0.12,<2.0" +tomli = {version = ">=1.0.0", markers = "python_version < \"3.11\""} + +[package.extras] +testing = ["argcomplete", "attrs (>=19.2.0)", "hypothesis (>=3.56)", "mock", "nose", "pygments (>=2.7.2)", "requests", "xmlschema"] + +[[package]] +name = "pytest-asyncio" +version = "0.19.0" +description = "Pytest support for asyncio" +category = "dev" +optional = false +python-versions = ">=3.7" +files = [ + {file = "pytest-asyncio-0.19.0.tar.gz", hash = "sha256:ac4ebf3b6207259750bc32f4c1d8fcd7e79739edbc67ad0c58dd150b1d072fed"}, + {file = "pytest_asyncio-0.19.0-py3-none-any.whl", hash = "sha256:7a97e37cfe1ed296e2e84941384bdd37c376453912d397ed39293e0916f521fa"}, +] + +[package.dependencies] +pytest = ">=6.1.0" + +[package.extras] +testing = ["coverage (>=6.2)", "flaky (>=3.5.0)", "hypothesis (>=5.7.1)", "mypy (>=0.931)", "pytest-trio (>=0.7.0)"] + +[[package]] +name = "pyyaml" +version = "6.0" +description = "YAML parser and emitter for Python" +category = "dev" +optional = false +python-versions = ">=3.6" +files = [ + {file = "PyYAML-6.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d4db7c7aef085872ef65a8fd7d6d09a14ae91f691dec3e87ee5ee0539d516f53"}, + {file = "PyYAML-6.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9df7ed3b3d2e0ecfe09e14741b857df43adb5a3ddadc919a2d94fbdf78fea53c"}, + {file = "PyYAML-6.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:77f396e6ef4c73fdc33a9157446466f1cff553d979bd00ecb64385760c6babdc"}, + {file = "PyYAML-6.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a80a78046a72361de73f8f395f1f1e49f956c6be882eed58505a15f3e430962b"}, + {file = "PyYAML-6.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:f84fbc98b019fef2ee9a1cb3ce93e3187a6df0b2538a651bfb890254ba9f90b5"}, + {file = "PyYAML-6.0-cp310-cp310-win32.whl", hash = "sha256:2cd5df3de48857ed0544b34e2d40e9fac445930039f3cfe4bcc592a1f836d513"}, + {file = "PyYAML-6.0-cp310-cp310-win_amd64.whl", hash = "sha256:daf496c58a8c52083df09b80c860005194014c3698698d1a57cbcfa182142a3a"}, + {file = "PyYAML-6.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:d4b0ba9512519522b118090257be113b9468d804b19d63c71dbcf4a48fa32358"}, + {file = "PyYAML-6.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:81957921f441d50af23654aa6c5e5eaf9b06aba7f0a19c18a538dc7ef291c5a1"}, + {file = "PyYAML-6.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:afa17f5bc4d1b10afd4466fd3a44dc0e245382deca5b3c353d8b757f9e3ecb8d"}, + {file = "PyYAML-6.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:dbad0e9d368bb989f4515da330b88a057617d16b6a8245084f1b05400f24609f"}, + {file = "PyYAML-6.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:432557aa2c09802be39460360ddffd48156e30721f5e8d917f01d31694216782"}, + {file = "PyYAML-6.0-cp311-cp311-win32.whl", hash = "sha256:bfaef573a63ba8923503d27530362590ff4f576c626d86a9fed95822a8255fd7"}, + {file = "PyYAML-6.0-cp311-cp311-win_amd64.whl", hash = "sha256:01b45c0191e6d66c470b6cf1b9531a771a83c1c4208272ead47a3ae4f2f603bf"}, + {file = "PyYAML-6.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:897b80890765f037df3403d22bab41627ca8811ae55e9a722fd0392850ec4d86"}, + {file = "PyYAML-6.0-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:50602afada6d6cbfad699b0c7bb50d5ccffa7e46a3d738092afddc1f9758427f"}, + {file = "PyYAML-6.0-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:48c346915c114f5fdb3ead70312bd042a953a8ce5c7106d5bfb1a5254e47da92"}, + {file = "PyYAML-6.0-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:98c4d36e99714e55cfbaaee6dd5badbc9a1ec339ebfc3b1f52e293aee6bb71a4"}, + {file = "PyYAML-6.0-cp36-cp36m-win32.whl", hash = "sha256:0283c35a6a9fbf047493e3a0ce8d79ef5030852c51e9d911a27badfde0605293"}, + {file = "PyYAML-6.0-cp36-cp36m-win_amd64.whl", hash = "sha256:07751360502caac1c067a8132d150cf3d61339af5691fe9e87803040dbc5db57"}, + {file = "PyYAML-6.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:819b3830a1543db06c4d4b865e70ded25be52a2e0631ccd2f6a47a2822f2fd7c"}, + {file = "PyYAML-6.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:473f9edb243cb1935ab5a084eb238d842fb8f404ed2193a915d1784b5a6b5fc0"}, + {file = "PyYAML-6.0-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0ce82d761c532fe4ec3f87fc45688bdd3a4c1dc5e0b4a19814b9009a29baefd4"}, + {file = "PyYAML-6.0-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:231710d57adfd809ef5d34183b8ed1eeae3f76459c18fb4a0b373ad56bedcdd9"}, + {file = "PyYAML-6.0-cp37-cp37m-win32.whl", hash = "sha256:c5687b8d43cf58545ade1fe3e055f70eac7a5a1a0bf42824308d868289a95737"}, + {file = "PyYAML-6.0-cp37-cp37m-win_amd64.whl", hash = "sha256:d15a181d1ecd0d4270dc32edb46f7cb7733c7c508857278d3d378d14d606db2d"}, + {file = "PyYAML-6.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:0b4624f379dab24d3725ffde76559cff63d9ec94e1736b556dacdfebe5ab6d4b"}, + {file = "PyYAML-6.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:213c60cd50106436cc818accf5baa1aba61c0189ff610f64f4a3e8c6726218ba"}, + {file = "PyYAML-6.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9fa600030013c4de8165339db93d182b9431076eb98eb40ee068700c9c813e34"}, + {file = "PyYAML-6.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:277a0ef2981ca40581a47093e9e2d13b3f1fbbeffae064c1d21bfceba2030287"}, + {file = "PyYAML-6.0-cp38-cp38-win32.whl", hash = "sha256:d4eccecf9adf6fbcc6861a38015c2a64f38b9d94838ac1810a9023a0609e1b78"}, + {file = "PyYAML-6.0-cp38-cp38-win_amd64.whl", hash = "sha256:1e4747bc279b4f613a09eb64bba2ba602d8a6664c6ce6396a4d0cd413a50ce07"}, + {file = "PyYAML-6.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:055d937d65826939cb044fc8c9b08889e8c743fdc6a32b33e2390f66013e449b"}, + {file = "PyYAML-6.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:e61ceaab6f49fb8bdfaa0f92c4b57bcfbea54c09277b1b4f7ac376bfb7a7c174"}, + {file = "PyYAML-6.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d67d839ede4ed1b28a4e8909735fc992a923cdb84e618544973d7dfc71540803"}, + {file = "PyYAML-6.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cba8c411ef271aa037d7357a2bc8f9ee8b58b9965831d9e51baf703280dc73d3"}, + {file = "PyYAML-6.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:40527857252b61eacd1d9af500c3337ba8deb8fc298940291486c465c8b46ec0"}, + {file = "PyYAML-6.0-cp39-cp39-win32.whl", hash = "sha256:b5b9eccad747aabaaffbc6064800670f0c297e52c12754eb1d976c57e4f74dcb"}, + {file = "PyYAML-6.0-cp39-cp39-win_amd64.whl", hash = "sha256:b3d267842bf12586ba6c734f89d1f5b871df0273157918b0ccefa29deb05c21c"}, + {file = "PyYAML-6.0.tar.gz", hash = "sha256:68fb519c14306fec9720a2a5b45bc9f0c8d1b9c72adf45c37baedfcd949c35a2"}, +] + +[[package]] +name = "rich" +version = "13.3.5" +description = "Render rich text, tables, progress bars, syntax highlighting, markdown and more to the terminal" +category = "dev" +optional = false +python-versions = ">=3.7.0" +files = [ + {file = "rich-13.3.5-py3-none-any.whl", hash = "sha256:69cdf53799e63f38b95b9bf9c875f8c90e78dd62b2f00c13a911c7a3b9fa4704"}, + {file = "rich-13.3.5.tar.gz", hash = "sha256:2d11b9b8dd03868f09b4fffadc84a6a8cda574e40dc90821bd845720ebb8e89c"}, +] + +[package.dependencies] +markdown-it-py = ">=2.2.0,<3.0.0" +pygments = ">=2.13.0,<3.0.0" + +[package.extras] +jupyter = ["ipywidgets (>=7.5.1,<9)"] + +[[package]] +name = "setuptools" +version = "67.7.2" +description = "Easily download, build, install, upgrade, and uninstall Python packages" +category = "dev" +optional = false +python-versions = ">=3.7" +files = [ + {file = "setuptools-67.7.2-py3-none-any.whl", hash = "sha256:23aaf86b85ca52ceb801d32703f12d77517b2556af839621c641fca11287952b"}, + {file = "setuptools-67.7.2.tar.gz", hash = "sha256:f104fa03692a2602fa0fec6c6a9e63b6c8a968de13e17c026957dd1f53d80990"}, +] + +[package.extras] +docs = ["furo", "jaraco.packaging (>=9)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-favicon", "sphinx-hoverxref (<2)", "sphinx-inline-tabs", "sphinx-lint", "sphinx-notfound-page (==0.8.3)", "sphinx-reredirects", "sphinxcontrib-towncrier"] +testing = ["build[virtualenv]", "filelock (>=3.4.0)", "flake8 (<5)", "flake8-2020", "ini2toml[lite] (>=0.9)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "pip (>=19.1)", "pip-run (>=8.8)", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=1.3)", "pytest-flake8", "pytest-mypy (>=0.9.1)", "pytest-perf", "pytest-timeout", "pytest-xdist", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel"] +testing-integration = ["build[virtualenv]", "filelock (>=3.4.0)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "pytest", "pytest-enabler", "pytest-xdist", "tomli", "virtualenv (>=13.0.0)", "wheel"] + +[[package]] +name = "six" +version = "1.16.0" +description = "Python 2 and 3 compatibility utilities" +category = "dev" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*" +files = [ + {file = "six-1.16.0-py2.py3-none-any.whl", hash = "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"}, + {file = "six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"}, +] + +[[package]] +name = "smmap" +version = "5.0.0" +description = "A pure Python implementation of a sliding window memory map manager" +category = "dev" +optional = false +python-versions = ">=3.6" +files = [ + {file = "smmap-5.0.0-py3-none-any.whl", hash = "sha256:2aba19d6a040e78d8b09de5c57e96207b09ed71d8e55ce0959eeee6c8e190d94"}, + {file = "smmap-5.0.0.tar.gz", hash = "sha256:c840e62059cd3be204b0c9c9f74be2c09d5648eddd4580d9314c3ecde0b30936"}, +] + +[[package]] +name = "snowballstemmer" +version = "2.2.0" +description = "This package provides 29 stemmers for 28 languages generated from Snowball algorithms." +category = "dev" +optional = false +python-versions = "*" +files = [ + {file = "snowballstemmer-2.2.0-py2.py3-none-any.whl", hash = "sha256:c8e1716e83cc398ae16824e5572ae04e0d9fc2c6b985fb0f900f5f0c96ecba1a"}, + {file = "snowballstemmer-2.2.0.tar.gz", hash = "sha256:09b16deb8547d3412ad7b590689584cd0fe25ec8db3be37788be3810cbf19cb1"}, +] + +[[package]] +name = "stevedore" +version = "5.0.0" +description = "Manage dynamic plugins for Python applications" +category = "dev" +optional = false +python-versions = ">=3.8" +files = [ + {file = "stevedore-5.0.0-py3-none-any.whl", hash = "sha256:bd5a71ff5e5e5f5ea983880e4a1dd1bb47f8feebbb3d95b592398e2f02194771"}, + {file = "stevedore-5.0.0.tar.gz", hash = "sha256:2c428d2338976279e8eb2196f7a94910960d9f7ba2f41f3988511e95ca447021"}, +] + +[package.dependencies] +pbr = ">=2.0.0,<2.1.0 || >2.1.0" + +[[package]] +name = "toml" +version = "0.10.2" +description = "Python Library for Tom's Obvious, Minimal Language" +category = "dev" +optional = false +python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*" +files = [ + {file = "toml-0.10.2-py2.py3-none-any.whl", hash = "sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b"}, + {file = "toml-0.10.2.tar.gz", hash = "sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f"}, +] + +[[package]] +name = "tomli" +version = "2.0.1" +description = "A lil' TOML parser" +category = "dev" +optional = false +python-versions = ">=3.7" +files = [ + {file = "tomli-2.0.1-py3-none-any.whl", hash = "sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc"}, + {file = "tomli-2.0.1.tar.gz", hash = "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f"}, +] + +[[package]] +name = "tomlkit" +version = "0.11.8" +description = "Style preserving TOML library" +category = "dev" +optional = false +python-versions = ">=3.7" +files = [ + {file = "tomlkit-0.11.8-py3-none-any.whl", hash = "sha256:8c726c4c202bdb148667835f68d68780b9a003a9ec34167b6c673b38eff2a171"}, + {file = "tomlkit-0.11.8.tar.gz", hash = "sha256:9330fc7faa1db67b541b28e62018c17d20be733177d290a13b24c62d1614e0c3"}, +] + +[[package]] +name = "tox" +version = "3.28.0" +description = "tox is a generic virtualenv management and test command line tool" +category = "dev" +optional = false +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7" +files = [ + {file = "tox-3.28.0-py2.py3-none-any.whl", hash = "sha256:57b5ab7e8bb3074edc3c0c0b4b192a4f3799d3723b2c5b76f1fa9f2d40316eea"}, + {file = "tox-3.28.0.tar.gz", hash = "sha256:d0d28f3fe6d6d7195c27f8b054c3e99d5451952b54abdae673b71609a581f640"}, +] + +[package.dependencies] +colorama = {version = ">=0.4.1", markers = "platform_system == \"Windows\""} +filelock = ">=3.0.0" +packaging = ">=14" +pluggy = ">=0.12.0" +py = ">=1.4.17" +six = ">=1.14.0" +tomli = {version = ">=2.0.1", markers = "python_version >= \"3.7\" and python_version < \"3.11\""} +virtualenv = ">=16.0.0,<20.0.0 || >20.0.0,<20.0.1 || >20.0.1,<20.0.2 || >20.0.2,<20.0.3 || >20.0.3,<20.0.4 || >20.0.4,<20.0.5 || >20.0.5,<20.0.6 || >20.0.6,<20.0.7 || >20.0.7" + +[package.extras] +docs = ["pygments-github-lexers (>=0.0.5)", "sphinx (>=2.0.0)", "sphinxcontrib-autoprogram (>=0.1.5)", "towncrier (>=18.5.0)"] +testing = ["flaky (>=3.4.0)", "freezegun (>=0.3.11)", "pathlib2 (>=2.3.3)", "psutil (>=5.6.1)", "pytest (>=4.0.0)", "pytest-cov (>=2.5.1)", "pytest-mock (>=1.10.0)", "pytest-randomly (>=1.0.0)"] + +[[package]] +name = "tox-poetry" +version = "0.4.1" +description = "Tox poetry plugin" +category = "dev" +optional = false +python-versions = "*" +files = [ + {file = "tox-poetry-0.4.1.tar.gz", hash = "sha256:2395808e1ce487b5894c10f2202e14702bfa6d6909c0d1e525170d14809ac7ef"}, + {file = "tox_poetry-0.4.1-py2.py3-none-any.whl", hash = "sha256:11d9cd4e51d4cd9484b3ba63f2650ab4cfb4096e5f0682ecf561ddfc3c8e8c92"}, +] + +[package.dependencies] +pluggy = "*" +toml = "*" +tox = {version = ">=3.7.0", markers = "python_version >= \"3\""} + +[package.extras] +test = ["coverage", "pycodestyle", "pylint", "pytest"] + +[[package]] +name = "typer" +version = "0.7.0" +description = "Typer, build great CLIs. Easy to code. Based on Python type hints." +category = "dev" +optional = false +python-versions = ">=3.6" +files = [ + {file = "typer-0.7.0-py3-none-any.whl", hash = "sha256:b5e704f4e48ec263de1c0b3a2387cd405a13767d2f907f44c1a08cbad96f606d"}, + {file = "typer-0.7.0.tar.gz", hash = "sha256:ff797846578a9f2a201b53442aedeb543319466870fbe1c701eab66dd7681165"}, +] + +[package.dependencies] +click = ">=7.1.1,<9.0.0" + +[package.extras] +all = ["colorama (>=0.4.3,<0.5.0)", "rich (>=10.11.0,<13.0.0)", "shellingham (>=1.3.0,<2.0.0)"] +dev = ["autoflake (>=1.3.1,<2.0.0)", "flake8 (>=3.8.3,<4.0.0)", "pre-commit (>=2.17.0,<3.0.0)"] +doc = ["cairosvg (>=2.5.2,<3.0.0)", "mdx-include (>=1.4.1,<2.0.0)", "mkdocs (>=1.1.2,<2.0.0)", "mkdocs-material (>=8.1.4,<9.0.0)", "pillow (>=9.3.0,<10.0.0)"] +test = ["black (>=22.3.0,<23.0.0)", "coverage (>=6.2,<7.0)", "isort (>=5.0.6,<6.0.0)", "mypy (==0.910)", "pytest (>=4.4.0,<8.0.0)", "pytest-cov (>=2.10.0,<5.0.0)", "pytest-sugar (>=0.9.4,<0.10.0)", "pytest-xdist (>=1.32.0,<4.0.0)", "rich (>=10.11.0,<13.0.0)", "shellingham (>=1.3.0,<2.0.0)"] + +[[package]] +name = "typing-extensions" +version = "4.5.0" +description = "Backported and Experimental Type Hints for Python 3.7+" +category = "dev" +optional = false +python-versions = ">=3.7" +files = [ + {file = "typing_extensions-4.5.0-py3-none-any.whl", hash = "sha256:fb33085c39dd998ac16d1431ebc293a8b3eedd00fd4a32de0ff79002c19511b4"}, + {file = "typing_extensions-4.5.0.tar.gz", hash = "sha256:5cb5f4a79139d699607b3ef622a1dedafa84e115ab0024e0d9c044a9479ca7cb"}, +] + +[[package]] +name = "typing-inspect" +version = "0.8.0" +description = "Runtime inspection utilities for typing module." +category = "dev" +optional = false +python-versions = "*" +files = [ + {file = "typing_inspect-0.8.0-py3-none-any.whl", hash = "sha256:5fbf9c1e65d4fa01e701fe12a5bca6c6e08a4ffd5bc60bfac028253a447c5188"}, + {file = "typing_inspect-0.8.0.tar.gz", hash = "sha256:8b1ff0c400943b6145df8119c41c244ca8207f1f10c9c057aeed1560e4806e3d"}, +] + +[package.dependencies] +mypy-extensions = ">=0.3.0" +typing-extensions = ">=3.7.4" + +[[package]] +name = "virtualenv" +version = "20.23.0" +description = "Virtual Python Environment builder" +category = "dev" +optional = false +python-versions = ">=3.7" +files = [ + {file = "virtualenv-20.23.0-py3-none-any.whl", hash = "sha256:6abec7670e5802a528357fdc75b26b9f57d5d92f29c5462ba0fbe45feacc685e"}, + {file = "virtualenv-20.23.0.tar.gz", hash = "sha256:a85caa554ced0c0afbd0d638e7e2d7b5f92d23478d05d17a76daeac8f279f924"}, +] + +[package.dependencies] +distlib = ">=0.3.6,<1" +filelock = ">=3.11,<4" +platformdirs = ">=3.2,<4" + +[package.extras] +docs = ["furo (>=2023.3.27)", "proselint (>=0.13)", "sphinx (>=6.1.3)", "sphinx-argparse (>=0.4)", "sphinxcontrib-towncrier (>=0.2.1a0)", "towncrier (>=22.12)"] +test = ["covdefaults (>=2.3)", "coverage (>=7.2.3)", "coverage-enable-subprocess (>=1)", "flaky (>=3.7)", "packaging (>=23.1)", "pytest (>=7.3.1)", "pytest-env (>=0.8.1)", "pytest-freezegun (>=0.4.2)", "pytest-mock (>=3.10)", "pytest-randomly (>=3.12)", "pytest-timeout (>=2.1)", "setuptools (>=67.7.1)", "time-machine (>=2.9)"] + +[[package]] +name = "wrapt" +version = "1.15.0" +description = "Module for decorators, wrappers and monkey patching." +category = "dev" +optional = false +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7" +files = [ + {file = "wrapt-1.15.0-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:ca1cccf838cd28d5a0883b342474c630ac48cac5df0ee6eacc9c7290f76b11c1"}, + {file = "wrapt-1.15.0-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:e826aadda3cae59295b95343db8f3d965fb31059da7de01ee8d1c40a60398b29"}, + {file = "wrapt-1.15.0-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:5fc8e02f5984a55d2c653f5fea93531e9836abbd84342c1d1e17abc4a15084c2"}, + {file = "wrapt-1.15.0-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:96e25c8603a155559231c19c0349245eeb4ac0096fe3c1d0be5c47e075bd4f46"}, + {file = "wrapt-1.15.0-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:40737a081d7497efea35ab9304b829b857f21558acfc7b3272f908d33b0d9d4c"}, + {file = "wrapt-1.15.0-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:f87ec75864c37c4c6cb908d282e1969e79763e0d9becdfe9fe5473b7bb1e5f09"}, + {file = "wrapt-1.15.0-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:1286eb30261894e4c70d124d44b7fd07825340869945c79d05bda53a40caa079"}, + {file = "wrapt-1.15.0-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:493d389a2b63c88ad56cdc35d0fa5752daac56ca755805b1b0c530f785767d5e"}, + {file = "wrapt-1.15.0-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:58d7a75d731e8c63614222bcb21dd992b4ab01a399f1f09dd82af17bbfc2368a"}, + {file = "wrapt-1.15.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:21f6d9a0d5b3a207cdf7acf8e58d7d13d463e639f0c7e01d82cdb671e6cb7923"}, + {file = "wrapt-1.15.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:ce42618f67741d4697684e501ef02f29e758a123aa2d669e2d964ff734ee00ee"}, + {file = "wrapt-1.15.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:41d07d029dd4157ae27beab04d22b8e261eddfc6ecd64ff7000b10dc8b3a5727"}, + {file = "wrapt-1.15.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:54accd4b8bc202966bafafd16e69da9d5640ff92389d33d28555c5fd4f25ccb7"}, + {file = "wrapt-1.15.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2fbfbca668dd15b744418265a9607baa970c347eefd0db6a518aaf0cfbd153c0"}, + {file = "wrapt-1.15.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:76e9c727a874b4856d11a32fb0b389afc61ce8aaf281ada613713ddeadd1cfec"}, + {file = "wrapt-1.15.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:e20076a211cd6f9b44a6be58f7eeafa7ab5720eb796975d0c03f05b47d89eb90"}, + {file = "wrapt-1.15.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:a74d56552ddbde46c246b5b89199cb3fd182f9c346c784e1a93e4dc3f5ec9975"}, + {file = "wrapt-1.15.0-cp310-cp310-win32.whl", hash = "sha256:26458da5653aa5b3d8dc8b24192f574a58984c749401f98fff994d41d3f08da1"}, + {file = "wrapt-1.15.0-cp310-cp310-win_amd64.whl", hash = "sha256:75760a47c06b5974aa5e01949bf7e66d2af4d08cb8c1d6516af5e39595397f5e"}, + {file = "wrapt-1.15.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:ba1711cda2d30634a7e452fc79eabcadaffedf241ff206db2ee93dd2c89a60e7"}, + {file = "wrapt-1.15.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:56374914b132c702aa9aa9959c550004b8847148f95e1b824772d453ac204a72"}, + {file = "wrapt-1.15.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a89ce3fd220ff144bd9d54da333ec0de0399b52c9ac3d2ce34b569cf1a5748fb"}, + {file = "wrapt-1.15.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3bbe623731d03b186b3d6b0d6f51865bf598587c38d6f7b0be2e27414f7f214e"}, + {file = "wrapt-1.15.0-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3abbe948c3cbde2689370a262a8d04e32ec2dd4f27103669a45c6929bcdbfe7c"}, + {file = "wrapt-1.15.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:b67b819628e3b748fd3c2192c15fb951f549d0f47c0449af0764d7647302fda3"}, + {file = "wrapt-1.15.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:7eebcdbe3677e58dd4c0e03b4f2cfa346ed4049687d839adad68cc38bb559c92"}, + {file = "wrapt-1.15.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:74934ebd71950e3db69960a7da29204f89624dde411afbfb3b4858c1409b1e98"}, + {file = "wrapt-1.15.0-cp311-cp311-win32.whl", hash = "sha256:bd84395aab8e4d36263cd1b9308cd504f6cf713b7d6d3ce25ea55670baec5416"}, + {file = "wrapt-1.15.0-cp311-cp311-win_amd64.whl", hash = "sha256:a487f72a25904e2b4bbc0817ce7a8de94363bd7e79890510174da9d901c38705"}, + {file = "wrapt-1.15.0-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:4ff0d20f2e670800d3ed2b220d40984162089a6e2c9646fdb09b85e6f9a8fc29"}, + {file = "wrapt-1.15.0-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:9ed6aa0726b9b60911f4aed8ec5b8dd7bf3491476015819f56473ffaef8959bd"}, + {file = "wrapt-1.15.0-cp35-cp35m-manylinux2010_i686.whl", hash = "sha256:896689fddba4f23ef7c718279e42f8834041a21342d95e56922e1c10c0cc7afb"}, + {file = "wrapt-1.15.0-cp35-cp35m-manylinux2010_x86_64.whl", hash = "sha256:75669d77bb2c071333417617a235324a1618dba66f82a750362eccbe5b61d248"}, + {file = "wrapt-1.15.0-cp35-cp35m-win32.whl", hash = "sha256:fbec11614dba0424ca72f4e8ba3c420dba07b4a7c206c8c8e4e73f2e98f4c559"}, + {file = "wrapt-1.15.0-cp35-cp35m-win_amd64.whl", hash = "sha256:fd69666217b62fa5d7c6aa88e507493a34dec4fa20c5bd925e4bc12fce586639"}, + {file = "wrapt-1.15.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:b0724f05c396b0a4c36a3226c31648385deb6a65d8992644c12a4963c70326ba"}, + {file = "wrapt-1.15.0-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bbeccb1aa40ab88cd29e6c7d8585582c99548f55f9b2581dfc5ba68c59a85752"}, + {file = "wrapt-1.15.0-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:38adf7198f8f154502883242f9fe7333ab05a5b02de7d83aa2d88ea621f13364"}, + {file = "wrapt-1.15.0-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:578383d740457fa790fdf85e6d346fda1416a40549fe8db08e5e9bd281c6a475"}, + {file = "wrapt-1.15.0-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:a4cbb9ff5795cd66f0066bdf5947f170f5d63a9274f99bdbca02fd973adcf2a8"}, + {file = "wrapt-1.15.0-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:af5bd9ccb188f6a5fdda9f1f09d9f4c86cc8a539bd48a0bfdc97723970348418"}, + {file = "wrapt-1.15.0-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:b56d5519e470d3f2fe4aa7585f0632b060d532d0696c5bdfb5e8319e1d0f69a2"}, + {file = "wrapt-1.15.0-cp36-cp36m-win32.whl", hash = "sha256:77d4c1b881076c3ba173484dfa53d3582c1c8ff1f914c6461ab70c8428b796c1"}, + {file = "wrapt-1.15.0-cp36-cp36m-win_amd64.whl", hash = "sha256:077ff0d1f9d9e4ce6476c1a924a3332452c1406e59d90a2cf24aeb29eeac9420"}, + {file = "wrapt-1.15.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:5c5aa28df055697d7c37d2099a7bc09f559d5053c3349b1ad0c39000e611d317"}, + {file = "wrapt-1.15.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3a8564f283394634a7a7054b7983e47dbf39c07712d7b177b37e03f2467a024e"}, + {file = "wrapt-1.15.0-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:780c82a41dc493b62fc5884fb1d3a3b81106642c5c5c78d6a0d4cbe96d62ba7e"}, + {file = "wrapt-1.15.0-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e169e957c33576f47e21864cf3fc9ff47c223a4ebca8960079b8bd36cb014fd0"}, + {file = "wrapt-1.15.0-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:b02f21c1e2074943312d03d243ac4388319f2456576b2c6023041c4d57cd7019"}, + {file = "wrapt-1.15.0-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:f2e69b3ed24544b0d3dbe2c5c0ba5153ce50dcebb576fdc4696d52aa22db6034"}, + {file = "wrapt-1.15.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:d787272ed958a05b2c86311d3a4135d3c2aeea4fc655705f074130aa57d71653"}, + {file = "wrapt-1.15.0-cp37-cp37m-win32.whl", hash = "sha256:02fce1852f755f44f95af51f69d22e45080102e9d00258053b79367d07af39c0"}, + {file = "wrapt-1.15.0-cp37-cp37m-win_amd64.whl", hash = "sha256:abd52a09d03adf9c763d706df707c343293d5d106aea53483e0ec8d9e310ad5e"}, + {file = "wrapt-1.15.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:cdb4f085756c96a3af04e6eca7f08b1345e94b53af8921b25c72f096e704e145"}, + {file = "wrapt-1.15.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:230ae493696a371f1dbffaad3dafbb742a4d27a0afd2b1aecebe52b740167e7f"}, + {file = "wrapt-1.15.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:63424c681923b9f3bfbc5e3205aafe790904053d42ddcc08542181a30a7a51bd"}, + {file = "wrapt-1.15.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d6bcbfc99f55655c3d93feb7ef3800bd5bbe963a755687cbf1f490a71fb7794b"}, + {file = "wrapt-1.15.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c99f4309f5145b93eca6e35ac1a988f0dc0a7ccf9ccdcd78d3c0adf57224e62f"}, + {file = "wrapt-1.15.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:b130fe77361d6771ecf5a219d8e0817d61b236b7d8b37cc045172e574ed219e6"}, + {file = "wrapt-1.15.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:96177eb5645b1c6985f5c11d03fc2dbda9ad24ec0f3a46dcce91445747e15094"}, + {file = "wrapt-1.15.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:d5fe3e099cf07d0fb5a1e23d399e5d4d1ca3e6dfcbe5c8570ccff3e9208274f7"}, + {file = "wrapt-1.15.0-cp38-cp38-win32.whl", hash = "sha256:abd8f36c99512755b8456047b7be10372fca271bf1467a1caa88db991e7c421b"}, + {file = "wrapt-1.15.0-cp38-cp38-win_amd64.whl", hash = "sha256:b06fa97478a5f478fb05e1980980a7cdf2712015493b44d0c87606c1513ed5b1"}, + {file = "wrapt-1.15.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:2e51de54d4fb8fb50d6ee8327f9828306a959ae394d3e01a1ba8b2f937747d86"}, + {file = "wrapt-1.15.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:0970ddb69bba00670e58955f8019bec4a42d1785db3faa043c33d81de2bf843c"}, + {file = "wrapt-1.15.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:76407ab327158c510f44ded207e2f76b657303e17cb7a572ffe2f5a8a48aa04d"}, + {file = "wrapt-1.15.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:cd525e0e52a5ff16653a3fc9e3dd827981917d34996600bbc34c05d048ca35cc"}, + {file = "wrapt-1.15.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9d37ac69edc5614b90516807de32d08cb8e7b12260a285ee330955604ed9dd29"}, + {file = "wrapt-1.15.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:078e2a1a86544e644a68422f881c48b84fef6d18f8c7a957ffd3f2e0a74a0d4a"}, + {file = "wrapt-1.15.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:2cf56d0e237280baed46f0b5316661da892565ff58309d4d2ed7dba763d984b8"}, + {file = "wrapt-1.15.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:7dc0713bf81287a00516ef43137273b23ee414fe41a3c14be10dd95ed98a2df9"}, + {file = "wrapt-1.15.0-cp39-cp39-win32.whl", hash = "sha256:46ed616d5fb42f98630ed70c3529541408166c22cdfd4540b88d5f21006b0eff"}, + {file = "wrapt-1.15.0-cp39-cp39-win_amd64.whl", hash = "sha256:eef4d64c650f33347c1f9266fa5ae001440b232ad9b98f1f43dfe7a79435c0a6"}, + {file = "wrapt-1.15.0-py3-none-any.whl", hash = "sha256:64b1df0f83706b4ef4cfb4fb0e4c2669100fd7ecacfb59e091fad300d4e04640"}, + {file = "wrapt-1.15.0.tar.gz", hash = "sha256:d06730c6aed78cee4126234cf2d071e01b44b915e725a6cb439a879ec9754a3a"}, +] + +[metadata] +lock-version = "2.0" +python-versions = "^3.10" +content-hash = "da96c8da6df9a1e93509950d064ca803bad959afa8b85410e059156293a30447" diff --git a/packages/polywrap-test-cases/polywrap_test_cases/__init__.py b/packages/polywrap-test-cases/polywrap_test_cases/__init__.py new file mode 100644 index 00000000..b74016f8 --- /dev/null +++ b/packages/polywrap-test-cases/polywrap_test_cases/__init__.py @@ -0,0 +1,39 @@ +"""This package contains the utility functions to fetch the wrappers\ + from the wasm-test-harness repo.""" +import io +import os +import zipfile +from urllib.error import HTTPError +from urllib.request import urlopen + + +def get_path_to_test_wrappers() -> str: + """Get the path to the test wrappers.""" + return os.path.abspath(os.path.join(os.path.dirname(__file__), "..", "wrappers")) + + +def fetch_file(url: str) -> bytes: + """Fetch a file using HTTP.""" + with urlopen(url) as response: + if response.status != 200: + raise HTTPError( + url, response.status, "Failed to fetch file", response.headers, None + ) + return response.read() + + +def unzip_file(file_buffer: bytes, destination: str) -> None: + """Unzip a file to a destination.""" + with zipfile.ZipFile(io.BytesIO(file_buffer), "r") as zip_ref: + zip_ref.extractall(destination) + + +def fetch_wrappers() -> None: + """Fetch the wrappers from the wasm-test-harness repo.""" + tag = "0.1.0" + repo_name = "wasm-test-harness" + url = f"https://github.com/polywrap/{repo_name}/releases/download/{tag}/wrappers" + + buffer = fetch_file(url) + zip_built_folder = get_path_to_test_wrappers() + unzip_file(buffer, zip_built_folder) diff --git a/packages/polywrap-test-cases/polywrap_test_cases/__main__.py b/packages/polywrap-test-cases/polywrap_test_cases/__main__.py new file mode 100644 index 00000000..3df55d7f --- /dev/null +++ b/packages/polywrap-test-cases/polywrap_test_cases/__main__.py @@ -0,0 +1,5 @@ +"""This module contains the main entry point of the package.""" +from . import fetch_wrappers + +if __name__ == "__main__": + fetch_wrappers() diff --git a/packages/polywrap-test-cases/polywrap_test_cases/py.typed b/packages/polywrap-test-cases/polywrap_test_cases/py.typed new file mode 100644 index 00000000..e69de29b diff --git a/packages/polywrap-test-cases/pyproject.toml b/packages/polywrap-test-cases/pyproject.toml new file mode 100644 index 00000000..f78b6fa4 --- /dev/null +++ b/packages/polywrap-test-cases/pyproject.toml @@ -0,0 +1,58 @@ +[build-system] +requires = ["poetry-core"] +build-backend = "poetry.core.masonry.api" + +[tool.poetry] +name = "polywrap-test-cases" +version = "0.1.0a29" +description = "Plugin package" +authors = ["Cesar "] +readme = "README.md" + +[tool.poetry.dependencies] +python = "^3.10" + +[tool.poetry.dev-dependencies] +pytest = "^7.1.2" +pytest-asyncio = "^0.19.0" +pylint = "^2.15.4" +black = "^22.10.0" +bandit = { version = "^1.7.4", extras = ["toml"]} +tox = "^3.26.0" +tox-poetry = "^0.4.1" +isort = "^5.10.1" +pyright = "^1.1.275" +pydocstyle = "^6.1.1" + +[tool.poetry.group.dev.dependencies] +pycln = "^2.1.3" + +[tool.bandit] +exclude_dirs = ["tests"] + +[tool.black] +target-version = ["py310"] + +[tool.pyright] +typeCheckingMode = "strict" +reportShadowedImports = false + +[tool.pytest.ini_options] +asyncio_mode = "auto" +testpaths = [ + "tests" +] + +[tool.pylint] +disable = [ +] +ignore = [ + "tests/" +] + +[tool.isort] +profile = "black" +multi_line_output = 3 + +[tool.pydocstyle] +# default \ No newline at end of file diff --git a/packages/polywrap-test-cases/tests/test_sanity.py b/packages/polywrap-test-cases/tests/test_sanity.py new file mode 100644 index 00000000..176c6edf --- /dev/null +++ b/packages/polywrap-test-cases/tests/test_sanity.py @@ -0,0 +1,16 @@ +import os +from polywrap_test_cases import get_path_to_test_wrappers +import pytest + + +@pytest.mark.parametrize( + "wrapper", ["asyncify", "bigint-type", "enum-type", "map-type"] +) +@pytest.mark.parametrize("language", ["as", "rs"]) +def test_wrappers_exist(wrapper: str, language: str): + assert os.path.exists(get_path_to_test_wrappers()) + wrapper_path = os.path.join(get_path_to_test_wrappers(), wrapper, "implementations", language) + assert os.path.exists(wrapper_path) + assert os.path.isdir(wrapper_path) + assert os.path.exists(os.path.join(wrapper_path, "wrap.info")) + assert os.path.exists(os.path.join(wrapper_path, "wrap.wasm")) diff --git a/packages/polywrap-test-cases/tox.ini b/packages/polywrap-test-cases/tox.ini new file mode 100644 index 00000000..4e7326a9 --- /dev/null +++ b/packages/polywrap-test-cases/tox.ini @@ -0,0 +1,33 @@ +[tox] +isolated_build = True +envlist = py310 + +[testenv] +commands = + pytest tests/ + +[testenv:getwraps] +commands = + python -m polywrap_test_cases + +[testenv:lint] +commands = + isort --check-only polywrap_test_cases + black --check polywrap_test_cases + pycln --check polywrap_test_cases --disable-all-dunder-policy + pylint polywrap_test_cases + pydocstyle polywrap_test_cases + +[testenv:typecheck] +commands = + pyright polywrap_test_cases + +[testenv:secure] +commands = + bandit -r polywrap_test_cases -c pyproject.toml + +[testenv:dev] +commands = + isort polywrap_test_cases + black polywrap_test_cases + pycln polywrap_test_cases --disable-all-dunder-policy diff --git a/python-monorepo.code-workspace b/python-monorepo.code-workspace index d6fea917..7c532afe 100644 --- a/python-monorepo.code-workspace +++ b/python-monorepo.code-workspace @@ -39,6 +39,10 @@ { "name": "polywrap-plugin", "path": "packages/polywrap-plugin" + }, + { + "name": "polywrap-test-cases", + "path": "packages/polywrap-test-cases" } ], "settings": { From 082c1dec08cb4f148586aaf0377501ebff30b97a Mon Sep 17 00:00:00 2001 From: Niraj Kamdar Date: Tue, 6 Jun 2023 03:31:12 +0530 Subject: [PATCH 09/47] fix: skipping trivial CVE for now --- packages/polywrap-test-cases/pyproject.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/polywrap-test-cases/pyproject.toml b/packages/polywrap-test-cases/pyproject.toml index f78b6fa4..73aad8e5 100644 --- a/packages/polywrap-test-cases/pyproject.toml +++ b/packages/polywrap-test-cases/pyproject.toml @@ -29,6 +29,7 @@ pycln = "^2.1.3" [tool.bandit] exclude_dirs = ["tests"] +skips = ["B310"] [tool.black] target-version = ["py310"] From ca863deffb1f945a9fb93673b10ceae7949b0e18 Mon Sep 17 00:00:00 2001 From: Niraj Kamdar Date: Tue, 6 Jun 2023 03:36:45 +0530 Subject: [PATCH 10/47] fix: test-cases tests --- packages/polywrap-test-cases/tox.ini | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/polywrap-test-cases/tox.ini b/packages/polywrap-test-cases/tox.ini index 4e7326a9..bc546a3c 100644 --- a/packages/polywrap-test-cases/tox.ini +++ b/packages/polywrap-test-cases/tox.ini @@ -4,6 +4,7 @@ envlist = py310 [testenv] commands = + python -m polywrap_test_cases pytest tests/ [testenv:getwraps] From 743fd8a833a1636a93899e419e94f304f8f27d17 Mon Sep 17 00:00:00 2001 From: Niraj Kamdar Date: Tue, 6 Jun 2023 02:26:57 +0530 Subject: [PATCH 11/47] refactor: polywrap-uri-resolvers --- .../polywrap-uri-resolvers/assets/style.css | 186 ++++++++++++ packages/polywrap-uri-resolvers/poetry.lock | 280 ++++++++++++------ .../polywrap_uri_resolvers/__init__.py | 1 - .../polywrap_uri_resolvers/errors.py | 32 +- .../resolvers/abc/resolver_with_history.py | 25 +- .../aggregator/uri_resolver_aggregator.py | 83 ++---- .../uri_resolver_aggregator_base.py | 81 +++++ .../resolvers/cache/__init__.py | 3 +- .../cache/request_synchronizer_resolver.py | 132 --------- .../cache/resolution_result_cache_resolver.py | 114 +++++++ .../extensions/extendable_uri_resolver.py | 49 +-- .../extension_wrapper_uri_resolver.py | 162 ++++------ .../uri_resolver_extension_file_reader.py | 18 +- .../resolvers/legacy/base_resolver.py | 16 +- .../resolvers/legacy/fs_resolver.py | 25 +- .../package_to_wrapper_resolver.py | 25 +- .../resolvers/legacy/redirect_resolver.py | 18 +- .../legacy/wrapper_cache/__init__.py | 3 + .../wrapper_cache}/in_memory_wrapper_cache.py | 10 +- .../legacy/wrapper_cache}/wrapper_cache.py | 12 +- .../wrapper_cache_resolver.py} | 30 +- .../resolvers/package/__init__.py | 1 - .../resolvers/package/package_resolver.py | 25 +- .../resolvers/recursive/recursive_resolver.py | 22 +- .../resolvers/redirect/redirect_resolver.py | 15 +- .../resolvers/static/static_resolver.py | 41 ++- .../resolvers/wrapper/wrapper_resolver.py | 23 +- .../polywrap_uri_resolvers/types/__init__.py | 1 - .../types/cache/__init__.py | 5 +- .../cache/resolution_result_cache/__init__.py | 3 + .../in_memory_resolution_result_cache.py | 37 +++ .../resolution_result_cache.py | 29 ++ .../types/static_resolver_like.py | 16 +- .../types/uri_resolution_context/__init__.py | 3 - .../uri_resolution_context.py | 121 -------- .../uri_resolution_step.py | 18 -- .../polywrap_uri_resolvers/utils/__init__.py | 4 - .../utils/build_clean_uri_history.py | 73 ----- .../utils/get_env_from_uri_history.py | 22 -- .../utils/get_uri_resolution_path.py | 35 --- .../polywrap-uri-resolvers/pyproject.toml | 11 +- .../polywrap-uri-resolvers/tests/__init__.py | 0 .../tests/integration/__init__.py | 0 .../aggregator_resolver/__init__.py | 0 .../aggregator_resolver/conftest.py | 18 ++ .../aggregator_resolver/histories/__init__.py | 0 .../histories/can_resolve_first.py | 6 + .../histories/can_resolve_last.py | 8 + .../histories/not_resolve.py | 8 + .../aggregator_resolver/test_can_resolve.py | 28 ++ .../aggregator_resolver/test_not_resolve.py | 15 + .../extension_resolver/__init__.py | 0 .../extension_resolver/histories/__init__.py | 0 .../histories/can_resolve_package.py | 20 ++ .../can_resolve_package_with_subinvoke.py | 30 ++ .../histories/can_resolve_uri.py | 38 +++ .../can_resolve_uri_with_subinvoke.py | 62 ++++ .../histories/can_use_wasm_fs_resolver.py | 30 ++ .../histories/not_a_match.py | 20 ++ .../histories/not_a_match_with_subinvoke.py | 30 ++ .../histories/not_found_extension.py | 13 + .../histories/shows_plugin_extension_error.py | 20 ++ ...s_plugin_extension_error_with_subinvoke.py | 30 ++ .../histories/shows_wasm_extension_error.py | 20 ++ ...ows_wasm_extension_error_with_subinvoke.py | 30 ++ .../integration/extension_resolver/mocker.py | 71 +++++ .../test_can_resolve_package.py | 60 ++++ ...test_can_resolve_package_with_subinvoke.py | 64 ++++ .../test_can_resolve_uri.py | 56 ++++ .../test_can_resolve_uri_with_subinvoke.py | 60 ++++ .../extension_resolver/test_not_a_match.py | 59 ++++ .../test_not_a_match_with_subinvoke.py | 65 ++++ .../test_not_found_extension.py | 44 +++ .../test_shows_plugin_extension_error.py | 59 ++++ ...s_plugin_extension_error_with_subinvoke.py | 64 ++++ .../test_use_wasm_fs_resolver.py | 60 ++++ .../integration/package_resolver/__init__.py | 0 .../integration/package_resolver/conftest.py | 14 + .../package_resolver/histories/__init__.py | 0 .../histories/not_resolve_package.py | 3 + .../histories/resolve_package.py | 3 + .../test_not_resolve_package.py | 14 + .../package_resolver/test_resolve_package.py | 15 + .../recursive_resolver/__init__.py | 0 .../recursive_resolver/conftest.py | 46 +++ .../recursive_resolver/histories/__init__.py | 0 .../histories/infinite_loop.py | 5 + .../histories/no_resolve.py | 3 + .../histories/recursive_resolve.py | 6 + .../recursive_resolver/test_infinite_loop.py | 58 ++++ .../recursive_resolver/test_not_resolve.py | 20 ++ .../test_recursive_resolve.py | 19 ++ .../integration/redirect_resolver/__init__.py | 0 .../integration/redirect_resolver/conftest.py | 14 + .../redirect_resolver/histories/__init__.py | 0 .../histories/can_redirect.py | 3 + .../histories/not_redirect.py | 3 + .../test_can_redirect_uri.py | 17 ++ .../test_not_redirect_uri.py | 17 ++ .../__init__.py | 0 .../conftest.py | 65 ++++ .../histories/__init__.py | 0 .../histories/error_with_cache.py | 3 + .../histories/error_without_cache.py | 4 + .../histories/package_with_cache.py | 3 + .../histories/package_without_cache.py | 6 + .../histories/uri_with_cache.py | 1 + .../histories/uri_without_cache.py | 6 + .../histories/wrapper_with_cache.py | 3 + .../histories/wrapper_without_cache.py | 4 + .../test_cached_error.py | 31 ++ .../test_cached_package.py | 29 ++ .../test_cached_uri.py | 30 ++ .../test_cached_wrapper.py | 29 ++ .../test_not_cached_error.py | 29 ++ .../test_resolution_path.py | 23 ++ .../integration/static_resolver/__init__.py | 0 .../integration/static_resolver/conftest.py | 31 ++ .../static_resolver/histories/__init__.py | 0 .../static_resolver/histories/can_redirect.py | 3 + .../histories/can_resolve_package.py | 3 + .../histories/can_resolve_wrapper.py | 3 + .../static_resolver/histories/not_resolve.py | 3 + .../static_resolver/test_can_redirect.py | 17 ++ .../test_can_resolve_package.py | 15 + .../test_can_resolve_wrapper.py | 14 + .../static_resolver/test_not_resolve.py | 15 + .../integration/wrapper_resolver/__init__.py | 0 .../integration/wrapper_resolver/conftest.py | 14 + .../wrapper_resolver/histories/__init__.py | 0 .../histories/not_resolve_wrapper.py | 3 + .../histories/resolve_wrapper.py | 3 + .../test_not_resolve_wrapper.py | 17 ++ .../wrapper_resolver/test_resolve_wrapper.py | 14 + .../tests/test_static_resolver.py | 70 ----- .../tests/unit/__init__.py | 0 .../tests/{ => unit}/cases/simple/wrap.info | 0 .../tests/{ => unit}/cases/simple/wrap.wasm | Bin .../tests/{ => unit}/test_file_resolver.py | 5 +- packages/polywrap-uri-resolvers/tox.ini | 1 + 140 files changed, 2685 insertions(+), 970 deletions(-) create mode 100644 packages/polywrap-uri-resolvers/assets/style.css create mode 100644 packages/polywrap-uri-resolvers/polywrap_uri_resolvers/resolvers/aggregator/uri_resolver_aggregator_base.py delete mode 100644 packages/polywrap-uri-resolvers/polywrap_uri_resolvers/resolvers/cache/request_synchronizer_resolver.py create mode 100644 packages/polywrap-uri-resolvers/polywrap_uri_resolvers/resolvers/cache/resolution_result_cache_resolver.py rename packages/polywrap-uri-resolvers/polywrap_uri_resolvers/resolvers/{package => legacy}/package_to_wrapper_resolver.py (80%) create mode 100644 packages/polywrap-uri-resolvers/polywrap_uri_resolvers/resolvers/legacy/wrapper_cache/__init__.py rename packages/polywrap-uri-resolvers/polywrap_uri_resolvers/{types/cache => resolvers/legacy/wrapper_cache}/in_memory_wrapper_cache.py (64%) rename packages/polywrap-uri-resolvers/polywrap_uri_resolvers/{types/cache => resolvers/legacy/wrapper_cache}/wrapper_cache.py (54%) rename packages/polywrap-uri-resolvers/polywrap_uri_resolvers/resolvers/{cache/cache_resolver.py => legacy/wrapper_cache_resolver.py} (82%) create mode 100644 packages/polywrap-uri-resolvers/polywrap_uri_resolvers/types/cache/resolution_result_cache/__init__.py create mode 100644 packages/polywrap-uri-resolvers/polywrap_uri_resolvers/types/cache/resolution_result_cache/in_memory_resolution_result_cache.py create mode 100644 packages/polywrap-uri-resolvers/polywrap_uri_resolvers/types/cache/resolution_result_cache/resolution_result_cache.py delete mode 100644 packages/polywrap-uri-resolvers/polywrap_uri_resolvers/types/uri_resolution_context/__init__.py delete mode 100644 packages/polywrap-uri-resolvers/polywrap_uri_resolvers/types/uri_resolution_context/uri_resolution_context.py delete mode 100644 packages/polywrap-uri-resolvers/polywrap_uri_resolvers/types/uri_resolution_context/uri_resolution_step.py delete mode 100644 packages/polywrap-uri-resolvers/polywrap_uri_resolvers/utils/__init__.py delete mode 100644 packages/polywrap-uri-resolvers/polywrap_uri_resolvers/utils/build_clean_uri_history.py delete mode 100644 packages/polywrap-uri-resolvers/polywrap_uri_resolvers/utils/get_env_from_uri_history.py delete mode 100644 packages/polywrap-uri-resolvers/polywrap_uri_resolvers/utils/get_uri_resolution_path.py create mode 100644 packages/polywrap-uri-resolvers/tests/__init__.py create mode 100644 packages/polywrap-uri-resolvers/tests/integration/__init__.py create mode 100644 packages/polywrap-uri-resolvers/tests/integration/aggregator_resolver/__init__.py create mode 100644 packages/polywrap-uri-resolvers/tests/integration/aggregator_resolver/conftest.py create mode 100644 packages/polywrap-uri-resolvers/tests/integration/aggregator_resolver/histories/__init__.py create mode 100644 packages/polywrap-uri-resolvers/tests/integration/aggregator_resolver/histories/can_resolve_first.py create mode 100644 packages/polywrap-uri-resolvers/tests/integration/aggregator_resolver/histories/can_resolve_last.py create mode 100644 packages/polywrap-uri-resolvers/tests/integration/aggregator_resolver/histories/not_resolve.py create mode 100644 packages/polywrap-uri-resolvers/tests/integration/aggregator_resolver/test_can_resolve.py create mode 100644 packages/polywrap-uri-resolvers/tests/integration/aggregator_resolver/test_not_resolve.py create mode 100644 packages/polywrap-uri-resolvers/tests/integration/extension_resolver/__init__.py create mode 100644 packages/polywrap-uri-resolvers/tests/integration/extension_resolver/histories/__init__.py create mode 100644 packages/polywrap-uri-resolvers/tests/integration/extension_resolver/histories/can_resolve_package.py create mode 100644 packages/polywrap-uri-resolvers/tests/integration/extension_resolver/histories/can_resolve_package_with_subinvoke.py create mode 100644 packages/polywrap-uri-resolvers/tests/integration/extension_resolver/histories/can_resolve_uri.py create mode 100644 packages/polywrap-uri-resolvers/tests/integration/extension_resolver/histories/can_resolve_uri_with_subinvoke.py create mode 100644 packages/polywrap-uri-resolvers/tests/integration/extension_resolver/histories/can_use_wasm_fs_resolver.py create mode 100644 packages/polywrap-uri-resolvers/tests/integration/extension_resolver/histories/not_a_match.py create mode 100644 packages/polywrap-uri-resolvers/tests/integration/extension_resolver/histories/not_a_match_with_subinvoke.py create mode 100644 packages/polywrap-uri-resolvers/tests/integration/extension_resolver/histories/not_found_extension.py create mode 100644 packages/polywrap-uri-resolvers/tests/integration/extension_resolver/histories/shows_plugin_extension_error.py create mode 100644 packages/polywrap-uri-resolvers/tests/integration/extension_resolver/histories/shows_plugin_extension_error_with_subinvoke.py create mode 100644 packages/polywrap-uri-resolvers/tests/integration/extension_resolver/histories/shows_wasm_extension_error.py create mode 100644 packages/polywrap-uri-resolvers/tests/integration/extension_resolver/histories/shows_wasm_extension_error_with_subinvoke.py create mode 100644 packages/polywrap-uri-resolvers/tests/integration/extension_resolver/mocker.py create mode 100644 packages/polywrap-uri-resolvers/tests/integration/extension_resolver/test_can_resolve_package.py create mode 100644 packages/polywrap-uri-resolvers/tests/integration/extension_resolver/test_can_resolve_package_with_subinvoke.py create mode 100644 packages/polywrap-uri-resolvers/tests/integration/extension_resolver/test_can_resolve_uri.py create mode 100644 packages/polywrap-uri-resolvers/tests/integration/extension_resolver/test_can_resolve_uri_with_subinvoke.py create mode 100644 packages/polywrap-uri-resolvers/tests/integration/extension_resolver/test_not_a_match.py create mode 100644 packages/polywrap-uri-resolvers/tests/integration/extension_resolver/test_not_a_match_with_subinvoke.py create mode 100644 packages/polywrap-uri-resolvers/tests/integration/extension_resolver/test_not_found_extension.py create mode 100644 packages/polywrap-uri-resolvers/tests/integration/extension_resolver/test_shows_plugin_extension_error.py create mode 100644 packages/polywrap-uri-resolvers/tests/integration/extension_resolver/test_shows_plugin_extension_error_with_subinvoke.py create mode 100644 packages/polywrap-uri-resolvers/tests/integration/extension_resolver/test_use_wasm_fs_resolver.py create mode 100644 packages/polywrap-uri-resolvers/tests/integration/package_resolver/__init__.py create mode 100644 packages/polywrap-uri-resolvers/tests/integration/package_resolver/conftest.py create mode 100644 packages/polywrap-uri-resolvers/tests/integration/package_resolver/histories/__init__.py create mode 100644 packages/polywrap-uri-resolvers/tests/integration/package_resolver/histories/not_resolve_package.py create mode 100644 packages/polywrap-uri-resolvers/tests/integration/package_resolver/histories/resolve_package.py create mode 100644 packages/polywrap-uri-resolvers/tests/integration/package_resolver/test_not_resolve_package.py create mode 100644 packages/polywrap-uri-resolvers/tests/integration/package_resolver/test_resolve_package.py create mode 100644 packages/polywrap-uri-resolvers/tests/integration/recursive_resolver/__init__.py create mode 100644 packages/polywrap-uri-resolvers/tests/integration/recursive_resolver/conftest.py create mode 100644 packages/polywrap-uri-resolvers/tests/integration/recursive_resolver/histories/__init__.py create mode 100644 packages/polywrap-uri-resolvers/tests/integration/recursive_resolver/histories/infinite_loop.py create mode 100644 packages/polywrap-uri-resolvers/tests/integration/recursive_resolver/histories/no_resolve.py create mode 100644 packages/polywrap-uri-resolvers/tests/integration/recursive_resolver/histories/recursive_resolve.py create mode 100644 packages/polywrap-uri-resolvers/tests/integration/recursive_resolver/test_infinite_loop.py create mode 100644 packages/polywrap-uri-resolvers/tests/integration/recursive_resolver/test_not_resolve.py create mode 100644 packages/polywrap-uri-resolvers/tests/integration/recursive_resolver/test_recursive_resolve.py create mode 100644 packages/polywrap-uri-resolvers/tests/integration/redirect_resolver/__init__.py create mode 100644 packages/polywrap-uri-resolvers/tests/integration/redirect_resolver/conftest.py create mode 100644 packages/polywrap-uri-resolvers/tests/integration/redirect_resolver/histories/__init__.py create mode 100644 packages/polywrap-uri-resolvers/tests/integration/redirect_resolver/histories/can_redirect.py create mode 100644 packages/polywrap-uri-resolvers/tests/integration/redirect_resolver/histories/not_redirect.py create mode 100644 packages/polywrap-uri-resolvers/tests/integration/redirect_resolver/test_can_redirect_uri.py create mode 100644 packages/polywrap-uri-resolvers/tests/integration/redirect_resolver/test_not_redirect_uri.py create mode 100644 packages/polywrap-uri-resolvers/tests/integration/resolution_result_cache_resolver/__init__.py create mode 100644 packages/polywrap-uri-resolvers/tests/integration/resolution_result_cache_resolver/conftest.py create mode 100644 packages/polywrap-uri-resolvers/tests/integration/resolution_result_cache_resolver/histories/__init__.py create mode 100644 packages/polywrap-uri-resolvers/tests/integration/resolution_result_cache_resolver/histories/error_with_cache.py create mode 100644 packages/polywrap-uri-resolvers/tests/integration/resolution_result_cache_resolver/histories/error_without_cache.py create mode 100644 packages/polywrap-uri-resolvers/tests/integration/resolution_result_cache_resolver/histories/package_with_cache.py create mode 100644 packages/polywrap-uri-resolvers/tests/integration/resolution_result_cache_resolver/histories/package_without_cache.py create mode 100644 packages/polywrap-uri-resolvers/tests/integration/resolution_result_cache_resolver/histories/uri_with_cache.py create mode 100644 packages/polywrap-uri-resolvers/tests/integration/resolution_result_cache_resolver/histories/uri_without_cache.py create mode 100644 packages/polywrap-uri-resolvers/tests/integration/resolution_result_cache_resolver/histories/wrapper_with_cache.py create mode 100644 packages/polywrap-uri-resolvers/tests/integration/resolution_result_cache_resolver/histories/wrapper_without_cache.py create mode 100644 packages/polywrap-uri-resolvers/tests/integration/resolution_result_cache_resolver/test_cached_error.py create mode 100644 packages/polywrap-uri-resolvers/tests/integration/resolution_result_cache_resolver/test_cached_package.py create mode 100644 packages/polywrap-uri-resolvers/tests/integration/resolution_result_cache_resolver/test_cached_uri.py create mode 100644 packages/polywrap-uri-resolvers/tests/integration/resolution_result_cache_resolver/test_cached_wrapper.py create mode 100644 packages/polywrap-uri-resolvers/tests/integration/resolution_result_cache_resolver/test_not_cached_error.py create mode 100644 packages/polywrap-uri-resolvers/tests/integration/resolution_result_cache_resolver/test_resolution_path.py create mode 100644 packages/polywrap-uri-resolvers/tests/integration/static_resolver/__init__.py create mode 100644 packages/polywrap-uri-resolvers/tests/integration/static_resolver/conftest.py create mode 100644 packages/polywrap-uri-resolvers/tests/integration/static_resolver/histories/__init__.py create mode 100644 packages/polywrap-uri-resolvers/tests/integration/static_resolver/histories/can_redirect.py create mode 100644 packages/polywrap-uri-resolvers/tests/integration/static_resolver/histories/can_resolve_package.py create mode 100644 packages/polywrap-uri-resolvers/tests/integration/static_resolver/histories/can_resolve_wrapper.py create mode 100644 packages/polywrap-uri-resolvers/tests/integration/static_resolver/histories/not_resolve.py create mode 100644 packages/polywrap-uri-resolvers/tests/integration/static_resolver/test_can_redirect.py create mode 100644 packages/polywrap-uri-resolvers/tests/integration/static_resolver/test_can_resolve_package.py create mode 100644 packages/polywrap-uri-resolvers/tests/integration/static_resolver/test_can_resolve_wrapper.py create mode 100644 packages/polywrap-uri-resolvers/tests/integration/static_resolver/test_not_resolve.py create mode 100644 packages/polywrap-uri-resolvers/tests/integration/wrapper_resolver/__init__.py create mode 100644 packages/polywrap-uri-resolvers/tests/integration/wrapper_resolver/conftest.py create mode 100644 packages/polywrap-uri-resolvers/tests/integration/wrapper_resolver/histories/__init__.py create mode 100644 packages/polywrap-uri-resolvers/tests/integration/wrapper_resolver/histories/not_resolve_wrapper.py create mode 100644 packages/polywrap-uri-resolvers/tests/integration/wrapper_resolver/histories/resolve_wrapper.py create mode 100644 packages/polywrap-uri-resolvers/tests/integration/wrapper_resolver/test_not_resolve_wrapper.py create mode 100644 packages/polywrap-uri-resolvers/tests/integration/wrapper_resolver/test_resolve_wrapper.py delete mode 100644 packages/polywrap-uri-resolvers/tests/test_static_resolver.py create mode 100644 packages/polywrap-uri-resolvers/tests/unit/__init__.py rename packages/polywrap-uri-resolvers/tests/{ => unit}/cases/simple/wrap.info (100%) rename packages/polywrap-uri-resolvers/tests/{ => unit}/cases/simple/wrap.wasm (100%) rename packages/polywrap-uri-resolvers/tests/{ => unit}/test_file_resolver.py (76%) diff --git a/packages/polywrap-uri-resolvers/assets/style.css b/packages/polywrap-uri-resolvers/assets/style.css new file mode 100644 index 00000000..3edac88e --- /dev/null +++ b/packages/polywrap-uri-resolvers/assets/style.css @@ -0,0 +1,186 @@ +body { + font-family: Helvetica, Arial, sans-serif; + font-size: 12px; + /* do not increase min-width as some may use split screens */ + min-width: 800px; + color: #999; +} + +h1 { + font-size: 24px; + color: black; +} + +h2 { + font-size: 16px; + color: black; +} + +p { + color: black; +} + +a { + color: #999; +} + +table { + border-collapse: collapse; +} + +/****************************** + * SUMMARY INFORMATION + ******************************/ +#environment td { + padding: 5px; + border: 1px solid #E6E6E6; +} +#environment tr:nth-child(odd) { + background-color: #f6f6f6; +} + +/****************************** + * TEST RESULT COLORS + ******************************/ +span.passed, +.passed .col-result { + color: green; +} + +span.skipped, +span.xfailed, +span.rerun, +.skipped .col-result, +.xfailed .col-result, +.rerun .col-result { + color: orange; +} + +span.error, +span.failed, +span.xpassed, +.error .col-result, +.failed .col-result, +.xpassed .col-result { + color: red; +} + +/****************************** + * RESULTS TABLE + * + * 1. Table Layout + * 2. Extra + * 3. Sorting items + * + ******************************/ +/*------------------ + * 1. Table Layout + *------------------*/ +#results-table { + border: 1px solid #e6e6e6; + color: #999; + font-size: 12px; + width: 100%; +} +#results-table th, +#results-table td { + padding: 5px; + border: 1px solid #E6E6E6; + text-align: left; +} +#results-table th { + font-weight: bold; +} + +/*------------------ + * 2. Extra + *------------------*/ +.log { + background-color: #e6e6e6; + border: 1px solid #e6e6e6; + color: black; + display: block; + font-family: "Courier New", Courier, monospace; + height: 230px; + overflow-y: scroll; + padding: 5px; + white-space: pre-wrap; +} +.log:only-child { + height: inherit; +} + +div.image { + border: 1px solid #e6e6e6; + float: right; + height: 240px; + margin-left: 5px; + overflow: hidden; + width: 320px; +} +div.image img { + width: 320px; +} + +div.video { + border: 1px solid #e6e6e6; + float: right; + height: 240px; + margin-left: 5px; + overflow: hidden; + width: 320px; +} +div.video video { + overflow: hidden; + width: 320px; + height: 240px; +} + +.collapsed { + display: none; +} + +.expander::after { + content: " (show details)"; + color: #BBB; + font-style: italic; + cursor: pointer; +} + +.collapser::after { + content: " (hide details)"; + color: #BBB; + font-style: italic; + cursor: pointer; +} + +/*------------------ + * 3. Sorting items + *------------------*/ +.sortable { + cursor: pointer; +} + +.sort-icon { + font-size: 0px; + float: left; + margin-right: 5px; + margin-top: 5px; + /*triangle*/ + width: 0; + height: 0; + border-left: 8px solid transparent; + border-right: 8px solid transparent; +} +.inactive .sort-icon { + /*finish triangle*/ + border-top: 8px solid #E6E6E6; +} +.asc.active .sort-icon { + /*finish triangle*/ + border-bottom: 8px solid #999; +} +.desc.active .sort-icon { + /*finish triangle*/ + border-top: 8px solid #999; +} diff --git a/packages/polywrap-uri-resolvers/poetry.lock b/packages/polywrap-uri-resolvers/poetry.lock index 1d490585..9b354d05 100644 --- a/packages/polywrap-uri-resolvers/poetry.lock +++ b/packages/polywrap-uri-resolvers/poetry.lock @@ -1,15 +1,15 @@ -# This file is automatically @generated by Poetry 1.4.2 and should not be changed by hand. +# This file is automatically @generated by Poetry and should not be changed by hand. [[package]] name = "astroid" -version = "2.15.4" +version = "2.15.5" description = "An abstract syntax tree for Python with inference support." category = "dev" optional = false python-versions = ">=3.7.2" files = [ - {file = "astroid-2.15.4-py3-none-any.whl", hash = "sha256:a1b8543ef9d36ea777194bc9b17f5f8678d2c56ee6a45b2c2f17eec96f242347"}, - {file = "astroid-2.15.4.tar.gz", hash = "sha256:c81e1c7fbac615037744d067a9bb5f9aeb655edf59b63ee8b59585475d6f80d8"}, + {file = "astroid-2.15.5-py3-none-any.whl", hash = "sha256:078e5212f9885fa85fbb0cf0101978a336190aadea6e13305409d099f71b2324"}, + {file = "astroid-2.15.5.tar.gz", hash = "sha256:1039262575027b441137ab4a62a793a9b43defb42c32d5670f38686207cd780f"}, ] [package.dependencies] @@ -273,42 +273,41 @@ files = [ [[package]] name = "libcst" -version = "0.4.9" +version = "0.4.10" description = "A concrete syntax tree with AST-like properties for Python 3.5, 3.6, 3.7, 3.8, 3.9, and 3.10 programs." category = "dev" optional = false python-versions = ">=3.7" files = [ - {file = "libcst-0.4.9-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:4f9e42085c403e22201e5c41e707ef73e4ea910ad9fc67983ceee2368097f54e"}, - {file = "libcst-0.4.9-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:1266530bf840cc40633a04feb578bb4cac1aa3aea058cc3729e24eab09a8e996"}, - {file = "libcst-0.4.9-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f9679177391ccb9b0cdde3185c22bf366cb672457c4b7f4031fcb3b5e739fbd6"}, - {file = "libcst-0.4.9-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d67bc87e0d8db9434f2ea063734938a320f541f4c6da1074001e372f840f385d"}, - {file = "libcst-0.4.9-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e316da5a126f2a9e1d7680f95f907b575f082a35e2f8bd5620c59b2aaaebfe0a"}, - {file = "libcst-0.4.9-cp310-cp310-win_amd64.whl", hash = "sha256:7415569ab998a85b0fc9af3a204611ea7fadb2d719a12532c448f8fc98f5aca4"}, - {file = "libcst-0.4.9-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:15ded11ff7f4572f91635e02b519ae959f782689fdb4445bbebb7a3cc5c71d75"}, - {file = "libcst-0.4.9-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:5b266867b712a120fad93983de432ddb2ccb062eb5fd2bea748c9a94cb200c36"}, - {file = "libcst-0.4.9-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:045b3b0b06413cdae6e9751b5f417f789ffa410f2cb2815e3e0e0ea6bef10ec0"}, - {file = "libcst-0.4.9-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e799add8fba4976628b9c1a6768d73178bf898f0ed1bd1322930c2d3db9063ba"}, - {file = "libcst-0.4.9-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:10479371d04ee8dc978c889c1774bbf6a83df88fa055fcb0159a606f6679c565"}, - {file = "libcst-0.4.9-cp311-cp311-win_amd64.whl", hash = "sha256:7a98286cbbfa90a42d376900c875161ad02a5a2a6b7c94c0f7afd9075e329ce4"}, - {file = "libcst-0.4.9-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:400166fc4efb9aa06ce44498d443aa78519082695b1894202dd73cd507d2d712"}, - {file = "libcst-0.4.9-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:46123863fba35cc84f7b54dd68826419cabfd9504d8a101c7fe3313ea03776f9"}, - {file = "libcst-0.4.9-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:27be8db54c0e5fe440021a771a38b81a7dbc23cd630eb8b0e9828b7717f9b702"}, - {file = "libcst-0.4.9-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:132bec627b064bd567e7e4cd6c89524d02842151eb0d8f5f3f7ffd2579ec1b09"}, - {file = "libcst-0.4.9-cp37-cp37m-win_amd64.whl", hash = "sha256:596860090aeed3ee6ad1e59c35c6c4110a57e4e896abf51b91cae003ec720a11"}, - {file = "libcst-0.4.9-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:f4487608258109f774300466d4ca97353df29ae6ac23d1502e13e5509423c9d5"}, - {file = "libcst-0.4.9-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:aa53993e9a2853efb3ed3605da39f2e7125df6430f613eb67ef886c1ce4f94b5"}, - {file = "libcst-0.4.9-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f6ce794483d4c605ef0f5b199a49fb6996f9586ca938b7bfef213bd13858d7ab"}, - {file = "libcst-0.4.9-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:786e562b54bbcd17a060d1244deeef466b7ee07fe544074c252c4a169e38f1ee"}, - {file = "libcst-0.4.9-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:794250d2359edd518fb698e5d21c38a5bdfc5e4a75d0407b4c19818271ce6742"}, - {file = "libcst-0.4.9-cp38-cp38-win_amd64.whl", hash = "sha256:76491f67431318c3145442e97dddcead7075b074c59eac51be7cc9e3fffec6ee"}, - {file = "libcst-0.4.9-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:3cf48d7aec6dc54b02aec0b1bb413c5bb3b02d852fd6facf1f05c7213e61a176"}, - {file = "libcst-0.4.9-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:9b3348c6b7711a5235b133bd8e11d22e903c388db42485b8ceb5f2aa0fae9b9f"}, - {file = "libcst-0.4.9-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7e33b66762efaa014c38819efae5d8f726dd823e32d5d691035484411d2a2a69"}, - {file = "libcst-0.4.9-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1350d375d3fb9b20a6cf10c09b2964baca9be753a033dde7c1aced49d8e58387"}, - {file = "libcst-0.4.9-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3822056dc13326082362db35b3f649e0f4a97e36ddb4e487441da8e0fb9db7b3"}, - {file = "libcst-0.4.9-cp39-cp39-win_amd64.whl", hash = "sha256:183636141b839aa35b639e100883813744523bc7c12528906621121731b28443"}, - {file = "libcst-0.4.9.tar.gz", hash = "sha256:01786c403348f76f274dbaf3888ae237ffb73e6ed6973e65eba5c1fc389861dd"}, + {file = "libcst-0.4.10-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:8fa0ec646ed7bce984d0ee9dbf514af278050bdb16a4fb986e916ace534eebc6"}, + {file = "libcst-0.4.10-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:3cb3b7821eac00713844cda079583230c546a589b22ed5f03f2ddc4f985c384b"}, + {file = "libcst-0.4.10-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e7acfa747112ae40b032739661abd7c81aff37191294f7c2dab8bbd72372e78f"}, + {file = "libcst-0.4.10-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1312e293b864ef3cb4b09534ed5f104c2dc45b680233c68bf76237295041c781"}, + {file = "libcst-0.4.10-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:76884b1afe475e8e68e704bf26eb9f9a2867029643e58f2f26a0286e3b6e998e"}, + {file = "libcst-0.4.10-cp310-cp310-win_amd64.whl", hash = "sha256:1069b808a711db5cd47538f27eb2c73206317aa0d8b5a3500b23aab24f86eb2e"}, + {file = "libcst-0.4.10-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:50be085346a35812535c7f876319689e15a7bfd1bd8efae8fd70589281d944b6"}, + {file = "libcst-0.4.10-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:bb9f10e5763e361e8bd8ff765fc0f1bcf744f242ff8b6d3e50ffec4dda3972ac"}, + {file = "libcst-0.4.10-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cfeeabb528b5df7b4be1817b584ce79e9a1a66687bd72f6de9c22272462812f1"}, + {file = "libcst-0.4.10-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5648aeae8c90a2abab1f7b1bf205769a0179ed2cfe1ea7f681f6885e87b8b193"}, + {file = "libcst-0.4.10-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a144f20aff4643b00374facf8409d30c7935db8176e5b2a07e1fd44004db2c1f"}, + {file = "libcst-0.4.10-cp311-cp311-win_amd64.whl", hash = "sha256:a10adc2e8ea2dda2b70eabec631ead2fc4a7a7ab633d6c2b690823c698b8431a"}, + {file = "libcst-0.4.10-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:58fe90458a26a55358207f74abf8a05dff51d662069f070b4bd308a000a80c09"}, + {file = "libcst-0.4.10-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:999fbbe467f61cbce9e6e054f86cd1c5ffa3740fd3dc8ebdd600db379f699256"}, + {file = "libcst-0.4.10-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:83ee7e7be4efac4c140a97d772e1f6b3553f98fa5f46ad78df5dfe51e5a4aa4d"}, + {file = "libcst-0.4.10-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:158478e8f45578fb26621b3dc0fe275f9e004297e9afdcf08936ecda05681174"}, + {file = "libcst-0.4.10-cp37-cp37m-win_amd64.whl", hash = "sha256:5ed101fee1af7abea3684fcff7fab5b170ceea4040756f54c15c870539daec66"}, + {file = "libcst-0.4.10-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:349f2b4ee4b982fe254c65c78d941fc96299f3c422b79f95ef8c7bba2b7f0f90"}, + {file = "libcst-0.4.10-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:7cfa4d4beb84d0d63247aca27f1a15c63984512274c5b23040f8b4ba511036d7"}, + {file = "libcst-0.4.10-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:24582506da24e31f2644f862f11413a6b80fbad68d15194bfcc3f7dfebf2ec5e"}, + {file = "libcst-0.4.10-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8cdf2d0157438d3d52d310b0b6be31ff99bed19de489b2ebd3e2a4cd9946da45"}, + {file = "libcst-0.4.10-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a677103d2f1ab0e50bc3a7cc6c96c7d64bcbac826d785e4cbf5ee9aaa9fcfa25"}, + {file = "libcst-0.4.10-cp38-cp38-win_amd64.whl", hash = "sha256:a8fdfd4a7d301adb785aa4b98e4a7cca45c5ff8cfb460b485d081efcfaaeeab7"}, + {file = "libcst-0.4.10-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:b1569d87536bed4e9c11dd5c94a137dc0bce2a2b05961489c6016bf4521bb7cf"}, + {file = "libcst-0.4.10-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:72dff8783ac79cd10f2bd2fde0b28f262e9a22718ae26990948ba6131b85ca8b"}, + {file = "libcst-0.4.10-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:76adc53660ef094ff83f77a2550a7e00d1cab8e5e63336e071c17c09b5a89fe2"}, + {file = "libcst-0.4.10-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f3e9d9fdd9a9b9b8991936ff1c07527ce7ef396c8233280ba9a7137e72c2e48e"}, + {file = "libcst-0.4.10-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7e1b4cbaf7b1cdad5fa3eababe42d5b46c0d52afe13c5ba4eac2495fc57630ea"}, + {file = "libcst-0.4.10-cp39-cp39-win_amd64.whl", hash = "sha256:bcbd07cec3d7a7be6f0299b0c246e085e3d6cc8af367e2c96059183b97c2e2fe"}, ] [package.dependencies] @@ -317,7 +316,7 @@ typing-extensions = ">=3.7.4.2" typing-inspect = ">=0.4.0" [package.extras] -dev = ["Sphinx (>=5.1.1)", "black (==22.10.0)", "coverage (>=4.5.4)", "fixit (==0.1.1)", "flake8 (>=3.7.8,<5)", "hypothesis (>=4.36.0)", "hypothesmith (>=0.0.4)", "jinja2 (==3.1.2)", "jupyter (>=1.0.0)", "maturin (>=0.8.3,<0.14)", "nbsphinx (>=0.4.2)", "prompt-toolkit (>=2.0.9)", "pyre-check (==0.9.9)", "setuptools-rust (>=1.5.2)", "setuptools-scm (>=6.0.1)", "slotscheck (>=0.7.1)", "sphinx-rtd-theme (>=0.4.3)", "ufmt (==2.0.1)", "usort (==1.0.5)"] +dev = ["Sphinx (>=5.1.1)", "black (==23.1.0)", "build (>=0.10.0)", "coverage (>=4.5.4)", "fixit (==0.1.1)", "flake8 (>=3.7.8,<5)", "hypothesis (>=4.36.0)", "hypothesmith (>=0.0.4)", "jinja2 (==3.1.2)", "jupyter (>=1.0.0)", "maturin (>=0.8.3,<0.14)", "nbsphinx (>=0.4.2)", "prompt-toolkit (>=2.0.9)", "pyre-check (==0.9.10)", "setuptools-rust (>=1.5.2)", "setuptools-scm (>=6.0.1)", "slotscheck (>=0.7.1)", "sphinx-rtd-theme (>=0.4.3)", "ufmt (==2.1.0)", "usort (==1.0.6)"] [[package]] name = "markdown-it-py" @@ -455,14 +454,14 @@ files = [ [[package]] name = "nodeenv" -version = "1.7.0" +version = "1.8.0" description = "Node.js virtual environment builder" category = "dev" optional = false python-versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*" files = [ - {file = "nodeenv-1.7.0-py2.py3-none-any.whl", hash = "sha256:27083a7b96a25f2f5e1d8cb4b6317ee8aeda3bdd121394e5ac54e498028a042e"}, - {file = "nodeenv-1.7.0.tar.gz", hash = "sha256:e0e7f7dfb85fc5394c6fe1e8fa98131a2473e04311a45afb6508f7cf1836fa2b"}, + {file = "nodeenv-1.8.0-py2.py3-none-any.whl", hash = "sha256:df865724bb3c3adc86b3876fa209771517b0cfe596beff01a92700e0e8be4cec"}, + {file = "nodeenv-1.8.0.tar.gz", hash = "sha256:d51e0c37e64fbf47d017feac3145cdbb58836d7eee8c6f6d3b6880c5456227d2"}, ] [package.dependencies] @@ -506,18 +505,18 @@ files = [ [[package]] name = "platformdirs" -version = "3.5.0" +version = "3.5.1" description = "A small Python package for determining appropriate platform-specific dirs, e.g. a \"user data dir\"." category = "dev" optional = false python-versions = ">=3.7" files = [ - {file = "platformdirs-3.5.0-py3-none-any.whl", hash = "sha256:47692bc24c1958e8b0f13dd727307cff1db103fca36399f457da8e05f222fdc4"}, - {file = "platformdirs-3.5.0.tar.gz", hash = "sha256:7954a68d0ba23558d753f73437c55f89027cf8f5108c19844d4b82e5af396335"}, + {file = "platformdirs-3.5.1-py3-none-any.whl", hash = "sha256:e2378146f1964972c03c085bb5662ae80b2b8c06226c54b2ff4aa9483e8a13a5"}, + {file = "platformdirs-3.5.1.tar.gz", hash = "sha256:412dae91f52a6f84830f39a8078cecd0e866cb72294a5c66808e74d5e88d251f"}, ] [package.extras] -docs = ["furo (>=2023.3.27)", "proselint (>=0.13)", "sphinx (>=6.1.3)", "sphinx-autodoc-typehints (>=1.23,!=1.23.4)"] +docs = ["furo (>=2023.3.27)", "proselint (>=0.13)", "sphinx (>=6.2.1)", "sphinx-autodoc-typehints (>=1.23,!=1.23.4)"] test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=7.3.1)", "pytest-cov (>=4)", "pytest-mock (>=3.10)"] [[package]] @@ -536,6 +535,25 @@ files = [ dev = ["pre-commit", "tox"] testing = ["pytest", "pytest-benchmark"] +[[package]] +name = "polywrap-client" +version = "0.1.0a29" +description = "" +category = "dev" +optional = false +python-versions = "^3.10" +files = [] +develop = true + +[package.dependencies] +polywrap-core = {path = "../polywrap-core", develop = true} +polywrap-manifest = {path = "../polywrap-manifest", develop = true} +polywrap-msgpack = {path = "../polywrap-msgpack", develop = true} + +[package.source] +type = "directory" +url = "../polywrap-client" + [[package]] name = "polywrap-core" version = "0.1.0a29" @@ -589,6 +607,39 @@ msgpack = "^1.0.4" type = "directory" url = "../polywrap-msgpack" +[[package]] +name = "polywrap-plugin" +version = "0.1.0a29" +description = "Plugin package" +category = "dev" +optional = false +python-versions = "^3.10" +files = [] +develop = true + +[package.dependencies] +polywrap-core = {path = "../polywrap-core", develop = true} +polywrap-manifest = {path = "../polywrap-manifest", develop = true} +polywrap-msgpack = {path = "../polywrap-msgpack", develop = true} + +[package.source] +type = "directory" +url = "../polywrap-plugin" + +[[package]] +name = "polywrap-test-cases" +version = "0.1.0a29" +description = "Plugin package" +category = "dev" +optional = false +python-versions = "^3.10" +files = [] +develop = true + +[package.source] +type = "directory" +url = "../polywrap-test-cases" + [[package]] name = "polywrap-wasm" version = "0.1.0a29" @@ -644,48 +695,48 @@ typer = ">=0.4.1,<0.8.0" [[package]] name = "pydantic" -version = "1.10.7" +version = "1.10.8" description = "Data validation and settings management using python type hints" category = "main" optional = false python-versions = ">=3.7" files = [ - {file = "pydantic-1.10.7-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e79e999e539872e903767c417c897e729e015872040e56b96e67968c3b918b2d"}, - {file = "pydantic-1.10.7-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:01aea3a42c13f2602b7ecbbea484a98169fb568ebd9e247593ea05f01b884b2e"}, - {file = "pydantic-1.10.7-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:516f1ed9bc2406a0467dd777afc636c7091d71f214d5e413d64fef45174cfc7a"}, - {file = "pydantic-1.10.7-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ae150a63564929c675d7f2303008d88426a0add46efd76c3fc797cd71cb1b46f"}, - {file = "pydantic-1.10.7-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:ecbbc51391248116c0a055899e6c3e7ffbb11fb5e2a4cd6f2d0b93272118a209"}, - {file = "pydantic-1.10.7-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:f4a2b50e2b03d5776e7f21af73e2070e1b5c0d0df255a827e7c632962f8315af"}, - {file = "pydantic-1.10.7-cp310-cp310-win_amd64.whl", hash = "sha256:a7cd2251439988b413cb0a985c4ed82b6c6aac382dbaff53ae03c4b23a70e80a"}, - {file = "pydantic-1.10.7-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:68792151e174a4aa9e9fc1b4e653e65a354a2fa0fed169f7b3d09902ad2cb6f1"}, - {file = "pydantic-1.10.7-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:dfe2507b8ef209da71b6fb5f4e597b50c5a34b78d7e857c4f8f3115effaef5fe"}, - {file = "pydantic-1.10.7-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:10a86d8c8db68086f1e30a530f7d5f83eb0685e632e411dbbcf2d5c0150e8dcd"}, - {file = "pydantic-1.10.7-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d75ae19d2a3dbb146b6f324031c24f8a3f52ff5d6a9f22f0683694b3afcb16fb"}, - {file = "pydantic-1.10.7-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:464855a7ff7f2cc2cf537ecc421291b9132aa9c79aef44e917ad711b4a93163b"}, - {file = "pydantic-1.10.7-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:193924c563fae6ddcb71d3f06fa153866423ac1b793a47936656e806b64e24ca"}, - {file = "pydantic-1.10.7-cp311-cp311-win_amd64.whl", hash = "sha256:b4a849d10f211389502059c33332e91327bc154acc1845f375a99eca3afa802d"}, - {file = "pydantic-1.10.7-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:cc1dde4e50a5fc1336ee0581c1612215bc64ed6d28d2c7c6f25d2fe3e7c3e918"}, - {file = "pydantic-1.10.7-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e0cfe895a504c060e5d36b287ee696e2fdad02d89e0d895f83037245218a87fe"}, - {file = "pydantic-1.10.7-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:670bb4683ad1e48b0ecb06f0cfe2178dcf74ff27921cdf1606e527d2617a81ee"}, - {file = "pydantic-1.10.7-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:950ce33857841f9a337ce07ddf46bc84e1c4946d2a3bba18f8280297157a3fd1"}, - {file = "pydantic-1.10.7-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:c15582f9055fbc1bfe50266a19771bbbef33dd28c45e78afbe1996fd70966c2a"}, - {file = "pydantic-1.10.7-cp37-cp37m-win_amd64.whl", hash = "sha256:82dffb306dd20bd5268fd6379bc4bfe75242a9c2b79fec58e1041fbbdb1f7914"}, - {file = "pydantic-1.10.7-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:8c7f51861d73e8b9ddcb9916ae7ac39fb52761d9ea0df41128e81e2ba42886cd"}, - {file = "pydantic-1.10.7-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:6434b49c0b03a51021ade5c4daa7d70c98f7a79e95b551201fff682fc1661245"}, - {file = "pydantic-1.10.7-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:64d34ab766fa056df49013bb6e79921a0265204c071984e75a09cbceacbbdd5d"}, - {file = "pydantic-1.10.7-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:701daea9ffe9d26f97b52f1d157e0d4121644f0fcf80b443248434958fd03dc3"}, - {file = "pydantic-1.10.7-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:cf135c46099ff3f919d2150a948ce94b9ce545598ef2c6c7bf55dca98a304b52"}, - {file = "pydantic-1.10.7-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:b0f85904f73161817b80781cc150f8b906d521fa11e3cdabae19a581c3606209"}, - {file = "pydantic-1.10.7-cp38-cp38-win_amd64.whl", hash = "sha256:9f6f0fd68d73257ad6685419478c5aece46432f4bdd8d32c7345f1986496171e"}, - {file = "pydantic-1.10.7-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:c230c0d8a322276d6e7b88c3f7ce885f9ed16e0910354510e0bae84d54991143"}, - {file = "pydantic-1.10.7-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:976cae77ba6a49d80f461fd8bba183ff7ba79f44aa5cfa82f1346b5626542f8e"}, - {file = "pydantic-1.10.7-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7d45fc99d64af9aaf7e308054a0067fdcd87ffe974f2442312372dfa66e1001d"}, - {file = "pydantic-1.10.7-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d2a5ebb48958754d386195fe9e9c5106f11275867051bf017a8059410e9abf1f"}, - {file = "pydantic-1.10.7-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:abfb7d4a7cd5cc4e1d1887c43503a7c5dd608eadf8bc615413fc498d3e4645cd"}, - {file = "pydantic-1.10.7-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:80b1fab4deb08a8292d15e43a6edccdffa5377a36a4597bb545b93e79c5ff0a5"}, - {file = "pydantic-1.10.7-cp39-cp39-win_amd64.whl", hash = "sha256:d71e69699498b020ea198468e2480a2f1e7433e32a3a99760058c6520e2bea7e"}, - {file = "pydantic-1.10.7-py3-none-any.whl", hash = "sha256:0cd181f1d0b1d00e2b705f1bf1ac7799a2d938cce3376b8007df62b29be3c2c6"}, - {file = "pydantic-1.10.7.tar.gz", hash = "sha256:cfc83c0678b6ba51b0532bea66860617c4cd4251ecf76e9846fa5a9f3454e97e"}, + {file = "pydantic-1.10.8-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:1243d28e9b05003a89d72e7915fdb26ffd1d39bdd39b00b7dbe4afae4b557f9d"}, + {file = "pydantic-1.10.8-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c0ab53b609c11dfc0c060d94335993cc2b95b2150e25583bec37a49b2d6c6c3f"}, + {file = "pydantic-1.10.8-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f9613fadad06b4f3bc5db2653ce2f22e0de84a7c6c293909b48f6ed37b83c61f"}, + {file = "pydantic-1.10.8-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:df7800cb1984d8f6e249351139667a8c50a379009271ee6236138a22a0c0f319"}, + {file = "pydantic-1.10.8-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:0c6fafa0965b539d7aab0a673a046466d23b86e4b0e8019d25fd53f4df62c277"}, + {file = "pydantic-1.10.8-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:e82d4566fcd527eae8b244fa952d99f2ca3172b7e97add0b43e2d97ee77f81ab"}, + {file = "pydantic-1.10.8-cp310-cp310-win_amd64.whl", hash = "sha256:ab523c31e22943713d80d8d342d23b6f6ac4b792a1e54064a8d0cf78fd64e800"}, + {file = "pydantic-1.10.8-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:666bdf6066bf6dbc107b30d034615d2627e2121506c555f73f90b54a463d1f33"}, + {file = "pydantic-1.10.8-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:35db5301b82e8661fa9c505c800d0990bc14e9f36f98932bb1d248c0ac5cada5"}, + {file = "pydantic-1.10.8-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f90c1e29f447557e9e26afb1c4dbf8768a10cc676e3781b6a577841ade126b85"}, + {file = "pydantic-1.10.8-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:93e766b4a8226e0708ef243e843105bf124e21331694367f95f4e3b4a92bbb3f"}, + {file = "pydantic-1.10.8-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:88f195f582851e8db960b4a94c3e3ad25692c1c1539e2552f3df7a9e972ef60e"}, + {file = "pydantic-1.10.8-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:34d327c81e68a1ecb52fe9c8d50c8a9b3e90d3c8ad991bfc8f953fb477d42fb4"}, + {file = "pydantic-1.10.8-cp311-cp311-win_amd64.whl", hash = "sha256:d532bf00f381bd6bc62cabc7d1372096b75a33bc197a312b03f5838b4fb84edd"}, + {file = "pydantic-1.10.8-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:7d5b8641c24886d764a74ec541d2fc2c7fb19f6da2a4001e6d580ba4a38f7878"}, + {file = "pydantic-1.10.8-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7b1f6cb446470b7ddf86c2e57cd119a24959af2b01e552f60705910663af09a4"}, + {file = "pydantic-1.10.8-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c33b60054b2136aef8cf190cd4c52a3daa20b2263917c49adad20eaf381e823b"}, + {file = "pydantic-1.10.8-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:1952526ba40b220b912cdc43c1c32bcf4a58e3f192fa313ee665916b26befb68"}, + {file = "pydantic-1.10.8-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:bb14388ec45a7a0dc429e87def6396f9e73c8c77818c927b6a60706603d5f2ea"}, + {file = "pydantic-1.10.8-cp37-cp37m-win_amd64.whl", hash = "sha256:16f8c3e33af1e9bb16c7a91fc7d5fa9fe27298e9f299cff6cb744d89d573d62c"}, + {file = "pydantic-1.10.8-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:1ced8375969673929809d7f36ad322934c35de4af3b5e5b09ec967c21f9f7887"}, + {file = "pydantic-1.10.8-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:93e6bcfccbd831894a6a434b0aeb1947f9e70b7468f274154d03d71fabb1d7c6"}, + {file = "pydantic-1.10.8-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:191ba419b605f897ede9892f6c56fb182f40a15d309ef0142212200a10af4c18"}, + {file = "pydantic-1.10.8-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:052d8654cb65174d6f9490cc9b9a200083a82cf5c3c5d3985db765757eb3b375"}, + {file = "pydantic-1.10.8-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:ceb6a23bf1ba4b837d0cfe378329ad3f351b5897c8d4914ce95b85fba96da5a1"}, + {file = "pydantic-1.10.8-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:6f2e754d5566f050954727c77f094e01793bcb5725b663bf628fa6743a5a9108"}, + {file = "pydantic-1.10.8-cp38-cp38-win_amd64.whl", hash = "sha256:6a82d6cda82258efca32b40040228ecf43a548671cb174a1e81477195ed3ed56"}, + {file = "pydantic-1.10.8-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:3e59417ba8a17265e632af99cc5f35ec309de5980c440c255ab1ca3ae96a3e0e"}, + {file = "pydantic-1.10.8-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:84d80219c3f8d4cad44575e18404099c76851bc924ce5ab1c4c8bb5e2a2227d0"}, + {file = "pydantic-1.10.8-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2e4148e635994d57d834be1182a44bdb07dd867fa3c2d1b37002000646cc5459"}, + {file = "pydantic-1.10.8-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:12f7b0bf8553e310e530e9f3a2f5734c68699f42218bf3568ef49cd9b0e44df4"}, + {file = "pydantic-1.10.8-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:42aa0c4b5c3025483240a25b09f3c09a189481ddda2ea3a831a9d25f444e03c1"}, + {file = "pydantic-1.10.8-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:17aef11cc1b997f9d574b91909fed40761e13fac438d72b81f902226a69dac01"}, + {file = "pydantic-1.10.8-cp39-cp39-win_amd64.whl", hash = "sha256:66a703d1983c675a6e0fed8953b0971c44dba48a929a2000a493c3772eb61a5a"}, + {file = "pydantic-1.10.8-py3-none-any.whl", hash = "sha256:7456eb22ed9aaa24ff3e7b4757da20d9e5ce2a81018c1b3ebd81a0b88a18f3b2"}, + {file = "pydantic-1.10.8.tar.gz", hash = "sha256:1410275520dfa70effadf4c21811d755e7ef9bb1f1d077a21958153a92c8d9ca"}, ] [package.dependencies] @@ -759,14 +810,14 @@ testutils = ["gitpython (>3)"] [[package]] name = "pyright" -version = "1.1.306" +version = "1.1.311" description = "Command line wrapper for pyright" category = "dev" optional = false python-versions = ">=3.7" files = [ - {file = "pyright-1.1.306-py3-none-any.whl", hash = "sha256:008eb2a29584ae274a154d749cf81476a3073fb562a462eac8d43a753378b9db"}, - {file = "pyright-1.1.306.tar.gz", hash = "sha256:16d5d198be64de497d5f9002000a271176c381e21b977ca5566cf779b643c9ed"}, + {file = "pyright-1.1.311-py3-none-any.whl", hash = "sha256:04df30c6b31d05068effe5563411291c876f5e4221d0af225a267b61dce1ca85"}, + {file = "pyright-1.1.311.tar.gz", hash = "sha256:554b555d3f770e8da2e76d6bb94e2ac63b3edc7dcd5fb8de202f9dd53e36689a"}, ] [package.dependencies] @@ -817,6 +868,41 @@ pytest = ">=6.1.0" [package.extras] testing = ["coverage (>=6.2)", "flaky (>=3.5.0)", "hypothesis (>=5.7.1)", "mypy (>=0.931)", "pytest-trio (>=0.7.0)"] +[[package]] +name = "pytest-html" +version = "3.2.0" +description = "pytest plugin for generating HTML reports" +category = "dev" +optional = false +python-versions = ">=3.6" +files = [ + {file = "pytest-html-3.2.0.tar.gz", hash = "sha256:c4e2f4bb0bffc437f51ad2174a8a3e71df81bbc2f6894604e604af18fbe687c3"}, + {file = "pytest_html-3.2.0-py3-none-any.whl", hash = "sha256:868c08564a68d8b2c26866f1e33178419bb35b1e127c33784a28622eb827f3f3"}, +] + +[package.dependencies] +py = ">=1.8.2" +pytest = ">=5.0,<6.0.0 || >6.0.0" +pytest-metadata = "*" + +[[package]] +name = "pytest-metadata" +version = "3.0.0" +description = "pytest plugin for test session metadata" +category = "dev" +optional = false +python-versions = ">=3.7" +files = [ + {file = "pytest_metadata-3.0.0-py3-none-any.whl", hash = "sha256:a17b1e40080401dc23177599208c52228df463db191c1a573ccdffacd885e190"}, + {file = "pytest_metadata-3.0.0.tar.gz", hash = "sha256:769a9c65d2884bd583bc626b0ace77ad15dbe02dd91a9106d47fd46d9c2569ca"}, +] + +[package.dependencies] +pytest = ">=7.0.0" + +[package.extras] +test = ["black (>=22.1.0)", "flake8 (>=4.0.1)", "pre-commit (>=2.17.0)", "tox (>=3.24.5)"] + [[package]] name = "pyyaml" version = "6.0" @@ -888,19 +974,19 @@ jupyter = ["ipywidgets (>=7.5.1,<9)"] [[package]] name = "setuptools" -version = "67.7.2" +version = "67.8.0" description = "Easily download, build, install, upgrade, and uninstall Python packages" category = "dev" optional = false python-versions = ">=3.7" files = [ - {file = "setuptools-67.7.2-py3-none-any.whl", hash = "sha256:23aaf86b85ca52ceb801d32703f12d77517b2556af839621c641fca11287952b"}, - {file = "setuptools-67.7.2.tar.gz", hash = "sha256:f104fa03692a2602fa0fec6c6a9e63b6c8a968de13e17c026957dd1f53d80990"}, + {file = "setuptools-67.8.0-py3-none-any.whl", hash = "sha256:5df61bf30bb10c6f756eb19e7c9f3b473051f48db77fddbe06ff2ca307df9a6f"}, + {file = "setuptools-67.8.0.tar.gz", hash = "sha256:62642358adc77ffa87233bc4d2354c4b2682d214048f500964dbe760ccedf102"}, ] [package.extras] docs = ["furo", "jaraco.packaging (>=9)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-favicon", "sphinx-hoverxref (<2)", "sphinx-inline-tabs", "sphinx-lint", "sphinx-notfound-page (==0.8.3)", "sphinx-reredirects", "sphinxcontrib-towncrier"] -testing = ["build[virtualenv]", "filelock (>=3.4.0)", "flake8 (<5)", "flake8-2020", "ini2toml[lite] (>=0.9)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "pip (>=19.1)", "pip-run (>=8.8)", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=1.3)", "pytest-flake8", "pytest-mypy (>=0.9.1)", "pytest-perf", "pytest-timeout", "pytest-xdist", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel"] +testing = ["build[virtualenv]", "filelock (>=3.4.0)", "flake8-2020", "ini2toml[lite] (>=0.9)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "pip (>=19.1)", "pip-run (>=8.8)", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=1.3)", "pytest-mypy (>=0.9.1)", "pytest-perf", "pytest-ruff", "pytest-timeout", "pytest-xdist", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel"] testing-integration = ["build[virtualenv]", "filelock (>=3.4.0)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "pytest", "pytest-enabler", "pytest-xdist", "tomli", "virtualenv (>=13.0.0)", "wheel"] [[package]] @@ -941,14 +1027,14 @@ files = [ [[package]] name = "stevedore" -version = "5.0.0" +version = "5.1.0" description = "Manage dynamic plugins for Python applications" category = "dev" optional = false python-versions = ">=3.8" files = [ - {file = "stevedore-5.0.0-py3-none-any.whl", hash = "sha256:bd5a71ff5e5e5f5ea983880e4a1dd1bb47f8feebbb3d95b592398e2f02194771"}, - {file = "stevedore-5.0.0.tar.gz", hash = "sha256:2c428d2338976279e8eb2196f7a94910960d9f7ba2f41f3988511e95ca447021"}, + {file = "stevedore-5.1.0-py3-none-any.whl", hash = "sha256:8cc040628f3cea5d7128f2e76cf486b2251a4e543c7b938f58d9a377f6694a2d"}, + {file = "stevedore-5.1.0.tar.gz", hash = "sha256:a54534acf9b89bc7ed264807013b505bf07f74dbe4bcfa37d32bd063870b087c"}, ] [package.dependencies] @@ -1059,26 +1145,26 @@ test = ["black (>=22.3.0,<23.0.0)", "coverage (>=6.2,<7.0)", "isort (>=5.0.6,<6. [[package]] name = "typing-extensions" -version = "4.5.0" +version = "4.6.2" description = "Backported and Experimental Type Hints for Python 3.7+" category = "main" optional = false python-versions = ">=3.7" files = [ - {file = "typing_extensions-4.5.0-py3-none-any.whl", hash = "sha256:fb33085c39dd998ac16d1431ebc293a8b3eedd00fd4a32de0ff79002c19511b4"}, - {file = "typing_extensions-4.5.0.tar.gz", hash = "sha256:5cb5f4a79139d699607b3ef622a1dedafa84e115ab0024e0d9c044a9479ca7cb"}, + {file = "typing_extensions-4.6.2-py3-none-any.whl", hash = "sha256:3a8b36f13dd5fdc5d1b16fe317f5668545de77fa0b8e02006381fd49d731ab98"}, + {file = "typing_extensions-4.6.2.tar.gz", hash = "sha256:06006244c70ac8ee83fa8282cb188f697b8db25bc8b4df07be1873c43897060c"}, ] [[package]] name = "typing-inspect" -version = "0.8.0" +version = "0.9.0" description = "Runtime inspection utilities for typing module." category = "dev" optional = false python-versions = "*" files = [ - {file = "typing_inspect-0.8.0-py3-none-any.whl", hash = "sha256:5fbf9c1e65d4fa01e701fe12a5bca6c6e08a4ffd5bc60bfac028253a447c5188"}, - {file = "typing_inspect-0.8.0.tar.gz", hash = "sha256:8b1ff0c400943b6145df8119c41c244ca8207f1f10c9c057aeed1560e4806e3d"}, + {file = "typing_inspect-0.9.0-py3-none-any.whl", hash = "sha256:9ee6fc59062311ef8547596ab6b955e1b8aa46242d854bfc78f4f6b0eff35f9f"}, + {file = "typing_inspect-0.9.0.tar.gz", hash = "sha256:b23fc42ff6f6ef6954e4852c1fb512cdd18dbea03134f91f856a95ccc9461f78"}, ] [package.dependencies] @@ -1236,4 +1322,4 @@ files = [ [metadata] lock-version = "2.0" python-versions = "^3.10" -content-hash = "94ae3e22f4506227dc928324abc370121de92d93372dc588a0005fdaaeaf2dff" +content-hash = "79ae9ce53c2dd5d8fbaf60d88c5e2b7fe5f119f5ada10ff0ebd2515b76fe9d7c" diff --git a/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/__init__.py b/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/__init__.py index 0d1e90f6..79616fc5 100644 --- a/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/__init__.py +++ b/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/__init__.py @@ -2,4 +2,3 @@ from .errors import * from .resolvers import * from .types import * -from .utils import * diff --git a/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/errors.py b/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/errors.py index b55063b7..ed4e1b0d 100644 --- a/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/errors.py +++ b/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/errors.py @@ -1,13 +1,8 @@ """This module contains all the errors related to URI resolution.""" import json -from dataclasses import asdict -from typing import List, TypeVar +from typing import List -from polywrap_core import IUriResolutionStep, Uri, UriLike - -from .utils import get_uri_resolution_path - -TUriLike = TypeVar("TUriLike", bound=UriLike) +from polywrap_core import Uri, UriResolutionStep, build_clean_uri_history class UriResolutionError(Exception): @@ -17,17 +12,21 @@ class UriResolutionError(Exception): class InfiniteLoopError(UriResolutionError): """Raised when an infinite loop is detected while resolving a URI.""" - def __init__(self, uri: Uri, history: List[IUriResolutionStep[TUriLike]]): + uri: Uri + history: List[UriResolutionStep] + + def __init__(self, uri: Uri, history: List[UriResolutionStep]): """Initialize a new InfiniteLoopError instance. Args: uri (Uri): The URI that caused the infinite loop. - history (List[IUriResolutionStep[TUriLike]]): The resolution history. + history (List[UriResolutionStep]): The resolution history. """ - resolution_path = get_uri_resolution_path(history) + self.uri = uri + self.history = history super().__init__( f"An infinite loop was detected while resolving the URI: {uri.uri}\n" - f"History: {json.dumps([asdict(step) for step in resolution_path], indent=2)}" + f"History: {json.dumps(build_clean_uri_history(history), indent=2)}" ) @@ -38,14 +37,19 @@ class UriResolverExtensionError(UriResolutionError): class UriResolverExtensionNotFoundError(UriResolverExtensionError): """Raised when an extension resolver wrapper could not be found for a URI.""" - def __init__(self, uri: Uri, history: List[IUriResolutionStep[TUriLike]]): + uri: Uri + history: List[UriResolutionStep] + + def __init__(self, uri: Uri, history: List[UriResolutionStep]): """Initialize a new UriResolverExtensionNotFoundError instance. Args: uri (Uri): The URI that caused the error. - history (List[IUriResolutionStep[TUriLike]]): The resolution history. + history (List[UriResolutionStep]): The resolution history. """ + self.uri = uri + self.history = history super().__init__( f"Could not find an extension resolver wrapper for the URI: {uri.uri}\n" - f"History: {json.dumps([asdict(step) for step in history], indent=2)}" + f"History: {json.dumps(build_clean_uri_history(history), indent=2)}" ) diff --git a/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/resolvers/abc/resolver_with_history.py b/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/resolvers/abc/resolver_with_history.py index f88ddc86..5755cf50 100644 --- a/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/resolvers/abc/resolver_with_history.py +++ b/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/resolvers/abc/resolver_with_history.py @@ -3,14 +3,13 @@ from polywrap_core import ( InvokerClient, - IUriResolutionContext, Uri, UriPackageOrWrapper, + UriResolutionContext, + UriResolutionStep, UriResolver, ) -from ...types import UriResolutionStep - class ResolverWithHistory(UriResolver): """Defines an abstract resolver that tracks its steps in\ @@ -20,11 +19,11 @@ class ResolverWithHistory(UriResolver): their steps in the resolution context. """ - async def try_resolve_uri( + def try_resolve_uri( self, uri: Uri, - client: InvokerClient[UriPackageOrWrapper], - resolution_context: IUriResolutionContext[UriPackageOrWrapper], + client: InvokerClient, + resolution_context: UriResolutionContext, ) -> UriPackageOrWrapper: """Try to resolve a URI to a wrap package, a wrapper, or a URI and \ update the resolution context with the result. @@ -35,15 +34,15 @@ async def try_resolve_uri( Args: uri (Uri): The URI to resolve. - client (InvokerClient[UriPackageOrWrapper]): The client to use for\ + client (InvokerClient): The client to use for\ resolving the URI. - resolution_context (IUriResolutionContext[UriPackageOrWrapper]):\ + resolution_context (IUriResolutionContext):\ The resolution context to update. Returns: UriPackageOrWrapper: The resolved URI package, wrapper, or URI. """ - result = await self._try_resolve_uri(uri, client, resolution_context) + result = self._try_resolve_uri(uri, client, resolution_context) step = UriResolutionStep( source_uri=uri, result=result, description=self.get_step_description() ) @@ -56,17 +55,17 @@ def get_step_description(self) -> str: """Get a description of the resolution step.""" @abstractmethod - async def _try_resolve_uri( + def _try_resolve_uri( self, uri: Uri, - client: InvokerClient[UriPackageOrWrapper], - resolution_context: IUriResolutionContext[UriPackageOrWrapper], + client: InvokerClient, + resolution_context: UriResolutionContext, ) -> UriPackageOrWrapper: """Resolve a URI to a wrap package, a wrapper, or a URI using an internal function. Args: uri (Uri): The URI to resolve. - client (InvokerClient[UriPackageOrWrapper]): The client to use for\ + client (InvokerClient): The client to use for\ resolving the URI. resolution_context (IUriResolutionContext[UriPackageOrWrapper]):\ The resolution context to update. diff --git a/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/resolvers/aggregator/uri_resolver_aggregator.py b/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/resolvers/aggregator/uri_resolver_aggregator.py index a49e9c49..4d6ecc3b 100644 --- a/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/resolvers/aggregator/uri_resolver_aggregator.py +++ b/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/resolvers/aggregator/uri_resolver_aggregator.py @@ -1,20 +1,12 @@ """This module contains the UriResolverAggregator Resolver.""" -from typing import List, Optional, cast +from typing import List, Optional -from polywrap_core import ( - InvokerClient, - IUriResolutionContext, - Uri, - UriPackage, - UriPackageOrWrapper, - UriResolver, - UriWrapper, -) +from polywrap_core import InvokerClient, UriResolutionContext, UriResolver -from ...types import UriResolutionStep +from .uri_resolver_aggregator_base import UriResolverAggregatorBase -class UriResolverAggregator(UriResolver): +class UriResolverAggregator(UriResolverAggregatorBase): """Defines a resolver that aggregates a list of resolvers. This resolver aggregates a list of resolvers and tries to resolve\ @@ -27,10 +19,10 @@ class UriResolverAggregator(UriResolver): step. Defaults to the class name. """ - __slots__ = ("resolvers", "step_description") + __slots__ = ("_resolvers", "_step_description") - resolvers: List[UriResolver] - step_description: Optional[str] + _resolvers: List[UriResolver] + _step_description: Optional[str] def __init__( self, resolvers: List[UriResolver], step_description: Optional[str] = None @@ -42,51 +34,16 @@ def __init__( step_description (Optional[str]): The description of the resolution\ step. Defaults to the class name. """ - self.step_description = step_description or self.__class__.__name__ - self.resolvers = resolvers - - async def try_resolve_uri( - self, - uri: Uri, - client: InvokerClient[UriPackageOrWrapper], - resolution_context: IUriResolutionContext[UriPackageOrWrapper], - ) -> UriPackageOrWrapper: - """Try to resolve a URI to a wrap package, a wrapper, or a URI. - - This method tries to resolve the uri with each of the aggregated\ - resolvers. If a resolver returns a value other than the resolving\ - uri, the value is returned. - - Args: - uri (Uri): The URI to resolve. - client (InvokerClient[UriPackageOrWrapper]): The client to use for\ - resolving the URI. - resolution_context (IUriResolutionContext[UriPackageOrWrapper]):\ - The resolution context to update. - """ - sub_context = resolution_context.create_sub_history_context() - - for resolver in self.resolvers: - uri_package_or_wrapper = await resolver.try_resolve_uri( - uri, client, sub_context - ) - if uri_package_or_wrapper != uri or isinstance( - uri_package_or_wrapper, (UriPackage, UriWrapper) - ): - step = UriResolutionStep( - source_uri=uri, - result=cast(UriPackageOrWrapper, uri_package_or_wrapper), - sub_history=sub_context.get_history(), - description=self.step_description, - ) - resolution_context.track_step(step) - return cast(UriPackageOrWrapper, uri_package_or_wrapper) - - step = UriResolutionStep( - source_uri=uri, - result=uri, - sub_history=sub_context.get_history(), - description=self.step_description, - ) - resolution_context.track_step(step) - return uri + self._step_description = step_description or self.__class__.__name__ + self._resolvers = resolvers + super().__init__() + + def get_step_description(self) -> Optional[str]: + """Get the description of the resolution step.""" + return self._step_description + + def get_resolvers( + self, client: InvokerClient, resolution_context: UriResolutionContext + ) -> List[UriResolver]: + """Get the list of resolvers to aggregate.""" + return self._resolvers diff --git a/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/resolvers/aggregator/uri_resolver_aggregator_base.py b/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/resolvers/aggregator/uri_resolver_aggregator_base.py new file mode 100644 index 00000000..98d47488 --- /dev/null +++ b/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/resolvers/aggregator/uri_resolver_aggregator_base.py @@ -0,0 +1,81 @@ +"""This module contains the UriResolverAggregator Resolver.""" +# pylint: disable=unnecessary-ellipsis +from abc import ABC, abstractmethod +from typing import List, Optional + +from polywrap_core import ( + InvokerClient, + Uri, + UriPackage, + UriPackageOrWrapper, + UriResolutionContext, + UriResolutionStep, + UriResolver, + UriWrapper, +) + + +class UriResolverAggregatorBase(UriResolver, ABC): + """Defines a base resolver that aggregates a list of resolvers. + + This resolver aggregates a list of resolvers and tries to resolve\ + the uri with each of them. If a resolver returns a value\ + other than the resolving uri, the value is returned. + """ + + @abstractmethod + def get_resolvers( + self, client: InvokerClient, resolution_context: UriResolutionContext + ) -> List[UriResolver]: + """Get the list of resolvers to aggregate.""" + ... + + @abstractmethod + def get_step_description(self) -> Optional[str]: + """Get the description of the resolution step. Defaults to the class name.""" + ... + + def try_resolve_uri( + self, + uri: Uri, + client: InvokerClient, + resolution_context: UriResolutionContext, + ) -> UriPackageOrWrapper: + """Try to resolve a URI to a wrap package, a wrapper, or a URI. + + This method tries to resolve the uri with each of the aggregated\ + resolvers. If a resolver returns a value other than the resolving\ + uri, the value is returned. + + Args: + uri (Uri): The URI to resolve. + client (InvokerClient): The client to use for\ + resolving the URI. + resolution_context (UriResolutionContext):\ + The resolution context to update. + """ + sub_context = resolution_context.create_sub_history_context() + + for resolver in self.get_resolvers(client, sub_context): + uri_package_or_wrapper = resolver.try_resolve_uri(uri, client, sub_context) + if ( + isinstance(uri_package_or_wrapper, (UriPackage, UriWrapper)) + or uri_package_or_wrapper != uri + ): + step = UriResolutionStep( + source_uri=uri, + result=uri_package_or_wrapper, + sub_history=sub_context.get_history(), + description=self.get_step_description(), + ) + resolution_context.track_step(step) + return uri_package_or_wrapper + + step = UriResolutionStep( + source_uri=uri, + result=uri, + sub_history=sub_context.get_history(), + description=self.get_step_description(), + ) + resolution_context.track_step(step) + return uri diff --git a/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/resolvers/cache/__init__.py b/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/resolvers/cache/__init__.py index a2b310c6..dc25fa1e 100644 --- a/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/resolvers/cache/__init__.py +++ b/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/resolvers/cache/__init__.py @@ -1,3 +1,2 @@ """This package contains the resolvers for caching.""" -from .cache_resolver import * -from .request_synchronizer_resolver import * +from .resolution_result_cache_resolver import * diff --git a/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/resolvers/cache/request_synchronizer_resolver.py b/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/resolvers/cache/request_synchronizer_resolver.py deleted file mode 100644 index ebc3df99..00000000 --- a/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/resolvers/cache/request_synchronizer_resolver.py +++ /dev/null @@ -1,132 +0,0 @@ -"""This module contains the RequestSynchronizerResolver.""" -from asyncio import Future, ensure_future -from dataclasses import dataclass -from typing import Optional, Union - -from polywrap_core import ( - Dict, - InvokerClient, - IUriResolutionContext, - Uri, - UriPackageOrWrapper, - UriResolver, -) - -from ...types import UriResolutionStep - - -@dataclass(kw_only=True, slots=True) -class RequestSynchronizerResolverOptions: - """Defines the options for the RequestSynchronizerResolver. - - Attributes: - should_ignore_cache (Optional[bool]): Whether to ignore the cache.\ - Defaults to False. - """ - - should_ignore_cache: Optional[bool] - - -class RequestSynchronizerResolver(UriResolver): - """Defines a resolver that synchronizes requests. - - This resolver synchronizes requests to the same uri.\ - If a request is already in progress, it returns the future\ - of the existing request.\ - If a request is not in progress, it creates a new request\ - and returns the future of the new request. - - Attributes: - existing_requests (Dict[Uri, Future[UriPackageOrWrapper]]):\ - The existing requests. - resolver_to_synchronize (UriResolver): The URI resolver \ - to synchronize. - options (Optional[RequestSynchronizerResolverOptions]):\ - The options to use. - """ - - __slots__ = ("resolver_to_synchronize", "options") - - existing_requests: Dict[Uri, Future[UriPackageOrWrapper]] - resolver_to_synchronize: UriResolver - options: Optional[RequestSynchronizerResolverOptions] - - def __init__( - self, - resolver_to_synchronize: UriResolver, - options: Optional[RequestSynchronizerResolverOptions] = None, - ): - """Initialize a new RequestSynchronizerResolver instance. - - Args: - resolver_to_synchronize (UriResolver): The URI resolver \ - to synchronize. - options (Optional[RequestSynchronizerResolverOptions]):\ - The options to use. - """ - self.existing_requests = {} - self.resolver_to_synchronize = resolver_to_synchronize - self.options = options - - def get_options(self) -> Union[RequestSynchronizerResolverOptions, None]: - """Get the options. - - Returns: - Union[RequestSynchronizerResolverOptions, None]:\ - The options or None. - """ - return self.options - - async def try_resolve_uri( - self, - uri: Uri, - client: InvokerClient[UriPackageOrWrapper], - resolution_context: IUriResolutionContext[UriPackageOrWrapper], - ) -> UriPackageOrWrapper: - """Try to resolve the given uri to a wrap package, wrapper or uri. - - Synchronize requests to the same uri.\ - If a request is already in progress, it returns the future\ - of the existing request.\ - If a request is not in progress, it creates a new request\ - and returns the future of the new request. - - Args: - uri (Uri): The uri to resolve. - client (InvokerClient[UriPackageOrWrapper]): The client to use. - resolution_context (IUriResolutionContext[UriPackageOrWrapper]):\ - The resolution context. - - Returns: - UriPackageOrWrapper: The resolved uri package, wrapper or uri. - """ - sub_context = resolution_context.create_sub_history_context() - - if existing_request := self.existing_requests.get(uri): - uri_package_or_wrapper = await existing_request - resolution_context.track_step( - UriResolutionStep( - source_uri=uri, - result=uri_package_or_wrapper, - description="RequestSynchronizerResolver (Cache)", - ) - ) - return uri_package_or_wrapper - - request_future = ensure_future( - self.resolver_to_synchronize.try_resolve_uri( - uri, - client, - sub_context, - ) - ) - self.existing_requests[uri] = request_future - uri_package_or_wrapper = await request_future - resolution_context.track_step( - UriResolutionStep( - source_uri=uri, - result=uri_package_or_wrapper, - description="RequestSynchronizerResolver (Cache)", - ) - ) - return uri_package_or_wrapper diff --git a/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/resolvers/cache/resolution_result_cache_resolver.py b/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/resolvers/cache/resolution_result_cache_resolver.py new file mode 100644 index 00000000..247ccde2 --- /dev/null +++ b/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/resolvers/cache/resolution_result_cache_resolver.py @@ -0,0 +1,114 @@ +"""This module contains the ResolutionResultCacheResolver.""" + +from polywrap_core import ( + InvokerClient, + Uri, + UriPackageOrWrapper, + UriResolutionContext, + UriResolutionStep, + UriResolver, +) + +from ...errors import UriResolutionError +from ...types import ResolutionResultCache + + +class ResolutionResultCacheResolver(UriResolver): + """An implementation of IUriResolver that caches the URI resolution result. + + The URI resolution result can be a URI, IWrapPackage, Wrapper, or Error. + Errors are not cached by default and can be cached by setting the cache_errors option to True. + + Attributes: + resolver_to_cache (UriResolver): The URI resolver to cache. + cache (ResolutionResultCache): The resolution result cache. + options (ResolutionResultCacheResolverOptions): The options to use. + """ + + __slots__ = ("resolver_to_cache", "cache", "cache_errors") + + resolver_to_cache: UriResolver + cache: ResolutionResultCache + cache_errors: bool + + def __init__( + self, + resolver_to_cache: UriResolver, + cache: ResolutionResultCache, + cache_errors: bool = False, + ): + """Initialize a new ResolutionResultCacheResolver instance. + + Args: + resolver_to_cache (UriResolver): The URI resolver to cache. + cache (ResolutionResultCache): The resolution result cache. + options (ResolutionResultCacheResolverOptions): The options to use. + """ + self.resolver_to_cache = resolver_to_cache + self.cache = cache + self.cache_errors = cache_errors + + def try_resolve_uri( + self, + uri: Uri, + client: InvokerClient, + resolution_context: UriResolutionContext, + ) -> UriPackageOrWrapper: + """Try to resolve a URI to a wrap package, a wrapper, or a URI. + + This method tries to resolve the URI with the resolver to cache.\ + If the result is in the cache, it returns the cached result.\ + If the result is not in the cache, it resolves the URI using\ + the inner resolver and caches the result. + + Args: + uri (Uri): The URI to resolve. + client (InvokerClient): The client to use. + resolution_context (UriResolutionContext): The resolution context to use. + + Returns: + UriPackageOrWrapper: The result of the resolution. + """ + if cached_result := self.cache.get(uri): + if isinstance(cached_result, UriResolutionError): + raise cached_result + + resolution_context.track_step( + UriResolutionStep( + source_uri=uri, + result=cached_result, + description="ResolutionResultCacheResolver (Cache)", + ) + ) + return cached_result + + sub_context = resolution_context.create_sub_history_context() + result: UriPackageOrWrapper + + if self.cache_errors: + try: + result = self.resolver_to_cache.try_resolve_uri( + uri, + client, + sub_context, + ) + except UriResolutionError as error: + self.cache.set(uri, error) + raise error + else: + result = self.resolver_to_cache.try_resolve_uri( + uri, + client, + sub_context, + ) + self.cache.set(uri, result) + + resolution_context.track_step( + UriResolutionStep( + source_uri=uri, + result=result, + sub_history=sub_context.get_history(), + description="ResolutionResultCacheResolver", + ) + ) + return result diff --git a/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/resolvers/extensions/extendable_uri_resolver.py b/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/resolvers/extensions/extendable_uri_resolver.py index 29bff003..e2c27b9e 100644 --- a/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/resolvers/extensions/extendable_uri_resolver.py +++ b/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/resolvers/extensions/extendable_uri_resolver.py @@ -1,19 +1,13 @@ """This module contains the ExtendableUriResolver class.""" -from typing import List, Optional, cast +from typing import List, Optional -from polywrap_core import ( - InvokerClient, - IUriResolutionContext, - Uri, - UriPackageOrWrapper, - UriResolver, -) +from polywrap_core import InvokerClient, Uri, UriResolutionContext, UriResolver -from ..aggregator import UriResolverAggregator +from ..aggregator import UriResolverAggregatorBase from .extension_wrapper_uri_resolver import ExtensionWrapperUriResolver -class ExtendableUriResolver(UriResolver): +class ExtendableUriResolver(UriResolverAggregatorBase): """Defines a resolver that resolves a uri to a wrapper by using extension wrappers. This resolver resolves a uri to a wrapper by using extension wrappers.\ @@ -52,35 +46,22 @@ def __init__( """ self.ext_interface_uris = ext_interface_uris or self.DEFAULT_EXT_INTERFACE_URIS self.resolver_name = resolver_name or self.__class__.__name__ + super().__init__() - async def try_resolve_uri( - self, - uri: Uri, - client: InvokerClient[UriPackageOrWrapper], - resolution_context: IUriResolutionContext[UriPackageOrWrapper], - ) -> UriPackageOrWrapper: - """Try to resolve a URI to a wrap package, a wrapper, or a URI. + def get_step_description(self) -> Optional[str]: + """Get the description of the resolution step.""" + return self.resolver_name - Args: - uri (Uri): The URI to resolve. - client (InvokerClient[UriPackageOrWrapper]): The client to use for\ - resolving the URI. - resolution_context (IUriResolutionContext[UriPackageOrWrapper]): The\ - resolution context. - - Returns: - UriPackageOrWrapper: The resolved URI, wrap package, or wrapper. - """ + def get_resolvers( + self, client: InvokerClient, resolution_context: UriResolutionContext + ) -> List[UriResolver]: + """Get the list of resolvers to aggregate.""" uri_resolvers_uris: List[Uri] = [] for ext_interface_uri in self.ext_interface_uris: uri_resolvers_uris.extend( - client.get_implementations(ext_interface_uri) or [] + client.get_implementations(ext_interface_uri, apply_resolution=False) + or [] ) - resolvers = [ExtensionWrapperUriResolver(uri) for uri in uri_resolvers_uris] - aggregator = UriResolverAggregator( - cast(List[UriResolver], resolvers), self.resolver_name - ) - - return await aggregator.try_resolve_uri(uri, client, resolution_context) + return [ExtensionWrapperUriResolver(uri) for uri in uri_resolvers_uris] diff --git a/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/resolvers/extensions/extension_wrapper_uri_resolver.py b/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/resolvers/extensions/extension_wrapper_uri_resolver.py index 1692df02..5862b99a 100644 --- a/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/resolvers/extensions/extension_wrapper_uri_resolver.py +++ b/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/resolvers/extensions/extension_wrapper_uri_resolver.py @@ -1,28 +1,29 @@ """This module contains the ExtensionWrapperUriResolver class.""" -from typing import Optional, TypedDict, cast +from __future__ import annotations + +from typing import Optional, TypedDict from polywrap_core import ( - Client, - InvokeOptions, InvokerClient, - IUriResolutionContext, - TryResolveUriOptions, Uri, UriPackage, UriPackageOrWrapper, - UriWrapper, - Wrapper, + UriResolutionContext, + UriResolutionStep, + UriResolver, + WrapError, ) -from polywrap_msgpack import msgpack_decode from polywrap_wasm import WasmPackage -from ...errors import UriResolverExtensionError, UriResolverExtensionNotFoundError -from ...utils import get_env_from_uri_history -from ..abc import ResolverWithHistory +from ...errors import ( + InfiniteLoopError, + UriResolverExtensionError, + UriResolverExtensionNotFoundError, +) from .uri_resolver_extension_file_reader import UriResolverExtensionFileReader -class MaybeUriOrManifest(TypedDict): +class MaybeUriOrManifest(TypedDict, total=False): """Defines a type for the return value of the extension wrapper's\ tryResolveUri function. @@ -34,7 +35,7 @@ class MaybeUriOrManifest(TypedDict): manifest: Optional[bytes] -class ExtensionWrapperUriResolver(ResolverWithHistory): +class ExtensionWrapperUriResolver(UriResolver): """Defines a resolver that resolves a uri to a wrapper by using an extension wrapper. This resolver resolves a uri to a wrapper by using an extension wrapper.\ @@ -65,11 +66,11 @@ def get_step_description(self) -> str: """ return f"ResolverExtension ({self.extension_wrapper_uri})" - async def _try_resolve_uri( + def try_resolve_uri( self, uri: Uri, - client: InvokerClient[UriPackageOrWrapper], - resolution_context: IUriResolutionContext[UriPackageOrWrapper], + client: InvokerClient, + resolution_context: UriResolutionContext, ) -> UriPackageOrWrapper: """Try to resolve a URI to a wrap package, a wrapper, or a URI. @@ -80,9 +81,9 @@ async def _try_resolve_uri( Args: uri (Uri): The URI to resolve. - client (InvokerClient[UriPackageOrWrapper]): The client to use for\ + client (InvokerClient): The client to use for\ resolving the URI. - resolution_context (IUriResolutionContext[UriPackageOrWrapper]): The\ + resolution_context (UriResolutionContext): The\ resolution context. Returns: @@ -91,103 +92,70 @@ async def _try_resolve_uri( sub_context = resolution_context.create_sub_context() try: - extension_wrapper = await self._load_resolver_extension(client, sub_context) - uri_or_manifest = await self._try_resolve_uri_with_extension( - uri, extension_wrapper, client, sub_context + uri_package_or_wrapper = self._try_resolve_uri_with_extension( + uri, client, sub_context ) - if uri_or_manifest.get("uri"): - return Uri.from_str(cast(str, uri_or_manifest["uri"])) - - if uri_or_manifest.get("manifest"): - package = WasmPackage( - UriResolverExtensionFileReader( - self.extension_wrapper_uri, uri, client - ), - uri_or_manifest["manifest"], + resolution_context.track_step( + UriResolutionStep( + source_uri=uri, + result=uri_package_or_wrapper, + description=self.get_step_description(), + sub_history=sub_context.get_history(), ) - return UriPackage(uri, package) - - return uri + ) - except Exception as err: + return uri_package_or_wrapper + except WrapError as err: raise UriResolverExtensionError( f"Failed to resolve uri: {uri}, using extension resolver: " f"({self.extension_wrapper_uri})" ) from err - - async def _load_resolver_extension( - self, - client: InvokerClient[UriPackageOrWrapper], - resolution_context: IUriResolutionContext[UriPackageOrWrapper], - ) -> Wrapper[UriPackageOrWrapper]: - """Load the URI resolver extension wrapper. - - Args: - client (InvokerClient[UriPackageOrWrapper]): The client to use for\ - resolving the URI. - resolution_context (IUriResolutionContext[UriPackageOrWrapper]): The\ - resolution context. - """ - result = await client.try_resolve_uri( - TryResolveUriOptions( - uri=self.extension_wrapper_uri, resolution_context=resolution_context - ) - ) - - extension_wrapper: Wrapper[UriPackageOrWrapper] - - if isinstance(result, UriPackage): - extension_wrapper = await cast( - UriPackage[UriPackageOrWrapper], result - ).package.create_wrapper() - elif isinstance(result, UriWrapper): - extension_wrapper = cast(UriWrapper[UriPackageOrWrapper], result).wrapper - else: - raise UriResolverExtensionNotFoundError( - self.extension_wrapper_uri, resolution_context.get_history() - ) - return extension_wrapper - - async def _try_resolve_uri_with_extension( + except InfiniteLoopError as err: + if err.uri == self.extension_wrapper_uri: + raise UriResolverExtensionNotFoundError( + self.extension_wrapper_uri, sub_context.get_history() + ) from err + raise err + + def _try_resolve_uri_with_extension( self, uri: Uri, - extension_wrapper: Wrapper[UriPackageOrWrapper], - client: InvokerClient[UriPackageOrWrapper], - resolution_context: IUriResolutionContext[UriPackageOrWrapper], - ) -> MaybeUriOrManifest: + client: InvokerClient, + resolution_context: UriResolutionContext, + ) -> UriPackageOrWrapper: """Try to resolve a URI to a uri or a manifest using the extension wrapper. Args: uri (Uri): The URI to resolve. - extension_wrapper (Wrapper[UriPackageOrWrapper]): The extension wrapper. - client (InvokerClient[UriPackageOrWrapper]): The client to use for\ - resolving the URI. - resolution_context (IUriResolutionContext[UriPackageOrWrapper]): The\ - resolution context. + client (InvokerClient): The client to use for resolving the URI. + resolution_context (UriResolutionContext): The resolution context. Returns: MaybeUriOrManifest: The resolved URI or manifest. """ - env = ( - get_env_from_uri_history( - resolution_context.get_resolution_path(), cast(Client, client) - ) - if hasattr(client, "get_env_by_uri") - else None + uri_or_manifest: Optional[MaybeUriOrManifest] = client.invoke( + uri=self.extension_wrapper_uri, + method="tryResolveUri", + args={ + "authority": uri.authority, + "path": uri.path, + }, + encode_result=False, + resolution_context=resolution_context, ) - result = await extension_wrapper.invoke( - InvokeOptions( - uri=self.extension_wrapper_uri, - method="tryResolveUri", - args={ - "authority": uri.authority, - "path": uri.path, - }, - env=env, - ), - client, - ) + if uri_or_manifest is None: + return uri + + if result_uri := uri_or_manifest.get("uri"): + return Uri.from_str(result_uri) + + if result_manifest := uri_or_manifest.get("manifest"): + package = WasmPackage( + UriResolverExtensionFileReader(self.extension_wrapper_uri, uri, client), + result_manifest, + ) + return UriPackage(uri=uri, package=package) - return msgpack_decode(result) if isinstance(result, bytes) else result + return uri diff --git a/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/resolvers/extensions/uri_resolver_extension_file_reader.py b/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/resolvers/extensions/uri_resolver_extension_file_reader.py index 7bacf0eb..c5106917 100644 --- a/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/resolvers/extensions/uri_resolver_extension_file_reader.py +++ b/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/resolvers/extensions/uri_resolver_extension_file_reader.py @@ -1,7 +1,7 @@ """This module contains the UriResolverExtensionFileReader class.""" from pathlib import Path -from polywrap_core import FileReader, Invoker, InvokerOptions, Uri, UriPackageOrWrapper +from polywrap_core import FileReader, Invoker, Uri class UriResolverExtensionFileReader(FileReader): @@ -14,31 +14,31 @@ class UriResolverExtensionFileReader(FileReader): Attributes: extension_uri (Uri): The uri of the extension wrapper. wrapper_uri (Uri): The uri of the wrapper that uses the extension wrapper. - invoker (Invoker[UriPackageOrWrapper]): The invoker used to invoke the getFile method. + invoker (Invoker): The invoker used to invoke the getFile method. """ extension_uri: Uri wrapper_uri: Uri - invoker: Invoker[UriPackageOrWrapper] + invoker: Invoker def __init__( self, extension_uri: Uri, wrapper_uri: Uri, - invoker: Invoker[UriPackageOrWrapper], + invoker: Invoker, ): """Initialize a new UriResolverExtensionFileReader instance. Args: extension_uri (Uri): The uri of the extension wrapper. wrapper_uri (Uri): The uri of the wrapper that uses the extension wrapper. - invoker (Invoker[UriPackageOrWrapper]): The invoker used to invoke the getFile method. + invoker (Invoker): The invoker used to invoke the getFile method. """ self.extension_uri = extension_uri self.wrapper_uri = wrapper_uri self.invoker = invoker - async def read_file(self, file_path: str) -> bytes: + def read_file(self, file_path: str) -> bytes: """Read a file using the extension wrapper. Args: @@ -48,10 +48,8 @@ async def read_file(self, file_path: str) -> bytes: bytes: The contents of the file. """ path = str(Path(self.wrapper_uri.path).joinpath(file_path)) - result = await self.invoker.invoke( - InvokerOptions( - uri=self.extension_uri, method="getFile", args={"path": path} - ) + result = self.invoker.invoke( + uri=self.extension_uri, method="getFile", args={"path": path} ) if not isinstance(result, bytes): diff --git a/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/resolvers/legacy/base_resolver.py b/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/resolvers/legacy/base_resolver.py index 6fd1bcc4..fd3c8582 100644 --- a/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/resolvers/legacy/base_resolver.py +++ b/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/resolvers/legacy/base_resolver.py @@ -4,9 +4,9 @@ from polywrap_core import ( FileReader, InvokerClient, - IUriResolutionContext, Uri, UriPackageOrWrapper, + UriResolutionContext, UriResolver, ) @@ -30,26 +30,26 @@ def __init__(self, file_reader: FileReader, redirects: Dict[Uri, Uri]): self._fs_resolver = FsUriResolver(file_reader) self._redirect_resolver = RedirectUriResolver(redirects) - async def try_resolve_uri( + def try_resolve_uri( self, uri: Uri, - client: InvokerClient[UriPackageOrWrapper], - resolution_context: IUriResolutionContext[UriPackageOrWrapper], + client: InvokerClient, + resolution_context: UriResolutionContext, ) -> UriPackageOrWrapper: """Try to resolve a URI to a wrap package, a wrapper, or a URI. Args: uri (Uri): The URI to resolve. - client (InvokerClient[UriPackageOrWrapper]): The client to use for resolving the URI. - resolution_context (IUriResolutionContext[UriPackageOrWrapper]): The resolution context. + client (InvokerClient): The client to use for resolving the URI. + resolution_context (UriResolutionContext): The resolution context. Returns: UriPackageOrWrapper: The resolved URI. """ - redirected_uri = await self._redirect_resolver.try_resolve_uri( + redirected_uri = self._redirect_resolver.try_resolve_uri( uri, client, resolution_context ) - return await self._fs_resolver.try_resolve_uri( + return self._fs_resolver.try_resolve_uri( redirected_uri, client, resolution_context ) diff --git a/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/resolvers/legacy/fs_resolver.py b/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/resolvers/legacy/fs_resolver.py index b793702f..ade7ff60 100644 --- a/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/resolvers/legacy/fs_resolver.py +++ b/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/resolvers/legacy/fs_resolver.py @@ -4,19 +4,20 @@ from polywrap_core import ( FileReader, InvokerClient, - IUriResolutionContext, Uri, UriPackage, UriPackageOrWrapper, + UriResolutionContext, UriResolver, ) -from polywrap_wasm import WRAP_MANIFEST_PATH, WRAP_MODULE_PATH, WasmPackage +from polywrap_wasm import WasmPackage +from polywrap_wasm.constants import WRAP_MANIFEST_PATH, WRAP_MODULE_PATH class SimpleFileReader(FileReader): """Defines a simple file reader.""" - async def read_file(self, file_path: str) -> bytes: + def read_file(self, file_path: str) -> bytes: """Read a file. Args: @@ -42,18 +43,18 @@ def __init__(self, file_reader: FileReader): """ self.file_reader = file_reader - async def try_resolve_uri( + def try_resolve_uri( self, uri: Uri, - client: InvokerClient[UriPackageOrWrapper], - resolution_context: IUriResolutionContext[UriPackageOrWrapper], + client: InvokerClient, + resolution_context: UriResolutionContext, ) -> UriPackageOrWrapper: """Try to resolve a URI. Args: uri (Uri): The URI to resolve. - client (InvokerClient[UriPackageOrWrapper]): The client to use for resolving the URI. - resolution_context (IUriResolutionContext[UriPackageOrWrapper]): The resolution context. + client (InvokerClient): The client to use for resolving the URI. + resolution_context (UriResolutionContext): The resolution context. Returns: UriPackageOrWrapper: The resolved URI. @@ -63,13 +64,9 @@ async def try_resolve_uri( wrapper_path = Path(uri.path) - wasm_module = await self.file_reader.read_file( - str(wrapper_path / WRAP_MODULE_PATH) - ) + wasm_module = self.file_reader.read_file(str(wrapper_path / WRAP_MODULE_PATH)) - manifest = await self.file_reader.read_file( - str(wrapper_path / WRAP_MANIFEST_PATH) - ) + manifest = self.file_reader.read_file(str(wrapper_path / WRAP_MANIFEST_PATH)) return UriPackage( uri=uri, diff --git a/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/resolvers/package/package_to_wrapper_resolver.py b/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/resolvers/legacy/package_to_wrapper_resolver.py similarity index 80% rename from packages/polywrap-uri-resolvers/polywrap_uri_resolvers/resolvers/package/package_to_wrapper_resolver.py rename to packages/polywrap-uri-resolvers/polywrap_uri_resolvers/resolvers/legacy/package_to_wrapper_resolver.py index 3dd2a472..7cc45eea 100644 --- a/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/resolvers/package/package_to_wrapper_resolver.py +++ b/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/resolvers/legacy/package_to_wrapper_resolver.py @@ -1,19 +1,19 @@ """This module contains the PackageToWrapperResolver class.""" from dataclasses import dataclass -from typing import Optional, cast +from typing import Optional from polywrap_core import ( InvokerClient, - IUriResolutionContext, Uri, UriPackage, UriPackageOrWrapper, + UriResolutionContext, + UriResolutionStep, UriResolver, UriWrapper, ) from polywrap_manifest import DeserializeManifestOptions -from ...types import UriResolutionStep from ..abc import ResolverWithHistory @@ -58,31 +58,30 @@ def __init__( """ self.resolver = resolver self.options = options + super().__init__() - async def _try_resolve_uri( + def _try_resolve_uri( self, uri: Uri, - client: InvokerClient[UriPackageOrWrapper], - resolution_context: IUriResolutionContext[UriPackageOrWrapper], + client: InvokerClient, + resolution_context: UriResolutionContext, ) -> UriPackageOrWrapper: """Try to resolve the given URI to a wrapper or a redirected URI. Args: uri (Uri): The URI to resolve. - client (InvokerClient[UriPackageOrWrapper]): The client to use. - resolution_context (IUriResolutionContext[UriPackageOrWrapper]):\ + client (InvokerClient): The client to use. + resolution_context (IUriResolutionContext):\ The resolution context to use. Returns: UriPackageOrWrapper: The resolved URI or wrapper. """ sub_context = resolution_context.create_sub_context() - result = await self.resolver.try_resolve_uri(uri, client, sub_context) + result = self.resolver.try_resolve_uri(uri, client, sub_context) if isinstance(result, UriPackage): - wrapper = await cast( - UriPackage[UriPackageOrWrapper], result - ).package.create_wrapper() - result = UriWrapper(uri, wrapper) + wrapper = result.package.create_wrapper() + result = UriWrapper(uri=uri, wrapper=wrapper) resolution_context.track_step( UriResolutionStep( diff --git a/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/resolvers/legacy/redirect_resolver.py b/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/resolvers/legacy/redirect_resolver.py index cdb9b652..3e34ab67 100644 --- a/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/resolvers/legacy/redirect_resolver.py +++ b/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/resolvers/legacy/redirect_resolver.py @@ -1,13 +1,7 @@ """This module contains the RedirectUriResolver class.""" from typing import Dict -from polywrap_core import ( - InvokerClient, - IUriResolutionContext, - Uri, - UriPackageOrWrapper, - UriResolver, -) +from polywrap_core import InvokerClient, Uri, UriResolutionContext, UriResolver class RedirectUriResolver(UriResolver): @@ -23,18 +17,18 @@ def __init__(self, redirects: Dict[Uri, Uri]): """ self._redirects = redirects - async def try_resolve_uri( + def try_resolve_uri( self, uri: Uri, - client: InvokerClient[UriPackageOrWrapper], - resolution_context: IUriResolutionContext[UriPackageOrWrapper], + client: InvokerClient, + resolution_context: UriResolutionContext, ) -> Uri: """Try to resolve a URI to redirected URI. Args: uri (Uri): The URI to resolve. - client (InvokerClient[UriPackageOrWrapper]): The client to use for resolving the URI. - resolution_context (IUriResolutionContext[UriPackageOrWrapper]): The resolution context. + client (InvokerClient): The client to use for resolving the URI. + resolution_context (UriResolutionContext): The resolution context. Returns: Uri: The resolved URI. diff --git a/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/resolvers/legacy/wrapper_cache/__init__.py b/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/resolvers/legacy/wrapper_cache/__init__.py new file mode 100644 index 00000000..30b09078 --- /dev/null +++ b/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/resolvers/legacy/wrapper_cache/__init__.py @@ -0,0 +1,3 @@ +"""This package contains interface and implementations for wrapper cache.""" +from .in_memory_wrapper_cache import * +from .wrapper_cache import * diff --git a/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/types/cache/in_memory_wrapper_cache.py b/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/resolvers/legacy/wrapper_cache/in_memory_wrapper_cache.py similarity index 64% rename from packages/polywrap-uri-resolvers/polywrap_uri_resolvers/types/cache/in_memory_wrapper_cache.py rename to packages/polywrap-uri-resolvers/polywrap_uri_resolvers/resolvers/legacy/wrapper_cache/in_memory_wrapper_cache.py index aca47d11..16975e64 100644 --- a/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/types/cache/in_memory_wrapper_cache.py +++ b/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/resolvers/legacy/wrapper_cache/in_memory_wrapper_cache.py @@ -1,7 +1,7 @@ """This module contains the in-memory wrapper cache.""" from typing import Dict, Union -from polywrap_core import Uri, UriPackageOrWrapper, Wrapper +from polywrap_core import Uri, UriWrapper from .wrapper_cache import WrapperCache @@ -10,19 +10,19 @@ class InMemoryWrapperCache(WrapperCache): """InMemoryWrapperCache is an in-memory implementation of the wrapper cache interface. Attributes: - map (Dict[Uri, Wrapper]): The map of uris to wrappers. + map (Dict[Uri, UriWrapper]): The map of uris to wrappers. """ - map: Dict[Uri, Wrapper[UriPackageOrWrapper]] + map: Dict[Uri, UriWrapper] def __init__(self): """Initialize a new InMemoryWrapperCache instance.""" self.map = {} - def get(self, uri: Uri) -> Union[Wrapper[UriPackageOrWrapper], None]: + def get(self, uri: Uri) -> Union[UriWrapper, None]: """Get a wrapper from the cache by its uri.""" return self.map.get(uri) - def set(self, uri: Uri, wrapper: Wrapper[UriPackageOrWrapper]) -> None: + def set(self, uri: Uri, wrapper: UriWrapper) -> None: """Set a wrapper in the cache by its uri.""" self.map[uri] = wrapper diff --git a/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/types/cache/wrapper_cache.py b/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/resolvers/legacy/wrapper_cache/wrapper_cache.py similarity index 54% rename from packages/polywrap-uri-resolvers/polywrap_uri_resolvers/types/cache/wrapper_cache.py rename to packages/polywrap-uri-resolvers/polywrap_uri_resolvers/resolvers/legacy/wrapper_cache/wrapper_cache.py index 505eb6be..9825b59b 100644 --- a/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/types/cache/wrapper_cache.py +++ b/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/resolvers/legacy/wrapper_cache/wrapper_cache.py @@ -1,20 +1,20 @@ """This module contains the wrapper cache interface.""" -from abc import ABC, abstractmethod -from typing import Union +from abc import abstractmethod +from typing import Protocol, Union -from polywrap_core import Uri, UriPackageOrWrapper, Wrapper +from polywrap_core import Uri, UriWrapper -class WrapperCache(ABC): +class WrapperCache(Protocol): """Defines a cache interface for caching wrappers by uri. This is used by the wrapper resolver to cache wrappers for a given uri. """ @abstractmethod - def get(self, uri: Uri) -> Union[Wrapper[UriPackageOrWrapper], None]: + def get(self, uri: Uri) -> Union[UriWrapper, None]: """Get a wrapper from the cache by its uri.""" @abstractmethod - def set(self, uri: Uri, wrapper: Wrapper[UriPackageOrWrapper]) -> None: + def set(self, uri: Uri, wrapper: UriWrapper) -> None: """Set a wrapper in the cache by its uri.""" diff --git a/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/resolvers/cache/cache_resolver.py b/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/resolvers/legacy/wrapper_cache_resolver.py similarity index 82% rename from packages/polywrap-uri-resolvers/polywrap_uri_resolvers/resolvers/cache/cache_resolver.py rename to packages/polywrap-uri-resolvers/polywrap_uri_resolvers/resolvers/legacy/wrapper_cache_resolver.py index 94e076ab..08ac0748 100644 --- a/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/resolvers/cache/cache_resolver.py +++ b/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/resolvers/legacy/wrapper_cache_resolver.py @@ -1,19 +1,19 @@ """This module contains the WrapperCacheResolver.""" from dataclasses import dataclass -from typing import List, Optional, Union, cast +from typing import List, Optional, Union from polywrap_core import ( InvokerClient, - IUriResolutionContext, Uri, UriPackageOrWrapper, + UriResolutionContext, + UriResolutionStep, UriResolver, UriWrapper, - Wrapper, ) from polywrap_manifest import DeserializeManifestOptions -from ...types import UriResolutionStep, WrapperCache +from .wrapper_cache import WrapperCache @dataclass(kw_only=True, slots=True) @@ -75,11 +75,11 @@ def get_options(self) -> Union[WrapperCacheResolverOptions, None]: """ return self.options - async def try_resolve_uri( + def try_resolve_uri( self, uri: Uri, - client: InvokerClient[UriPackageOrWrapper], - resolution_context: IUriResolutionContext[UriPackageOrWrapper], + client: InvokerClient, + resolution_context: UriResolutionContext, ) -> UriPackageOrWrapper: """Try to resolve a URI to a wrapper, or a URI. @@ -90,37 +90,35 @@ async def try_resolve_uri( Args: uri (Uri): The URI to resolve. client (InvokerClient): The client to use. - resolution_context (IUriResolutionContext): The resolution\ + resolution_context (UriResolutionContext): The resolution\ context to use. Returns: UriPackageOrWrapper: The result of the resolution. """ - if wrapper := self.cache.get(uri): - result = UriWrapper(uri, wrapper) + if uri_wrapper := self.cache.get(uri): resolution_context.track_step( UriResolutionStep( source_uri=uri, - result=result, + result=uri_wrapper, description="WrapperCacheResolver (Cache Hit)", ) ) - return result + return uri_wrapper sub_context = resolution_context.create_sub_history_context() - result = await self.resolver_to_cache.try_resolve_uri( + result = self.resolver_to_cache.try_resolve_uri( uri, client, sub_context, ) - if isinstance(result, Wrapper): - uri_wrapper = cast(UriWrapper[UriPackageOrWrapper], result) + if isinstance(result, UriWrapper): resolution_path: List[Uri] = sub_context.get_resolution_path() for cache_uri in resolution_path: - self.cache.set(cache_uri, uri_wrapper.wrapper) + self.cache.set(cache_uri, result) resolution_context.track_step( UriResolutionStep( diff --git a/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/resolvers/package/__init__.py b/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/resolvers/package/__init__.py index d7c941e1..9538aca7 100644 --- a/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/resolvers/package/__init__.py +++ b/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/resolvers/package/__init__.py @@ -1,3 +1,2 @@ """This package contains the resolvers for packages.""" from .package_resolver import * -from .package_to_wrapper_resolver import * diff --git a/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/resolvers/package/package_resolver.py b/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/resolvers/package/package_resolver.py index 2af39593..c25623c0 100644 --- a/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/resolvers/package/package_resolver.py +++ b/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/resolvers/package/package_resolver.py @@ -1,10 +1,10 @@ """This module contains the PackageResolver class.""" from polywrap_core import ( InvokerClient, - IUriResolutionContext, Uri, UriPackage, UriPackageOrWrapper, + UriResolutionContext, WrapPackage, ) @@ -14,20 +14,21 @@ class PackageResolver(ResolverWithHistory): """Defines a resolver that resolves a uri to a package.""" - __slots__ = ("uri", "wrap_package") + __slots__ = ("uri", "package") uri: Uri - wrap_package: WrapPackage[UriPackageOrWrapper] + package: WrapPackage - def __init__(self, uri: Uri, wrap_package: WrapPackage[UriPackageOrWrapper]): + def __init__(self, uri: Uri, wrap_package: WrapPackage): """Initialize a new PackageResolver instance. Args: uri (Uri): The uri to resolve. - wrap_package (WrapPackage[UriPackageOrWrapper]): The wrap package to return. + wrap_package (WrapPackage): The wrap package to return. """ self.uri = uri - self.wrap_package = wrap_package + self.package = wrap_package + super().__init__() def get_step_description(self) -> str: """Get the description of the resolver step. @@ -37,11 +38,11 @@ def get_step_description(self) -> str: """ return f"Package ({self.uri.uri})" - async def _try_resolve_uri( + def _try_resolve_uri( self, uri: Uri, - client: InvokerClient[UriPackageOrWrapper], - resolution_context: IUriResolutionContext[UriPackageOrWrapper], + client: InvokerClient, + resolution_context: UriResolutionContext, ) -> UriPackageOrWrapper: """Try to resolve a URI to a wrap package, a wrapper, or a URI. @@ -51,12 +52,12 @@ async def _try_resolve_uri( Args: uri (Uri): The URI to resolve. - client (InvokerClient[UriPackageOrWrapper]): The client to use for\ + client (InvokerClient): The client to use for\ resolving the URI. - resolution_context (IUriResolutionContext[UriPackageOrWrapper]): The\ + resolution_context (UriResolutionContext): The\ resolution context. Returns: UriPackageOrWrapper: The resolved URI package, wrapper, or URI. """ - return uri if uri != self.uri else UriPackage(uri, self.wrap_package) + return uri if uri != self.uri else UriPackage(uri=uri, package=self.package) diff --git a/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/resolvers/recursive/recursive_resolver.py b/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/resolvers/recursive/recursive_resolver.py index e00fe37d..06a69e13 100644 --- a/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/resolvers/recursive/recursive_resolver.py +++ b/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/resolvers/recursive/recursive_resolver.py @@ -1,9 +1,9 @@ """This module contains the recursive resolver.""" from polywrap_core import ( InvokerClient, - IUriResolutionContext, Uri, UriPackageOrWrapper, + UriResolutionContext, UriResolver, ) @@ -32,18 +32,18 @@ def __init__(self, resolver: UriResolver): """ self.resolver = resolver - async def try_resolve_uri( + def try_resolve_uri( self, uri: Uri, - client: InvokerClient[UriPackageOrWrapper], - resolution_context: IUriResolutionContext[UriPackageOrWrapper], + client: InvokerClient, + resolution_context: UriResolutionContext, ) -> UriPackageOrWrapper: """Try to resolve a URI to a wrap package, a wrapper, or a URI. Args: uri (Uri): The URI to resolve. - client (InvokerClient[UriPackageOrWrapper]): The client to use for resolving the URI. - resolution_context (IUriResolutionContext[UriPackageOrWrapper]): The resolution context. + client (InvokerClient): The client to use for resolving the URI. + resolution_context (UriResolutionContext): The resolution context. Returns: UriPackageOrWrapper: The resolved URI. @@ -53,13 +53,15 @@ async def try_resolve_uri( resolution_context.start_resolving(uri) - uri_package_or_wrapper = await self.resolver.try_resolve_uri( + uri_package_or_wrapper = self.resolver.try_resolve_uri( uri, client, resolution_context ) - if uri_package_or_wrapper != uri: - uri_package_or_wrapper = await self.try_resolve_uri( - uri_package_or_wrapper, client, resolution_context + if isinstance(uri_package_or_wrapper, Uri) and uri_package_or_wrapper != uri: + uri_package_or_wrapper = self.try_resolve_uri( + uri_package_or_wrapper, + client, + resolution_context, ) resolution_context.stop_resolving(uri) diff --git a/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/resolvers/redirect/redirect_resolver.py b/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/resolvers/redirect/redirect_resolver.py index 34f3b05b..837d53ed 100644 --- a/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/resolvers/redirect/redirect_resolver.py +++ b/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/resolvers/redirect/redirect_resolver.py @@ -1,5 +1,5 @@ """This module contains the RedirectResolver class.""" -from polywrap_core import InvokerClient, IUriResolutionContext, Uri, UriPackageOrWrapper +from polywrap_core import InvokerClient, Uri, UriPackageOrWrapper, UriResolutionContext from ..abc import ResolverWithHistory @@ -30,6 +30,7 @@ def __init__(self, from_uri: Uri, to_uri: Uri) -> None: """ self.from_uri = from_uri self.to_uri = to_uri + super().__init__() def get_step_description(self) -> str: """Get the description of the resolver step. @@ -39,11 +40,11 @@ def get_step_description(self) -> str: """ return f"Redirect ({self.from_uri} - {self.to_uri})" - async def _try_resolve_uri( + def _try_resolve_uri( self, uri: Uri, - client: InvokerClient[UriPackageOrWrapper], - resolution_context: IUriResolutionContext[UriPackageOrWrapper], + client: InvokerClient, + resolution_context: UriResolutionContext, ) -> UriPackageOrWrapper: """Try to resolve a URI to a wrap package, a wrapper, or a URI. @@ -53,10 +54,8 @@ async def _try_resolve_uri( Args: uri (Uri): The URI to resolve. - client (InvokerClient[UriPackageOrWrapper]): The client to use for\ - resolving the URI. - resolution_context (IUriResolutionContext[UriPackageOrWrapper]): The\ - resolution context. + client (InvokerClient): The client to use for resolving the URI. + resolution_context (UriResolutionContext): The resolution context. Returns: UriPackageOrWrapper: The resolved URI package, wrapper, or URI. diff --git a/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/resolvers/static/static_resolver.py b/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/resolvers/static/static_resolver.py index 5a5757d4..cd1db81d 100644 --- a/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/resolvers/static/static_resolver.py +++ b/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/resolvers/static/static_resolver.py @@ -1,15 +1,13 @@ """This module contains the StaticResolver class.""" from polywrap_core import ( InvokerClient, - IUriResolutionContext, - IUriResolutionStep, Uri, UriPackage, UriPackageOrWrapper, + UriResolutionContext, + UriResolutionStep, UriResolver, UriWrapper, - WrapPackage, - Wrapper, ) from ...types import StaticResolverLike @@ -34,38 +32,39 @@ def __init__(self, uri_map: StaticResolverLike): """ self.uri_map = uri_map - async def try_resolve_uri( + def try_resolve_uri( self, uri: Uri, - client: InvokerClient[UriPackageOrWrapper], - resolution_context: IUriResolutionContext[UriPackageOrWrapper], + client: InvokerClient, + resolution_context: UriResolutionContext, ) -> UriPackageOrWrapper: """Try to resolve a URI to a wrap package, a wrapper, or a URI. Args: uri (Uri): The URI to resolve. - client (InvokerClient[UriPackageOrWrapper]): The client to use for resolving the URI. - resolution_context (IUriResolutionContext[UriPackageOrWrapper]): The resolution context. + client (InvokerClient): The client to use for resolving the URI. + resolution_context (UriResolutionContext): The resolution context. Returns: UriPackageOrWrapper: The resolved URI. """ result = self.uri_map.get(uri) - uri_package_or_wrapper: UriPackageOrWrapper = uri - description: str = "StaticResolver - Miss" - if result: - if isinstance(result, WrapPackage): - description = f"Static - Package ({uri})" - uri_package_or_wrapper = UriPackage(uri, result) - elif isinstance(result, Wrapper): - description = f"Static - Wrapper ({uri})" - uri_package_or_wrapper = UriWrapper(uri, result) - else: - description = f"Static - Redirect ({uri}, {result})" + match result: + case None: + description: str = "Static - Miss" + uri_package_or_wrapper: UriPackageOrWrapper = uri + case UriPackage(): + description = "Static - Package" + uri_package_or_wrapper = result + case UriWrapper(): + description = "Static - Wrapper" + uri_package_or_wrapper = result + case _: + description = f"Static - Redirect ({uri} - {result})" uri_package_or_wrapper = result - step = IUriResolutionStep( + step = UriResolutionStep( source_uri=uri, result=uri_package_or_wrapper, description=description ) resolution_context.track_step(step) diff --git a/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/resolvers/wrapper/wrapper_resolver.py b/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/resolvers/wrapper/wrapper_resolver.py index c549d076..4d39d230 100644 --- a/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/resolvers/wrapper/wrapper_resolver.py +++ b/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/resolvers/wrapper/wrapper_resolver.py @@ -1,9 +1,9 @@ """This module contains the resolver for wrappers.""" from polywrap_core import ( InvokerClient, - IUriResolutionContext, Uri, UriPackageOrWrapper, + UriResolutionContext, UriWrapper, Wrapper, ) @@ -16,23 +16,24 @@ class WrapperResolver(ResolverWithHistory): Attributes: uri (Uri): The uri to resolve. - wrapper (Wrapper[UriPackageOrWrapper]): The wrapper to use. + wrapper (Wrapper): The wrapper to use. """ __slots__ = ("uri", "wrapper") uri: Uri - wrapper: Wrapper[UriPackageOrWrapper] + wrapper: Wrapper - def __init__(self, uri: Uri, wrapper: Wrapper[UriPackageOrWrapper]): + def __init__(self, uri: Uri, wrapper: Wrapper): """Initialize a new WrapperResolver instance. Args: uri (Uri): The uri to resolve. - wrapper (Wrapper[UriPackageOrWrapper]): The wrapper to use. + wrapper (Wrapper): The wrapper to use. """ self.uri = uri self.wrapper = wrapper + super().__init__() def get_step_description(self) -> str: """Get the description of the resolver step. @@ -42,20 +43,20 @@ def get_step_description(self) -> str: """ return f"Wrapper ({self.uri})" - async def _try_resolve_uri( + def _try_resolve_uri( self, uri: Uri, - client: InvokerClient[UriPackageOrWrapper], - resolution_context: IUriResolutionContext[UriPackageOrWrapper], + client: InvokerClient, + resolution_context: UriResolutionContext, ) -> UriPackageOrWrapper: """Try to resolve a URI to a wrap package, a wrapper, or a URI. Args: uri (Uri): The URI to resolve. - client (InvokerClient[UriPackageOrWrapper]): The client to use for resolving the URI. - resolution_context (IUriResolutionContext[UriPackageOrWrapper]): The resolution context. + client (InvokerClient): The client to use for resolving the URI. + resolution_context (UriResolutionContext): The resolution context. Returns: UriPackageOrWrapper: The resolved URI, wrap package, or wrapper. """ - return uri if uri != self.uri else UriWrapper(uri, self.wrapper) + return uri if uri != self.uri else UriWrapper(uri=uri, wrapper=self.wrapper) diff --git a/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/types/__init__.py b/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/types/__init__.py index abfded87..b5019260 100644 --- a/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/types/__init__.py +++ b/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/types/__init__.py @@ -2,5 +2,4 @@ from .cache import * from .static_resolver_like import * from .uri_redirect import * -from .uri_resolution_context import * from .uri_resolver_like import * diff --git a/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/types/cache/__init__.py b/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/types/cache/__init__.py index 30b09078..3824e09e 100644 --- a/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/types/cache/__init__.py +++ b/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/types/cache/__init__.py @@ -1,3 +1,2 @@ -"""This package contains interface and implementations for wrapper cache.""" -from .in_memory_wrapper_cache import * -from .wrapper_cache import * +"""This package contains implementations for the cache.""" +from .resolution_result_cache import * diff --git a/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/types/cache/resolution_result_cache/__init__.py b/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/types/cache/resolution_result_cache/__init__.py new file mode 100644 index 00000000..58b79226 --- /dev/null +++ b/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/types/cache/resolution_result_cache/__init__.py @@ -0,0 +1,3 @@ +"""This package contains interface and implementations for wrapper cache.""" +from .in_memory_resolution_result_cache import * +from .resolution_result_cache import * diff --git a/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/types/cache/resolution_result_cache/in_memory_resolution_result_cache.py b/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/types/cache/resolution_result_cache/in_memory_resolution_result_cache.py new file mode 100644 index 00000000..035833e6 --- /dev/null +++ b/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/types/cache/resolution_result_cache/in_memory_resolution_result_cache.py @@ -0,0 +1,37 @@ +"""This module contains the in-memory wrapper cache.""" +from typing import Dict, Union + +from polywrap_core import Uri, UriPackageOrWrapper + +from ....errors import UriResolutionError +from .resolution_result_cache import ResolutionResultCache + + +class InMemoryResolutionResultCache(ResolutionResultCache): + """InMemoryResolutionResultCache is an in-memory implementation \ + of the resolution result cache interface. + + Attributes: + map (Dict[Uri, Union[UriPackageOrWrapper, UriResolutionError]]):\ + The map of uris to resolution result. + """ + + map: Dict[Uri, Union[UriPackageOrWrapper, UriResolutionError]] + + def __init__(self): + """Initialize a new InMemoryResolutionResultCache instance.""" + self.map = {} + + def get(self, uri: Uri) -> Union[UriPackageOrWrapper, UriResolutionError, None]: + """Get the resolution result from the cache by its uri.""" + return self.map.get(uri) + + def set( + self, uri: Uri, result: Union[UriPackageOrWrapper, UriResolutionError] + ) -> None: + """Set the resolution result in the cache by its uri.""" + self.map[uri] = result + + def __str__(self) -> str: + """Display cache as a string.""" + return f"{self.map}" diff --git a/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/types/cache/resolution_result_cache/resolution_result_cache.py b/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/types/cache/resolution_result_cache/resolution_result_cache.py new file mode 100644 index 00000000..154eb71c --- /dev/null +++ b/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/types/cache/resolution_result_cache/resolution_result_cache.py @@ -0,0 +1,29 @@ +"""This module contains the wrapper cache interface.""" +# pylint: disable=unnecessary-ellipsis +from typing import Protocol, Union + +from polywrap_core import Uri, UriPackageOrWrapper + +from ....errors import UriResolutionError + + +class ResolutionResultCache(Protocol): + """Defines a cache interface for caching resolution results by uri. + + This is used by the resolution result resolver to cache resolution results\ + for a given uri. + """ + + def get(self, uri: Uri) -> Union[UriPackageOrWrapper, UriResolutionError, None]: + """Get the resolution result from the cache by its uri.""" + ... + + def set( + self, uri: Uri, result: Union[UriPackageOrWrapper, UriResolutionError] + ) -> None: + """Set the resolution result in the cache by its uri.""" + ... + + def __str__(self) -> str: + """Display cache as a string.""" + ... diff --git a/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/types/static_resolver_like.py b/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/types/static_resolver_like.py index 0bad456f..933b62ec 100644 --- a/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/types/static_resolver_like.py +++ b/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/types/static_resolver_like.py @@ -2,19 +2,9 @@ StaticResolverLike is a type that represents a union of types\ that can be used as a StaticResolver. - ->>> StaticResolverLike = Union[ -... Dict[Uri, Uri], -... Dict[Uri, WrapPackage], -... Dict[Uri, Wrapper], -... ] """ -from typing import Dict, Union +from typing import Dict -from polywrap_core import Uri, UriPackageOrWrapper, WrapPackage, Wrapper +from polywrap_core import Uri, UriPackageOrWrapper -StaticResolverLike = Union[ - Dict[Uri, Uri], - Dict[Uri, WrapPackage[UriPackageOrWrapper]], - Dict[Uri, Wrapper[UriPackageOrWrapper]], -] +StaticResolverLike = Dict[Uri, UriPackageOrWrapper] diff --git a/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/types/uri_resolution_context/__init__.py b/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/types/uri_resolution_context/__init__.py deleted file mode 100644 index 5923e009..00000000 --- a/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/types/uri_resolution_context/__init__.py +++ /dev/null @@ -1,3 +0,0 @@ -"""This module contains the utility classes and functions for URI Resolution.""" -from .uri_resolution_context import * -from .uri_resolution_step import * diff --git a/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/types/uri_resolution_context/uri_resolution_context.py b/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/types/uri_resolution_context/uri_resolution_context.py deleted file mode 100644 index 700a9c1a..00000000 --- a/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/types/uri_resolution_context/uri_resolution_context.py +++ /dev/null @@ -1,121 +0,0 @@ -"""This module contains implementation of IUriResolutionContext interface.""" -from typing import List, Optional, Set - -from polywrap_core import ( - IUriResolutionContext, - IUriResolutionStep, - Uri, - UriPackageOrWrapper, -) - - -class UriResolutionContext(IUriResolutionContext[UriPackageOrWrapper]): - """Represents the context of a uri resolution. - - Attributes: - resolving_uri_set: A set of uris that are currently being resolved. - resolution_path: A list of uris in the order that they are being resolved. - history: A list of steps that have been taken to resolve the uri. - """ - - resolving_uri_set: Set[Uri] - resolution_path: List[Uri] - history: List[IUriResolutionStep[UriPackageOrWrapper]] - - __slots__ = ("resolving_uri_map", "resolution_path", "history") - - def __init__( - self, - resolving_uri_set: Optional[Set[Uri]] = None, - resolution_path: Optional[List[Uri]] = None, - history: Optional[List[IUriResolutionStep[UriPackageOrWrapper]]] = None, - ): - """Initialize a new instance of UriResolutionContext. - - Args: - resolving_uri_set: A set of uris that are currently being resolved. - resolution_path: A list of uris in the order that they are being resolved. - history: A list of steps that have been taken to resolve the uri. - """ - self.resolving_uri_set = resolving_uri_set or set() - self.resolution_path = resolution_path or [] - self.history = history or [] - - def is_resolving(self, uri: Uri) -> bool: - """Check if the given uri is currently being resolved. - - Args: - uri: The uri to check. - - Returns: - bool: True if the uri is currently being resolved, otherwise False. - """ - return uri in self.resolving_uri_set - - def start_resolving(self, uri: Uri) -> None: - """Start resolving the given uri. - - Args: - uri: The uri to start resolving. - - Returns: None - """ - self.resolving_uri_set.add(uri) - self.resolution_path.append(uri) - - def stop_resolving(self, uri: Uri) -> None: - """Stop resolving the given uri. - - Args: - uri: The uri to stop resolving. - - Returns: None - """ - self.resolving_uri_set.remove(uri) - - def track_step(self, step: IUriResolutionStep[UriPackageOrWrapper]) -> None: - """Track the given step in the resolution history. - - Args: - step: The step to track. - - Returns: None - """ - self.history.append(step) - - def get_history(self) -> List[IUriResolutionStep[UriPackageOrWrapper]]: - """Get the resolution history. - - Returns: - List[IUriResolutionStep]: The resolution history. - """ - return self.history - - def get_resolution_path(self) -> List[Uri]: - """Get the resolution path. - - Returns: - List[Uri]: The ordered list of URI resolution path. - """ - return self.resolution_path - - def create_sub_history_context(self) -> IUriResolutionContext[UriPackageOrWrapper]: - """Create a new sub context that shares the same resolution path. - - Returns: - IUriResolutionContext: The new context. - """ - return UriResolutionContext( - resolving_uri_set=self.resolving_uri_set, - resolution_path=self.resolution_path, - ) - - def create_sub_context(self) -> IUriResolutionContext[UriPackageOrWrapper]: - """Create a new sub context that shares the same resolution history. - - Returns: - IUriResolutionContext: The new context. - """ - return UriResolutionContext( - resolving_uri_set=self.resolving_uri_set, history=self.history - ) diff --git a/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/types/uri_resolution_context/uri_resolution_step.py b/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/types/uri_resolution_context/uri_resolution_step.py deleted file mode 100644 index effeec4a..00000000 --- a/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/types/uri_resolution_context/uri_resolution_step.py +++ /dev/null @@ -1,18 +0,0 @@ -"""This module contains implementation of IUriResolutionStep interface.""" -from __future__ import annotations - -from dataclasses import dataclass - -from polywrap_core import IUriResolutionStep, UriPackageOrWrapper - - -@dataclass(slots=True, kw_only=True) -class UriResolutionStep(IUriResolutionStep[UriPackageOrWrapper]): - """Represents a single step in the resolution of a uri. - - Attributes: - source_uri: The uri that was resolved. - result: The result of the resolution. - description: A description of the resolution step. - sub_history: A list of sub steps that were taken to resolve the uri. - """ diff --git a/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/utils/__init__.py b/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/utils/__init__.py deleted file mode 100644 index 6f71584a..00000000 --- a/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/utils/__init__.py +++ /dev/null @@ -1,4 +0,0 @@ -"""This package contains the utilities used by the polywrap-uri-resolvers package.""" -from .build_clean_uri_history import * -from .get_env_from_uri_history import * -from .get_uri_resolution_path import * diff --git a/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/utils/build_clean_uri_history.py b/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/utils/build_clean_uri_history.py deleted file mode 100644 index 9eddd139..00000000 --- a/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/utils/build_clean_uri_history.py +++ /dev/null @@ -1,73 +0,0 @@ -"""This module contains an utility function for building a clean history of URI resolution steps.""" -from typing import List, Optional, TypeVar, Union - -from polywrap_core import IUriResolutionStep, Uri, UriLike, UriPackage - -CleanResolutionStep = List[Union[str, "CleanResolutionStep"]] - -TUriLike = TypeVar("TUriLike", bound=UriLike) - - -def build_clean_uri_history( - history: List[IUriResolutionStep[TUriLike]], depth: Optional[int] = None -) -> CleanResolutionStep: - """Build a clean history of the URI resolution steps. - - Args: - history: A list of URI resolution steps. - depth: The depth of the history to build. - - Returns: - CleanResolutionStep: A clean history of the URI resolution steps. - """ - clean_history: CleanResolutionStep = [] - - if depth is not None: - depth -= 1 - - if not history: - return clean_history - - for step in history: - clean_history.append(_build_clean_history_step(step)) - - if ( - not step.sub_history - or len(step.sub_history) == 0 - or (depth is not None and depth < 0) - ): - continue - - sub_history = build_clean_uri_history(step.sub_history, depth) - if len(sub_history) > 0: - clean_history.append(sub_history) - - return clean_history - - -def _build_clean_history_step(step: IUriResolutionStep[TUriLike]) -> str: - uri_package_or_wrapper = step.result - - if isinstance(uri_package_or_wrapper, Uri): - if step.source_uri == uri_package_or_wrapper: - return ( - f"{step.source_uri} => {step.description}" - if step.description - else f"{step.source_uri}" - ) - return ( - f"{step.source_uri} => {step.description} => uri ({uri_package_or_wrapper.uri})" - if step.description - else f"{step.source_uri} => uri ({uri_package_or_wrapper})" - ) - if isinstance(uri_package_or_wrapper, UriPackage): - return ( - f"{step.source_uri} => {step.description} => package ({uri_package_or_wrapper})" - if step.description - else f"{step.source_uri} => package ({uri_package_or_wrapper})" - ) - return ( - f"{step.source_uri} => {step.description} => wrapper ({uri_package_or_wrapper})" - if step.description - else f"{step.source_uri} => wrapper ({uri_package_or_wrapper})" - ) diff --git a/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/utils/get_env_from_uri_history.py b/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/utils/get_env_from_uri_history.py deleted file mode 100644 index 1e5b3d6b..00000000 --- a/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/utils/get_env_from_uri_history.py +++ /dev/null @@ -1,22 +0,0 @@ -"""This module contains the utility function for getting the env from the URI history.""" -from typing import Any, Dict, List, Union - -from polywrap_core import Client, Uri - - -def get_env_from_uri_history( - uri_history: List[Uri], client: Client -) -> Union[Dict[str, Any], None]: - """Get environment variable from URI resolution history. - - Args: - uri_history: List of URIs from the URI resolution history - client: Polywrap client instance to use for getting the env by URI - - Returns: - env if found, None otherwise - """ - for uri in uri_history: - if env := client.get_env_by_uri(uri): - return env - return None diff --git a/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/utils/get_uri_resolution_path.py b/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/utils/get_uri_resolution_path.py deleted file mode 100644 index 6e650e6a..00000000 --- a/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/utils/get_uri_resolution_path.py +++ /dev/null @@ -1,35 +0,0 @@ -"""This module contains the get_uri_resolution_path function.""" -from typing import List, TypeVar - -from polywrap_core import IUriResolutionStep, UriLike - -TUriLike = TypeVar("TUriLike", bound=UriLike) - - -def get_uri_resolution_path( - history: List[IUriResolutionStep[TUriLike]], -) -> List[IUriResolutionStep[TUriLike]]: - """Get the URI resolution path from the URI resolution history. - - Args: - history (List[IUriResolutionStep[TUriLike]]): URI resolution history - - Returns: - List[IUriResolutionStep[TUriLike]]: URI resolution path - """ - # Get all non-empty items from the resolution history - - def add_uri_resolution_path_for_sub_history( - step: IUriResolutionStep[TUriLike], - ) -> IUriResolutionStep[TUriLike]: - if step.sub_history and len(step.sub_history): - step.sub_history = get_uri_resolution_path(step.sub_history) - return step - - return [ - add_uri_resolution_path_for_sub_history(step) - for step in filter( - lambda step: step.source_uri != step.result, - history, - ) - ] diff --git a/packages/polywrap-uri-resolvers/pyproject.toml b/packages/polywrap-uri-resolvers/pyproject.toml index 727c52cf..152a9232 100644 --- a/packages/polywrap-uri-resolvers/pyproject.toml +++ b/packages/polywrap-uri-resolvers/pyproject.toml @@ -13,7 +13,12 @@ readme = "README.md" python = "^3.10" polywrap-wasm = {path = "../polywrap-wasm", develop = true} polywrap-core = {path = "../polywrap-core", develop = true} -[tool.poetry.dev-dependencies] + +[tool.poetry.group.dev.dependencies] +pycln = "^2.1.3" +polywrap-client = {path = "../polywrap-client", develop = true} +polywrap-plugin = {path = "../polywrap-plugin", develop = true} +polywrap-test-cases = {path = "../polywrap-test-cases", develop = true} pytest = "^7.1.2" pytest-asyncio = "^0.19.0" pylint = "^2.15.4" @@ -24,9 +29,7 @@ tox-poetry = "^0.4.1" isort = "^5.10.1" pyright = "^1.1.275" pydocstyle = "^6.1.1" - -[tool.poetry.group.dev.dependencies] -pycln = "^2.1.3" +pytest-html = "^3.2.0" [tool.bandit] exclude_dirs = ["tests"] diff --git a/packages/polywrap-uri-resolvers/tests/__init__.py b/packages/polywrap-uri-resolvers/tests/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/packages/polywrap-uri-resolvers/tests/integration/__init__.py b/packages/polywrap-uri-resolvers/tests/integration/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/packages/polywrap-uri-resolvers/tests/integration/aggregator_resolver/__init__.py b/packages/polywrap-uri-resolvers/tests/integration/aggregator_resolver/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/packages/polywrap-uri-resolvers/tests/integration/aggregator_resolver/conftest.py b/packages/polywrap-uri-resolvers/tests/integration/aggregator_resolver/conftest.py new file mode 100644 index 00000000..37f75ff8 --- /dev/null +++ b/packages/polywrap-uri-resolvers/tests/integration/aggregator_resolver/conftest.py @@ -0,0 +1,18 @@ +import pytest +from polywrap_core import Uri, UriResolutionContext, ClientConfig +from polywrap_client import PolywrapClient +from polywrap_uri_resolvers import UriResolverAggregator, RedirectResolver + +@pytest.fixture +def client() -> PolywrapClient: + resolver = UriResolverAggregator([ + RedirectResolver(Uri.from_str("test/1"), Uri.from_str("test/2")), + RedirectResolver(Uri.from_str("test/2"), Uri.from_str("test/3")), + RedirectResolver(Uri.from_str("test/3"), Uri.from_str("test/4")), + ], "TestAggregator") + return PolywrapClient(ClientConfig(resolver=resolver)) + +@pytest.fixture +def resolution_context() -> UriResolutionContext: + return UriResolutionContext() + diff --git a/packages/polywrap-uri-resolvers/tests/integration/aggregator_resolver/histories/__init__.py b/packages/polywrap-uri-resolvers/tests/integration/aggregator_resolver/histories/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/packages/polywrap-uri-resolvers/tests/integration/aggregator_resolver/histories/can_resolve_first.py b/packages/polywrap-uri-resolvers/tests/integration/aggregator_resolver/histories/can_resolve_first.py new file mode 100644 index 00000000..71edc200 --- /dev/null +++ b/packages/polywrap-uri-resolvers/tests/integration/aggregator_resolver/histories/can_resolve_first.py @@ -0,0 +1,6 @@ +EXPECTED = [ + "wrap://test/1 => TestAggregator => uri (wrap://test/2)", + [ + "wrap://test/1 => Redirect (wrap://test/1 - wrap://test/2) => uri (wrap://test/2)", + ] +] diff --git a/packages/polywrap-uri-resolvers/tests/integration/aggregator_resolver/histories/can_resolve_last.py b/packages/polywrap-uri-resolvers/tests/integration/aggregator_resolver/histories/can_resolve_last.py new file mode 100644 index 00000000..0ecc3af6 --- /dev/null +++ b/packages/polywrap-uri-resolvers/tests/integration/aggregator_resolver/histories/can_resolve_last.py @@ -0,0 +1,8 @@ +EXPECTED = [ + "wrap://test/3 => TestAggregator => uri (wrap://test/4)", + [ + "wrap://test/3 => Redirect (wrap://test/1 - wrap://test/2)", + "wrap://test/3 => Redirect (wrap://test/2 - wrap://test/3)", + "wrap://test/3 => Redirect (wrap://test/3 - wrap://test/4) => uri (wrap://test/4)", + ] +] diff --git a/packages/polywrap-uri-resolvers/tests/integration/aggregator_resolver/histories/not_resolve.py b/packages/polywrap-uri-resolvers/tests/integration/aggregator_resolver/histories/not_resolve.py new file mode 100644 index 00000000..aa408c4e --- /dev/null +++ b/packages/polywrap-uri-resolvers/tests/integration/aggregator_resolver/histories/not_resolve.py @@ -0,0 +1,8 @@ +EXPECTED = [ + "wrap://test/no-match => TestAggregator", + [ + "wrap://test/no-match => Redirect (wrap://test/1 - wrap://test/2)", + "wrap://test/no-match => Redirect (wrap://test/2 - wrap://test/3)", + "wrap://test/no-match => Redirect (wrap://test/3 - wrap://test/4)", + ] +] diff --git a/packages/polywrap-uri-resolvers/tests/integration/aggregator_resolver/test_can_resolve.py b/packages/polywrap-uri-resolvers/tests/integration/aggregator_resolver/test_can_resolve.py new file mode 100644 index 00000000..9cfd6ee3 --- /dev/null +++ b/packages/polywrap-uri-resolvers/tests/integration/aggregator_resolver/test_can_resolve.py @@ -0,0 +1,28 @@ +from polywrap_core import Uri, UriResolutionContext, build_clean_uri_history +from polywrap_client import PolywrapClient + + +def test_can_resolve_first(client: PolywrapClient, resolution_context: UriResolutionContext) -> None: + uri = Uri.from_str("test/1") + + result = client.try_resolve_uri(uri=uri, resolution_context=resolution_context) + + from .histories.can_resolve_first import EXPECTED + assert build_clean_uri_history(resolution_context.get_history()) == EXPECTED + + assert isinstance(result, Uri), "Expected a Uri result." + assert result.uri == "wrap://test/2" + + +def test_can_resolve_last(client: PolywrapClient, resolution_context: UriResolutionContext) -> None: + uri = Uri.from_str("test/3") + + result = client.try_resolve_uri(uri=uri, resolution_context=resolution_context) + + print(build_clean_uri_history(resolution_context.get_history())) + + from .histories.can_resolve_last import EXPECTED + assert build_clean_uri_history(resolution_context.get_history()) == EXPECTED + + assert isinstance(result, Uri), "Expected a Uri result." + assert result.uri == "wrap://test/4" diff --git a/packages/polywrap-uri-resolvers/tests/integration/aggregator_resolver/test_not_resolve.py b/packages/polywrap-uri-resolvers/tests/integration/aggregator_resolver/test_not_resolve.py new file mode 100644 index 00000000..4e9ff210 --- /dev/null +++ b/packages/polywrap-uri-resolvers/tests/integration/aggregator_resolver/test_not_resolve.py @@ -0,0 +1,15 @@ +from polywrap_core import Uri, UriResolutionContext, build_clean_uri_history +from polywrap_client import PolywrapClient + + +def test_no_match(client: PolywrapClient, resolution_context: UriResolutionContext) -> None: + uri = Uri.from_str("test/no-match") + + result = client.try_resolve_uri(uri=uri, resolution_context=resolution_context) + + from .histories.not_resolve import EXPECTED + assert build_clean_uri_history(resolution_context.get_history()) == EXPECTED + + assert isinstance(result, Uri), "Expected a Uri result." + assert result.uri == "wrap://test/no-match" + diff --git a/packages/polywrap-uri-resolvers/tests/integration/extension_resolver/__init__.py b/packages/polywrap-uri-resolvers/tests/integration/extension_resolver/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/packages/polywrap-uri-resolvers/tests/integration/extension_resolver/histories/__init__.py b/packages/polywrap-uri-resolvers/tests/integration/extension_resolver/histories/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/packages/polywrap-uri-resolvers/tests/integration/extension_resolver/histories/can_resolve_package.py b/packages/polywrap-uri-resolvers/tests/integration/extension_resolver/histories/can_resolve_package.py new file mode 100644 index 00000000..51b2d6bf --- /dev/null +++ b/packages/polywrap-uri-resolvers/tests/integration/extension_resolver/histories/can_resolve_package.py @@ -0,0 +1,20 @@ +EXPECTED = [ + "wrap://test/package => UriResolverAggregator => package (wrap://test/package)", + [ + "wrap://test/package => Static - Miss", + "wrap://test/package => ExtendableUriResolver => package (wrap://test/package)", + [ + "wrap://test/package => ResolverExtension (wrap://package/test-resolver) => package (wrap://test/package)", + [ + "wrap://package/test-resolver => Client.load_wrapper => wrapper (wrap://package/test-resolver)", + [ + "wrap://package/test-resolver => UriResolverAggregator => package (wrap://package/test-resolver)", + [ + "wrap://package/test-resolver => Static - Package => package (wrap://package/test-resolver)" + ], + ], + "wrap://package/test-resolver => Wrapper.invoke", + ], + ], + ], +] diff --git a/packages/polywrap-uri-resolvers/tests/integration/extension_resolver/histories/can_resolve_package_with_subinvoke.py b/packages/polywrap-uri-resolvers/tests/integration/extension_resolver/histories/can_resolve_package_with_subinvoke.py new file mode 100644 index 00000000..0ff4c663 --- /dev/null +++ b/packages/polywrap-uri-resolvers/tests/integration/extension_resolver/histories/can_resolve_package_with_subinvoke.py @@ -0,0 +1,30 @@ +EXPECTED = [ + "wrap://test/package => UriResolverAggregator => package (wrap://test/package)", + [ + "wrap://test/package => Static - Miss", + "wrap://test/package => ExtendableUriResolver => package (wrap://test/package)", + [ + "wrap://test/package => ResolverExtension (wrap://package/test-subinvoke-resolver) => package (wrap://test/package)", + [ + "wrap://package/test-subinvoke-resolver => Client.load_wrapper => wrapper (wrap://package/test-subinvoke-resolver)", + [ + "wrap://package/test-subinvoke-resolver => UriResolverAggregator => package (wrap://package/test-subinvoke-resolver)", + [ + "wrap://package/test-subinvoke-resolver => Static - Package => package (wrap://package/test-subinvoke-resolver)" + ], + ], + "wrap://package/test-subinvoke-resolver => Wrapper.invoke", + [ + "wrap://package/test-resolver => Client.load_wrapper => wrapper (wrap://package/test-resolver)", + [ + "wrap://package/test-resolver => UriResolverAggregator => package (wrap://package/test-resolver)", + [ + "wrap://package/test-resolver => Static - Package => package (wrap://package/test-resolver)" + ], + ], + "wrap://package/test-resolver => Wrapper.invoke", + ], + ], + ], + ], +] diff --git a/packages/polywrap-uri-resolvers/tests/integration/extension_resolver/histories/can_resolve_uri.py b/packages/polywrap-uri-resolvers/tests/integration/extension_resolver/histories/can_resolve_uri.py new file mode 100644 index 00000000..ab794c14 --- /dev/null +++ b/packages/polywrap-uri-resolvers/tests/integration/extension_resolver/histories/can_resolve_uri.py @@ -0,0 +1,38 @@ +EXPECTED = [ + "wrap://test/from => UriResolverAggregator => uri (wrap://test/to)", + [ + "wrap://test/from => Package (wrap://package/test-resolver)", + "wrap://test/from => ExtendableUriResolver => uri (wrap://test/to)", + [ + "wrap://test/from => ResolverExtension (wrap://package/test-resolver) => uri (wrap://test/to)", + [ + "wrap://package/test-resolver => Client.load_wrapper => wrapper (wrap://package/test-resolver)", + [ + "wrap://package/test-resolver => UriResolverAggregator => package (wrap://package/test-resolver)", + [ + "wrap://package/test-resolver => Package (wrap://package/test-resolver) => package (wrap://package/test-resolver)" + ], + ], + "wrap://package/test-resolver => Wrapper.invoke", + ], + ], + ], + "wrap://test/to => UriResolverAggregator", + [ + "wrap://test/to => Package (wrap://package/test-resolver)", + "wrap://test/to => ExtendableUriResolver", + [ + "wrap://test/to => ResolverExtension (wrap://package/test-resolver)", + [ + "wrap://package/test-resolver => Client.load_wrapper => wrapper (wrap://package/test-resolver)", + [ + "wrap://package/test-resolver => UriResolverAggregator => package (wrap://package/test-resolver)", + [ + "wrap://package/test-resolver => Package (wrap://package/test-resolver) => package (wrap://package/test-resolver)" + ], + ], + "wrap://package/test-resolver => Wrapper.invoke", + ], + ], + ], +] diff --git a/packages/polywrap-uri-resolvers/tests/integration/extension_resolver/histories/can_resolve_uri_with_subinvoke.py b/packages/polywrap-uri-resolvers/tests/integration/extension_resolver/histories/can_resolve_uri_with_subinvoke.py new file mode 100644 index 00000000..20900ae1 --- /dev/null +++ b/packages/polywrap-uri-resolvers/tests/integration/extension_resolver/histories/can_resolve_uri_with_subinvoke.py @@ -0,0 +1,62 @@ +EXPECTED = [ + "wrap://test/from => UriResolverAggregator => uri (wrap://test/to)", + [ + "wrap://test/from => Package (wrap://package/test-subinvoke-resolver)", + "wrap://test/from => Package (wrap://package/test-resolver)", + "wrap://test/from => ExtendableUriResolver => uri (wrap://test/to)", + [ + "wrap://test/from => ResolverExtension (wrap://package/test-subinvoke-resolver) => uri (wrap://test/to)", + [ + "wrap://package/test-subinvoke-resolver => Client.load_wrapper => wrapper (wrap://package/test-subinvoke-resolver)", + [ + "wrap://package/test-subinvoke-resolver => UriResolverAggregator => package (wrap://package/test-subinvoke-resolver)", + [ + "wrap://package/test-subinvoke-resolver => Package (wrap://package/test-subinvoke-resolver) => package (wrap://package/test-subinvoke-resolver)" + ], + ], + "wrap://package/test-subinvoke-resolver => Wrapper.invoke", + [ + "wrap://package/test-resolver => Client.load_wrapper => wrapper (wrap://package/test-resolver)", + [ + "wrap://package/test-resolver => UriResolverAggregator => package (wrap://package/test-resolver)", + [ + "wrap://package/test-resolver => Package (wrap://package/test-subinvoke-resolver)", + "wrap://package/test-resolver => Package (wrap://package/test-resolver) => package (wrap://package/test-resolver)", + ], + ], + "wrap://package/test-resolver => Wrapper.invoke", + ], + ], + ], + ], + "wrap://test/to => UriResolverAggregator", + [ + "wrap://test/to => Package (wrap://package/test-subinvoke-resolver)", + "wrap://test/to => Package (wrap://package/test-resolver)", + "wrap://test/to => ExtendableUriResolver", + [ + "wrap://test/to => ResolverExtension (wrap://package/test-subinvoke-resolver)", + [ + "wrap://package/test-subinvoke-resolver => Client.load_wrapper => wrapper (wrap://package/test-subinvoke-resolver)", + [ + "wrap://package/test-subinvoke-resolver => UriResolverAggregator => package (wrap://package/test-subinvoke-resolver)", + [ + "wrap://package/test-subinvoke-resolver => Package (wrap://package/test-subinvoke-resolver) => package (wrap://package/test-subinvoke-resolver)" + ], + ], + "wrap://package/test-subinvoke-resolver => Wrapper.invoke", + [ + "wrap://package/test-resolver => Client.load_wrapper => wrapper (wrap://package/test-resolver)", + [ + "wrap://package/test-resolver => UriResolverAggregator => package (wrap://package/test-resolver)", + [ + "wrap://package/test-resolver => Package (wrap://package/test-subinvoke-resolver)", + "wrap://package/test-resolver => Package (wrap://package/test-resolver) => package (wrap://package/test-resolver)", + ], + ], + "wrap://package/test-resolver => Wrapper.invoke", + ], + ], + ], + ], +] diff --git a/packages/polywrap-uri-resolvers/tests/integration/extension_resolver/histories/can_use_wasm_fs_resolver.py b/packages/polywrap-uri-resolvers/tests/integration/extension_resolver/histories/can_use_wasm_fs_resolver.py new file mode 100644 index 00000000..4cadedbf --- /dev/null +++ b/packages/polywrap-uri-resolvers/tests/integration/extension_resolver/histories/can_use_wasm_fs_resolver.py @@ -0,0 +1,30 @@ +import os +from polywrap_core import Uri +from polywrap_test_cases import get_path_to_test_wrappers + + +source_uri = Uri( + "fs", + os.path.join(get_path_to_test_wrappers(), "asyncify", "implementations", "as"), +) + +EXPECTED = [ + f"{source_uri} => UriResolverAggregator", + [ + f"{source_uri} => Package (wrap://package/test-fs-resolver)", + f"{source_uri} => ExtendableUriResolver", + [ + f"{source_uri} => ResolverExtension (wrap://package/test-fs-resolver)", + [ + "wrap://package/test-fs-resolver => Client.load_wrapper => wrapper (wrap://package/test-fs-resolver)", + [ + "wrap://package/test-fs-resolver => UriResolverAggregator => package (wrap://package/test-fs-resolver)", + [ + "wrap://package/test-fs-resolver => Package (wrap://package/test-fs-resolver) => package (wrap://package/test-fs-resolver)" + ], + ], + "wrap://package/test-fs-resolver => Wrapper.invoke", + ], + ], + ], +] diff --git a/packages/polywrap-uri-resolvers/tests/integration/extension_resolver/histories/not_a_match.py b/packages/polywrap-uri-resolvers/tests/integration/extension_resolver/histories/not_a_match.py new file mode 100644 index 00000000..57e6465c --- /dev/null +++ b/packages/polywrap-uri-resolvers/tests/integration/extension_resolver/histories/not_a_match.py @@ -0,0 +1,20 @@ +EXPECTED = [ + "wrap://test/not-a-match => UriResolverAggregator", + [ + "wrap://test/not-a-match => Static - Miss", + "wrap://test/not-a-match => ExtendableUriResolver", + [ + "wrap://test/not-a-match => ResolverExtension (wrap://package/test-resolver)", + [ + "wrap://package/test-resolver => Client.load_wrapper => wrapper (wrap://package/test-resolver)", + [ + "wrap://package/test-resolver => UriResolverAggregator => package (wrap://package/test-resolver)", + [ + "wrap://package/test-resolver => Static - Package => package (wrap://package/test-resolver)" + ], + ], + "wrap://package/test-resolver => Wrapper.invoke", + ], + ], + ], +] diff --git a/packages/polywrap-uri-resolvers/tests/integration/extension_resolver/histories/not_a_match_with_subinvoke.py b/packages/polywrap-uri-resolvers/tests/integration/extension_resolver/histories/not_a_match_with_subinvoke.py new file mode 100644 index 00000000..81d2bd56 --- /dev/null +++ b/packages/polywrap-uri-resolvers/tests/integration/extension_resolver/histories/not_a_match_with_subinvoke.py @@ -0,0 +1,30 @@ +EXPECTED = [ + "wrap://test/not-a-match => UriResolverAggregator", + [ + "wrap://test/not-a-match => Static - Miss", + "wrap://test/not-a-match => ExtendableUriResolver", + [ + "wrap://test/not-a-match => ResolverExtension (wrap://package/test-subinvoke-resolver)", + [ + "wrap://package/test-subinvoke-resolver => Client.load_wrapper => wrapper (wrap://package/test-subinvoke-resolver)", + [ + "wrap://package/test-subinvoke-resolver => UriResolverAggregator => package (wrap://package/test-subinvoke-resolver)", + [ + "wrap://package/test-subinvoke-resolver => Static - Package => package (wrap://package/test-subinvoke-resolver)" + ], + ], + "wrap://package/test-subinvoke-resolver => Wrapper.invoke", + [ + "wrap://package/test-resolver => Client.load_wrapper => wrapper (wrap://package/test-resolver)", + [ + "wrap://package/test-resolver => UriResolverAggregator => package (wrap://package/test-resolver)", + [ + "wrap://package/test-resolver => Static - Package => package (wrap://package/test-resolver)" + ], + ], + "wrap://package/test-resolver => Wrapper.invoke", + ], + ], + ], + ], +] diff --git a/packages/polywrap-uri-resolvers/tests/integration/extension_resolver/histories/not_found_extension.py b/packages/polywrap-uri-resolvers/tests/integration/extension_resolver/histories/not_found_extension.py new file mode 100644 index 00000000..22dcd12b --- /dev/null +++ b/packages/polywrap-uri-resolvers/tests/integration/extension_resolver/histories/not_found_extension.py @@ -0,0 +1,13 @@ +EXPECTED = [ + 'wrap://test/not-a-match => UriResolverAggregator => error (Unable to find URI wrap://test/undefined-resolver.\ncode: 28 URI NOT FOUND\nuri: wrap://test/undefined-resolver\nuriResolutionStack: [\n "wrap://test/undefined-resolver => UriResolverAggregator"\n])', + [ + 'wrap://test/not-a-match => ExtendableUriResolver => error (Unable to find URI wrap://test/undefined-resolver.\ncode: 28 URI NOT FOUND\nuri: wrap://test/undefined-resolver\nuriResolutionStack: [\n "wrap://test/undefined-resolver => UriResolverAggregator"\n])', + [ + 'wrap://test/not-a-match => ResolverExtension (wrap://test/undefined-resolver) => error (Unable to find URI wrap://test/undefined-resolver.\ncode: 28 URI NOT FOUND\nuri: wrap://test/undefined-resolver\nuriResolutionStack: [\n "wrap://test/undefined-resolver => UriResolverAggregator"\n])', + [ + 'wrap://test/undefined-resolver => Client.loadWrapper => error (Unable to find URI wrap://test/undefined-resolver.\ncode: 28 URI NOT FOUND\nuri: wrap://test/undefined-resolver\nuriResolutionStack: [\n "wrap://test/undefined-resolver => UriResolverAggregator"\n])', + ["wrap://test/undefined-resolver => UriResolverAggregator"], + ], + ], + ], +] diff --git a/packages/polywrap-uri-resolvers/tests/integration/extension_resolver/histories/shows_plugin_extension_error.py b/packages/polywrap-uri-resolvers/tests/integration/extension_resolver/histories/shows_plugin_extension_error.py new file mode 100644 index 00000000..6dd11d75 --- /dev/null +++ b/packages/polywrap-uri-resolvers/tests/integration/extension_resolver/histories/shows_plugin_extension_error.py @@ -0,0 +1,20 @@ +EXPECTED = [ + 'wrap://test/error => UriResolverAggregator => error (Test error\ncode: 51 WRAPPER INVOKE ABORTED\nuri: wrap://package/test-resolver\nmethod: tryResolveUri\nargs: {\n "authority": "test",\n "path": "error"\n} )', + [ + "wrap://test/error => StaticResolver - Miss", + 'wrap://test/error => ExtendableUriResolver => error (Test error\ncode: 51 WRAPPER INVOKE ABORTED\nuri: wrap://package/test-resolver\nmethod: tryResolveUri\nargs: {\n "authority": "test",\n "path": "error"\n} )', + [ + 'wrap://test/error => ResolverExtension (wrap://package/test-resolver) => error (Test error\ncode: 51 WRAPPER INVOKE ABORTED\nuri: wrap://package/test-resolver\nmethod: tryResolveUri\nargs: {\n "authority": "test",\n "path": "error"\n} )', + [ + "wrap://package/test-resolver => Client.loadWrapper => wrapper (wrap://package/test-resolver)", + [ + "wrap://package/test-resolver => UriResolverAggregator => package (wrap://package/test-resolver)", + [ + "wrap://package/test-resolver => StaticResolver - Package (wrap://package/test-resolver) => package (wrap://package/test-resolver)" + ], + ], + 'wrap://package/test-resolver => Client.invokeWrapper => error (Test error\ncode: 51 WRAPPER INVOKE ABORTED\nuri: wrap://package/test-resolver\nmethod: tryResolveUri\nargs: {\n "authority": "test",\n "path": "error"\n} )', + ], + ], + ], +] diff --git a/packages/polywrap-uri-resolvers/tests/integration/extension_resolver/histories/shows_plugin_extension_error_with_subinvoke.py b/packages/polywrap-uri-resolvers/tests/integration/extension_resolver/histories/shows_plugin_extension_error_with_subinvoke.py new file mode 100644 index 00000000..f6451065 --- /dev/null +++ b/packages/polywrap-uri-resolvers/tests/integration/extension_resolver/histories/shows_plugin_extension_error_with_subinvoke.py @@ -0,0 +1,30 @@ +EXPECTED = [ + 'wrap://test/error => UriResolverAggregator => error (__wrap_abort: Test error\ncode: 51 WRAPPER INVOKE ABORTED\nuri: wrap://package/test-resolver\nmethod: tryResolveUri\nargs: {\n "authority": "test",\n "path": "error"\n} \nsource: { , row: 35, col: 21 }\ncode: 51 WRAPPER INVOKE ABORTED\nuri: wrap://package/subinvoke-resolver\nmethod: tryResolveUri\nargs: {\n "authority": "test",\n "path": "error"\n} \nsource: { , row: 177, col: 15 })', + [ + "wrap://test/error => StaticResolver - Miss", + 'wrap://test/error => ExtendableUriResolver => error (__wrap_abort: Test error\ncode: 51 WRAPPER INVOKE ABORTED\nuri: wrap://package/test-resolver\nmethod: tryResolveUri\nargs: {\n "authority": "test",\n "path": "error"\n} \nsource: { , row: 35, col: 21 }\ncode: 51 WRAPPER INVOKE ABORTED\nuri: wrap://package/subinvoke-resolver\nmethod: tryResolveUri\nargs: {\n "authority": "test",\n "path": "error"\n} \nsource: { , row: 177, col: 15 })', + [ + 'wrap://test/error => ResolverExtension (wrap://package/subinvoke-resolver) => error (__wrap_abort: Test error\ncode: 51 WRAPPER INVOKE ABORTED\nuri: wrap://package/test-resolver\nmethod: tryResolveUri\nargs: {\n "authority": "test",\n "path": "error"\n} \nsource: { , row: 35, col: 21 }\ncode: 51 WRAPPER INVOKE ABORTED\nuri: wrap://package/subinvoke-resolver\nmethod: tryResolveUri\nargs: {\n "authority": "test",\n "path": "error"\n} \nsource: { , row: 177, col: 15 })', + [ + "wrap://package/subinvoke-resolver => Client.loadWrapper => wrapper (wrap://package/subinvoke-resolver)", + [ + "wrap://package/subinvoke-resolver => UriResolverAggregator => package (wrap://package/subinvoke-resolver)", + [ + "wrap://package/subinvoke-resolver => StaticResolver - Package (wrap://package/subinvoke-resolver) => package (wrap://package/subinvoke-resolver)" + ], + ], + 'wrap://package/subinvoke-resolver => Client.invokeWrapper => error (__wrap_abort: Test error\ncode: 51 WRAPPER INVOKE ABORTED\nuri: wrap://package/test-resolver\nmethod: tryResolveUri\nargs: {\n "authority": "test",\n "path": "error"\n} \nsource: { , row: 35, col: 21 }\ncode: 51 WRAPPER INVOKE ABORTED\nuri: wrap://package/subinvoke-resolver\nmethod: tryResolveUri\nargs: {\n "authority": "test",\n "path": "error"\n} \nsource: { , row: 177, col: 15 })', + [ + "wrap://package/test-resolver => Client.loadWrapper => wrapper (wrap://package/test-resolver)", + [ + "wrap://package/test-resolver => UriResolverAggregator => package (wrap://package/test-resolver)", + [ + "wrap://package/test-resolver => StaticResolver - Package (wrap://package/test-resolver) => package (wrap://package/test-resolver)" + ], + ], + 'wrap://package/test-resolver => Client.invokeWrapper => error (__wrap_abort: Test error\ncode: 51 WRAPPER INVOKE ABORTED\nuri: wrap://package/test-resolver\nmethod: tryResolveUri\nargs: {\n "authority": "test",\n "path": "error"\n} \nsource: { , row: 35, col: 21 })', + ], + ], + ], + ], +] diff --git a/packages/polywrap-uri-resolvers/tests/integration/extension_resolver/histories/shows_wasm_extension_error.py b/packages/polywrap-uri-resolvers/tests/integration/extension_resolver/histories/shows_wasm_extension_error.py new file mode 100644 index 00000000..e2eb9107 --- /dev/null +++ b/packages/polywrap-uri-resolvers/tests/integration/extension_resolver/histories/shows_wasm_extension_error.py @@ -0,0 +1,20 @@ +EXPECTED = [ + 'wrap://test/error => UriResolverAggregator => error (__wrap_abort: Test error\ncode: 51 WRAPPER INVOKE ABORTED\nuri: wrap://package/test-resolver\nmethod: tryResolveUri\nargs: {\n "authority": "test",\n "path": "error"\n} \nsource: { file: "src/wrap/module/wrapped.rs", row: 35, col: 21 })', + [ + "wrap://test/error => StaticResolver - Miss", + 'wrap://test/error => ExtendableUriResolver => error (__wrap_abort: Test error\ncode: 51 WRAPPER INVOKE ABORTED\nuri: wrap://package/test-resolver\nmethod: tryResolveUri\nargs: {\n "authority": "test",\n "path": "error"\n} \nsource: { file: "src/wrap/module/wrapped.rs", row: 35, col: 21 })', + [ + 'wrap://test/error => ResolverExtension (wrap://package/test-resolver) => error (__wrap_abort: Test error\ncode: 51 WRAPPER INVOKE ABORTED\nuri: wrap://package/test-resolver\nmethod: tryResolveUri\nargs: {\n "authority": "test",\n "path": "error"\n} \nsource: { file: "src/wrap/module/wrapped.rs", row: 35, col: 21 })', + [ + "wrap://package/test-resolver => Client.loadWrapper => wrapper (wrap://package/test-resolver)", + [ + "wrap://package/test-resolver => UriResolverAggregator => package (wrap://package/test-resolver)", + [ + "wrap://package/test-resolver => StaticResolver - Package (wrap://package/test-resolver) => package (wrap://package/test-resolver)" + ], + ], + 'wrap://package/test-resolver => Client.invokeWrapper => error (__wrap_abort: Test error\ncode: 51 WRAPPER INVOKE ABORTED\nuri: wrap://package/test-resolver\nmethod: tryResolveUri\nargs: {\n "authority": "test",\n "path": "error"\n} \nsource: { file: "src/wrap/module/wrapped.rs", row: 35, col: 21 })', + ], + ], + ], +] diff --git a/packages/polywrap-uri-resolvers/tests/integration/extension_resolver/histories/shows_wasm_extension_error_with_subinvoke.py b/packages/polywrap-uri-resolvers/tests/integration/extension_resolver/histories/shows_wasm_extension_error_with_subinvoke.py new file mode 100644 index 00000000..cdd2b285 --- /dev/null +++ b/packages/polywrap-uri-resolvers/tests/integration/extension_resolver/histories/shows_wasm_extension_error_with_subinvoke.py @@ -0,0 +1,30 @@ +EXPECTED = [ + 'wrap://test/error => UriResolverAggregator => error (SubInvocation exception encountered\ncode: 51 WRAPPER INVOKE ABORTED\nuri: wrap://package/subinvoke-resolver\nmethod: tryResolveUri\nargs: {\n "authority": "test",\n "path": "error"\n} \nsource: { file: "src/wrap/module/wrapped.rs", row: 35, col: 21 }\n\nAnother exception was encountered during execution:\nWrapError: __wrap_abort: Test error\ncode: 51 WRAPPER INVOKE ABORTED\nuri: wrap://package/test-resolver\nmethod: tryResolveUri\nargs: {\n "authority": "test",\n "path": "error"\n} \nsource: { file: "src/wrap/module/wrapped.rs", row: 35, col: 21 })', + [ + "wrap://test/error => StaticResolver - Miss", + 'wrap://test/error => ExtendableUriResolver => error (SubInvocation exception encountered\ncode: 51 WRAPPER INVOKE ABORTED\nuri: wrap://package/subinvoke-resolver\nmethod: tryResolveUri\nargs: {\n "authority": "test",\n "path": "error"\n} \nsource: { file: "src/wrap/module/wrapped.rs", row: 35, col: 21 }\n\nAnother exception was encountered during execution:\nWrapError: __wrap_abort: Test error\ncode: 51 WRAPPER INVOKE ABORTED\nuri: wrap://package/test-resolver\nmethod: tryResolveUri\nargs: {\n "authority": "test",\n "path": "error"\n} \nsource: { file: "src/wrap/module/wrapped.rs", row: 35, col: 21 })', + [ + 'wrap://test/error => ResolverExtension (wrap://package/subinvoke-resolver) => error (SubInvocation exception encountered\ncode: 51 WRAPPER INVOKE ABORTED\nuri: wrap://package/subinvoke-resolver\nmethod: tryResolveUri\nargs: {\n "authority": "test",\n "path": "error"\n} \nsource: { file: "src/wrap/module/wrapped.rs", row: 35, col: 21 }\n\nAnother exception was encountered during execution:\nWrapError: __wrap_abort: Test error\ncode: 51 WRAPPER INVOKE ABORTED\nuri: wrap://package/test-resolver\nmethod: tryResolveUri\nargs: {\n "authority": "test",\n "path": "error"\n} \nsource: { file: "src/wrap/module/wrapped.rs", row: 35, col: 21 })', + [ + "wrap://package/subinvoke-resolver => Client.loadWrapper => wrapper (wrap://package/subinvoke-resolver)", + [ + "wrap://package/subinvoke-resolver => UriResolverAggregator => package (wrap://package/subinvoke-resolver)", + [ + "wrap://package/subinvoke-resolver => StaticResolver - Package (wrap://package/subinvoke-resolver) => package (wrap://package/subinvoke-resolver)" + ], + ], + 'wrap://package/subinvoke-resolver => Client.invokeWrapper => error (SubInvocation exception encountered\ncode: 51 WRAPPER INVOKE ABORTED\nuri: wrap://package/subinvoke-resolver\nmethod: tryResolveUri\nargs: {\n "authority": "test",\n "path": "error"\n} \nsource: { file: "src/wrap/module/wrapped.rs", row: 35, col: 21 }\n\nAnother exception was encountered during execution:\nWrapError: __wrap_abort: Test error\ncode: 51 WRAPPER INVOKE ABORTED\nuri: wrap://package/test-resolver\nmethod: tryResolveUri\nargs: {\n "authority": "test",\n "path": "error"\n} \nsource: { file: "src/wrap/module/wrapped.rs", row: 35, col: 21 })', + [ + "wrap://package/test-resolver => Client.loadWrapper => wrapper (wrap://package/test-resolver)", + [ + "wrap://package/test-resolver => UriResolverAggregator => package (wrap://package/test-resolver)", + [ + "wrap://package/test-resolver => StaticResolver - Package (wrap://package/test-resolver) => package (wrap://package/test-resolver)" + ], + ], + 'wrap://package/test-resolver => Client.invokeWrapper => error (__wrap_abort: Test error\ncode: 51 WRAPPER INVOKE ABORTED\nuri: wrap://package/test-resolver\nmethod: tryResolveUri\nargs: {\n "authority": "test",\n "path": "error"\n} \nsource: { file: "src/wrap/module/wrapped.rs", row: 35, col: 21 })', + ], + ], + ], + ], +] diff --git a/packages/polywrap-uri-resolvers/tests/integration/extension_resolver/mocker.py b/packages/polywrap-uri-resolvers/tests/integration/extension_resolver/mocker.py new file mode 100644 index 00000000..6108f930 --- /dev/null +++ b/packages/polywrap-uri-resolvers/tests/integration/extension_resolver/mocker.py @@ -0,0 +1,71 @@ +import os +from typing import Dict, Optional +from polywrap_core import Any, InvokerClient, Uri, UriPackage +from polywrap_plugin import PluginModule, PluginPackage +from polywrap_uri_resolvers import ( + MaybeUriOrManifest, + WasmPackage, +) +from polywrap_test_cases import get_path_to_test_wrappers + + +class MockPluginExtensionResolver(PluginModule[None]): + URI = Uri.from_str("wrap://package/test-resolver") + + def __init__(self): + super().__init__(None) + + def tryResolveUri( + self, args: Dict[str, Any], *_: Any + ) -> Optional[MaybeUriOrManifest]: + if args.get("authority") != "test": + return None + + match args.get("path"): + case "from": + return {"uri": Uri.from_str("test/to").uri} + case "package": + return {"manifest": b"test"} + case "error": + raise ValueError("test error") + case _: + return None + + +def mock_plugin_extension_resolver(): + return PluginPackage(MockPluginExtensionResolver(), NotImplemented) + + +class MockSubinvokePluginResolver(PluginModule[None]): + URI = Uri.from_str("wrap://package/test-subinvoke-resolver") + + def __init__(self): + super().__init__(None) + + def tryResolveUri( + self, args: Dict[str, Any], client: InvokerClient, *_: Any + ) -> Optional[MaybeUriOrManifest]: + return client.invoke( + uri=Uri.from_str("package/test-resolver"), method="tryResolveUri", args=args + ) + + +def mock_subinvoke_plugin_resolver() -> PluginPackage[None]: + return PluginPackage(MockSubinvokePluginResolver(), NotImplemented) + + +def mock_fs_wasm_package_resolver() -> UriPackage: + wrapper_module_path = os.path.join( + get_path_to_test_wrappers(), "resolver", "02-fs", "implementations", "as", "wrap.wasm" + ) + wrapper_manifest_path = os.path.join( + get_path_to_test_wrappers(), "resolver", "02-fs", "implementations", "as", "wrap.info" + ) + with open(wrapper_module_path, "rb") as f: + module = f.read() + + with open(wrapper_manifest_path, "rb") as f: + manifest = f.read() + + package = WasmPackage(NotImplemented, manifest=manifest, wasm_module=module) + return UriPackage(uri=Uri.from_str("package/test-fs-resolver"),package=package) diff --git a/packages/polywrap-uri-resolvers/tests/integration/extension_resolver/test_can_resolve_package.py b/packages/polywrap-uri-resolvers/tests/integration/extension_resolver/test_can_resolve_package.py new file mode 100644 index 00000000..dfc439e0 --- /dev/null +++ b/packages/polywrap-uri-resolvers/tests/integration/extension_resolver/test_can_resolve_package.py @@ -0,0 +1,60 @@ +from polywrap_client import PolywrapClient +from polywrap_core import ( + ClientConfig, + Uri, + UriPackage, + UriResolutionContext, + build_clean_uri_history, +) +from polywrap_uri_resolvers import ( + ExtendableUriResolver, + RecursiveResolver, + StaticResolver, + UriResolverAggregator, +) +import pytest + +from .mocker import mock_plugin_extension_resolver, MockPluginExtensionResolver + + +@pytest.fixture +def client() -> PolywrapClient: + resolver = RecursiveResolver( + UriResolverAggregator( + [ + StaticResolver( + { + MockPluginExtensionResolver.URI: UriPackage( + uri=MockPluginExtensionResolver.URI, + package=mock_plugin_extension_resolver(), + ) + } + ), + ExtendableUriResolver(), + ] + ) + ) + return PolywrapClient( + ClientConfig( + resolver=resolver, + interfaces={ + ExtendableUriResolver.DEFAULT_EXT_INTERFACE_URIS[0]: [ + MockPluginExtensionResolver.URI + ] + }, + ) + ) + + +def test_can_resolve_package_with_plugin_extension(client: PolywrapClient) -> None: + resolution_context = UriResolutionContext() + source_uri = Uri.from_str("test/package") + + result = client.try_resolve_uri( + uri=source_uri, resolution_context=resolution_context + ) + + from .histories.can_resolve_package import EXPECTED + + assert isinstance(result, UriPackage), "Expected a UriPackage result." + assert build_clean_uri_history(resolution_context.get_history()) == EXPECTED diff --git a/packages/polywrap-uri-resolvers/tests/integration/extension_resolver/test_can_resolve_package_with_subinvoke.py b/packages/polywrap-uri-resolvers/tests/integration/extension_resolver/test_can_resolve_package_with_subinvoke.py new file mode 100644 index 00000000..692c8862 --- /dev/null +++ b/packages/polywrap-uri-resolvers/tests/integration/extension_resolver/test_can_resolve_package_with_subinvoke.py @@ -0,0 +1,64 @@ +from polywrap_client import PolywrapClient +from polywrap_core import ( + ClientConfig, + Uri, + UriPackage, + UriResolutionContext, + build_clean_uri_history, +) +from polywrap_uri_resolvers import ( + ExtendableUriResolver, + RecursiveResolver, + StaticResolver, + UriResolverAggregator, +) +import pytest + +from .mocker import mock_subinvoke_plugin_resolver, mock_plugin_extension_resolver, MockPluginExtensionResolver, MockSubinvokePluginResolver + + +@pytest.fixture +def client() -> PolywrapClient: + resolver = RecursiveResolver( + UriResolverAggregator( + [ + StaticResolver( + { + MockPluginExtensionResolver.URI: UriPackage( + uri=MockPluginExtensionResolver.URI, + package=mock_plugin_extension_resolver(), + ), + MockSubinvokePluginResolver.URI: UriPackage( + uri=MockSubinvokePluginResolver.URI, + package=mock_subinvoke_plugin_resolver(), + ), + } + ), + ExtendableUriResolver(), + ] + ) + ) + return PolywrapClient( + ClientConfig( + resolver=resolver, + interfaces={ + ExtendableUriResolver.DEFAULT_EXT_INTERFACE_URIS[0]: [ + MockSubinvokePluginResolver.URI + ] + }, + ) + ) + + +def test_can_resolve_package_with_plugin_extension(client: PolywrapClient) -> None: + resolution_context = UriResolutionContext() + source_uri = Uri.from_str("test/package") + + result = client.try_resolve_uri( + uri=source_uri, resolution_context=resolution_context + ) + + from .histories.can_resolve_package_with_subinvoke import EXPECTED + print(build_clean_uri_history(resolution_context.get_history())) + assert isinstance(result, UriPackage), "Expected a UriPackage result." + assert build_clean_uri_history(resolution_context.get_history()) == EXPECTED diff --git a/packages/polywrap-uri-resolvers/tests/integration/extension_resolver/test_can_resolve_uri.py b/packages/polywrap-uri-resolvers/tests/integration/extension_resolver/test_can_resolve_uri.py new file mode 100644 index 00000000..18d28e72 --- /dev/null +++ b/packages/polywrap-uri-resolvers/tests/integration/extension_resolver/test_can_resolve_uri.py @@ -0,0 +1,56 @@ +from polywrap_client import PolywrapClient +from polywrap_core import ( + ClientConfig, + Uri, + UriResolutionContext, + build_clean_uri_history, +) +from polywrap_uri_resolvers import ( + ExtendableUriResolver, + RecursiveResolver, + UriResolverAggregator, + PackageResolver, +) +import pytest + +from .mocker import mock_plugin_extension_resolver, MockPluginExtensionResolver + + +@pytest.fixture +def client() -> PolywrapClient: + resolver = RecursiveResolver( + UriResolverAggregator( + [ + PackageResolver( + MockPluginExtensionResolver.URI, + mock_plugin_extension_resolver(), + ), + ExtendableUriResolver(), + ] + ) + ) + return PolywrapClient( + ClientConfig( + resolver=resolver, + interfaces={ + ExtendableUriResolver.DEFAULT_EXT_INTERFACE_URIS[0]: [ + MockPluginExtensionResolver.URI + ] + }, + ) + ) + + +def test_can_resolve_uri_with_plugin_extension(client: PolywrapClient) -> None: + resolution_context = UriResolutionContext() + source_uri = Uri.from_str("test/from") + redirected_uri = Uri.from_str("test/to") + + result = client.try_resolve_uri( + uri=source_uri, resolution_context=resolution_context + ) + + from .histories.can_resolve_uri import EXPECTED + assert isinstance(result, Uri), "Expected a Uri result." + assert result == redirected_uri + assert build_clean_uri_history(resolution_context.get_history()) == EXPECTED diff --git a/packages/polywrap-uri-resolvers/tests/integration/extension_resolver/test_can_resolve_uri_with_subinvoke.py b/packages/polywrap-uri-resolvers/tests/integration/extension_resolver/test_can_resolve_uri_with_subinvoke.py new file mode 100644 index 00000000..bc57abb0 --- /dev/null +++ b/packages/polywrap-uri-resolvers/tests/integration/extension_resolver/test_can_resolve_uri_with_subinvoke.py @@ -0,0 +1,60 @@ +from polywrap_client import PolywrapClient +from polywrap_core import ( + ClientConfig, + Uri, + UriResolutionContext, + build_clean_uri_history, +) +from polywrap_uri_resolvers import ( + ExtendableUriResolver, + RecursiveResolver, + UriResolverAggregator, + PackageResolver, +) +import pytest + +from .mocker import mock_subinvoke_plugin_resolver, mock_plugin_extension_resolver, MockPluginExtensionResolver, MockSubinvokePluginResolver + + +@pytest.fixture +def client() -> PolywrapClient: + resolver = RecursiveResolver( + UriResolverAggregator( + [ + PackageResolver( + MockSubinvokePluginResolver.URI, + mock_subinvoke_plugin_resolver(), + ), + PackageResolver( + MockPluginExtensionResolver.URI, + mock_plugin_extension_resolver(), + ), + ExtendableUriResolver(), + ] + ) + ) + return PolywrapClient( + ClientConfig( + resolver=resolver, + interfaces={ + ExtendableUriResolver.DEFAULT_EXT_INTERFACE_URIS[0]: [ + MockSubinvokePluginResolver.URI + ] + }, + ) + ) + + +def test_can_resolve_uri_with_plugin_extension(client: PolywrapClient) -> None: + resolution_context = UriResolutionContext() + source_uri = Uri.from_str("test/from") + redirected_uri = Uri.from_str("test/to") + + result = client.try_resolve_uri( + uri=source_uri, resolution_context=resolution_context + ) + + from .histories.can_resolve_uri_with_subinvoke import EXPECTED + assert isinstance(result, Uri), "Expected a Uri result." + assert result == redirected_uri + assert build_clean_uri_history(resolution_context.get_history()) == EXPECTED diff --git a/packages/polywrap-uri-resolvers/tests/integration/extension_resolver/test_not_a_match.py b/packages/polywrap-uri-resolvers/tests/integration/extension_resolver/test_not_a_match.py new file mode 100644 index 00000000..fd1a124f --- /dev/null +++ b/packages/polywrap-uri-resolvers/tests/integration/extension_resolver/test_not_a_match.py @@ -0,0 +1,59 @@ +from polywrap_client import PolywrapClient +from polywrap_core import ( + ClientConfig, + Uri, + UriPackage, + UriResolutionContext, + build_clean_uri_history, +) +from polywrap_uri_resolvers import ( + ExtendableUriResolver, + RecursiveResolver, + StaticResolver, + UriResolverAggregator, +) +import pytest + +from .mocker import mock_plugin_extension_resolver, MockPluginExtensionResolver + + +@pytest.fixture +def client() -> PolywrapClient: + resolver = RecursiveResolver( + UriResolverAggregator( + [ + StaticResolver( + { + MockPluginExtensionResolver.URI: UriPackage( + uri=MockPluginExtensionResolver.URI, + package=mock_plugin_extension_resolver(), + ) + } + ), + ExtendableUriResolver(), + ] + ) + ) + return PolywrapClient( + ClientConfig( + resolver=resolver, + interfaces={ + ExtendableUriResolver.DEFAULT_EXT_INTERFACE_URIS[0]: [ + MockPluginExtensionResolver.URI + ] + }, + ) + ) + + +def test_can_resolve_uri_with_plugin_extension(client: PolywrapClient) -> None: + resolution_context = UriResolutionContext() + source_uri = Uri.from_str("test/not-a-match") + + result = client.try_resolve_uri( + uri=source_uri, resolution_context=resolution_context + ) + + from .histories.not_a_match import EXPECTED + assert isinstance(result, Uri), "Expected a Uri result." + assert build_clean_uri_history(resolution_context.get_history()) == EXPECTED diff --git a/packages/polywrap-uri-resolvers/tests/integration/extension_resolver/test_not_a_match_with_subinvoke.py b/packages/polywrap-uri-resolvers/tests/integration/extension_resolver/test_not_a_match_with_subinvoke.py new file mode 100644 index 00000000..c05c6c5c --- /dev/null +++ b/packages/polywrap-uri-resolvers/tests/integration/extension_resolver/test_not_a_match_with_subinvoke.py @@ -0,0 +1,65 @@ +from polywrap_client import PolywrapClient +from polywrap_core import ( + ClientConfig, + Uri, + UriPackage, + UriResolutionContext, + build_clean_uri_history, +) +from polywrap_uri_resolvers import ( + ExtendableUriResolver, + RecursiveResolver, + StaticResolver, + UriResolverAggregator, +) +import pytest + +from .mocker import MockSubinvokePluginResolver, mock_plugin_extension_resolver, MockPluginExtensionResolver, mock_subinvoke_plugin_resolver + + + +@pytest.fixture +def client() -> PolywrapClient: + resolver = RecursiveResolver( + UriResolverAggregator( + [ + StaticResolver( + { + MockPluginExtensionResolver.URI: UriPackage( + uri=MockPluginExtensionResolver.URI, + package=mock_plugin_extension_resolver(), + ), + MockSubinvokePluginResolver.URI: UriPackage( + uri=MockSubinvokePluginResolver.URI, + package=mock_subinvoke_plugin_resolver(), + ), + } + ), + ExtendableUriResolver(), + ] + ) + ) + return PolywrapClient( + ClientConfig( + resolver=resolver, + interfaces={ + ExtendableUriResolver.DEFAULT_EXT_INTERFACE_URIS[0]: [ + MockSubinvokePluginResolver.URI + ] + }, + ) + ) + + + +def test_can_resolve_uri_with_plugin_extension(client: PolywrapClient) -> None: + resolution_context = UriResolutionContext() + source_uri = Uri.from_str("test/not-a-match") + + result = client.try_resolve_uri( + uri=source_uri, resolution_context=resolution_context + ) + + from .histories.not_a_match_with_subinvoke import EXPECTED + assert isinstance(result, Uri), "Expected a Uri result." + assert build_clean_uri_history(resolution_context.get_history()) == EXPECTED diff --git a/packages/polywrap-uri-resolvers/tests/integration/extension_resolver/test_not_found_extension.py b/packages/polywrap-uri-resolvers/tests/integration/extension_resolver/test_not_found_extension.py new file mode 100644 index 00000000..a456870d --- /dev/null +++ b/packages/polywrap-uri-resolvers/tests/integration/extension_resolver/test_not_found_extension.py @@ -0,0 +1,44 @@ +from polywrap_client import PolywrapClient +from polywrap_core import ( + ClientConfig, + Uri, + UriResolutionContext, +) +from polywrap_uri_resolvers import ( + ExtendableUriResolver, + RecursiveResolver, + UriResolverAggregator, + UriResolverExtensionNotFoundError, +) +import pytest + + +@pytest.fixture +def client() -> PolywrapClient: + resolver = RecursiveResolver( + UriResolverAggregator( + [ + ExtendableUriResolver(), + ] + ) + ) + return PolywrapClient( + ClientConfig( + resolver=resolver, + interfaces={ + ExtendableUriResolver.DEFAULT_EXT_INTERFACE_URIS[0]: [ + Uri.from_str("test/undefined-resolver") + ] + }, + ) + ) + + +def test_can_resolve_uri_with_plugin_extension(client: PolywrapClient) -> None: + resolution_context = UriResolutionContext() + source_uri = Uri.from_str("test/not-a-match") + + with pytest.raises(UriResolverExtensionNotFoundError): + client.try_resolve_uri( + uri=source_uri, resolution_context=resolution_context + ) diff --git a/packages/polywrap-uri-resolvers/tests/integration/extension_resolver/test_shows_plugin_extension_error.py b/packages/polywrap-uri-resolvers/tests/integration/extension_resolver/test_shows_plugin_extension_error.py new file mode 100644 index 00000000..7dcd60bf --- /dev/null +++ b/packages/polywrap-uri-resolvers/tests/integration/extension_resolver/test_shows_plugin_extension_error.py @@ -0,0 +1,59 @@ +from polywrap_client import PolywrapClient +from polywrap_core import ( + ClientConfig, + Uri, + UriPackage, + UriResolutionContext, +) +from polywrap_uri_resolvers import ( + ExtendableUriResolver, + RecursiveResolver, + StaticResolver, + UriResolverAggregator, + UriResolverExtensionError, +) +import pytest + +from .mocker import mock_plugin_extension_resolver, MockPluginExtensionResolver + + +@pytest.fixture +def client() -> PolywrapClient: + resolver = RecursiveResolver( + UriResolverAggregator( + [ + StaticResolver( + { + MockPluginExtensionResolver.URI: UriPackage( + uri=MockPluginExtensionResolver.URI, + package=mock_plugin_extension_resolver(), + ) + } + ), + ExtendableUriResolver(), + ] + ) + ) + return PolywrapClient( + ClientConfig( + resolver=resolver, + interfaces={ + ExtendableUriResolver.DEFAULT_EXT_INTERFACE_URIS[0]: [ + MockPluginExtensionResolver.URI + ] + }, + ) + ) + + +def test_shows_error_with_plugin_extension(client: PolywrapClient) -> None: + resolution_context = UriResolutionContext() + source_uri = Uri.from_str("test/error") + + with pytest.raises(UriResolverExtensionError) as excinfo: + client.try_resolve_uri(uri=source_uri, resolution_context=resolution_context) + + assert ( + excinfo.value.args[0] + == f"Failed to resolve uri: {source_uri}, using extension resolver: ({MockPluginExtensionResolver.URI})" + ) diff --git a/packages/polywrap-uri-resolvers/tests/integration/extension_resolver/test_shows_plugin_extension_error_with_subinvoke.py b/packages/polywrap-uri-resolvers/tests/integration/extension_resolver/test_shows_plugin_extension_error_with_subinvoke.py new file mode 100644 index 00000000..c11c6dc6 --- /dev/null +++ b/packages/polywrap-uri-resolvers/tests/integration/extension_resolver/test_shows_plugin_extension_error_with_subinvoke.py @@ -0,0 +1,64 @@ +from polywrap_client import PolywrapClient +from polywrap_core import ( + ClientConfig, + Uri, + UriPackage, + UriResolutionContext, +) +from polywrap_uri_resolvers import ( + ExtendableUriResolver, + RecursiveResolver, + StaticResolver, + UriResolverAggregator, + UriResolverExtensionError, +) +import pytest + +from .mocker import mock_subinvoke_plugin_resolver, mock_plugin_extension_resolver, MockPluginExtensionResolver, MockSubinvokePluginResolver + + +@pytest.fixture +def client() -> PolywrapClient: + resolver = RecursiveResolver( + UriResolverAggregator( + [ + StaticResolver( + { + MockSubinvokePluginResolver.URI: UriPackage( + uri=MockSubinvokePluginResolver.URI, + package=mock_subinvoke_plugin_resolver(), + ), + MockPluginExtensionResolver.URI: UriPackage( + uri=MockPluginExtensionResolver.URI, + package=mock_plugin_extension_resolver(), + ), + } + ), + ExtendableUriResolver(), + ] + ) + ) + return PolywrapClient( + ClientConfig( + resolver=resolver, + interfaces={ + ExtendableUriResolver.DEFAULT_EXT_INTERFACE_URIS[0]: [ + MockSubinvokePluginResolver.URI + ] + }, + ) + ) + + + +def test_shows_error_with_plugin_extension_subinvoke(client: PolywrapClient) -> None: + resolution_context = UriResolutionContext() + source_uri = Uri.from_str("test/error") + + with pytest.raises(UriResolverExtensionError) as excinfo: + client.try_resolve_uri(uri=source_uri, resolution_context=resolution_context) + + assert ( + excinfo.value.args[0] + == f"Failed to resolve uri: {source_uri}, using extension resolver: ({MockSubinvokePluginResolver.URI})" + ) diff --git a/packages/polywrap-uri-resolvers/tests/integration/extension_resolver/test_use_wasm_fs_resolver.py b/packages/polywrap-uri-resolvers/tests/integration/extension_resolver/test_use_wasm_fs_resolver.py new file mode 100644 index 00000000..923b7e1d --- /dev/null +++ b/packages/polywrap-uri-resolvers/tests/integration/extension_resolver/test_use_wasm_fs_resolver.py @@ -0,0 +1,60 @@ +import os +from polywrap_client import PolywrapClient +from polywrap_core import ( + ClientConfig, + Uri, + UriResolutionContext, + build_clean_uri_history, +) +from polywrap_uri_resolvers import ( + ExtendableUriResolver, + RecursiveResolver, + UriResolverAggregator, + PackageResolver, +) +from polywrap_test_cases import get_path_to_test_wrappers +import pytest + +from .mocker import mock_fs_wasm_package_resolver + + +@pytest.fixture +def client() -> PolywrapClient: + uri_package = mock_fs_wasm_package_resolver() + resolver = RecursiveResolver( + UriResolverAggregator( + [ + PackageResolver( + uri_package.uri, + uri_package.package, + ), + ExtendableUriResolver(), + ] + ) + ) + return PolywrapClient( + ClientConfig( + resolver=resolver, + interfaces={ + ExtendableUriResolver.DEFAULT_EXT_INTERFACE_URIS[0]: [uri_package.uri] + }, + ) + ) + + +def test_can_use_wasm_fs_resolver(client: PolywrapClient) -> None: + resolution_context = UriResolutionContext() + source_uri = Uri( + "fs", + os.path.join(get_path_to_test_wrappers(), "asyncify", "implementations", "as"), + ) + + result = client.try_resolve_uri( + uri=source_uri, resolution_context=resolution_context + ) + + from .histories.can_use_wasm_fs_resolver import EXPECTED + assert build_clean_uri_history(resolution_context.get_history()) == EXPECTED + + # Note: real wasm fs resolver should returns a UriPackage, not a Uri. + assert isinstance(result, Uri), "Expected a Uri result." \ No newline at end of file diff --git a/packages/polywrap-uri-resolvers/tests/integration/package_resolver/__init__.py b/packages/polywrap-uri-resolvers/tests/integration/package_resolver/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/packages/polywrap-uri-resolvers/tests/integration/package_resolver/conftest.py b/packages/polywrap-uri-resolvers/tests/integration/package_resolver/conftest.py new file mode 100644 index 00000000..2c7c4342 --- /dev/null +++ b/packages/polywrap-uri-resolvers/tests/integration/package_resolver/conftest.py @@ -0,0 +1,14 @@ +import pytest +from polywrap_core import Uri, UriResolutionContext, ClientConfig +from polywrap_client import PolywrapClient +from polywrap_uri_resolvers import PackageResolver + +@pytest.fixture +def client() -> PolywrapClient: + resolver = PackageResolver(Uri.from_str("test/package"), NotImplemented) + return PolywrapClient(ClientConfig(resolver=resolver)) + +@pytest.fixture +def resolution_context() -> UriResolutionContext: + return UriResolutionContext() + diff --git a/packages/polywrap-uri-resolvers/tests/integration/package_resolver/histories/__init__.py b/packages/polywrap-uri-resolvers/tests/integration/package_resolver/histories/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/packages/polywrap-uri-resolvers/tests/integration/package_resolver/histories/not_resolve_package.py b/packages/polywrap-uri-resolvers/tests/integration/package_resolver/histories/not_resolve_package.py new file mode 100644 index 00000000..b68a6d8d --- /dev/null +++ b/packages/polywrap-uri-resolvers/tests/integration/package_resolver/histories/not_resolve_package.py @@ -0,0 +1,3 @@ +EXPECTED = [ + "wrap://test/not-a-match => Package (wrap://test/package)" +] diff --git a/packages/polywrap-uri-resolvers/tests/integration/package_resolver/histories/resolve_package.py b/packages/polywrap-uri-resolvers/tests/integration/package_resolver/histories/resolve_package.py new file mode 100644 index 00000000..dea27dbe --- /dev/null +++ b/packages/polywrap-uri-resolvers/tests/integration/package_resolver/histories/resolve_package.py @@ -0,0 +1,3 @@ +EXPECTED = [ + "wrap://test/package => Package (wrap://test/package) => package (wrap://test/package)" +] diff --git a/packages/polywrap-uri-resolvers/tests/integration/package_resolver/test_not_resolve_package.py b/packages/polywrap-uri-resolvers/tests/integration/package_resolver/test_not_resolve_package.py new file mode 100644 index 00000000..e3e66a52 --- /dev/null +++ b/packages/polywrap-uri-resolvers/tests/integration/package_resolver/test_not_resolve_package.py @@ -0,0 +1,14 @@ +from polywrap_core import Uri, UriResolutionContext, build_clean_uri_history +from polywrap_client import PolywrapClient + + +def test_not_resolve_package(client: PolywrapClient, resolution_context: UriResolutionContext) -> None: + uri = Uri.from_str("test/not-a-match") + + result = client.try_resolve_uri(uri=uri, resolution_context=resolution_context) + + from .histories.not_resolve_package import EXPECTED + assert build_clean_uri_history(resolution_context.get_history()) == EXPECTED + + assert isinstance(result, Uri), "Expected a Uri result." + assert result.uri == "wrap://test/not-a-match" diff --git a/packages/polywrap-uri-resolvers/tests/integration/package_resolver/test_resolve_package.py b/packages/polywrap-uri-resolvers/tests/integration/package_resolver/test_resolve_package.py new file mode 100644 index 00000000..7f3d7830 --- /dev/null +++ b/packages/polywrap-uri-resolvers/tests/integration/package_resolver/test_resolve_package.py @@ -0,0 +1,15 @@ +from polywrap_core import Uri, UriResolutionContext, UriPackage, build_clean_uri_history +from polywrap_client import PolywrapClient + + + +def test_resolve_package(client: PolywrapClient, resolution_context: UriResolutionContext) -> None: + uri = Uri.from_str("test/package") + + result = client.try_resolve_uri(uri=uri, resolution_context=resolution_context) + + from .histories.resolve_package import EXPECTED + assert build_clean_uri_history(resolution_context.get_history()) == EXPECTED + + assert isinstance(result, UriPackage), "Expected a UriPackage result." + assert result.uri.uri == "wrap://test/package" diff --git a/packages/polywrap-uri-resolvers/tests/integration/recursive_resolver/__init__.py b/packages/polywrap-uri-resolvers/tests/integration/recursive_resolver/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/packages/polywrap-uri-resolvers/tests/integration/recursive_resolver/conftest.py b/packages/polywrap-uri-resolvers/tests/integration/recursive_resolver/conftest.py new file mode 100644 index 00000000..a120a5c1 --- /dev/null +++ b/packages/polywrap-uri-resolvers/tests/integration/recursive_resolver/conftest.py @@ -0,0 +1,46 @@ +import pytest +from polywrap_core import ( + ClientConfig, + InvokerClient, + Uri, + UriPackageOrWrapper, + UriResolutionContext, + UriResolutionStep, +) +from polywrap_client import PolywrapClient +from polywrap_uri_resolvers import RecursiveResolver + + +class SimpleRedirectResolver: + def try_resolve_uri( + self, uri: Uri, client: InvokerClient, resolution_context: UriResolutionContext + ) -> UriPackageOrWrapper: + result: UriPackageOrWrapper + + if uri.uri == "wrap://test/1": + result = Uri.from_str("test/2") + elif uri.uri == "wrap://test/2": + result = Uri.from_str("test/3") + elif uri.uri == "wrap://test/3": + result = Uri.from_str("test/4") + else: + result = uri + + resolution_context.track_step( + UriResolutionStep( + source_uri=uri, result=result, description="SimpleRedirectResolver" + ) + ) + + return result + + +@pytest.fixture +def simple_redirect_resolver() -> SimpleRedirectResolver: + return SimpleRedirectResolver() + + +@pytest.fixture +def client(simple_redirect_resolver: SimpleRedirectResolver) -> PolywrapClient: + resolver = RecursiveResolver(simple_redirect_resolver) + return PolywrapClient(ClientConfig(resolver=resolver)) diff --git a/packages/polywrap-uri-resolvers/tests/integration/recursive_resolver/histories/__init__.py b/packages/polywrap-uri-resolvers/tests/integration/recursive_resolver/histories/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/packages/polywrap-uri-resolvers/tests/integration/recursive_resolver/histories/infinite_loop.py b/packages/polywrap-uri-resolvers/tests/integration/recursive_resolver/histories/infinite_loop.py new file mode 100644 index 00000000..20e7be22 --- /dev/null +++ b/packages/polywrap-uri-resolvers/tests/integration/recursive_resolver/histories/infinite_loop.py @@ -0,0 +1,5 @@ +EXPECTED = [ + "wrap://test/1 => InfiniteRedirectResolver => uri (wrap://test/2)", + "wrap://test/2 => InfiniteRedirectResolver => uri (wrap://test/3)", + "wrap://test/3 => InfiniteRedirectResolver => uri (wrap://test/1)", +] diff --git a/packages/polywrap-uri-resolvers/tests/integration/recursive_resolver/histories/no_resolve.py b/packages/polywrap-uri-resolvers/tests/integration/recursive_resolver/histories/no_resolve.py new file mode 100644 index 00000000..98e9f8e0 --- /dev/null +++ b/packages/polywrap-uri-resolvers/tests/integration/recursive_resolver/histories/no_resolve.py @@ -0,0 +1,3 @@ +EXPECTED = [ + "wrap://test/not-a-match => SimpleRedirectResolver" +] diff --git a/packages/polywrap-uri-resolvers/tests/integration/recursive_resolver/histories/recursive_resolve.py b/packages/polywrap-uri-resolvers/tests/integration/recursive_resolver/histories/recursive_resolve.py new file mode 100644 index 00000000..508d0957 --- /dev/null +++ b/packages/polywrap-uri-resolvers/tests/integration/recursive_resolver/histories/recursive_resolve.py @@ -0,0 +1,6 @@ +EXPECTED = [ + "wrap://test/1 => SimpleRedirectResolver => uri (wrap://test/2)", + "wrap://test/2 => SimpleRedirectResolver => uri (wrap://test/3)", + "wrap://test/3 => SimpleRedirectResolver => uri (wrap://test/4)", + "wrap://test/4 => SimpleRedirectResolver" +] diff --git a/packages/polywrap-uri-resolvers/tests/integration/recursive_resolver/test_infinite_loop.py b/packages/polywrap-uri-resolvers/tests/integration/recursive_resolver/test_infinite_loop.py new file mode 100644 index 00000000..51041075 --- /dev/null +++ b/packages/polywrap-uri-resolvers/tests/integration/recursive_resolver/test_infinite_loop.py @@ -0,0 +1,58 @@ +import pytest +from polywrap_core import ( + ClientConfig, + InvokerClient, + Uri, + UriPackageOrWrapper, + UriResolutionContext, + UriResolutionStep, + build_clean_uri_history, +) +from polywrap_client import PolywrapClient +from polywrap_uri_resolvers import RecursiveResolver, InfiniteLoopError + + +class InfiniteRedirectResolver: + def try_resolve_uri( + self, uri: Uri, client: InvokerClient, resolution_context: UriResolutionContext + ) -> UriPackageOrWrapper: + result: UriPackageOrWrapper + + if uri.uri == "wrap://test/1": + result = Uri.from_str("test/2") + elif uri.uri == "wrap://test/2": + result = Uri.from_str("test/3") + elif uri.uri == "wrap://test/3": + result = Uri.from_str("test/1") + else: + result = uri + + resolution_context.track_step( + UriResolutionStep( + source_uri=uri, result=result, description="InfiniteRedirectResolver" + ) + ) + + return result + + +@pytest.fixture +def infinite_redirect_resolver() -> InfiniteRedirectResolver: + return InfiniteRedirectResolver() + + +@pytest.fixture +def client(infinite_redirect_resolver: InfiniteRedirectResolver) -> PolywrapClient: + resolver = RecursiveResolver(infinite_redirect_resolver) + return PolywrapClient(ClientConfig(resolver=resolver)) + + +def test_infinite_loop(client: PolywrapClient): + uri = Uri.from_str("test/1") + resolution_context = UriResolutionContext() + + with pytest.raises(InfiniteLoopError) as excinfo: + client.try_resolve_uri(uri=uri, resolution_context=resolution_context) + from .histories.infinite_loop import EXPECTED + assert excinfo.value.uri == uri + assert build_clean_uri_history(resolution_context.get_history()) == EXPECTED diff --git a/packages/polywrap-uri-resolvers/tests/integration/recursive_resolver/test_not_resolve.py b/packages/polywrap-uri-resolvers/tests/integration/recursive_resolver/test_not_resolve.py new file mode 100644 index 00000000..ab503464 --- /dev/null +++ b/packages/polywrap-uri-resolvers/tests/integration/recursive_resolver/test_not_resolve.py @@ -0,0 +1,20 @@ +from polywrap_core import ( + Uri, + UriResolutionContext, + build_clean_uri_history +) +from polywrap_client import PolywrapClient + + +def test_not_resolve_uri(client: PolywrapClient) -> None: + uri = Uri.from_str("test/not-a-match") + + resolution_context = UriResolutionContext() + result = client.try_resolve_uri(uri=uri, resolution_context=resolution_context) + + + from .histories.no_resolve import EXPECTED + assert build_clean_uri_history(resolution_context.get_history()) == EXPECTED + + assert isinstance(result, Uri), "Expected a Uri result." + assert result.uri == "wrap://test/not-a-match" diff --git a/packages/polywrap-uri-resolvers/tests/integration/recursive_resolver/test_recursive_resolve.py b/packages/polywrap-uri-resolvers/tests/integration/recursive_resolver/test_recursive_resolve.py new file mode 100644 index 00000000..cf2fe82a --- /dev/null +++ b/packages/polywrap-uri-resolvers/tests/integration/recursive_resolver/test_recursive_resolve.py @@ -0,0 +1,19 @@ +from polywrap_core import ( + Uri, + UriResolutionContext, + build_clean_uri_history +) +from polywrap_client import PolywrapClient + + +def test_recursive_resolve_uri(client: PolywrapClient) -> None: + uri = Uri.from_str("test/1") + + resolution_context = UriResolutionContext() + result = client.try_resolve_uri(uri=uri, resolution_context=resolution_context) + + from .histories.recursive_resolve import EXPECTED + assert build_clean_uri_history(resolution_context.get_history()) == EXPECTED + + assert isinstance(result, Uri), "Expected a Uri result." + assert result.uri == "wrap://test/4" diff --git a/packages/polywrap-uri-resolvers/tests/integration/redirect_resolver/__init__.py b/packages/polywrap-uri-resolvers/tests/integration/redirect_resolver/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/packages/polywrap-uri-resolvers/tests/integration/redirect_resolver/conftest.py b/packages/polywrap-uri-resolvers/tests/integration/redirect_resolver/conftest.py new file mode 100644 index 00000000..12650fad --- /dev/null +++ b/packages/polywrap-uri-resolvers/tests/integration/redirect_resolver/conftest.py @@ -0,0 +1,14 @@ +import pytest +from polywrap_core import Uri, UriResolutionContext, ClientConfig +from polywrap_client import PolywrapClient +from polywrap_uri_resolvers import RedirectResolver + +@pytest.fixture +def client() -> PolywrapClient: + resolver = RedirectResolver(Uri.from_str("test/from"), Uri.from_str("test/to")) + return PolywrapClient(ClientConfig(resolver=resolver)) + +@pytest.fixture +def resolution_context() -> UriResolutionContext: + return UriResolutionContext() + diff --git a/packages/polywrap-uri-resolvers/tests/integration/redirect_resolver/histories/__init__.py b/packages/polywrap-uri-resolvers/tests/integration/redirect_resolver/histories/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/packages/polywrap-uri-resolvers/tests/integration/redirect_resolver/histories/can_redirect.py b/packages/polywrap-uri-resolvers/tests/integration/redirect_resolver/histories/can_redirect.py new file mode 100644 index 00000000..1628caf8 --- /dev/null +++ b/packages/polywrap-uri-resolvers/tests/integration/redirect_resolver/histories/can_redirect.py @@ -0,0 +1,3 @@ +EXPECTED = [ + "wrap://test/from => Redirect (wrap://test/from - wrap://test/to) => uri (wrap://test/to)" +] diff --git a/packages/polywrap-uri-resolvers/tests/integration/redirect_resolver/histories/not_redirect.py b/packages/polywrap-uri-resolvers/tests/integration/redirect_resolver/histories/not_redirect.py new file mode 100644 index 00000000..583ef804 --- /dev/null +++ b/packages/polywrap-uri-resolvers/tests/integration/redirect_resolver/histories/not_redirect.py @@ -0,0 +1,3 @@ +EXPECTED = [ + "wrap://test/not-a-match => Redirect (wrap://test/from - wrap://test/to)" +] \ No newline at end of file diff --git a/packages/polywrap-uri-resolvers/tests/integration/redirect_resolver/test_can_redirect_uri.py b/packages/polywrap-uri-resolvers/tests/integration/redirect_resolver/test_can_redirect_uri.py new file mode 100644 index 00000000..c8af0058 --- /dev/null +++ b/packages/polywrap-uri-resolvers/tests/integration/redirect_resolver/test_can_redirect_uri.py @@ -0,0 +1,17 @@ +from polywrap_core import Uri, UriResolutionContext, build_clean_uri_history +from polywrap_client import PolywrapClient + + +def test_can_redirect_uri( + client: PolywrapClient, resolution_context: UriResolutionContext +) -> None: + uri = Uri.from_str("test/from") + + result = client.try_resolve_uri(uri=uri, resolution_context=resolution_context) + + from .histories.can_redirect import EXPECTED + + assert build_clean_uri_history(resolution_context.get_history()) == EXPECTED + + assert isinstance(result, Uri), "Expected a Uri result." + assert result.uri == "wrap://test/to" diff --git a/packages/polywrap-uri-resolvers/tests/integration/redirect_resolver/test_not_redirect_uri.py b/packages/polywrap-uri-resolvers/tests/integration/redirect_resolver/test_not_redirect_uri.py new file mode 100644 index 00000000..7a6fe0f9 --- /dev/null +++ b/packages/polywrap-uri-resolvers/tests/integration/redirect_resolver/test_not_redirect_uri.py @@ -0,0 +1,17 @@ +from polywrap_core import Uri, UriResolutionContext, UriPackage, build_clean_uri_history +from polywrap_client import PolywrapClient + + +def test_not_redirect_uri( + client: PolywrapClient, resolution_context: UriResolutionContext +) -> None: + uri = Uri.from_str("test/not-a-match") + + result = client.try_resolve_uri(uri=uri, resolution_context=resolution_context) + + from .histories.not_redirect import EXPECTED + + assert build_clean_uri_history(resolution_context.get_history()) == EXPECTED + + assert isinstance(result, Uri), "Expected a Uri result." + assert result.uri == "wrap://test/not-a-match" diff --git a/packages/polywrap-uri-resolvers/tests/integration/resolution_result_cache_resolver/__init__.py b/packages/polywrap-uri-resolvers/tests/integration/resolution_result_cache_resolver/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/packages/polywrap-uri-resolvers/tests/integration/resolution_result_cache_resolver/conftest.py b/packages/polywrap-uri-resolvers/tests/integration/resolution_result_cache_resolver/conftest.py new file mode 100644 index 00000000..1ceebe11 --- /dev/null +++ b/packages/polywrap-uri-resolvers/tests/integration/resolution_result_cache_resolver/conftest.py @@ -0,0 +1,65 @@ +import pytest +from polywrap_core import ( + ClientConfig, + InvokerClient, + Uri, + UriPackageOrWrapper, + UriResolutionContext, + UriResolutionStep, + UriWrapper, + UriPackage, +) +from polywrap_client import PolywrapClient +from polywrap_uri_resolvers import ( + RecursiveResolver, + ResolutionResultCacheResolver, + UriResolutionError, + UriResolver, + InMemoryResolutionResultCache, +) + + +class TestResolver(UriResolver): + def try_resolve_uri( + self, uri: Uri, client: InvokerClient, resolution_context: UriResolutionContext + ) -> UriPackageOrWrapper: + result: UriPackageOrWrapper + + if uri.uri == "wrap://test/package": + result = UriPackage(uri=uri, package=NotImplemented) + elif uri.uri == "wrap://test/wrapper": + result = UriWrapper(uri=uri, wrapper=NotImplemented) + elif uri.uri == "wrap://test/from": + result = Uri.from_str("test/to") + elif uri.uri == "wrap://test/A": + result = Uri.from_str("test/B") + elif uri.uri == "wrap://test/B": + result = Uri.from_str("test/wrapper") + elif uri.uri == "wrap://test/error": + raise UriResolutionError("A test error") + else: + raise UriResolutionError(f"Unexpected URI: {uri.uri}") + + resolution_context.track_step( + UriResolutionStep(source_uri=uri, result=result, description="TestResolver") + ) + + return result + + +@pytest.fixture +def client(): + resolver = ResolutionResultCacheResolver( + TestResolver(), cache=InMemoryResolutionResultCache() + ) + return PolywrapClient(ClientConfig(resolver=resolver)) + + +@pytest.fixture +def recursive_client(): + resolver = RecursiveResolver( + ResolutionResultCacheResolver( + TestResolver(), cache=InMemoryResolutionResultCache() + ) + ) + return PolywrapClient(ClientConfig(resolver=resolver)) diff --git a/packages/polywrap-uri-resolvers/tests/integration/resolution_result_cache_resolver/histories/__init__.py b/packages/polywrap-uri-resolvers/tests/integration/resolution_result_cache_resolver/histories/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/packages/polywrap-uri-resolvers/tests/integration/resolution_result_cache_resolver/histories/error_with_cache.py b/packages/polywrap-uri-resolvers/tests/integration/resolution_result_cache_resolver/histories/error_with_cache.py new file mode 100644 index 00000000..c9bcf5a3 --- /dev/null +++ b/packages/polywrap-uri-resolvers/tests/integration/resolution_result_cache_resolver/histories/error_with_cache.py @@ -0,0 +1,3 @@ +EXPECTED = [ + "wrap://test/error => ResolutionResultCacheResolver (Cache) => error (A test error)" +] diff --git a/packages/polywrap-uri-resolvers/tests/integration/resolution_result_cache_resolver/histories/error_without_cache.py b/packages/polywrap-uri-resolvers/tests/integration/resolution_result_cache_resolver/histories/error_without_cache.py new file mode 100644 index 00000000..e0fbe0f3 --- /dev/null +++ b/packages/polywrap-uri-resolvers/tests/integration/resolution_result_cache_resolver/histories/error_without_cache.py @@ -0,0 +1,4 @@ +EXPECTED = [ + "wrap://test/error => ResolutionResultCacheResolver => error (A test error)", + ["wrap://test/error => TestResolver => error (A test error)"] +] diff --git a/packages/polywrap-uri-resolvers/tests/integration/resolution_result_cache_resolver/histories/package_with_cache.py b/packages/polywrap-uri-resolvers/tests/integration/resolution_result_cache_resolver/histories/package_with_cache.py new file mode 100644 index 00000000..a44f4484 --- /dev/null +++ b/packages/polywrap-uri-resolvers/tests/integration/resolution_result_cache_resolver/histories/package_with_cache.py @@ -0,0 +1,3 @@ +EXPECTED = [ + "wrap://test/package => ResolutionResultCacheResolver (Cache) => package (wrap://test/package)" +] diff --git a/packages/polywrap-uri-resolvers/tests/integration/resolution_result_cache_resolver/histories/package_without_cache.py b/packages/polywrap-uri-resolvers/tests/integration/resolution_result_cache_resolver/histories/package_without_cache.py new file mode 100644 index 00000000..be244bd6 --- /dev/null +++ b/packages/polywrap-uri-resolvers/tests/integration/resolution_result_cache_resolver/histories/package_without_cache.py @@ -0,0 +1,6 @@ +EXPECTED = [ + "wrap://test/package => ResolutionResultCacheResolver => package (wrap://test/package)", + [ + "wrap://test/package => TestResolver => package (wrap://test/package)" + ] +] diff --git a/packages/polywrap-uri-resolvers/tests/integration/resolution_result_cache_resolver/histories/uri_with_cache.py b/packages/polywrap-uri-resolvers/tests/integration/resolution_result_cache_resolver/histories/uri_with_cache.py new file mode 100644 index 00000000..b0d4f0f4 --- /dev/null +++ b/packages/polywrap-uri-resolvers/tests/integration/resolution_result_cache_resolver/histories/uri_with_cache.py @@ -0,0 +1 @@ +EXPECTED = ["wrap://test/from => ResolutionResultCacheResolver (Cache) => uri (wrap://test/to)"] diff --git a/packages/polywrap-uri-resolvers/tests/integration/resolution_result_cache_resolver/histories/uri_without_cache.py b/packages/polywrap-uri-resolvers/tests/integration/resolution_result_cache_resolver/histories/uri_without_cache.py new file mode 100644 index 00000000..a7c38388 --- /dev/null +++ b/packages/polywrap-uri-resolvers/tests/integration/resolution_result_cache_resolver/histories/uri_without_cache.py @@ -0,0 +1,6 @@ +EXPECTED = [ + "wrap://test/from => ResolutionResultCacheResolver => uri (wrap://test/to)", + [ + "wrap://test/from => TestResolver => uri (wrap://test/to)" + ] +] diff --git a/packages/polywrap-uri-resolvers/tests/integration/resolution_result_cache_resolver/histories/wrapper_with_cache.py b/packages/polywrap-uri-resolvers/tests/integration/resolution_result_cache_resolver/histories/wrapper_with_cache.py new file mode 100644 index 00000000..39792f38 --- /dev/null +++ b/packages/polywrap-uri-resolvers/tests/integration/resolution_result_cache_resolver/histories/wrapper_with_cache.py @@ -0,0 +1,3 @@ +EXPECTED = [ + "wrap://test/wrapper => ResolutionResultCacheResolver (Cache) => wrapper (wrap://test/wrapper)" +] diff --git a/packages/polywrap-uri-resolvers/tests/integration/resolution_result_cache_resolver/histories/wrapper_without_cache.py b/packages/polywrap-uri-resolvers/tests/integration/resolution_result_cache_resolver/histories/wrapper_without_cache.py new file mode 100644 index 00000000..700f278c --- /dev/null +++ b/packages/polywrap-uri-resolvers/tests/integration/resolution_result_cache_resolver/histories/wrapper_without_cache.py @@ -0,0 +1,4 @@ +EXPECTED = [ + "wrap://test/wrapper => ResolutionResultCacheResolver => wrapper (wrap://test/wrapper)", + ["wrap://test/wrapper => TestResolver => wrapper (wrap://test/wrapper)"] +] diff --git a/packages/polywrap-uri-resolvers/tests/integration/resolution_result_cache_resolver/test_cached_error.py b/packages/polywrap-uri-resolvers/tests/integration/resolution_result_cache_resolver/test_cached_error.py new file mode 100644 index 00000000..a6ab5a9d --- /dev/null +++ b/packages/polywrap-uri-resolvers/tests/integration/resolution_result_cache_resolver/test_cached_error.py @@ -0,0 +1,31 @@ +from polywrap_core import ( + Uri, + UriResolutionContext, +) +from polywrap_client import PolywrapClient +from polywrap_uri_resolvers import UriResolutionError +import pytest + + +def test_cached_error(client: PolywrapClient): + client._config.resolver.cache_errors = True # type: ignore + + resolution_context = UriResolutionContext() + with pytest.raises(UriResolutionError) as exc_info_1: + client.try_resolve_uri( + uri=Uri.from_str("test/error"), resolution_context=resolution_context + ) + + assert exc_info_1.value.__class__.__name__ == "UriResolutionError" + assert exc_info_1.value.args[0] == "A test error" + + resolution_context = UriResolutionContext() + with pytest.raises(UriResolutionError) as exc_info_2: + client.try_resolve_uri( + uri=Uri.from_str("test/error"), resolution_context=resolution_context + ) + + assert exc_info_2.value.__class__.__name__ == "UriResolutionError" + assert exc_info_2.value.args[0] == "A test error" + + assert exc_info_1.value is exc_info_2.value diff --git a/packages/polywrap-uri-resolvers/tests/integration/resolution_result_cache_resolver/test_cached_package.py b/packages/polywrap-uri-resolvers/tests/integration/resolution_result_cache_resolver/test_cached_package.py new file mode 100644 index 00000000..92189d84 --- /dev/null +++ b/packages/polywrap-uri-resolvers/tests/integration/resolution_result_cache_resolver/test_cached_package.py @@ -0,0 +1,29 @@ +from polywrap_core import ( + Uri, + UriResolutionContext, + UriPackage, + build_clean_uri_history, +) +from polywrap_client import PolywrapClient + + +def test_cached_package(client: PolywrapClient): + uri = Uri.from_str("test/package") + + resolution_context = UriResolutionContext() + result = client.try_resolve_uri(uri=uri, resolution_context=resolution_context) + + from .histories.package_without_cache import EXPECTED + assert build_clean_uri_history(resolution_context.get_history()) == EXPECTED + + assert isinstance(result, UriPackage), "Expected a UriPackage result." + assert result.uri.uri == "wrap://test/package" + + resolution_context = UriResolutionContext() + result = client.try_resolve_uri(uri=uri, resolution_context=resolution_context) + + from .histories.package_with_cache import EXPECTED + assert build_clean_uri_history(resolution_context.get_history()) == EXPECTED + + assert isinstance(result, UriPackage), "Expected a UriPackage result." + assert result.uri.uri == "wrap://test/package" diff --git a/packages/polywrap-uri-resolvers/tests/integration/resolution_result_cache_resolver/test_cached_uri.py b/packages/polywrap-uri-resolvers/tests/integration/resolution_result_cache_resolver/test_cached_uri.py new file mode 100644 index 00000000..7bc9fddb --- /dev/null +++ b/packages/polywrap-uri-resolvers/tests/integration/resolution_result_cache_resolver/test_cached_uri.py @@ -0,0 +1,30 @@ +from polywrap_core import ( + Uri, + UriResolutionContext, + build_clean_uri_history, +) +from polywrap_client import PolywrapClient + + +def test_cached_uri(client: PolywrapClient): + uri = Uri.from_str("test/from") + + resolution_context = UriResolutionContext() + result = client.try_resolve_uri(uri=uri, resolution_context=resolution_context) + + from .histories.uri_without_cache import EXPECTED + + assert build_clean_uri_history(resolution_context.get_history()) == EXPECTED + + assert isinstance(result, Uri), "Expected a Uri result." + assert result.uri == "wrap://test/to" + + resolution_context = UriResolutionContext() + result = client.try_resolve_uri(uri=uri, resolution_context=resolution_context) + + from .histories.uri_with_cache import EXPECTED + + assert build_clean_uri_history(resolution_context.get_history()) == EXPECTED + + assert isinstance(result, Uri), "Expected a Uri result." + assert result.uri == "wrap://test/to" diff --git a/packages/polywrap-uri-resolvers/tests/integration/resolution_result_cache_resolver/test_cached_wrapper.py b/packages/polywrap-uri-resolvers/tests/integration/resolution_result_cache_resolver/test_cached_wrapper.py new file mode 100644 index 00000000..150e8d5c --- /dev/null +++ b/packages/polywrap-uri-resolvers/tests/integration/resolution_result_cache_resolver/test_cached_wrapper.py @@ -0,0 +1,29 @@ +from polywrap_core import ( + Uri, + UriResolutionContext, + UriWrapper, + build_clean_uri_history, +) +from polywrap_client import PolywrapClient + + +def test_cached_wrapper(client: PolywrapClient): + uri = Uri.from_str("test/wrapper") + + resolution_context = UriResolutionContext() + result = client.try_resolve_uri(uri=uri, resolution_context=resolution_context) + + from .histories.wrapper_without_cache import EXPECTED + assert build_clean_uri_history(resolution_context.get_history()) == EXPECTED + + assert isinstance(result, UriWrapper), "Expected a UriWrapper result." + assert result.uri.uri == "wrap://test/wrapper" + + resolution_context = UriResolutionContext() + result = client.try_resolve_uri(uri=uri, resolution_context=resolution_context) + + from .histories.wrapper_with_cache import EXPECTED + assert build_clean_uri_history(resolution_context.get_history()) == EXPECTED + + assert isinstance(result, UriWrapper), "Expected a UriWrapper result." + assert result.uri.uri == "wrap://test/wrapper" diff --git a/packages/polywrap-uri-resolvers/tests/integration/resolution_result_cache_resolver/test_not_cached_error.py b/packages/polywrap-uri-resolvers/tests/integration/resolution_result_cache_resolver/test_not_cached_error.py new file mode 100644 index 00000000..93b8341b --- /dev/null +++ b/packages/polywrap-uri-resolvers/tests/integration/resolution_result_cache_resolver/test_not_cached_error.py @@ -0,0 +1,29 @@ +from polywrap_core import ( + Uri, + UriResolutionContext, +) +from polywrap_client import PolywrapClient +from polywrap_uri_resolvers import UriResolutionError +import pytest + + +def test_not_cached_error(client: PolywrapClient): + resolution_context = UriResolutionContext() + with pytest.raises(UriResolutionError) as exc_info_1: + client.try_resolve_uri( + uri=Uri.from_str("test/error"), resolution_context=resolution_context + ) + + assert exc_info_1.value.__class__.__name__ == "UriResolutionError" + assert exc_info_1.value.args[0] == "A test error" + + resolution_context = UriResolutionContext() + with pytest.raises(UriResolutionError) as exc_info_2: + client.try_resolve_uri( + uri=Uri.from_str("test/error"), resolution_context=resolution_context + ) + + assert exc_info_2.value.__class__.__name__ == "UriResolutionError" + assert exc_info_2.value.args[0] == "A test error" + + assert exc_info_1.value is not exc_info_2.value diff --git a/packages/polywrap-uri-resolvers/tests/integration/resolution_result_cache_resolver/test_resolution_path.py b/packages/polywrap-uri-resolvers/tests/integration/resolution_result_cache_resolver/test_resolution_path.py new file mode 100644 index 00000000..a90bbcf5 --- /dev/null +++ b/packages/polywrap-uri-resolvers/tests/integration/resolution_result_cache_resolver/test_resolution_path.py @@ -0,0 +1,23 @@ +from polywrap_client import PolywrapClient +from polywrap_core import Uri, UriResolutionContext + + +def test_same_resolution_path_after_caching(recursive_client: PolywrapClient): + uri = Uri.from_str("test/A") + expected_path = [ + Uri.from_str("wrap://test/A"), + Uri.from_str("wrap://test/B"), + Uri.from_str("wrap://test/wrapper"), + ] + + resolution_context = UriResolutionContext() + recursive_client.try_resolve_uri(uri=uri, resolution_context=resolution_context) + + resolution_path = resolution_context.get_resolution_path() + assert resolution_path == expected_path + + resolution_context = UriResolutionContext() + recursive_client.try_resolve_uri(uri=uri, resolution_context=resolution_context) + + resolution_path = resolution_context.get_resolution_path() + assert resolution_path == expected_path diff --git a/packages/polywrap-uri-resolvers/tests/integration/static_resolver/__init__.py b/packages/polywrap-uri-resolvers/tests/integration/static_resolver/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/packages/polywrap-uri-resolvers/tests/integration/static_resolver/conftest.py b/packages/polywrap-uri-resolvers/tests/integration/static_resolver/conftest.py new file mode 100644 index 00000000..23559a3d --- /dev/null +++ b/packages/polywrap-uri-resolvers/tests/integration/static_resolver/conftest.py @@ -0,0 +1,31 @@ +import pytest +from polywrap_core import ( + Uri, + UriPackage, + UriResolutionContext, + ClientConfig, + UriWrapper, +) +from polywrap_client import PolywrapClient +from polywrap_uri_resolvers import StaticResolver + + +@pytest.fixture +def client() -> PolywrapClient: + resolver = StaticResolver( + { + Uri.from_str("test/from"): Uri.from_str("test/to"), + Uri.from_str("test/package"): UriPackage( + uri=Uri.from_str("test/package"), package=NotImplemented + ), + Uri.from_str("test/wrapper"): UriWrapper( + uri=Uri.from_str("test/wrapper"), wrapper=NotImplemented + ), + } + ) + return PolywrapClient(ClientConfig(resolver=resolver)) + + +@pytest.fixture +def resolution_context() -> UriResolutionContext: + return UriResolutionContext() diff --git a/packages/polywrap-uri-resolvers/tests/integration/static_resolver/histories/__init__.py b/packages/polywrap-uri-resolvers/tests/integration/static_resolver/histories/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/packages/polywrap-uri-resolvers/tests/integration/static_resolver/histories/can_redirect.py b/packages/polywrap-uri-resolvers/tests/integration/static_resolver/histories/can_redirect.py new file mode 100644 index 00000000..2b61d564 --- /dev/null +++ b/packages/polywrap-uri-resolvers/tests/integration/static_resolver/histories/can_redirect.py @@ -0,0 +1,3 @@ +EXPECTED = [ + "wrap://test/from => Static - Redirect (wrap://test/from - wrap://test/to) => uri (wrap://test/to)" +] diff --git a/packages/polywrap-uri-resolvers/tests/integration/static_resolver/histories/can_resolve_package.py b/packages/polywrap-uri-resolvers/tests/integration/static_resolver/histories/can_resolve_package.py new file mode 100644 index 00000000..5502638a --- /dev/null +++ b/packages/polywrap-uri-resolvers/tests/integration/static_resolver/histories/can_resolve_package.py @@ -0,0 +1,3 @@ +EXPECTED = [ + "wrap://test/package => Static - Package => package (wrap://test/package)" +] diff --git a/packages/polywrap-uri-resolvers/tests/integration/static_resolver/histories/can_resolve_wrapper.py b/packages/polywrap-uri-resolvers/tests/integration/static_resolver/histories/can_resolve_wrapper.py new file mode 100644 index 00000000..29e09e5e --- /dev/null +++ b/packages/polywrap-uri-resolvers/tests/integration/static_resolver/histories/can_resolve_wrapper.py @@ -0,0 +1,3 @@ +EXPECTED = [ + "wrap://test/wrapper => Static - Wrapper => wrapper (wrap://test/wrapper)" +] diff --git a/packages/polywrap-uri-resolvers/tests/integration/static_resolver/histories/not_resolve.py b/packages/polywrap-uri-resolvers/tests/integration/static_resolver/histories/not_resolve.py new file mode 100644 index 00000000..17635786 --- /dev/null +++ b/packages/polywrap-uri-resolvers/tests/integration/static_resolver/histories/not_resolve.py @@ -0,0 +1,3 @@ +EXPECTED = [ + "wrap://test/no-match => Static - Miss" +] diff --git a/packages/polywrap-uri-resolvers/tests/integration/static_resolver/test_can_redirect.py b/packages/polywrap-uri-resolvers/tests/integration/static_resolver/test_can_redirect.py new file mode 100644 index 00000000..c8af0058 --- /dev/null +++ b/packages/polywrap-uri-resolvers/tests/integration/static_resolver/test_can_redirect.py @@ -0,0 +1,17 @@ +from polywrap_core import Uri, UriResolutionContext, build_clean_uri_history +from polywrap_client import PolywrapClient + + +def test_can_redirect_uri( + client: PolywrapClient, resolution_context: UriResolutionContext +) -> None: + uri = Uri.from_str("test/from") + + result = client.try_resolve_uri(uri=uri, resolution_context=resolution_context) + + from .histories.can_redirect import EXPECTED + + assert build_clean_uri_history(resolution_context.get_history()) == EXPECTED + + assert isinstance(result, Uri), "Expected a Uri result." + assert result.uri == "wrap://test/to" diff --git a/packages/polywrap-uri-resolvers/tests/integration/static_resolver/test_can_resolve_package.py b/packages/polywrap-uri-resolvers/tests/integration/static_resolver/test_can_resolve_package.py new file mode 100644 index 00000000..e7b885bb --- /dev/null +++ b/packages/polywrap-uri-resolvers/tests/integration/static_resolver/test_can_resolve_package.py @@ -0,0 +1,15 @@ +from polywrap_core import Uri, UriResolutionContext, UriPackage, build_clean_uri_history +from polywrap_client import PolywrapClient + + + +def test_resolve_package(client: PolywrapClient, resolution_context: UriResolutionContext) -> None: + uri = Uri.from_str("test/package") + + result = client.try_resolve_uri(uri=uri, resolution_context=resolution_context) + + from .histories.can_resolve_package import EXPECTED + assert build_clean_uri_history(resolution_context.get_history()) == EXPECTED + + assert isinstance(result, UriPackage), "Expected a UriPackage result." + assert result.uri.uri == "wrap://test/package" diff --git a/packages/polywrap-uri-resolvers/tests/integration/static_resolver/test_can_resolve_wrapper.py b/packages/polywrap-uri-resolvers/tests/integration/static_resolver/test_can_resolve_wrapper.py new file mode 100644 index 00000000..803cfd5a --- /dev/null +++ b/packages/polywrap-uri-resolvers/tests/integration/static_resolver/test_can_resolve_wrapper.py @@ -0,0 +1,14 @@ +from polywrap_core import Uri, UriResolutionContext, UriWrapper, build_clean_uri_history +from polywrap_client import PolywrapClient + + +def test_resolve_wrapper(client: PolywrapClient, resolution_context: UriResolutionContext) -> None: + uri = Uri.from_str("test/wrapper") + + result = client.try_resolve_uri(uri=uri, resolution_context=resolution_context) + + from .histories.can_resolve_wrapper import EXPECTED + assert build_clean_uri_history(resolution_context.get_history()) == EXPECTED + + assert isinstance(result, UriWrapper), "Expected a UriWrapper result." + assert result.uri.uri == "wrap://test/wrapper" diff --git a/packages/polywrap-uri-resolvers/tests/integration/static_resolver/test_not_resolve.py b/packages/polywrap-uri-resolvers/tests/integration/static_resolver/test_not_resolve.py new file mode 100644 index 00000000..4e9ff210 --- /dev/null +++ b/packages/polywrap-uri-resolvers/tests/integration/static_resolver/test_not_resolve.py @@ -0,0 +1,15 @@ +from polywrap_core import Uri, UriResolutionContext, build_clean_uri_history +from polywrap_client import PolywrapClient + + +def test_no_match(client: PolywrapClient, resolution_context: UriResolutionContext) -> None: + uri = Uri.from_str("test/no-match") + + result = client.try_resolve_uri(uri=uri, resolution_context=resolution_context) + + from .histories.not_resolve import EXPECTED + assert build_clean_uri_history(resolution_context.get_history()) == EXPECTED + + assert isinstance(result, Uri), "Expected a Uri result." + assert result.uri == "wrap://test/no-match" + diff --git a/packages/polywrap-uri-resolvers/tests/integration/wrapper_resolver/__init__.py b/packages/polywrap-uri-resolvers/tests/integration/wrapper_resolver/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/packages/polywrap-uri-resolvers/tests/integration/wrapper_resolver/conftest.py b/packages/polywrap-uri-resolvers/tests/integration/wrapper_resolver/conftest.py new file mode 100644 index 00000000..2e17944f --- /dev/null +++ b/packages/polywrap-uri-resolvers/tests/integration/wrapper_resolver/conftest.py @@ -0,0 +1,14 @@ +import pytest +from polywrap_core import Uri, UriResolutionContext, ClientConfig +from polywrap_client import PolywrapClient +from polywrap_uri_resolvers import WrapperResolver + +@pytest.fixture +def client() -> PolywrapClient: + resolver = WrapperResolver(Uri.from_str("test/wrapper"), NotImplemented) + return PolywrapClient(ClientConfig(resolver=resolver)) + +@pytest.fixture +def resolution_context() -> UriResolutionContext: + return UriResolutionContext() + diff --git a/packages/polywrap-uri-resolvers/tests/integration/wrapper_resolver/histories/__init__.py b/packages/polywrap-uri-resolvers/tests/integration/wrapper_resolver/histories/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/packages/polywrap-uri-resolvers/tests/integration/wrapper_resolver/histories/not_resolve_wrapper.py b/packages/polywrap-uri-resolvers/tests/integration/wrapper_resolver/histories/not_resolve_wrapper.py new file mode 100644 index 00000000..2c53be78 --- /dev/null +++ b/packages/polywrap-uri-resolvers/tests/integration/wrapper_resolver/histories/not_resolve_wrapper.py @@ -0,0 +1,3 @@ +EXPECTED = [ + "wrap://test/not-a-match => Wrapper (wrap://test/wrapper)" +] diff --git a/packages/polywrap-uri-resolvers/tests/integration/wrapper_resolver/histories/resolve_wrapper.py b/packages/polywrap-uri-resolvers/tests/integration/wrapper_resolver/histories/resolve_wrapper.py new file mode 100644 index 00000000..a46b9cda --- /dev/null +++ b/packages/polywrap-uri-resolvers/tests/integration/wrapper_resolver/histories/resolve_wrapper.py @@ -0,0 +1,3 @@ +EXPECTED = [ + "wrap://test/wrapper => Wrapper (wrap://test/wrapper) => wrapper (wrap://test/wrapper)" +] diff --git a/packages/polywrap-uri-resolvers/tests/integration/wrapper_resolver/test_not_resolve_wrapper.py b/packages/polywrap-uri-resolvers/tests/integration/wrapper_resolver/test_not_resolve_wrapper.py new file mode 100644 index 00000000..fcebe6af --- /dev/null +++ b/packages/polywrap-uri-resolvers/tests/integration/wrapper_resolver/test_not_resolve_wrapper.py @@ -0,0 +1,17 @@ +from polywrap_core import Uri, UriResolutionContext, build_clean_uri_history +from polywrap_client import PolywrapClient + + +def test_not_resolve_wrapper( + client: PolywrapClient, resolution_context: UriResolutionContext +) -> None: + uri = Uri.from_str("test/not-a-match") + + result = client.try_resolve_uri(uri=uri, resolution_context=resolution_context) + + from .histories.not_resolve_wrapper import EXPECTED + + assert build_clean_uri_history(resolution_context.get_history()) == EXPECTED + + assert isinstance(result, Uri), "Expected a Uri result." + assert result.uri == "wrap://test/not-a-match" diff --git a/packages/polywrap-uri-resolvers/tests/integration/wrapper_resolver/test_resolve_wrapper.py b/packages/polywrap-uri-resolvers/tests/integration/wrapper_resolver/test_resolve_wrapper.py new file mode 100644 index 00000000..fbdb4a48 --- /dev/null +++ b/packages/polywrap-uri-resolvers/tests/integration/wrapper_resolver/test_resolve_wrapper.py @@ -0,0 +1,14 @@ +from polywrap_core import Uri, UriResolutionContext, UriWrapper, build_clean_uri_history +from polywrap_client import PolywrapClient + + +def test_resolve_wrapper(client: PolywrapClient, resolution_context: UriResolutionContext) -> None: + uri = Uri.from_str("test/wrapper") + + result = client.try_resolve_uri(uri=uri, resolution_context=resolution_context) + + from .histories.resolve_wrapper import EXPECTED + assert build_clean_uri_history(resolution_context.get_history()) == EXPECTED + + assert isinstance(result, UriWrapper), "Expected a UriWrapper result." + assert result.uri.uri == "wrap://test/wrapper" diff --git a/packages/polywrap-uri-resolvers/tests/test_static_resolver.py b/packages/polywrap-uri-resolvers/tests/test_static_resolver.py deleted file mode 100644 index 2ddeae58..00000000 --- a/packages/polywrap-uri-resolvers/tests/test_static_resolver.py +++ /dev/null @@ -1,70 +0,0 @@ -# import pytest -# from pathlib import Path - -# from polywrap_result import Ok, Err, Result -# from polywrap_wasm import WRAP_MANIFEST_PATH, WRAP_MODULE_PATH, IFileReader, WasmPackage, WasmWrapper -# from polywrap_core import UriPackage, Uri, UriResolutionContext, UriWrapper, IWrapPackage -# from polywrap_client import PolywrapClient -# from polywrap_uri_resolvers import StaticResolver -# from polywrap_manifest import deserialize_wrap_manifest - - -# @pytest.fixture -# def simple_wrap_module(): -# wrap_path = Path(__file__).parent / "cases" / "simple" / "wrap.wasm" -# with open(wrap_path, "rb") as f: -# yield f.read() - - -# @pytest.fixture -# def simple_wrap_manifest(): -# wrap_path = Path(__file__).parent / "cases" / "simple" / "wrap.info" -# with open(wrap_path, "rb") as f: -# yield f.read() - -# @pytest.fixture -# def simple_file_reader(simple_wrap_module: bytes, simple_wrap_manifest: bytes): -# class FileReader(IFileReader): -# async def read_file(self, file_path: str) -> Result[bytes]: -# if file_path == WRAP_MODULE_PATH: -# return Ok(simple_wrap_module) -# if file_path == WRAP_MANIFEST_PATH: -# return Ok(simple_wrap_manifest) -# return Err.from_str(f"FileNotFound: {file_path}") - -# yield FileReader() - -# @pytest.mark.asyncio -# async def test_static_resolver( -# simple_file_reader: IFileReader, -# simple_wrap_module: bytes, -# simple_wrap_manifest: bytes -# ): -# package = WasmPackage(simple_file_reader) - -# manifest = deserialize_wrap_manifest(simple_wrap_manifest).unwrap() -# wrapper = WasmWrapper(simple_file_reader, simple_wrap_module, manifest) - -# uri_wrapper = UriWrapper(uri=Uri("ens/wrapper.eth"), wrapper=wrapper) -# uri_package = UriPackage(uri=Uri("ens/package.eth"), package=package) - -# resolver = StaticResolver.from_list([ uri_package, uri_wrapper, [ -# UriPackage(uri=Uri("ens/nested-package.eth"), package=package) -# ]]).unwrap() - -# resolution_context = UriResolutionContext() -# result = await resolver.try_resolve_uri(Uri("ens/package.eth"), PolywrapClient(), resolution_context) - -# assert result.is_ok -# assert isinstance((result.unwrap()).package, IWrapPackage) - -# result = await resolver.try_resolve_uri(Uri("ens/wrapper.eth"), PolywrapClient(), resolution_context) - -# assert result.is_ok -# assert isinstance((result.unwrap()).wrapper, WasmWrapper) - -# result = await resolver.try_resolve_uri(Uri("ens/nested-package.eth"), PolywrapClient(), resolution_context) - -# assert result.is_ok -# assert isinstance((result.unwrap()).package, IWrapPackage) - diff --git a/packages/polywrap-uri-resolvers/tests/unit/__init__.py b/packages/polywrap-uri-resolvers/tests/unit/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/packages/polywrap-uri-resolvers/tests/cases/simple/wrap.info b/packages/polywrap-uri-resolvers/tests/unit/cases/simple/wrap.info similarity index 100% rename from packages/polywrap-uri-resolvers/tests/cases/simple/wrap.info rename to packages/polywrap-uri-resolvers/tests/unit/cases/simple/wrap.info diff --git a/packages/polywrap-uri-resolvers/tests/cases/simple/wrap.wasm b/packages/polywrap-uri-resolvers/tests/unit/cases/simple/wrap.wasm similarity index 100% rename from packages/polywrap-uri-resolvers/tests/cases/simple/wrap.wasm rename to packages/polywrap-uri-resolvers/tests/unit/cases/simple/wrap.wasm diff --git a/packages/polywrap-uri-resolvers/tests/test_file_resolver.py b/packages/polywrap-uri-resolvers/tests/unit/test_file_resolver.py similarity index 76% rename from packages/polywrap-uri-resolvers/tests/test_file_resolver.py rename to packages/polywrap-uri-resolvers/tests/unit/test_file_resolver.py index 9444620e..c7b28aa9 100644 --- a/packages/polywrap-uri-resolvers/tests/test_file_resolver.py +++ b/packages/polywrap-uri-resolvers/tests/unit/test_file_resolver.py @@ -14,12 +14,11 @@ def fs_resolver(file_reader: FileReader): return FsUriResolver(file_reader=file_reader) -@pytest.mark.asyncio -async def test_file_resolver(fs_resolver: UriResolver): +def test_file_resolver(fs_resolver: UriResolver): path = Path(__file__).parent / "cases" / "simple" uri = Uri.from_str(f"wrap://fs/{path}") - result = await fs_resolver.try_resolve_uri(uri, None, None) # type: ignore + result = fs_resolver.try_resolve_uri(uri, None, None) # type: ignore assert result assert isinstance(result, UriPackage) diff --git a/packages/polywrap-uri-resolvers/tox.ini b/packages/polywrap-uri-resolvers/tox.ini index 2aa32861..3ba7cd01 100644 --- a/packages/polywrap-uri-resolvers/tox.ini +++ b/packages/polywrap-uri-resolvers/tox.ini @@ -4,6 +4,7 @@ envlist = py310 [testenv] commands = + python -m polywrap_test_cases pytest tests/ [testenv:lint] From 6a9a173bd11b54bdf74ecf8477ef5462727ce47b Mon Sep 17 00:00:00 2001 From: Niraj Kamdar Date: Tue, 6 Jun 2023 02:38:22 +0530 Subject: [PATCH 12/47] refactor: polywrap-client --- packages/polywrap-client/poetry.lock | 24 ++- .../polywrap-client/polywrap_client/client.py | 190 ++++++++++------- packages/polywrap-client/pyproject.toml | 3 +- .../tests/cases/asyncify/wrap.info | Bin 5449 -> 0 bytes .../tests/cases/asyncify/wrap.wasm | Bin 128018 -> 0 bytes .../tests/cases/big-number/wrap.info | Bin 724 -> 0 bytes .../tests/cases/big-number/wrap.wasm | Bin 55810 -> 0 bytes .../tests/cases/sha3/wrap.info | 1 - .../tests/cases/sha3/wrap.wasm | Bin 140755 -> 0 bytes .../tests/cases/simple-env/wrap.info | Bin 629 -> 0 bytes .../tests/cases/simple-env/wrap.wasm | Bin 41433 -> 0 bytes .../simple-interface/implementation/wrap.info | Bin 1975 -> 0 bytes .../simple-interface/implementation/wrap.wasm | Bin 43278 -> 0 bytes .../simple-interface/interface/wrap.info | Bin 635 -> 0 bytes .../cases/simple-interface/wrapper/wrap.info | Bin 1779 -> 0 bytes .../cases/simple-interface/wrapper/wrap.wasm | Bin 47187 -> 0 bytes .../tests/cases/simple-invoke/wrap.info | 1 - .../tests/cases/simple-invoke/wrap.wasm | Bin 30774 -> 0 bytes .../cases/simple-subinvoke/invoke/wrap.info | Bin 798 -> 0 bytes .../cases/simple-subinvoke/invoke/wrap.wasm | Bin 41368 -> 0 bytes .../simple-subinvoke/subinvoke/wrap.info | 1 - .../simple-subinvoke/subinvoke/wrap.wasm | Bin 35001 -> 0 bytes .../cases/subinvoke/00-subinvoke/wrap.info | Bin 1379 -> 0 bytes .../cases/subinvoke/00-subinvoke/wrap.wasm | Bin 92555 -> 0 bytes .../tests/cases/subinvoke/01-invoke/wrap.info | Bin 2069 -> 0 bytes .../tests/cases/subinvoke/01-invoke/wrap.wasm | Bin 100627 -> 0 bytes .../cases/subinvoke/02-consumer/wrap.info | Bin 2102 -> 0 bytes .../cases/subinvoke/02-consumer/wrap.wasm | Bin 100660 -> 0 bytes packages/polywrap-client/tests/conftest.py | 86 -------- packages/polywrap-client/tests/consts.py | 1 + .../polywrap-client/tests/msgpack/__init__.py | 0 .../tests/msgpack/asyncify/__init__.py | 0 .../tests/msgpack/asyncify/conftest.py | 54 +++++ .../tests/msgpack/asyncify/test_asyncify.py | 130 ++++++++++++ .../polywrap-client/tests/msgpack/conftest.py | 24 +++ .../tests/msgpack/test_bigint.py | 51 +++++ .../tests/msgpack/test_bignumber.py | 81 ++++++++ .../tests/msgpack/test_bytes.py | 33 +++ .../tests/msgpack/test_enum.py | 91 ++++++++ .../tests/msgpack/test_invalid_type.py | 83 ++++++++ .../tests/msgpack/test_json.py | 53 +++++ .../polywrap-client/tests/msgpack/test_map.py | 124 +++++++++++ .../tests/msgpack/test_numbers.py | 139 +++++++++++++ .../tests/msgpack/test_object.py | 118 +++++++++++ .../polywrap-client/tests/test_asyncify.py | 111 ---------- .../polywrap-client/tests/test_bignumber.py | 71 ------- packages/polywrap-client/tests/test_client.py | 195 ------------------ packages/polywrap-client/tests/test_sha3.py | 111 ---------- packages/polywrap-client/tests/test_timer.py | 49 ----- .../tests/wrap_features/.gitignore | 1 + .../tests/wrap_features/__init__.py | 0 .../tests/wrap_features/env/__init__.py | 0 .../tests/wrap_features/env/conftest.py | 90 ++++++++ .../env/test_method_require_env.py | 47 +++++ .../env/test_mock_updated_env.py | 39 ++++ .../env/test_subinvoke_env_method.py | 31 +++ .../interface_implementations/__init__.py | 0 .../interface_implementations/conftest.py | 49 +++++ .../test_get_implementations.py | 42 ++++ .../test_implementation_register.py | 31 +++ .../test_interface_invoke.py | 32 +++ .../tests/wrap_features/subinvoke/__init__.py | 0 .../tests/wrap_features/subinvoke/conftest.py | 43 ++++ .../wrap_features/subinvoke/test_subinvoke.py | 24 +++ packages/polywrap-client/tox.ini | 1 + 65 files changed, 1552 insertions(+), 703 deletions(-) delete mode 100644 packages/polywrap-client/tests/cases/asyncify/wrap.info delete mode 100644 packages/polywrap-client/tests/cases/asyncify/wrap.wasm delete mode 100644 packages/polywrap-client/tests/cases/big-number/wrap.info delete mode 100644 packages/polywrap-client/tests/cases/big-number/wrap.wasm delete mode 100644 packages/polywrap-client/tests/cases/sha3/wrap.info delete mode 100644 packages/polywrap-client/tests/cases/sha3/wrap.wasm delete mode 100644 packages/polywrap-client/tests/cases/simple-env/wrap.info delete mode 100644 packages/polywrap-client/tests/cases/simple-env/wrap.wasm delete mode 100644 packages/polywrap-client/tests/cases/simple-interface/implementation/wrap.info delete mode 100755 packages/polywrap-client/tests/cases/simple-interface/implementation/wrap.wasm delete mode 100644 packages/polywrap-client/tests/cases/simple-interface/interface/wrap.info delete mode 100644 packages/polywrap-client/tests/cases/simple-interface/wrapper/wrap.info delete mode 100755 packages/polywrap-client/tests/cases/simple-interface/wrapper/wrap.wasm delete mode 100644 packages/polywrap-client/tests/cases/simple-invoke/wrap.info delete mode 100644 packages/polywrap-client/tests/cases/simple-invoke/wrap.wasm delete mode 100644 packages/polywrap-client/tests/cases/simple-subinvoke/invoke/wrap.info delete mode 100755 packages/polywrap-client/tests/cases/simple-subinvoke/invoke/wrap.wasm delete mode 100644 packages/polywrap-client/tests/cases/simple-subinvoke/subinvoke/wrap.info delete mode 100755 packages/polywrap-client/tests/cases/simple-subinvoke/subinvoke/wrap.wasm delete mode 100644 packages/polywrap-client/tests/cases/subinvoke/00-subinvoke/wrap.info delete mode 100755 packages/polywrap-client/tests/cases/subinvoke/00-subinvoke/wrap.wasm delete mode 100644 packages/polywrap-client/tests/cases/subinvoke/01-invoke/wrap.info delete mode 100755 packages/polywrap-client/tests/cases/subinvoke/01-invoke/wrap.wasm delete mode 100644 packages/polywrap-client/tests/cases/subinvoke/02-consumer/wrap.info delete mode 100755 packages/polywrap-client/tests/cases/subinvoke/02-consumer/wrap.wasm delete mode 100644 packages/polywrap-client/tests/conftest.py create mode 100644 packages/polywrap-client/tests/consts.py create mode 100644 packages/polywrap-client/tests/msgpack/__init__.py create mode 100644 packages/polywrap-client/tests/msgpack/asyncify/__init__.py create mode 100644 packages/polywrap-client/tests/msgpack/asyncify/conftest.py create mode 100644 packages/polywrap-client/tests/msgpack/asyncify/test_asyncify.py create mode 100644 packages/polywrap-client/tests/msgpack/conftest.py create mode 100644 packages/polywrap-client/tests/msgpack/test_bigint.py create mode 100644 packages/polywrap-client/tests/msgpack/test_bignumber.py create mode 100644 packages/polywrap-client/tests/msgpack/test_bytes.py create mode 100644 packages/polywrap-client/tests/msgpack/test_enum.py create mode 100644 packages/polywrap-client/tests/msgpack/test_invalid_type.py create mode 100644 packages/polywrap-client/tests/msgpack/test_json.py create mode 100644 packages/polywrap-client/tests/msgpack/test_map.py create mode 100644 packages/polywrap-client/tests/msgpack/test_numbers.py create mode 100644 packages/polywrap-client/tests/msgpack/test_object.py delete mode 100644 packages/polywrap-client/tests/test_asyncify.py delete mode 100644 packages/polywrap-client/tests/test_bignumber.py delete mode 100644 packages/polywrap-client/tests/test_client.py delete mode 100644 packages/polywrap-client/tests/test_sha3.py delete mode 100644 packages/polywrap-client/tests/test_timer.py create mode 100644 packages/polywrap-client/tests/wrap_features/.gitignore create mode 100644 packages/polywrap-client/tests/wrap_features/__init__.py create mode 100644 packages/polywrap-client/tests/wrap_features/env/__init__.py create mode 100644 packages/polywrap-client/tests/wrap_features/env/conftest.py create mode 100644 packages/polywrap-client/tests/wrap_features/env/test_method_require_env.py create mode 100644 packages/polywrap-client/tests/wrap_features/env/test_mock_updated_env.py create mode 100644 packages/polywrap-client/tests/wrap_features/env/test_subinvoke_env_method.py create mode 100644 packages/polywrap-client/tests/wrap_features/interface_implementations/__init__.py create mode 100644 packages/polywrap-client/tests/wrap_features/interface_implementations/conftest.py create mode 100644 packages/polywrap-client/tests/wrap_features/interface_implementations/test_get_implementations.py create mode 100644 packages/polywrap-client/tests/wrap_features/interface_implementations/test_implementation_register.py create mode 100644 packages/polywrap-client/tests/wrap_features/interface_implementations/test_interface_invoke.py create mode 100644 packages/polywrap-client/tests/wrap_features/subinvoke/__init__.py create mode 100644 packages/polywrap-client/tests/wrap_features/subinvoke/conftest.py create mode 100644 packages/polywrap-client/tests/wrap_features/subinvoke/test_subinvoke.py diff --git a/packages/polywrap-client/poetry.lock b/packages/polywrap-client/poetry.lock index 5898fce1..dcd3ec56 100644 --- a/packages/polywrap-client/poetry.lock +++ b/packages/polywrap-client/poetry.lock @@ -1,4 +1,4 @@ -# This file is automatically @generated by Poetry 1.4.2 and should not be changed by hand. +# This file is automatically @generated by Poetry and should not be changed by hand. [[package]] name = "astroid" @@ -578,6 +578,20 @@ polywrap-msgpack = {path = "../polywrap-msgpack", develop = true} type = "directory" url = "../polywrap-plugin" +[[package]] +name = "polywrap-test-cases" +version = "0.1.0a29" +description = "Plugin package" +category = "dev" +optional = false +python-versions = "^3.10" +files = [] +develop = true + +[package.source] +type = "directory" +url = "../polywrap-test-cases" + [[package]] name = "polywrap-uri-resolvers" version = "0.1.0a29" @@ -790,14 +804,14 @@ testutils = ["gitpython (>3)"] [[package]] name = "pyright" -version = "1.1.306" +version = "1.1.307" description = "Command line wrapper for pyright" category = "dev" optional = false python-versions = ">=3.7" files = [ - {file = "pyright-1.1.306-py3-none-any.whl", hash = "sha256:008eb2a29584ae274a154d749cf81476a3073fb562a462eac8d43a753378b9db"}, - {file = "pyright-1.1.306.tar.gz", hash = "sha256:16d5d198be64de497d5f9002000a271176c381e21b977ca5566cf779b643c9ed"}, + {file = "pyright-1.1.307-py3-none-any.whl", hash = "sha256:6b360d2e018311bdf8acea73ef1f21bf0b5b502345aa94bc6763cf197b2e75b3"}, + {file = "pyright-1.1.307.tar.gz", hash = "sha256:b7a8734fad4a2438b8bb0dfbe462f529c9d4eb31947bdae85b9b4e7a97ff6a49"}, ] [package.dependencies] @@ -1261,4 +1275,4 @@ files = [ [metadata] lock-version = "2.0" python-versions = "^3.10" -content-hash = "6f0a98c0051b3b8224458518af16bf6c692c4e3a4e92f468b7786c9c02d79617" +content-hash = "4155c5c48793c71912efd5d8fbf125766472bcc9c1c3a7ba7144df0afd26eade" diff --git a/packages/polywrap-client/polywrap_client/client.py b/packages/polywrap-client/polywrap_client/client.py index 358e3a44..6b29321b 100644 --- a/packages/polywrap-client/polywrap_client/client.py +++ b/packages/polywrap-client/polywrap_client/client.py @@ -3,27 +3,25 @@ import json from textwrap import dedent -from typing import Any, Dict, List, Optional, Union, cast +from typing import Any, Dict, List, Optional, Union from polywrap_core import ( Client, ClientConfig, - Env, - GetFileOptions, - GetManifestOptions, - InvokerOptions, - IUriResolutionContext, - TryResolveUriOptions, Uri, UriPackage, UriPackageOrWrapper, + UriResolutionStep, UriResolver, UriWrapper, Wrapper, + build_clean_uri_history, + get_env_from_resolution_path, ) -from polywrap_manifest import AnyWrapManifest +from polywrap_core import get_implementations as core_get_implementations +from polywrap_manifest import AnyWrapManifest, DeserializeManifestOptions from polywrap_msgpack import msgpack_decode, msgpack_encode -from polywrap_uri_resolvers import UriResolutionContext, build_clean_uri_history +from polywrap_uri_resolvers import UriResolutionContext class PolywrapClient(Client): @@ -59,13 +57,13 @@ def get_uri_resolver(self) -> UriResolver: """ return self._config.resolver - def get_envs(self) -> Dict[Uri, Env]: + def get_envs(self) -> Dict[Uri, Any]: """Get the dictionary of environment variables. Returns: - Dict[Uri, Env]: The dictionary of environment variables. + Dict[Uri, Any]: The dictionary of environment variables. """ - envs: Dict[Uri, Env] = self._config.envs + envs: Dict[Uri, Any] = self._config.envs return envs def get_interfaces(self) -> Dict[Uri, List[Uri]]: @@ -77,142 +75,189 @@ def get_interfaces(self) -> Dict[Uri, List[Uri]]: interfaces: Dict[Uri, List[Uri]] = self._config.interfaces return interfaces - def get_implementations(self, uri: Uri) -> Union[List[Uri], None]: - """Get the implementations for the given interface URI. + def get_implementations( + self, + uri: Uri, + apply_resolution: bool = True, + resolution_context: Optional[UriResolutionContext] = None, + ) -> Optional[List[Uri]]: + """Get implementations of an interface with its URI. Args: - uri (Uri): The interface URI. + uri (Uri): URI of the interface. + apply_resolution (bool): If True, apply resolution to the URI and interfaces. Returns: - Union[List[Uri], None]: The list of implementation URIs. + Optional[List[Uri]]: List of implementations or None if not found. """ interfaces: Dict[Uri, List[Uri]] = self.get_interfaces() - return interfaces.get(uri) + if not apply_resolution: + return interfaces.get(uri) + + return core_get_implementations(uri, interfaces, self, resolution_context) - def get_env_by_uri(self, uri: Uri) -> Union[Env, None]: + def get_env_by_uri(self, uri: Uri) -> Union[Any, None]: """Get the environment variables for the given URI. Args: uri (Uri): The URI of the wrapper. Returns: - Union[Env, None]: The environment variables. + Union[Any, None]: The environment variables. """ return self._config.envs.get(uri) - async def get_file(self, uri: Uri, options: GetFileOptions) -> Union[bytes, str]: + def get_file( + self, uri: Uri, path: str, encoding: Optional[str] = "utf-8" + ) -> Union[bytes, str]: """Get the file from the given wrapper URI. Args: uri (Uri): The wrapper URI. - options (GetFileOptions): The options for getting the file. + (GetFile: The for getting the file. Returns: Union[bytes, str]: The file contents. """ - loaded_wrapper = await self.load_wrapper(uri) - return await loaded_wrapper.get_file(options) + loaded_wrapper = self.load_wrapper(uri) + return loaded_wrapper.get_file(path, encoding) - async def get_manifest( - self, uri: Uri, options: Optional[GetManifestOptions] = None + def get_manifest( + self, uri: Uri, options: Optional[DeserializeManifestOptions] = None ) -> AnyWrapManifest: """Get the manifest from the given wrapper URI. Args: uri (Uri): The wrapper URI. - options (Optional[GetManifestOptions]): The options for getting the manifest. + (Optional[GetManifest): The for getting the manifest. Returns: AnyWrapManifest: The manifest. """ - loaded_wrapper = await self.load_wrapper(uri) + loaded_wrapper = self.load_wrapper(uri) return loaded_wrapper.get_manifest() - async def try_resolve_uri( - self, options: TryResolveUriOptions[UriPackageOrWrapper] + def try_resolve_uri( + self, uri: Uri, resolution_context: Optional[UriResolutionContext] = None ) -> UriPackageOrWrapper: """Try to resolve the given URI. Args: - options (TryResolveUriOptions[UriPackageOrWrapper]): The options for resolving the URI. + (TryResolveUriUriPackageOrWrapper]): The for resolving the URI. Returns: UriPackageOrWrapper: The resolved URI, package or wrapper. """ - uri = options.uri uri_resolver = self._config.resolver - resolution_context = options.resolution_context or UriResolutionContext() + resolution_context = resolution_context or UriResolutionContext() - return await uri_resolver.try_resolve_uri(uri, self, resolution_context) + return uri_resolver.try_resolve_uri(uri, self, resolution_context) - async def load_wrapper( + def load_wrapper( self, uri: Uri, - resolution_context: Optional[IUriResolutionContext[UriPackageOrWrapper]] = None, - ) -> Wrapper[UriPackageOrWrapper]: + resolution_context: Optional[UriResolutionContext] = None, + ) -> Wrapper: """Load the wrapper for the given URI. Args: uri (Uri): The wrapper URI. - resolution_context (Optional[IUriResolutionContext[UriPackageOrWrapper]]):\ + resolution_context (Optional[UriResolutionContext]):\ The resolution context. Returns: - Wrapper[UriPackageOrWrapper]: initialized wrapper instance. + Wrapper: initialized wrapper instance. """ resolution_context = resolution_context or UriResolutionContext() - uri_package_or_wrapper = await self.try_resolve_uri( - TryResolveUriOptions(uri=uri, resolution_context=resolution_context) + uri_package_or_wrapper = self.try_resolve_uri( + uri=uri, resolution_context=resolution_context ) - if isinstance(uri_package_or_wrapper, UriPackage): - return await cast( - UriPackage[UriPackageOrWrapper], uri_package_or_wrapper - ).package.create_wrapper() - - if isinstance(uri_package_or_wrapper, UriWrapper): - return cast(UriWrapper[UriPackageOrWrapper], uri_package_or_wrapper).wrapper - - raise RuntimeError( - dedent( - f""" - Error resolving URI "{uri.uri}" - URI not found - Resolution Stack: { - json.dumps( - build_clean_uri_history( - resolution_context.get_history() - ), indent=2 + match uri_package_or_wrapper: + case UriPackage(uri=uri, package=package): + return package.create_wrapper() + case UriWrapper(uri=uri, wrapper=wrapper): + return wrapper + case _: + raise RuntimeError( + dedent( + f""" + Error resolving URI "{uri.uri}" + URI not found + Resolution Stack: { + json.dumps( + build_clean_uri_history( + resolution_context.get_history() + ), indent=2 + ) + } + """ ) - } - """ - ) - ) + ) - async def invoke(self, options: InvokerOptions[UriPackageOrWrapper]) -> Any: + def invoke( + self, + uri: Uri, + method: str, + args: Optional[Any] = None, + env: Optional[Any] = None, + resolution_context: Optional[UriResolutionContext] = None, + encode_result: Optional[bool] = False, + ) -> Any: """Invoke the given wrapper URI. Args: - options (InvokerOptions[UriPackageOrWrapper]): The options for invoking the wrapper. + (InvokerUriPackageOrWrapper]): The for invoking the wrapper. Returns: Any: The result of the invocation. """ - resolution_context = options.resolution_context or UriResolutionContext() - wrapper = await self.load_wrapper( - options.uri, resolution_context=resolution_context + resolution_context = resolution_context or UriResolutionContext() + load_wrapper_context = resolution_context.create_sub_history_context() + wrapper = self.load_wrapper(uri, resolution_context=load_wrapper_context) + wrapper_resolution_path = load_wrapper_context.get_resolution_path() + wrapper_resolved_uri = wrapper_resolution_path[-1] + + resolution_context.track_step( + UriResolutionStep( + source_uri=uri, + result=UriWrapper(uri=uri, wrapper=wrapper), + description="Client.load_wrapper", + sub_history=load_wrapper_context.get_history(), + ) ) - options.env = options.env or self.get_env_by_uri(options.uri) - invocable_result = await wrapper.invoke(options, invoker=self) + env = env or get_env_from_resolution_path( + load_wrapper_context.get_resolution_path(), self + ) + + wrapper_invoke_context = resolution_context.create_sub_history_context() - if options.encode_result and not invocable_result.encoded: + invocable_result = wrapper.invoke( + uri=wrapper_resolved_uri, + method=method, + args=args, + env=env, + resolution_context=wrapper_invoke_context, + client=self, + ) + + resolution_context.track_step( + UriResolutionStep( + source_uri=wrapper_resolved_uri, + result=wrapper_resolved_uri, + description="Wrapper.invoke", + sub_history=wrapper_invoke_context.get_history(), + ) + ) + + if encode_result and not invocable_result.encoded: encoded = msgpack_encode(invocable_result.result) return encoded if ( - not options.encode_result + not encode_result and invocable_result.encoded and isinstance(invocable_result.result, (bytes, bytearray)) ): @@ -220,3 +265,6 @@ async def invoke(self, options: InvokerOptions[UriPackageOrWrapper]) -> Any: return decoded return invocable_result.result + + +__all__ = ["PolywrapClient"] diff --git a/packages/polywrap-client/pyproject.toml b/packages/polywrap-client/pyproject.toml index 683da987..76b7e9cb 100644 --- a/packages/polywrap-client/pyproject.toml +++ b/packages/polywrap-client/pyproject.toml @@ -11,7 +11,6 @@ readme = "README.md" [tool.poetry.dependencies] python = "^3.10" -polywrap-uri-resolvers = {path = "../polywrap-uri-resolvers", develop = true} polywrap-manifest = {path = "../polywrap-manifest", develop = true} polywrap-msgpack = {path = "../polywrap-msgpack", develop = true} polywrap-core = {path = "../polywrap-core", develop = true} @@ -21,6 +20,7 @@ pytest = "^7.1.2" pytest-asyncio = "^0.19.0" polywrap-plugin = {path = "../polywrap-plugin", develop = true} polywrap-client-config-builder = {path = "../polywrap-client-config-builder", develop = true} +polywrap-test-cases = {path = "../polywrap-test-cases", develop = true} pylint = "^2.15.4" black = "^22.10.0" bandit = { version = "^1.7.4", extras = ["toml"]} @@ -52,6 +52,7 @@ testpaths = [ [tool.pylint] disable = [ + "too-many-arguments", ] ignore = [ "tests/" diff --git a/packages/polywrap-client/tests/cases/asyncify/wrap.info b/packages/polywrap-client/tests/cases/asyncify/wrap.info deleted file mode 100644 index d77304d24c822a12954712690f35a3793954b922..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5449 zcmbuD%Wl&^6oy-=Prwr(7VK!b>{!wCnqJgJ11u0ilVqAs8{1*VPURhlw5-d94ZGZW z5k;tM*}#@Q0B?gmXRM58+;L{uMaqA^b9`+7XO4U0E~bnGe*fY8qk)e+e1=%;H^^Q* z2;&YO93kfQQJwT;;bl-iz>Tn$2-xWdE*w=zYo~rNI3#{^_M$_B4yGZ&?8`Cyy&F>E zw|ItO`tRZy#cv}*aq~Bixi?}B)JC)?N#saHK6eYYqUZ{+6$k86Id;hbyIhW4cEGNb zV^mSPSnD)bI*D(|ZLxe|k`ETDC&&U@ zER2A%fU86sOFmBuj6CcotuHXsE^0?u!6|0SC8q4qlxwLe+sKcNJt-0!t0)RE)nvMf zla3Tjtr5Rm^Vkv^Q+~bG5M&-)LgNB9k1haP&MpWt4=vpK4WsL<|H$)vRYb?;ZCF*EdV}aI9 zQAf)f3$$*FI$G9Ppmk%^(Xz$@ty`mxmNgb=-5hnatSLmNzH!wKlKuV#qTBrZoI4a} zCdK_w5h})&KY}V+XUBt0;#;d7)TgRZRT_&_#m-g2ocYe8I!ivCBnS7Z-wh6Ne!)0< z1)IQY-b`JrmO4a~qWFXtHGOREV~w7K(?++fBVvF*;4$;uoMsfXD5bWwF_{gi|+F+z+H3E#&)IvQv-RZY0j#wp;0PoTpqByLS_(qQJe`YMzFxl1(Bj59 zA~up0g?uH}v5{@XA&HXETRC+cImSUraHFK8QCoT=$Fx>blBx-|)s`e`Lldm`?je6+XwdS z`S2e1sp~#{{blEf4|M~{SSTML(!Ota?w0dqMG@vx{u`Iy^~reU#{cUFHr)N)-@Ep`f8+A+eCSj0!T5vMeaGL~ zH}N|^IQEJ7#7l9qbAS5LRdJErl5SmH8I4=ZW zi1TfNr{nxP1YeBvn+4Cr`F6pV;`|oDvvIydFwNsuvVWi%)3O!ShGVT&@pjrcDh_Sh z)vK+JisybeRcpV_zp>rh^Q4t*ee3?4!m@-CyPt@+_mWQ1Dvp~1^HhOiKV2+KJ1bS> zKvmMM#R+1>#AwGY(v!r$$kOedxHXWV6A`Hs70)Ww4N=r8qP$^BiBw9hI33M`UpBVA zh*!lc(ydvNMcoIA2#UqGbgo!#X_M8|&r;%_a`E{ZQpBVn`Cy8>P0kD;A2ZF8Zd4?L zF^gBC*-SW*|G6@lC7Y6mvRXz(KWM>&fOJ!Ge-;&EyL#Qp$z;m>>$ImPrqWugSN4Xq0hn=dBfoR?d>>*yQY*TC};Q z3=XfH?IpnDm3K73ft64`-JHCp7Wl_=b92WUo0C^~P)nXuBM`|oPwk8%k)IkTtF5UW zodn6+L9!?gu5_4;RcdFNqWA__*NT77-^uPfim|e;bY-Tkc&G46?D%zKuM_J_vQvXk zp}F)ff)r^8rf#mDpB>RuFe^*wbopvEUYv zUqzt@V%sn1VDQwQ9hKBLd3thl@~DWjDS4#b^W$qo6SS*^7G0X4Z432-Gpn7q37Vz} zZivoL^iH)Dh#o`q&ggPP^xi0<^KyQoPnHE(qEA*c?_4@R(WlCU>VgZwf668e%;miJ z*IgIfXF4FLP4C;o-{xLA{%d2q^~(;Zz8(I+28A70K+p9N(B zmOcxrnRhO6^ht}uN7G`l<-cvuMAOc)Z-U_I%cSl*VV;Bi_+?nb(rWe$;z2%QJE|z$?{^+ zU=l>D$zG#ax`UZZOwF>i2$sgg@-#zl`{0Kn&b!+p1W?OGlUB_o>K|)nB3xV+uPLNm zEVjk3DQmo@c5D)n)|AC;0d&=Y{Y81&&Rf~-Pa(qIzAZcW6!om{$W!WRYndYS&`w95 zN{c!zxV@Jm{7|iF$M}|%rN>zVnPQ18{mQcRjR|wXOfuc0cEq5OVoFkbJp9;!{Pto& z-e_kn@zAAZRtPjjz4#(!Hi}>1?@A_#rGsdhhGb|Pg$yl$B(YZt zdr|RQPkCV^Exzi*+kOPPBX{3kEQ0KpmX$#mN4}vOP~+5MFRGg9ba`1VnuQ5uE-sea ziowi{AVO3xh^#0hN5!#^rQLgr6=hu0p-QQYiMP@%-IUdfx(~K5@zwe^WUQ}55X6Y; z%V>?S(T8|r`rd$)wK7zgh(vl{vC`Iyq@VBVM214TZZ)nds@EakHXh0)TE zGiZouJ#rB7P0N!5f(tZ`CUTzQs8o64x9!q0d|24_+^B9z*WH2z{`PG0B3+}fL8*q0}7$Zs3J@8EYc zzwP{P;kScctp!noaCcxjm!L0pYr6XCvV}Bi+Qn+yLO}ote3NNh?PNQ?=u|2_EHg@w zFv^)7f)cwy>@wD%g2bh=GyWgaPa9^&*NQ7D{!8VV5mo&6$}>}Y@fVfnI?vy%JToMV zkNsT8Z;a3hACP%bM88Z*`( zC@!-E-B6Aasq>5|ww~26Y8(dVa>SCfJ!Qm_%ggjaqcI?sTyAr_zRb;xIX9iz3G|9G z1BNOsdc|Op(4sV=;bN|3dn?dabQy#Tf<%&vAI?;=Y`|J)2C~!$lJuzIgUIH_v2s;L zcRYn|^7g09a9x@u`2vUOnljf>n69y9Tz4K!uPigLm|i)UWL``=?Q9x6mki)}RV72= zdDTFM7sPY3@DwlD0G>%-bD<=QU-nqwu`Oma+akc&;xquz0Q?Ofo;76WJx;dFcS2 z*H$tVp4Sd!ctJd`6Q1Jv*MR4x?Y6=5x-!>McwT4AxaK@~USDQl@w|R8$^3YZXBUI# z$^kq#R5BEv8wN7GAfB6q=f&W819+|kO^y1EWv-*}+-S?V`aF1UDl@QnZW>H7Kc3C3 z2cFpgo|`Kf3eU|08D0?2EyA-0o;QML)}AnUZYgseh36Jq#=7(1`HnIJi|0EAlgy9j zShgBGR}J8KLnTAudBZ@47sT@>;VDsQ8+fj2j~hI1EOQ-&=Z&_EwdcX}rZNMI=S_o2 z=Et*+k#58(OEN`}JoodX$O5YKlCPl^If)#tImVxyUPqL zp6?z^GC!X6Yz=tM4B&Yps^lm{PecP*UJ%oF2~!EPH-qU+d(2?^<&f_vRKM&>3EGii zY2nvH78coGA4)VowrO@1*j_n+?N_Q<3fr#?W_dwu-z{tDunEQRgA8qD&7*lrcJTA17dwrksUgY8#C zzN4`Hsw*XEYlg8s8M3h0o*YUvKekDBHP|j3!1gz)Sqj_V7|im5*cQU}YOvh_whP;- zUkfXtU54>JZZCrhT2DyT6T9Vdh*Ijhl00Ii=DvGH7`t6&RiVn8W%nZXLVYB&v0xRH z&uFn{7DK(nuiRhK&eH96BTzdJ{o8=QS>j(DolA?W5Yb-%oTk)HY7CpyXg7Rs8 zo%X*jGc?;JJBxqqGRaLQosvz>pT+ZoSv>Eu$ZQtN9Cgm4S^urUEPl&najDH>+Gk<6 zy(H;NgC{BBx2s7btFZfRm->=njorTq(W7F{sO?$lG3 zFBVvxPYTTB>jl>4*9xr9HwtXXrv%cxt`+Y24G0!l`e8tDEZ)@{$ACb4yUp!+$E}X- zTDZdsy4k+lXs}ibx zG}-DmDQvClm0DK}3hH3r_67x$Wu4d54#%{#DTnq4x(dPbn)xIvn(R)qKT$6_JLm*= zK9w(~rnVxJVlK_%B`Dl6DvL>NQjAND2-8|ru@#`Zp#pH00#jw_8RXTh()LPGfJ$LTNKWKARuL0ZL-=BVN<`JO?IdJmVQWL%ymdo z;@?}3`o&RHRR~-Cby`338~yz`Kn|0G`0a!?BPO!N+k16GCi5Woz>4wb0=s$eVBMGt^P1 zPV`Viw6LU@ET(3Q$BuckiAhFJuT{MEi+-NN zt=d)w!FVxawjb&cCs-P&n{~Wp!9>~6VjYG(l-qE&6K|R2H5mlkfjSl;&TgRO`OtI= zRP1e}NhY>uo$Y%>(FudP?7yxR)o&8t$|u?ww^;HF$6Rk?u5~dJAJe23Ml{1=#uoN3 zHNypJH$)%gQJrxv-CVnsC@*{wYm5hN+u~iacuw^iUq@jdVXuRIB(NB%lKW! z?>z&|zu$;!*@fBkdn^fI)7h@xvei-6F0f5#Z_h9DV;_z6Wt}Ly6~5oQt%&#bc4qC{ z^2;(ncG-&FWkq^hPN+z;_KM!lqWzG*6~FMcpZ{94v%s#dO$N8oh|3DdIh`%bZX?bn z*ugU8Njr3rRQO708kk*1zRO@N-J7#zd{_GeQ_8qC+qo%80d1Lj)s(1d>?hjA$7r@k zZlTk(w|6k;YGv>7Y`puoJ^M~vA1!5+Wkoi-I%-jT-ZtioCSz~bn9fp)eZ9`Xn0FG z6HIEU0o&Q1b(p!t31^a(uz$cb3uH#n-^MRa%fas}_sV;-YH| z$m;$38x@u&^Rb-}P7|vHE6GZJ1_(ASB3F*-js)q)9$t(r3-vDtQNBdexn3C16yRYrxD*wH>-PPnE*GPJ8w>N`a#hKxav zKf%gwW{?1y-7WUPJj7scOzfOd$Ut#wnzXM#H4Sg(!#@~~Sp1#gh|LyJ(smtNU1x!{ zSQc2SzcbO|d7mt@&VxWOBe4j`9Lt%KH2dlGE%&WpI${xUmLoP>WId0-JY6%Gc-Z95 zzGG~;pDN&qMjU6SA0`ZwtRqi~*)hhd2p$_XAd1BnXW;U^drj;(iuripQsTF-Q7Gx?}y)Mol80kt6pJXp*SzJdmW z31$=TTbjF5KwVR6IW4h%JO8vap=oKtOiMB_a&ywL7{S0!jFLYn8I%5|AZsXij#)#v zMI&_>R~_yFz;`7gvb4M%KviJ4rg5O&qM|e(af+0dQKXz<_PVWbrXzk9@UxePHX8~4 zWrxvFQ(=>Rg=tc9Q>C4pf|&`l>HbY`ViLP4)wQRpmz5gZR&l~ishQ<9#5En{4TwrT zEX~vaZ6S|DD2g-zN% z1}~RwkzB^4AKA)XY%16B8lQ;XgwaVYDB05D3#=ihtV%`Z%%w`@-&R#BO{D25elmfW zY+!*7COs_K>L0riT}q@-3c(zME!wpF2Y=_zPS(6U@u3~yTsBZi-gcJ-!^!>8QZ zy6pv7WWL{$&6>m8H%hX&JyVjKAX0rI>f0Xiq0XdnqP`ON*qZ4#?RuQ2$5$`61BBv6m znVvUQyc9X<7F|V%>x81jHZE~3Ynsw1BKtFuH?E)3sSDnmjb?itClb+qo06NdDJgt5 z0G>r8I)O;EHk(rSnjtz7GQJ=ZO#={#x_p~jQ@eLF!s}GAb(dt(c2%EYyHD|xV49ZV zkkfBe>Zda!ljML#1Wii2qR5!cI*23h@~0m{8W>=2Qnprrw2_9OcqnhVkOkQYcr$WGyt>~ePH_Sph$4cuxXg# zF~bbqaRuMSE#IlzwU}z+SwUE$F)6}ZSX_x!qySTWG(h4zOu6Da%$x8XpLW`^k$>xk z(+bN*E^_@XE&d(tJ!zRnpY_o1RG0?6odNkfE{o-^vzif!x>%N^W=Il#QKyKs9MYIf zz13UXnL?ZXrjNPY$VfC6m{VC?e2)6ws5XpM4s5P8y8hitjfr?8L-BV*l{0MzR1Uhl zP>JmZ;|n3S9gT0+2J@dY9*;2|%~6*(X@mK-YW++j4Ghh%4cAtr@QoNtga7rANy3&( z%IN(1P_okY(in7E%w_OpNo(@?M#x8G&x&ujTx@ru&5ePOg-0hfTHQVZxoBNvY>~VT z=IM}|EYlvKds#ME&F%Ia(@ZQa7&}aeJh!pULf$o;PMEyeji7&5 zR^D?0bINnf!KoKE~U|8oNt2Y4HpOrM#i~I}k6Ato3>J|UKL=baa^$Q(O`1cO6WqvBMmW1jC z%D^Q24fj*vH3 z1(7r1%jy0vC&QN${a=oSFGu^o91dR&^?#Wwzo=4Yud(Mk!4nQ16?C;c?A{#$7Duls5jjGzg2FGA$_wHA>h4jy#yoI~uipsVFc_wEF+IDK7-$SHyqL{5Y+ z$NRq=4PTD*e>oJs9PIz{YC!Q^Kk{eFFGA$xbrz9h4jy)J&cU-n%+>O=L-G``ID37G z$QgnaL{5b-C;Pt~4_}V;e>oDq9Pa;eFnpQo|8lNGUWlB&-Xe0s!J`fya`06lGIU2qk>Hl)5{31kN zl_vXwjN;JHcreA>Yig07aw+&hk=rrQzL`Zp~4pR9-+843ScRt!3* z{RHMWTYv{P%wj-WD_*&77Pld_;-zb6ap_SjUf>MG4Z!EFnaz8^XRe;bK)hBwxo#F$ zAEaM9o9Dm-SIy$dg!G7v$e^+*;soJhjz6Men&zj&JO!_$&KZ5 zU}JK#JqWV3M^%Z$;g<6JZFYw}fg9^6C`*jrujZ$-E`Q0|B^<&1eV2PUI%BNQbka_X z4YTI_gOEjo(ptqI3?*8_s>e32J?&?mYq&;Uu)Vjia|t=J_m_2x*R*h2&f}Riv%Q5~ zI;~6rUq+c{enRd{s99`|@tzr~nQF2frG;G)qao48 z0EUs%?x4Yc3|Xk(4ASR6x(q9afmC`Qeg0F(!qVqI4JEn|eU@}C9;VN^D`$I4Jbhkc zr6Brftdrq3USnpyh%;ZV)yqt6m|K;fm3#VGo`HpZLJmO>^`E)5mHzWM3lPyq3lh=ifFSf?VIp=onm&INYGM?*E6k3P%Y z!G=E$S&X93AG-`IM~{Z+b2emQ>2r1{(S_;b21#{%9a>kR&u3ZJh(229h(1pULLb&U znl?t$=f8xSS^E5!p_rqv-P|F2l-E zry=_MX~@FT=TCW*KW3t5b!&pDUj)#dCsJb(RJ$imX+&xR6Rm_F0P^f|G#;EJo4if4B@QN2`YV&nqDdOP^PU5?z=+ z7Y)GKyuHJgt<7rP@Ke;KkEMW4TP z8CH&D4bkU+hAb?7{^wAl3)9C<(pCO*=DG@fUS=sO`eT{|;GL`uy*qL>H#dlHvYy?)nOSUSowT z`e?-~`n)0teOUQwnKYU{-wZXg^!esc&E})eb+SA}#C$DeF^WE~xeP1EzlP}ZS0M{a zpT8PPbYc1|9;Odw1wnp(oCUP#V>V-;kJ*fYJ}juUoE%M`zYaCC^!e+dn$1TaYcx7m zydJU`MW5GQhLr}n0K{o zgFdAhr=!h_dUmM`HL~knXe{GQvH9A}R=Uu5cAX1NWSI-KvTKxCTZ^(YYwQaAr8Qc{ zUAiRY z68Eej-IE-UFr*XJi&qWpp24}KeJ4fA!Aq6&xdr~6YIoRB?}df_oz|R34f$SL_FDPvMYs#6$K$7J?$&Xi({E!LTB*UdF^GQBmN%E7GB)C`@C}r9w zIaW#XbCo2lk_VDp*n({Fdw(Vk!|ND|G z@JT*XN%G^BBplWqzy+63w!<8)B>8+LiMJR+fr;dWL*rHmx3Qn7*3Xz}4A|0qVz{=Vh4`H02BVMsWXMD|6HBqB z`Q%Wt86+Qc$P27`)z4BTR^3PJF|l! zGvpxjwg*RKc2f>x=fD}Ye#53T<-u#_=K~w9lJ)V8W+qYpeS>GJf3U1xpDE2DV@mUb z1Jo-`X==uWGxHqt78@aEx+^~Wv)KBW2@fdOv1XdI?t=+qFo`Q!0?eS2E=;?bzWnL3 z4jd##iOw;?VEHO5*g?zJ?kLOGev{WXbTT;Dx^m>Kg{iAKQp~Ai_Csc{Tes(9O&>|j zA=wP4)=`XGrio6CdesZuSL@7}%qB@2^*ZKEat6S`Pfo1oG;A? zKs6aSVj37>r%5f00Aeg2n>vYQ`)Z5RcvP@EyCyN4S2CA1C%OEy4pQ@lEMcmu_XaU)f=)iXxb9c$c3Wif8_vAfos@zbu5X~&Fc zb(!mn8U0XbZw`&Cefi14S%<8u7S8Qa?X2^6(3*4P+5 zAtYwu-DJ>^S@BYR)SRF*d2i6*)7bqR6VIk6M%xnOhXOHZ#m*92t!+OF=R9XUbjG2D zSrLdKX+hwsZ^jJsjN$(VBHS8?+-o2rv4Kd-1|mosh>UF@;p=oX1P!} zUim89aehvwWW-=%mPY@^pMjBfk$R1^3pX%>e`t6=9-3QN{mtTWM~#KUUE_yC+^Co{ zrvE=2Vw(|AGNGkz0Ta^=M*Pn<(1h<$9Ef?%c1Gw8=Ao9|XkeOc+s+o>cWh^0@8<1n z=56234&E)>*|yuUoxM84ppg6*unjlOGH3}*OP5E`huaHU#Z(>};l?Zs7O+EvoSGD0 z{y8t)M8!WdVJqBp1`>3Af>V_Qzfnoh9!MbbTvNgyR1%!7BxnsJkX55e@TZjoe_Tm0 zF_56+6Z};r!CzJqj1MGe`vi~wd_ejWCTx*z4kXZir>W9EtR#4%l3;8gfi_G{f}gJ> z_(CN?V<3TcTup+1T1oKBl?3&H1lqDS2~JiLe7TY!9Y~-(Uz6Y)l?10M2{`L!<~=K> z{YbSxZ)OSfBd#|uDD~31>SJkTJKM7PrF2?0_gN+uW|l3^5WLz3PZQi~gIa>Gv%%*H zzS{;*61>U=PY`^U4L(b7jSW6S@SQezjNlbEc$DBxHuxmL)i(H9f?I45X)x>AphU$@ zHuyNfi*4`#!Ru^rj^HIW_$uq)>uvBAg3E1CtK!Wzc$VO_31$o7CT!_tYtaA;UWvwB zaE2WQ!OPLm2(DrWMlfT?N^m6_F2PGTnY#?K-1^ncmY^}!ntX*@n|B?zLc?=<1yfF1 zG>tKap?YmAt;Sw%`SCghxW5K0jat3eef-WI#r-bGg6=|wy7j*SCg69vQLi=YOG z8=({$kh&rIG+0mU0C#08HzaHeBOB6ki%Yzt*HB{0kpgU~ z7WxUSb*VJ-w)d0ooUX|zy&$b4ALIO~^m$df`YL^!mCoEs?{%fSzS2Ko>5#GXK-smL zG`wz>r%A$EPW+sL&h>7e_!$At|b?{IkIvt z;wLK6-CFJ^LTpFCd9DCai=XcbkY7h4k$L*Jb1veEYW<9hLIRM);8K>Hi7oMemFkc2q*pvX6~&NiDXU8FT!whWiI0 zGe!^N^&gDLY&HFrew$I-zBOC}86vo)M#vAxA-HCUzP~_D=n*MY?ZahB#nBUKv8p)v z<+S^^cx@}cD6kZV#J6*d;xm=PD*m+28Gl-zaYZ7enW8)wV{Pf>_@6A(!^W1O)(EL*&Zd9Byg#D=yyN|G?@T_eIYF=4n=t=}_H|R!$K4eBp{UBqILi!&q^?xo@ z$|CSNS0xU4o1Vc?^*!UKL)@r1Vi5T05W5cn4Y5abeNC*h>E;vUk>(Y*d;;Cx!+CNXb3vqB^hg^L*v#l*hJ1*oq=ael6t+Ivey1U3u zN|)G=^{OMgV#3jg7(gnU;v6H{{Zis2GJQ>N#OnA^{|H2%=G zotT+3q1NDGFO&j(3aT%J%&day3nMaXTjtg@K-+zMT+ z@`hUnbXK*d!=6puq16R2Miv9uCYlD^v6(rdnIVYI0FXo10uX!gnjmR)17PVURDsRx zA{`-aN-{=>lGuDR073Rv0P^nb0Oanw0SMan01$rf1!S9&`v8c*_X7~v9|RyUe-N-* zx3)DUMn4Qd@ZSqSxPAn{;^0vLBKI7w@U((BAc!b_P>^-T{^P|- zbAOB{JO7`N{}=IH^ds(5dHwI*Wvqc)+IxCrH>-r_%@u%n4V2<9OEJpja4msiF4@Up z_u^85x{vTSoqWfTmRy?qzN;7Q+J~}%hj{O<;$5>XMCW90ar$eFtk|26)u>k%p@*V)jufX9!m;5L$3_edwli1PF=tzr`mQ>vAL8V%=ARxGN1y>T(_Vwa@khHd23xl*c z{dL{sc!w;dxpczOn6k!4mc=+1IYfQKPP*>a3a70F9SB<6>d9uQ74L-Sh$xA0haD(@ zJSIN{3BIP1x+h%=HX~+R>t2<`_!ZLWNa|SIqoGYmj*swfWga1=y%W))fZu&OjA~b$ z`rQ;ZUz{oStp+@5tFgBzW z0tJ(CuP*;OJlWIaVmBx#l{0+qqgnKQyXoDUFHBDSF}0-)$y?Nm_Xv0KCu%!Id(+l2 z{jP^MwPcqR@5+3ST756A4xtn1nZ>(5NM-u!M*n6Z_$|~ec6HOB@zruPC1dEjiy|y_ zsbD{K6CpiJ+?qMyo*42bp1kR9A{**D!m#9p3Q-0#hwQ?=36cOz9>l%{M97xf%=i~j zql%-OIm8e*%^E%rRsbeC>sL~>$;#wGDWmhy{s1-s>OY}9YN0)7D>Hkv7{zp6vUj6C zz60kn>agm)qE43Vgcqpy64Y2Wy{Oxh%d~i)8)r4to-N-yq4`~=X$kDQYX$s+PM(OS zU2(jDZVrBBLnO1pQg7xG!yK8XuS8v3X^wbQE7a8rT<}_UPjxG0ggRZDbI?q!U`S{1 zZ#%MDazV`tk}L6SXRBjB26~jiX(v@kixbVFm(qz=X6FXfFdDe0+doKM-CmxutNqk zywG$YF#_LlO;@I|(MgNw8sq~*i`?8e)ZEdWg&7?9hT%2Qc9nG79$eRq@eN(3@tSX| zxX_KL!n_z0RU{Co*C8K>Jtw!Y;Sg(pq{TSn?Kot^9FS**z@b{+T@DGo{2gCFlM&=1xVT9fKBfGiSm_bQEUoGF^w4ZRLjQ)7=Q zpE1eFZ3qRueDxh#%xq%vZUTY+($8oL?x{fJAJqEl5N5cjL-9h0!=X@q;hX%Ibf#$lsSkVHs-a(zof-H(cNRuh%p zc!r+Rvxpvq7cq1vt57dKsEfUMh7OB6$Pj#;)k!pB_`Jy7*T_uz_!2>69|Zya?aKtu z*tY;5;T3{s?OTA4@EXB$_AS6iIPgMRylUS9e1yk&JNJSq4d5d@LGYk`3-A&AxGp}+ zyF>Ofz{fls-abi?N8xZJ1fM3zquw43!Dk5asJF*L@L7U9>h19me2yTGdV3-SpC`zp z-kuD>7YOpGx2HnzMS?u)?Mnnt+aSQdeVO1H`xf9Myh8A-eGBjrUL$zUz6JOQ2fhX! z?OTA4@HlVhzGeyr_y|uBJZRqne1y*uJY?Sje1s4DBs!>0&8;^jok7hB*-m)M_>z1zyLSliw>|g=Qh-t&S7iv=FZ zFA;b&zf@o@&NIOSah?kvjPsu0<8i)9@KBtu7JMSkFB8O(;^l%kR=h&+NSx0IJ{jk0 z1dnnpaV;E zH6HU+qqKOTeQ^sESv{NAbYYWIveT5~eCz*PmyyX! zp)O#Q9S`Q_#&e-AwVL8tmw4%TIhIFU&=}`T6aurGavu&==y!oC()681H@im z_26Gto+WX7v+|50s+jwkke+Sv;uDqUF`hqNc}5dj{AlHQoaZMh&l5apLX>%-FKbsl^; zII_fT^qb2O3`Tf;Y*g-7kgMFx->?ue9EH(3VI)4lF;Xs8&?SzI$_)miFdDZQ$?Ca( zl!faGYzs}45r;=vrG@BSz3sg*4U@%X8{vhb5q#fsQ-UyJv@(=Cr9(CvXSj{l3M26o z4u0l~&2^0!QIy0Ug^_bMFVo3>jDoLui;?p*PsHFqeUe~i-b{d7{AD1Auil7fZ78?~G?xQeTVk^32 z2&3SQ-D2cCu@mw97>#9@IE=KXY_7%E3NFwsM($#JZ!j|NII3qW9Y)3{sOfdstv4#J z(7C;XHgc}eLx!U;x?C7Z2IJ^97dh#o#71y7&Ti81{Oa6|%NDr5je@&yi;=sL-rJ+h zixC#O4kP12-CzVuZ&bXB>sGF;$ZUTP8IHo}GGQbM6YJ}|W6st$iu}CXJGc4D0;V6M zUYX2d)GH&Ne;n1a2fQFp~Vt@!z~{PQy2f)n!hj z+Q{8Y-W|f|vND;)$lbS1#Peg6WXl{z`092TnZ9y)nIYcv!N^^?9Woq+(JEoI42*Ed zk!u^pm2PFESYO8tPah{J5qx|g!VR!bb6a+eo51}6IUL<%pE#bCAIG=%*dvwpxq@BK z7oxczS>2T7PrqeX8!MaP<&@rJ*HG$u8K+;X{lM$kVa=}BF5(86rEip3`X-sBZP5ir?-MmbnK`!n7$J1zc+4{y86o7l(aV z+T_06wJtKzpY~CB@v}Y*JM53HWtEBk&wLbKJmbSsHTUJNRhfx?(nsONulq0q8TIcf zW1|se+!J*$=DB5TI3k&S%;^~;l1BlYRCxq&nan>TnUp*X;K#Ov z?gwBfavuP5lY0SpHophJ?#kT&j8AR{V9;_a03(u{0VsR70x)m632>zhS|S;yYyd2j zu}dWTlC^+bhA>gKNS7`|GB(KoJvnTTbRoku0Lzob0L)^vd4X9Bs(x!Q9%U0>%9hBW z?!e}xtqI34o8W=(uW$wuMJ#hGJiw_99cCx_Z{qFA&r zp(D*SCI)~R?ZluPrX-}FOxF>>(zZ}PaW--3XdAm|b0-pQhH1x8@w)bbBWQN(kPOQD zbA`d`$l73Or_GvRHHsNux6%UZRql7P7FaX3j$SPlwWcn7_{vneu3Znbu6Bb9!wqdE zF&wS8{Tt=?AEOv`D&w9%18@<@YQTi(XuR~V1u!tUZB#>H1AxxI1wePd2|x$m3ZP5h z44@O=3ZUEG4xppn4Zwcu9snKnUH~2SJ^=Px_X8M`4+0p09|SPw9s)4R9tJS3_5v75 zj{q1uj{+DijM=&d$N@pd1Y^4H#&}(0`jDO(#n@rhHE^-Rs%xxbhgH|`JR-=5d{U4> zcvO&ahaFa3L+zL#qYFE%y6n2J!>Y@!3p*?>=P`Cz+^A#huAd0~fDmz~!s zL2gFD4y!JEFYK`DviHIct1f%5GlJNAy(Eae*PtC%>$xkEsr|J<74-|z8&py2P7|75 z*G{mT=rq-9l1!@RHK?eKs(HQDRBy1F>Md4Nt(zN(vel}gZ?y{R+pWU-ZmY0<1Nzpc z9ZBx86svHZF$&japThOlQ3}_YUfQp4wWAU?fZ~uLxh`5;QRbB&%~+LAw>h9jzP-2ca4^)zCPYtR+c}y=*Ma>=!TPRAbaqVkEkX1!-0Juye{SXM4H} zc+23tN8CoAHGGnSF?^HZX-o`B@%XP010F|^3sy7~#ieL(@hnS##Pbp)Z5?b)ECI^P zUSVCjp9Em;CjqWhN0C<9s8us|HmJxRWvWhOs9GyCg@KUqSa;fM0e!~BLZvU@0qpGS zT0U%uu;DL7N7(ZX(Y?d~HB({NDJpldz?j)2io5Ujx3QGBy1F*Q7)4dLEybmCy@lIS zwGQ(P<5;(}7q7MD<5-O{MMFVYrg%*uw!f*#2=@x47Ynp$pOufB(e z*I%z;6B&-{P`)_cFuIMBl(zho@|^$>Sn^VUE%A8I=+2&UnWx*uMEu=gI*KsmF|1|J+ZcYsA&h*P_l44tWDR-5V}>?QX*eTcS}wD4#5A;H1l|uwzob&sqFZ;t8WY`^sEr(L z@=O@os!Ld(!LnMjG=zolZ%V90@Sa|6#Z!4}0tCAQ&NOM!7)TgiFUOiT~S9VVFR0#Ytbx(#^&SOI$tG@Z48ty-7;dt{5z%nI;%ZI#4gODH!ArE;#LqC+VFa!a z6}_XI4FAdaYW7`NJHznSYvL=JXc^#ZEbdq;)(o$`$A0}z`}Mut@5)At7+y{H4BG$9 z8S$>kS{z04fV?hh%9}x5qX*3gwS_y>zNB%HbpWr|9@Fs9wxN-kMZE@hv18VUJZMre z^XxIyEtx~mf7iP2_m`#G-bMBf8O+bvL+aITqf8S{J-x75%Et6s6vIXoQCjO4x-|?5 zYEEu5J{qPh=vt5n(8SfrL9>Y(6_lD4Rl3Bcw0l$G)aT`)VF-FRLz;_81oF?=@zdY_>y5BLvuBi;N6OcaRy~I@BZR=3|KCH1lET&0GJV zg7@`zO8AhrQvbGk29)Ny@db2^HMP5Y3!kFLs!j&MDcE3k@F_YB?C>Bxh1|^4NDnow zj|3ww3Cnpb8#7BJ!z3k9SPr07QpD49n8UyHOEi%lxM%y;EHP^u-LtI*A@&vvG!QY8 z+sczhKcH-#uq}X@Sa-F*+qGL=SJ540Sz(w>s^l`TU>F&sYCC9V&tXLJF<7#qvqBLt zeIV>2K*I&K$Y1|jb^)6xMZqLmD53FSjkFS0koI>M^LI}NJq^S_pM|6bvC8@%Kr1NmlUBSC7&!zUEcZ6A0s#zqWV2RhxU93L&*_JJ2b zY{al7fWYO7cH078Qm_$&#y{lf^!)zTUK_EhFaKhA@{1vgf0_TbmUnU#K2L6p^#NVcZNX=3#@vpzSSF0xaB z8NznuX0TwIU=~N}9iU3B7?bV0CZ2+9WcNOS7y`E~u<(5pHm6$GODRNbcpcRpLuM?d zzqg0Xa;wSGGf6kQBnDh0^&}ll0H!B=-Mi-61Q+9=Yoi!%Rn z@vh$3WSwa+(%Fu-tV_illiPY@=4ko;_qf2;yXacuV)NKv!|N1lz1|sqk7oj6#+|X& zwul9CS|p}==DX%G6do@N^*b1^O5~`s`{F{Vpma$uHqp% zrHY4f&NT2!OIEI?m7?FY1)(OL$4=kkqs83EK7Qbl-KgHj>=p9i1>Pd0Eu(XA6J*2n zjuX&8wn=6Gpthp0{;(x&BswMpDU~!%kgqh1QiRTI;Q^^F8DY#kS(a#?LJDWlA1~C-4tTsWy|Gh}7Y zu27Bp706?j7>27%Z#I*cVNaP?U1E4`NWy%o?GyM3=bN=m7ALAQ@64}DM=)=aJ(ykm z$kO<-9SX0zS*_pC2d9BJ`|)MJrKH7fmaZYb!EU=X$R#aacrxY1V{%@C zMu=XA&lQ+iy`m0Og!g%cAl-~PA>p)$SqC!%l_!*`Q(8pb^`kn&*a#H3s0qSqjNaf_*TBabG8CllfV%)VRu2R_Cc~^ z(GSD&7*q`H%p}&$y}B(_Oou9K@~voy>{cTQgx3E+Y%>#Krq>V+D^o zCK__S0TqCrrfQKKyGZu91URU;qM zSyU%vKfJ;r76Dh9BSG|0&20%r=yXRmK&sltBUDb6G;|lKiq#y06DflF%@%uS;S_Me z5@%g>B(@7nCSK9vNURReR*D%jY>AjLVF->NYrH|2s%X8)s*q;qAL~WY%FfyX%-THD zFjl>wLC-T++S_Uc9i51{x^OzW#nnj_GAPY)(jev4gRx;bM+Hv>P+f+H9;wRgG0+vO zDyy_uOjmTah1I3_yj@XxgADQhe4Q_7pls)h>3q&Cai9!)&T_c(sgQX(Ur^83&gaY% zZN><)^K`x`KfRmbuoSGF0wvh`oM!-X=+O*7r(TYwUN!^LDxV2X8$Htbs8Ug#m^!3T z#VJq*>R?njBZef3x%sG4)vstsI_-+hxZ}+j5!(uJIlOT*@2j^u2nsT>guc^Eo0^=scS(kV_|7p4pJ{| z>y1|i{Ct@Q%ShWjoUX!Z7D{<>UOFx*yNONiG#Ka`Y_*W-k=u2k#5$Y_3VQiqO^So1 zzZpZAh$w0O%{Z;dgjhlrvn&GP&d#5 z!m>We5S6(D9%PttP}K;{gTExVI!;y7x17*4NO5@4F)i=<0R&^xMyBRtiFm2hDG@(X zYF(Uir>e72AGekV=nX1Hnk=(1E^|trsxoD<>O!%`Ds3j&YCGkvruEqGFlYq}O?8_G ziUDnp(zk6d#yE)>k69|0^n`SpE}-XPOWhHqt7v|T-!m(*?R~l*d*Yvxwn&?#xd+{* zl!xkOTX!jB$aoX#QUeTMlWi7-k#++~Qe}Sxi5i+JTK@DQ8%29DncE=@);erqm4O#bw!Yxlj0y~>HiPDgp zy?48Rdrh}fyEHG zTp$~aFD=}n*eg!e$DfYvSUD=kOnSk2INs`)OH`xZmS?!=TF@2gY zax2UDtl3&uA7*QPj;^BK-M|vmuHtK^8OX|Uv<#UH$*^<;2B&u$r|oj%v?BtWjnk4x z2~)|prb@lOwtY|0v(@psQ6V-Lv#41rua(qn9VLFQ;bM#K4pO<5=F0t?&yIVNp-?SpD8bQ@CY-m`J|ED9meuF`AY0 zE?L+5R%1bqdoFJn25Z+$7eT|)ns@|rcb3I{mSJO7L4sOil!62gN2<}7Rgkb3DFq1( zM|&Wcfl5JQTn;P-AP-Fg+R}`S$=BBmfSGPBfK8M2fX?P*gI9apWV9Z?zc5}r=ze_l zx1jTIhD+v9ZF$7js6O6+dc#u_M-9#11d9RqJ>f20Gui5;hE#l?L9;{NF?nypH5_@+ zab}SPoYN@jLv_j$TIFf7RXQ$718g74;T2sW8^1+ah^e9ZV#9F%d&t@B8?tLf3A0kl z*49OF@$TKcNpUFzGf0c~*pd>OBW5KxYpumpByWIh5e>Yc$9Lgn5};#3i$f7Kg(`Jalf{` z6?oVOq%`-1O0#E?D%#?)JgDBPwKkP)jrQzuRY7%Nh@XvZCrjookcX-;jciO66{j-K zZ21{w`_^0amibDoh#s2N1*#3u0J` z(N!uhFqYf9dXVC8Ds=T zwrJR=!|!b*ihAG4Vs@CkvA>4aL=CIQorW8%somNecS}V^<2Z}Q-uP23O!;bllc0OO zGkB16rY-hjHDdSmW*tfAE6&8bHQOnLM4axfUOL&VH^!Rd6FM_T(~obiu_0uTM0rrI ze#2N}*kC~G2AVzf-dW_udUmwUmIApg~Ke^N;B>REgkvBHRm93#f7#bAmJhVa%#>r3HA{_rMJeTtb=>w@h7a(zCs% zMQLVi!I606(8ehHGOOeX1DD~=z-R^|aG!Trsp6e}dk050EK@63VgfD|nbXMot}`%j z;flcoJnW5_4s=Ut0v;M4nN}`-vgF!mi>2#AKSC2(fsZP&x*w%I%8C`Z-$C$QR-~%- zHHwo_=r!>cn0s@tNM~j*_N02Uy~OC!)&lqSmQPR%s~Q}{yWbWZXvmOIagF*`cRdOu?P4WKG<^oXe%p8F9) z|JJ-6jv`woKccT{+iboOv;LFY)_=-&OnJX2iQXS7qC+h??>blfSg z`IGnUH!?%I-A1<$Rc=$xS9;hiw57X^LU%%?+|QdYdDsrL$=!CKJE;;5xXgol*!r`{ z-R7S=u@cUx%#%E9@Y&>UgU{~5gblv=Dj&A+Y;w1SXZK`KTDeJOzT{yG&n9!vA_! zpQ};PE3c~Q*oEbJC(FaPSrsoyYN;2tJCjr01q&A~Ua}Mw9*aFKkEGetN(z+@uND(R z+o(@#vzjb8x!bIGQKl%|#7$6rYz8=OjYUc|U`!8;u-bGhl8f9z(BC*|v%ElQ2;VC0 zI<@r^}8=>Zf%L~H4FV8L7G1xH+ z>(0Wr6u)4@=F4*n`9;3G1#fA2VL{-_a|`~3zP#>RT3!(SeR=K>=mKBf)LU9!5a@k* zPMqhEj%~lmx3s(uc96jaB^B2*+HT^RP+rB&}YESy|+|9;s(RdF6xG&F%-yL6` zpD^DV{DS!H%cHp@e7Ajh-tO?NDKE&`zC0&ow|sftW6)buUXY%Bc}{l5`p5Q9FLJ&$ z<}T9C3dBrw?Nr#X!rfeddJ?RKfCDGVy@tZy(iN4~)O5||5XjJun ztx~;TEfY<*iUqc$r6j_WPo*T3S^wmCx-LQqB|<=#f8^8g__Jl$q-)|stz&aqLQdvr zS4mPfMn6|ZkBiUvaC=#q2zOS)iGIvSq`b#{xJ{iMNf(i5h@=O6L=ye=ulmMYQYKnB zD$!s1h$K4a!|1L(P76j=@2rnVqCfOuH2uDM-BBg|2Op6{U-Mz(u+CCX_nHsk^jkh6 ziN5N?x^%s36X|Yqjv-YVkJkD%ACW}A>cj0tWunfgM8D`GlISTPu2io*s(L@|Ba-Md zJ}ftRt`}>AbEp^pn2$)JPy28s(Zr}kANLVS^v!?b8&{XfTSCZ!XQ-tA;UkjhWgnKG zJ=bB`YaQ-;FZqZh`U4*}&iQOfZ2S(l(>HuX68&2r*0EOCVRh-vP~-lFk4U1g_^@%M zXG_wi@KBb{e2%+^;{y> z*Tac^*heJMCw#b4J=7<|iT>(W{PD85_zNG#q~5bA=AK~|^~$gGv8b1QItqTN40{%Z zdcm-JxD^42Y6J8b8-Q)u090tU{=EDDKW$2%4y8M&LwSShlM4zU^QlkXrsZ(hQ1#+R zY?n80({gxT^~u|`9G+Kw@-{7p=T)D)P0QhV)hBP$a(G_#$=kFXo>zVHHZ6zeRiC^~ z%i(#|CvVeocwY6%+q4{>SAFuPmctk1o|VfCJU?^llecL(Jg@rXO)ZBnjNiQKlecL( zJg@rXZCVb`t3G-Am&5+fVXuxL)M8jsz-T0M?a|4@Yuq_}4BBBuOxyfH%C%Jx#T+wbY!3%OhLPw zyq^Q62k8+xdpBOs>e!?9)qs-%=DRN@3 z78ie_Vg*LyT|l(n2y@9ji0iFD>d z8=kljlsPwsFrA9a1uSYQc|wN<+y<9Jk&Y@``?@+TcC$s@Tw-ObJAvs>ifOVX77dq= zflJx`ASuh*U6`%cusE;n1YbGvt4GEvc%t|#nFiN&en9^->l2MA^|3mZ!)dEXIAicl z9Zf8_0jT&3-DO#%gkIE*nsAZV}TSbFn$bvAj^@%yr#Et)N|q zp6*=1F%eFPkU0foM=4)Y>x*x2`UnI5WbeLW3Lmuvt`4c=I2C6I6G!bjHrulGHeED` zoE(s_48U#KA+va8vnYt>()GR4{y3YYG1?qdX=UAPvez~i2kMAwoFH48ZjiN#*FKeY zcY6;K{ybT!rPMV=h2tr%+rSKa=`Hx^0ZHF+er^Bl98?%%2-(`uxBM;YvX+HWnT_O5 z#g_yNU1HVLIoxiYpYG@!kuk`wqDI|=+?aT-==R;rL}I&-Ir!D7Tn=UNMB{Z(c)E=< zZ%P}zwMNGn6v*fpQwW$ETY`lTFCr>Cs7(8yJWy(YrHXS?dmX1xR6akxZLj?!z*?kZIbO3 zGh<6)+3P3${%nk`UhrolBbACj8&1o5S2xC+4d(XNC(fxaIBzyooP)Zt@q(yh9bx`M zC0}u8Q|I(8N1GX|=2Rc%*cEP`^!u|RuB~s(fn(C(mC8ASpe7}3G}&x=9zPVdOdCP58R3habn%Es`890 zF?IF=fVB)UIGOEG8Z#(?1htm||2-DLQAh;Nl@wohN7kKLLA9Xf_FiHTS!~X$Qz~Yp z8Y!m2ZF8Bk_*U#sa7PfRTmg?b8S0qR5NC|BqA^B0WeG++WDuGI?THRHzUfh-Q+y#t7YzeqbFh#pPl40m{Lo%jU1}O~?S?^?hDG{A?yh*uKZ+6_&PG zqH*lm*#%S^{2oa%WGVA|Gfa}|!DsqZ#ny~?_o!dXfhA*0on1o;`@1fHZm1zelF>s- zeaR20um;9p-T0p9dgsxsO2d${!;m4RlgvF0FxU{?Mvi zjv5Yh*3z0_L}zsi|(Zx38Zo((W~hubGi<~ss6($i4Nu0|2eIVyWO`M{0wwt-b*U1tP1H>@7PwI9$9 z0a%xoha2Omp}R4jTB}4*Np`DNRDRyV$;KgykHxRcEiWax8}742c$@(b_IbIYoEzWy z5e4*n2DOpcn5*ec3hsDz_dJhCQ4-Fa6Q+*P9g0C%>d!(V(Lvp$dzB=8xrh`Q5G3ff z3MJ;ygeQn*o%0ZcmKvfuJs-@3ZwCjFuB{|+3r!)X&nAEj{tZP`v)=_lESY*@s7Ru5 zven;Zofd0wlv$kndYVTy(OpKAy}IzwX+ND&O<46XfOLpG($T}>Ra1vvlx`&jHb3}W zsea}ndEUOxJmb4fna2Pw#0Zu*;pi0fw z?{|{=utfPLTncaiZw=}YBb^|7UP!QX#y_}9JcVGHV)RfevYl>?YDYu$uNB(r5V$5n zv&PYg(&|cUF}f=D%q%^|N*PhI#HBdlio6k*ll$1o!u6Qe{TNNiC!IUt_FntOvVD^s zE6yUbxmM)KI;Tu_7I8J#()*P;B2?R>wW_aAMc|`Gq`lKG?7gp~EYyh8s{=LS%{(;< z`yIAMPIM~`@WrU8gcJj;w<`z0M3{@IM!9tCBaB9LwG!VcvY5leH$+nTFx6GD3-Xu2 zj&o(#`cj(l4Pi@@%!6&%9kAFs)5?JZ4LYgp51|pnBb;71mvQz4 zn#TE1D+Phc)?1F@oX}MIp$fh5TNxKY;<5FnFELg+11Blw!@3k&TpPD->i&Zi^U^G6 zn)g3CJag))iAt8Vj?4o$#tyn z0)_;4jm~e!PGBv0$TEN}<7hq_b8GN*25gH?4&ma^WZoH$+nvj@&Kz zl#_t!+?-I*Bt|dS$r@Y;NVMd@x0d0Ym*E(JmoUwd?$)2w<0g7Sn8Nd~|GnFoe-Y}7 z)-2PhAUZeMR>)<6#DoT~y^_#LWGs|5w;ByDAxVMZP ztWIl$MTxh{O;wQyi1O45tYcPS9diOJP2vRBF|mIR>#7Iwmi{y(u+rX6f``n;PmLk0 zk>cJ=I~Z&cJNq*jNg<>>OP-j8ezKju`e?z`eCn92D|WA7{64bVv_EnZt_jBxVN<>s0W*5hCm3AdJv$~NdRdH0n!oz7Bj~KbkYkTnGTSl&j+l| z**Vb`7h_OcTwH6+y*_O205;^!3yFPBO^w($hfplBkJSk)nXy7H$9X^pdJkakImY+h z1YiN`Y$@tGDTFvku8RukS-QQDMYiHSY@Z(jm;*!~Gznl*y4o<6PRICtE@eY{D<|EY zWat?Zon)RWP}H|lg`=v{s47quq*S&;>J@oXr#|*g70{WQv%l!i6Yq}Pp zX+r9Ca0oitw%TSxuG5}esb)Ugskoy|)ezY@j9>MKjgFrdb@FPc!%T8B1IaWc`>OUd zJK$Ev49SE1IthABkO;~+OPeuPk#qul+l_0dtYKAKtED(WO;*m$8k(l7tX63nwlH{x zCP~bluY~0j&|D}>m~*Gv1+qo(+_g=qp>L`x_Ep(8VFiQw?mjQ|qEdnb`Nn`3ReWK` z#Xo%xg&vWeFzfYCs?Hm#qd`%1F=fT^VJhc(+mMtfE|1Jr5WsP#v!czlrAZ=eSwOli{4;D*_2^jp2X zxI9nd@__OdQ=?m*$B+R%f#vc5XUOmd7Wb}+@F)|b$hwMk`g4(0#IV1~X^E^n)PRY?T`1QOs@5g|a9s_Y4fxe-D_fFKCC zprn#|fyz=9Y6;-d6pQVKip!`U8*OoHaTo1HR8+JTwN=0tg|;0=QVf(O%8K#M) zumE@aA>)*0mLiv$49{l6smbu-lDI*Nc8Wa7>H`tUNsdH&C4}l}6SS&)pNCyd-+7ul z3+e9Qh7cI(4KGTWM;aUhrYKhwJTOV?l!seNg(tjNE=}K2`Qk%)#-&79>5SUXOBz^c zq-K0uTmy9M;>0Z^%wu|ci%5%wFi2XgSe7T35R1-}5R0%?S&a_Vv4U-)*tNj5GL56M zu7Q17*NU7W>srDbiVvk-W7tUR)?G-M3MsR!TwGRiu8er4DY_IaZrME%IT#9M0COYC zxP_@orm^*1iZ0rgr0B|dPdjp+rRYkSPa3AB?i5pBHKpj1YsFG@Df1UYU*IhWKiS|X z9;V_rHVuAmyI>#sbnp{~(EN~uVnn92Qy9;pwzGRY2;MOn5@(&uc|_K^j7fCc61PI< zs7Z)`zE|%C?}R|qy{R}123ke)_nQ45WI~JsOV@f)HUMry6sJRh8x*l7v4h}r&;1;} zp{mWrDMn5nIU6~HbZ!Bu#=TLX=%$2k5CM=?DL-C{F8RngG zoY22A!CI>4ezu(swe7TvKuV=OS#yI$-onJu?U2;P5iGDwTS)mEL^PFhPgQ4|O{acW zJzm^uTGlWUUMd%kwiT`^>ov-YvR*TPi&?MRZU-jqx1(>RPBpfgKN6=~ehzl7cRS*` z3`*J&w>?Yj+*5PgH_}p=1ZqjvQjeCNlS<;wummx2y#r_`dyBM>oo&aI>~g2<$@~H+ zw5y$G`gd-YvD9fjA(I)&Ts*=3TZQ@>RcDk!;@k*n3*#P0f2qt@?bJhFD(zpatg%_1 zZsj-EZ zob!BV(qAN-IGE+sS|MSwj?YQW(pklx+weNn-df5Wk_OpPcak~8HfLq}GVCdoCy%63 zF3m~s)p{>q0sH=BV`hqUF-KWy5KJ)499<5jlGN#JoC1)S_}V)nYYML5F?vg)GTW|N zjmm`UK&tE%jmVjWYeXSMSt>Cz#tzY2ngKC1m``fN!FCaGX-cC>D4g>bhr$VSajoD@ z4uzQ(&6uBC#oc2WCrF1QKzDc2^W$F8DmH2sNU+gx7hXOf>Iz&=k3<^>N(xREq$khXmhGRs1!QOX)n~&K-US;F9 z+32BFCj^Qa%ly=im{QH%MXBW`5<^e00Ew>+fSizEYbpCX?%jo$$_^%dbI_TB~q}_%r2rviMiwm-H3Cu z1sh>Ilfdr<&;o6t8;;4GX0VOh2p*6@+BICefdXcP0jGkZ8Os`;ghFMtnw!5^XJ~b@ z#kj_cI?3p1QijzUs#bIjn2b|pQM>2R5N3>Ujt**&v1KQtZZe9-I@co%VjAm&t2FsM z#6@h7u{2`!>8YI!S~JoKIWi0`ZDI6MY*p%iVKoYqUT=-WSn6b>bm(Z0@E1l&oNvYk zV8RTYg`XyBLmGa{(0SSoG6u7WIgs7MBoo~04n4|G%F2C+SVHG)h>Xt7;i3hPLheKg zAa}A7kS|$Qf|3c2Db-U>MoEmns`;IhEdvEJunh^w*lHP=KHUQXg(VKmE7^Z%sF(&7 zOjGaJsC2k_#ad~#X9gIqRL;V7%}&XT;W{BFfHv?WXS6930b~G|$0iLTW8;Oof!}0U z(43CSXvuL+zb8*?RfPW00J#reQj&q*!-XStF@lOzHg_XP>uj#+VYDC&C4Sayzuoo? z?8u>8L#PLN%ZVS63xbzPZKKuz`ICjaEl+vKFG>??Pg&fF-HNT1HuBoY+eCuRBzHaG zP!*~WMN(_!^^tj^hiH>goQ*;cd$oE+VK(%w&pHkGPfr`01Bia zK~$Y5c)kMAtn;aCL?4-t{H7ZSVCM!KS^EN-I>-ZSV8Z^QJ(X^W>AGbLkj!WSbO>tD z<3;THLsCu%Z9*fou*8w_ltze{cbI-ecMDvnGydu;FcUix;JZFUjS5UG6@z>kl%P%6 zVz3mMGd?rkRcp3yY$d*pVQDt|iz%%WYbbe+*UFg&k&OVf|i+uGu`PY!2l{cKmrW+u%gXwxYRGkZKYklEV9}%(iN&^Mt^8Cq)EHOA=jz>_`g#F8Efc8qFJ}BP@k%X+@9*k-=zkJ4_RCpvIS_G?`GPHkp(lV zAK#PJkj0H9HKa+^rfNeT9p=Y(QiB@{UMx|fWnK7GHRKUue*A$94oRF?>TJjq%c*L} zqs0999a#-YtXS$4$aJ!)YRJRJ{P=a$;O1r)IF`U6weU?k$RIim;EA>huWnDNaN5&m%xEfG7Y&8Ux`j329A;XHH+;mWK8wrGL-N z7d?DO0*|X#u@>|?eyOtk6M`7Zq$KhRVR;zA!}vGo`s~Le8BKz`X@&tJH%;fEuB4ok zlu=SHNXp)%Ty15zGx_5!0ah&q&rp^57`brzt~yt$l479m-9h@gP?93=RD-0fqdy}+ z!yQe3M-&ZNfy9DSkKdDvF0S2eX9RrcM;8HNzQVfD;U!O#k=Me%HcMnzv=DD#!6h#u zdIDrd^qG0ku7DcT%1LL7#JeG=PjITdX@hg+@{mDu0oQo4$NGW+DHQ!)rlaA{q zzkDL#gOG$l($1N^s6?70M63}DBYROtIyBnn!@>b)=U3KgFE!belHmlSP7a7fU7$KV zJf@TEdfNLus%pKX&4-SiQ8_!A&6X+YiOF=xU~;S|L^J?xsPHWLFW055mopvIxBXQ3 zA}@n-jzeGyUWSJhn6W@rY1xxYTMl|?h7d|>o`FmO1r&LtmW!py>7+iEZ8WeN$Q9j=wYTdgGKN4}6prfwy3t>~3v6!Yk<6mdmk z&ULEH#$^AOk~<|zkGbj$ZtjZ3;UxRdyDQFr5FC*t*7~ zuxi<;yK#akB2~1Tl0|?W5_3UlR|<82y$S22P&EH{Q%$Rl1Kj;AAt4Hi*#&);9Wz5d zS(#7Bmyl$k^5G({hS89xpui`GwVsOeEI!9wi7K+)T6JJcf#gY9$=8k~G4iSWU}%Z)T4IATA`Qh6DzMq(ZgB7u`!-7jto4mRD^Plr12c^b+k^&nOjM z^Bi|&awl{7-E}gN++B51=*1ZJvuU)tA93bUS2PrW>rv zEEWMvWjbN*vNI{I!=TKPLbs`F@{1own=@O0BPTK``n-!KJy^<@oJ0Hf~TR;n@Z?T=otR5>7)C5>jRsqcay3w85L<2d^n#Q}R?!ofr9#2ad zpfDa zW|m(%fiM!Wb*GtN6Ce;@1V$r$XP&&cn}1i8-zwk{TAX=b07d+bcj%po(V<1qvgR(V!BC}8(p=|kG{0^zv+rD|&=<$>2gGKwy+ zhGI6RU5Y9F#M59}DMF`JAd#7-Y8{~MNUM%W&9Ba<8UmXN{}Z=Dq72pqqn|O z%fEQLu{CjItU;`b3{#OCHxmhkpcojUT^b?mlDwKULU^GphI~skBmx;oA%zTTy%9Gkg%nz8 z1ZHU`XkM3_nbe_SN~Syy95qrwr=(4Z0!H>tJN1y2MkI+*){>cmX7i12(j=#UNkLo94N||D z7@6b?4xo5tJNl%CHnB4}wbD_DaThXDC=}UOGqiHT+8als+O#~-BK14(Gw!Pv)06nl zZzZQRv8e-U4hH_T+0AOBt?Y5lPB*(snq44AX~TWTX)^m>YMs+~xQGB)s6-GmO5`jE zeuiajM#_Lv+LGy^r+yzTE_2lST%z!sd zVXrIbS&9TEdnuN zwsO;VcS0Un7`9ITHci5H3_Qd~G1WeZ)5CX+7ECDwiVjIl6q~`aDlH+XrN=*8ali8U z5^}6m4*aC`k@B^Q;8GzLFrhl)50s6Xc!N0@JLRIM0iwCB^+E62GOVZ9@vGiY>Uvqq zThkywS)w4PnV_PzF}m@kDeFr$|4cZd<7RYJtPOpOVd5s5UMC4nHk-0_HrYIvP>1t7 zy<Qp2j*#9 z6{?`cBn%-mm1QVo>{AE?jF9h8tO=iOT-SQ6K;yi!FTUF!S?iJ7QZ`pAtTA|^0%yy$ zUsa~f0tSKS5w_e(EU3A)76X0Y4ka56(V@u22r}4&To+7t!MaF65||-ORK(Of)&tqy z%mfzot;}Tsa&0sCK@kNyWApms_X!K5I!y)(#UaXCaAcWzfD{8M!?}eR&XMMUxt+7F zon2=uSjsd9;t}b)IFMeg!IuWhT}eV1q@{_8YlOtINNe7-r_&4jE#PMsv9=*4eF;r0 zV@t$-%iDn+V-7Y4%~69A}7 zD*>>$M>y5N2tY2K;Zmy5lasnb5ZzmU%e|g5fe|$XZowolmc(s4S&Sc-cDbJ?dfL`M z`tk5jBJX9l_f(B)V>TXw%KBsRA6`+~xy18M^Gtf)12&qyeXZ>Se zcyP%ji0_{Hc-n5~W&h-D7MW;zK}mIqT*O*@@7g8qHdWRI)y4Ov@tY!zU(Gw%S^P(@>B>t zuv&;$SV*Wsm<>HF?6d_veo!I*P%s%i7G@Top8ZMf`(MSVwJoNQFCZR_$EU$U5*6IB z5S%mdm&oeH!Q=reL_ZV?=WR4kO(Mla_-f*t$pFQ{eIn7|zwRT!6b^6qbXiV0I}_2x z+`=vK-S*pACKWj{Mes5#9ccy#iuXzVN+~A*WXjIsxrErIa*3NWHg(d-GJsql60q)B z6Uw$T4pm6`B-?@*-K-VqO5vvUpB~3X|8e$_Q z_rko2YA!9}jpPwwD!}1VxTU;=2}ruddNQ^kgZn|}8eJi+9J~yFlyB&p3WerTskrGQ z#+k}V1;Z6FnW_SBho%qYPt>&{BHKa1Eb5{FgJx4m)S@tTn0&HY2w~Y}7o_zr6xP=N zqC8c8FRgP=#XG?U{1Q;;zJLOYI@#ne&ZaSWa`HO?@i766I?(~Tt^&S>UP7^T$ygYs zN9YKkiuVzTQMuv?@EGrtQbbP`&(x?PIX+yMSTvM2IW${_1eFqmljY!0I*~ky$I=AY zsc5s<={_UJT%BMFdhzxC7Ktc&hzsBo4{*B#nOw?;ug1S48kAZX^`p~SlrdKF_H`7EN#!50P`gaO&WB0|St9BwmxfDWBCGd(Cn!VE$n)Gb~ zx}=;QsA*y)(fp?Sn#$Ib4hrVJHb{bGiWYd9{fOgy(=%4o>URW|H&aTwby(M#xjph| z#IqIbg%{XZXHPgca>+%}putrw!*+rtlU+3e9bPEefo9PSR_b(z>KgD$c6Iet+^FDD8xURU>Iu{qHC&skQ;`7VqG@DiqasdH_}S0(J4>w* zq6OQa8rjVd7{P0jMT3J$pLt{l>Zc3r*uVM-lEX7i0SzWAp!B3kyU_Uo6i}xV~!DCLC=_pL%veAkN(oi5;shGT0AHh#HSkf+uyeCWc zS*!2XTOPy~mdj#kT2+hMGoe?DR1{{?Lsh86Q0`2_!1PJhqKi}Nkp=-V?dEAMRmeQl zGkV@7IJcZf`IL0e_oh>_@H`P}dcF`|NI)BXOQQ`5kWh3X3rwW_m@O%ncc1_$2#J)F zS89U0I0*((?zquM(oe-pg`n9yK2!RvW$sd-X0wGpzV#EO_&8X`&6IcirGgI=0jWjo zF}4iHazZ$qMe{&1N+|M4K2xIMw1X@`lxY;5hd(8%C4qBfOV~xYPf}n8>Oq=v8&M+3GKAU@rR2?=X7yi{NRJ2|ExOF2TsaWu2U#hEr4&*Q zD3noxLV;Nna(q*0fi%T5G=?b*oUBfE$=5AX7jJ+?ZJEjt%EZcAumB4;E91x-!#|@> zI>O3%4sVz<-7cs$w>MsoxRY@Rt4IQv6t$W$71mJ}mRP%U988LByBC;%iVl4b8* zJd6N@ek8bLL1|Q!Hai_^x8?YKx&9~*lb9!h8VAKk1`a&p&IWbauF8t1PNEvHb z^{M$x@LRktal%S#P`up!Nh3xS2CM4i`PrHlO0ZfWS zY1gpm8M;t|DA3Fr6qRNM5acj<8=E}9NCgCJ5gKb#fQ$m;0t+*$4Jt*YoN8ye<`g2F zAZS9a6^~ayc3Bh3JeZ(+;X#*nN$<1pUQ8T3m?JmV5_>Q~?(9K4d9)KZ!+ekwFEyi3 zjmb^NJk}ZE4Cv!MZTL}BlZ??-Ex}djwoo+8Q509fe#r6TM^I2Q$@wV+HFp&XpA;{P zC74IS;6xO4t*#E;>S{ymg(>pd>gxJ~rJ$|Vpj|*;8#y?I!&{2UdDo0^OpX>Zi=~qG zVS8DiJO$IDqzO2k;j)VFD?G~xXNtHAa%DRSucvdpauRpFp!HWHCWOp&VycF|C|zyT zMtq!nV{RE`g#a;8HECY$yYMiPf2@K9g;l8;F4mNLpzDPx$#s~K`OT~G!}l18z&NTz z;>?(}&@GD7JTg#;b&}X4kA@6T@ANk2yR6=#e{Q=tuGV@Weelqzva9PRdMDb$;soWQ zP+C=#5>d)yXmA@VLiio#*Cq9lm9`&w8GJiK!MG&rcw*eEn)2`@abF{V_-2J)%wd-p z!SKs?@q8|JlCz{4v2L8wQ&Mo>?_WuU=7=tu!zA0|=@2wmNS>mlWw{lx5$a7^lb{h$ zWF&SDMonZaRN%d6zhp`y_>z01gC(+ED4{6e$Ml@V1CsTaa-w-i5QsrCBjh@4Ilk#D zNN-(pk4X_J70ATx;A}KQ??&u!7?X~k-Ua&VrsNhOuWP7eO?ZXxqTreQG$HOFB1g_( zun?|#ayUoa)6Cy6410$cfB#-kOJv(j6`_$TA;{xWEul4X{(%`Ft1v@pY+wt`{_^^l z0^h$bzS{x@90z)$pU4E3?Pb@D6FfgSAuN?E)mmG7y`yu+%&u979X|VrBafPM^f7bi z9edpIQFjmUz>FDBTsLA1cKLcs^7Z(u;&qd#}E04fE(<&{;BYQ)*cP<)B?uz1qB5g$l4=~n7RUI&9Mc&B_+PZ_A1h4 z@dd7QUgkqlkrjrZ`zIMx(2|O^6b&kbD%fw>jZ!lW=9I+5mS0Nm$$}d&|52p^9dN>P zk_#EgVaT)d()nodrioBw6f*+s9{zUc*g)f&%CUjrz(|H>5=_QSjuc`EDGf}`EuVP$ zhVGAJCXOP__6d&JccvJ#TCPRHPc%i0tym=Ov}AE9)#RFweZ)sdn74_kU69BTY&=D7 zaEpB*(M!P!AY-)`-|>}>UGe>&K6Mk{zy3bHmp6@&hsBHE^{e`>_{Vi!|Ived{qs4= z4}Wr1{H{maH*ozu@8tT7{$z#c1)u&!`>wd6J%iK_?Ow_{${WYjjYK42W;M(0Ui|(yl;Q>P zZ}|N4Ab#7MO7X`6UgkSJm${jx0kuha2(cXLG!!fM6bgdn^9Q~s@}|XWqH>t@Z^W9U+^DDjX$~vv6bx)n{u6)D%6z-BOoFj2Y;nH*6T`cO$ z9^C3Ku~sg-wA)=GHFS3A8h7bcetzjD<#n$Az3-*z(+dfw z*xmKC1t?E-d|(=u9*YcQbB4{`hm(k?79Bp9(5BL65_M5TGjxVALT8U8CX4RF^*pn% zP0MKKV124{i^Nq-RbUVDtDJ>xl6P>swNdTioDn8?W~3xlqP&!)ZVT2GyJvF(Xo@_k z*zb073mU}rX`G<;o|awiuoMdp5GUA%ke|c}R-L$k7(E5+lE&A3ndKIaL}uy)1Z{Rs zX<<(0;+U%5%8i}(%&$r2^@$+f`zB;c?)J?GlO}`#U_1$9ejn~)>`z1 z12z_8xXDH!hXa;Xg+W#N0){TVhD3vUDQ0sufn4TlP*o<1h=P~Sr{JXvC}`J03fep= z7v}rJpww!&C}ZnC$El zUemE=MxlJMYuK|U&w5P*N0XzHEw?ofGCE(n*!Dtf3o$QP=v8}I6?YC1kPO=`*V!I? z=qVBl{P;_(0H03@|6aFYE??GdaW@`+Rkx2^ESky!N{5}&d${VGFWh|(h)5Ncbfu$P7Rs z4-!RY9z8S#M;0Yy#0~=cDA?9$a}vq#GyscQ(}adL5)DkoJy~S16$y9E7*XqC?WD3^ zfB>X!!#*R!H8*01DkvFBd`>$_bCOX1G@?FO7gZU5hPb4~nilX*dx&i?Ka3k0Gfq)M zWfPk-c4+vZeoMSI28qEV_?0T^ZU~`Z%o@|_W&5FFav4vSvlK=5;m<2>#&0GYqEtnD zsBXNA8(%ir-2eCum4+2&LKnX>JAv6N3x-PYCraft=f)w(c8Vy)5 zP$xRL**teQ!qm-zBwJ%`y?3FdnMkdWmLM>lMq(TmCoNkZNGkIY@&mwr@IiZLB7YRuO+puK;};F91R1qjSffxIJdW{9 zR5A0YPSLDFJ!kS~PDKtPC`nMF;^v2?de@{P39OzvW@{+zTPVP#_dtgtUqCZdo~N3tzu(@D)9k}!2c%ngRFDPjs?K{Evg zSb`7<&_+G*D~E+$Bty50WN03n3EM?76w&PEE{X-J1h{MIW(alC+eAWPdqt9?w#`pb zok331iz$nSr&i!Eh7Y2s@VL#u9)^TpvbqYW&pwiYqBT~u~&6ZgIpwf}j>SAm|!JDErP2J2L(_U4G_)&=X zQAi`E5b>kH%X~25H(Nu%iVr9qq7y_ZTqmpsqyiY$|FbkAq9zzsA#ULmY|Z2yR;Z-g zWf+iyb+AMpll(%O876&v$LApQ8bLuHs}vM46PaTzP51l&PD*uc;(K}$hAHVN`C2!> zzzLSf#zdyX31`V$N^GpG7a|_8U_=}kL^BdsTwuWbjc@u~K~PFP!V;94I$j{8r5u}B z$si<(!5%U=r}(rVzuc1$J8$9?M3$MC;)=^!@;`%CTxr(3532m+gd>%OSYXcz29_db zOp9UkQO)65rU%2QNJtU|TDM1`b$fx6O``~WL37Pgz1rrhbRW%i?!fSv>EjBY)!=0U*a7r$Q6I1z{ReHE zdQ6c`;hHaNXf-g`zwFCDW2PXfiJ0L)0j7hN#zo^3p-j$= zAIObgNC+8#>zrq9d?;Gt##e?v@dkPGp+LDC-#0ft86;ZW_=>($EUUd6b*9;kU+}pz z|7hIf^tmU(rP(1e;gXq~<*KrEC-wLEMtcI|oFX86kC);Tfsw*6!>+Jd zIRoLv&V8W49A&FVv7drm+69SDB}pMoA;TwjA*}~QwnTArE1LDNMJuZTxg5!BIh%B! ziL!!c4%r0M24KbtV~rEU5b*NcHeDA`r z+_LJn;If4=D*Dj)<3UY^)kJVhwvy>7%MN2vXSGX^Wwe~KG*{7OWf*y;znf7A6h+XH z{fC!f9uTjWu)_#R{sD0;iJDA?3hFXJ$JTvDl||Y#M@~4$su65t;`4c3*}}YJ)TvfOrMOzSY{K^4AGf{-Z-LS=4p`ydYKXuz6o0t>(bR;?~&BQTs7GwB`Dk?`Xq;> zb1K-w2^y-Xzab6XyA*~8Elh8EiNsBK)2qBcBmCa57O|rE)6-kgO zG5gEu;0!yW(wL0tFF$EPzar<0{(z{$Mt`?MH@j`iJTxfoWj!y3zu40&y>!bs@_Qti z8Z3FDHHrEVH&Zka=_jZB;feAD7ABtQ}~XlUG32|0ZnJKMKp!#AdoZLy+!f zS>d44L9UjpOSf$VIq*M-?~B7O+!^1cjsNr=z_9sdW_VzAoiHhK1)J9i(H3x~Re%MS z0F*mr z;^q>ehrCK|0X#zMCT`;AYGyixx%UZgMVC%%XJh!|xW$JyZb$sTF>Zem_$?~}CbK`t zxCH5gvcJsmqm5Bz;5K8u%=0$U;Av9U&2+B?B+NHiZ1{G1`fWW~-mu)q?|udIkceSr zQCrRv+Eh#vPT!otPv68)dMOdULHXRIM0;^DWRuWQEK|>?nc%6FYkeea^+Xm-Xhkjo z6_@T}%p&0uN#16;Ao*4B3VN-Grn^JuDP4pP?LmUZNz90o4L?A7a0WV_!yd)=MG^r%m6V2YlFiuW|S0u?a zIYeSBh{|RoKQyiZ8WghYn2p?=tJ=hspz>xL7FO}M92l!jqKC|@^@koD4m>4gV004p znj_5cI21;kwiXJHHygAkBH*wM@R85KoRQH+d%kB{%t`j-E7IgLT2W#CIU! zMZSWbagv$fVn$ z{0D^1S6>N5&Qp2*5jF+9`T0G6gw6iul-A)qEqL>`r-$B%bv-G>=4qQy|Iq;Rw9TfE z`z(=ak=|Rpbx!Rxj;iIm$db0Zs_l{lAJHyJSdyfu>g+}z<^pGu#AStiJBa8`$cMXFw{77!M{oPsQ=7Apu%cm8KX2U(Y{q4!-Hd1 z#V8PPL@6!ZHp8tTa7)`Q`CX!|49F~b$mK8mLHm)|4`wWN7D+Q+rk!;X`>pEiL1(z> zV=mU%gh~WN%~|B?I9Ml8bTAXlu`O8|$F|R?OTbJ5K2u2`pVUnww!hXNY$(iD=bT2; zOebS?Go8wjGzl8e(paDNsG)F@LM5Y>wbXFBKqeC5vH$9DX6^4Me(-ZEB_D4^%)$fN+PY-=rv2iM} zg7~>~@;C+VH$kf@c|SHArmk!@V3vz_qR4DE7V|j`GRyKMg~w?Hn{72y3D)V~8A}qM zGZ{NzzfHlN;w05s9yHlG%?PG6j{&~JfSAS1*b-p6&%zCfGfaN4cB2Lt*Z+vAA+#1E zJd1SP%r8$Q))qpjSX+E*Nvv&)`Q^>N+bA&@L^Wft&LcuHB0`Of~(XxEYCT( ziF_K|IHf#<)fFOMV3pbQ!0eWZ@o%-(O@5lGF%f$QCf7{{O2>2v*A-*rb+XDqo8>gQ zS%zFzVmlI^7%w2zxee2^JV$r|yM^J}L97_2SP*@Tvr~gchVAWviVQCJ!X`b^+!LEX zf-=C(StNNhsDyP`=9R}$?^`gUTFJhG-?&#PfhLU%Nae;Diz8U!43gL$1!*m_5>{qj zvjaAX^^HNdf6$ia{wkOWL6jCf$xBiv4?zbm{)AU&L26O8TcDJqz6izwo*O2De1e|^ zeAVzdbB4wG;LyzTRnaB|tZCNtq`A;6T&IvQBk}W=X9S)P?pHcP(J%p7hCAi45{_$@ zC`w1)Sw7D^hO(3>Kw~!_b%$C>EHP`Z+}xysEW;I+Ut!*RL@qm?@alE-{znnsHpFF=|dcp>pq9LD#K{chk zn%}W+No<)T-o_r6rWNHj=mf6{a(XUWP2pE%tfcQs3KYRT^kfccm(5aI|MnDJZl+HM zrL>6z;9Nl-Q%)hS=g474p&O0pE6hQ*;f%2H(A_saE~nTO<9Hf6i6$ZR z*XDmW%3v{x48VhPy6Nl1KQHEvsrRV;y*s;JOkwOC9xiFp7#(ta*Nf}l_ot}=XMB1Z z47x!7%{d_eK|+e`*dxFxq50_)6ivbbmS{>)r)es$2?GY1n&%Pv{lk9XAJ7LQiYhte zWbof;-84kcYypDEsrQlf0Qti&2g28#qumfO?d1JL`a(@TDeozG;`kb2GSly&%@gSN zs=S9LbkoCsQV&}~Y6=|a3H4Bppwjwhy^{Fo(kr6y>sI8=k z0X=#%gD)c5JmjF2ZQ=Ih3^*g*Ldza}YP+UhIjBF~9ee1h?-)oTG@eAZn7Rd1K#SHs zP4<%#=P8ElQ!`om~xPW`x#^#omuK0nQb#s}Bc&%`zm_vw8y9*~yn=NBgd(^o}c}DrQ(|)y> zTh}dhN1bGeG3<)REwyCSj$&gAV>_yx@x2L|TlLQ^WiSE>Q?s8xQUO-FxIsrZI7xdWE(7mUp(}9jHNE8-L zC|6I7mH|bzjA8@leg{&#s!f4Y>m-Aa{n*}F(^LG`Q{~s5x+I@=wUR}D+DkyMV#^Bb z2KD&z%{}b~m$taVu7Xu9WdM>|1E_tASSqS3JQ(mGP1Q|$eD4;XL-}WjJM1~+s&Y&g zCIzV}itYRP*9Z7&kw9h3yaBi524&49m@U5Zb(|}1jXTce)nzRaRf2APl~-Y_eUm)( zJo_eH;sX07hP08pdf7{{9(AO43*b5(vu=&_RGqn! zj+to@qg`Ey>cD`(f&Ci*OKY5KIs$%q*6|{39?Nr*4 z1P(vXp)(0)?GAi`nHG8gC?a|UsGDDZ5I|jNKoOuE$QJO;flS#T9LN-KRRCE*wRb@C zoxa?%tv4u7qSOkBH0Y9bWa?pdSJxv6tI5B+`5;Yp%~O+I^VH;G^YS=4*Sx?ruehAF zqp`z>}-eRUT<-5qE30*25XWxbX#(*L%1d z3yb2F>Xt)wCQCk2&B<9tuy8=tm7WJ5l3N6juZHX)tB;18EV@z{I~*DAP!^vK&SuDf z2z8b@ksK-_bRD91^C&P-L}`T@X%F)0;FP}~?Hz$dua|Kny}R&w9H4qVA(?tThDC7! z7?oa6EF`Z_AF|ES>km8~Lc!B6!#yp%vKY}IqgGG7WLig8fcl#N{`D#Jk%9m&6zM)> zvs0on+p`7RQp9`l^<6d@9g`@5CumMWwmM9jNV7@hvrnLZ(-GpH;vUT~jmbMET-V`Y zfVl4|wU4ZjuGC~Hi2bM79P+Ix7Qapx{iZWKG65i21uZuJg3e9e29NtFoOS*nK9k(J z)0@Wfnn@lVKos+U5ziB^<{sJ1Al&oOK*K!Z8Q)$K^qfUJ;}ys~K{PNIVsb)`T-<%I zj0e^(OJ^`C_Q@Mh!V6X*O-Eo1ESo_5Cg)OJW~Y@cRM|A{AnaMPh7CWsZc zCVLVbl>b^{+pGAYFCZ7hU%wkSJZe-iaG)SW7}Aq7JP{%i6aO?CUO~Jrvsc7^Yc5(H zrxApZn7>^#hx6vGkkW>^*ohv_`I+k*I12awawF};3#wa~yS(lI)7WJHMKc-5kX8Tpplo{fJOYZn{Ddf__DT-bvQy9m2oSs5%n z5)gwi1X{Qy8JG$KGfXPPi+rif>ahNo0qZeU2|31QYI9u1jV{K#aaSC&`Ecaf#wzX? zNyxm4C4;<0$q_K$x>O4RUwYW4T&4{iaBO%LzYH@VSzLt&445)8sX|Lg5&M`#qfoby zD}(0oz7pG+^|bAZ=Ujz^Z7DkRDjC7r_L+NJd-sglhPsMw>-Mn{v0)plU`g*(H>0nr zMXc`j?Lj%n1iC5imgO|md&q}MO*EPQSw^yuM?r+7dkO56ktXk+SAV@M7}Ps+v&`8= zNa4vXt)mK0X^K5+(jfGB4ldLy$oT4ZsG$jCpR6!?ql-h(QZ({=dFqhDplBj(GX*@- zAm$bO#ft0g>^o>%#-Bx+?)Be$&sT2y(f@esU)*+Gy~E4*X4g;o#_IKue8Wf6y7^Q! z-^~vpT!}96@+0WLd>5BexXS&()c2P#8`bN#T^e{YXV&k$Xr{-iLXHwg7YE)L?=X(T zIrQgq%;wnMzk7FMAliCiV|0A?*xI$@LsyUV?_F^6)@XPr>K}@>o;5PEHQLv|d%WQt z!TqXBbsotvIZPlftzN!*#p;!-SFK*Xdd(V| zxQ5rSq3Sg}wuVd1cy+ws!O_hzB{-OentTt34jwOMFa^W({07c7Z(E)n-95Oyv1CtU z&-N=vs9;{nxA$Dhy_&xx{XxH3z!*M6~Ynl;)<~=qjRZ4WB+2x zo~(|>&_GhdEnF8ZNq=|GyV~tdqf!5u!!91O6OSzF*8Y1aH75~M|F8bhgeUmNI`#wn zg_HhD`YXI~aA^CmXuwz_8Xw!SXmzyhTE31pt{QI)ZEr+7Muzt!(DuAX%D#6B&khbj z%LfON2eNw^ID2}u_|%+=qv1;_HI^@2ym;}8>>UXfFx#6bgT{ZW=RKeM>)by;DSW$? z`Kj5yt#QTRP;~k;BcZ_peK|S0`by}C248fIXWzmzGr0FXl%MGMr-QR-KV()K(=T_;l4A1G^-m8$Pm3U#;6i?I>$ zHqEK!+$$PGVYI2`-tnQq?ZX3&C3{B(p~%~IH}n*=jt8DW+0G%lmY$0@Ea33`uw1TG zf@-B!ZJX6TuYPpLF`ZpAI%bx-!ov)z9Q>GNKD^DXoK+l-l;&;9N17B6|$ zWiPt?$2Yz1^>2LB2R{Dk&wTlwul?N*9{K0Tywa@0PVQU2YVB#y+;q;1ZhAdG{?(^H zbI;%1d*37f?3Fra*sp6(J8Q$Hb6z~qxap05_Rg=}dtc|Qlex6%(idL#;>!mbuY2PM zc;w4p`{5)1{AlN_vo;MhCT{w~U7!2>cOHE7mp8uRweNl3=RW`CuiW>&f86-?&wlfs zd+*zH{+3Ih|KiJE{rWe2{BJ(_`7hk_l?P`XdDIIp`}M#7;jxK5SN-6JGmak`o_Fl! zFaMK|e(bu>+;!wp#~r`n?DMxg?**5=_)o6;>n}g>o$o*T%YPdgeZ$!JTTfiP@bK>UG4R1TTe#EQZ zQeIL%ts2aj(>C$Bp0SRJ?;g`po_MT0@xzXPeP_6;?fT1RPuy9X_G^FFH_n;Yeq`IZrHR*6KJ?y>qe^|Zm9GEZi9`;RC*Id}{l8WH=#&b- zzOFR!xo~bcv(u~iKAj87)oM_ywFT|uOrBBd@@EByl@Fga+dm>WDmc1xUisMC@d&az zOS^)Pg&z;@3hoQO6+F=Kown}=4+h`!A1?nW_(|!f!7rjmOTP*JclcYs2)9c=*K?0;^D(y`Rdod zD?>)%;`v(!8khaeC+E(q*4pc{k6O8A?fXCQ&_A@Ty5)`UueP6d#*V=^ylK|(<)8n> zzr0}EuYUK~MbCZ5pDkW;(t?ZM`R?2P>w9m1|3^N3*Ow~wjw6m;`>eB`^S;}^@y&Nv zk3Od78D~7}CqMs}$G%MdfD@i^;(}$X*KR!L+zT$c_!8mX*6ocQyGE~h`E{>(?*~72 z$KCgT^kYNApL_F*dtO=&ON+uCp}%DD#0|%WeKY5k=C>VJKDB&iX~roNAFRwT%`Yve zEw7*d?CV#x9ob%+bJ|&J!tJ%T-XqK1;oP#nZgpvMc}c0g+E!f`omA>*TN$n`A5$%L zR4>@HYFX#9>f&1a^(S7q`PAAeM;>$HyxB*!ozDx->^!>KUfEbXscpQz{)|&9rethGS#vkmF6!J= zZJ+q{hW2B_vp1~@XVls&YpU(nuROYXS~%|#f9BH88~<#_czxnauQ_*n=S{s`N50{M zH=KRjr*2qNJ*9M6<;3<4?F-6>-*CqZ8=FgOssE&oBzKU(Rx zcdwe?`J+`In$f>z$(-BP^v>(w_`i<3?c8827h*NB=ms0sk`P^!}j1f|1_TM;K>D4Ppx4Ya#3ZugKAZi zcxj;XdBGamm%im#f1_XWsobym&+&t5M{S!QwAHJdg1OY^`>SU7ys=#O=ePMgN`8e# z1xE*^u#2p%K~V8$`oKOsHaL#|by!epeo$}op~L=o(Btn5+0faqg#QQ-Xl+$B2DM6i z;P)QiSL)@w>@OgNdPFDva5X>jV7Rsx1aA*X>0i|g!{DBEp8vPqUidnHYvff11Fz&0 z0eC?G$ENK^2W9_l!7+z*`X|01z-+_`e?k3Ta6!1C-dB35zjEfu^s_zeqt2@T%y53$ubn|m z+wwN1f`54^Py!VHoqkw5!XWGWNBT3WVfk-s>daAsDr2Sl{NQJ_twK3BxVWY(I|UDZ zZLoioU-sJk;NKW|Fv7ou_mzmbTTro)ss!O;0FKbZ-4`B7Q>f)76dq;-%#$(s+MXZ$)x)61@e?T&$erSyF3*~x!JX;@U z>frYR)7gfmv$LDd zHa4AYYC1co>1=b;*}2)-MU9a`1oxMy%L@?iht>I$Wdj%<8AIuJCYVKn(AwyV#+cEr zC?2_D^vuR+;n{;c;LJcNY>Ce=lbgdX)wlwX_h*`{0Gra zZo!ZP)V8O8=-NqLh^>X|?ep38d8U1yWuF`D^KARvXrG(x^Bnu!Y@g@aXFdn*G@pca zn$JQz&8MNA=JU`_^NDDu`AoFad@9;$J{RpYpNw{z&qg~v=yaSG>{S7rdxOMKG`BS^bgACF*Y1+htpv)8){q~N!E|{ z4K}V`GCn%8#723^b|~cVk`c^S;Muiib-n_^IlgT%hPOq1jqTf4E?u)`VB4C;_SH+5 zElFFt=<5E_J&Q(07xgag>s{QtXzxg4ao=)#e9!0=*!*`N)qI^#C$N6xDPk_ntsK`+w)2 z{=MAz7Vgt~i{mBR-~N188zc!vCvDjDytAJ7+`g43EpEE7deZswN#{!^o%dzuz;tDP zH)qT8dpRq-iL?AQxw0P4N(~h5u9C|52 zU&GFz8TrX3fu-rRZ)MZz>iq0t>MY)@^Wxn)FWkPtfiZvHE)**`=b|m==Rd=HXif2a zsBpqOX!I8@Y%m90e#7~LyYrLt21iFFn~z|9AA~1II|duO2i8U>;Xv7YtZ)9nS5u@`o`VYw)l*fj6jpNFIm&OYWcFps-s>W4(BI#?9hX}F@_}V5dzUwsuGzMuv2Ep&)XtLoKpjqr@LhJC?`@_pKSjxtp7(g` z9vvGn0y{XITI@aVPU_x7onHayvc2!f=>Cqu-Meu;Fu*`}$BxE`H~V;J-hrlJxxBe3!30J^wo2S8_N$FOHyU62DF3 zn(d7SjxUg5z=fF3ft}zPF0HpHfL+ps{WIiX}<&9Uh#?d-w3(Q#s_{OwSkb zU3eLtaYpn2_sB1{Hfr^ur#|&|e)~Q5iPq>ZvQKz_QtG-6%$MHplKT=6tYu&wKn)gh zsTqjmi`6T=Ej=>5dESLdnYQQgj(1_+DxP6fkl0Jzn|a5-atIDjLfzZPM@EMwX?=sb z&!x_vamXj zG0`D8XFi9x=xO{iMF0UJk&^IZqhNuc!8vP#qbCdY`{_a zVZts(lCLg4!%5CL?KVd%WCC*67#|uP-|LJ;vcb5R5vFouWMq6VoCQ(WEDjJ51kSPH z;b`~p5dK=UM+kyy7=l&lx)d+&8rsE-13HTa8v6(zuqzP|8nGJ(piBtSyBgOtwvU@X z)aroTj$VtnF+4uPBRWyd?sc@Fp|jCzM>R#S8Xra?cjEzJYczH#B#CbDP5xEareWd| zOizeL5v&_mOXi4P(ij;YLn#`Ndphlc1pM^-;1K4lXm9_By3`l}*Qsx)F?RLv$S&8; zEBl8Ab{Ctodl>RT_pm6z-yP*MT8lYu@fC}s(QEezCO~a?@5!Rei-w1GUu%^m9a5A; z(pH)_IKIbKgsx+@Dw}7_xBe)*?i}6OX+CaOn}ute0eEOkAw>PV_0DU77sEHYZ3K(g zP_%b&ZzJv101`+4zyPpM9O(PthJs^y5z0P3+R!T@0YfHjBwsWy`nQ>#F|BQUh}YqP z=lLs#!I#2$;UUSDV@>Bfc*Owdw@2a<)ebaNRFukHOqdIY1(;Ero82x)IWUij$B;bBHm(GUHMF;{j;G8?;65PF1Xr4OYt zNlJgR`=AlgNiO#4Pq|M#Gd({80xI1^ZAxR6PT{-ex#9^l*G0P*a!7B{xo9`xR899R z;aqY=KAxlF+qW|?JH~e__Ce2z*D21do_rS_)OXPu{r*%QslJuIL+@1lhuWa_sa@*7 z+N19}1Q-3LdqwM3b0`K*u+hDOqv);b)HVI4`&FlCsNg4A>(cqYcQ!{K$2^W%9KVIu z{(|G5IPT~82xItE9=B5eYdBuQv6JIcjuJ_^fRdL*dweuA1rxA2=lO*eDWFjg6_|S_MaxoNkC7i`dJPM8*#YFLCgA6e zcZRvS;YGH;t+1>B6$kn9M4*wld+W^sX732Mnj>UiL_4%{!Ilggvg08EIbbABFdvvF z6Ull!aOp;Voa1CG%1kf8L!|!S Te9wFp0)W$=s<9LISK5~+e`~E%J^S)E>#C~iM_0aDpQ+D$ zwK=2r&KbM#rLxZz538?sxyz;EKV=s5P2Zc>RK*_FXPVVs_gkl)eQD(@U(w|&&;H7b zr&g;ayLUsl_xy>|FCIVom1j>q_j1*-C)*~UoI3jQD=(~uXE#nhJ9_HWi>Ini=je&k z3*S8Y%@W}B&wZ&{sOq{?)!n-4RoyN(^{-o13r$@$TrUOMWYt;h@vqm@ng@v z{GAhDd;S~W`O3?y&z@TS$}1P29&Ug6hSbV) zM_1Lu>e1@w`}NaHi*@DdLH)?`pZ&|`OXqrZ@67F8*F4fae0%Tq-tMMyE5{Esm3>UUm+q*eOMlc1n&}GNR6)hNgWJ1Dx`*3p)U=h`c6@g;Y^!6Vx^uX#+vZ80H22lj zxaZE+k9W_s9akUgwR{`;Zw=oX*Boo>$6clS|7YiS{-_q6$DMH+d5WD)ct5*d# z(2Ocz@3g(gRbQ~z0rsk`KT}oI(Ga+4L*S-cIPEUhr}*%BV6RWP{_3gE)+(sc^#Gzd z_9UaDN;x{(ZpPh-@zw6b#glG%)tx=tJ;pHjc8cypv)fmFU*YR;Rb8%}j*sbe)NQM_ z%iSAJyZ7r;r74Z96h+hSEHoR$~brtJ)&j@ZOt%V5;?=M2GNOeVe}GPyM#V5wW5-h?7bvdf(udi&K$O=;A(KSp!}YU~adMtqN?)HcB5hbRDF5ClVRb zypyCk`l;adRB*)?M1iZ+Hh1VA$&6>R<HfR)P6E4~@?j%l?v=3t3t+>YO1g;Bp zObp2Az}yhk*hR{iZ;Tg#_Th)sldxwSS{+bUvNbk)aml^EvlSZJa^|wAFA4u_^lY7b#-{sJ;%?rwG~3s zHK*J9DQ-bKQX&i*s(|v`+sp3#W%v6F?qW4piv+_L9R^u8tH&hJDp?;NQ49|LVvgYN zXXROY<;lf!seztdkjcTy;*h5>f3U`>#bAH1?!f}XMrSyxq<+wE|NR_`wV?GpOvxl0 zt^B7A(K;s75aT+^qY012{4+T%*hVL1rIut46+r4Mna~4~TO})-B#nuTO>~kh(6**I zPaP}C?yo42of=G2I~%}t(IZl9d1HW1WnLI$}kbAf`JKWjqZr&xg8^ul0N18OZ_bt!WmbtUC31134R0BcAmx($jCH< z6V+Y1Q_XNoCgDiF*GaXSe%Xq(_onbProAbAgx?+DBQV?=D-3pPQRg>Kz2 zw%EA-Nh878c52u6b-2L(#7rhjVk`RR3J>Uc6P^?DQ1k-n;Gc7`=XH4Q#|1T0M}}P! z{@L&t>}Fzc4bv=;#ARoVgt2l%+1xoR0zopC#cCdXofcC(aZnO?iEY{K?kN#VA1nrI1 z*#8F@y9Sg|@@x>wYqT2WRcQ4ZrKhCV;13%@6%CSDjMCya@rHZd$`yx%>(%2=dBIAk zZYv(C3MnF7yTy}G>*7h`(Xfv`akq11lbjDEJ*~;}_X163wy6V@xCc|dE!E(Wz;$4KhsMUeOvs-X%~mUWBP1fs+>6#U~l2_qkCHPj#ol{6zB?b2K00zip0<7bG?pX}dQS)bBk3oQtGH`aY;X zUZh~}a7BE7-0L2;!2SY({Usl!z}*f0m$F83tl;3)F?oT<88%$q_6(h!A~x0x7mx)Z zGS-RlV*I^IHL7-TcmrM@fDWWjmt*^feft1mLnvTKlBauIL1BeTLlFJCga8?f70>+= z0*eZ|c3O=8?Oc`)G&{L0A81-Gh>Kk@9I-ouBmP}?)(tE?YcmBAT#~6!v2qpW1`?dO z7TqtTU}nf<`Is|S_2W|k%mqnWi^q_FTXFwe&n?cE9*TI^7QSSv3Q59UL@#<05{xO@ zl)^C6A0~%{8s-9RGm;qd>eZbMO1(>F*B+9%H1j+>f3H4CVpfUcMu|6f+ex=zsaa7b zm7oAxR3(@vHu^r5-m^-JRDn%bR#7U{J2k39J@luqXUf*ypaLsoV;4iQ&=?|DiCmFC z=*OoL4BQ}4;FeD-%YDiSSGSe-J^N2Or{Er}Z1_ed9^S9WR8?g%>yCNE+`}v4-a?KZ zLn77iV{628eBf*2p`6w`#gXn}n&(GSOrTI$a;QMyM-q7=;9DRWlImj_K(;1;FOO0f zK-yX>1;!njDY8{gIXXcgcArrL9b_OjN89lBb07|D#Ap1uP)*WKMK@vUK%$gZdLFY2 zU{u=D^?t=cm;MC*@fC!)&t69yQrT65BZKcZS4}Zw{<;2eUf*pp>Q;axQg>W{&{*ht zB8rF5-{Rh18Q!=CL-;5N^KU_e4JG2Q5~2IA=ip&m*0kAf!_bh4mQtT)w+*i?PU46& zWk_<1?jv#Ndx!imBtYJMi@Au=qyux{5NstJHfh<3{QMq59DQactv+tl@Bp1iS4G-P z92<^@k>^)AIVKr0c<1W5noRIPVf5+inii7Rm6c}h;!x}l4$l7_wEh`j`18tNm!Cnt3MgTZ zH6?udtHo!INxr$WZ~ZAkQl&3`?{m+%1uJ*<*Z=k9&NFbo3jE-Y@1yJh)~{DJ{7zIl zV9p!vnKn8U@E|cG$V8U>Y{W=6Ht9&W&t$s(Y7Uze>bA7UEs!lX;pPf*{2EA%5GN$M zO1>y>?zYq84t5$t4>+v?PAf>ja9SmtRuQL|jsd4t#wj-wPWc>giWg`!D|Lbx_qtpP zY({Lw1OckEZ9uEJrS2Y6P8(7%gtgHNp68e&OrXeYQNi2=uQ7R@7e*ae4&z7bLg-g4 z-pFL*0i&8l({}@tx2*L^|#~x#P%K zDhbR;!bikn;DcEE9`u2nw@9y*TvJRH{6X}bg&W!hENF=)`e}~0y%Xck@Dtd&c#bcy zf<`2cVLiM7VMccFyXKmfmM)ZShM^1g$!p3Vs+7SGz8bPHdamyM+tk=!R&FIW{ z)^G_nkgbUn95aP~Z)w(fZL>-(aa5Y-@>+Q&ua%3uRxa{dxvax%?|Djc&8Uwhap6|* z;FmUzJMN8s{w@nD*S01O=F2Z=jllW-@McvKhG`R4#*J3vOP(vVj%;bl-&IB5(PHT6 zjC;RD;tKnVz9-V6uv(V|i=nr^hHwl@<+7?z25CP+3TAE64YNQZlo+&DY$+B4v%VXF zmy4tURdPFfZaJ2Bua5}K3NFPoVg)NRh-KQ2dwa8$0o0;QYP74+A+B4l04=J`m5K5c z*;Ewql(wlTV#K&P6^X>SxhN7nT0#~~cahiht4^-lHIvj=7=k6L3Lexxcu-sLAj+gR zn6Pgw&bm8u&HU-`Y!R285&V;DH(2l5%WJE)xf@V+9m#Q_KgD9P^%kHZzjDVed4-~G zvO-Z8Mirt_-7`+|-78w+@M5AM+Dl3C{w6=+C|TblEZot0FV<6~+3C8AOH48z;dGh2 zq^j%Q72$LWQ4re6qM#n`pgY;9-ve z>nm_z9#mp7=3P{Yvs{eH+Q|%7ySG1KWdetVzJiGHsFe{|Fd4#bCyfRUvkF!qb69Qi zu;T)Q7nLy`{i`fji7a z+}k5}lSQb8v6L5MaiKDD63WvOYje1mLwSZqj#@X1v5Hl+5r0B!LL}VOObYsoWg~Y+ z2lF4YF=aa3eRb|EEm&ER*WgVb><;>nMX|Cg(YO64wMtz?N?aSCG7y9}k@Xytgv(I0 z0Um;b05y3I3A`OAM2s%(vxV{)ZZ@kWH!^AJDVKS7Y-LJrv@)3+8>9ZLl{;Rq6|88w zV}=>K1v3(OyWRSk;>K>FQ+w7=$%>{w6Dz`H(osaNBJChu4Az1X-P^vODNgLV%!v!u zPsxVXPtt9vpOW#cpMvosSCyP+Wisaxq3~Q)a-NkbIM29hitV~Cvt8uylJSfZ3dVEq z-R^F*L`CAg#8ua|xDZY$BI6UBGWc(P%HBsb5H*v@$IqrUSi&8p0IE zQNfs2`c&~{O@ZZv66@F&66~Qw=9PPQ7oOiZD<+Si78jr9Fq_bN3Z?qnij#gc|Kp$5 zxX=a{939v6C;tQBVdp3>)>?Vb!nero7`2}?_)ByI%=sY*86$|L7*Fs*uWH+vm`wl% zL*<7*ZQ$SjBrCQj=W-Hw;>H>HMw0;ruttct)2D1MHa?1Xf7+vX?~|;9zS<}>t!WCh zuSKIc`|p44+b3QBTYUWRZ+}3Vq5tjc9noL(X15a+j(-^dyJpA>Qyt6TQ*uodPy%eS zE|z(blOhcglasdIJ$WibOL3Sf{UN0nPp87kXX4TMJAAW>iTGyE*N>!>qt+SF-rm*Q*}HgqTW{~% zr%&_gJ-wa3Tc7lH{vO`m)!W&7d3#%L@9FLQefp%g^LzA3Z|CpOC%wH+M;<_#0cO!F zTZ8q-TG%Kf7v+T7<0Sap`Mtqo4mLn8lWhQm%l+=3_1u7fOfUl$b7GlpU*8R0vHw$| zwqk^Vbeb?3OiUE1*XGwTGwj!NDBK&xPmJCCw{v#M7I9vQeyG4AG7zpel(-NxN2Erf zx`xz+?DK{uP;+}m-{ewnqAw@`NmI28$`ej8LUvIrAat^pk?mQ_UN+<|X`m5R5oh_A z^`qE%o+Q1V>M?&^_a``JIIPlRn>s7_O4g&zVlhL*Pts$U8$|#zvTZGT)LTX6Y`#^) zPffy$jGJ=FeODlYGP|^5buO{KZkfRDZK1! zE0M3Q-}X!SL1W>lQ?;OATnEA>oE;MOzKu>4$98v1x+~JI-2V(|xsK7;pF~B{m8hhG{5^_>=WTT5&F2=)MY1h0a{7w0xgjG!W603>X~ilz7O=B8G1z= zk&%g00kJQ`%-zTFE9pjb22ZmZ^w}>3N_wNt9 zB8?{I7m!va^FiX3?CFFunH4;*WH-k|KO~=Q-pDK2(FsMeqhq}CW^KHZoE<;7JQ;rIo$PQV?IAYsFX`99mGAoD966b$%j7Bl-;kctwc=0M3WVX%;{{A z9sXo{Saaop9;1?0G*{U>>kMy#nu2#0gpH>??;u>&D4kStS(cE}!7ePrhEW09rg2vd z-s;Tm*eOC0#I36l=&)$9E=s0x2}|zQ5sH`y&G$JRLOa?X7ZnCG&T`wbSZ&XwOtz1QaM}Qo}3nn8%PrQpw24f9nxo&Ik)wXk29Z$aJ`<~LAnS;g(pn$nAKz= z1w=2V&7|T*Y_h}#Rh&3Sp@<+1`~n10am3l%1uZ@yRVX9FE>f%(OB!e!&_`V>7AMSN zM+0^s&+J^k`gB3Tem4-8bxc=GEJV{FulZVWn`hFQAqfS_&Bn3|%QN(?Pa2be7>2h{ z!%f>TW-cR>L+${CFBFyzC>!1t(VduFU@&9azetoo2&T;y;q|%_p2iQrG98l}{O@x% zH5R-5N_Phe^0||1Xwb<2IcH4DbKF47e$fkJCeSwMn2DWdT2qc0ITyC-{Is^RUz!tI zDGc8^>wrQo{hI3ur(%!wQ%dJZOZu22A{8&D%v_<#AQj@Sje4RQM8Y}E~kTPSxU#@3EbR~UwEemdt z&>I#ntPH7K??qcBnrK0ilFh~TJ-A7o?8$kN>JE2v2ODNs+VKCg;>=|v*w?iY6 z8h17ijfVR6h0!Km)}h^&2kj<_ZHs4!hooLa98d4y&7Ex?bLbe|)RSY-!+1e=$Ne3a zIS~tvWup}_U~{m1D=cz&4Eu=P2wIs7(u}nZ^%h^5Ps;!r6<&~ ze1W26TM7bEa4c4gWZ z?RMM2F%U?570VF-GKVlq7H@j1@Zg!~3y5nKH z<+bsacJr%DXyCNG<#+R&-u^quII)p60^rJl1sgPbhl95jHzTy0AKv+&(B6_bcga%i z%y0-3!RJdYp3e>lX}Jh7VA7EL*Hi@GD@{ct4L_SqB__H@T}+mN+X1bz_|ul_m@pBk zjQRx7DG%DoXSDrE{pRsEcuOP4cBBa#BjRg0M>eQ9Fx&@+&Tt=%h>mb?6K0iisDmlC zO2NaMt~B&BWtFne2Z&ZFxO`KU+Tm-OtXG+;@n+Kz)vt}Wya|P6sIzYf)T~cgiD8n3 zxT{+;Gv53rW5pilurK^8Wejgd-`wL7t*SZ;yV zXf%F}1`eP$cr;q7!5W)(^TB2pm%)MNZZ2C6HhZ|R`}+`=;lbu1E}ITCUx;${cd8(0 zISXJWZ#-AGY7sjUaU;ho1fdA;VcnXO_H_3!K}A;GAYZsh!_=D1V5*^Cma{lR-8MY# za7cr1De@4cmyN&NiC^QB1y7{oAb40d#BNRXmgNg>8b%%m^7v_u?%%91LG|G)$h_OY zsy=Xz9@jiFos$ZDaJgSEPiNTf&e|;-%hRiAENve)J4(AzQY-wpXkQwaUGN8&-H22! z>(F3P7$?o8D2GX)5YAoFekZ94TDJRWkpaz{h~&7OynRw*T|y3`Fe0P0a&nPjIzDV* zGOX|AU*u7Us`9D`PkUltrL-PGr6Yq}TxUD5qBjX3)d=Ows=;KjvoFuer|G2g<-n=Z zp^)7IazmA}9uQ!?tOpVe7+h91$JYo{SO-DM8$i)v4ddwP=n1n#G#v6xi-kOn0}Aq( z2wg{G*8iZaq+8g7S45r#pU$`l;yA%q$SEwdrFNk7(O7sly$s4RKiefkdAjSlWkt9% ztFXd=GZ?cZhbL@|L6Q@N?1)MAA4Mbhbf96D*6O7OK20l=l=P_KgYe>F5!9oswH<gXKEXleJ z^4pg-?uR)!ya(3FGT$>O(T_OU$b1!Rdyg_*MSP&>lzA?9!g(4cKvXmlY1F!f6BY{j z;c2qTcBE-7Yu~Z(5H74A-;okj5DJ*cD>yg4R%24D@NFjagx&FP7iSlc7rUQP3~;{m z!`0Ob_I{yWOt0+nT4o(I(hm$$Y7QhFRuVHIcM10k6Kt-wkV&^-qD!Kpa5Ri`QAip9 zjs~tulK!|WCR|EwQRp_)7MLNa{MEF@V!N#6>AmBko_;ag0__jExo8m0hNlD{H>SW_x@X2<*nzkT%A5^hW6}5$IA+Mm*-GWKX zn?`9MDh^@S7~$P>#kx_+T8)Qj*pS6k3}zt9#@+LziQ?RF^;mtZr#8S>10_mTH8Zvmh)+)rECR&2CJL=coK zbS$is8i-b-ZC?%zg!qBflNtz(1lG9@*DtsXNOc`OJ8!M;-`&(~In%rrRdh<;uN59E z9XDm!kfGWl#3hBth>Lj#f{PpoE^;8a-0dS_dwk4npMqs~5-cN1c4u>Vv{gk|0|4i0 zZb!3QyRNdrza_FdygQSCIegKwSa9bL3~wGUXz~7Nkp=u{wGo@)%7p+JdR9NsLvR=& znw3bSHJeJ=$pUy196QG1R3i;2fJTEkTe^f5#;jl}=z{8L^`?98^TV45zCj~r8d^Ex zTV?ou+Ht9AoelRKXTgGaD_*4e8TDp*2!vx$D>l`N%16uD-_@}KafkC`)}`+!Mve%_ zY;Aw=i(@zgJnwlLw?Y;?ACJ=wpEg+_D~29r)fZ7N6+9RUZqCU3 zQ575fjmo#E>Dn>Y@?OxYMm7gzpx@QVA6KE3ExDEdHMR1uCR)+*-_XjI+)BBDN=I&J za)SS5Q6`CutTf%(ixs*3k5foe2!|vW%388=Z(sC<${-h1!ubm$c(FGZLmVFGt4Y<=ed1W&2T;3}48agprnC@OM)RBL#2 znI=`C8-Z&)@!ehw}$ZG zo4%F2lw7AKDOMAfl1DVQTZsz33G!-CN1wuLBtE4*&t%ElFZPLTjjkCE?4;}2AeqC@VSf5gEfzU$Nsm7Vn?aB@Wp77 znBuqxNjiQygWm{Xe>%4ngosWDaYvF^W{QX>kiK2mCKI^d)k3uLF>B8gQlfEl0HJ-R zGtF9s!MKSQvsKddF{Ws4z`rtwp{=A;0{bn9Di*Rg2#MRu27l(jM_rE~Q+CbS6cT5Em+Q#Xg>zuP;wyPLap)9GsUqKUIKU0OHjr;*TrnQ*9*m_{RJ zIy^K&07iBo3KhNZ>rFBS^E%R2JTBnR>e&S_Yh+SGdRZ%VuS%#w^LbLk0BP(a!W!KuL{C`S{1{j#fYkpI0*-7-L(oE znu4K5G`LATZsk$PZEw{lISAiSVbKmQUnl||n9bHmFyyR}81pB>b9&6-b*IRs(sMTL z^rHsS^&w`FV%9Rkup=0Zp+}XnxhJX#re4y{*L&(eJa3-9kKXZZP3;_|)vgfQ{oYcu zFuO9MI2>YaR>t$Y6VHz%OgdY@f5L>3&d@`K%ulCKRD02_NILvn~kw`oQ zyGL(dHO4X))|n+JSBl3xLGZ68@&ui?+Wx~kzyCe0t$6E~nTP%u-hXS{Kl|pG#V5NILg?iw zk>OUg{WrZwmtCpaW+gA_ZYbathw7$TAyjhRd1{1_f=*oe2W`E978*n;6c2-#x5m3z zHsGbbsg)5NBCCSgH^cv0rW3o22>L~-AV#?A}^v7SGhv%LCW8XYa)2v=C=n7HHwmoj&!_dX=~iU6>al*B8c158I;G|8Po^ zb)#xD`v$u|8oHCx7tvY9w%xKt7lOjGm|)+$(hvkMbRCw9g5W{hnZbjs)&HDXErQ^% z(_-QbgoLYn^u{P%^1TR@AVey&#Q`m;O0{eHC)lcN!pvd!+Hz3Vzl|FoYcWx?zisS^ z2OMvsZp1W&Inf-Zzrt_@84oeSpdW37SRv(s46qsp7$ub$kl>jIIn&)l?D4|G^>;^@ z-4lm2Fcj4*t;J|6NP-@b!0k?2io<)UkSs;U9yy?(fpKS3%}JqVI~OKng>fnhC{~9p}>d}xF!cqnYD@KjS zViezuwPcK@t^#LbU8t+5GCJ;}vJ@T5QuqeRsPU7sQBjd@DGXJPRqMO=4%h*$fq!B3 znng<3mFQh~Q;eZU#+4RF30jTSx+xnFg8ls>*xwNBN9Z;d>KEhrHgKAW^b@ymdmafq zS1dPfH=ENNq^W_Ljgq!;e^EVZ z^YL5NqvM9S0&*o!Ns(u8?;cX~zgJt5Ajp{*-A)_Pa4sNK(&GdSncd!mkm(pR1R;Z| zp~KuFAR&*26{SP4__;IamG~#nn4y&hj8G0U$6}cx314Bgi`9a4Z9DLZ=Gb}M#~~G? zbmB0euC&Su``KOmj0X6BBUY6S^D|Qnuyfc?5vhzPu%ZBwlpVb8p9 z05CQwteGz_nxlhhD6?sP{108vhrWkxD_CCGGr?P_FiT^B}1Sof8>h=XfKeaslLpeA~r`$O91@c z*jP-QoM~fYA$3Cj2TEKTpqrVcl!`La)-Mk*WeY)<67VrgK}NR;M1V~B7Wc00P5K|% zat|g$(xr$zATQ4!U}s!A^gruN-JEJ!9^S|BQnH2NnQ*)D5femAnU;ZRul|jmtV~Rs zU%o9D86Kp-wuu6!7)XelF(HzSV1F!E1GgNF>^|lzVipRwo?zus1LsY-Fj2zKQ~0K- zUThl7f>>v4*yk1ef@B1#Ru@d{;^iB;9ezvIEC?=Sh<0&dnaOT0EIPTH3mKw4T*wgZ z<3fh$5En8;4{;eDXj0zhhjD%RZ+B-m0~e0soM6>@mmp?aT)4(!IU?IlY8sS_>AGf+ zDn|A84>+IYH#rS?jb9gtJg0`nSSTxsXinvSXf7EA?%f}962NWl*BkdSNH3TM1?l<8 zq$Oe@(DS$xj+Gr@Vwr;``l!6E*`&D+r=lg(-n@WlYzj6>{?ag~Ez5KV1w36o9OFqP zI05Y-SCfdXM4}-+SF`hnM9#pnmndrurW_gX%_wid|po%Ez z^)8s#>X&H6`u&jqelWXWzHs=!btUWyOTmD}{hvOqV)97b)?2RYut%Y_lzG5}J5FaL zhE4U&p*N7Q8>J&C8sY%O0h&ub?CTOr8H9t`nH9=yOCZp~1O72?* z4+DwtJTtx~l-aSXhIi6&pdPauY|mx^rx9|4G)&D&Gz!-}&d>G($%Y-Q>(1_TZ|@s^ zIy!Fz%i4bAuf|>cQN?l`oH<$e>^Sq-3uflreil+c*~%l3?auFa@9w9cVCfOU&p61? z&P-9U2E+y*%sJ^Kl`UPrW_TFvB!i3s7OkAd4xYsFT*#XQd5(fMLl>PvAO(T9GWE~@7AM9DIl*Wn^)nYa6K;aSZpCgVf4ESv*7`z^N|VBs z9O36>yc|&nCP%oFhC(}qd1h#qCWIGaJKYo#<@Z+&&B5SO0YntLOr;Q~Q9Tz48O=FN zDl`Yv%GPnLO~$!)wxCoySWiCI3mh6i^9W|Ie&we)rK{kKu^nk|awyG9vZ&nI-wwx= zCZoy}ze)6HD#2QIgitzN6s(&hPBssimmsdQxf6?I(}vT>=<9dbz>97Q7EYm?n4M(h z;Ek@>4(CZL$I~KCwt~=hL67;6bS3p=k$>#->oPrTVdJ#vVH+I$xx;8kY>t^2#y^@9 z!kk=NxRE0X`4RTP%+~H?giQ`y-*CRKZEVdwjqqPIO?Ni-Qml@dZvx$E=b`YdiyN_oq=)WI}TmLaQ$< z{a^`et%2p6f?8ZAH_@#h-AGjaMgAXS3O=ge9Yg%y$g(1QPOm5Bed-e+B&iVRrE%}B zNRhpNsX|z%*^%gzn)N!@T1I91{`{lZ&$!vt$W?-;^HkNtFOKl#{X`KN?abJjLoCTS zO;!MfoMOa1@7%I_wDo7|0M5*QZ_$YCEO)-T{Ibt&*+pFMYCz(I}b(yB})~H(z4D!?Bw2q0t*&M(PTCh z8V&-Z_o={7Q8Xt_8~6GjR(4ouFdL#{uarB%Ia~{!o6ONcIviAsJ#|8;4vMf{WGoQl zw~aA<0XwVHKn)2mg*Cy!WIz@IKdG;b!fX~`dI6aZ08N3MKxR{r%{%Z@Y9Ii}nN}Xa z7+4dz=r9H`m33^?kT+p)NckV4JLovr5^1r8#FYfk3J38BHA9ZGs_lcn3myV(XKTXK zwv@5AtOISQC=R42+78wPrnh#VdIW|aUNO2BcL~~xkQal)QxHk!yE?)phG_gr4VIUkb-d2E3#sZOQvp1wUx`$9p%BC0 zY7GTFXK6iTu%|Nn8Ab@g(}G$lMI(&BN`etklrDR;J8YSXhE<5Z&Tu!SgXA-# zy-MC+5J~d>mZSH_)BQMq)bd$&$pedy1-vuNy|U%*`}~MgZVAFvS~ET|IBDi6lM;t zHJa#}W%q=>v+vR2OxGrQA7POJ(n%Hr!jThJq%sAZd0lz$2|}t{#BV)TLi9FnOyFnW z!(_2O!LX7evV?P3UJ-*$87tZI5LQBvRX$Zai2h#4PZ45E7zwxtPpmad;ASTUGu55_ zQE*d(lY+Wt5Xm{gGkh3a1lPm{5%Yo>zA_r?Vk}k-k?;XkiZka}Gf2uci-0U63&Ggz z?;+KdhFWtWV>btB-Mctjc06noTn4)`sxId}f|65zMQ*5Dumd`Bz=R05nJ`Xt~x zQ-KKh&gmkbNJTv0KVyJ@A{NVlcipYA={eeS$TKe>5T2-3#^~3cY2UL+pxY*D z-d5C%@WEX zM-q09(oRpt=n=)b(nH956kB$$|8vNn*RuOKj{3;A?+LJb*oW4}p|I8ybqtKLFDCK{ z0obBLhOss@dN{6U0lIw#piKtQ?ehTIRRB~QK)YrDVvwIqZJx!okz)R&FJ=>JF^^BB zA}j7j)2E**ig=$_UJ$a+CQcV-%{$|BhH*z~58Z3+-H{=KqCKrK?OH=2IkP)e7`g?k zu)6>ty2n#?f$!dKa@cCu-I*F`QL~E-^v8}V@%g4aSf={# ziY;=l8Xj?X#rBfwF)FnXs)g)6ohtN(+W_Fx#jsiZq9mI(VRzl#v7meV_x+^Y9ovTI z&8)a56&aG*&~WZ4imYiZl~|c)JKdX_jdOEv0pzsp6dX`*3)~m0;v+=c>AnJ{h~kJ< z35SSPP0*fHU*U-(ZcnTm=wa#lSK-9KL|8284`&LCajvz!Dw^4Qr@Q)W}e;Z+E zHnY9flJZKC3|mjB13S1mc^uF>LKvEC|9ft-EDIydJUBeqUAEJuk|WMqY$(VA5|CuG zwXSfmxD}K^2Z0&nbFg{Q9wZ?W-Ya~vWOWmVMDa^Ao18^Y6}`J3{(*O;3?~FR>EFHc z2j-_Wr#a`BOd3mM9vg9l1l60vzTZAJ`FZ(F0J|Vx;G$LGCmhFhc%-Enox_0N)5>j~ z*QrAGLytP@yXzt6#}0M+GYWugjP?>DHQI&r(}&~U3uAbaBm7oXW)aA3Bs9Q~;FeB| zshHmx&;qEnb-ggZ>v2DIu9JiPiXLof@Vgp+tCWHD=p{T%!*V%P9O;5t?P1AEkA8MJ#`9B zWSpIWao(S^^{_a-cx}eH&R?ZNi12f-k^WIY^0W5!j9~V9#_(rGP)K5hMsib>735|JUSwWrbfTM7LMi~g zzxS@+3{>V76u>a+Cv#5KE)PFPcR_$zxB|w|f2h}f6sXWO4_DyF#vyKogQ7NJA+M`P zb#u6L7=gL-u`yXahwNM>=D;dn1(2g|uzEBfc_T z*T+x#U1zBk5Oo~DfP?)xd1-es2y<(EUnwA@!sTuu^P5v&Z?yy44l{Uo`Ij}a7C-*s zWj4cf-eRTMcSrC#D*V%?eb$H zP)3n{Ul%B#Ik)GSVIMrjfEVixnO_n!Ih-y}&|)`5&cJH_ah0maa9FO+*d^i>5X+$- zpXipY$3CbPnNN0@>8P@ck%lDQsD>!3wtk%Fh80{;37RA4@2d&syfjI%I2fWZ-m=Rz0C#SjJLF#^G2C(zt^It4D}cy`CV6)`lm1 z;MurgdxxxhK4Tii>Sk@L65HDV4a+ z?70zg+@vpBjabn3d@aGuSg6rsG3?@X2sXIXlMewU30_UY^ zo3lovh4S^>N4Y|0vb0{EGFC0Wp8Xy33}rSog|Tsi z;+IsEFfDc+6*w^PqAp~k9Yz6C!HXZ^00YJLOJpN+qOt~;wVNMYuuqW*8eGm@7X!3) z5PpEdago8sxl;7mZ?&MMA_a}2_DhC4wqzLIDXd-CjR|}b;Dd_7#HghhCQ>G-1Fg>q zdd7;FF;M6Xckw5F5l_mJ(2f<#nGa2b{g#4t7*vL}W+qft2MTMb!;k?{kq{Wni_3f* z-ktqP<<9>ErbpK#xzbjF2%?IRxsiwf%t=e+j$@WY5lR1(>p9nI9mmd#oIjEN)U)&% zCUTPVxt$>AJw>p%sNjsB`ck7Pa-tXcyY=jkDHQu75hSp(q)REt)46LC%aBCPNpz4C zVdVPd)+9UvD~fl-f-ATUpQ-q0U$B&v{omNC**F;6969)-h1s)s))>k)MPo3K+`0du z+6CEl;n}=2jW1N|X~s$o|d(d&iTU zm|JC=sw6q!E`INGRwW35xmC8SN)!r*-PyPPR0ju4{%qMa!gi`oGW6WpAN=usRwr9} zn&>=-nw3^{QkvAA{q=u+xnq^WLe06r?P{A{_3f}NhoG$PYQ$F?Sh6_DS09HQcR?V# z{K-_e_aK)iEl=|?h<%qotEsq4`DP>KyKvKB@b=H0tt)p90@+#RzdC=+pWKE1;P6BF zd!t z=~doe=KU4E-^=x7UpK$I3rmANcjxa0i$?G`eV?XBwe@xD{U~>yqm5q$(927+Blr}x za^HgW6!pJD&#zS9;NMZcPr%^bSe|WVSLplel>avUzDVs=yMBXrwJ0b84g|NmyhbY- zmQ|p5i8^0540@<0Afc5v29vO;Y0XK^Ynj*AdHq$Vs)lz|)%ow&)!~P?RA>Loe^6Eb z>fiRN-}|pV%VWVZn8fA+H;265?)jHmRBID|?%c{`E%m86$Rp4ko?<36_5iti2hlQ3 zYb(_HCL`4>y(pO7<*8B=J;yKZgO$No|7QHgRS-PP>kG8?GB5S*Y2j}LC|dea53fKW zM~NXt9Djycnt&j;>Mn1Z#Ibr2M!rDXtGxaL+CEx+ixGZ}woe%4o}!1Z@$^Mtus`?4 z=Gk#~d8D4xpL=KXe4PFb=)1GEU$Gv_Nd_!E>A8eXv>v~+ot?|NTlct`ms#=hTbouGxbdZ0Rxdv#Z~%pz)% zy~GsHGl2VONqwsAY4*B+BAF(ThF1+=?d5epuLpST$mW29zf*J_{%T$MzTT6Dzuu|6pZfPx|9K~&1A?hEZ z{(4F9LFzw9{RgT4AoU-l{)5yPRf#e*yP6?kS(wsj1+jWn&1dc3ukbE&MymHHuW!(z zs8Wd*{pmV{|xOCuK4>iJn-`u8I;FGvP6fLS0Wr;d8!wTG-Nv1+{usZT*u0Au~ptByJEziz-D~q7Kcl zW=WV9wlrcvt)5j||6~YxE)*w;8${8fN>P@mLo=*d5~hVMjaX2tXVsqgb06%ORostJ zL_98$D)A>#C9xuWYAkB!IShp7t7Fx1bjUZ+AunPeokW9pWAQXv>f5NvzvVk~mv_$U zqn2mY3_it0z&XPhr6R5?b={>X)k{lj>OQxHmpA+lsW>q=6XK^A~}0LOH7q z3C2&%*J}Tff9~Ji2Wym?FuvRyx6W^?ooMTwTW3v)8z}L!W~9iJ_%_;j!u$ZvE4R*$ zR))4WZDOs~FfK|x4mO|XTT6T2WHw|_Rqn!Vvwhz}E7>&6hITS(-R0Znm@)q`)sC3W zBm2yoDA8)0HCAL+$Qu#S$ifqFvcPk95nNfCDgn5Yf9^8A-?RbJr%YS@4F6hR+I=vm zlS4PBPkS0jJ1M$i*dkN#{TU=iTo%h)FK0dt+>A%D` zA^g5Mmgj_zFc9mGa98YM;}Gw%75;iU9+%m=DAGhmzfdK zmW=I*KX+wLE%{XP0$1nHfav9uvwdmiCTqz8EdJc3b=8u!TKu^WJ~=Cd4^!Yvj7Nf1 zrnxw6mdjo=p2}Q!2NWvGy#oxkMHhT@mp?T-qU}6*gg#z@3gt%J5$I9%?a!UNV^$0) zN-$Zg^eV(ZXd*gf0VY^@WF^aaC{uXTA& zE%Cu5gueo=BqPEY-MKqw`e7cs$m6XHKnIZ1`HDFprHZ8>l4;^R?c%Yj*zH znQ?uCF}(=otfKNmO+!m~bC);Riu|E4+T4zNA9v2xciT)=K!w z{pyoDclSnGnTrL{@rGKNiv_`Q&nzBhsU~WMfJgVvoLaNk^R*Hd+?5T~N~3mf+&c^5 zT79Kax=Z)Y;2sgRQ_s@>)5qiBI4LGffTH3Kc_s#>e zRGlq>hl7yKP{?&Yttsv`5dhToHKuykr zW^Pj7N6j8uaaZ=uw}{o^b8wUWxpVtx$0^(8VP^h0G*J%tg?4pu@9dw2SaxZI!PASk z6hv2|GRT-eZr$o4c?^sZURox-?a)e3(AFD+lH{FER@sXPRDO z@Nx@EB592zWrja%gOLxV;Isy)^vSPsU-4FjlyyhM`!!0+@OXjmavOw%)o3&c7I)>~ zEIJ?JL1rYm7WZJBYf{Q6?0s`4>RwuhFx@+c2JhEb)Is>Gx&D~fMh5pRK#TrFHS%QS zOiB*;p$a|TkrZv~o62jRpX0S^GG%QPh%&rX8Pn>RZ@!f>BPEAdNE14RHlG_1(go4+ z5{-V8?!sqg<--#^dzw~C*fe#LYCaG4En4;*wyqxCxzEn_qAbQQ(4zVgd?(Bf*O*Qa z-VomOWV-!Hn1U@G#&YGegV*bG{)@fWyr1TEgeD~%#bSO+6!-B6JOQQTDVRTf*FA7S z;XZh1zN!;p2^u**B9a$@RiC`c_$}4Vf9{>n&2MF`iSpuP0zrc1b8}c&@dq!#JV>4) z<*#R1r1>vdTi?BpBuWo|X?h4J$&GLQ$jGpEtdEny=ZQ=@``HgCp8g|j-mjjh+LOg>?6e!O5GXEq5ieQkt zJg=F%XyzBGoHekhAbPT~*{HiH?B4i6HF&$eU?cKxHJ8_UNh3;Pl%m`dyZBmQDV*l> z>9Uf18qXt5i9KKMC9YmkNJ=UQCs`zz^vOTTp}BS{{8t9@3J`(&(r;F?CfU=J$z*ug zX7cKxD@~CirO!d4laa?cL`t{s{BVsqcZ^9SBEFjqI9{RJ+@PIi^|=`MaOZw&4r#Ou zYSu<+t5@kM#uKM-Lo+kIDfssyV?7qjx-0W~6CwTrqfmTB5vSRnHPYu|BcSBMkLL8Y zOo3?nm;vT4U8|Tyf7}&{&4eUnYCmOYeL3-l?2wbp-1C6ri7xghA{B{?DDNns(D&Kl zu=0RGT>kB9R?Ep!eVN9-W-(9AuA-l_O?ZrGO^CYAIsL5N12MUGerL|;era8!^OTY^ z;eK@f?p_<~EMPV^P0{bp8QtNzqk9S>iR%y6F(TSXf9~Ax%^BU_~;rordY2mZSjJZyN)hY0r4oI$sAt1!JpZR~EED=3ox+#A0?2YO`y)`ouC zW4?|NxN|?Ak{LJArIHwRhD~%!v6&S#hbbaaE$tKyLD}Q-?R~sf*VB|Z&J5_j=s@!y z*M2F=Q2e=be=r4&ppZK@QP5qOE_O3TR(Kr_e0E+}cZp)N%U!<8BhR3Z1C8L7t?cbI zO_5+0QO#OvdNR2vW?hz=yY%kVsDNPh&s~`=rol^D+(WuEnV|06Po`Q^u`aKokY;RN zF`+WG#Ak3su^H1zK?jM@wbKtD%&R6JezMw>)#@(%;hf%Pt0~Y|{JG2Xs%0SOM@If% D)L!h7 diff --git a/packages/polywrap-client/tests/cases/sha3/wrap.info b/packages/polywrap-client/tests/cases/sha3/wrap.info deleted file mode 100644 index 4c52e6c9..00000000 --- a/packages/polywrap-client/tests/cases/sha3/wrap.info +++ /dev/null @@ -1 +0,0 @@ -„§version£0.1¤name¬sha3-wasm-rs¤type¤wasm£abi‚§version£0.1ªmoduleTypeƒ¤type¦Module¤kindÌ€§methodsœ†¤name¨sha3_512¦return…¤type¦String¤name¨sha3_512¨requiredäkind"¦scalar„¤name¨sha3_512¤type¦String¨requiredäkind¤type¦Method¤kind@¨requiredéarguments‘…¤type¦String¤name§message¨requiredäkind"¦scalar„¤name§message¤type¦String¨requiredäkind†¤name¨sha3_384¦return…¤type¦String¤name¨sha3_384¨requiredäkind"¦scalar„¤name¨sha3_384¤type¦String¨requiredäkind¤type¦Method¤kind@¨requiredéarguments‘…¤type¦String¤name§message¨requiredäkind"¦scalar„¤name§message¤type¦String¨requiredäkind†¤name¨sha3_256¦return…¤type¦String¤name¨sha3_256¨requiredäkind"¦scalar„¤name¨sha3_256¤type¦String¨requiredäkind¤type¦Method¤kind@¨requiredéarguments‘…¤type¦String¤name§message¨requiredäkind"¦scalar„¤name§message¤type¦String¨requiredäkind†¤name¨sha3_224¦return…¤type¦String¤name¨sha3_224¨requiredäkind"¦scalar„¤name¨sha3_224¤type¦String¨requiredäkind¤type¦Method¤kind@¨requiredéarguments‘…¤type¦String¤name§message¨requiredäkind"¦scalar„¤name§message¤type¦String¨requiredäkind†¤nameªkeccak_512¦return…¤type¦String¤nameªkeccak_512¨requiredäkind"¦scalar„¤nameªkeccak_512¤type¦String¨requiredäkind¤type¦Method¤kind@¨requiredéarguments‘…¤type¦String¤name§message¨requiredäkind"¦scalar„¤name§message¤type¦String¨requiredäkind†¤nameªkeccak_384¦return…¤type¦String¤nameªkeccak_384¨requiredäkind"¦scalar„¤nameªkeccak_384¤type¦String¨requiredäkind¤type¦Method¤kind@¨requiredéarguments‘…¤type¦String¤name§message¨requiredäkind"¦scalar„¤name§message¤type¦String¨requiredäkind†¤nameªkeccak_256¦return…¤type¦String¤nameªkeccak_256¨requiredäkind"¦scalar„¤nameªkeccak_256¤type¦String¨requiredäkind¤type¦Method¤kind@¨requiredéarguments‘…¤type¦String¤name§message¨requiredäkind"¦scalar„¤name§message¤type¦String¨requiredäkind†¤nameªkeccak_224¦return…¤type¦String¤nameªkeccak_224¨requiredäkind"¦scalar„¤nameªkeccak_224¤type¦String¨requiredäkind¤type¦Method¤kind@¨requiredéarguments‘…¤type¦String¤name§message¨requiredäkind"¦scalar„¤name§message¤type¦String¨requiredäkind†¤name®hex_keccak_256¦return…¤type¦String¤name®hex_keccak_256¨requiredäkind"¦scalar„¤name®hex_keccak_256¤type¦String¨requiredäkind¤type¦Method¤kind@¨requiredéarguments‘…¤type¦String¤name§message¨requiredäkind"¦scalar„¤name§message¤type¦String¨requiredäkind†¤name±buffer_keccak_256¦return…¤type¦String¤name±buffer_keccak_256¨requiredäkind"¦scalar„¤name±buffer_keccak_256¤type¦String¨requiredäkind¤type¦Method¤kind@¨requiredéarguments‘…¤type¥Bytes¤name§message¨requiredäkind"¦scalar„¤name§message¤type¥Bytes¨requiredäkind†¤name©shake_256¦return…¤type¦String¤name©shake_256¨requiredäkind"¦scalar„¤name©shake_256¤type¦String¨requiredäkind¤type¦Method¤kind@¨requiredéarguments’…¤type¦String¤name§message¨requiredäkind"¦scalar„¤name§message¤type¦String¨requiredäkind…¤type£Int¤nameªoutputBits¨requiredäkind"¦scalar„¤nameªoutputBits¤type£Int¨requiredäkind†¤name©shake_128¦return…¤type¦String¤name©shake_128¨requiredäkind"¦scalar„¤name©shake_128¤type¦String¨requiredäkind¤type¦Method¤kind@¨requiredéarguments’…¤type¦String¤name§message¨requiredäkind"¦scalar„¤name§message¤type¦String¨requiredäkind…¤type£Int¤nameªoutputBits¨requiredäkind"¦scalar„¤nameªoutputBits¤type£Int¨requiredäkind \ No newline at end of file diff --git a/packages/polywrap-client/tests/cases/sha3/wrap.wasm b/packages/polywrap-client/tests/cases/sha3/wrap.wasm deleted file mode 100644 index 004b76f729762ef4e91c983f349819b03c6283ac..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 140755 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 J$DZ}w|3A~=(+&Ut diff --git a/packages/polywrap-client/tests/cases/simple-env/wrap.info b/packages/polywrap-client/tests/cases/simple-env/wrap.info deleted file mode 100644 index 9789e69cece2864b0ef0ddd2200f54c4be72131c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 629 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 WDZNdiHONJi@Xa)|Jjm&S{{H|0sUS4~ diff --git a/packages/polywrap-client/tests/cases/simple-interface/implementation/wrap.info b/packages/polywrap-client/tests/cases/simple-interface/implementation/wrap.info deleted file mode 100644 index afe55c112cf144ee065e1431dcb953371e7641f5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1975 zcmeHI!A{#i5DiieduaO8k`Ae_-A9>UUiZFbinZcruk9Qp|k4lz`!QY3nA zuk@d~o^jTW?X-e$>?zUid$Tid-i-U>bC8OABHUQt90}&av;|7ZZ<)v zrkOxm73;>4lVl?)-z<)a9grF0H0cg+J=wxXZd`UNX$r8e6~!~Y|eeasdN3mIdr_6Lo~ BWi9{! diff --git a/packages/polywrap-client/tests/cases/simple-interface/implementation/wrap.wasm b/packages/polywrap-client/tests/cases/simple-interface/implementation/wrap.wasm deleted file mode 100755 index e8772878ceb4720ef332678dfc6735d2f0a21e68..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 43278 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 diff --git a/packages/polywrap-client/tests/cases/simple-invoke/wrap.info b/packages/polywrap-client/tests/cases/simple-invoke/wrap.info deleted file mode 100644 index e0ca0d11..00000000 --- a/packages/polywrap-client/tests/cases/simple-invoke/wrap.info +++ /dev/null @@ -1 +0,0 @@ -„§version£0.1¤name¦Simple¤type¤wasm£abi‚§version£0.1ªmoduleTypeƒ¤type¦Module¤kindÌ€§methods‘†¤name¬simpleMethod¦return…¤type¦String¤name¬simpleMethod¨requiredäkind"¦scalar„¤name¬simpleMethod¤type¦String¨requiredäkind¤type¦Method¤kind@¨requiredéarguments‘…¤type¦String¤name£arg¨requiredäkind"¦scalar„¤name£arg¤type¦String¨requiredäkind \ No newline at end of file diff --git a/packages/polywrap-client/tests/cases/simple-invoke/wrap.wasm b/packages/polywrap-client/tests/cases/simple-invoke/wrap.wasm deleted file mode 100644 index fa6ac41cc9d8502b37bc13aa6fbe4e67ff1001ed..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 30774 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 diff --git a/packages/polywrap-client/tests/cases/simple-subinvoke/invoke/wrap.wasm b/packages/polywrap-client/tests/cases/simple-subinvoke/invoke/wrap.wasm deleted file mode 100755 index fc8365b71afec34ca09fe3b1ee82027304cf6af5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 41368 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 diff --git a/packages/polywrap-client/tests/cases/simple-subinvoke/subinvoke/wrap.info b/packages/polywrap-client/tests/cases/simple-subinvoke/subinvoke/wrap.info deleted file mode 100644 index 94137ba9..00000000 --- a/packages/polywrap-client/tests/cases/simple-subinvoke/subinvoke/wrap.info +++ /dev/null @@ -1 +0,0 @@ -„§version£0.1¤name¦Simple¤type¤wasm£abi‚§version£0.1ªmoduleTypeƒ¤type¦Module¤kindÌ€§methods‘†¤name£add¦return…¤type£Int¤name£add¨requiredäkind"¦scalar„¤name£add¤type£Int¨requiredäkind¤type¦Method¤kind@¨requiredéarguments’…¤type£Int¤name¡a¨requiredäkind"¦scalar„¤name¡a¤type£Int¨requiredäkind…¤type£Int¤name¡b¨requiredäkind"¦scalar„¤name¡b¤type£Int¨requiredäkind \ No newline at end of file diff --git a/packages/polywrap-client/tests/cases/simple-subinvoke/subinvoke/wrap.wasm b/packages/polywrap-client/tests/cases/simple-subinvoke/subinvoke/wrap.wasm deleted file mode 100755 index 878af17357d313275d3c4b6d13445442964f89e8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 35001 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 diff --git a/packages/polywrap-client/tests/cases/subinvoke/00-subinvoke/wrap.wasm b/packages/polywrap-client/tests/cases/subinvoke/00-subinvoke/wrap.wasm deleted file mode 100755 index 50a0ba0bc01d06a97935ea473a6cd8900b3a4e81..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 92555 zcmeFa3$$f-UFW%9=W*{jx9Zd*;gTxMJ}0Hzk}6VYNMeX^|F^A5$^sJ@aA?ILs5E#l z0#zx?FhJ^tR713B8(Vq?T&NMjL`@_J*b!M{z$oFNM2vznXh&tHStHtMS9CIK=*fJ( zzyJTg_dbtX_g1Jd-D{azx&M96+57+eyC@@y8}ifE@FBS& z<$rxnZYcO`U!*tRkZ@P3TU+{)ZAiyng4)U#{lmKl0jBuUmWN%U^NgRW~M?{W1u@-1uWZ=zmQ5_Whp8?_Yl6l{fy_ zYfirWHLrYa(y?2fvcWA$Za-f%_46xFoOs=dMh6$pz9T%pEBqSfY!8P??;iij&n*1b z55K+Q2VZyMWU`RI^0lYhKl;iaecg#SWJ#94>5XYOOZBhlibr72%$-6R<#JLZxi z%af$lDvFH5>*m|CqUg1XR@Q2@vMl5Gg75jSNcmV4#r8bU=Cds4c^=I9KbcDsb}Qx@eQy2p&$7dZ+Q8QCtq>mA{-;dQT%-`|o>K5*id z_P|>v9|+&ylJ2ZJdetjWYLt_&Om0o*E>9De_744vSFf$U{`ldGPyP4}YcGG*D_{4m zFF5@}m+d)y-RRmkJ@wn3|6|WO`h!2Z|GTdn9sA)o-~5V8zw>3UoxkUn)*FB4Xtr=V zzxk5XWk-tTOR`I{r7Uq*uU(!cb~#G*GBoi#69x+ zg=Y6S|8%dLf!n--3YS_>@4?Yd?J z0+(%f=9db$YjBf3xjlpVQF53&dff4pRrjHf6iZ1m>Rg^Ad@)#ccYUPTpCnh<$L^|o zU*qF@?0PidNB3;{Y5RWK?l<0B@WmV0sbsK=kqcC$Uepg zt>s=?cW=51i01AQjw0bGSY6!PgyTrd*5DZ~_q(>EIuN@(K5mZ{jmOf#Q(Q6m$P(j? z+U~+@7-n+I61I#({#ZIn58KZk0PSmcJ2RYHNrpRII-Kw20haxYv#YyMwu=*GwQ!nH*%(|1vpZD8$%T zu7aR!TDuxLE!zNO+YkNJYUpQYS8Kd0M}P!(ykVF!3g@x@`diNo2X4o(-EZ~OQ>W@_ z4oFDdf8nU1xGhb`YJg3qmE=tvblc4!h8ud}M4F*uZKRMxBMC+;In+ zF+bSV3w?If=Umlir<@x+&CN~rsk1vg>OfyYe;xGzQm(Pk767VWfXZH(LG1>jaZrkg z-de=q2LQ^!71>D|kni;jUxDO&HGDGEa+)-FoEUZmT7h1kj%0f5mKMyaA~)UP!dbiP zHM*;){#bXzZ58<~*G9d4N!fF|SB*NBy_NKetl*1BKU#>u^c>CJvR5u#o-NY!+~Vrx z0BX6dno!TZ^Zmu(pGOLq2KY&OkXq&{uA`@6I-Ua+bl^Eq*_-^j_e6T>PWLkJ5Bn+A zT>OgNJhUe}3^^N=nd`2O688`9EiQ$MrO$zEW$tg^8%UVjHEgf^B(Q!v*w-(rW1j>> z9r!32{6KvRkOQ0;-~?FNafe1s4MLmXqvxuQfusB;4@UwgNL>V{F_P7*!KzFL*E{+X z7lF!wqedBFO3;bI_3Jy`gSQle7rK6RuaT-Gjt!ZAKQwf3lcw3}XZ8307l^!I^oZcq_?mkc}n51J19{6Eh@hyi31gnurOCnNmZ8-ve5^0xcIcUAKp zgR}zKS%C>Se$^6Zf|#Jbb~XCSUTA}*cKe<$7++XFOlDpkTu^l|U-ntp1(T21!g!>DJ|u_;Z1dH^tgj0jeQ9AA z&f28$h0XUlAiqmtVP${ViC@h@yehV5+{}pEeEdCdM{e^#XdJWViY=EO544UelNvjq zdq>~(%Z|%e-B0|YNsXzb#*TZd|CI2lqC2j7q~{-b%h)52-)fX45JJVIVzb{?gpC?!3qVV_FHxHz%qpbQ4q4_-kyoBa=s*OVP z+xZ|p;Wl9dH?8Z()cDK_-N9f=U;ud%-gCR|k@TYWD^ak1YCT8R0~fi*J#})D2a{L3 z;)sdBGiBuc`Kw2RmB-UtSBe)JAC%0Lzd8(~;Uv!+QM{-*++f9B;)>f!wom;!>c6`WtY(U1c6K0eW|o(qlKEF#H^Od z+raaiynxgYmjG^wOEmZKv|zka6a^wW9|N#aV`8a$kmU{B$WLw8Mcm@?E^zys{05&C zk+Y5V`WI}+X2uLtV+s?3*Cov{IKNAL|2r$7o8UI;`zAxXC4-_R@YK(CU)2-51`TcB zbWaETT$aFu#0Zk#stm~zQK)d=9J_Fj0T6vJ>DkSx`{vl4MoSJ0iLzR*@sPcUrY+F= zme|iAbKl~h+kKHYS3EubRJJfze7}2o{JB2VMdT7XS*q@w8{}@Oc^^E4$8%R2F1NUO zf4q6XwZD}kGIjA=<4C& zerW)iv6(;M6tzkO<^0_Dix43sacx=6vC zHk|3Q$%g_k?-(rD?uvb=3Kk$LVUBS~|fvSAz9zA`fe|iwu-i)We<19~qhkrV% z?@`oeW!R%$!+LV}V1gk@VkB!it-rf64++wn=nu1$ty2GZ8Z!0FllIOsB2$F0fSm0?EqHxd@OtiQ-`zssIc#x+i|?#fn7Dh)_Vk_Ay+%ap^Na-C_(Y|LdH|kf zAM1FszL9-Fxre%$$K``Gj9JKgOz$LCe|j?FQW>J~Pjugmgv3B=kQAM&i+ zcYEP3fmmU_um|ccydCU;sfX(2nKg{%)rPQswY;KV2V*Bt^o?2- z`@`nb5eK4xr;6J|1J`xSGiZ?RZ9&oH7CCrd-w;^@bRH|Hr);Y`ouO{fC-;f92!y**+BduAR0?4|lcsY^U6+UNA&r zm0;MFW?j(W`0mo=muGz%wqihoc($7crDKr>nXROmyFA-RGk#7md-{_<&A_jG!5wjBQ_b_xQ`hxFu{d+us))OOiP zcji;YDsuNIVYI>}?x~1u>8Uk$@o_FLKCdGC?Y5ctnDNK|uFnjqB_>t`nlE zTHr5BAx@)!=U&dEOi$o!@#{|3%H;T~$Cj{=@^IKgj5FD?d(>|g>L`=yt+D{MNB4|y z(w!Qmr`Xc`xC~>3JM(D;X1zeplLbr+{z1l?V{50!0>QN%+I>@<2Ek12S1vV*4b7M1 zw)x#kj~by&%S>xW)YAooNjh(a)g?pT@*VVGo`8Ru4={MT!BNSj%rQS9P~-|5G2f^5 zk*)MWQeg?B;xGWC*}1R%eu4Vy-fl}9W=^hy{M1QSA2z0a{IEQws9Lsj982O(-w2op z*z%L3mOJxF4SvM%X~?rgT4 zA$@E2(i2*{@QK-O=e#-V6u29uCr8}Q!CfAuIGpBwPKI%=Q8 z+|n>NAx)fC*i)v;{;n~E-(4m+zPp(gJ-xX(ILN`;_GWQ=i{spEyBjtJOEtTYln@`b zU2BJ~c#^_iXd^AarrXn*X=f81st1O&eIJZM$20oid>8;I zu;UHqk=N(J@f)@4fyDqX-3P2sUx1-h04tQ%?v&Y4Xn~-YOX0FX5vCi!IGq6FGKV|% zB6PCn*V)l>v3A`a=m$WaX-@~DcoSgG`l^G-R<%lfvz{4oL;!v|jtRbqu%6C3g_cf% zc+Cnt1yT#rc8XJd@oKmj79NH~vx1>0XhOew%< z>{ko&e3(Fo3>!bKk;x|3ghZ{i)@RRH~-uv3Rw zPk!vgLXLe&Q^mPZW_)IqWq#BLcEo#+4O2a*C)g{E1-zp7`sMrM37b&LI@DM?c%jY> zPQzxg1qRb>m;oDmCelTu>M{9nv~4ge;^ef`Lg7Tm3vFClv%_I<`z z2?5~jny{mzemaut`fL>Y6{jDT1!ohH4-AC;UmXhTTC0jOFOYv)9v}=q1rQPIxxsdk zkqj!>K?4|(!I6QF;3%$V1d7}JEVY87idivNi-VdX& zWoQi`>gf<8@KCiYJbz5=>FN~J1|ne)VHh3-r^)5fGXWf0f+RxVDZrLc zJz_<%Dn_MmB0(>JEN-ub7ZLOzt1vHq5Qsf-f)0uMFq`xE#oCK$^ttVmg+v?u_zo_S zeRN3^zkL^%Z};EQ#2aqs@}2%$ns~#VT)xMDOA~Lnhs*c*Z)xHU_i}lc|CT1+a37Z+ z_TSRP8zNr22l(z|{%4wa=l%7!4|2&zt>LrvQVKI+>q)t6u4l8^fK z%k||WT=G%hezm@Qj7vW1+ehom^#>3({kLD^+i-as-||uSzJtp%57;G5{Pta3zTJOI z6K}Yk%Xj*3Y2poca`_(rEls@P9xmVKzom&c+{@)%{#%-O!+l(S*ndkCZ+L*qkNIzD z;tdaSdB6XbCf@KxE zc*FXq*h&8_O}wGvLto>&@Utk;mRXW?E(s-`Jd6^QyRU~tZAUWWe@M@2@BXJ}+oyAM z9!hHO59Bj}FVIXT=@>2FjR4ATix_KY_M$YBk5ejEeSfwz+^H`Q`COgLhR_=&=^!gC zWmn7Vv_D%O?$W1ghuhRV-zV@~k0+5&Tgc<-dRr)YJdY%6qYT?k<_Kbe>UOK}aDum+OQ4ThZ^4p*kK+ zmIzMcj_lH8KdOEAl=vH=b4#NgD}&qEp&cvT+t`I2K0@t9Bb4lN*B$KV&O3U@@oo1w zk&GQD)him;;hL>&IoW3j3aIh^mu%VpvsHvU@`5`u_eFAad_U3wyC+W!w(~8x{bFPa z`&mgk5c12(xX2WNe}GT#x|2JW><)8vUdeZCE-EE4__oI`YivLZCuZh1pt8HO%P-T~ zm$H}2z(%`QfTEaRHrOY1F_9DMR6wMIYb4WP&0uFcg9~CZP3+k1)bnm9gbEv<1-Imb zUBn{?+j!=ZtCE*;2P?M;2cY068Ycz@rh}_u)=lMk4QGa=uc`Z!B6@JNbEVMf5RSwh zFC7-d=+whKC!IB1om~TfFkHrPA;YF}H2L97XP+92{m3p&Un(&{p5^YTQR@UB9)CQ? z;8aJNvRvg{O)s}SvD||3Lz+!LSRH|s4QC*MT4#rNws?~1cTXZEf30(zIq1_VxBma; z$GKWOb%Kf6i~yG%SL8rV#KT5%4ywW6pT%?>KR&zZv2NK@@$x~c+0-zU&Q1x6^9=~P%rd!LME8VxQu*h4>T|&<@d^|In zSYMrJ<42tLI6xv^>`wBlNR6R3`&lq@{7olU8qVd5tOg9cfu^`yqv%AJ*C36Va;COJ zm3(x+_EsRVN)nWE8S_B7AR+v>U8F?qi%0pMJG`qtkcLPiXm8F%w2HESjdmiBUb`Ii zt48lS*&{Fet{l8Lrh8Ob0<2~)1f8aAEJ`L;zSP>J!S^LfBe{dJjL5xDH~i7GfJv#H9;~&wg_8Y?$Bu6QTy&U+kRFd z-l!1sM;RMKaoN)aVQiZ1A!f+TMD&O^fC!eoa-M&^W9WUCaZjLs&_hqF>dX&AaHbUU zKB}|@rgVK{N=w;gAP=)TG-_+$d0ihMp&{2N&`m0iHf;yn;%CkHZJY2O-F8g$3{40O z+@oEr{DJL-qQAR>E9J)GXuUN3Rv0aF*zebl87Mbe`(pp=i~O%IBw8%@Tb>V5%KSfg zM!L2wPm=^=PUm3K<&3~~u*Y4ZOiidmez)+VT%dV8zg6fVJ%Rc8-D{T%vY9BDPfx*l z&@`LGp-zFx2QQ5YFdn+-J|GFYJw||0evC2gx`_LQLRfb6wRQ{x9HvmA6JQNNVmG%b z%seT#`)1&qOpPYdU=HFYI#ia_b#-bCG`lPYSH|R+${BBmTEI=P3n{%apicx}WHm8u zgaNiMNi)wfUT8KkJW%YU2?74H2W_w|RZKZxUC*PD5yR$$e3%;bHk^N*`x56L@?Gj@ z1(ad_eL)60UEEym05taJ*N=88kyCTB1#X87lG_QuKn`yMQs~WCBM@q*j|3ws3CX#& z?A*OlzV(a|Nl6r*0w^9j;nV&28s7JQjz}N!tCDNW%JZnNPxg zn(B1w#2j?+K^YTs1{ZO7eqyP>L1L>Bn?jFEdIgPaQTa9883~@YyaP$r?f6907!1@Y zJM7_(oRnlw)+-S34;3NYN)L`KidRXTk+?$~z4Wsv=_m1IF%gB4g+)vUV~wnDeLRi; zUY*;cxvqbx7~JSWMo*M{c=qLnMJ)U$SNhb;*{>D0S z1c56I9a2Z4q~LF?vqtJ3L*9tz&Be06u}!b^i**)?>tvV!LL`hmb z3TCR%ziyps;bQ3D$4Dadp?@LGBD#WkIzTKKhZ_bw1FhZgx(PU_$UEY#0YROM;SuR2 zF%u*9EWoPypFZ6%1cmqKFCFd>T5(i$CPv{(xBeSiUC70Vx%$=okoMPx^D31bIi z*_W*@CD@@ACjnaQPY%M(60rg3(18&Z0*tc)N7ZwtJ!#AK=Uq&aTp?M=1S{n8tiVv% zYi_m**aTc0sdr*ma@Ub#L5#=IjhqS!vx3?xhU86~a$8~>?qPasrGjV9yH~^1LSx=#z}-KMaOD{gdJOj(g~~LIXNX zqp6YGz7ptUt->yBj5WnhJ?Fnf=F!(F#^TAZUI5u(EvpBTL_V#m|3@eh(b?954JLA& z^<}yfams>F*8~%hv%~b0YJpyxw-#A$@1`K6U?wJJW?uZ-vBs=8@U-?04}o z4eWl$ZfSAHPVT^j&jPI1#vRY6lR!8hrYEJ~Ps|%Ude|(l9rw5C5oVV%?Th_{`bYVU zP=?{pz4n?7mVls~x*LwW+fR!tb^VfVKm9$LzBkbNi86F^9gnL>Z#8*;T3C}Co zeme`Ux&V)7-=d?09lYhtO~h8xO?rlEo9T?)gv4!^$npv|PMIA}=J>V`pu_j{1X{AL(cSyYyO;>lB~L(*Pg z)wV5x`W*I>8ku2IlSPS|#Jh}o=?vmsdPduxii#YSPBwqS#c zJ15WEXde3)tbyx6u$_6BDa37ZTt1_Myh&DN*E#+|5Q|bJ9E8QDh%$7+W#%v}vSpn% z;#(I%T5&aSp>pnsy1=xS0|Usgr@xz?O@c;#qt{iDocv&ty5}9|8d`-M9(^6JI zK?F}B{cLTORrueej#@d2IR8XD5a*Ak0$+AFNCDKv>*Ix(OdOOx!=haOgT)yT zLSjM%y})&G>WT^AScYtt$RTr%FsH1XLs&2=q|GXT6U|c^sZzT6rKN8On8A_lavdkj z(qVTHSIA`G6M&`t7rVt{sq0kNc9m6Exm^LzI#z>23>jUH5;gd+E*jl%CfuW20b!ZP zm_HNZR_(DYEag1aUYOz>vtVYUR+s?bDYUWQh|CRB8S#*Qzzq!X(${`oLs;&d%T9qa zlC*|}=D?kEiY}TXRong$N@Y7S&ziH7!)=V-abH6xT>uf;vzBMf3;gIUOD%PyHL;Wa zWJXPo89s#C!-7e$MOQ#K6S#u#=BtFYPq}IRe!Ns zV)Jf(Bwnxa5ggo3_XA8s*Mz->a;~x5cDc>(EQZI&Z@~=7CR;mdt-4#*i`TfpDSrlj zqmexPVsnWvGDWc1QA_hAq(e(%oNAt&nNETAb4L*uZ&Mp};#zV|z|O>OBN9J!1o=2M zew#K}wZjCUFeczT0A>bc7*y()2$`8dX8fiBR!dw!;lMU*ux$`2hd2xk=75hH5gCIJPB4fdHp3k(IoBB@@oYrq zNwX#v(AMN&g1Vy0Vr@@DTmr>v?_s0)8q-UL=|yC&Q^G{F6oiFS9H3+dT`6?M6ET1; z!KndgC?QJ9Q$%DaUo@|(Pt+rVatKrsgA>^UWL)ZfKo9`P9z=!Df~0nX?CGg!&vI!b zf(}Z=Y>a)tJm|FVJIxxM!XQ00&8DfTB2C$zYKBmEL7aK_JQ=FyS(hlQ=845m^K5M} zPcbo;d@Rm(1HwPyQwfs|rOfh1-<$O_?koxY1aC=p5z7qnXTH6c^oDIOok<3dB2Qh| ziEtp3&hRx!I>Trv=?sH~4<9k<44NwGtgSq=MH-XN+LFM^*x^1&S1#$@zL<4RXOoo- zmud-1L5@Snv{$=npMsP_lwE6#G77UCEhaeUu)BRwZBP^ZE3yJAfIc#N{DwkfNm%(B#T6xf*9Rxylz> z)fmFMaP5ErUgJ436ACmw)~RL;=)@R4a1Nl<3bO0M+# zy0hA9mpmt(HR3pmV>zh(p;h{Q09kES6V@0`?vYE=D{qm`NArE`#i4euXVWnjMjtJx^ns@97`XVnpbK? z#Ez0L0{US45c)h&qfa@3J{*qWcJ1%==o9?C^|BQ+f(RlkG4#07Bg-UZAc!6VQPJtDfL+2L0p!sYoG28dIRp+x2#?-!EX*nKag1@(N44f5X5INYT zLlI+|BhJQ{rVCah3S*#i;@eef;l>al$J0g_bLg!rhu-D^bD^>D*(fvadi5yN_tS`; ziO6eapp3-db3~aysw?kiwh_vVdtg1v1Rrd4g`oVL^-v_Kf8+3Gu}{Y6hAgh(5H%JT zY6AMDEQENcjUTUFm!3n0s(#+rgXP(a(Ho9ldmR1a!RHuaHQJj!UOOKBhmw0CcB78g*x>QnW#=Cc9y{+tBJ^XEwb#x!|9Eh`c~=ict4$uS%j)^Z zgFDXqc#!?=ad)8+9*mF!e};=FVX>+g^*P?SV9B$i6TPnK52m+)cS#pBj^V-7*s9zUe-0!54JA+AF@j2(!$Wi&AfMxvb-49 z+O`X_yokc~!nW;$9XogJzTiT1S(H63U6wuV5+)tK+RYW#M*Vc4%;n42%crmWI@_~o zHwea-_zE8eebo9$3IrzjFM>w$l%NPMTu=e{=A$8eYcwkbJae>$Mi9pfI>Ci;yxr$@ zyjsYQ<7J);UJ%ENTF6#*bMy7p!hakuDD4zKvube*JJ0L->iEbwUQpy?b-INe=XJbV zA&BDzg@0#U-{8ECSBw5}ybun#BaXNIypC53^l`i(&J(WU&o9)%_9(Uq_H7O?wG9#lP+GAwDM6>#Jq@I9`zIqffCC%(pV$=Ig7KfH+=I1EL{2O7iE4Ue{Vf z953h%7`!WqRyERnSrY8tg_miOzh=p_cpxOxB6Lfp#YQIS4POR=T@+Xc5?Ec*d-p<; zEr0$0u*k@Wi(q+4YLaEJ0k(Vm?5C1q(!)waHsj9l1*n2D{O32UzWL0fU_ zcd53v;@l|p@N3~!2>rd)Ll@0@=+R%RANp$b(4HP88Rsb&w(wLQB7~wbQhU{XIo`-f ze-W?yJha_Ew8%pQTr?i)thzsqH}cTu;3ya#z2B`KTI{(UexwU|Xvf${ z7_&a{YsJ9?vu)UykH+U1_&2I+d#+1X_JZ%}0(!D)dDWKU82#1i_SC&UUiY6`J+yn) zLq8X9WW0C9>ppW1Te^#frndAQ@kSo{$#{+ZJwCK^)?rM5FW=-$W zcq0$}r+D2MNmWIrruQG?jXd<1@w&gWn%?$V5B*uZk%#^`UiS$%8~82X#zO?;G{6KX z{!F})hkiF+_bKZi9$J|7&~L{ZdFVs&x-q@}tm*w)ypf0AAFr`vMktnpa|()oF5bvP z|5LnfJTyP+p`VI3^3dDjb)QlQ0bdlsGd0rVzY<@_1UkoS%wG{;@wH9^>?83;M*5q0 zt%m~a;rN|C+`o=D^3b2hYXx|Qhm>1C1rdJ|Z{(rR#cSn%hlk`8o_gq$@kSo{c)TVx zJ{~ThFbxsE6>sFB55{XvFF=HJ?kO<(m3Si${bIb<^uj~v*V7NZJKo4cKOL_d)5Cl+ z{m@Uu8+quKcum}1BvFc!n<7!`zcNOm9=o$X>qn~VNTM(e7`ca9alxkg3n0c{K(_n^ zyU^|Z{ouboYl<1zGKHGK>IRcGlr5T1HWffBcWx91g8Af0Qip4YY8)^1>dlj+4sU2a zd6LxO4b3M{k~+Mh`Q%Abhc`5zJW1;ChUSweNgdwMeDWlz!yB4Uo+Nd6L-Wa#qz-Rr zK6#SV;SJ3vPe>i!lzKMaITqhOlCD7ro%JR>VY?8ih1U`zOxp#B)-7TI!uh(q?p)3RMwcKR6I0 zv?fMS+HA}1pk!floEP%4JVxm#w8VO~@TXd2kdtsFmYDE8GOytHRE(IWMr4pprsn)| zKxQm9I8Lgl2^Kr>39f9BCNdZ?G;Ss(t>V#AGEm8<&ywkL&j)00;R8vl*YlHw)sVER ziE{U{Z>}_lm;zj`)nB zKS^9p!&p@9gxhz*Z${0w<7Nb}M-{tKZw6cOoPzGAtlXLUE5x z0DTdNKz%h3L57(c@N2H>0Y3%sgIgkopeREF)DqxlGXTFo1Mq9!=>ebF$?*^(L6kf< zwyxT9pmklyx&rHqdA?x^3Tc~M6!AG8yL~7dXtYRLiJ?=d@xeDlvUwbc_+B$VzwCl# z2k*h;m@FITzEk3ORUL;RCs4iSZhpnVH4wr_f}wuK?saGEUd_3DU%~7jVo7Qv{MI0> z!I$bxd;&`%#K=9K)b&`VR#uzo{cM7fJ_Luv*pjKoYHPcHEZEw8YMjz_1cguwmGB^t zp?=Tg40;jl=99&y{dR(2xDo`MjWu0K^*Q?QR`323+z_}Jh+cz45(4Xi(UZES5xo%Y z6_J6hQH%EI3Jt%Y>kWJt)>TNEc0=o0E`nN+ctkVi|(Bi&FT zjAo6Ra|CpT1{F(*5zwJ%x)~ z<{q&(mZ3-8ZZh|V+Z2n=y<@q1eR9XFH%sBu6Mb^}tlMstNLOydu-?et>xPs$$xeNR zHDNtHG@Ns9S-(Go*)&8lTdX9rvb*h)xitKjx6-tTADV3&F5Y!tA~&!_p(FOT5wFr6 ze3J{t7K{TixXq$bHS_eut4Q)z{lLR!fevrkKi>QWFD+T+LvKKNCVG-Qb^LO?9UA=3lYGZ`17t(~D z&u#V)2x1XbROeBC7?HILjaYe7bQpPFS%^XK3riGJCwWh=-BTitYw=Q#JWO|RXG! zkHms#QwiUl22BZI12G&GM@WBXkr8ly=k)VYayp<;;KqbWulXoDrQblPOqyPBwG=G2 zgN7pD2!e3bp8*bDibsZ5L^G^W2@B0a*jzR=V%ha*xXS?XBa&|cO>(~&Mr%zVgJQ=3ha;#a(D^#i3Q58G~0d-%is^CqM zF!j47JgAC5qTEl_)z(c2f%!61LQ-I^_0JRx=G(_Fwm+)R1|(9$o>?#_ciKZw;?{Zj zh5_;5>CouZ>J0NJJwpTiQ8C=P54N2W5o}#7wXJu3Xe-A`ZRZAKOgS6?WJj+xNXks5 zw$Yk68@{7Kgwsi>VS~H9ueQ=Ie22At_VG7T5S$lfq~S#ww9s%l|CCd!9cnX+$aDh4 zQkzF(8w!&xW2H01!Ko(`4hbq6VHsA8>H#9sQ+Axf9qNz*7nJe_et69ZGDn$dC;3~P zptc78m)RP8vU}Z$1-+`?K7;VQ5`#Qe280D2KjAXJT8)baQ&$N`vk=~=R`^pmi~4|d z=OO`_uW}m(f5ArGLFAbMcx)8I%Hb*qyh1Pp(TI_L8I%oRKkcE^sd_%sBrCHqP1_!b zn9YmnC~5{U2WAqVKD^<&Jk{a>X-pyrY(P!e{0kp!c0wlo4m{XYgd#9wPvJTqp*sPg zIg&u(LhW+}@knW&h0vULtbNWQ2(2_(K}TbO2o7642j-{kndo5V4uJ)Jds0Fo!2HC$ z$=zg6ayt3(Jx0E4+@pwWrtz`2tv!P`5Ffrv6u$R2y|g!}DqUHtN?n!#zR)Ooo<;^( z8nJg8W!KW^HKjDlM4;J=WJ6OTn$qk;AfZ`8RiZgS(L)+(Of;7byIYUJUx#KCSZuMv zLFhY9sReu>kma?)6-N!-BPf@|{YsAZ<%8K?Sh%q9#gK>%Q0f&#$4e0QXnh z16DlfCcgU$R%)VWOIAx&x46qpJIMWpMdfmc~|d!zbN z&BfNeR2JTHTDVgAtWesn#A=-(;t@4)EByn_fPP*Qb&y6sk5aH0OhlN`?jp=+m%bFI zC_%&TpKTI9VUn^L)>dC;hynVUQTT849cOi=pB2@qHLF_cMQgBG1);Zk5@VsU*Un*O zY%lAd7yH`q7nZjORM8B8v5wpK8dA`iXMff85u(sA5Vf=;Qla$vy;>MXE-M$M1I&eFY^sBCh~EE8u~TR;%bpAK^+7FAX~|=uV#~R-6jvQ|V6xIT4v*%fc(s-J zoVtCID=A7AC3bpT@}RO$qX}(oOE2S*c|F2cySeU%YaAa^D*X2I+rZCCsBcph^=gRW z6h|Wk=_S!Job%Q*x(|l|DQeh+Q}@6BdrI|kbFd0?b2ZGC=4eY~PUK-nC4zU~Ry851 zqz`OE!v)xYxkv(+I#yx*oq;ll_W<*f2|!9aFmr3vre=7I%K`9UXs*C?j(xI1l*oyC zo1H3IorgRqQl3H{)FPY#jND6udQsB!q-C^JIbn&0P@V%cre#>h)Me2wrfjpM_kZ-# zxk+Mw84yf3D|oHfb%@vt`=RneA*ei!s65S<>|%&fp32h%yVw@|asi;Ic#tCJKf`oz zFQ=j|Q|53Fm<_a8H7HBMnsW#F3c85?Ja3G=&`Zk@7c$cwta1XMtYV&cVJv(?mj5u# zIj30pgjzqSwqC^TN-p(9h9E_&B2SWfAtE)&QPolvEE&ydw>n(!MeWcvPs<2fmt%q( zLSRsI2HzW*M|9o-DXL`x4-92T>TnSg%?hCfCcnY=p@dA$dnniBOUMM~6T=9!oDECJKuQf(kC@$pk~B4MLHMZ-Kk%34IgTBE z%?sx1!w(E${2}%RU_2ccg-yDg<0Z`yyo)Lzt`=AGh-z^alfcUvEGJ=c^rS6hdrzVT|BX7yt3VnFV}xHD&j>m&rO6i2KC+cq_WC zR%EzPwV$wy*s8u^CM6^G)YKBO_a>!ChIMM^ETf!Rtc8khB2rX-4r!h)(#DF9 z!i<(ixn2;W*KX8QO(t!s2^_Gj>nH;Hyz9_$!^p3$tJi`=1E(Huz7zx(+bIgNsaAtt z0MXTJK~P@wS`hFz#$e2{Zj?Q4;q_+Er=|qQ?H@pehcBf}d88`0^wv`Gu`e{b4K{9D7YI zt+WsOC-E=rU$uw2C_CGV9JdJ`lH83T{Y8sQy?TJUDSFd{sv1`BDcLQBn%^vMULup~ zsuC`BfN$@sUsIyg7UjFggQ$tV_}|{B48*$2($Sj*x}~zqVk|EZ-Z#@KbdU5G8c{v= ztftoTFaWqDw+C`vb)5KDlkl!Uv;bcMH4wU(*=}X@L0^tN(!j}+R1uxUuo_!EkjVHo zb(f7|?42T2a=nMJP`ySV1pw&nC33^7BFG{LS0&kFNIl7FiRZBwi)d1naGgn&oiT}; zS@=mbO6Ww1nKRyC8uDDTpOcdap$6zPr%q@-p|B2@L?d8G@@4eO2@tONiwEJrT>LB; z$?rR8F%J1-M*8~oBDMcJLwEPm^Apav5*xJ=GYpROjFUoQGY%dVfTfDD3czB5!W=(F zJA3~)H*F3%v=s^2T*k74AoofcqS?T6+?0^FE*e8cDMHYKiniQ7GwFcyToV531mdCPPRld zRf{!jOwg($R{59V=3X`TUrH@Ekr;Y{1xS1aH>Gq-%qq2fjB1Ec%^ZcnwnA*G6$^3D zv^`b+Bs56{Ia7#(NP%r`B1Y0I0Z6sCvNK)+FxDN(_3lIUp;ggf&vLwCl7gE?0BT4L zBDG10DUY;HVpxz=q#dB*D|YZXHqmMz!9S-qAw6uY$!~%flWhVvhp-8@9i^XnP5(7> z1W5@UwJ2@a!!}U-IW7a4y6jUw9fjkd64a#eX;1cN$x8VXs!jsB+721b9N>h+jn4nM zKXHBzW)xOLg~kk8pqCxwl;(`(zN!7lRM=&0G+8LACTmqUq=Ld{WDK`=RyTSzFG#b` z-1_8YFq(~PsnWSg8P+RyW(o|eSGtobi>+jliGVSJITom~F=dBSHyK4|U9%M1F`aeL zB9PT1wSmmWL&nmGp<&d$2C(L&135AXF0SMBA`Va<(x4iJNyFPD%}XNLC>|a25&Xg^ zaT_;Sx5Z!S=mH;#-b{`zQQd9_WaFWe-9tt@glm0)aNUB(fz61J2#)80&Y6|K=-eWd z&3uuNJCOp&ovZ}Z^OTjKFu^fWJyq0`#Q118U6`~CG|a$uBmkoq6lp5Uz}D&Bc*G2N zCHt?vdu|IQhQWB|kbQ5_;@ zljMPf$*>@tE?a2HuB+d}(+aZDKQuu4;8pjbLUMu!N9tk;6=@$EB1r4g9@E2wZ}~EG zt!r;am_IUV6Ilv9gL+U`7x$Vx5DX@@jb1b4PZGoW0rVCLd%~s9^nI}d#<8DN5`N?rNO3L|Bn=*?K+CU=|r{qa_q!A+KeFJ-z+t4x=+`VUzOMO5?>emc4 zYA~^iFv*|5fW!AZrm?%hrc-jseku9BycnWfD!!vD27QelrE-dJY4a?Go2nyqk zGI+-&VT=5R(HV@AqBD@21D@O*qQNLRZjFTMJXR>|Ne5O1HVDB1$Fb-JVY{4|#=sTb zU|w*(w3j>bz*uyHS#_IEKn)P08@!9K5!#S=$6u(3j?YyvuHnupv_b4cvz`cSsK?b3 zz4tMLwjgnNZ#~B!9l=#l1Jc`APy-NdE1J<6Ayf)#uqPTp4O36VF$gNK01%0Wbs&N5 zhDAAOgPGlVj&hhW@yQ9<*2t-!27fHi44!VE$DRDxE_vB;8sC3B<>bc?9G(0r=*~J3 ziq!N00(0`yvz+{YIzOG}Dz8qkgnJ>^j&(>!#`ZSzRMzGWs_M$zVN5DFUgFuvMt@Bp zVB-P%+4-%k1VXJ<*b7o12(<}?H2k{@2QM6aMY7TK)nFw5JcFitkPLM)Dj&D-PJ0BP&bt)I;)3T6eGL4T1Ak>rZPWg^-$~d zsrw~*z@o`2g2i?!mvdGRwL+e{e_QQCFyBsPXU^)OR-{P+uX+gT^i;m(tR8BeI(2`4 zSK+9rz$$``bt;2$Ru8p3HFbYQ4;~(ZNp&hGa#jzu88vmEuX+e})Tu1TSv}Nw7pc3S z9{gFrlqE_`OI@zoq>RgJ{ zy_+69ZibACs2@}ozF9rg85F7eSJgg*Jc{TLK#uX6#H=0~SrhIIJs?a051}AZGovp< zo2%52+!wf!IWZ~-jiQYRFZ_V?0R>gi5cISgZ|es=;_q5%XHt)7(AB0MVLrtzi2ilX z9tIEvfY3=nw2P_QK|X6zR$nyTMpAj=%6u{68VTHWjuTqU>!DqT*OMS1qD)F6Z@a5~ z*4Sg{`n)efufmZaFIK?KU4>!N4nn&a+A_3Dp*4mZw!|2L~8)4=))I zAC@Yr3msnav}KoJi0Acdh{6i>&K&W(3`Fn{@@-;ws!#a=jdgO1j+!&q!JDMfM?5Hz zWdIxO4tlp_fzg4_n^(+nhJ>XBk8nH047xm-O zs1ChF1MaTBS=PILWK#;q2Sn}9?4_VWAv~rQa^oqD?0OlumK|jy89tE2)v7-1CTB2y zFqsY+OpX=h7-fJB9UjI~BW(2@%9#%6$Je*X%b=RL5SWIS;fw+^mekeM+uKw;7iexs zL*{G<%BK&7sp+JE`uZ|cjMTMJFUs6ki3DK)p@ZHm7cQ$giL%{bgEN>yLYRl2CHt*e z67wTp$UA1wQnRap7*tB@=&cC2qA|}G5g@upVK%gd|45V`AHBiNe`9etIs^97e`7B= z&HTI56b0XKEx89iTDWJpM}D&y{C687gUr9C5ik(t9%PKjw`C*4Eu_U6nUiP+chV{vQ`_LWpRXzpL? z>n~4RZ$3dqoAXWp+fCge1<=%vO5ji$7~`{}jF9{eYR$qj>L=$nqYW^%q+1p4$sV zk${iU3tQ1)76EjspCm1vC?@R|* zo&8OKCIJm}&I+zF3;0ae(H4ZH2+;IoU3dZ^Q~JQ-k|Y*XC)06HFS|0IhjU3~K98ph zNhS%8B|~6_nX_CxPqMRR|Idy|mu0qXshfuXHq6Ac-#ZYI%+m3&YmOf-@<)}97qtYy z$AWG|gF-r9LOPz%9O!5!<<(wXM^au6p3SJb-HLP)@ z=`o2#LI47&l!gb6pdjuU@)j)*vn?#oq^vQkq?RD;g0KqNH!m@S=9;~jjm3QJ8zK>e33PUuJ zKEr#g!hg^()q>j#jG8RLq9kC60+x2A;_{1HsA2^&MbS5eoyYEDN?s(B%vJ|})G|IW zfGoBcX-w3;#Tek!dSjv(Hvt-TJk7x*)ie}LZS!^Ije5^!b`qre@+XY@YR0U@efj?I zktvQXK+~~=Z9naCNz#J-{j}rz8PGH2;jDR$fY&CTdInOd{4u6X=i!}%uuzF0Qf(S^ z1%8IIO{%niKGK#-3>|yk`(HxD-uMfrm`B6KX~+^4ev6Ng>oDpyUyo_Of^v3FeC*%O zP~jW3c;p=Bl$5gs=F>>{qLJ`Lqj+!{g^tm{i#8L*Vo_}fJ)tm4Uxk8FyZ7QvhegHF^vvg+S4l)I@X4vQxVye(n+Pzs=BxA>KqG zDocl1D`QIT7ZF@KL@5@iBmO|y=!p@`=dd8J9TO1EEjz4itUu`8T*X>hwR`Me7lV@# z?qgh#1Qp0>C8#J|UN_z-acM%L@jQivn;ioAjdzV=29S>=*IVI$R;h6e zXHp@6atIhrA?Qm|5HP}X1gP-dNuoZk5CkYB$_C@T8JQeO-*g7H0`7u5;$}D)ovXZ; z_GZ39dK2+HDsYXweI30f(s}j<9xU+w13Pg6E!Yb(=@laxgJZeB{Joc~$D@<@6tYW_uU!Y7x8laOE zbR;AggACxdR;JhWJfJmb5PS}E#B;_d(9HE~JM&d27S^70@CHhOgQvN6B$`oV>e~nR zFnR5)2SA!8V8ZcuGcua8XaT6>nLgM*rCI%4K{)eNeYi>dhqz4RzePg9s5Zm@S~$bV z+-4YS%sy_JJ#&5{!QWR(9@sEGu((grjPt58&cL#(0 zb#hEpVr&4+pr>CWYT=ZP>*porHmh?87{@m+5FNW6$-OyAA+My*sykUqfpuArZQU42 zo{k6JWTuFfI!a>}tP#oS!iZ0(l@Wv5KG?~>K6bN|C{w&KT8LFxkeGrR4LmFmZ3;a8 zyq&eCUlDttwij(Av~Qf(q-b~3$Cro@;qfhSkf4Ek4ubpFJwh1-{s(t}3Xu;5$0XO9 z?KTK8vfjFTNtx$=?h}Ou{&kO zdxE_VtXBCU2xYoM@|~x3Q7rK|W2h5jP1xiHjev9SXfw0;m~x`#SJprO+wXYff!l67 z@FG)#;g0Y}KMi>TF!fu=TT|T*9c8{FoO$9C+&cLFXo`&XCC~Fs9-trszyr;~LKoAC+`=%iGU)IZ2|-lq z|1ZBD)u+ro7O%OFP$9o6%H5!!tLjZ5j1!?DSV~eatgETyG9d=!MR8yP{4H)<6-ThXvwe-e56Hi!zL9BYDmLIK60uK)7d@hP zcdFNf9j?NNX4E|l!9)=T&R1SI^t-BiXjss@JAvBfv|mx((f=2yQd2DPOZ6%k8^SHkv+UhJYVLK!aePjD~_)MAik^) zoEh5645i0=l|GIpg;0Y2D3u;j*)<^nf=pXUp9UdPZ?!;b@TZ8Dv8aXGGuCu__heRU zOJ*utuzrSnjpWmFyA=V2Yt-1=DBn{i78eRWK(CdX>{Tlmo|yo&gQ_(IddWUZ`pPiZ z+7KEtOyl&!j=|ET0V{ZdMH%g(pA0b{zM+Yln2y$)E&I9fDtmt-D%z9Cs)eHE$Y+9V zmC2DksAF0lJ{wKQ=AuuDjv^eLLop#2>BogHzyRckjb?($CQUG` zWK6%-=d+k#yjENX5P;T$7e%VQu|1Y;F*=SUkil*E=bG_C_B;iRPu~0Ts{FHwvfn!8hScRIp2gZL& z`Fu~L9+BVk@LnYt<=~;7(eoC_=L-SVDCwU+7*VqEJYidUz7carl$T}Y`w%=tBZb_N zbs?e3tf{rk4+TI+4&q+jsVT4GBnpww(2#4PPhnYhEZ-%Ij#aZ#@S?G)N;z;}dVk@* z36Aku+OPbw0`h|3HYNERSB7D!ugIKDM9D=x3yTobTmJ|wjFDvt5rAbk1d~xgV2!1f zRt{T28F6fUUaUT=4@5)qOuT@0o+|H1!jd*Gj#*XS!C+lR>SkW!-j|E4JFR*=v9#g+ zfGHjY)lD-uW-ve<@a8Ch{hSzS2hdH~#8H0*LGbbI-y5t?+078gAmLjCp}?j~%v1jk zCI7FENY^dr32>6o=!;y=5#fVXLqf}FZcUZ~45cW+ghf<_K$$(-gBM2x@b;L>@!4^2 zS9qCfbWz1$o-&eHae$C)pHSIlf8O;1d2w^uZ)J!k8j9pu87<{p@a3fWwhJ<}F*23y zwZZ=g@S2amrQBl9ifWdyaBS3+U?sqppXU*9B=`^xaQB-Ov5Kc=>1Bat_f-1dtUF=*Sg2#uWuu=f)Bx7J4L-+1_SqdFLS~UAdYJtJHL$Oi7wDz|b)1 z0};wBNwfFSRysfF^J&1Cq;e=CjVPkf8a05Xk3WY-t}q(;WoZ@>OKC(AX=Ll9QKdc_ zRqCTTAQg3Tym2>FuwPt~jOLV_-o^hSu!?|XvTm|c_+3Q|`Ro6D?_Mg6az%|c*+RMQ z$Xzj*SB%=1`S~aUZ*Mg3!_(M1seNn(1cYZ;LRTuVDtqr#x;cQA8T!8y%EWy}9Zzf>(|Ljh~Zn>ES z(E}|5Cm3|LXZL?)Sq=k=q74vy^!UZ3mJy@{rKI)MTXIXz+uxr+df{n?W<|(7Z|;2 zVH>chsIBZ15aE8D5MRChBZ?xPu#b5U?pZxV<}t3ONWY5BV1amrqj0m8UYH^FYqMbE zY}mM$jWDMgv?1+4w@J=6WveK0s8_TDvW^HAC`X*7IG>QIW4uoWH8B})jfB|=URYadq3NT5e?j!&Epnb0sv zhv1WNsZt=Pl5#W_z@wYOEn|L zZ{IGKk>fA}?#~yM6=E(xD5s5)xZ6I#0g90ut8GxlicN@9NL}`ty7G^ZWYqN&R_1e?Fx@pVptx=+9^M=MVJf5B2AB z`tzXv{E_~AUVr{re;(4GKhd8*)t@iu&lmOQ&-CYi)t~=Of4-zYf381&p+EnDKd?oa z6MMgvpVi!_BOcBaIkzr4D&DF}mKKKwXb|jxI;a-qK(PW!{-?Fl+O$5 z0>wF>*`Lffv+gV@*~|cy;JE=?im^ACRVcvkQZx!kSaMVht=7@7^d!P5Zm|o>-!$w% z@>V47o=^7I+=Cx|#!;?6^UGYfj-H@8P2zt3(cYT-tDe69%P(;G3ya~0n~%Gne`Nj$ z-@o_g_??l*s?a0lE^y|aK2y3hZ+!hIqi3?sTk|FotP zqn?qZHTRGH9Th{{deMZ|p;rVEdUNYZEh8AT!7QmtwKSHvcl}i1mfTnP`wN+S+fNtn z1F-#CKEu)#Yy#&R&lb^8;pK_K;Sm2npC+;B+SyoZNnJSG`T+=6(0ON=Ad+t1`S z-WfsQEOEqhrq);-amVvwWXu_KU3R+huTg`%7Fx;LAj|HW3`s7Q18BF9NI~OD&PG?3 z1tlqWNMS||({>;$*ll`2RKsd++&)qHHVME}6@CcG zTG$0O47CY0C{6{hlS;AT6DFOKhC%nyFz6Bu^EyDooDW5UXQhXGcjmL+Cq-Ag$SsTwuARa!j zTI$ldMOAaAimEns35AmrjwfaLs=W^s(}g-3{M0l(${=b$SrLOOrXy zh+BvRpo^YAK?oQ~WBRWA2WHfX=GvN#D9ZNX-%wy(I!-l2sG8Pe-S`MMo}9G#JaK!9 z0R?f6LVGi-V07?KuF9?p_>>V~ypxL{{25W!TLKvvVgMOmQ`}(1AgA2i$xs_RNn|nW ziu_sKmE=WMm?CmSD=8SUNPNT6C@{fvfl;%E66v~9>i-w-xkI2)$Be4bBEFJo&``8q zcSKgC07F!2l-j(!h?ohV;$ww+=zG- zYnklcU~wV9Ob#<2ZwI*N?!yiHE}+$F$R&yU*oS0L4d66pbvvs)6}&U%0G-s_z(T=2 zt85iCG5|!0I?Efp|qw z3kU-9Jv9!X^%5hgUQgO9P_ry_lmGHPVQXN`&AXEoRFj&R%E5K0ny53<1}fc>CgzUX{71Uh(prg zZ{19;siKOB+Xaf@iU3@`%;aj9!dQGUfSb=CS;ouAPKqy2Fo?~TA$QO)@g@r_CWHEe zATeA@ncWH6cvBj3%0I`-36-R~Ingvd2{9Ds3zt2!hhB1o{!GM?17A{(+@@v0J90H3 zS8}C6T`^G`__iA;gXrh({a}L$M&GEI;Ml?&NKz2ln|Yo|7K=0$fRJk8mCn9_-~N2O zXK=*%V~j{s+CvD3yKu|7#oWFS|<-r8`gTim&z`UVasa( zm{$M+&_P+zymOQ^XxN7;U$8$gGVKqI_J=7Sld8e~wD#}g^j)a56edS&igGxQW7!!)mN_0jx6%JpbE>edP zD1-l`_x99-L;#2;Fj#>Jovt7vK!!hlW05+*27GYBI$rtP2J^j>5BL5Jg<__Uzd=R}rFmNP!$_Km-b&B2L{X%d%|w$alZ)U%5XCIVZ7pyX zUb<9?(gBu&bwz~A!wWb>n!Pv+KPjCDP#6 zB|M81tm+8$BZ|vmOCX5ot~zz9B`N&{w2nJnr9M4;C$EgXr%|G_fuTWzB8WjHBt_-0 zCJLJSKFYyUe)ZeXi)xWCqA=rs-7g7>Xl*{ze>%6so!hxx@L$Kdy+2E*OvaPk4>G2XX5fjC$QV;9wD-iMM>1v%Nhsm*Zaf?*a9<2YDG)-g;cdtDwP3oE#x!3uMdcs z(}d`CSC(bdnHJ}VyVkpe`Ni*&bRN|rBX4$aNH((^iP51Z+@yT!ie-A}%A_ac zNVZ;hQ3my>Rr{4-c=Gs2_5q+2f=B1Fbe(%-9NPrs>paGzfOVQ{qixMr6ji=N?#ihwIM6Lnow{n^SeTUI z-V+Uziue@^)&DoRH}}5vpY~=WxOo@xuKxr#vvEqXz~7L)`JcZr^hT`fybzmj7()HG zwlUu@Y`P~UOnVdQrD-)-Ca#0p444JPIPLuvz`WjHfh9?bsy>m)3QskzXpPLS-pZI;@`t1dpQqWFV7-XDV7>>mLxJ4#<^!_G2tGa4J z8Hcnb!G2mAt5UKuZI0-q)ja076=`R+lO?@Nunj3$we*GEegk=ZBWy6M=*VN2N4W`k z{XJUjruc0K9_M07rS?auT zAC+;FRn$Nl!c>%;W42phExcAE_h(|-my#!eVx=%Ce+Qkb3CP0f8M$%j{~IkP9);;~ z5QQn#X)8xjFCwZy;V77nj)EPTbrfE4k&(Va#hScs?I?cw8%S2+2k1JZe68GwoK_j^ z=S)t|qxSY#Hf=}Vz+eOB%3uRv`M?93@mG;=fyxpePB<`;VigCBtrC#dHwN5q_|F!^)cx)?#T$tc@@l)WC|2 zo9*T6321^2Dxk@1FBTOuWqbLVl$|%rkjM>uSa0D8uLxz6tH^AARTQrku@XB~2%#L} z`aV1r+-P>E)lpDa!K`IpT40jC6s_jP?z{(7ZmbaV%`J?tcmDKln*k0D!9xRL5TcPs znx=C0Y{9(~kJ)0Kct~Tg1k!lb+`g6D7XLa5Bk3n&mP1nyg<+ zM>7f@EEiDf+JKo*HX|A04;~7_^~%O(XkJ;Ocrab@35oD4waQ4w<^5GDD^43FArg|Z7OD@V>* zr$hotHcU62c^%Ki9xE&Qey9XhHKON)UmCc%#d%uxj`bp=i!{Di@%u$bM@xC zSr8^+ICeNesy!-ldVaJKtgyP!4}t zNh>Vpp?lu)gxo_j7WJQJENYTy!N~>U?62T>Q*T41uQO%S)m0l3#80jb)elkEvjr&5 zOvycRl8Rn&umXD~Au7eWoqLLG1Tn9GJqMLUNQmRa@PCLd$doi$ZF7VoLtiolo5}0F zk&f)p>fpbpF?Q}5G_SD{%U(=-U5Se(0}tx2qt6ziIksdCo^)|M0kQ* z;apr+fdRAc<9Otf-ot5@p49;(iYhr|KcHf?ZVRGk(uK+`a(;+q(IzU6of+E^;Xii}e;&k|DUIOV4nD}10Qxu=1H%6(Wp5?~phh@BJbj~xn~9lm ztvs|Sr0^@0urh|cl+b&3;o!96c?jbw&p9kG(z}p^+}o}5jhac&XL>vMl0|p|CP}^b zXJ_XHGtT^+4tu1LIp^uq1%m92S?A|$In*h#^@S&QXpmDH$@)!2SCx2l8i6C|i zAHhZccCsh$$bM_vbjh$rA}Mnc1)`B;LZjelnm@5UJIG69!L`R zJG@SW)10Flg1o7ch$b^+<0#H_S08ih zGPbPKZY#!?56!JP;L~c zdI5IC(i@b28zCqoL^|4PRB@`*_daj|MV7EenRblf(uAcrE_2neMK<}BTyo6-9dn1b zHO5z>Zig8C8_6FmQ#-4t}^5fHW)#tw1<=Tp8+qwUT*`2+!3UER0 z<<6pF3Dd>WJM5-s5(P87i15$3siB%|fNueZg%h({dTA$cslFV*CzU9O<4rp3tvKql z>;o|xDy_vsuK=CPK_?a7*ij%E9|SKmYCoPKH)0g=%rH5nBe8Oa81>fsF>0&96k?Rg zvQFHYETi4ECd+7HRTaystay`Y%(ULEuiQ*qNNDnM4K}wJ%L|Qyyn8j9Pw9K*MDp)0 zc%Qm8$s>|Y@`&VW@+#})O!9b>yy`7np5Dq)ha8_+Hgp@)5GjNvo7|!%lKn;Xcr_&BF z!D24AK4jW4y1-q zy~}pQ58C`bNcE7l56y~Su)ll1%Dl#2X-qWHmTA)w|31?rm3bV$wPqLcmsU0#ii~lT zf-xg59JsQ1@A-&B?lGj;Z)G!#6Oix0H{p*fWV3pQxW9k@P5Bt#s*!+7UKPu zO6=beKjcDSYa}pzo&R7}dgS*6s04(74{KiEqj_y?%c$3McjxW?-6GpC}gEiMNe z_p1*go#|)%=p+B39T)@L$38F~+5*vD+K+jpKMGS+u;THRHBNx;*#$=g#%8)mbkY%r zbLt>NFjs6Yw}%UaHykdsN(JX?fm*@+uRQjX5fYqNQg=M1!T}$~d1>5uuYj*u%A9dH zwfTldeq@C$Psj!PUdSzF?iA;7(}B<3l5K~9n?6qeNw_!YFmfK~VOQW(2SP}$YAip3 zs|RB?qTs8mAg>obK%9M!Pm=UDodwOo_$m)&MaI2zyD`HDUyxWZzDj4Dc)(!&;!uC= z;=@r9bkd)R7BdVBn30ft{A6&wOKkE836u}c%`&Foh$`cB69Gvvp;#_nnRj&dL8W+{ z`(m=pfVU1`bMEEjDo$bjkhlgYI6BRa117434$kBY@DgVj6cfb7KSA2cB{fs1};GGFh)8iiFJPpa2Wa`TDA-h|j-!d=cib+x_^lJV$OC_bYvM z9Ck$kL_j^D0Wb@27=V5ZFdL9i(rGm*51**!i|Im7Pcb{8E4j`k!?Ko@m8?9xR@aB+ z?Mk|+a&r)$a1qW%KweMyD7G)7C5vg*xX-Ccub$_)Bywm$oP~fIfE8}Ty}v4qTAJ~` z8)3@FiXX)N%Bt{s+!MaJ0HTAS3D69n{L-lrUC}3fD3+G+5rw)kF|=JxfU1O&Qxd7d zq^xaM_0hC8f%vl-GkEg`=q1{0JjY46D)OkNXOu!Al^v4{x{@l$sZ1`dX4Gs!DWt$0 zT`d&#EO-Ylsk*M|22Dsh&D#TM8O;@d-^=4L*W)U$&S5{k=Rh@T!PUZOFgF@An7%L4U{} z_ILXu{-{6Zj|cpLKp+?h1;T;uKqL?i!~*f4KNtuGgP~wJ*d2@nqrq4(9`c6*p`D z;6kLA5pOGCF+f+cW2&4lC^{OQ(H^V@VZK4jlnoTrM$j(C3R~rSfP?z?6S#Iv<5087 zG6qg$M&GsGo9RvLMoxKIDVVJbiHrb-1ZL15!Ik`W!g38v$s;*8Y! z>QtXY8j@kx;YxLRn%C<+!^orD3eekUNCv9^VUBwg@!g33G_KU%Jm{a)+eg%~R90TO zN~UJeNjFR6iLH<$RQV*=kXE!Yt`>1;;Ywv~#Fb>cg@a^HRx8MgoY<=9rbL2#T_KY| z%%iyZR8p1YP9if8{6vvOPd{)i0{HnC=*#oo%=`1y^puuSN3dzoJd@IiJXe=~oJc&p=Y{F~C-{5!%v z=QnpuUU1QM{>`UcaN(tGzo@M{Zrz)2d3{Hme#X$Rc3pJwWnaAc&bz<=;6so8zX&i8Zyx+nyC``v#6ZGpX*n?5kHl z`ox}^h9!73u=%vp&m2ms7hQHUl05k6i?958Z%xD6fuvg6^{spEyZ@Qz_Wu67&s=c* z4foyu;KO@f_<8?V?tT2BC-w{suHU@n%%RU;e94{Px$FKPKJ@T&4UKb8JN++zeP>@O zbJj0ktev0L+S-Rc_37JgKll6hG|rtjzwemA^{1SA`k9|T_uCIX{mg&v{r#Wy{3V6r z6^p#S8*jhs{)hKG_u^G+uKbGslKKDs^b`9A*PnWt-BDM+*!SA&SuMKih$GitdfCRY z;vPU8^-k0=Rl8>^io4cc4no9(=9u4jXIl+YzGvB6g7=@HuxACfcT zw!=%0NIUNkT5LPt7PiT@j@J@|5Jz`a~-vAKoPH}J|A zI9@1S?^r3+2`lX}$1-W>zJ?};uc1p=P`9A2bfLKO%4YYR&s{G0q!o6)w#iw#ucP28 zJ=@}uO8cbJi=IDREkvDDr_U~Z*HL;*ay6|GT(+2_&*8BZ-1CG}#VyX#c};DuM&~-Q z^ab0k*L&uQf!*TN3yUxVDV1)hpZc?%$xCf`dy!bWPiPhDYB(EXC>$@@?YzU`-^7Oe9d%Yq_#M?KB=Dmox57w><*WE_S{Ik=cb#V|Cuv->18+B zT`N|PrY`wngEn;kYp?rDdk~+x{>0&nIzzFZ{$tl|*tqFrYJ0;8b#y$x<5TB; z;rd%{zvBl_-gbLdyYEY9cAO&#VwW%~FrT-yvt0<(wTTOz^Q2|c(PHh=(k-@y;zF_0 z5q1wAH5GL>x*Sa_*2aZ|!|89776`2pTN4wHlYFAf?zFFw7mFTeMCg%P?4rlMVIUf+ z3E904*VLjDk6Y$g+SszFZT4K}ATl_*rrGYY^*a_ji|!*=FSV_ZT(%QzOsW^8(gh>) z`W>#)4QF<&b-QdehxOQ8k>%pt()U&-H+uS=uD-Rc{f><_19n&GFMY0d;h2G_Q0s8n z;&#_mq}jegXgitJ1#8ax>S)njdf*G|5;eR0^^KR@vh$eT-`g3tFBMO>Epqj_I;F#Q z-f^0GoEWz^tf3}x6n@i_U9V2|^$htYZHq5u#O3y5lRxe<=E}=!_r`F7G=#kjelS_C0SLv@y z)`>2WKd<5Fb*oB0T4`hACaE>dPt`6Llb(}ZrQ2fdHOoaOdW5ZX)p^fj`$CN{Ar9Hl zzv?_<42A1-bPP_NU(yd$n8-! zs!#3S$i1-OB<`h`H{JFtW%KV|S+M2F-|XHZbFXdL%g#NO%W-zD3u+K{S~1q|_Rpzj zDkKw+eI=h@^IA`H_c)!bNn}oRWNDeO(y_FO$x$Q_9gskF7vIi$D7lF37tF=CFrJU2 z$BR599-GGtSjLL5ga~XlkI|T71Gj_O1s6Y$tw352Qg#A8unH2yg&m8D2`iC=OnC~o z@o~^+<21AHs+F&3?5$Wd~$g-$jqG8>5En|V>F$9a4_ zZ)0@~ycgQ}dH7ockA;KrZYP5rW<|b(Z5Kq|$!x;U!30oiCyczq=Hi)uen9jiEU``; ze=4JpOo-tn5(+&Ip8tw~Z{*r3LxF#24aa`GfDw76MkDmr(Adyo0?)Y$HXezP=u&75f$Yvcw4} zrPwKm?CZeK@f(CbcR)OcMe3HIoGu{%oOZTKSST^aYOIY3JJA)`kU*>iQ`pr^aLh3{ z%UC0;wF}aZ9aNaP#8uQ4#bf+$L7NTNR(_L%o@^t2;H`>d{h7o$8UJV0JX!?16#0o* zyVGeiYRbk7UN9U=4`QF#2vUIMY#TBF&(Yc_E0}L?J}gOe$82>R1}BakA)Y{HotK{r zB^@6=aX5JUJn?cI4JHO1td=!OtPWTk42)8eU5hlUL~y{Kv2(*%D8gBN?g;2xWRo7P z=2blf)%9#r6ioxat1y{Udt@b7=1hk3y%1`b=2m z(PB1X_!KzqN-SO_yYnFBfDb~`3vfETYmF$WP|)IDPSxsW2UW*Ea=<|Bo4Wb=vzVcmlMjm8*ayW~9gl3=J|#sytAZvcKrT$M ztU4jn*dcFEsT00pUiZQIqojQaG)K*+!wkw7;1eQZ#!`i?#St$IxvqekNJN71cyc7J zCSt*mFQ=s^$)D9Vq2x1NdcMo=4fwr&BV8sx2ItW@kSR&%;beM{>CXKPWy*ji@`LyQ z8_H~#GsS#C9#P34GCIm)m??|B@{YqyTOT2HOx34dQ9Y)QOUk;JX&_ z$#%ILSF-V@--d$I@18HeJ9yqGKAI`A=l+DapLkC?GfEB-<=G~k)x0OW@L+z#K9U3S z;=X}X)}C@wAhOsy<3Vh{aCpCPaKCV1It)HVDzOm?RpKI4l@mghY>G3}QLri@1*=k0 zu#yyxL8UrRBV3gj<(nC*!i0AfL`Mz`Rz*apDk4Iah$EVoo-Qz?o~mzGlhY5fsme>M z9?Q&CbX}R8j%ZX|`3*|6*gLS^kU1woPH%=xRgDk?RV6S$Y?%=ZL}mnImCz>Otd30K z>ev*nir#0kv69|+P>tZ&jq3+1ua8WPftu=YwkiM)sY=y@KEpX%i7=Q-R|3bU@_96O z3`%DeQ#vHYXi7~dd*sD%uD#XB3}5k_xu%a~Q+7P7O=SBh#-NhH@V1!i#51 z9;}}!^3kb$F0D+yulrdpW-ZFnlLz?ueLCb(!WZ{P!yz>qjK`FO67WZpNk#D|;FeXw z$xy@}R)g`8QFSCjLVG_yy4m(f=G8Yb?l{o=8whcd;~y4xzK}FzYf7`cKJfDZ_W*D{ z3_XN+Q(@s~DxIFm!AB66d_?5$vC^H7bo9&$Ux6^qH~bxFB+-w$Gsm*}X2u;4yl(@@ z=Vpcf1NStCVTB*VeFOl{`3Q;oQA1TK`~K7&2~~x&HJ!?&3LJMSaMJi@(LN7OEaI;f z_9IOGG$juaVdx7ccY5RuJdAMf<<<147Y^ahC78HSGdau@X!14ZjetGj7RL31&N~3a8!LP{?rGj5p<(dbQIL~r zKB1>_MoGxWm{$vih{A-2o-zmcoR*{c6?C4A=_#ej78Gn!KB|la&g;ZD$K8cIqriP= zM*pNbQXKP@={6d`8^~`I`7HyGZ`=xZ;hx%~yn3}$EPg0HxZxGy;Htg^nBQQuIjHe z7nUbRw6&SC;19@$`0#hYoha&gjoQ%;;9duuzXgy#*L)%8v^)$1%)nXQC!_30Wr`Vk zkx#)BEMvN_fH@L#Y6O09;GsT9IvUA!suKdzgBAj)zDNdJ~mJPi4Zt@+XQMl;=i zepDVF)Uv8IKWfz}w0UTyW15bRl{7~J4O4b{`PQ7*q|_vt2@+0(eR}kRA8XWPeL8hiaL@|fH0fcfdZ96`N=$W&9jOc zv~ROMAkb8GoTiUa4BU}#-oTgDFsG&I3e9anmsZU&@oZJs3aJbj1xv#!0x9#>eJTt4 zL(VBW6-m|6)`2gp7A7=(+@y1>l1-+o$w_Mv8z>%3ER6rA#4}{9+^KrUymEdrLp%Z3 zwA>OB>s?wlJ!v2-7l>xq%Cv&CR54>BLX8>5o6*nE-xPWJxj9KP9jw&bgkkcH7!1x9 zX!==6Q=XIH7pgBmqQeBt%DGfdwMvzQMgrpryf06_Y=7%zslEDDP22 z=kL@YcgRC0FF}8?`anuH?Ue$qB)<|$mXg41O^r?(6WBQgGdS{AO+zix%$b5Z#*=Z< z++b#-td}A!*+7;qV#%NBc#si4MI6!-J`13+(h9GJ041G@XtL(Hm*SrKIn6~;UnkkU z96)vrg-Lc}Dt<;BAHt+RRO&NdOe9b-qs27Mn^9UC<7mx-yL?Y_knTy=(ECFPmOWiEed%zoscms0hw3#Kt zve=%=^S1IWAdkiNN{EEpjHH&9KZ!GLIp5?QtoaFb0z5f3Jk#}18 diff --git a/packages/polywrap-client/tests/cases/subinvoke/01-invoke/wrap.info b/packages/polywrap-client/tests/cases/subinvoke/01-invoke/wrap.info deleted file mode 100644 index ea74685401b8004f14f919dddc58169b383c0eb1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2069 zcmds1!A`Vh+EBq5HC)uAUiF{s zZlTzvtv#wY$j;1r3~#0vbO0q2+}kK^`kdG>lCH&gM>N5APTJsiiL^apvGec9u`Q_E zf@%op1bY%Zb6Q0ZZE6~bJ=Wt(x_3Lo@xyd;FI1OxY8iLB3OFjC5P`b@&nb#0( z;LZ@iagkqWrdQ@pD(V*D*kuUx-B+rsLs=s&g1uC5EM>4(rrYU#w9eKXF(O!Z)k5;x z*kwTGsFdjgk~z;5vhszjOrglSm(aRB6!t;Otuy|!iP`wvJ+f(;`~7iaAEPW(8z{QF zhyoKw8SDtr0>bsJEkJXvTtI81W`YK_;Cc3=s~T1uWW27IDt4h$hB~$@!j8d4Nk!lgyCN+3ksDd#k4(ostnl`~5lVPv{k3#&LwjjGeRJ=cz zmyFi%!qZRuDREP%7vm=-+d%>JOhqw}1ug%zjc}i6gmis`4BWNpsSM0w4M`EEY diff --git a/packages/polywrap-client/tests/cases/subinvoke/01-invoke/wrap.wasm b/packages/polywrap-client/tests/cases/subinvoke/01-invoke/wrap.wasm deleted file mode 100755 index efba976df64408a7c065a249e8adb14459714308..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 100627 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 Pw{#*t>IgKoH3j}3U6c-C diff --git a/packages/polywrap-client/tests/cases/subinvoke/02-consumer/wrap.info b/packages/polywrap-client/tests/cases/subinvoke/02-consumer/wrap.info deleted file mode 100644 index b730341696135bc7deed52a356b03e2710155641..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2102 zcmeHIO-sW-5LNJ(c(>|5P(h&wL9ln(bjNmSvKwbNE#4HXo~ys0BqX+i3L@fFulk?N zZql!`sX2I1=q+L2ym>p!d)tnhfRYLBZr$kA%`~9#>Tn z9N;QMP#*G2Q|Xtvnu)qYIPn+){RlMcYACD3CfJ?{9#UnhR#J6FkKx%GA$kOBo)#o; zGFrN1gqqR4OLF^ViLCiVRxVL8y0>_AdnlX(+p97D^APj#b9LmGYcY+%6S82oN7pOX^W!(Yow ti)a|+U3U=;`V|`Hf3Y3c@a%&Ba^^lIMyM1Bh$(1B+T^1(h5mzK@eK;0ty2I1 diff --git a/packages/polywrap-client/tests/cases/subinvoke/02-consumer/wrap.wasm b/packages/polywrap-client/tests/cases/subinvoke/02-consumer/wrap.wasm deleted file mode 100755 index 3b5e06c945453e1f547ecf696d0cfa2e45681e41..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 100660 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 diff --git a/packages/polywrap-client/tests/conftest.py b/packages/polywrap-client/tests/conftest.py deleted file mode 100644 index db1f91b1..00000000 --- a/packages/polywrap-client/tests/conftest.py +++ /dev/null @@ -1,86 +0,0 @@ - -from pathlib import Path -from polywrap_core import FileReader, ClientConfig, Invoker, UriPackageOrWrapper, Env, Uri -from polywrap_uri_resolvers import ( - RecursiveResolver, - UriResolverAggregator, - StaticResolver, - FsUriResolver, - SimpleFileReader, - WRAP_MANIFEST_PATH, - WRAP_MODULE_PATH -) -from polywrap_plugin import PluginModule, PluginPackage -from pytest import fixture -from typing import Dict, Any, Optional -from polywrap_client import PolywrapClient -import time - -@fixture -def client(memory_storage_plugin: PluginPackage[None]): - memory_storage_uri = Uri.from_str("wrap://ens/memory-storage.polywrap.eth") - config = ClientConfig( - resolver=RecursiveResolver( - UriResolverAggregator( - [ - FsUriResolver(file_reader=SimpleFileReader()), - StaticResolver({ memory_storage_uri: memory_storage_plugin}) - ] - ) - ) - ) - return PolywrapClient(config) - -@fixture -def simple_wrap_module(): - wrap_path = Path(__file__).parent / "cases" / "simple-invoke" / "wrap.wasm" - with open(wrap_path, "rb") as f: - yield f.read() - - -@fixture -def simple_wrap_manifest(): - wrap_path = Path(__file__).parent / "cases" / "simple-invoke" / "wrap.info" - with open(wrap_path, "rb") as f: - yield f.read() - -@fixture -def simple_file_reader(simple_wrap_module: bytes, simple_wrap_manifest: bytes): - class SimpleFileReader(FileReader): - async def read_file(self, file_path: str) -> bytes: - if file_path == WRAP_MODULE_PATH: - return simple_wrap_module - if file_path == WRAP_MANIFEST_PATH: - return simple_wrap_manifest - raise FileNotFoundError(f"FileNotFound: {file_path}") - - yield SimpleFileReader() - -class MemoryStorage(PluginModule[None]): - def __init__(self): - super().__init__(None) - self.value = 0 - - def getData(self, args: Dict[str, Any], client: Invoker[UriPackageOrWrapper], env: Optional[Env]) -> int: - time.sleep(0.05) # Sleep for 50 milliseconds - return self.value - - def setData(self, args: Dict[str, Any], client: Invoker[UriPackageOrWrapper], env: Optional[Env]) -> bool: - time.sleep(0.05) # Sleep for 50 milliseconds - self.value = args["value"] - return True - - -@fixture -def memory_storage_plugin() -> PluginPackage[None]: - return PluginPackage(module=MemoryStorage(), manifest={}) # type: ignore - - -class Adder(PluginModule[None]): - def add(self, args: Dict[str, Any], client: Invoker[UriPackageOrWrapper], env: Optional[Env]) -> int: - return args["a"] + args["b"] - - -@fixture -def adder_plugin() -> PluginPackage[None]: - return PluginPackage(module=Adder(None), manifest={}) # type: ignore diff --git a/packages/polywrap-client/tests/consts.py b/packages/polywrap-client/tests/consts.py new file mode 100644 index 00000000..ecae4792 --- /dev/null +++ b/packages/polywrap-client/tests/consts.py @@ -0,0 +1 @@ +SUPPORTED_IMPLEMENTATIONS = ["as", "rs"] \ No newline at end of file diff --git a/packages/polywrap-client/tests/msgpack/__init__.py b/packages/polywrap-client/tests/msgpack/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/packages/polywrap-client/tests/msgpack/asyncify/__init__.py b/packages/polywrap-client/tests/msgpack/asyncify/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/packages/polywrap-client/tests/msgpack/asyncify/conftest.py b/packages/polywrap-client/tests/msgpack/asyncify/conftest.py new file mode 100644 index 00000000..16650bdf --- /dev/null +++ b/packages/polywrap-client/tests/msgpack/asyncify/conftest.py @@ -0,0 +1,54 @@ +import time +from typing import Any, Callable, Dict +from polywrap_test_cases import get_path_to_test_wrappers + +import pytest +from polywrap_client_config_builder import PolywrapClientConfigBuilder +from polywrap_client_config_builder.types import ClientConfigBuilder +from polywrap_core import Uri +from polywrap_plugin import PluginModule, PluginPackage +from polywrap_uri_resolvers import FsUriResolver, SimpleFileReader + + +class MemoryStoragePlugin(PluginModule[None]): + def __init__(self): + super().__init__(None) + self._value = None + + def getData(self, *_: Any) -> Any: + self.sleep(0.005) + return self._value + + def setData(self, args: Dict[str, Any], *_:Any) -> bool: + self.sleep(0.005) + self._value = args["value"] + return True + + def sleep(self, seconds: float) -> None: + time.sleep(seconds) + + +def memory_storage_plugin() -> PluginPackage[None]: + return PluginPackage(manifest=NotImplemented, module=MemoryStoragePlugin()) + + +@pytest.fixture +def wrapper_uri() -> Callable[[str], Uri]: + def get_subinvoke_wrapper_uri(implementation: str) -> Uri: + subinvoke_wrapper_path = f"{get_path_to_test_wrappers()}/asyncify/implementations/{implementation}" + return Uri.from_str(f"file/{subinvoke_wrapper_path}") + + return get_subinvoke_wrapper_uri + + +@pytest.fixture +def builder() -> ClientConfigBuilder: + return ( + PolywrapClientConfigBuilder() + .set_package( + Uri.from_str("ens/memory-storage.polywrap.eth"), + memory_storage_plugin(), + ) + .add_resolver(FsUriResolver(SimpleFileReader())) + ) + diff --git a/packages/polywrap-client/tests/msgpack/asyncify/test_asyncify.py b/packages/polywrap-client/tests/msgpack/asyncify/test_asyncify.py new file mode 100644 index 00000000..ef40a752 --- /dev/null +++ b/packages/polywrap-client/tests/msgpack/asyncify/test_asyncify.py @@ -0,0 +1,130 @@ +from typing import Callable, Dict +from polywrap_client import PolywrapClient +from polywrap_core import Uri +from polywrap_client_config_builder.types import ClientConfigBuilder +import pytest + +from ...consts import SUPPORTED_IMPLEMENTATIONS + +@pytest.mark.parametrize("implementation", SUPPORTED_IMPLEMENTATIONS) +def test_subsequent_invokes(implementation: str, builder: ClientConfigBuilder, wrapper_uri: Callable[[str], Uri]): + client = PolywrapClient(builder.build()) + subsequent_invokes = client.invoke( + uri=wrapper_uri(implementation), + method="subsequentInvokes", + args={ + "numberOfTimes": 40, + }, + ) + + expected = [str(index) for index in range(40)] + assert subsequent_invokes == expected + + +@pytest.mark.parametrize("implementation", SUPPORTED_IMPLEMENTATIONS) +def test_local_var_method(implementation: str, builder: ClientConfigBuilder, wrapper_uri: Callable[[str], Uri]): + client = PolywrapClient(builder.build()) + localVarMethod = client.invoke( + uri=wrapper_uri(implementation), + method="localVarMethod", + ) + + assert localVarMethod == True + + +@pytest.mark.parametrize("implementation", SUPPORTED_IMPLEMENTATIONS) +def test_global_var_method(implementation: str, builder: ClientConfigBuilder, wrapper_uri: Callable[[str], Uri]): + client = PolywrapClient(builder.build()) + globalVarMethod = client.invoke( + uri=wrapper_uri(implementation), + method="globalVarMethod", + ) + + assert globalVarMethod == True + + +@pytest.mark.parametrize("implementation", SUPPORTED_IMPLEMENTATIONS) +def test_set_data_with_large_args(implementation: str, builder: ClientConfigBuilder, wrapper_uri: Callable[[str], Uri]): + client = PolywrapClient(builder.build()) + large_str = "polywrap " * 10000 + + setDataWithLargeArgs = client.invoke( + uri=wrapper_uri(implementation), + method="setDataWithLargeArgs", + args={ + "value": large_str, + }, + ) + + assert setDataWithLargeArgs == large_str + + + +@pytest.mark.parametrize("implementation", SUPPORTED_IMPLEMENTATIONS) +def test_set_data_with_many_args(implementation: str, builder: ClientConfigBuilder, wrapper_uri: Callable[[str], Uri]): + client = PolywrapClient(builder.build()) + args = { + "valueA": "polywrap a", + "valueB": "polywrap b", + "valueC": "polywrap c", + "valueD": "polywrap d", + "valueE": "polywrap e", + "valueF": "polywrap f", + "valueG": "polywrap g", + "valueH": "polywrap h", + "valueI": "polywrap i", + "valueJ": "polywrap j", + "valueK": "polywrap k", + "valueL": "polywrap l", + } + + setDataWithManyArgs = client.invoke( + uri=wrapper_uri(implementation), + method="setDataWithManyArgs", + args=args, + ) + + expected = "polywrap apolywrap bpolywrap cpolywrap dpolywrap epolywrap fpolywrap gpolywrap hpolywrap ipolywrap jpolywrap kpolywrap l" + assert setDataWithManyArgs == expected + +@pytest.mark.parametrize("implementation", SUPPORTED_IMPLEMENTATIONS) +def test_set_data_with_many_structured_args( + implementation: str, builder: ClientConfigBuilder, wrapper_uri: Callable[[str], Uri] +): + client = PolywrapClient(builder.build()) + create_obj: Callable[[int], Dict[str, str]] = lambda i: { + "propA": f"a-{i}", + "propB": f"b-{i}", + "propC": f"c-{i}", + "propD": f"d-{i}", + "propE": f"e-{i}", + "propF": f"f-{i}", + "propG": f"g-{i}", + "propH": f"h-{i}", + "propI": f"i-{i}", + "propJ": f"j-{i}", + "propK": f"k-{i}", + "propL": f"l-{i}", + } + args = { + "valueA": create_obj(1), + "valueB": create_obj(2), + "valueC": create_obj(3), + "valueD": create_obj(4), + "valueE": create_obj(5), + "valueF": create_obj(6), + "valueG": create_obj(7), + "valueH": create_obj(8), + "valueI": create_obj(9), + "valueJ": create_obj(10), + "valueK": create_obj(11), + "valueL": create_obj(12), + } + + setDataWithManyStructuredArgs = client.invoke( + uri=wrapper_uri(implementation), + method="setDataWithManyStructuredArgs", + args=args, + ) + + assert setDataWithManyStructuredArgs == True diff --git a/packages/polywrap-client/tests/msgpack/conftest.py b/packages/polywrap-client/tests/msgpack/conftest.py new file mode 100644 index 00000000..6fde8d48 --- /dev/null +++ b/packages/polywrap-client/tests/msgpack/conftest.py @@ -0,0 +1,24 @@ +from typing import Callable + +import pytest +from polywrap_client_config_builder import ( + ClientConfigBuilder, + PolywrapClientConfigBuilder, +) +from polywrap_core import Uri +from polywrap_test_cases import get_path_to_test_wrappers +from polywrap_uri_resolvers import FsUriResolver, SimpleFileReader + + +@pytest.fixture +def builder() -> ClientConfigBuilder: + return PolywrapClientConfigBuilder().add_resolver(FsUriResolver(SimpleFileReader())) + + +@pytest.fixture +def wrapper_uri() -> Callable[[str, str], Uri]: + def get_wrapper_uri(wrapper_name: str, implementation: str) -> Uri: + wrapper_path = f"{get_path_to_test_wrappers()}/{wrapper_name}/implementations/{implementation}" + return Uri.from_str(f"file/{wrapper_path}") + + return get_wrapper_uri diff --git a/packages/polywrap-client/tests/msgpack/test_bigint.py b/packages/polywrap-client/tests/msgpack/test_bigint.py new file mode 100644 index 00000000..4bb9e01d --- /dev/null +++ b/packages/polywrap-client/tests/msgpack/test_bigint.py @@ -0,0 +1,51 @@ +from typing import Callable +from polywrap_client import PolywrapClient +from polywrap_core import Uri +from polywrap_client_config_builder.types import ClientConfigBuilder +import pytest + +from ..consts import SUPPORTED_IMPLEMENTATIONS + + +@pytest.mark.parametrize("implementation", SUPPORTED_IMPLEMENTATIONS) +def test_bigint_method_with_arg1_and_obj( + implementation: str, + builder: ClientConfigBuilder, + wrapper_uri: Callable[[str, str], Uri], +): + client = PolywrapClient(builder.build()) + uri = wrapper_uri("bigint-type", implementation) + + arg1 = "123456789123456789" + prop1 = "987654321987654321" + + response = client.invoke( + uri=uri, method="method", args={"arg1": arg1, "obj": {"prop1": prop1}} + ) + + result = int(arg1) * int(prop1) + assert response == str(result) + + +@pytest.mark.parametrize("implementation", SUPPORTED_IMPLEMENTATIONS) +def test_bigint_method_with_arg1_arg2_and_obj( + implementation: str, + builder: ClientConfigBuilder, + wrapper_uri: Callable[[str, str], Uri], +): + client = PolywrapClient(builder.build()) + uri = wrapper_uri("bigint-type", implementation) + + arg1 = "123456789123456789" + arg2 = "123456789123456789123456789123456789" + prop1 = "987654321987654321" + prop2 = "987654321987654321987654321987654321" + + response = client.invoke( + uri=uri, + method="method", + args={"arg1": arg1, "arg2": arg2, "obj": {"prop1": prop1, "prop2": prop2}}, + ) + + result = int(arg1) * int(arg2) * int(prop1) * int(prop2) + assert response == str(result) diff --git a/packages/polywrap-client/tests/msgpack/test_bignumber.py b/packages/polywrap-client/tests/msgpack/test_bignumber.py new file mode 100644 index 00000000..1189830c --- /dev/null +++ b/packages/polywrap-client/tests/msgpack/test_bignumber.py @@ -0,0 +1,81 @@ +from typing import Callable +from polywrap_client import PolywrapClient +from polywrap_core import Uri +from polywrap_client_config_builder.types import ClientConfigBuilder +import pytest + +from ..consts import SUPPORTED_IMPLEMENTATIONS + + +@pytest.mark.parametrize("implementation", SUPPORTED_IMPLEMENTATIONS) +def test_bignumber_method_with_arg1_and_obj( + implementation: str, + builder: ClientConfigBuilder, + wrapper_uri: Callable[[str, str], Uri], +): + client = PolywrapClient(builder.build()) + uri = wrapper_uri("bignumber-type", implementation) + + arg1 = "1234.56789123456789" + prop1 = "98.7654321987654321" + + response = client.invoke( + uri=uri, + method="method", + args={ + "arg1": arg1, + "obj": { + "prop1": prop1, + }, + }, + ) + + import decimal + decimal.getcontext().prec = len(response) + + arg1 = decimal.Decimal(arg1) + prop1 = decimal.Decimal(prop1) + result = arg1 * prop1 + + + assert response == str(result) + + +@pytest.mark.parametrize("implementation", SUPPORTED_IMPLEMENTATIONS) +def test_bignumber_method_with_arg1_arg2_and_obj( + implementation: str, + builder: ClientConfigBuilder, + wrapper_uri: Callable[[str, str], Uri], +): + client = PolywrapClient(builder.build()) + uri = wrapper_uri("bignumber-type", implementation) + + arg1 = "1234567.89123456789" + arg2 = "123456789123.456789123456789123456789" + prop1 = "987654.321987654321" + prop2 = "987.654321987654321987654321987654321" + + response = client.invoke( + uri=uri, + method="method", + args={ + "arg1": arg1, + "arg2": arg2, + "obj": { + "prop1": prop1, + "prop2": prop2, + }, + }, + ) + + import decimal + + decimal.getcontext().prec = len(response) + + arg1 = decimal.Decimal(arg1) + arg2 = decimal.Decimal(arg2) + prop1 = decimal.Decimal(prop1) + prop2 = decimal.Decimal(prop2) + result = arg1 * arg2 * prop1 * prop2 + + assert response == str(result) diff --git a/packages/polywrap-client/tests/msgpack/test_bytes.py b/packages/polywrap-client/tests/msgpack/test_bytes.py new file mode 100644 index 00000000..2c7e5f39 --- /dev/null +++ b/packages/polywrap-client/tests/msgpack/test_bytes.py @@ -0,0 +1,33 @@ +from typing import Callable, Dict +from polywrap_client import PolywrapClient +from polywrap_core import Uri +from polywrap_client_config_builder.types import ClientConfigBuilder +import pytest + +from ..consts import SUPPORTED_IMPLEMENTATIONS + + +@pytest.mark.parametrize("implementation", SUPPORTED_IMPLEMENTATIONS) +def test_bytes( + implementation: str, + builder: ClientConfigBuilder, + wrapper_uri: Callable[[str, str], Uri], +): + client = PolywrapClient(builder.build()) + uri = wrapper_uri("bytes-type", implementation) + + prop = b"hello world" + expected = b"hello world Sanity!" + + response: bytes = client.invoke( + uri=uri, + method="bytesMethod", + args={ + "arg": { + "prop": prop, + } + }, + ) + + assert response == expected + diff --git a/packages/polywrap-client/tests/msgpack/test_enum.py b/packages/polywrap-client/tests/msgpack/test_enum.py new file mode 100644 index 00000000..23c1d141 --- /dev/null +++ b/packages/polywrap-client/tests/msgpack/test_enum.py @@ -0,0 +1,91 @@ +from typing import Callable +from polywrap_client import PolywrapClient +from polywrap_core import Uri, WrapAbortError +from polywrap_client_config_builder.types import ClientConfigBuilder +import pytest + +from ..consts import SUPPORTED_IMPLEMENTATIONS + + +@pytest.mark.parametrize("implementation", SUPPORTED_IMPLEMENTATIONS) +def test_invalid_required_enum( + implementation: str, + builder: ClientConfigBuilder, + wrapper_uri: Callable[[str, str], Uri], +): + client = PolywrapClient(builder.build()) + uri = wrapper_uri("enum-type", implementation) + + with pytest.raises(WrapAbortError) as err: + client.invoke( + uri=uri, + method="method1", + args={ + "en": 5, + } + ) + + assert "Invalid value for enum 'SanityEnum': 5" in err.value.args[0] + + +@pytest.mark.parametrize("implementation", SUPPORTED_IMPLEMENTATIONS) +def test_valid_enum( + implementation: str, + builder: ClientConfigBuilder, + wrapper_uri: Callable[[str, str], Uri], +): + client = PolywrapClient(builder.build()) + uri = wrapper_uri("enum-type", implementation) + + response = client.invoke( + uri=uri, + method="method1", + args={ + "en": 2, + "optEnum": 1, + } + ) + + assert response == 2 + + +@pytest.mark.parametrize("implementation", SUPPORTED_IMPLEMENTATIONS) +def test_invalid_optional_enum( + implementation: str, + builder: ClientConfigBuilder, + wrapper_uri: Callable[[str, str], Uri], +): + client = PolywrapClient(builder.build()) + uri = wrapper_uri("enum-type", implementation) + + with pytest.raises(WrapAbortError) as err: + client.invoke( + uri=uri, + method="method1", + args={ + "en": 2, + "optEnum": "INVALID", + } + ) + + assert "Invalid key for enum 'SanityEnum': INVALID" in err.value.args[0] + + +@pytest.mark.parametrize("implementation", SUPPORTED_IMPLEMENTATIONS) +def test_valid_enum_array( + implementation: str, + builder: ClientConfigBuilder, + wrapper_uri: Callable[[str, str], Uri], +): + client = PolywrapClient(builder.build()) + uri = wrapper_uri("enum-type", implementation) + + response = client.invoke( + uri=uri, + method="method2", + args={ + "enumArray": ["OPTION1", 0, "OPTION3"], + } + ) + + assert response == [0, 0, 2] diff --git a/packages/polywrap-client/tests/msgpack/test_invalid_type.py b/packages/polywrap-client/tests/msgpack/test_invalid_type.py new file mode 100644 index 00000000..89ce532f --- /dev/null +++ b/packages/polywrap-client/tests/msgpack/test_invalid_type.py @@ -0,0 +1,83 @@ +from typing import Callable +from polywrap_client import PolywrapClient +from polywrap_core import Uri, WrapAbortError +from polywrap_client_config_builder.types import ClientConfigBuilder +import pytest + +from ..consts import SUPPORTED_IMPLEMENTATIONS + + +@pytest.mark.parametrize("implementation", SUPPORTED_IMPLEMENTATIONS) +def test_invalid_bool( + implementation: str, + builder: ClientConfigBuilder, + wrapper_uri: Callable[[str, str], Uri], +): + client = PolywrapClient(builder.build()) + uri = wrapper_uri("invalid-type", implementation) + + with pytest.raises(WrapAbortError) as err: + client.invoke( + uri=uri, + method="boolMethod", + args={"arg": 10}, + ) + + assert "Property must be of type 'bool'. Found 'int'." in err.value.args[0] + + +@pytest.mark.parametrize("implementation", SUPPORTED_IMPLEMENTATIONS) +def test_invalid_int( + implementation: str, + builder: ClientConfigBuilder, + wrapper_uri: Callable[[str, str], Uri], +): + client = PolywrapClient(builder.build()) + uri = wrapper_uri("invalid-type", implementation) + + with pytest.raises(WrapAbortError) as err: + client.invoke( + uri=uri, + method="intMethod", + args={"arg": "10"}, + ) + + assert "Property must be of type 'int'. Found 'string'." in err.value.args[0] + + +@pytest.mark.parametrize("implementation", SUPPORTED_IMPLEMENTATIONS) +def test_invalid_bytes( + implementation: str, + builder: ClientConfigBuilder, + wrapper_uri: Callable[[str, str], Uri], +): + client = PolywrapClient(builder.build()) + uri = wrapper_uri("invalid-type", implementation) + + with pytest.raises(WrapAbortError) as err: + client.invoke( + uri=uri, + method="bytesMethod", + args={"arg": 10.23}, + ) + + assert "Property must be of type 'bytes'. Found 'float64'." in err.value.args[0] + + +@pytest.mark.parametrize("implementation", SUPPORTED_IMPLEMENTATIONS) +def test_invalid_array( + implementation: str, + builder: ClientConfigBuilder, + wrapper_uri: Callable[[str, str], Uri], +): + client = PolywrapClient(builder.build()) + uri = wrapper_uri("invalid-type", implementation) + + with pytest.raises(WrapAbortError) as err: + client.invoke( + uri=uri, + method="arrayMethod", + args={"arg": {"prop": 1}}, + ) + + assert "Property must be of type 'array'. Found 'map'." in err.value.args[0] diff --git a/packages/polywrap-client/tests/msgpack/test_json.py b/packages/polywrap-client/tests/msgpack/test_json.py new file mode 100644 index 00000000..8c96d589 --- /dev/null +++ b/packages/polywrap-client/tests/msgpack/test_json.py @@ -0,0 +1,53 @@ +import json +from typing import Callable +from polywrap_client import PolywrapClient +from polywrap_core import Uri +from polywrap_client_config_builder.types import ClientConfigBuilder +import pytest + +from ..consts import SUPPORTED_IMPLEMENTATIONS + + +@pytest.mark.parametrize("implementation", SUPPORTED_IMPLEMENTATIONS) +def test_json_parse( + implementation: str, + builder: ClientConfigBuilder, + wrapper_uri: Callable[[str, str], Uri], +): + client = PolywrapClient(builder.build()) + uri = wrapper_uri("json-type", implementation) + value = { "foo": "bar", "bar": "bar" } + json_value = json.dumps(value) + + response = client.invoke( + uri=uri, + method="parse", + args={ + "value": json_value, + }, + ) + + assert json.loads(response) == value + + +@pytest.mark.parametrize("implementation", SUPPORTED_IMPLEMENTATIONS) +def test_json_stringify( + implementation: str, + builder: ClientConfigBuilder, + wrapper_uri: Callable[[str, str], Uri], +): + client = PolywrapClient(builder.build()) + uri = wrapper_uri("json-type", implementation) + values = [json.dumps({"bar": "foo"}), json.dumps({"foo": "bar"})] + + response = client.invoke( + uri=uri, + method="stringify", + args={ + "values": values, + }, + ) + + # Note: python json.dumps() adds a space after the colon, + # but the JS implementation does not. + assert response.replace(":", ": ") == "".join(values) diff --git a/packages/polywrap-client/tests/msgpack/test_map.py b/packages/polywrap-client/tests/msgpack/test_map.py new file mode 100644 index 00000000..565f26b0 --- /dev/null +++ b/packages/polywrap-client/tests/msgpack/test_map.py @@ -0,0 +1,124 @@ +from typing import Callable +from polywrap_client import PolywrapClient +from polywrap_core import Uri +from polywrap_msgpack import GenericMap +from polywrap_client_config_builder.types import ClientConfigBuilder +import pytest + +from ..consts import SUPPORTED_IMPLEMENTATIONS + + +@pytest.mark.parametrize("implementation", SUPPORTED_IMPLEMENTATIONS) +def test_return_map_when_map( + implementation: str, + builder: ClientConfigBuilder, + wrapper_uri: Callable[[str, str], Uri], +): + client = PolywrapClient(builder.build()) + uri = wrapper_uri("map-type", implementation) + map_value = GenericMap({"Hello": 1, "World": 2}) + + response = client.invoke( + uri=uri, + method="returnMap", + args={ + "map": map_value, + }, + ) + + assert response == map_value + + +@pytest.mark.parametrize("implementation", SUPPORTED_IMPLEMENTATIONS) +def test_return_map_when_dict( + implementation: str, + builder: ClientConfigBuilder, + wrapper_uri: Callable[[str, str], Uri], +): + client = PolywrapClient(builder.build()) + uri = wrapper_uri("map-type", implementation) + map_value = {"Hello": 1, "World": 2} + + response = client.invoke( + uri=uri, + method="returnMap", + args={ + "map": map_value, + }, + ) + + assert response == GenericMap(map_value) + + +@pytest.mark.parametrize("implementation", SUPPORTED_IMPLEMENTATIONS) +def test_get_key( + implementation: str, + builder: ClientConfigBuilder, + wrapper_uri: Callable[[str, str], Uri], +): + client = PolywrapClient(builder.build()) + uri = wrapper_uri("map-type", implementation) + map_value = {"Hello": 1, "World": 2} + nested_map_value = {"Nested": map_value} + + response = client.invoke( + uri=uri, + method="getKey", + args={ + "foo": { + "map": map_value, + "nestedMap": nested_map_value, + }, + "key": "Hello", + }, + ) + + assert response == 1 + + +@pytest.mark.parametrize("implementation", SUPPORTED_IMPLEMENTATIONS) +def test_return_custom_map( + implementation: str, + builder: ClientConfigBuilder, + wrapper_uri: Callable[[str, str], Uri], +): + client = PolywrapClient(builder.build()) + uri = wrapper_uri("map-type", implementation) + map_value = GenericMap({"Hello": 1, "World": 2}) + nested_map_value = GenericMap({"Nested": map_value}) + foo = { + "map": map_value, + "nestedMap": nested_map_value, + } + + response = client.invoke( + uri=uri, + method="returnCustomMap", + args={ + "foo": foo, + }, + ) + + assert response == foo + + +@pytest.mark.parametrize("implementation", SUPPORTED_IMPLEMENTATIONS) +def test_return_nested_map( + implementation: str, + builder: ClientConfigBuilder, + wrapper_uri: Callable[[str, str], Uri], +): + client = PolywrapClient(builder.build()) + uri = wrapper_uri("map-type", implementation) + map_value = GenericMap({"Hello": 1, "World": 2}) + nested_map_value = GenericMap({"Nested": map_value}) + + response = client.invoke( + uri=uri, + method="returnNestedMap", + args={ + "foo": nested_map_value, + }, + ) + + assert response == nested_map_value diff --git a/packages/polywrap-client/tests/msgpack/test_numbers.py b/packages/polywrap-client/tests/msgpack/test_numbers.py new file mode 100644 index 00000000..949b5cbd --- /dev/null +++ b/packages/polywrap-client/tests/msgpack/test_numbers.py @@ -0,0 +1,139 @@ +from typing import Callable +from polywrap_client import PolywrapClient +from polywrap_core import Uri, WrapAbortError +from polywrap_client_config_builder.types import ClientConfigBuilder +import pytest + +from ..consts import SUPPORTED_IMPLEMENTATIONS + + +@pytest.mark.parametrize("implementation", SUPPORTED_IMPLEMENTATIONS) +def test_invalid_int8( + implementation: str, + builder: ClientConfigBuilder, + wrapper_uri: Callable[[str, str], Uri], +): + client = PolywrapClient(builder.build()) + uri = wrapper_uri("numbers-type", implementation) + + with pytest.raises(WrapAbortError) as err: + client.invoke( + uri=uri, + method="i8Method", + args={ + "first": -129, + "second": 10, + } + ) + + assert "integer overflow: value = -129; bits = 8" in err.value.args[0] + + +@pytest.mark.parametrize("implementation", SUPPORTED_IMPLEMENTATIONS) +def test_invalid_uint8( + implementation: str, + builder: ClientConfigBuilder, + wrapper_uri: Callable[[str, str], Uri], +): + client = PolywrapClient(builder.build()) + uri = wrapper_uri("numbers-type", implementation) + + with pytest.raises(WrapAbortError) as err: + client.invoke( + uri=uri, + method="u8Method", + args={ + "first": 256, + "second": 10, + } + ) + + assert "integer overflow: value = 256; bits = 8" in err.value.args[0] + + +@pytest.mark.parametrize("implementation", SUPPORTED_IMPLEMENTATIONS) +def test_invalid_int16( + implementation: str, + builder: ClientConfigBuilder, + wrapper_uri: Callable[[str, str], Uri], +): + client = PolywrapClient(builder.build()) + uri = wrapper_uri("numbers-type", implementation) + + with pytest.raises(WrapAbortError) as err: + client.invoke( + uri=uri, + method="i16Method", + args={ + "first": -32769, + "second": 10, + } + ) + + assert "integer overflow: value = -32769; bits = 16" in err.value.args[0] + + +@pytest.mark.parametrize("implementation", SUPPORTED_IMPLEMENTATIONS) +def test_invalid_uint16( + implementation: str, + builder: ClientConfigBuilder, + wrapper_uri: Callable[[str, str], Uri], +): + client = PolywrapClient(builder.build()) + uri = wrapper_uri("numbers-type", implementation) + + with pytest.raises(WrapAbortError) as err: + client.invoke( + uri=uri, + method="u16Method", + args={ + "first": 65536, + "second": 10, + } + ) + + assert "integer overflow: value = 65536; bits = 16" in err.value.args[0] + + +@pytest.mark.parametrize("implementation", SUPPORTED_IMPLEMENTATIONS) +def test_invalid_int32( + implementation: str, + builder: ClientConfigBuilder, + wrapper_uri: Callable[[str, str], Uri], +): + client = PolywrapClient(builder.build()) + uri = wrapper_uri("numbers-type", implementation) + + with pytest.raises(WrapAbortError) as err: + client.invoke( + uri=uri, + method="i32Method", + args={ + "first": -2147483649, + "second": 10, + } + ) + + assert "integer overflow: value = -2147483649; bits = 32" in err.value.args[0] + + +@pytest.mark.parametrize("implementation", SUPPORTED_IMPLEMENTATIONS) +def test_invalid_uint32( + implementation: str, + builder: ClientConfigBuilder, + wrapper_uri: Callable[[str, str], Uri], +): + client = PolywrapClient(builder.build()) + uri = wrapper_uri("numbers-type", implementation) + + with pytest.raises(WrapAbortError) as err: + client.invoke( + uri=uri, + method="u32Method", + args={ + "first": 4294967296, + "second": 10, + } + ) + + assert "integer overflow: value = 4294967296; bits = 32" in err.value.args[0] diff --git a/packages/polywrap-client/tests/msgpack/test_object.py b/packages/polywrap-client/tests/msgpack/test_object.py new file mode 100644 index 00000000..71c62925 --- /dev/null +++ b/packages/polywrap-client/tests/msgpack/test_object.py @@ -0,0 +1,118 @@ +from typing import Callable +from polywrap_client import PolywrapClient +from polywrap_core import Uri +from polywrap_client_config_builder.types import ClientConfigBuilder +import pytest + +from ..consts import SUPPORTED_IMPLEMENTATIONS + + +@pytest.mark.parametrize("implementation", SUPPORTED_IMPLEMENTATIONS) +def test_object_method1( + implementation: str, + builder: ClientConfigBuilder, + wrapper_uri: Callable[[str, str], Uri], +): + client = PolywrapClient(builder.build()) + uri = wrapper_uri("object-type", implementation) + obj = { + "arg1": { + "prop": "arg1 prop", + "nested": { + "prop": "arg1 nested prop", + }, + } + } + + response = client.invoke( + uri=uri, + method="method1", + args=obj, + ) + + assert response == [obj["arg1"], { + "prop": "", + "nested": { + "prop": "", + }, + }] + + +@pytest.mark.parametrize("implementation", SUPPORTED_IMPLEMENTATIONS) +def test_object_method2( + implementation: str, + builder: ClientConfigBuilder, + wrapper_uri: Callable[[str, str], Uri], +): + client = PolywrapClient(builder.build()) + uri = wrapper_uri("object-type", implementation) + obj = { + "arg": { + "prop": "null", + "nested": { + "prop": "arg nested prop", + }, + } + } + + response = client.invoke( + uri=uri, + method="method2", + args=obj, + ) + + assert response is None + + +@pytest.mark.parametrize("implementation", SUPPORTED_IMPLEMENTATIONS) +def test_object_method3( + implementation: str, + builder: ClientConfigBuilder, + wrapper_uri: Callable[[str, str], Uri], +): + client = PolywrapClient(builder.build()) + uri = wrapper_uri("object-type", implementation) + obj = { + "arg": { + "prop": "arg prop", + "nested": { + "prop": "arg nested prop", + }, + } + } + + response = client.invoke( + uri=uri, + method="method3", + args=obj, + ) + + assert response == [None, obj["arg"]] + + +@pytest.mark.parametrize("implementation", SUPPORTED_IMPLEMENTATIONS) +def test_object_method4( + implementation: str, + builder: ClientConfigBuilder, + wrapper_uri: Callable[[str, str], Uri], +): + client = PolywrapClient(builder.build()) + uri = wrapper_uri("object-type", implementation) + obj = { + "arg": { + "prop": [49, 50, 51, 52], + } + } + + response = client.invoke( + uri=uri, + method="method4", + args=obj, + ) + + assert response == { + "prop": "1234", + "nested": { + "prop": "nested prop", + }, + } diff --git a/packages/polywrap-client/tests/test_asyncify.py b/packages/polywrap-client/tests/test_asyncify.py deleted file mode 100644 index 63536585..00000000 --- a/packages/polywrap-client/tests/test_asyncify.py +++ /dev/null @@ -1,111 +0,0 @@ -# Polywrap Python Client - https://polywrap.io -# BigNumber wrapper schema - https://wrappers.io/v/ipfs/Qme2YXThmsqtfpiUPHJUEzZSBiqX3woQxxdXbDJZvXrvAD - -from pathlib import Path -from polywrap_client import PolywrapClient -from polywrap_core import Uri, InvokerOptions, UriPackageOrWrapper - - -async def test_asyncify(client: PolywrapClient): - uri = Uri.from_str( - f'fs/{Path(__file__).parent.joinpath("cases", "asyncify").absolute()}' - ) - args = { - "numberOfTimes": 40 - } - subsequent_invokes_options: InvokerOptions[UriPackageOrWrapper] = InvokerOptions( - uri=uri, method="subsequentInvokes", args=args - ) - subsequent_invokes_result = await client.invoke(subsequent_invokes_options) - subsequent_invokes_expected = [str(i) for i in range(40)] - - assert subsequent_invokes_result == subsequent_invokes_expected - - local_var_method_options: InvokerOptions[UriPackageOrWrapper] = InvokerOptions( - uri=uri, method="localVarMethod", args=None - ) - - local_var_method_result = await client.invoke(local_var_method_options) - - assert local_var_method_result == True - - global_var_method_options: InvokerOptions[UriPackageOrWrapper] = InvokerOptions( - uri=uri, method="globalVarMethod", args=None - ) - - global_var_method_result = await client.invoke(global_var_method_options) - assert global_var_method_result == True - - - large_str = "polywrap" * 10000 - set_data_with_large_args_options: InvokerOptions[UriPackageOrWrapper] = InvokerOptions( - uri=uri, method="setDataWithLargeArgs", args={"value":large_str} - ) - set_data_with_large_args_result = await client.invoke(set_data_with_large_args_options) - assert set_data_with_large_args_result == large_str - - large_str = "polywrap" * 10000 - set_data_with_large_args_options: InvokerOptions[UriPackageOrWrapper] = InvokerOptions( - uri=uri, method="setDataWithLargeArgs", args={"value":large_str} - ) - set_data_with_large_args_result = await client.invoke(set_data_with_large_args_options) - assert set_data_with_large_args_result == large_str - - set_data_with_many_args_args = { - "valueA": "polywrap a", - "valueB": "polywrap b", - "valueC": "polywrap c", - "valueD": "polywrap d", - "valueE": "polywrap e", - "valueF": "polywrap f", - "valueG": "polywrap g", - "valueH": "polywrap h", - "valueI": "polywrap i", - "valueJ": "polywrap j", - "valueK": "polywrap k", - "valueL": "polywrap l", - } - set_data_with_many_args_options: InvokerOptions[UriPackageOrWrapper] = InvokerOptions( - uri=uri, method="setDataWithManyArgs", args=set_data_with_many_args_args - ) - - set_data_with_many_args_result = await client.invoke(set_data_with_many_args_options) - - set_data_with_many_args_expected = "polywrap apolywrap bpolywrap cpolywrap dpolywrap epolywrap fpolywrap gpolywrap hpolywrap ipolywrap jpolywrap kpolywrap l" - assert set_data_with_many_args_result == set_data_with_many_args_expected - - def create_obj(i: int): - return { - "propA": f"a-{i}", - "propB": f"b-{i}", - "propC": f"c-{i}", - "propD": f"d-{i}", - "propE": f"e-{i}", - "propF": f"f-{i}", - "propG": f"g-{i}", - "propH": f"h-{i}", - "propI": f"i-{i}", - "propJ": f"j-{i}", - "propK": f"k-{i}", - "propL": f"l-{i}" - } - - set_data_with_many_structure_args_args = { - "valueA": create_obj(1), - "valueB": create_obj(2), - "valueC": create_obj(3), - "valueD": create_obj(4), - "valueE": create_obj(5), - "valueF": create_obj(6), - "valueG": create_obj(7), - "valueH": create_obj(8), - "valueI": create_obj(9), - "valueJ": create_obj(10), - "valueK": create_obj(11), - "valueL": create_obj(12), - } - set_data_with_many_structured_args_options: InvokerOptions[UriPackageOrWrapper] = InvokerOptions( - uri=uri, method="setDataWithManyStructuredArgs", args=set_data_with_many_structure_args_args - ) - set_data_with_many_structured_args_result = await client.invoke(set_data_with_many_structured_args_options) - assert set_data_with_many_structured_args_result == True diff --git a/packages/polywrap-client/tests/test_bignumber.py b/packages/polywrap-client/tests/test_bignumber.py deleted file mode 100644 index 3c196406..00000000 --- a/packages/polywrap-client/tests/test_bignumber.py +++ /dev/null @@ -1,71 +0,0 @@ -# Polywrap Python Client - https://polywrap.io -# BigNumber wrapper schema - https://wrappers.io/v/ipfs/Qme2YXThmsqtfpiUPHJUEzZSBiqX3woQxxdXbDJZvXrvAD - -from pathlib import Path -from polywrap_client import PolywrapClient -from polywrap_core import Uri, InvokerOptions, UriPackageOrWrapper - - -async def test_invoke_bignumber_1arg_and_1prop(client: PolywrapClient): - uri = Uri.from_str( - f'fs/{Path(__file__).parent.joinpath("cases", "big-number").absolute()}' - ) - args = { - "arg1": "123", # The base number - "obj": { - "prop1": "1000", # multiply the base number by this factor - }, - } - options: InvokerOptions[UriPackageOrWrapper] = InvokerOptions( - uri=uri, method="method", args=args, encode_result=False - ) - result = await client.invoke(options) - assert result == "123000" - - -async def test_invoke_bignumber_with_1arg_and_2props(client: PolywrapClient): - uri = Uri.from_str( - f'fs/{Path(__file__).parent.joinpath("cases", "big-number").absolute()}' - ) - args = {"arg1": "123123", "obj": {"prop1": "1000", "prop2": "4"}} - options: InvokerOptions[UriPackageOrWrapper] = InvokerOptions( - uri=uri, method="method", args=args, encode_result=False - ) - result = await client.invoke(options) - assert result == str(123123 * 1000 * 4) - - -async def test_invoke_bignumber_with_2args_and_1prop(client: PolywrapClient): - uri = Uri.from_str( - f'fs/{Path(__file__).parent.joinpath("cases", "big-number").absolute()}' - ) - args = {"arg1": "123123", "obj": {"prop1": "1000", "prop2": "444"}} - options: InvokerOptions[UriPackageOrWrapper] = InvokerOptions( - uri=uri, method="method", args=args, encode_result=False - ) - result = await client.invoke(options) - assert result == str(123123 * 1000 * 444) - - -async def test_invoke_bignumber_with_2args_and_2props(client: PolywrapClient): - uri = Uri.from_str( - f'fs/{Path(__file__).parent.joinpath("cases", "big-number").absolute()}' - ) - args = {"arg1": "123123", "arg2": "555", "obj": {"prop1": "1000", "prop2": "4"}} - options: InvokerOptions[UriPackageOrWrapper] = InvokerOptions( - uri=uri, method="method", args=args, encode_result=False - ) - result = await client.invoke(options) - assert result == str(123123 * 555 * 1000 * 4) - - -async def test_invoke_bignumber_with_2args_and_2props_floats(client: PolywrapClient): - uri = Uri.from_str( - f'fs/{Path(__file__).parent.joinpath("cases", "big-number").absolute()}' - ) - args = {"arg1": "123.123", "arg2": "55.5", "obj": {"prop1": "10.001", "prop2": "4"}} - options: InvokerOptions[UriPackageOrWrapper] = InvokerOptions( - uri=uri, method="method", args=args, encode_result=False - ) - result = await client.invoke(options) - assert result == str(123.123 * 55.5 * 10.001 * 4) diff --git a/packages/polywrap-client/tests/test_client.py b/packages/polywrap-client/tests/test_client.py deleted file mode 100644 index c79d0406..00000000 --- a/packages/polywrap-client/tests/test_client.py +++ /dev/null @@ -1,195 +0,0 @@ -from pathlib import Path - -from polywrap_client_config_builder import PolywrapClientConfigBuilder -from polywrap_plugin import PluginPackage -from polywrap_client import PolywrapClient -from polywrap_manifest import deserialize_wrap_manifest -from polywrap_core import ( - Uri, - InvokerOptions, - FileReader, - UriPackageOrWrapper, - ClientConfig, -) -from polywrap_uri_resolvers import ( - BaseUriResolver, - FsUriResolver, - SimpleFileReader, - StaticResolver, -) -from polywrap_wasm import WasmWrapper - - -async def test_invoke( - client: PolywrapClient, - simple_file_reader: FileReader, - simple_wrap_module: bytes, - simple_wrap_manifest: bytes, -): - uri = Uri.from_str( - f'fs/{Path(__file__).parent.joinpath("cases", "simple-invoke").absolute()}' - ) - args = {"arg": "hello polywrap"} - options: InvokerOptions[UriPackageOrWrapper] = InvokerOptions( - uri=uri, method="simpleMethod", args=args, encode_result=False - ) - result = await client.invoke(options) - - assert result == args["arg"] - - manifest = deserialize_wrap_manifest(simple_wrap_manifest) - - wrapper = WasmWrapper( - file_reader=simple_file_reader, - wasm_module=simple_wrap_module, - manifest=manifest, - ) - resolver = StaticResolver({Uri.from_str("ens/wrapper.eth"): wrapper}) - - config = ClientConfig(resolver=resolver) - client = PolywrapClient(config=config) - - args = {"arg": "hello polywrap"} - options = InvokerOptions( - uri=Uri.from_str("ens/wrapper.eth"), - method="simpleMethod", - args=args, - encode_result=False, - ) - result = await client.invoke(options) - - assert result == args["arg"] - - -async def test_subinvoke(): - uri_resolver = BaseUriResolver( - file_reader=SimpleFileReader(), - redirects={ - Uri.from_str("ens/add.eth"): Uri.from_str( - f'fs/{Path(__file__).parent.joinpath("cases", "simple-subinvoke", "subinvoke").absolute()}' - ), - }, - ) - - client = PolywrapClient(config=ClientConfig(resolver=uri_resolver)) - uri = Uri.from_str( - f'fs/{Path(__file__).parent.joinpath("cases", "simple-subinvoke", "invoke").absolute()}' - ) - args = {"a": 1, "b": 2} - options: InvokerOptions[UriPackageOrWrapper] = InvokerOptions( - uri=uri, method="add", args=args, encode_result=False - ) - result = await client.invoke(options) - - assert result == "1 + 2 = 3" - - -async def test_interface_implementation(): - uri_resolver = BaseUriResolver( - file_reader=SimpleFileReader(), - redirects={}, - ) - - interface_uri = Uri.from_str("ens/interface.eth") - impl_uri = Uri.from_str( - f'fs/{Path(__file__).parent.joinpath("cases", "simple-interface", "implementation").absolute()}' - ) - - client = PolywrapClient( - config=ClientConfig( - resolver=uri_resolver, interfaces={interface_uri: [impl_uri]} - ) - ) - uri = Uri.from_str( - f'fs/{Path(__file__).parent.joinpath("cases", "simple-interface", "wrapper").absolute()}' - ) - args = {"arg": {"str": "hello", "uint8": 2}} - options: InvokerOptions[UriPackageOrWrapper] = InvokerOptions( - uri=uri, method="moduleMethod", args=args, encode_result=False - ) - result = await client.invoke(options) - assert client.get_implementations(interface_uri) == [impl_uri] - assert result == {"str": "hello", "uint8": 2} - - -def test_get_env_by_uri(): - uri_resolver = BaseUriResolver( - file_reader=SimpleFileReader(), - redirects={}, - ) - uri = Uri.from_str( - f'fs/{Path(__file__).parent.joinpath("cases", "simple-env").absolute()}' - ) - env = {"externalArray": [1, 2, 3], "externalString": "hello"} - - client = PolywrapClient( - config=ClientConfig( - envs={uri: env}, - resolver=uri_resolver, - ) - ) - assert client.get_env_by_uri(uri) == env - - -async def test_env(): - uri_resolver = BaseUriResolver( - file_reader=SimpleFileReader(), - redirects={}, - ) - - uri = Uri.from_str( - f'fs/{Path(__file__).parent.joinpath("cases", "simple-env").absolute()}' - ) - env = {"externalArray": [1, 2, 3], "externalString": "hello"} - - client = PolywrapClient( - config=ClientConfig( - envs={uri: env}, - resolver=uri_resolver, - ) - ) - options: InvokerOptions[UriPackageOrWrapper] = InvokerOptions( - uri=uri, - method="externalEnvMethod", - args={}, - encode_result=False, - ) - - result = await client.invoke(options) - - assert result == env - - -async def test_complex_subinvocation(adder_plugin: PluginPackage[None]): - config = ( - PolywrapClientConfigBuilder() - .add_resolver(FsUriResolver(SimpleFileReader())) - .set_redirect( - Uri.from_str("ens/imported-subinvoke.eth"), - Uri.from_str( - f'fs/{Path(__file__).parent.joinpath("cases", "subinvoke", "00-subinvoke").absolute()}' - ), - ) - .set_redirect( - Uri.from_str("ens/imported-invoke.eth"), - Uri.from_str( - f'fs/{Path(__file__).parent.joinpath("cases", "subinvoke", "01-invoke").absolute()}' - ), - ) - .set_package( - Uri.from_str("plugin/adder"), - adder_plugin, - ) - ).build() - - client = PolywrapClient(config) - uri = Uri.from_str( - f'fs/{Path(__file__).parent.joinpath("cases", "subinvoke", "02-consumer").absolute()}' - ) - args = {"a": 1, "b": 1} - options: InvokerOptions[UriPackageOrWrapper] = InvokerOptions( - uri=uri, method="addFromPluginAndIncrement", args=args - ) - result = await client.invoke(options) - - assert result == 4 diff --git a/packages/polywrap-client/tests/test_sha3.py b/packages/polywrap-client/tests/test_sha3.py deleted file mode 100644 index d67fcec8..00000000 --- a/packages/polywrap-client/tests/test_sha3.py +++ /dev/null @@ -1,111 +0,0 @@ -# # Polywrap Python Client - https://polywrap.io -# # SHA3 Wrapper Schema - https://wrappers.io/v/ipfs/QmbYw6XfEmNdR3Uoa7u2U1WRqJEXbseiSoBNBt3yPFnKvi - -# from pathlib import Path -# from polywrap_client import PolywrapClient -# from polywrap_core import Uri, InvokerOptions -# import hashlib -# import pytest -# from Crypto.Hash import keccak, SHAKE128, SHAKE256 - -# client = PolywrapClient() -# uri = Uri(f'fs/{Path(__file__).parent.joinpath("cases", "sha3").absolute()}') - -# args = {"message": "hello polywrap!"} - -# @pytest.mark.skip(reason="can't invoke sha3 wrapper due to an error related to wasmtime") -# async def test_invoke_sha3_512(): -# options = InvokerOptions(uri=uri, method="sha3_512", args=args, encode_result=False) -# result = await client.invoke(options) -# s = hashlib.sha512() -# s.update(b"hello polywrap!") -# assert result.unwrap() == s.digest() - -# @pytest.mark.skip(reason="can't invoke sha3 wrapper due to an error related to wasmtime") -# async def test_invoke_sha3_384(): -# options = InvokerOptions(uri=uri, method="sha3_384", args=args, encode_result=False) -# result = await client.invoke(options) -# s = hashlib.sha384() -# s.update(b"hello polywrap!") -# assert result.unwrap() == s.digest() - -# @pytest.mark.skip(reason="can't invoke sha3 wrapper due to an error related to wasmtime") -# async def test_invoke_sha3_256(): -# options = InvokerOptions(uri=uri, method="sha3_256", args=args, encode_result=False) -# result = await client.invoke(options) -# s = hashlib.sha256() -# s.update(b"hello polywrap!") -# assert result.unwrap() == s.digest() - -# @pytest.mark.skip(reason="can't invoke sha3 wrapper due to an error related to wasmtime") -# async def test_invoke_sha3_224(): -# options = InvokerOptions(uri=uri, method="sha3_224", args=args, encode_result=False) -# result = await client.invoke(options) -# s = hashlib.sha224() -# s.update(b"hello polywrap!") -# assert result.unwrap() == s.digest() - -# @pytest.mark.skip(reason="can't invoke sha3 wrapper due to an error related to wasmtime") -# async def test_invoke_keccak_512(): -# options = InvokerOptions(uri=uri, method="keccak_512", args=args, encode_result=False) -# result = await client.invoke(options) -# k = keccak.new(digest_bits=512) -# k.update(b'hello polywrap!') -# assert result.unwrap() == k.digest() - -# @pytest.mark.skip(reason="can't invoke sha3 wrapper due to an error related to wasmtime") -# async def test_invoke_keccak_384(): -# options = InvokerOptions(uri=uri, method="keccak_384", args=args, encode_result=False) -# result = await client.invoke(options) -# k = keccak.new(digest_bits=384) -# k.update(b'hello polywrap!') -# assert result.unwrap() == k.digest() - -# @pytest.mark.skip(reason="can't invoke sha3 wrapper due to an error related to wasmtime") -# async def test_invoke_keccak_256(): -# options = InvokerOptions(uri=uri, method="keccak_256", args=args, encode_result=False) -# result = await client.invoke(options) -# k = keccak.new(digest_bits=256) -# k.update(b'hello polywrap!') -# assert result.unwrap() == k.digest() - -# @pytest.mark.skip(reason="can't invoke sha3 wrapper due to an error related to wasmtime") -# async def test_invoke_keccak_224(): -# options = InvokerOptions(uri=uri, method="keccak_224", args=args, encode_result=False) -# result = await client.invoke(options) -# k = keccak.new(digest_bits=224) -# k.update(b'hello polywrap!') -# assert result.unwrap() == k.digest() - -# @pytest.mark.skip(reason="can't invoke sha3 wrapper due to an error related to wasmtime") -# async def test_invoke_hex_keccak_256(): -# options = InvokerOptions(uri=uri, method="hex_keccak_256", args=args, encode_result=False) -# result = await client.invoke(options) -# k = keccak.new(digest_bits=256) -# k.update(b'hello polywrap!') -# assert result.unwrap() == k.hexdigest() - -# @pytest.mark.skip(reason="buffer keccak must be implemented in python in order to assert") -# async def test_invoke_buffer_keccak_256(): -# options = InvokerOptions(uri=uri, method="buffer_keccak_256", args=args, encode_result=False) -# result = await client.invoke(options) -# # TODO: Not sure exactly what this function `buffer_keccak_256` is doing in order to assert it properly -# assert result.unwrap() == False - -# @pytest.mark.skip(reason="can't invoke sha3 wrapper due to an error related to wasmtime") -# async def test_invoke_shake_256(): -# args = {"message": "hello polywrap!", "outputBits":8} -# options = InvokerOptions(uri=uri, method="shake_256", args=args, encode_result=False) -# result = await client.invoke(options) -# s = SHAKE256.new() -# s.update(b"hello polywrap!") -# assert result.unwrap() == s.read(8).hex() - -# @pytest.mark.skip(reason="can't invoke sha3 wrapper due to an error related to wasmtime") -# async def test_invoke_shake_128(): -# args = {"message": "hello polywrap!", "outputBits":8} -# options = InvokerOptions(uri=uri, method="shake_128", args=args, encode_result=False) -# result = await client.invoke(options) -# s = SHAKE128.new() -# s.update(b"hello polywrap!") -# assert result.unwrap() == s.read(8).hex() \ No newline at end of file diff --git a/packages/polywrap-client/tests/test_timer.py b/packages/polywrap-client/tests/test_timer.py deleted file mode 100644 index 435b5050..00000000 --- a/packages/polywrap-client/tests/test_timer.py +++ /dev/null @@ -1,49 +0,0 @@ -# import asyncio -# from typing import Any, Dict - -# from pathlib import Path -# from polywrap_core import Invoker, Uri, InvokerOptions, UriWrapper, Wrapper -# from polywrap_plugin import PluginModule, PluginWrapper -# from polywrap_uri_resolvers import StaticResolver -# from polywrap_manifest import AnyWrapManifest -# from polywrap_result import Result, Ok, Err -# from polywrap_client import PolywrapClient, PolywrapClientConfig -# from pytest import fixture - - -# @fixture -# def timer_module(): -# class TimerModule(PluginModule[None, str]): -# def __init__(self, config: None): -# super().__init__(config) - -# async def sleep(self, args: Dict[str, Any], client: Invoker): -# await asyncio.sleep(args["time"]) -# print(f"Woke up after {args['time']} seconds") -# return Ok(True) - -# return TimerModule(None) - -# @fixture -# def simple_wrap_manifest(): -# wrap_path = Path(__file__).parent / "cases" / "simple-invoke" / "wrap.info" -# with open(wrap_path, "rb") as f: -# yield f.read() - -# @fixture -# def timer_wrapper(timer_module: PluginModule[None, str], simple_wrap_manifest: AnyWrapManifest): -# return PluginWrapper(module=timer_module, manifest=simple_wrap_manifest) - - -# async def test_timer(timer_wrapper: Wrapper): -# uri_wrapper = UriWrapper(uri=Uri("ens/timer.eth"), wrapper=timer_wrapper) -# resolver = StaticResolver.from_list([uri_wrapper]).unwrap() - -# config = PolywrapClientConfig(resolver=resolver) - -# client = PolywrapClient(config) -# uri = Uri('ens/timer.eth') or Uri(f'fs/{Path(__file__).parent.joinpath("cases", "big-number").absolute()}') -# args = { "time": 1 } -# options = InvokerOptions(uri=uri, method="sleep", args=args, encode_result=False) -# result = await client.invoke(options) -# assert result.unwrap() == True diff --git a/packages/polywrap-client/tests/wrap_features/.gitignore b/packages/polywrap-client/tests/wrap_features/.gitignore new file mode 100644 index 00000000..becd6eb0 --- /dev/null +++ b/packages/polywrap-client/tests/wrap_features/.gitignore @@ -0,0 +1 @@ +!env/ \ No newline at end of file diff --git a/packages/polywrap-client/tests/wrap_features/__init__.py b/packages/polywrap-client/tests/wrap_features/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/packages/polywrap-client/tests/wrap_features/env/__init__.py b/packages/polywrap-client/tests/wrap_features/env/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/packages/polywrap-client/tests/wrap_features/env/conftest.py b/packages/polywrap-client/tests/wrap_features/env/conftest.py new file mode 100644 index 00000000..782ce83b --- /dev/null +++ b/packages/polywrap-client/tests/wrap_features/env/conftest.py @@ -0,0 +1,90 @@ +from typing import Any, Callable + +import pytest +from polywrap_client_config_builder import PolywrapClientConfigBuilder +from polywrap_client_config_builder.types import ClientConfigBuilder +from polywrap_core import Uri +from polywrap_test_cases import get_path_to_test_wrappers +from polywrap_uri_resolvers import FsUriResolver, SimpleFileReader + + +@pytest.fixture +def external_wrapper_uri() -> Callable[[str], Uri]: + def get_external_wrapper_uri(implementation: str) -> Uri: + external_wrapper_path = f"{get_path_to_test_wrappers()}/env-type/00-external/implementations/{implementation}" + return Uri.from_str(f"file/{external_wrapper_path}") + + return get_external_wrapper_uri + + +@pytest.fixture +def wrapper_uri() -> Callable[[str], Uri]: + def get_wrapper_uri(implementation: str) -> Uri: + wrapper_path = f"{get_path_to_test_wrappers()}/env-type/01-main/implementations/{implementation}" + return Uri.from_str(f"file/{wrapper_path}") + + return get_wrapper_uri + + +@pytest.fixture +def wrapper_env() -> Any: + return { + "object": { + "prop": "object string", + }, + "str": "string", + "optFilledStr": "optional string", + "number": 10, + "bool": True, + "en": "FIRST", + "array": [32, 23], + } + + +@pytest.fixture +def expected_wrapper_env(wrapper_env: Any) -> Any: + return { + **wrapper_env, + "optStr": None, + "optNumber": None, + "optBool": None, + "optObject": None, + "optEnum": None, + "en": 0, + } + + +@pytest.fixture +def external_wrapper_env() -> Any: + return { + "externalArray": [1, 2, 3], + "externalString": "iamexternal", + } + + +@pytest.fixture +def builder( + wrapper_uri: Callable[[str], Uri], + external_wrapper_uri: Callable[[str], Uri], + wrapper_env: Any, + external_wrapper_env: Any, +) -> Callable[[str], ClientConfigBuilder]: + def get_builder(implementation: str) -> ClientConfigBuilder: + return ( + PolywrapClientConfigBuilder() + .add_env( + wrapper_uri(implementation), + wrapper_env, + ) + .add_env( + external_wrapper_uri(implementation), + external_wrapper_env, + ) + .set_redirect( + Uri.from_str("ens/external-env.polywrap.eth"), + external_wrapper_uri(implementation), + ) + .add_resolver(FsUriResolver(SimpleFileReader())) + ) + + return get_builder diff --git a/packages/polywrap-client/tests/wrap_features/env/test_method_require_env.py b/packages/polywrap-client/tests/wrap_features/env/test_method_require_env.py new file mode 100644 index 00000000..4dae3dda --- /dev/null +++ b/packages/polywrap-client/tests/wrap_features/env/test_method_require_env.py @@ -0,0 +1,47 @@ +from typing import Any, Callable + +import pytest +from polywrap_client_config_builder.types import ClientConfigBuilder +from polywrap_core import Uri + +from polywrap_client import PolywrapClient + +from ...consts import SUPPORTED_IMPLEMENTATIONS + + +@pytest.mark.parametrize("implementation", SUPPORTED_IMPLEMENTATIONS) +def test_method_require_env( + implementation: str, + builder: Callable[[str], ClientConfigBuilder], + wrapper_uri: Callable[[str], Uri], + wrapper_env: Any, + expected_wrapper_env: Any, +): + client = PolywrapClient(builder(implementation).build()) + method_require_env_result = client.invoke( + uri=wrapper_uri(implementation), + method="methodRequireEnv", + args={ + "arg": "string", + }, + ) + assert method_require_env_result == expected_wrapper_env + + k = { + Uri( + "file", + "/Users/niraj/Documents/Projects/polywrap/python-client/packages/polywrap-test-cases/wrappers/env-type/01-main/implementations/rs", + ): { + "object": {"prop": "object string"}, + "str": "string", + "optFilledStr": "optional string", + "number": 10, + "bool": True, + "en": "FIRST", + "array": [32, 23], + }, + Uri( + "file", + "/Users/niraj/Documents/Projects/polywrap/python-client/packages/polywrap-test-cases/wrappers/env-type/00-external/implementations/rs", + ): {"externalArray": [1, 2, 3], "externalString": "iamexternal"}, + } diff --git a/packages/polywrap-client/tests/wrap_features/env/test_mock_updated_env.py b/packages/polywrap-client/tests/wrap_features/env/test_mock_updated_env.py new file mode 100644 index 00000000..d28b338e --- /dev/null +++ b/packages/polywrap-client/tests/wrap_features/env/test_mock_updated_env.py @@ -0,0 +1,39 @@ +from typing import Any, Callable + +import pytest +from polywrap_client_config_builder.types import ClientConfigBuilder +from polywrap_core import Uri + +from polywrap_client import PolywrapClient + +from ...consts import SUPPORTED_IMPLEMENTATIONS + + +@pytest.mark.parametrize("implementation", SUPPORTED_IMPLEMENTATIONS) +def test_mock_updated_env( + implementation: str, + builder: Callable[[str], ClientConfigBuilder], + wrapper_uri: Callable[[str], Uri], + expected_wrapper_env: Any, +): + client = PolywrapClient(builder(implementation).build()) + override_env = { + "object": { + "prop": "object another string", + }, + "str": "another string", + "optFilledStr": "optional string", + "number": 10, + "bool": True, + "en": "FIRST", + "array": [32, 23], + } + mock_updated_env_result = client.invoke( + uri=wrapper_uri(implementation), + method="methodRequireEnv", + args={ + "arg": "string", + }, + env=override_env, + ) + assert mock_updated_env_result == {**expected_wrapper_env, **override_env, "en": 0} diff --git a/packages/polywrap-client/tests/wrap_features/env/test_subinvoke_env_method.py b/packages/polywrap-client/tests/wrap_features/env/test_subinvoke_env_method.py new file mode 100644 index 00000000..4f1425fe --- /dev/null +++ b/packages/polywrap-client/tests/wrap_features/env/test_subinvoke_env_method.py @@ -0,0 +1,31 @@ +from typing import Any, Callable + +import pytest +from polywrap_client_config_builder.types import ClientConfigBuilder +from polywrap_core import Uri + +from polywrap_client import PolywrapClient + +from ...consts import SUPPORTED_IMPLEMENTATIONS + + +@pytest.mark.parametrize("implementation", SUPPORTED_IMPLEMENTATIONS) +def test_subinvoke_env_method( + implementation: str, + builder: Callable[[str], ClientConfigBuilder], + wrapper_uri: Callable[[str], Uri], + expected_wrapper_env: Any, + external_wrapper_env: Any, +): + client = PolywrapClient(builder(implementation).build()) + subinvoke_env_method_result = client.invoke( + uri=wrapper_uri(implementation), + method="subinvokeEnvMethod", + args={ + "arg": "string", + }, + ) + assert subinvoke_env_method_result == { + "local": expected_wrapper_env, + "external": external_wrapper_env, + } diff --git a/packages/polywrap-client/tests/wrap_features/interface_implementations/__init__.py b/packages/polywrap-client/tests/wrap_features/interface_implementations/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/packages/polywrap-client/tests/wrap_features/interface_implementations/conftest.py b/packages/polywrap-client/tests/wrap_features/interface_implementations/conftest.py new file mode 100644 index 00000000..ec603be9 --- /dev/null +++ b/packages/polywrap-client/tests/wrap_features/interface_implementations/conftest.py @@ -0,0 +1,49 @@ +from typing import Callable + +import pytest +from polywrap_client_config_builder import PolywrapClientConfigBuilder +from polywrap_client_config_builder.types import ClientConfigBuilder +from polywrap_core import Uri +from polywrap_test_cases import get_path_to_test_wrappers +from polywrap_uri_resolvers import FsUriResolver, SimpleFileReader + + +@pytest.fixture +def interface_uri() -> Uri: + return Uri.from_str("wrap://ens/interface.eth") + + +@pytest.fixture +def implementation_uri() -> Callable[[str], Uri]: + def get_implementation_uri(implementation: str) -> Uri: + implementation_path = f"{get_path_to_test_wrappers()}/interface-invoke/01-implementation/implementations/{implementation}" + return Uri.from_str(f"file/{implementation_path}") + + return get_implementation_uri + + +@pytest.fixture +def wrapper_uri() -> Callable[[str], Uri]: + def get_wrapper_uri(implementation: str) -> Uri: + wrapper_path = f"{get_path_to_test_wrappers()}/interface-invoke/02-wrapper/implementations/{implementation}" + return Uri.from_str(f"file/{wrapper_path}") + + return get_wrapper_uri + + +@pytest.fixture +def builder( + interface_uri: Uri, + implementation_uri: Callable[[str], Uri], +) -> Callable[[str], ClientConfigBuilder]: + def get_builder(implementation: str) -> ClientConfigBuilder: + return ( + PolywrapClientConfigBuilder() + .add_interface_implementations( + interface_uri=interface_uri, + implementations_uris=[implementation_uri(implementation)] + ) + .add_resolver(FsUriResolver(SimpleFileReader())) + ) + + return get_builder diff --git a/packages/polywrap-client/tests/wrap_features/interface_implementations/test_get_implementations.py b/packages/polywrap-client/tests/wrap_features/interface_implementations/test_get_implementations.py new file mode 100644 index 00000000..3129b1ed --- /dev/null +++ b/packages/polywrap-client/tests/wrap_features/interface_implementations/test_get_implementations.py @@ -0,0 +1,42 @@ +import pytest +from polywrap_core import Uri +from polywrap_client import PolywrapClient +from polywrap_client_config_builder import PolywrapClientConfigBuilder + + + +def test_get_all_implementations_of_interface(): + interface1_uri = Uri.from_str("wrap://ens/some-interface1.eth") + interface2_uri = Uri.from_str("wrap://ens/some-interface2.eth") + interface3_uri = Uri.from_str("wrap://ens/some-interface3.eth") + + implementation1_uri = Uri.from_str("wrap://ens/some-implementation.eth") + implementation2_uri = Uri.from_str("wrap://ens/some-implementation2.eth") + implementation3_uri = Uri.from_str("wrap://ens/some-implementation3.eth") + implementation4_uri = Uri.from_str("wrap://ens/some-implementation4.eth") + + builder = ( + PolywrapClientConfigBuilder() + .set_redirect(interface1_uri, interface2_uri) + .set_redirect(implementation1_uri, implementation2_uri) + .set_redirect(implementation2_uri, implementation3_uri) + .set_package(implementation4_uri, NotImplemented) + .add_interface_implementations(interface1_uri, [implementation1_uri, implementation2_uri]) + .add_interface_implementations(interface2_uri, [implementation3_uri]) + .add_interface_implementations(interface3_uri, [implementation3_uri, implementation4_uri]) + ) + + + client = PolywrapClient(builder.build()) + + implementations1 = client.get_implementations(interface1_uri) + implementations2 = client.get_implementations(interface2_uri) + implementations3 = client.get_implementations(interface3_uri) + + assert implementations1 is not None + assert implementations2 is not None + assert implementations3 is not None + + assert set(implementations1) == {implementation1_uri, implementation2_uri, implementation3_uri} + assert set(implementations2) == {implementation1_uri, implementation2_uri, implementation3_uri} + assert set(implementations3) == {implementation3_uri, implementation4_uri} diff --git a/packages/polywrap-client/tests/wrap_features/interface_implementations/test_implementation_register.py b/packages/polywrap-client/tests/wrap_features/interface_implementations/test_implementation_register.py new file mode 100644 index 00000000..dda01a32 --- /dev/null +++ b/packages/polywrap-client/tests/wrap_features/interface_implementations/test_implementation_register.py @@ -0,0 +1,31 @@ +import pytest +from polywrap_core import Uri +from polywrap_client import PolywrapClient +from polywrap_client_config_builder import PolywrapClientConfigBuilder + + +def test_register_interface_implementations(): + interface_uri = Uri.from_str("wrap://ens/some-interface1.eth") + implementation1_uri = Uri.from_str("wrap://ens/some-implementation1.eth") + implementation2_uri = Uri.from_str("wrap://ens/some-implementation2.eth") + + builder = ( + PolywrapClientConfigBuilder() + .add_interface_implementations( + interface_uri, [implementation1_uri, implementation2_uri] + ) + .set_redirect(Uri.from_str("uri/foo"), Uri.from_str("uri/bar")) + ) + + client = PolywrapClient(builder.build()) + + interfaces = client.get_interfaces() + + assert interfaces == {interface_uri: [implementation1_uri, implementation2_uri]} + + implementations = client.get_implementations( + interface_uri + ) + + assert implementations is not None + assert set(implementations) == {implementation1_uri, implementation2_uri} diff --git a/packages/polywrap-client/tests/wrap_features/interface_implementations/test_interface_invoke.py b/packages/polywrap-client/tests/wrap_features/interface_implementations/test_interface_invoke.py new file mode 100644 index 00000000..8c687ae0 --- /dev/null +++ b/packages/polywrap-client/tests/wrap_features/interface_implementations/test_interface_invoke.py @@ -0,0 +1,32 @@ +from typing import Callable +from polywrap_client import PolywrapClient +from polywrap_core import Uri +from polywrap_client_config_builder.types import ClientConfigBuilder +import pytest + +from ...consts import SUPPORTED_IMPLEMENTATIONS + + +@pytest.mark.parametrize("implementation", SUPPORTED_IMPLEMENTATIONS) +def test_interface_invoke( + implementation: str, + builder: Callable[[str], ClientConfigBuilder], + wrapper_uri: Callable[[str], Uri], +): + client = PolywrapClient(builder(implementation).build()) + + result = client.invoke( + uri=wrapper_uri(implementation), + method="moduleMethod", + args={ + "arg": { + "uint8": 1, + "str": "Test String 1", + }, + }, + ) + + assert result == { + "uint8": 1, + "str": "Test String 1", + } diff --git a/packages/polywrap-client/tests/wrap_features/subinvoke/__init__.py b/packages/polywrap-client/tests/wrap_features/subinvoke/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/packages/polywrap-client/tests/wrap_features/subinvoke/conftest.py b/packages/polywrap-client/tests/wrap_features/subinvoke/conftest.py new file mode 100644 index 00000000..2eaba63a --- /dev/null +++ b/packages/polywrap-client/tests/wrap_features/subinvoke/conftest.py @@ -0,0 +1,43 @@ +from typing import Callable + +import pytest +from polywrap_client_config_builder import PolywrapClientConfigBuilder +from polywrap_client_config_builder.types import ClientConfigBuilder +from polywrap_core import Uri +from polywrap_test_cases import get_path_to_test_wrappers +from polywrap_uri_resolvers import FsUriResolver, SimpleFileReader + + +@pytest.fixture +def subinvoke_wrapper_uri() -> Callable[[str], Uri]: + def get_subinvoke_wrapper_uri(implementation: str) -> Uri: + subinvoke_wrapper_path = f"{get_path_to_test_wrappers()}/subinvoke/00-subinvoke/implementations/{implementation}" + return Uri.from_str(f"file/{subinvoke_wrapper_path}") + + return get_subinvoke_wrapper_uri + + +@pytest.fixture +def wrapper_uri() -> Callable[[str], Uri]: + def get_wrapper_uri(implementation: str) -> Uri: + wrapper_path = f"{get_path_to_test_wrappers()}/subinvoke/01-invoke/implementations/{implementation}" + return Uri.from_str(f"file/{wrapper_path}") + + return get_wrapper_uri + + +@pytest.fixture +def builder( + subinvoke_wrapper_uri: Callable[[str], Uri], +) -> Callable[[str], ClientConfigBuilder]: + def get_builder(implementation: str) -> ClientConfigBuilder: + return ( + PolywrapClientConfigBuilder() + .set_redirect( + Uri.from_str("ens/imported-subinvoke.eth"), + subinvoke_wrapper_uri(implementation), + ) + .add_resolver(FsUriResolver(SimpleFileReader())) + ) + + return get_builder diff --git a/packages/polywrap-client/tests/wrap_features/subinvoke/test_subinvoke.py b/packages/polywrap-client/tests/wrap_features/subinvoke/test_subinvoke.py new file mode 100644 index 00000000..fbc7d4dd --- /dev/null +++ b/packages/polywrap-client/tests/wrap_features/subinvoke/test_subinvoke.py @@ -0,0 +1,24 @@ +from typing import Callable +from polywrap_client import PolywrapClient +from polywrap_client_config_builder.types import ClientConfigBuilder +from polywrap_core import Uri +import pytest + +from ...consts import SUPPORTED_IMPLEMENTATIONS + + +@pytest.mark.parametrize("implementation", SUPPORTED_IMPLEMENTATIONS) +def test_subinvoke( + implementation: str, + builder: Callable[[str], ClientConfigBuilder], + wrapper_uri: Callable[[str], Uri], +): + client = PolywrapClient(builder(implementation).build()) + + result = client.invoke( + uri=wrapper_uri(implementation), + method="addAndIncrement", + args={"a": 1, "b": 1}, + ) + + assert result == 3 diff --git a/packages/polywrap-client/tox.ini b/packages/polywrap-client/tox.ini index 864ed32f..742e4c19 100644 --- a/packages/polywrap-client/tox.ini +++ b/packages/polywrap-client/tox.ini @@ -4,6 +4,7 @@ envlist = py310 [testenv] commands = + python -m polywrap_test_cases pytest tests/ [testenv:lint] From 8b9c16404e691cdc0dbde7cafa04778952ba2809 Mon Sep 17 00:00:00 2001 From: Niraj Kamdar Date: Tue, 6 Jun 2023 18:14:42 +0530 Subject: [PATCH 13/47] refactor: polywrap-client-config-builder package --- .gitignore | 2 - .../__init__.py | 1 + .../configures/base_configure.py | 4 +- .../configures/env_configure.py | 25 ++++---- .../configures/interface_configure.py | 7 ++- .../configures/package_configure.py | 21 ++++--- .../configures/redirect_configure.py | 7 ++- .../configures/resolver_configure.py | 7 ++- .../configures/wrapper_configure.py | 21 ++++--- .../polywrap_client_config_builder.py | 51 +++++++++-------- .../types/build_options.py | 9 ++- .../types/builder_config.py | 26 ++++----- .../types/client_config_builder.py | 57 ++++++++----------- 13 files changed, 121 insertions(+), 117 deletions(-) diff --git a/.gitignore b/.gitignore index 83e6d3d9..9cccc7c0 100644 --- a/.gitignore +++ b/.gitignore @@ -104,9 +104,7 @@ celerybeat.pid # Environments .env .venv -env/ venv/ -ENV/ env.bak/ venv.bak/ diff --git a/packages/polywrap-client-config-builder/polywrap_client_config_builder/__init__.py b/packages/polywrap-client-config-builder/polywrap_client_config_builder/__init__.py index 3cadfb7d..80579769 100644 --- a/packages/polywrap-client-config-builder/polywrap_client_config_builder/__init__.py +++ b/packages/polywrap-client-config-builder/polywrap_client_config_builder/__init__.py @@ -1,3 +1,4 @@ """This package contains modules related to client config builder.""" from .polywrap_client_config_builder import * +from .types import * diff --git a/packages/polywrap-client-config-builder/polywrap_client_config_builder/configures/base_configure.py b/packages/polywrap-client-config-builder/polywrap_client_config_builder/configures/base_configure.py index 867a7310..0dfcb7e1 100644 --- a/packages/polywrap-client-config-builder/polywrap_client_config_builder/configures/base_configure.py +++ b/packages/polywrap-client-config-builder/polywrap_client_config_builder/configures/base_configure.py @@ -1,8 +1,10 @@ """This module contains the base configure class for the client config builder.""" +from abc import ABC + from ..types import BuilderConfig, ClientConfigBuilder -class BaseConfigure(ClientConfigBuilder): +class BaseConfigure(ClientConfigBuilder, ABC): """BaseConfigure is the base configure class for the client config builder. Attributes: diff --git a/packages/polywrap-client-config-builder/polywrap_client_config_builder/configures/env_configure.py b/packages/polywrap-client-config-builder/polywrap_client_config_builder/configures/env_configure.py index daf2e7c2..1a1d1297 100644 --- a/packages/polywrap-client-config-builder/polywrap_client_config_builder/configures/env_configure.py +++ b/packages/polywrap-client-config-builder/polywrap_client_config_builder/configures/env_configure.py @@ -1,36 +1,39 @@ """This module contains the env configure class for the client config builder.""" -from typing import Dict, List, Union +from abc import ABC +from typing import Any, Dict, List, Union -from polywrap_core import Env, Uri +from polywrap_core import Uri -from ..types import ClientConfigBuilder +from ..types import BuilderConfig, ClientConfigBuilder -class EnvConfigure(ClientConfigBuilder): +class EnvConfigure(ClientConfigBuilder, ABC): """Allows configuring the environment variables.""" - def get_env(self, uri: Uri) -> Union[Env, None]: + config: BuilderConfig + + def get_env(self, uri: Uri) -> Union[Any, None]: """Return the env for the given uri.""" return self.config.envs.get(uri) - def get_envs(self) -> Dict[Uri, Env]: + def get_envs(self) -> Dict[Uri, Any]: """Return the envs from the builder's config.""" return self.config.envs - def set_env(self, uri: Uri, env: Env) -> ClientConfigBuilder: + def set_env(self, uri: Uri, env: Any) -> ClientConfigBuilder: """Set the env by uri in the builder's config, overiding any existing values.""" self.config.envs[uri] = env return self - def set_envs(self, uri_envs: Dict[Uri, Env]) -> ClientConfigBuilder: + def set_envs(self, uri_envs: Dict[Uri, Any]) -> ClientConfigBuilder: """Set the envs in the builder's config, overiding any existing values.""" self.config.envs.update(uri_envs) return self - def add_env(self, uri: Uri, env: Env) -> ClientConfigBuilder: + def add_env(self, uri: Uri, env: Any) -> ClientConfigBuilder: """Add an env for the given uri. - If an Env is already associated with the uri, it is modified. + If an Any is already associated with the uri, it is modified. """ if self.config.envs.get(uri): for key in self.config.envs[uri]: @@ -39,7 +42,7 @@ def add_env(self, uri: Uri, env: Env) -> ClientConfigBuilder: self.config.envs[uri] = env return self - def add_envs(self, uri_envs: Dict[Uri, Env]) -> ClientConfigBuilder: + def add_envs(self, uri_envs: Dict[Uri, Any]) -> ClientConfigBuilder: """Add a list of envs to the builder's config.""" for uri, env in uri_envs.items(): self.add_env(uri, env) diff --git a/packages/polywrap-client-config-builder/polywrap_client_config_builder/configures/interface_configure.py b/packages/polywrap-client-config-builder/polywrap_client_config_builder/configures/interface_configure.py index 5144a53c..26fc60d3 100644 --- a/packages/polywrap-client-config-builder/polywrap_client_config_builder/configures/interface_configure.py +++ b/packages/polywrap-client-config-builder/polywrap_client_config_builder/configures/interface_configure.py @@ -1,14 +1,17 @@ """This module contains the interface configure class for the client config builder.""" +from abc import ABC from typing import Dict, List, Union from polywrap_core import Uri -from ..types import ClientConfigBuilder +from ..types import BuilderConfig, ClientConfigBuilder -class InterfaceConfigure(ClientConfigBuilder): +class InterfaceConfigure(ClientConfigBuilder, ABC): """Allows configuring the interface-implementations.""" + config: BuilderConfig + def get_interfaces(self) -> Dict[Uri, List[Uri]]: """Return all registered interface and its implementations\ from the builder's config.""" diff --git a/packages/polywrap-client-config-builder/polywrap_client_config_builder/configures/package_configure.py b/packages/polywrap-client-config-builder/polywrap_client_config_builder/configures/package_configure.py index f6c6f832..e8de2f14 100644 --- a/packages/polywrap-client-config-builder/polywrap_client_config_builder/configures/package_configure.py +++ b/packages/polywrap-client-config-builder/polywrap_client_config_builder/configures/package_configure.py @@ -1,32 +1,31 @@ """This module contains the package configure class for the client config builder.""" +from abc import ABC from typing import Dict, List, Union -from polywrap_core import Uri, UriPackageOrWrapper, WrapPackage +from polywrap_core import Uri, WrapPackage -from ..types import ClientConfigBuilder +from ..types import BuilderConfig, ClientConfigBuilder -class PackageConfigure(ClientConfigBuilder): +class PackageConfigure(ClientConfigBuilder, ABC): """Allows configuring the WRAP packages.""" - def get_package(self, uri: Uri) -> Union[WrapPackage[UriPackageOrWrapper], None]: + config: BuilderConfig + + def get_package(self, uri: Uri) -> Union[WrapPackage, None]: """Return the package for the given uri.""" return self.config.packages.get(uri) - def get_packages(self) -> Dict[Uri, WrapPackage[UriPackageOrWrapper]]: + def get_packages(self) -> Dict[Uri, WrapPackage]: """Return the packages from the builder's config.""" return self.config.packages - def set_package( - self, uri: Uri, package: WrapPackage[UriPackageOrWrapper] - ) -> ClientConfigBuilder: + def set_package(self, uri: Uri, package: WrapPackage) -> ClientConfigBuilder: """Set the package by uri in the builder's config, overiding any existing values.""" self.config.packages[uri] = package return self - def set_packages( - self, uri_packages: Dict[Uri, WrapPackage[UriPackageOrWrapper]] - ) -> ClientConfigBuilder: + def set_packages(self, uri_packages: Dict[Uri, WrapPackage]) -> ClientConfigBuilder: """Set the packages in the builder's config, overiding any existing values.""" self.config.packages.update(uri_packages) return self diff --git a/packages/polywrap-client-config-builder/polywrap_client_config_builder/configures/redirect_configure.py b/packages/polywrap-client-config-builder/polywrap_client_config_builder/configures/redirect_configure.py index d143f74e..0b2b5aff 100644 --- a/packages/polywrap-client-config-builder/polywrap_client_config_builder/configures/redirect_configure.py +++ b/packages/polywrap-client-config-builder/polywrap_client_config_builder/configures/redirect_configure.py @@ -1,14 +1,17 @@ """This module contains the redirect configure class for the client config builder.""" +from abc import ABC from typing import Dict, List, Union from polywrap_core import Uri -from ..types import ClientConfigBuilder +from ..types import BuilderConfig, ClientConfigBuilder -class RedirectConfigure(ClientConfigBuilder): +class RedirectConfigure(ClientConfigBuilder, ABC): """Allows configuring the URI redirects.""" + config: BuilderConfig + def get_redirect(self, uri: Uri) -> Union[Uri, None]: """Return the redirect for the given uri.""" return self.config.redirects.get(uri) diff --git a/packages/polywrap-client-config-builder/polywrap_client_config_builder/configures/resolver_configure.py b/packages/polywrap-client-config-builder/polywrap_client_config_builder/configures/resolver_configure.py index 7b0b90ba..8134d81f 100644 --- a/packages/polywrap-client-config-builder/polywrap_client_config_builder/configures/resolver_configure.py +++ b/packages/polywrap-client-config-builder/polywrap_client_config_builder/configures/resolver_configure.py @@ -1,14 +1,17 @@ """This module contains the resolver configure class for the client config builder.""" +from abc import ABC from typing import List from polywrap_core import UriResolver -from ..types import ClientConfigBuilder +from ..types import BuilderConfig, ClientConfigBuilder -class ResolverConfigure(ClientConfigBuilder): +class ResolverConfigure(ClientConfigBuilder, ABC): """Allows configuring the URI resolvers.""" + config: BuilderConfig + def get_resolvers(self) -> List[UriResolver]: """Return the resolvers from the builder's config.""" return self.config.resolvers diff --git a/packages/polywrap-client-config-builder/polywrap_client_config_builder/configures/wrapper_configure.py b/packages/polywrap-client-config-builder/polywrap_client_config_builder/configures/wrapper_configure.py index 90fad354..e0572ce8 100644 --- a/packages/polywrap-client-config-builder/polywrap_client_config_builder/configures/wrapper_configure.py +++ b/packages/polywrap-client-config-builder/polywrap_client_config_builder/configures/wrapper_configure.py @@ -1,32 +1,31 @@ """This module contains the wrapper configure class for the client config builder.""" +from abc import ABC from typing import Dict, List, Union -from polywrap_core import Uri, UriPackageOrWrapper, Wrapper +from polywrap_core import Uri, Wrapper -from ..types import ClientConfigBuilder +from ..types import BuilderConfig, ClientConfigBuilder -class WrapperConfigure(ClientConfigBuilder): +class WrapperConfigure(ClientConfigBuilder, ABC): """Allows configuring the wrappers.""" - def get_wrapper(self, uri: Uri) -> Union[Wrapper[UriPackageOrWrapper], None]: + config: BuilderConfig + + def get_wrapper(self, uri: Uri) -> Union[Wrapper, None]: """Return the set wrapper for the given uri.""" return self.config.wrappers.get(uri) - def get_wrappers(self) -> Dict[Uri, Wrapper[UriPackageOrWrapper]]: + def get_wrappers(self) -> Dict[Uri, Wrapper]: """Return the wrappers from the builder's config.""" return self.config.wrappers - def set_wrapper( - self, uri: Uri, wrapper: Wrapper[UriPackageOrWrapper] - ) -> ClientConfigBuilder: + def set_wrapper(self, uri: Uri, wrapper: Wrapper) -> ClientConfigBuilder: """Set the wrapper by uri in the builder's config, overiding any existing values.""" self.config.wrappers[uri] = wrapper return self - def set_wrappers( - self, uri_wrappers: Dict[Uri, Wrapper[UriPackageOrWrapper]] - ) -> ClientConfigBuilder: + def set_wrappers(self, uri_wrappers: Dict[Uri, Wrapper]) -> ClientConfigBuilder: """Set the wrappers in the builder's config, overiding any existing values.""" self.config.wrappers.update(uri_wrappers) return self diff --git a/packages/polywrap-client-config-builder/polywrap_client_config_builder/polywrap_client_config_builder.py b/packages/polywrap-client-config-builder/polywrap_client_config_builder/polywrap_client_config_builder.py index a155fb7e..7fcdaca6 100644 --- a/packages/polywrap-client-config-builder/polywrap_client_config_builder/polywrap_client_config_builder.py +++ b/packages/polywrap-client-config-builder/polywrap_client_config_builder/polywrap_client_config_builder.py @@ -1,18 +1,17 @@ """This module provides a simple builder for building a ClientConfig object.""" # pylint: disable=too-many-ancestors -from typing import Optional +from typing import Optional, cast -from polywrap_core import ClientConfig +from polywrap_core import ClientConfig, UriPackage, UriWrapper from polywrap_uri_resolvers import ( ExtendableUriResolver, - InMemoryWrapperCache, - PackageToWrapperResolver, + InMemoryResolutionResultCache, RecursiveResolver, - RequestSynchronizerResolver, + ResolutionResultCacheResolver, StaticResolver, + StaticResolverLike, UriResolverAggregator, - WrapperCacheResolver, ) from .configures import ( @@ -51,30 +50,33 @@ def __init__(self): self.config = BuilderConfig( envs={}, interfaces={}, resolvers=[], wrappers={}, packages={}, redirects={} ) + super().__init__() def build(self, options: Optional[BuildOptions] = None) -> ClientConfig: """Build the ClientConfig object from the builder's config.""" + static_resolver_like = cast(StaticResolverLike, self.config.redirects) + + for uri, wrapper in self.config.wrappers.items(): + static_resolver_like[uri] = UriWrapper(uri=uri, wrapper=wrapper) + + for uri, package in self.config.packages.items(): + static_resolver_like[uri] = UriPackage(uri=uri, package=package) + resolver = ( options.resolver if options and options.resolver else RecursiveResolver( - RequestSynchronizerResolver( - WrapperCacheResolver( - PackageToWrapperResolver( - UriResolverAggregator( - [ - StaticResolver(self.config.redirects), - StaticResolver(self.config.wrappers), - StaticResolver(self.config.packages), - *self.config.resolvers, - ExtendableUriResolver(), - ] - ) - ), - options.wrapper_cache - if options and options.wrapper_cache - else InMemoryWrapperCache(), - ) + ResolutionResultCacheResolver( + UriResolverAggregator( + [ + StaticResolver(static_resolver_like), + *self.config.resolvers, + ExtendableUriResolver(), + ] + ), + options.resolution_result_cache + if options and options.resolution_result_cache + else InMemoryResolutionResultCache(), ) ) ) @@ -84,3 +86,6 @@ def build(self, options: Optional[BuildOptions] = None) -> ClientConfig: interfaces=self.config.interfaces, resolver=resolver, ) + + +__all__ = ["PolywrapClientConfigBuilder"] diff --git a/packages/polywrap-client-config-builder/polywrap_client_config_builder/types/build_options.py b/packages/polywrap-client-config-builder/polywrap_client_config_builder/types/build_options.py index 1533c36c..a9ff21a8 100644 --- a/packages/polywrap-client-config-builder/polywrap_client_config_builder/types/build_options.py +++ b/packages/polywrap-client-config-builder/polywrap_client_config_builder/types/build_options.py @@ -3,7 +3,7 @@ from typing import Optional from polywrap_core import UriResolver -from polywrap_uri_resolvers import WrapperCache +from polywrap_uri_resolvers import ResolutionResultCache @dataclass(slots=True, kw_only=True) @@ -11,9 +11,12 @@ class BuildOptions: """BuildOptions defines the options for build method of the client config builder. Attributes: - wrapper_cache: The wrapper cache. + resolution_result_cache: The Resolution Result Cache. resolver: The URI resolver. """ - wrapper_cache: Optional[WrapperCache] = None + resolution_result_cache: Optional[ResolutionResultCache] = None resolver: Optional[UriResolver] = None + + +__all__ = ["BuildOptions"] diff --git a/packages/polywrap-client-config-builder/polywrap_client_config_builder/types/builder_config.py b/packages/polywrap-client-config-builder/polywrap_client_config_builder/types/builder_config.py index 62bba8a3..2e60f279 100644 --- a/packages/polywrap-client-config-builder/polywrap_client_config_builder/types/builder_config.py +++ b/packages/polywrap-client-config-builder/polywrap_client_config_builder/types/builder_config.py @@ -1,15 +1,8 @@ """This module contains the BuilderConfig class.""" from dataclasses import dataclass -from typing import Dict, List +from typing import Any, Dict, List -from polywrap_core import ( - Env, - Uri, - UriPackageOrWrapper, - UriResolver, - WrapPackage, - Wrapper, -) +from polywrap_core import Uri, UriResolver, WrapPackage, Wrapper @dataclass(slots=True, kw_only=True) @@ -17,17 +10,20 @@ class BuilderConfig: """BuilderConfig defines the internal configuration for the client config builder. Attributes: - envs (Dict[Uri, Env]): The environment variables for the wrappers. + envs (Dict[Uri, Any]): The environment variables for the wrappers. interfaces (Dict[Uri, List[Uri]]): The interfaces and their implementations. - wrappers (Dict[Uri, Wrapper[UriPackageOrWrapper]]): The wrappers. - packages (Dict[Uri, WrapPackage[UriPackageOrWrapper]]): The WRAP packages. + wrappers (Dict[Uri, Wrapper]): The wrappers. + packages (Dict[Uri, WrapPackage]): The WRAP packages. resolvers (List[UriResolver]): The URI resolvers. redirects (Dict[Uri, Uri]): The URI redirects. """ - envs: Dict[Uri, Env] + envs: Dict[Uri, Any] interfaces: Dict[Uri, List[Uri]] - wrappers: Dict[Uri, Wrapper[UriPackageOrWrapper]] - packages: Dict[Uri, WrapPackage[UriPackageOrWrapper]] + wrappers: Dict[Uri, Wrapper] + packages: Dict[Uri, WrapPackage] resolvers: List[UriResolver] redirects: Dict[Uri, Uri] + + +__all__ = ["BuilderConfig"] diff --git a/packages/polywrap-client-config-builder/polywrap_client_config_builder/types/client_config_builder.py b/packages/polywrap-client-config-builder/polywrap_client_config_builder/types/client_config_builder.py index d109fce7..bb0bcebd 100644 --- a/packages/polywrap-client-config-builder/polywrap_client_config_builder/types/client_config_builder.py +++ b/packages/polywrap-client-config-builder/polywrap_client_config_builder/types/client_config_builder.py @@ -1,23 +1,15 @@ """This module contains the client config builder class.""" # pylint: disable=too-many-public-methods -from abc import ABC, abstractmethod -from typing import Dict, List, Optional, Union - -from polywrap_core import ( - ClientConfig, - Env, - Uri, - UriPackageOrWrapper, - UriResolver, - WrapPackage, - Wrapper, -) +from abc import abstractmethod +from typing import Any, Dict, List, Optional, Protocol, Union + +from polywrap_core import ClientConfig, Uri, UriResolver, WrapPackage, Wrapper from .build_options import BuildOptions from .builder_config import BuilderConfig -class ClientConfigBuilder(ABC): +class ClientConfigBuilder(Protocol): """Defines the interface for the client config builder.""" config: BuilderConfig @@ -33,30 +25,30 @@ def add(self, config: BuilderConfig) -> "ClientConfigBuilder": # ENV CONFIGURE @abstractmethod - def get_env(self, uri: Uri) -> Union[Env, None]: + def get_env(self, uri: Uri) -> Union[Any, None]: """Return the env for the given uri.""" @abstractmethod - def get_envs(self) -> Dict[Uri, Env]: + def get_envs(self) -> Dict[Uri, Any]: """Return the envs from the builder's config.""" @abstractmethod - def set_env(self, uri: Uri, env: Env) -> "ClientConfigBuilder": + def set_env(self, uri: Uri, env: Any) -> "ClientConfigBuilder": """Set the env by uri in the builder's config, overiding any existing values.""" @abstractmethod - def set_envs(self, uri_envs: Dict[Uri, Env]) -> "ClientConfigBuilder": + def set_envs(self, uri_envs: Dict[Uri, Any]) -> "ClientConfigBuilder": """Set the envs in the builder's config, overiding any existing values.""" @abstractmethod - def add_env(self, uri: Uri, env: Env) -> "ClientConfigBuilder": + def add_env(self, uri: Uri, env: Any) -> "ClientConfigBuilder": """Add an env for the given uri. - If an Env is already associated with the uri, it is modified. + If an Any is already associated with the uri, it is modified. """ @abstractmethod - def add_envs(self, uri_envs: Dict[Uri, Env]) -> "ClientConfigBuilder": + def add_envs(self, uri_envs: Dict[Uri, Any]) -> "ClientConfigBuilder": """Add a list of envs to the builder's config.""" @abstractmethod @@ -96,22 +88,20 @@ def remove_interface(self, interface_uri: Uri) -> "ClientConfigBuilder": # PACKAGE CONFIGURE @abstractmethod - def get_package(self, uri: Uri) -> Union[WrapPackage[UriPackageOrWrapper], None]: + def get_package(self, uri: Uri) -> Union[WrapPackage, None]: """Return the package for the given uri.""" @abstractmethod - def get_packages(self) -> Dict[Uri, WrapPackage[UriPackageOrWrapper]]: + def get_packages(self) -> Dict[Uri, WrapPackage]: """Return the packages from the builder's config.""" @abstractmethod - def set_package( - self, uri: Uri, package: WrapPackage[UriPackageOrWrapper] - ) -> "ClientConfigBuilder": + def set_package(self, uri: Uri, package: WrapPackage) -> "ClientConfigBuilder": """Set the package by uri in the builder's config, overiding any existing values.""" @abstractmethod def set_packages( - self, uri_packages: Dict[Uri, WrapPackage[UriPackageOrWrapper]] + self, uri_packages: Dict[Uri, WrapPackage] ) -> "ClientConfigBuilder": """Set the packages in the builder's config, overiding any existing values.""" @@ -167,23 +157,19 @@ def add_resolvers(self, resolvers_list: List[UriResolver]) -> "ClientConfigBuild # WRAPPER CONFIGURE @abstractmethod - def get_wrapper(self, uri: Uri) -> Union[Wrapper[UriPackageOrWrapper], None]: + def get_wrapper(self, uri: Uri) -> Union[Wrapper, None]: """Return the set wrapper for the given uri.""" @abstractmethod - def get_wrappers(self) -> Dict[Uri, Wrapper[UriPackageOrWrapper]]: + def get_wrappers(self) -> Dict[Uri, Wrapper]: """Return the wrappers from the builder's config.""" @abstractmethod - def set_wrapper( - self, uri: Uri, wrapper: Wrapper[UriPackageOrWrapper] - ) -> "ClientConfigBuilder": + def set_wrapper(self, uri: Uri, wrapper: Wrapper) -> "ClientConfigBuilder": """Set the wrapper by uri in the builder's config, overiding any existing values.""" @abstractmethod - def set_wrappers( - self, uri_wrappers: Dict[Uri, Wrapper[UriPackageOrWrapper]] - ) -> "ClientConfigBuilder": + def set_wrappers(self, uri_wrappers: Dict[Uri, Wrapper]) -> "ClientConfigBuilder": """Set the wrappers in the builder's config, overiding any existing values.""" @abstractmethod @@ -193,3 +179,6 @@ def remove_wrapper(self, uri: Uri) -> "ClientConfigBuilder": @abstractmethod def remove_wrappers(self, uris: List[Uri]) -> "ClientConfigBuilder": """Remove the wrappers for the given uris.""" + + +__all__ = ["ClientConfigBuilder"] From c66bfebf4c885605d55aff4163ddf83acc740929 Mon Sep 17 00:00:00 2001 From: Niraj Kamdar Date: Tue, 6 Jun 2023 03:20:46 +0530 Subject: [PATCH 14/47] fix: typing issue --- .../polywrap-core/polywrap_core/utils/get_implementations.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/polywrap-core/polywrap_core/utils/get_implementations.py b/packages/polywrap-core/polywrap_core/utils/get_implementations.py index e8657129..53c39231 100644 --- a/packages/polywrap-core/polywrap_core/utils/get_implementations.py +++ b/packages/polywrap-core/polywrap_core/utils/get_implementations.py @@ -43,7 +43,7 @@ def get_implementations( interface, client, resolution_context ) if final_current_interface_uri == final_interface_uri: - impls = set(interfaces.get(interface, [])) + impls: Set[Uri] = set(interfaces.get(interface, [])) final_implementations = final_implementations.union(impls) return list(final_implementations) if final_implementations else None From 5147e6a1c29cacdddd8968870ae379e76dee030d Mon Sep 17 00:00:00 2001 From: Niraj Kamdar Date: Thu, 8 Jun 2023 00:36:55 +0530 Subject: [PATCH 15/47] wip: config-builder tests --- .../poetry.lock | 194 ++++++++++++------ .../polywrap_client_config_builder.py | 19 +- .../types/builder_config.py | 14 +- .../pyproject.toml | 3 + .../tests/__init__.py | 0 .../tests/consts.py | 2 + .../tests/strategies.py | 67 ++++++ .../tests/test_add.py | 61 ++++++ .../tests/test_build.py | 121 +++++++++++ .../tests/test_client_config_builder.py | 4 + .../resolvers/package/package_resolver.py | 6 +- 11 files changed, 409 insertions(+), 82 deletions(-) create mode 100644 packages/polywrap-client-config-builder/tests/__init__.py create mode 100644 packages/polywrap-client-config-builder/tests/consts.py create mode 100644 packages/polywrap-client-config-builder/tests/strategies.py create mode 100644 packages/polywrap-client-config-builder/tests/test_add.py create mode 100644 packages/polywrap-client-config-builder/tests/test_build.py diff --git a/packages/polywrap-client-config-builder/poetry.lock b/packages/polywrap-client-config-builder/poetry.lock index 5c7e1f06..4446378c 100644 --- a/packages/polywrap-client-config-builder/poetry.lock +++ b/packages/polywrap-client-config-builder/poetry.lock @@ -1,15 +1,15 @@ -# This file is automatically @generated by Poetry 1.4.2 and should not be changed by hand. +# This file is automatically @generated by Poetry and should not be changed by hand. [[package]] name = "astroid" -version = "2.15.4" +version = "2.15.5" description = "An abstract syntax tree for Python with inference support." category = "dev" optional = false python-versions = ">=3.7.2" files = [ - {file = "astroid-2.15.4-py3-none-any.whl", hash = "sha256:a1b8543ef9d36ea777194bc9b17f5f8678d2c56ee6a45b2c2f17eec96f242347"}, - {file = "astroid-2.15.4.tar.gz", hash = "sha256:c81e1c7fbac615037744d067a9bb5f9aeb655edf59b63ee8b59585475d6f80d8"}, + {file = "astroid-2.15.5-py3-none-any.whl", hash = "sha256:078e5212f9885fa85fbb0cf0101978a336190aadea6e13305409d099f71b2324"}, + {file = "astroid-2.15.5.tar.gz", hash = "sha256:1039262575027b441137ab4a62a793a9b43defb42c32d5670f38686207cd780f"}, ] [package.dependencies] @@ -20,6 +20,25 @@ wrapt = [ {version = ">=1.14,<2", markers = "python_version >= \"3.11\""}, ] +[[package]] +name = "attrs" +version = "23.1.0" +description = "Classes Without Boilerplate" +category = "dev" +optional = false +python-versions = ">=3.7" +files = [ + {file = "attrs-23.1.0-py3-none-any.whl", hash = "sha256:1f28b4522cdc2fb4256ac1a020c78acf9cba2c6b461ccd2c126f3aa8e8335d04"}, + {file = "attrs-23.1.0.tar.gz", hash = "sha256:6279836d581513a26f1bf235f9acd333bc9115683f14f7e8fae46c98fc50e015"}, +] + +[package.extras] +cov = ["attrs[tests]", "coverage[toml] (>=5.3)"] +dev = ["attrs[docs,tests]", "pre-commit"] +docs = ["furo", "myst-parser", "sphinx", "sphinx-notfound-page", "sphinxcontrib-towncrier", "towncrier", "zope-interface"] +tests = ["attrs[tests-no-zope]", "zope-interface"] +tests-no-zope = ["cloudpickle", "hypothesis", "mypy (>=1.1.1)", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "pytest-xdist[psutil]"] + [[package]] name = "bandit" version = "1.7.5" @@ -195,6 +214,39 @@ files = [ [package.dependencies] gitdb = ">=4.0.1,<5" +[[package]] +name = "hypothesis" +version = "6.76.0" +description = "A library for property-based testing" +category = "dev" +optional = false +python-versions = ">=3.7" +files = [ + {file = "hypothesis-6.76.0-py3-none-any.whl", hash = "sha256:034f73dd485933b0f4c319d7c3c58230492fdd7b16e821d67d150a78138adb93"}, + {file = "hypothesis-6.76.0.tar.gz", hash = "sha256:526657eb3e4f2076b0383f722b2e6a92fd15d1d42db532decae8c41b14cab801"}, +] + +[package.dependencies] +attrs = ">=19.2.0" +exceptiongroup = {version = ">=1.0.0", markers = "python_version < \"3.11\""} +sortedcontainers = ">=2.1.0,<3.0.0" + +[package.extras] +all = ["backports.zoneinfo (>=0.2.1)", "black (>=19.10b0)", "click (>=7.0)", "django (>=3.2)", "dpcontracts (>=0.4)", "importlib-metadata (>=3.6)", "lark (>=0.10.1)", "libcst (>=0.3.16)", "numpy (>=1.16.0)", "pandas (>=1.1)", "pytest (>=4.6)", "python-dateutil (>=1.4)", "pytz (>=2014.1)", "redis (>=3.0.0)", "rich (>=9.0.0)", "tzdata (>=2023.3)"] +cli = ["black (>=19.10b0)", "click (>=7.0)", "rich (>=9.0.0)"] +codemods = ["libcst (>=0.3.16)"] +dateutil = ["python-dateutil (>=1.4)"] +django = ["django (>=3.2)"] +dpcontracts = ["dpcontracts (>=0.4)"] +ghostwriter = ["black (>=19.10b0)"] +lark = ["lark (>=0.10.1)"] +numpy = ["numpy (>=1.16.0)"] +pandas = ["pandas (>=1.1)"] +pytest = ["pytest (>=4.6)"] +pytz = ["pytz (>=2014.1)"] +redis = ["redis (>=3.0.0)"] +zoneinfo = ["backports.zoneinfo (>=0.2.1)", "tzdata (>=2023.3)"] + [[package]] name = "iniconfig" version = "2.0.0" @@ -407,14 +459,14 @@ files = [ [[package]] name = "nodeenv" -version = "1.7.0" +version = "1.8.0" description = "Node.js virtual environment builder" category = "dev" optional = false python-versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*" files = [ - {file = "nodeenv-1.7.0-py2.py3-none-any.whl", hash = "sha256:27083a7b96a25f2f5e1d8cb4b6317ee8aeda3bdd121394e5ac54e498028a042e"}, - {file = "nodeenv-1.7.0.tar.gz", hash = "sha256:e0e7f7dfb85fc5394c6fe1e8fa98131a2473e04311a45afb6508f7cf1836fa2b"}, + {file = "nodeenv-1.8.0-py2.py3-none-any.whl", hash = "sha256:df865724bb3c3adc86b3876fa209771517b0cfe596beff01a92700e0e8be4cec"}, + {file = "nodeenv-1.8.0.tar.gz", hash = "sha256:d51e0c37e64fbf47d017feac3145cdbb58836d7eee8c6f6d3b6880c5456227d2"}, ] [package.dependencies] @@ -458,18 +510,18 @@ files = [ [[package]] name = "platformdirs" -version = "3.5.0" +version = "3.5.1" description = "A small Python package for determining appropriate platform-specific dirs, e.g. a \"user data dir\"." category = "dev" optional = false python-versions = ">=3.7" files = [ - {file = "platformdirs-3.5.0-py3-none-any.whl", hash = "sha256:47692bc24c1958e8b0f13dd727307cff1db103fca36399f457da8e05f222fdc4"}, - {file = "platformdirs-3.5.0.tar.gz", hash = "sha256:7954a68d0ba23558d753f73437c55f89027cf8f5108c19844d4b82e5af396335"}, + {file = "platformdirs-3.5.1-py3-none-any.whl", hash = "sha256:e2378146f1964972c03c085bb5662ae80b2b8c06226c54b2ff4aa9483e8a13a5"}, + {file = "platformdirs-3.5.1.tar.gz", hash = "sha256:412dae91f52a6f84830f39a8078cecd0e866cb72294a5c66808e74d5e88d251f"}, ] [package.extras] -docs = ["furo (>=2023.3.27)", "proselint (>=0.13)", "sphinx (>=6.1.3)", "sphinx-autodoc-typehints (>=1.23,!=1.23.4)"] +docs = ["furo (>=2023.3.27)", "proselint (>=0.13)", "sphinx (>=6.2.1)", "sphinx-autodoc-typehints (>=1.23,!=1.23.4)"] test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=7.3.1)", "pytest-cov (>=4)", "pytest-mock (>=3.10)"] [[package]] @@ -595,48 +647,48 @@ files = [ [[package]] name = "pydantic" -version = "1.10.7" +version = "1.10.8" description = "Data validation and settings management using python type hints" category = "main" optional = false python-versions = ">=3.7" files = [ - {file = "pydantic-1.10.7-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e79e999e539872e903767c417c897e729e015872040e56b96e67968c3b918b2d"}, - {file = "pydantic-1.10.7-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:01aea3a42c13f2602b7ecbbea484a98169fb568ebd9e247593ea05f01b884b2e"}, - {file = "pydantic-1.10.7-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:516f1ed9bc2406a0467dd777afc636c7091d71f214d5e413d64fef45174cfc7a"}, - {file = "pydantic-1.10.7-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ae150a63564929c675d7f2303008d88426a0add46efd76c3fc797cd71cb1b46f"}, - {file = "pydantic-1.10.7-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:ecbbc51391248116c0a055899e6c3e7ffbb11fb5e2a4cd6f2d0b93272118a209"}, - {file = "pydantic-1.10.7-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:f4a2b50e2b03d5776e7f21af73e2070e1b5c0d0df255a827e7c632962f8315af"}, - {file = "pydantic-1.10.7-cp310-cp310-win_amd64.whl", hash = "sha256:a7cd2251439988b413cb0a985c4ed82b6c6aac382dbaff53ae03c4b23a70e80a"}, - {file = "pydantic-1.10.7-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:68792151e174a4aa9e9fc1b4e653e65a354a2fa0fed169f7b3d09902ad2cb6f1"}, - {file = "pydantic-1.10.7-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:dfe2507b8ef209da71b6fb5f4e597b50c5a34b78d7e857c4f8f3115effaef5fe"}, - {file = "pydantic-1.10.7-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:10a86d8c8db68086f1e30a530f7d5f83eb0685e632e411dbbcf2d5c0150e8dcd"}, - {file = "pydantic-1.10.7-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d75ae19d2a3dbb146b6f324031c24f8a3f52ff5d6a9f22f0683694b3afcb16fb"}, - {file = "pydantic-1.10.7-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:464855a7ff7f2cc2cf537ecc421291b9132aa9c79aef44e917ad711b4a93163b"}, - {file = "pydantic-1.10.7-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:193924c563fae6ddcb71d3f06fa153866423ac1b793a47936656e806b64e24ca"}, - {file = "pydantic-1.10.7-cp311-cp311-win_amd64.whl", hash = "sha256:b4a849d10f211389502059c33332e91327bc154acc1845f375a99eca3afa802d"}, - {file = "pydantic-1.10.7-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:cc1dde4e50a5fc1336ee0581c1612215bc64ed6d28d2c7c6f25d2fe3e7c3e918"}, - {file = "pydantic-1.10.7-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e0cfe895a504c060e5d36b287ee696e2fdad02d89e0d895f83037245218a87fe"}, - {file = "pydantic-1.10.7-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:670bb4683ad1e48b0ecb06f0cfe2178dcf74ff27921cdf1606e527d2617a81ee"}, - {file = "pydantic-1.10.7-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:950ce33857841f9a337ce07ddf46bc84e1c4946d2a3bba18f8280297157a3fd1"}, - {file = "pydantic-1.10.7-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:c15582f9055fbc1bfe50266a19771bbbef33dd28c45e78afbe1996fd70966c2a"}, - {file = "pydantic-1.10.7-cp37-cp37m-win_amd64.whl", hash = "sha256:82dffb306dd20bd5268fd6379bc4bfe75242a9c2b79fec58e1041fbbdb1f7914"}, - {file = "pydantic-1.10.7-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:8c7f51861d73e8b9ddcb9916ae7ac39fb52761d9ea0df41128e81e2ba42886cd"}, - {file = "pydantic-1.10.7-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:6434b49c0b03a51021ade5c4daa7d70c98f7a79e95b551201fff682fc1661245"}, - {file = "pydantic-1.10.7-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:64d34ab766fa056df49013bb6e79921a0265204c071984e75a09cbceacbbdd5d"}, - {file = "pydantic-1.10.7-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:701daea9ffe9d26f97b52f1d157e0d4121644f0fcf80b443248434958fd03dc3"}, - {file = "pydantic-1.10.7-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:cf135c46099ff3f919d2150a948ce94b9ce545598ef2c6c7bf55dca98a304b52"}, - {file = "pydantic-1.10.7-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:b0f85904f73161817b80781cc150f8b906d521fa11e3cdabae19a581c3606209"}, - {file = "pydantic-1.10.7-cp38-cp38-win_amd64.whl", hash = "sha256:9f6f0fd68d73257ad6685419478c5aece46432f4bdd8d32c7345f1986496171e"}, - {file = "pydantic-1.10.7-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:c230c0d8a322276d6e7b88c3f7ce885f9ed16e0910354510e0bae84d54991143"}, - {file = "pydantic-1.10.7-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:976cae77ba6a49d80f461fd8bba183ff7ba79f44aa5cfa82f1346b5626542f8e"}, - {file = "pydantic-1.10.7-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7d45fc99d64af9aaf7e308054a0067fdcd87ffe974f2442312372dfa66e1001d"}, - {file = "pydantic-1.10.7-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d2a5ebb48958754d386195fe9e9c5106f11275867051bf017a8059410e9abf1f"}, - {file = "pydantic-1.10.7-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:abfb7d4a7cd5cc4e1d1887c43503a7c5dd608eadf8bc615413fc498d3e4645cd"}, - {file = "pydantic-1.10.7-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:80b1fab4deb08a8292d15e43a6edccdffa5377a36a4597bb545b93e79c5ff0a5"}, - {file = "pydantic-1.10.7-cp39-cp39-win_amd64.whl", hash = "sha256:d71e69699498b020ea198468e2480a2f1e7433e32a3a99760058c6520e2bea7e"}, - {file = "pydantic-1.10.7-py3-none-any.whl", hash = "sha256:0cd181f1d0b1d00e2b705f1bf1ac7799a2d938cce3376b8007df62b29be3c2c6"}, - {file = "pydantic-1.10.7.tar.gz", hash = "sha256:cfc83c0678b6ba51b0532bea66860617c4cd4251ecf76e9846fa5a9f3454e97e"}, + {file = "pydantic-1.10.8-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:1243d28e9b05003a89d72e7915fdb26ffd1d39bdd39b00b7dbe4afae4b557f9d"}, + {file = "pydantic-1.10.8-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c0ab53b609c11dfc0c060d94335993cc2b95b2150e25583bec37a49b2d6c6c3f"}, + {file = "pydantic-1.10.8-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f9613fadad06b4f3bc5db2653ce2f22e0de84a7c6c293909b48f6ed37b83c61f"}, + {file = "pydantic-1.10.8-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:df7800cb1984d8f6e249351139667a8c50a379009271ee6236138a22a0c0f319"}, + {file = "pydantic-1.10.8-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:0c6fafa0965b539d7aab0a673a046466d23b86e4b0e8019d25fd53f4df62c277"}, + {file = "pydantic-1.10.8-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:e82d4566fcd527eae8b244fa952d99f2ca3172b7e97add0b43e2d97ee77f81ab"}, + {file = "pydantic-1.10.8-cp310-cp310-win_amd64.whl", hash = "sha256:ab523c31e22943713d80d8d342d23b6f6ac4b792a1e54064a8d0cf78fd64e800"}, + {file = "pydantic-1.10.8-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:666bdf6066bf6dbc107b30d034615d2627e2121506c555f73f90b54a463d1f33"}, + {file = "pydantic-1.10.8-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:35db5301b82e8661fa9c505c800d0990bc14e9f36f98932bb1d248c0ac5cada5"}, + {file = "pydantic-1.10.8-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f90c1e29f447557e9e26afb1c4dbf8768a10cc676e3781b6a577841ade126b85"}, + {file = "pydantic-1.10.8-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:93e766b4a8226e0708ef243e843105bf124e21331694367f95f4e3b4a92bbb3f"}, + {file = "pydantic-1.10.8-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:88f195f582851e8db960b4a94c3e3ad25692c1c1539e2552f3df7a9e972ef60e"}, + {file = "pydantic-1.10.8-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:34d327c81e68a1ecb52fe9c8d50c8a9b3e90d3c8ad991bfc8f953fb477d42fb4"}, + {file = "pydantic-1.10.8-cp311-cp311-win_amd64.whl", hash = "sha256:d532bf00f381bd6bc62cabc7d1372096b75a33bc197a312b03f5838b4fb84edd"}, + {file = "pydantic-1.10.8-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:7d5b8641c24886d764a74ec541d2fc2c7fb19f6da2a4001e6d580ba4a38f7878"}, + {file = "pydantic-1.10.8-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7b1f6cb446470b7ddf86c2e57cd119a24959af2b01e552f60705910663af09a4"}, + {file = "pydantic-1.10.8-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c33b60054b2136aef8cf190cd4c52a3daa20b2263917c49adad20eaf381e823b"}, + {file = "pydantic-1.10.8-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:1952526ba40b220b912cdc43c1c32bcf4a58e3f192fa313ee665916b26befb68"}, + {file = "pydantic-1.10.8-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:bb14388ec45a7a0dc429e87def6396f9e73c8c77818c927b6a60706603d5f2ea"}, + {file = "pydantic-1.10.8-cp37-cp37m-win_amd64.whl", hash = "sha256:16f8c3e33af1e9bb16c7a91fc7d5fa9fe27298e9f299cff6cb744d89d573d62c"}, + {file = "pydantic-1.10.8-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:1ced8375969673929809d7f36ad322934c35de4af3b5e5b09ec967c21f9f7887"}, + {file = "pydantic-1.10.8-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:93e6bcfccbd831894a6a434b0aeb1947f9e70b7468f274154d03d71fabb1d7c6"}, + {file = "pydantic-1.10.8-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:191ba419b605f897ede9892f6c56fb182f40a15d309ef0142212200a10af4c18"}, + {file = "pydantic-1.10.8-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:052d8654cb65174d6f9490cc9b9a200083a82cf5c3c5d3985db765757eb3b375"}, + {file = "pydantic-1.10.8-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:ceb6a23bf1ba4b837d0cfe378329ad3f351b5897c8d4914ce95b85fba96da5a1"}, + {file = "pydantic-1.10.8-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:6f2e754d5566f050954727c77f094e01793bcb5725b663bf628fa6743a5a9108"}, + {file = "pydantic-1.10.8-cp38-cp38-win_amd64.whl", hash = "sha256:6a82d6cda82258efca32b40040228ecf43a548671cb174a1e81477195ed3ed56"}, + {file = "pydantic-1.10.8-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:3e59417ba8a17265e632af99cc5f35ec309de5980c440c255ab1ca3ae96a3e0e"}, + {file = "pydantic-1.10.8-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:84d80219c3f8d4cad44575e18404099c76851bc924ce5ab1c4c8bb5e2a2227d0"}, + {file = "pydantic-1.10.8-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2e4148e635994d57d834be1182a44bdb07dd867fa3c2d1b37002000646cc5459"}, + {file = "pydantic-1.10.8-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:12f7b0bf8553e310e530e9f3a2f5734c68699f42218bf3568ef49cd9b0e44df4"}, + {file = "pydantic-1.10.8-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:42aa0c4b5c3025483240a25b09f3c09a189481ddda2ea3a831a9d25f444e03c1"}, + {file = "pydantic-1.10.8-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:17aef11cc1b997f9d574b91909fed40761e13fac438d72b81f902226a69dac01"}, + {file = "pydantic-1.10.8-cp39-cp39-win_amd64.whl", hash = "sha256:66a703d1983c675a6e0fed8953b0971c44dba48a929a2000a493c3772eb61a5a"}, + {file = "pydantic-1.10.8-py3-none-any.whl", hash = "sha256:7456eb22ed9aaa24ff3e7b4757da20d9e5ce2a81018c1b3ebd81a0b88a18f3b2"}, + {file = "pydantic-1.10.8.tar.gz", hash = "sha256:1410275520dfa70effadf4c21811d755e7ef9bb1f1d077a21958153a92c8d9ca"}, ] [package.dependencies] @@ -710,14 +762,14 @@ testutils = ["gitpython (>3)"] [[package]] name = "pyright" -version = "1.1.306" +version = "1.1.311" description = "Command line wrapper for pyright" category = "dev" optional = false python-versions = ">=3.7" files = [ - {file = "pyright-1.1.306-py3-none-any.whl", hash = "sha256:008eb2a29584ae274a154d749cf81476a3073fb562a462eac8d43a753378b9db"}, - {file = "pyright-1.1.306.tar.gz", hash = "sha256:16d5d198be64de497d5f9002000a271176c381e21b977ca5566cf779b643c9ed"}, + {file = "pyright-1.1.311-py3-none-any.whl", hash = "sha256:04df30c6b31d05068effe5563411291c876f5e4221d0af225a267b61dce1ca85"}, + {file = "pyright-1.1.311.tar.gz", hash = "sha256:554b555d3f770e8da2e76d6bb94e2ac63b3edc7dcd5fb8de202f9dd53e36689a"}, ] [package.dependencies] @@ -820,14 +872,14 @@ files = [ [[package]] name = "rich" -version = "13.3.5" +version = "13.4.1" description = "Render rich text, tables, progress bars, syntax highlighting, markdown and more to the terminal" category = "dev" optional = false python-versions = ">=3.7.0" files = [ - {file = "rich-13.3.5-py3-none-any.whl", hash = "sha256:69cdf53799e63f38b95b9bf9c875f8c90e78dd62b2f00c13a911c7a3b9fa4704"}, - {file = "rich-13.3.5.tar.gz", hash = "sha256:2d11b9b8dd03868f09b4fffadc84a6a8cda574e40dc90821bd845720ebb8e89c"}, + {file = "rich-13.4.1-py3-none-any.whl", hash = "sha256:d204aadb50b936bf6b1a695385429d192bc1fdaf3e8b907e8e26f4c4e4b5bf75"}, + {file = "rich-13.4.1.tar.gz", hash = "sha256:76f6b65ea7e5c5d924ba80e322231d7cb5b5981aa60bfc1e694f1bc097fe6fe1"}, ] [package.dependencies] @@ -839,19 +891,19 @@ jupyter = ["ipywidgets (>=7.5.1,<9)"] [[package]] name = "setuptools" -version = "67.7.2" +version = "67.8.0" description = "Easily download, build, install, upgrade, and uninstall Python packages" category = "dev" optional = false python-versions = ">=3.7" files = [ - {file = "setuptools-67.7.2-py3-none-any.whl", hash = "sha256:23aaf86b85ca52ceb801d32703f12d77517b2556af839621c641fca11287952b"}, - {file = "setuptools-67.7.2.tar.gz", hash = "sha256:f104fa03692a2602fa0fec6c6a9e63b6c8a968de13e17c026957dd1f53d80990"}, + {file = "setuptools-67.8.0-py3-none-any.whl", hash = "sha256:5df61bf30bb10c6f756eb19e7c9f3b473051f48db77fddbe06ff2ca307df9a6f"}, + {file = "setuptools-67.8.0.tar.gz", hash = "sha256:62642358adc77ffa87233bc4d2354c4b2682d214048f500964dbe760ccedf102"}, ] [package.extras] docs = ["furo", "jaraco.packaging (>=9)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-favicon", "sphinx-hoverxref (<2)", "sphinx-inline-tabs", "sphinx-lint", "sphinx-notfound-page (==0.8.3)", "sphinx-reredirects", "sphinxcontrib-towncrier"] -testing = ["build[virtualenv]", "filelock (>=3.4.0)", "flake8 (<5)", "flake8-2020", "ini2toml[lite] (>=0.9)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "pip (>=19.1)", "pip-run (>=8.8)", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=1.3)", "pytest-flake8", "pytest-mypy (>=0.9.1)", "pytest-perf", "pytest-timeout", "pytest-xdist", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel"] +testing = ["build[virtualenv]", "filelock (>=3.4.0)", "flake8-2020", "ini2toml[lite] (>=0.9)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "pip (>=19.1)", "pip-run (>=8.8)", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=1.3)", "pytest-mypy (>=0.9.1)", "pytest-perf", "pytest-ruff", "pytest-timeout", "pytest-xdist", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel"] testing-integration = ["build[virtualenv]", "filelock (>=3.4.0)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "pytest", "pytest-enabler", "pytest-xdist", "tomli", "virtualenv (>=13.0.0)", "wheel"] [[package]] @@ -890,16 +942,28 @@ files = [ {file = "snowballstemmer-2.2.0.tar.gz", hash = "sha256:09b16deb8547d3412ad7b590689584cd0fe25ec8db3be37788be3810cbf19cb1"}, ] +[[package]] +name = "sortedcontainers" +version = "2.4.0" +description = "Sorted Containers -- Sorted List, Sorted Dict, Sorted Set" +category = "dev" +optional = false +python-versions = "*" +files = [ + {file = "sortedcontainers-2.4.0-py2.py3-none-any.whl", hash = "sha256:a163dcaede0f1c021485e957a39245190e74249897e2ae4b2aa38595db237ee0"}, + {file = "sortedcontainers-2.4.0.tar.gz", hash = "sha256:25caa5a06cc30b6b83d11423433f65d1f9d76c4c6a0c90e3379eaa43b9bfdb88"}, +] + [[package]] name = "stevedore" -version = "5.0.0" +version = "5.1.0" description = "Manage dynamic plugins for Python applications" category = "dev" optional = false python-versions = ">=3.8" files = [ - {file = "stevedore-5.0.0-py3-none-any.whl", hash = "sha256:bd5a71ff5e5e5f5ea983880e4a1dd1bb47f8feebbb3d95b592398e2f02194771"}, - {file = "stevedore-5.0.0.tar.gz", hash = "sha256:2c428d2338976279e8eb2196f7a94910960d9f7ba2f41f3988511e95ca447021"}, + {file = "stevedore-5.1.0-py3-none-any.whl", hash = "sha256:8cc040628f3cea5d7128f2e76cf486b2251a4e543c7b938f58d9a377f6694a2d"}, + {file = "stevedore-5.1.0.tar.gz", hash = "sha256:a54534acf9b89bc7ed264807013b505bf07f74dbe4bcfa37d32bd063870b087c"}, ] [package.dependencies] @@ -989,14 +1053,14 @@ test = ["coverage", "pycodestyle", "pylint", "pytest"] [[package]] name = "typing-extensions" -version = "4.5.0" +version = "4.6.3" description = "Backported and Experimental Type Hints for Python 3.7+" category = "main" optional = false python-versions = ">=3.7" files = [ - {file = "typing_extensions-4.5.0-py3-none-any.whl", hash = "sha256:fb33085c39dd998ac16d1431ebc293a8b3eedd00fd4a32de0ff79002c19511b4"}, - {file = "typing_extensions-4.5.0.tar.gz", hash = "sha256:5cb5f4a79139d699607b3ef622a1dedafa84e115ab0024e0d9c044a9479ca7cb"}, + {file = "typing_extensions-4.6.3-py3-none-any.whl", hash = "sha256:88a4153d8505aabbb4e13aacb7c486c2b4a33ca3b3f807914a9b4c844c471c26"}, + {file = "typing_extensions-4.6.3.tar.gz", hash = "sha256:d91d5919357fe7f681a9f2b5b4cb2a5f1ef0a1e9f59c4d8ff0d3491e05c0ffd5"}, ] [[package]] @@ -1150,4 +1214,4 @@ files = [ [metadata] lock-version = "2.0" python-versions = "^3.10" -content-hash = "af1d9b727002057dee7ece1fa89fbeb5810309387c53f9fdc3ef38f778755dee" +content-hash = "4c83da528593354cc45f8379300b60bdd5322f1507ce0e1d8c4a8c3329e003c2" diff --git a/packages/polywrap-client-config-builder/polywrap_client_config_builder/polywrap_client_config_builder.py b/packages/polywrap-client-config-builder/polywrap_client_config_builder/polywrap_client_config_builder.py index 7fcdaca6..d392c0fc 100644 --- a/packages/polywrap-client-config-builder/polywrap_client_config_builder/polywrap_client_config_builder.py +++ b/packages/polywrap-client-config-builder/polywrap_client_config_builder/polywrap_client_config_builder.py @@ -54,13 +54,7 @@ def __init__(self): def build(self, options: Optional[BuildOptions] = None) -> ClientConfig: """Build the ClientConfig object from the builder's config.""" - static_resolver_like = cast(StaticResolverLike, self.config.redirects) - - for uri, wrapper in self.config.wrappers.items(): - static_resolver_like[uri] = UriWrapper(uri=uri, wrapper=wrapper) - - for uri, package in self.config.packages.items(): - static_resolver_like[uri] = UriPackage(uri=uri, package=package) + static_resolver_like = self._build_static_resolver_like() resolver = ( options.resolver @@ -87,5 +81,16 @@ def build(self, options: Optional[BuildOptions] = None) -> ClientConfig: resolver=resolver, ) + def _build_static_resolver_like(self) -> StaticResolverLike: + static_resolver_like = cast(StaticResolverLike, self.config.redirects) + + for uri, wrapper in self.config.wrappers.items(): + static_resolver_like[uri] = UriWrapper(uri=uri, wrapper=wrapper) + + for uri, package in self.config.packages.items(): + static_resolver_like[uri] = UriPackage(uri=uri, package=package) + + return static_resolver_like + __all__ = ["PolywrapClientConfigBuilder"] diff --git a/packages/polywrap-client-config-builder/polywrap_client_config_builder/types/builder_config.py b/packages/polywrap-client-config-builder/polywrap_client_config_builder/types/builder_config.py index 2e60f279..d94ac526 100644 --- a/packages/polywrap-client-config-builder/polywrap_client_config_builder/types/builder_config.py +++ b/packages/polywrap-client-config-builder/polywrap_client_config_builder/types/builder_config.py @@ -1,5 +1,5 @@ """This module contains the BuilderConfig class.""" -from dataclasses import dataclass +from dataclasses import dataclass, field from typing import Any, Dict, List from polywrap_core import Uri, UriResolver, WrapPackage, Wrapper @@ -18,12 +18,12 @@ class BuilderConfig: redirects (Dict[Uri, Uri]): The URI redirects. """ - envs: Dict[Uri, Any] - interfaces: Dict[Uri, List[Uri]] - wrappers: Dict[Uri, Wrapper] - packages: Dict[Uri, WrapPackage] - resolvers: List[UriResolver] - redirects: Dict[Uri, Uri] + envs: Dict[Uri, Any] = field(default_factory=dict) + interfaces: Dict[Uri, List[Uri]] = field(default_factory=dict) + wrappers: Dict[Uri, Wrapper] = field(default_factory=dict) + packages: Dict[Uri, WrapPackage] = field(default_factory=dict) + resolvers: List[UriResolver] = field(default_factory=list) + redirects: Dict[Uri, Uri] = field(default_factory=dict) __all__ = ["BuilderConfig"] diff --git a/packages/polywrap-client-config-builder/pyproject.toml b/packages/polywrap-client-config-builder/pyproject.toml index 26f33b82..59bbc3d0 100644 --- a/packages/polywrap-client-config-builder/pyproject.toml +++ b/packages/polywrap-client-config-builder/pyproject.toml @@ -25,6 +25,9 @@ isort = "^5.10.1" pyright = "^1.1.275" pydocstyle = "^6.1.1" +[tool.poetry.group.dev.dependencies] +hypothesis = "^6.76.0" + [tool.bandit] exclude_dirs = ["tests"] diff --git a/packages/polywrap-client-config-builder/tests/__init__.py b/packages/polywrap-client-config-builder/tests/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/packages/polywrap-client-config-builder/tests/consts.py b/packages/polywrap-client-config-builder/tests/consts.py new file mode 100644 index 00000000..24e79cc8 --- /dev/null +++ b/packages/polywrap-client-config-builder/tests/consts.py @@ -0,0 +1,2 @@ +C_LONG_MIN = -9223372036854775808 +C_LONG_MAX = 9223372036854775807 diff --git a/packages/polywrap-client-config-builder/tests/strategies.py b/packages/polywrap-client-config-builder/tests/strategies.py new file mode 100644 index 00000000..3c97bf5f --- /dev/null +++ b/packages/polywrap-client-config-builder/tests/strategies.py @@ -0,0 +1,67 @@ +from polywrap_core import Uri, UriResolver, WrapPackage, Wrapper +from hypothesis import strategies as st +from unittest.mock import Mock + +from polywrap_client_config_builder import BuilderConfig + +from .consts import C_LONG_MAX, C_LONG_MIN + +# List of Mock resolvers +MockResolvers = [Mock(UriResolver, name=f"MockResolver{i}") for i in range(10)] + +# List of Mock wrappers +MockWrappers = [Mock(Wrapper, name=f"MockWrapper{i}") for i in range(10)] + +# List of Mock packages +MockPackages = [Mock(WrapPackage, name=f"MockPackage{i}") for i in range(10)] + +# Scalars +scalar_st_list = [ + st.none(), + st.booleans(), + st.integers(min_value=C_LONG_MIN, max_value=C_LONG_MAX), + st.floats(allow_nan=False), + st.text(), + st.binary(), +] + +# Uri +uri_safe_chars_strategy = st.text( + alphabet=st.characters(whitelist_categories="L", whitelist_characters="-._~") +) +uri_strategy = st.builds(Uri, uri_safe_chars_strategy, uri_safe_chars_strategy) + +# Env +env_strategy = st.dictionaries(st.text(), st.one_of(scalar_st_list)) +envs_strategy = st.dictionaries( + uri_strategy, env_strategy +) + +# Interface Implementations +interfaces_strategy = st.dictionaries(uri_strategy, st.lists(uri_strategy)) + +# URI Redirects +redirects_strategy = st.dictionaries(uri_strategy, uri_strategy) + +# Resolver +resolver_strategy = st.sampled_from(MockResolvers) +resolvers_strategy = st.lists(resolver_strategy) + +# Wrapper +wrapper_strategy = st.sampled_from(MockWrappers) +wrappers_strategy = st.dictionaries(uri_strategy, wrapper_strategy) + +# Packages +package_strategy = st.sampled_from(MockPackages) +packages_strategy = st.dictionaries(uri_strategy, package_strategy) + +# builder config +builder_config_strategy = st.builds( + BuilderConfig, + envs=envs_strategy, + interfaces=interfaces_strategy, + wrappers=wrappers_strategy, + packages=packages_strategy, + resolvers=resolvers_strategy, + redirects=redirects_strategy, +) diff --git a/packages/polywrap-client-config-builder/tests/test_add.py b/packages/polywrap-client-config-builder/tests/test_add.py new file mode 100644 index 00000000..d0ca5951 --- /dev/null +++ b/packages/polywrap-client-config-builder/tests/test_add.py @@ -0,0 +1,61 @@ +from typing import List +from hypothesis import given, settings, strategies as st + +from polywrap_client_config_builder import ( + BuilderConfig, + ClientConfigBuilder, + PolywrapClientConfigBuilder, +) + +from .strategies import builder_config_strategy + + +@settings(max_examples=100) +@given(config=builder_config_strategy) +def test_add_builder_config( + config: BuilderConfig, +): + builder: ClientConfigBuilder = PolywrapClientConfigBuilder() + builder = builder.add(config) + assert builder.config.envs == config.envs + assert builder.config.interfaces == config.interfaces + assert builder.config.redirects == config.redirects + assert builder.config.resolvers == config.resolvers + assert builder.config.wrappers == config.wrappers + assert builder.config.packages == config.packages + + +@settings(max_examples=10) +@given(configs=st.lists(builder_config_strategy, max_size=10)) +def test_add_multiple_builder_config(configs: List[BuilderConfig]): + builder: ClientConfigBuilder = PolywrapClientConfigBuilder() + expected_config = BuilderConfig() + + for config in configs: + builder = builder.add(config) + expected_config.envs.update(config.envs) + expected_config.interfaces.update(config.interfaces) + expected_config.packages.update(config.packages) + expected_config.wrappers.update(config.wrappers) + expected_config.redirects.update(config.redirects) + expected_config.resolvers.extend(config.resolvers) + + assert builder.config == expected_config + + assert builder.config == expected_config + + +@settings(max_examples=100) +@given(config=builder_config_strategy) +def test_add_builder_config_with_duplicate_data( + config: BuilderConfig, +): + builder: ClientConfigBuilder = PolywrapClientConfigBuilder() + builder = builder.add(config) + builder = builder.add(config) + assert builder.config.envs == config.envs + assert builder.config.interfaces == config.interfaces + assert builder.config.redirects == config.redirects + assert len(builder.config.resolvers) == 2 * len(config.resolvers) + assert builder.config.wrappers == config.wrappers + assert builder.config.packages == config.packages diff --git a/packages/polywrap-client-config-builder/tests/test_build.py b/packages/polywrap-client-config-builder/tests/test_build.py new file mode 100644 index 00000000..783848ca --- /dev/null +++ b/packages/polywrap-client-config-builder/tests/test_build.py @@ -0,0 +1,121 @@ +from typing import Dict, cast +from unittest.mock import patch +from polywrap_uri_resolvers import ( + PackageResolver, + RecursiveResolver, + StaticResolver, + UriResolverAggregator, + ResolutionResultCacheResolver, + ExtendableUriResolver, + InMemoryResolutionResultCache, +) +from polywrap_client_config_builder import ( + BuildOptions, + PolywrapClientConfigBuilder, +) +from polywrap_core import Uri, UriPackage, UriWrapper, WrapPackage, Wrapper +import pytest + + +@pytest.fixture +def builder() -> PolywrapClientConfigBuilder: + """Return a PolywrapClientConfigBuilder with a default config.""" + return PolywrapClientConfigBuilder() + + +def test_build_resolver_order(builder: PolywrapClientConfigBuilder): + """Test the order of resolvers in UriResolverAggregator.""" + redirects: Dict[Uri, Uri] = {Uri.from_str("test/1"): Uri.from_str("test/2")} + builder.config.redirects = redirects + + config = builder.build() + + isinstance(config.resolver, RecursiveResolver) + recursive_resolver = cast(RecursiveResolver, config.resolver) + + isinstance(recursive_resolver.resolver, ResolutionResultCacheResolver) + cache_resolver = cast(ResolutionResultCacheResolver, recursive_resolver.resolver) + + isinstance(cache_resolver.resolver_to_cache, UriResolverAggregator) + aggregator_resolver = cast(UriResolverAggregator, cache_resolver.resolver_to_cache) + + aggregated_resolvers = aggregator_resolver._resolvers # type: ignore + assert isinstance(aggregated_resolvers[0], StaticResolver) + assert isinstance(aggregated_resolvers[1], ExtendableUriResolver) + + +def test_no_build_options(builder: PolywrapClientConfigBuilder): + """Test the absence of resolver in BuildOptions.""" + config = builder.build() + assert isinstance(config.resolver, RecursiveResolver) + + +def test_build_options_resolver(builder: PolywrapClientConfigBuilder): + """Test the presence of resolver in BuildOptions overrides the default one.""" + redirects: Dict[Uri, Uri] = {Uri.from_str("test/1"): Uri.from_str("test/2")} + builder.config.redirects = redirects + + config = builder.build( + BuildOptions( + resolver=PackageResolver( + uri=Uri.from_str("test/package"), package=NotImplemented + ) + ) + ) + + assert isinstance(config.resolver, PackageResolver) + + +def test_build_options_cache(builder: PolywrapClientConfigBuilder): + """Test the presence of cache in BuildOptions overrides the default one.""" + custom_cache = InMemoryResolutionResultCache() + config = builder.build(BuildOptions(resolution_result_cache=custom_cache)) + assert isinstance(config.resolver, RecursiveResolver) + assert isinstance(config.resolver.resolver, ResolutionResultCacheResolver) + + assert config.resolver.resolver.cache is custom_cache + + +def test_build_static_resolver_like(builder: PolywrapClientConfigBuilder): + """Test the composition of StaticResolverLike.""" + redirects: Dict[Uri, Uri] = {Uri.from_str("test/from"): Uri.from_str("test/to")} + builder.config.redirects = redirects + + with patch("polywrap_core.types.wrapper.Wrapper") as MockWrapper, patch( + "polywrap_core.types.wrap_package.WrapPackage" + ) as MockPackage: + + wrappers: Dict[Uri, Wrapper] = {Uri.from_str("test/wrapper"): MockWrapper} + builder.config.wrappers = wrappers + + packages: Dict[Uri, WrapPackage] = {Uri.from_str("test/package"): MockPackage} + builder.config.packages = packages + + static_resolver_like = builder._build_static_resolver_like() # type: ignore + + assert static_resolver_like[Uri.from_str("test/from")] == Uri.from_str( + "test/to" + ) + assert static_resolver_like[Uri.from_str("test/wrapper")] == UriWrapper( + uri=Uri.from_str("test/wrapper"), wrapper=MockWrapper + ) + assert static_resolver_like[Uri.from_str("test/package")] == UriPackage( + uri=Uri.from_str("test/package"), package=MockPackage + ) + + +def test_build_client_config_attributes(builder: PolywrapClientConfigBuilder): + """Test the attributes of ClientConfig.""" + envs = {Uri("test", "env1"): "test", Uri("test", "env2"): "test"} + builder.config.envs = envs + + interfaces = { + Uri("test", "interface1"): [Uri("test", "impl1"), Uri("test", "impl2")], + Uri("test", "interface2"): [Uri("test", "impl3")], + } + builder.config.interfaces = interfaces + + config = builder.build() + + assert config.envs is envs + assert config.interfaces is interfaces diff --git a/packages/polywrap-client-config-builder/tests/test_client_config_builder.py b/packages/polywrap-client-config-builder/tests/test_client_config_builder.py index 9c8ae684..e8b2f4a3 100644 --- a/packages/polywrap-client-config-builder/tests/test_client_config_builder.py +++ b/packages/polywrap-client-config-builder/tests/test_client_config_builder.py @@ -1,3 +1,7 @@ +# TODO: ccb test -> post-cd fix -> release -> plugin update -> default ccb + + + # """ # Polywrap Python Client. diff --git a/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/resolvers/package/package_resolver.py b/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/resolvers/package/package_resolver.py index c25623c0..496aa659 100644 --- a/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/resolvers/package/package_resolver.py +++ b/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/resolvers/package/package_resolver.py @@ -19,15 +19,15 @@ class PackageResolver(ResolverWithHistory): uri: Uri package: WrapPackage - def __init__(self, uri: Uri, wrap_package: WrapPackage): + def __init__(self, uri: Uri, package: WrapPackage): """Initialize a new PackageResolver instance. Args: uri (Uri): The uri to resolve. - wrap_package (WrapPackage): The wrap package to return. + package (WrapPackage): The wrap package to return. """ self.uri = uri - self.package = wrap_package + self.package = package super().__init__() def get_step_description(self) -> str: From b885018ce1060e4883d760d2283ef89e59744a13 Mon Sep 17 00:00:00 2001 From: Niraj Kamdar Date: Thu, 8 Jun 2023 08:33:18 +0530 Subject: [PATCH 16/47] feat(client-config-builder): add env tests --- .../configures/env_configure.py | 24 ++++++-- .../tests/.gitignore | 1 + .../tests/env/__init__.py | 0 .../tests/env/test_add_env.py | 27 +++++++++ .../tests/env/test_get_env.py | 40 +++++++++++++ .../tests/env/test_remove_env.py | 59 +++++++++++++++++++ .../tests/env/test_set_env.py | 50 ++++++++++++++++ 7 files changed, 197 insertions(+), 4 deletions(-) create mode 100644 packages/polywrap-client-config-builder/tests/.gitignore create mode 100644 packages/polywrap-client-config-builder/tests/env/__init__.py create mode 100644 packages/polywrap-client-config-builder/tests/env/test_add_env.py create mode 100644 packages/polywrap-client-config-builder/tests/env/test_get_env.py create mode 100644 packages/polywrap-client-config-builder/tests/env/test_remove_env.py create mode 100644 packages/polywrap-client-config-builder/tests/env/test_set_env.py diff --git a/packages/polywrap-client-config-builder/polywrap_client_config_builder/configures/env_configure.py b/packages/polywrap-client-config-builder/polywrap_client_config_builder/configures/env_configure.py index 1a1d1297..ff7a5d8d 100644 --- a/packages/polywrap-client-config-builder/polywrap_client_config_builder/configures/env_configure.py +++ b/packages/polywrap-client-config-builder/polywrap_client_config_builder/configures/env_configure.py @@ -1,6 +1,6 @@ """This module contains the env configure class for the client config builder.""" from abc import ABC -from typing import Any, Dict, List, Union +from typing import Any, Dict, List, Union, cast from polywrap_core import Uri @@ -35,9 +35,9 @@ def add_env(self, uri: Uri, env: Any) -> ClientConfigBuilder: If an Any is already associated with the uri, it is modified. """ - if self.config.envs.get(uri): - for key in self.config.envs[uri]: - self.config.envs[uri][key] = env[key] + if old_env := self.config.envs.get(uri): + new_env = self._merge_envs(old_env, env) + self.config.envs[uri] = new_env else: self.config.envs[uri] = env return self @@ -58,3 +58,19 @@ def remove_envs(self, uris: List[Uri]) -> ClientConfigBuilder: for uri in uris: self.remove_env(uri) return self + + @staticmethod + def _merge_envs(env1: Dict[str, Any], env2: Dict[str, Any]) -> Dict[str, Any]: + for key, val in env2.items(): + if key not in env1: + env1[key] = val + continue + + if isinstance(val, dict): + old_val = cast(Dict[str, Any], env1[key]) + new_val = cast(Dict[str, Any], val) + + EnvConfigure._merge_envs(old_val, new_val) + else: + env1[key] = val + return env1 \ No newline at end of file diff --git a/packages/polywrap-client-config-builder/tests/.gitignore b/packages/polywrap-client-config-builder/tests/.gitignore new file mode 100644 index 00000000..becd6eb0 --- /dev/null +++ b/packages/polywrap-client-config-builder/tests/.gitignore @@ -0,0 +1 @@ +!env/ \ No newline at end of file diff --git a/packages/polywrap-client-config-builder/tests/env/__init__.py b/packages/polywrap-client-config-builder/tests/env/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/packages/polywrap-client-config-builder/tests/env/test_add_env.py b/packages/polywrap-client-config-builder/tests/env/test_add_env.py new file mode 100644 index 00000000..0879f3bd --- /dev/null +++ b/packages/polywrap-client-config-builder/tests/env/test_add_env.py @@ -0,0 +1,27 @@ +from typing import Any, Dict +from hypothesis import assume, given, settings + +from polywrap_client_config_builder import ( + ClientConfigBuilder, + PolywrapClientConfigBuilder, +) +from polywrap_core import Uri + +from ..strategies import uri_strategy, env_strategy + + +@settings(max_examples=100) +@given(uri=uri_strategy, old_env=env_strategy, new_env=env_strategy) +def test_add_env(uri: Uri, old_env: Any, new_env: Any): + builder: ClientConfigBuilder = PolywrapClientConfigBuilder() + builder.config.envs = {uri: {"common": old_env, "unique_1": "unique_env_1"}} + + builder.add_env(uri, {"common": new_env, "unique_2": "unique_env_2"}) + + updated_env = {**old_env, **new_env} + + assert builder.config.envs[uri] == { + "common": updated_env, + "unique_1": "unique_env_1", + "unique_2": "unique_env_2", + } diff --git a/packages/polywrap-client-config-builder/tests/env/test_get_env.py b/packages/polywrap-client-config-builder/tests/env/test_get_env.py new file mode 100644 index 00000000..ffd0f8ad --- /dev/null +++ b/packages/polywrap-client-config-builder/tests/env/test_get_env.py @@ -0,0 +1,40 @@ +from typing import Any, Dict +from hypothesis import given, settings + +from polywrap_client_config_builder import ( + ClientConfigBuilder, + PolywrapClientConfigBuilder, +) +from polywrap_core import Uri + +from ..strategies import envs_strategy + + +@settings(max_examples=100) +@given(envs=envs_strategy) +def test_get_env_exists( + envs: Dict[Uri, Any] +): + builder: ClientConfigBuilder = PolywrapClientConfigBuilder() + builder.config.envs = envs + + for uri in envs: + assert builder.get_env(uri) == envs[uri] + assert builder.get_env(Uri.from_str("test/not-exists")) is None + + +def test_get_env_not_exists(): + builder: ClientConfigBuilder = PolywrapClientConfigBuilder() + assert builder.get_env(Uri.from_str("test/not-exists")) is None + + +@settings(max_examples=100) +@given(envs=envs_strategy) +def test_get_envs( + envs: Dict[Uri, Any] +): + builder: ClientConfigBuilder = PolywrapClientConfigBuilder() + assert builder.get_envs() == {} + + builder.config.envs = envs + assert builder.get_envs() == envs diff --git a/packages/polywrap-client-config-builder/tests/env/test_remove_env.py b/packages/polywrap-client-config-builder/tests/env/test_remove_env.py new file mode 100644 index 00000000..75d074e3 --- /dev/null +++ b/packages/polywrap-client-config-builder/tests/env/test_remove_env.py @@ -0,0 +1,59 @@ +from typing import Any, Dict +from random import randint +from hypothesis import assume, event, given, settings + +from polywrap_client_config_builder import ( + ClientConfigBuilder, + PolywrapClientConfigBuilder, +) +from polywrap_core import Uri + +from ..strategies import envs_strategy + + +@settings(max_examples=100) +@given(envs=envs_strategy) +def test_remove_env(envs: Dict[Uri, Any]): + assume(envs) + builder: ClientConfigBuilder = PolywrapClientConfigBuilder() + builder.config.envs = {**envs} + + uris = list(envs.keys()) + uri_index = randint(0, len(uris) - 1) + remove_uri = uris[uri_index] + event(f"Uri to remove: {remove_uri}") + + builder.remove_env(remove_uri) + assert len(builder.config.envs) == len(envs) - 1 + assert remove_uri not in builder.config.envs + + +@settings(max_examples=100) +@given(envs=envs_strategy) +def test_remove_non_existent_env(envs: Dict[Uri, Any]): + builder: ClientConfigBuilder = PolywrapClientConfigBuilder() + builder.config.envs = {**envs} + + builder.remove_env(Uri("test", "non-existent")) + assert builder.config.envs == envs + + +@settings(max_examples=100) +@given(envs=envs_strategy) +def test_remove_envs(envs: Dict[Uri, Any]): + assume(envs) + builder: ClientConfigBuilder = PolywrapClientConfigBuilder() + builder.config.envs = {**envs} + + uris = list(envs.keys()) + uri_indices = [ + randint(0, len(uris) - 1) for _ in range(randint(0, len(uris) - 1)) + ] + remove_uris = list({uris[uri_index] for uri_index in uri_indices}) + event(f"Uris to remove: {remove_uris}") + + builder.remove_envs(remove_uris) + assert len(builder.config.envs) == len(envs) - len(remove_uris) + assert set(remove_uris) & set(builder.config.envs.keys()) == set() + + diff --git a/packages/polywrap-client-config-builder/tests/env/test_set_env.py b/packages/polywrap-client-config-builder/tests/env/test_set_env.py new file mode 100644 index 00000000..f6753550 --- /dev/null +++ b/packages/polywrap-client-config-builder/tests/env/test_set_env.py @@ -0,0 +1,50 @@ +from typing import Any, Dict +from hypothesis import assume, given, settings + +from polywrap_client_config_builder import ( + ClientConfigBuilder, + PolywrapClientConfigBuilder, +) +from polywrap_core import Uri + +from ..strategies import envs_strategy, uri_strategy, env_strategy + + +@settings(max_examples=100) +@given(envs=envs_strategy, new_uri=uri_strategy, new_env=env_strategy) +def test_set_env(envs: Dict[Uri, Any], new_uri: Uri, new_env: Any): + builder: ClientConfigBuilder = PolywrapClientConfigBuilder() + builder.config.envs = {**envs} + + existing_uris = set(builder.config.envs.keys()) + assume(new_uri not in existing_uris) + + builder.set_env(new_uri, new_env) + + assert len(builder.config.envs) == len(existing_uris) + 1 + assert builder.config.envs[new_uri] == new_env + + +@settings(max_examples=100) +@given(uri=uri_strategy, old_env=env_strategy, new_env=env_strategy) +def test_set_env_overwrite(uri: Uri, old_env: Any, new_env: Any): + builder: ClientConfigBuilder = PolywrapClientConfigBuilder() + builder.config.envs = {uri: old_env} + + builder.set_env(uri, new_env) + + assert builder.config.envs == {uri: new_env} + + +@settings(max_examples=100) +@given(initial_envs=envs_strategy, new_envs=envs_strategy) +def test_set_envs( + initial_envs: Dict[Uri, Any], + new_envs: Dict[Uri, Any], +): + builder: ClientConfigBuilder = PolywrapClientConfigBuilder() + builder.config.envs = {**initial_envs} + + builder.set_envs(new_envs) + + assert len(builder.config.envs) <= len(initial_envs) + len(new_envs) From a9ff0e9c41d04fbb9eebb512b487083c7ae30900 Mon Sep 17 00:00:00 2001 From: Niraj Kamdar Date: Thu, 8 Jun 2023 15:03:34 +0530 Subject: [PATCH 17/47] wip: add interface tests --- .../configures/interface_configure.py | 5 +++- .../tests/env/test_add_env.py | 4 +-- .../tests/interface/__init__.py | 0 .../tests/interface/test_add_interface.py | 25 +++++++++++++++++++ .../tests/interface/test_get_interface.py | 0 .../tests/interface/test_remove_interface.py | 0 6 files changed, 31 insertions(+), 3 deletions(-) create mode 100644 packages/polywrap-client-config-builder/tests/interface/__init__.py create mode 100644 packages/polywrap-client-config-builder/tests/interface/test_add_interface.py create mode 100644 packages/polywrap-client-config-builder/tests/interface/test_get_interface.py create mode 100644 packages/polywrap-client-config-builder/tests/interface/test_remove_interface.py diff --git a/packages/polywrap-client-config-builder/polywrap_client_config_builder/configures/interface_configure.py b/packages/polywrap-client-config-builder/polywrap_client_config_builder/configures/interface_configure.py index 26fc60d3..7fb81ebb 100644 --- a/packages/polywrap-client-config-builder/polywrap_client_config_builder/configures/interface_configure.py +++ b/packages/polywrap-client-config-builder/polywrap_client_config_builder/configures/interface_configure.py @@ -26,7 +26,10 @@ def add_interface_implementations( ) -> ClientConfigBuilder: """Add a list of implementation URIs for the given interface URI to the builder's config.""" if interface_uri in self.config.interfaces.keys(): - self.config.interfaces[interface_uri].extend(implementations_uris) + existing_implementations = set(self.config.interfaces[interface_uri]) + for implementation_uri in implementations_uris: + if implementation_uri not in existing_implementations: + self.config.interfaces[interface_uri].append(implementation_uri) else: self.config.interfaces[interface_uri] = implementations_uris return self diff --git a/packages/polywrap-client-config-builder/tests/env/test_add_env.py b/packages/polywrap-client-config-builder/tests/env/test_add_env.py index 0879f3bd..05b91dd1 100644 --- a/packages/polywrap-client-config-builder/tests/env/test_add_env.py +++ b/packages/polywrap-client-config-builder/tests/env/test_add_env.py @@ -1,5 +1,5 @@ -from typing import Any, Dict -from hypothesis import assume, given, settings +from typing import Any +from hypothesis import given, settings from polywrap_client_config_builder import ( ClientConfigBuilder, diff --git a/packages/polywrap-client-config-builder/tests/interface/__init__.py b/packages/polywrap-client-config-builder/tests/interface/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/packages/polywrap-client-config-builder/tests/interface/test_add_interface.py b/packages/polywrap-client-config-builder/tests/interface/test_add_interface.py new file mode 100644 index 00000000..e409f3c3 --- /dev/null +++ b/packages/polywrap-client-config-builder/tests/interface/test_add_interface.py @@ -0,0 +1,25 @@ +from typing import Any, List +from hypothesis import given, settings, strategies as st + +from polywrap_client_config_builder import ( + ClientConfigBuilder, + PolywrapClientConfigBuilder, +) +from polywrap_core import Uri + +from ..strategies import uri_strategy + + +@settings(max_examples=100) +@given(uri=uri_strategy, old_impls=st.lists(uri_strategy), new_impls=st.lists(uri_strategy)) +def test_add_implementations_to_existing_interface(uri: Uri, old_impls: List[Uri], new_impls: List[Uri]): + builder: ClientConfigBuilder = PolywrapClientConfigBuilder() + builder.config.interfaces = {uri: old_impls} + + builder.add_interface_implementations(uri, new_impls) + + updated_impls = {*old_impls, *new_impls} + + assert set(builder.config.interfaces[uri]) == updated_impls + + diff --git a/packages/polywrap-client-config-builder/tests/interface/test_get_interface.py b/packages/polywrap-client-config-builder/tests/interface/test_get_interface.py new file mode 100644 index 00000000..e69de29b diff --git a/packages/polywrap-client-config-builder/tests/interface/test_remove_interface.py b/packages/polywrap-client-config-builder/tests/interface/test_remove_interface.py new file mode 100644 index 00000000..e69de29b From 7bb77001de24975ef0a534158d8ea2cfc379e7b0 Mon Sep 17 00:00:00 2001 From: Niraj Kamdar Date: Thu, 8 Jun 2023 18:03:02 +0530 Subject: [PATCH 18/47] feat: complete interface tests --- .../tests/interface/test_add_interface.py | 2 +- .../tests/interface/test_get_interface.py | 40 ++++++++++++ .../tests/interface/test_remove_interface.py | 65 +++++++++++++++++++ 3 files changed, 106 insertions(+), 1 deletion(-) diff --git a/packages/polywrap-client-config-builder/tests/interface/test_add_interface.py b/packages/polywrap-client-config-builder/tests/interface/test_add_interface.py index e409f3c3..23662e8b 100644 --- a/packages/polywrap-client-config-builder/tests/interface/test_add_interface.py +++ b/packages/polywrap-client-config-builder/tests/interface/test_add_interface.py @@ -1,4 +1,4 @@ -from typing import Any, List +from typing import List from hypothesis import given, settings, strategies as st from polywrap_client_config_builder import ( diff --git a/packages/polywrap-client-config-builder/tests/interface/test_get_interface.py b/packages/polywrap-client-config-builder/tests/interface/test_get_interface.py index e69de29b..325e3dbe 100644 --- a/packages/polywrap-client-config-builder/tests/interface/test_get_interface.py +++ b/packages/polywrap-client-config-builder/tests/interface/test_get_interface.py @@ -0,0 +1,40 @@ +from typing import Any, Dict, List +from hypothesis import given, settings + +from polywrap_client_config_builder import ( + ClientConfigBuilder, + PolywrapClientConfigBuilder, +) +from polywrap_core import Uri + +from ..strategies import interfaces_strategy + + +@settings(max_examples=100) +@given(interfaces=interfaces_strategy) +def test_get_interface_implementations( + interfaces: Dict[Uri, List[Uri]] +): + builder: ClientConfigBuilder = PolywrapClientConfigBuilder() + builder.config.interfaces = interfaces + + for uri in interfaces: + assert builder.get_interface_implementations(uri) == interfaces[uri] + assert builder.get_interface_implementations(Uri.from_str("test/not-exists")) is None + + +def test_get_implementations_not_exists(): + builder: ClientConfigBuilder = PolywrapClientConfigBuilder() + assert builder.get_interface_implementations(Uri.from_str("test/not-exists")) is None + + +@settings(max_examples=100) +@given(interfaces=interfaces_strategy) +def test_get_interfaces( + interfaces: Dict[Uri, List[Uri]] +): + builder: ClientConfigBuilder = PolywrapClientConfigBuilder() + assert builder.get_interfaces() == {} + + builder.config.interfaces = interfaces + assert builder.get_interfaces() == interfaces diff --git a/packages/polywrap-client-config-builder/tests/interface/test_remove_interface.py b/packages/polywrap-client-config-builder/tests/interface/test_remove_interface.py index e69de29b..aa73d382 100644 --- a/packages/polywrap-client-config-builder/tests/interface/test_remove_interface.py +++ b/packages/polywrap-client-config-builder/tests/interface/test_remove_interface.py @@ -0,0 +1,65 @@ +from typing import Any, Dict, List +from random import randint +from hypothesis import assume, event, given, settings + +from polywrap_client_config_builder import ( + ClientConfigBuilder, + PolywrapClientConfigBuilder, +) +from polywrap_core import Uri + +from ..strategies import interfaces_strategy + + +@settings(max_examples=100) +@given(interfaces=interfaces_strategy) +def test_remove_interface(interfaces: Dict[Uri, List[Uri]]): + assume(interfaces) + assume(all(interfaces[interface] for interface in interfaces)) + builder: ClientConfigBuilder = PolywrapClientConfigBuilder() + builder.config.interfaces = {**interfaces} + + uris = list(interfaces.keys()) + uri_index = randint(0, len(uris) - 1) + remove_uri = uris[uri_index] + event(f"Uri to remove: {remove_uri}") + + builder.remove_interface(remove_uri) + assert len(builder.config.interfaces) == len(interfaces) - 1 + assert remove_uri not in builder.config.interfaces + + +@settings(max_examples=100) +@given(interfaces=interfaces_strategy) +def test_remove_non_existent_interface(interfaces: Dict[Uri, List[Uri]]): + builder: ClientConfigBuilder = PolywrapClientConfigBuilder() + builder.config.interfaces = {**interfaces} + + builder.remove_interface(Uri("test", "non-existent")) + assert builder.config.interfaces == interfaces + + +@settings(max_examples=100) +@given(interfaces=interfaces_strategy) +def test_remove_interface_implementations(interfaces: Dict[Uri, List[Uri]]): + assume(interfaces) + assume(all(interfaces[interface] for interface in interfaces)) + builder: ClientConfigBuilder = PolywrapClientConfigBuilder() + builder.config.interfaces = {**interfaces} + + uris = list(interfaces.keys()) + uri_index = randint(0, len(uris) - 1) + remove_interface_uri = uris[uri_index] + event(f"Interface Uri to remove: {remove_interface_uri}") + + impls_uris = list(interfaces[remove_interface_uri]) + impl_uri_indices = [ + randint(0, len(impls_uris) - 1) for _ in range(randint(0, len(impls_uris) - 1)) + ] + remove_uris = list({impls_uris[uri_index] for uri_index in impl_uri_indices}) + event(f"Implementations Uri to remove: {remove_uris}") + + builder.remove_interface_implementations(remove_interface_uri, remove_uris) + assert ( + set(remove_uris) & set(builder.config.interfaces[remove_interface_uri]) == set() + ) From bf8347324f1821a47ca82f591df939f718eb253d Mon Sep 17 00:00:00 2001 From: Niraj Kamdar Date: Thu, 8 Jun 2023 18:42:28 +0530 Subject: [PATCH 19/47] feat: add package tests --- .../tests/package/__init__.py | 0 .../tests/package/test_get_package.py | 40 +++++++++++++ .../tests/package/test_remove_package.py | 59 +++++++++++++++++++ .../tests/package/test_set_package.py | 50 ++++++++++++++++ 4 files changed, 149 insertions(+) create mode 100644 packages/polywrap-client-config-builder/tests/package/__init__.py create mode 100644 packages/polywrap-client-config-builder/tests/package/test_get_package.py create mode 100644 packages/polywrap-client-config-builder/tests/package/test_remove_package.py create mode 100644 packages/polywrap-client-config-builder/tests/package/test_set_package.py diff --git a/packages/polywrap-client-config-builder/tests/package/__init__.py b/packages/polywrap-client-config-builder/tests/package/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/packages/polywrap-client-config-builder/tests/package/test_get_package.py b/packages/polywrap-client-config-builder/tests/package/test_get_package.py new file mode 100644 index 00000000..26b7b993 --- /dev/null +++ b/packages/polywrap-client-config-builder/tests/package/test_get_package.py @@ -0,0 +1,40 @@ +from typing import Any, Dict +from hypothesis import given, settings + +from polywrap_client_config_builder import ( + ClientConfigBuilder, + PolywrapClientConfigBuilder, +) +from polywrap_core import Uri + +from ..strategies import packages_strategy + + +@settings(max_examples=100) +@given(packages=packages_strategy) +def test_get_package_exists( + packages: Dict[Uri, Any] +): + builder: ClientConfigBuilder = PolywrapClientConfigBuilder() + builder.config.packages = packages + + for uri in packages: + assert builder.get_package(uri) == packages[uri] + assert builder.get_package(Uri.from_str("test/not-exists")) is None + + +def test_get_package_not_exists(): + builder: ClientConfigBuilder = PolywrapClientConfigBuilder() + assert builder.get_package(Uri.from_str("test/not-exists")) is None + + +@settings(max_examples=100) +@given(packages=packages_strategy) +def test_get_packages( + packages: Dict[Uri, Any] +): + builder: ClientConfigBuilder = PolywrapClientConfigBuilder() + assert builder.get_packages() == {} + + builder.config.packages = packages + assert builder.get_packages() == packages diff --git a/packages/polywrap-client-config-builder/tests/package/test_remove_package.py b/packages/polywrap-client-config-builder/tests/package/test_remove_package.py new file mode 100644 index 00000000..341f6368 --- /dev/null +++ b/packages/polywrap-client-config-builder/tests/package/test_remove_package.py @@ -0,0 +1,59 @@ +from typing import Any, Dict +from random import randint +from hypothesis import assume, event, given, settings + +from polywrap_client_config_builder import ( + ClientConfigBuilder, + PolywrapClientConfigBuilder, +) +from polywrap_core import Uri + +from ..strategies import packages_strategy + + +@settings(max_examples=100) +@given(packages=packages_strategy) +def test_remove_package(packages: Dict[Uri, Any]): + assume(packages) + builder: ClientConfigBuilder = PolywrapClientConfigBuilder() + builder.config.packages = {**packages} + + uris = list(packages.keys()) + uri_index = randint(0, len(uris) - 1) + remove_uri = uris[uri_index] + event(f"Uri to remove: {remove_uri}") + + builder.remove_package(remove_uri) + assert len(builder.config.packages) == len(packages) - 1 + assert remove_uri not in builder.config.packages + + +@settings(max_examples=100) +@given(packages=packages_strategy) +def test_remove_non_existent_package(packages: Dict[Uri, Any]): + builder: ClientConfigBuilder = PolywrapClientConfigBuilder() + builder.config.packages = {**packages} + + builder.remove_package(Uri("test", "non-existent")) + assert builder.config.packages == packages + + +@settings(max_examples=100) +@given(packages=packages_strategy) +def test_remove_packages(packages: Dict[Uri, Any]): + assume(packages) + builder: ClientConfigBuilder = PolywrapClientConfigBuilder() + builder.config.packages = {**packages} + + uris = list(packages.keys()) + uri_indices = [ + randint(0, len(uris) - 1) for _ in range(randint(0, len(uris) - 1)) + ] + remove_uris = list({uris[uri_index] for uri_index in uri_indices}) + event(f"Uris to remove: {remove_uris}") + + builder.remove_packages(remove_uris) + assert len(builder.config.packages) == len(packages) - len(remove_uris) + assert set(remove_uris) & set(builder.config.packages.keys()) == set() + + diff --git a/packages/polywrap-client-config-builder/tests/package/test_set_package.py b/packages/polywrap-client-config-builder/tests/package/test_set_package.py new file mode 100644 index 00000000..1e9161e7 --- /dev/null +++ b/packages/polywrap-client-config-builder/tests/package/test_set_package.py @@ -0,0 +1,50 @@ +from typing import Any, Dict +from hypothesis import assume, given, settings + +from polywrap_client_config_builder import ( + ClientConfigBuilder, + PolywrapClientConfigBuilder, +) +from polywrap_core import Uri + +from ..strategies import packages_strategy, uri_strategy, package_strategy + + +@settings(max_examples=100) +@given(packages=packages_strategy, new_uri=uri_strategy, new_package=package_strategy) +def test_set_package(packages: Dict[Uri, Any], new_uri: Uri, new_package: Any): + builder: ClientConfigBuilder = PolywrapClientConfigBuilder() + builder.config.packages = {**packages} + + existing_uris = set(builder.config.packages.keys()) + assume(new_uri not in existing_uris) + + builder.set_package(new_uri, new_package) + + assert len(builder.config.packages) == len(existing_uris) + 1 + assert builder.config.packages[new_uri] == new_package + + +@settings(max_examples=100) +@given(uri=uri_strategy, old_package=package_strategy, new_package=package_strategy) +def test_set_env_overwrite(uri: Uri, old_package: Any, new_package: Any): + builder: ClientConfigBuilder = PolywrapClientConfigBuilder() + builder.config.packages = {uri: old_package} + + builder.set_package(uri, new_package) + + assert builder.config.packages == {uri: new_package} + + +@settings(max_examples=100) +@given(initial_packages=packages_strategy, new_packages=packages_strategy) +def test_set_packages( + initial_packages: Dict[Uri, Any], + new_packages: Dict[Uri, Any], +): + builder: ClientConfigBuilder = PolywrapClientConfigBuilder() + builder.config.packages = {**initial_packages} + + builder.set_packages(new_packages) + + assert len(builder.config.envs) <= len(initial_packages) + len(new_packages) From f4ffd1d68e6e464f989943fcddde36f58fa613b2 Mon Sep 17 00:00:00 2001 From: Niraj Kamdar Date: Thu, 8 Jun 2023 18:43:57 +0530 Subject: [PATCH 20/47] feat: add wrapper tests --- .../tests/wrapper/__init__.py | 0 .../tests/wrapper/test_get_wrapper.py | 40 +++++++++++++ .../tests/wrapper/test_remove_wrapper.py | 59 +++++++++++++++++++ .../tests/wrapper/test_set_wrapper.py | 50 ++++++++++++++++ 4 files changed, 149 insertions(+) create mode 100644 packages/polywrap-client-config-builder/tests/wrapper/__init__.py create mode 100644 packages/polywrap-client-config-builder/tests/wrapper/test_get_wrapper.py create mode 100644 packages/polywrap-client-config-builder/tests/wrapper/test_remove_wrapper.py create mode 100644 packages/polywrap-client-config-builder/tests/wrapper/test_set_wrapper.py diff --git a/packages/polywrap-client-config-builder/tests/wrapper/__init__.py b/packages/polywrap-client-config-builder/tests/wrapper/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/packages/polywrap-client-config-builder/tests/wrapper/test_get_wrapper.py b/packages/polywrap-client-config-builder/tests/wrapper/test_get_wrapper.py new file mode 100644 index 00000000..2203892b --- /dev/null +++ b/packages/polywrap-client-config-builder/tests/wrapper/test_get_wrapper.py @@ -0,0 +1,40 @@ +from typing import Any, Dict +from hypothesis import given, settings + +from polywrap_client_config_builder import ( + ClientConfigBuilder, + PolywrapClientConfigBuilder, +) +from polywrap_core import Uri + +from ..strategies import wrappers_strategy + + +@settings(max_examples=100) +@given(wrappers=wrappers_strategy) +def test_get_wrapper_exists( + wrappers: Dict[Uri, Any] +): + builder: ClientConfigBuilder = PolywrapClientConfigBuilder() + builder.config.wrappers = wrappers + + for uri in wrappers: + assert builder.get_wrapper(uri) == wrappers[uri] + assert builder.get_wrapper(Uri.from_str("test/not-exists")) is None + + +def test_get_wrapper_not_exists(): + builder: ClientConfigBuilder = PolywrapClientConfigBuilder() + assert builder.get_wrapper(Uri.from_str("test/not-exists")) is None + + +@settings(max_examples=100) +@given(wrappers=wrappers_strategy) +def test_get_wrappers( + wrappers: Dict[Uri, Any] +): + builder: ClientConfigBuilder = PolywrapClientConfigBuilder() + assert builder.get_wrappers() == {} + + builder.config.wrappers = wrappers + assert builder.get_wrappers() == wrappers diff --git a/packages/polywrap-client-config-builder/tests/wrapper/test_remove_wrapper.py b/packages/polywrap-client-config-builder/tests/wrapper/test_remove_wrapper.py new file mode 100644 index 00000000..0a54eae4 --- /dev/null +++ b/packages/polywrap-client-config-builder/tests/wrapper/test_remove_wrapper.py @@ -0,0 +1,59 @@ +from typing import Any, Dict +from random import randint +from hypothesis import assume, event, given, settings + +from polywrap_client_config_builder import ( + ClientConfigBuilder, + PolywrapClientConfigBuilder, +) +from polywrap_core import Uri + +from ..strategies import wrappers_strategy + + +@settings(max_examples=100) +@given(wrappers=wrappers_strategy) +def test_remove_wrapper(wrappers: Dict[Uri, Any]): + assume(wrappers) + builder: ClientConfigBuilder = PolywrapClientConfigBuilder() + builder.config.wrappers = {**wrappers} + + uris = list(wrappers.keys()) + uri_index = randint(0, len(uris) - 1) + remove_uri = uris[uri_index] + event(f"Uri to remove: {remove_uri}") + + builder.remove_wrapper(remove_uri) + assert len(builder.config.wrappers) == len(wrappers) - 1 + assert remove_uri not in builder.config.wrappers + + +@settings(max_examples=100) +@given(wrappers=wrappers_strategy) +def test_remove_non_existent_wrapper(wrappers: Dict[Uri, Any]): + builder: ClientConfigBuilder = PolywrapClientConfigBuilder() + builder.config.wrappers = {**wrappers} + + builder.remove_wrapper(Uri("test", "non-existent")) + assert builder.config.wrappers == wrappers + + +@settings(max_examples=100) +@given(wrappers=wrappers_strategy) +def test_remove_wrappers(wrappers: Dict[Uri, Any]): + assume(wrappers) + builder: ClientConfigBuilder = PolywrapClientConfigBuilder() + builder.config.wrappers = {**wrappers} + + uris = list(wrappers.keys()) + uri_indices = [ + randint(0, len(uris) - 1) for _ in range(randint(0, len(uris) - 1)) + ] + remove_uris = list({uris[uri_index] for uri_index in uri_indices}) + event(f"Uris to remove: {remove_uris}") + + builder.remove_wrappers(remove_uris) + assert len(builder.config.wrappers) == len(wrappers) - len(remove_uris) + assert set(remove_uris) & set(builder.config.wrappers.keys()) == set() + + diff --git a/packages/polywrap-client-config-builder/tests/wrapper/test_set_wrapper.py b/packages/polywrap-client-config-builder/tests/wrapper/test_set_wrapper.py new file mode 100644 index 00000000..da05a52b --- /dev/null +++ b/packages/polywrap-client-config-builder/tests/wrapper/test_set_wrapper.py @@ -0,0 +1,50 @@ +from typing import Any, Dict +from hypothesis import assume, given, settings + +from polywrap_client_config_builder import ( + ClientConfigBuilder, + PolywrapClientConfigBuilder, +) +from polywrap_core import Uri + +from ..strategies import wrappers_strategy, uri_strategy, wrapper_strategy + + +@settings(max_examples=100) +@given(wrappers=wrappers_strategy, new_uri=uri_strategy, new_wrapper=wrapper_strategy) +def test_set_wrapper(wrappers: Dict[Uri, Any], new_uri: Uri, new_wrapper: Any): + builder: ClientConfigBuilder = PolywrapClientConfigBuilder() + builder.config.wrappers = {**wrappers} + + existing_uris = set(builder.config.wrappers.keys()) + assume(new_uri not in existing_uris) + + builder.set_wrapper(new_uri, new_wrapper) + + assert len(builder.config.wrappers) == len(existing_uris) + 1 + assert builder.config.wrappers[new_uri] == new_wrapper + + +@settings(max_examples=100) +@given(uri=uri_strategy, old_wrapper=wrapper_strategy, new_wrapper=wrapper_strategy) +def test_set_env_overwrite(uri: Uri, old_wrapper: Any, new_wrapper: Any): + builder: ClientConfigBuilder = PolywrapClientConfigBuilder() + builder.config.wrappers = {uri: old_wrapper} + + builder.set_wrapper(uri, new_wrapper) + + assert builder.config.wrappers == {uri: new_wrapper} + + +@settings(max_examples=100) +@given(initial_wrappers=wrappers_strategy, new_wrappers=wrappers_strategy) +def test_set_wrappers( + initial_wrappers: Dict[Uri, Any], + new_wrappers: Dict[Uri, Any], +): + builder: ClientConfigBuilder = PolywrapClientConfigBuilder() + builder.config.wrappers = {**initial_wrappers} + + builder.set_wrappers(new_wrappers) + + assert len(builder.config.envs) <= len(initial_wrappers) + len(new_wrappers) From 16939d63bf284e89a5ead6315f13a3e1d078fd7b Mon Sep 17 00:00:00 2001 From: Niraj Kamdar Date: Thu, 8 Jun 2023 18:53:14 +0530 Subject: [PATCH 21/47] feat: add redirect tests --- .../tests/redirect/__init__.py | 0 .../tests/redirect/test_get_redirect.py | 40 +++++++++++++ .../tests/redirect/test_remove_redirect.py | 59 +++++++++++++++++++ .../tests/redirect/test_set_redirect.py | 50 ++++++++++++++++ 4 files changed, 149 insertions(+) create mode 100644 packages/polywrap-client-config-builder/tests/redirect/__init__.py create mode 100644 packages/polywrap-client-config-builder/tests/redirect/test_get_redirect.py create mode 100644 packages/polywrap-client-config-builder/tests/redirect/test_remove_redirect.py create mode 100644 packages/polywrap-client-config-builder/tests/redirect/test_set_redirect.py diff --git a/packages/polywrap-client-config-builder/tests/redirect/__init__.py b/packages/polywrap-client-config-builder/tests/redirect/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/packages/polywrap-client-config-builder/tests/redirect/test_get_redirect.py b/packages/polywrap-client-config-builder/tests/redirect/test_get_redirect.py new file mode 100644 index 00000000..5a07cd7e --- /dev/null +++ b/packages/polywrap-client-config-builder/tests/redirect/test_get_redirect.py @@ -0,0 +1,40 @@ +from typing import Any, Dict +from hypothesis import given, settings + +from polywrap_client_config_builder import ( + ClientConfigBuilder, + PolywrapClientConfigBuilder, +) +from polywrap_core import Uri + +from ..strategies import redirects_strategy + + +@settings(max_examples=100) +@given(redirects=redirects_strategy) +def test_get_redirect_exists( + redirects: Dict[Uri, Any] +): + builder: ClientConfigBuilder = PolywrapClientConfigBuilder() + builder.config.redirects = redirects + + for uri in redirects: + assert builder.get_redirect(uri) == redirects[uri] + assert builder.get_redirect(Uri.from_str("test/not-exists")) is None + + +def test_get_redirect_not_exists(): + builder: ClientConfigBuilder = PolywrapClientConfigBuilder() + assert builder.get_redirect(Uri.from_str("test/not-exists")) is None + + +@settings(max_examples=100) +@given(redirects=redirects_strategy) +def test_get_redirects( + redirects: Dict[Uri, Any] +): + builder: ClientConfigBuilder = PolywrapClientConfigBuilder() + assert builder.get_redirects() == {} + + builder.config.redirects = redirects + assert builder.get_redirects() == redirects diff --git a/packages/polywrap-client-config-builder/tests/redirect/test_remove_redirect.py b/packages/polywrap-client-config-builder/tests/redirect/test_remove_redirect.py new file mode 100644 index 00000000..045f48cd --- /dev/null +++ b/packages/polywrap-client-config-builder/tests/redirect/test_remove_redirect.py @@ -0,0 +1,59 @@ +from typing import Any, Dict +from random import randint +from hypothesis import assume, event, given, settings + +from polywrap_client_config_builder import ( + ClientConfigBuilder, + PolywrapClientConfigBuilder, +) +from polywrap_core import Uri + +from ..strategies import redirects_strategy + + +@settings(max_examples=100) +@given(redirects=redirects_strategy) +def test_remove_redirect(redirects: Dict[Uri, Any]): + assume(redirects) + builder: ClientConfigBuilder = PolywrapClientConfigBuilder() + builder.config.redirects = {**redirects} + + uris = list(redirects.keys()) + uri_index = randint(0, len(uris) - 1) + remove_uri = uris[uri_index] + event(f"Uri to remove: {remove_uri}") + + builder.remove_redirect(remove_uri) + assert len(builder.config.redirects) == len(redirects) - 1 + assert remove_uri not in builder.config.redirects + + +@settings(max_examples=100) +@given(redirects=redirects_strategy) +def test_remove_non_existent_redirect(redirects: Dict[Uri, Any]): + builder: ClientConfigBuilder = PolywrapClientConfigBuilder() + builder.config.redirects = {**redirects} + + builder.remove_redirect(Uri("test", "non-existent")) + assert builder.config.redirects == redirects + + +@settings(max_examples=100) +@given(redirects=redirects_strategy) +def test_remove_redirects(redirects: Dict[Uri, Any]): + assume(redirects) + builder: ClientConfigBuilder = PolywrapClientConfigBuilder() + builder.config.redirects = {**redirects} + + uris = list(redirects.keys()) + uri_indices = [ + randint(0, len(uris) - 1) for _ in range(randint(0, len(uris) - 1)) + ] + remove_uris = list({uris[uri_index] for uri_index in uri_indices}) + event(f"Uris to remove: {remove_uris}") + + builder.remove_redirects(remove_uris) + assert len(builder.config.redirects) == len(redirects) - len(remove_uris) + assert set(remove_uris) & set(builder.config.redirects.keys()) == set() + + diff --git a/packages/polywrap-client-config-builder/tests/redirect/test_set_redirect.py b/packages/polywrap-client-config-builder/tests/redirect/test_set_redirect.py new file mode 100644 index 00000000..4eed5de9 --- /dev/null +++ b/packages/polywrap-client-config-builder/tests/redirect/test_set_redirect.py @@ -0,0 +1,50 @@ +from typing import Any, Dict +from hypothesis import assume, given, settings + +from polywrap_client_config_builder import ( + ClientConfigBuilder, + PolywrapClientConfigBuilder, +) +from polywrap_core import Uri + +from ..strategies import redirects_strategy, uri_strategy + + +@settings(max_examples=100) +@given(redirects=redirects_strategy, new_uri=uri_strategy, new_redirect=uri_strategy) +def test_set_redirect(redirects: Dict[Uri, Any], new_uri: Uri, new_redirect: Any): + builder: ClientConfigBuilder = PolywrapClientConfigBuilder() + builder.config.redirects = {**redirects} + + existing_uris = set(builder.config.redirects.keys()) + assume(new_uri not in existing_uris) + + builder.set_redirect(new_uri, new_redirect) + + assert len(builder.config.redirects) == len(existing_uris) + 1 + assert builder.config.redirects[new_uri] == new_redirect + + +@settings(max_examples=100) +@given(uri=uri_strategy, old_redirect=uri_strategy, new_redirect=uri_strategy) +def test_set_env_overwrite(uri: Uri, old_redirect: Any, new_redirect: Any): + builder: ClientConfigBuilder = PolywrapClientConfigBuilder() + builder.config.redirects = {uri: old_redirect} + + builder.set_redirect(uri, new_redirect) + + assert builder.config.redirects == {uri: new_redirect} + + +@settings(max_examples=100) +@given(initial_redirects=redirects_strategy, new_redirects=redirects_strategy) +def test_set_redirects( + initial_redirects: Dict[Uri, Any], + new_redirects: Dict[Uri, Any], +): + builder: ClientConfigBuilder = PolywrapClientConfigBuilder() + builder.config.redirects = {**initial_redirects} + + builder.set_redirects(new_redirects) + + assert len(builder.config.envs) <= len(initial_redirects) + len(new_redirects) From 58fe2365d6cd4aaf2380523faa57ac90a83fee7a Mon Sep 17 00:00:00 2001 From: Niraj Kamdar Date: Sat, 10 Jun 2023 08:55:14 +0530 Subject: [PATCH 22/47] feat: add resolver tests --- .../tests/resolver/__init__.py | 0 .../tests/resolver/test_add_resolvers.py | 35 +++++++++++++++++++ .../tests/resolver/test_get_resolvers.py | 22 ++++++++++++ 3 files changed, 57 insertions(+) create mode 100644 packages/polywrap-client-config-builder/tests/resolver/__init__.py create mode 100644 packages/polywrap-client-config-builder/tests/resolver/test_add_resolvers.py create mode 100644 packages/polywrap-client-config-builder/tests/resolver/test_get_resolvers.py diff --git a/packages/polywrap-client-config-builder/tests/resolver/__init__.py b/packages/polywrap-client-config-builder/tests/resolver/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/packages/polywrap-client-config-builder/tests/resolver/test_add_resolvers.py b/packages/polywrap-client-config-builder/tests/resolver/test_add_resolvers.py new file mode 100644 index 00000000..eba6062d --- /dev/null +++ b/packages/polywrap-client-config-builder/tests/resolver/test_add_resolvers.py @@ -0,0 +1,35 @@ +from typing import Any, List +from hypothesis import given, settings + +from polywrap_client_config_builder import ( + ClientConfigBuilder, + PolywrapClientConfigBuilder, +) +from polywrap_core import UriResolver + +from ..strategies import resolvers_strategy, resolver_strategy + + +@settings(max_examples=100) +@given(resolvers=resolvers_strategy, new_resolver=resolver_strategy) +def test_add_resolver(resolvers: List[UriResolver], new_resolver: Any): + builder: ClientConfigBuilder = PolywrapClientConfigBuilder() + builder.config.resolvers = [*resolvers] + builder.add_resolver(new_resolver) + + assert len(builder.config.resolvers) == len(resolvers) + 1 + assert builder.config.resolvers[-1] == new_resolver + + +@settings(max_examples=100) +@given(initial_resolvers=resolvers_strategy, new_resolvers=resolvers_strategy) +def test_add_resolvers( + initial_resolvers: List[UriResolver], + new_resolvers: List[UriResolver], +): + builder: ClientConfigBuilder = PolywrapClientConfigBuilder() + builder.config.resolvers = [*initial_resolvers] + + builder.add_resolvers(new_resolvers) + + assert len(builder.config.resolvers) == len(initial_resolvers) + len(new_resolvers) diff --git a/packages/polywrap-client-config-builder/tests/resolver/test_get_resolvers.py b/packages/polywrap-client-config-builder/tests/resolver/test_get_resolvers.py new file mode 100644 index 00000000..eb78c419 --- /dev/null +++ b/packages/polywrap-client-config-builder/tests/resolver/test_get_resolvers.py @@ -0,0 +1,22 @@ +from typing import Any, Dict, List +from hypothesis import given, settings + +from polywrap_client_config_builder import ( + ClientConfigBuilder, + PolywrapClientConfigBuilder, +) +from polywrap_core import UriResolver + +from ..strategies import resolvers_strategy + + +@settings(max_examples=100) +@given(resolvers=resolvers_strategy) +def test_get_resolvers( + resolvers: List[UriResolver] +): + builder: ClientConfigBuilder = PolywrapClientConfigBuilder() + assert builder.get_resolvers() == [] + + builder.config.resolvers = resolvers + assert builder.get_resolvers() == resolvers From a1e7421c55e5d63a85ef91a649a75d34e129a5c3 Mon Sep 17 00:00:00 2001 From: Niraj Kamdar Date: Sat, 10 Jun 2023 09:05:24 +0530 Subject: [PATCH 23/47] refactor: black fixes --- .../polywrap_client_config_builder/configures/env_configure.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/polywrap-client-config-builder/polywrap_client_config_builder/configures/env_configure.py b/packages/polywrap-client-config-builder/polywrap_client_config_builder/configures/env_configure.py index ff7a5d8d..6157c3c0 100644 --- a/packages/polywrap-client-config-builder/polywrap_client_config_builder/configures/env_configure.py +++ b/packages/polywrap-client-config-builder/polywrap_client_config_builder/configures/env_configure.py @@ -73,4 +73,4 @@ def _merge_envs(env1: Dict[str, Any], env2: Dict[str, Any]) -> Dict[str, Any]: EnvConfigure._merge_envs(old_val, new_val) else: env1[key] = val - return env1 \ No newline at end of file + return env1 From bba3a0731ba6ee62f7faa0f40f069e872a90db19 Mon Sep 17 00:00:00 2001 From: Niraj Kamdar Date: Sat, 10 Jun 2023 09:23:20 +0530 Subject: [PATCH 24/47] debug: try adjusting examples produced with strategies --- .../tests/interface/test_remove_interface.py | 6 +++--- .../tests/strategies.py | 14 +++++++------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/packages/polywrap-client-config-builder/tests/interface/test_remove_interface.py b/packages/polywrap-client-config-builder/tests/interface/test_remove_interface.py index aa73d382..1b35f0bf 100644 --- a/packages/polywrap-client-config-builder/tests/interface/test_remove_interface.py +++ b/packages/polywrap-client-config-builder/tests/interface/test_remove_interface.py @@ -11,7 +11,7 @@ from ..strategies import interfaces_strategy -@settings(max_examples=100) +@settings(max_examples=50) @given(interfaces=interfaces_strategy) def test_remove_interface(interfaces: Dict[Uri, List[Uri]]): assume(interfaces) @@ -29,7 +29,7 @@ def test_remove_interface(interfaces: Dict[Uri, List[Uri]]): assert remove_uri not in builder.config.interfaces -@settings(max_examples=100) +@settings(max_examples=50) @given(interfaces=interfaces_strategy) def test_remove_non_existent_interface(interfaces: Dict[Uri, List[Uri]]): builder: ClientConfigBuilder = PolywrapClientConfigBuilder() @@ -39,7 +39,7 @@ def test_remove_non_existent_interface(interfaces: Dict[Uri, List[Uri]]): assert builder.config.interfaces == interfaces -@settings(max_examples=100) +@settings(max_examples=50) @given(interfaces=interfaces_strategy) def test_remove_interface_implementations(interfaces: Dict[Uri, List[Uri]]): assume(interfaces) diff --git a/packages/polywrap-client-config-builder/tests/strategies.py b/packages/polywrap-client-config-builder/tests/strategies.py index 3c97bf5f..8eba9382 100644 --- a/packages/polywrap-client-config-builder/tests/strategies.py +++ b/packages/polywrap-client-config-builder/tests/strategies.py @@ -32,28 +32,28 @@ uri_strategy = st.builds(Uri, uri_safe_chars_strategy, uri_safe_chars_strategy) # Env -env_strategy = st.dictionaries(st.text(), st.one_of(scalar_st_list)) +env_strategy = st.dictionaries(st.text(), st.one_of(scalar_st_list), max_size=10) envs_strategy = st.dictionaries( - uri_strategy, env_strategy + uri_strategy, env_strategy, max_size=10 ) # Interface Implementations -interfaces_strategy = st.dictionaries(uri_strategy, st.lists(uri_strategy)) +interfaces_strategy = st.dictionaries(uri_strategy, st.lists(uri_strategy, max_size=10), max_size=10) # URI Redirects -redirects_strategy = st.dictionaries(uri_strategy, uri_strategy) +redirects_strategy = st.dictionaries(uri_strategy, uri_strategy, max_size=10) # Resolver resolver_strategy = st.sampled_from(MockResolvers) -resolvers_strategy = st.lists(resolver_strategy) +resolvers_strategy = st.lists(resolver_strategy, max_size=10) # Wrapper wrapper_strategy = st.sampled_from(MockWrappers) -wrappers_strategy = st.dictionaries(uri_strategy, wrapper_strategy) +wrappers_strategy = st.dictionaries(uri_strategy, wrapper_strategy, max_size=10) # Packages package_strategy = st.sampled_from(MockPackages) -packages_strategy = st.dictionaries(uri_strategy, package_strategy) +packages_strategy = st.dictionaries(uri_strategy, package_strategy, max_size=10) # builder config builder_config_strategy = st.builds( From 970903f664095357804e0c4ee2bd4688dd9a2e61 Mon Sep 17 00:00:00 2001 From: Niraj Kamdar Date: Sat, 10 Jun 2023 18:59:07 +0530 Subject: [PATCH 25/47] debug: adjusting assumptions --- .../tests/interface/test_remove_interface.py | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/polywrap-client-config-builder/tests/interface/test_remove_interface.py b/packages/polywrap-client-config-builder/tests/interface/test_remove_interface.py index 1b35f0bf..116c4ce8 100644 --- a/packages/polywrap-client-config-builder/tests/interface/test_remove_interface.py +++ b/packages/polywrap-client-config-builder/tests/interface/test_remove_interface.py @@ -15,7 +15,6 @@ @given(interfaces=interfaces_strategy) def test_remove_interface(interfaces: Dict[Uri, List[Uri]]): assume(interfaces) - assume(all(interfaces[interface] for interface in interfaces)) builder: ClientConfigBuilder = PolywrapClientConfigBuilder() builder.config.interfaces = {**interfaces} From 9442be4253f30cdd0339d779b8af4f1d81bc8251 Mon Sep 17 00:00:00 2001 From: Niraj Kamdar Date: Sun, 11 Jun 2023 20:23:19 +0530 Subject: [PATCH 26/47] fix: docs --- docs/build.sh | 1 + docs/clean.sh | 1 + docs/docgen.sh | 8 + docs/poetry.lock | 497 +++++------------- docs/pyproject.toml | 4 +- docs/source/index.rst | 1 - .../polywrap_core.types.invoke_args.rst | 7 - .../polywrap_core.types.invoke_options.rst | 7 + ...lywrap_core.types.options.file_options.rst | 7 - ...wrap_core.types.options.invoke_options.rst | 7 - ...ap_core.types.options.manifest_options.rst | 7 - .../polywrap_core.types.options.rst | 21 - ...ore.types.options.uri_resolver_options.rst | 7 - .../polywrap-core/polywrap_core.types.rst | 12 +- .../polywrap_core.types.uri_like.rst | 7 - ...rap_core.utils.build_clean_uri_history.rst | 7 + ...ore.utils.get_env_from_resolution_path.rst | 7 + ...olywrap_core.utils.get_implementations.rst | 7 + .../polywrap_core.utils.instance_of.rst | 7 - .../polywrap_core.utils.maybe_async.rst | 7 - .../polywrap-core/polywrap_core.utils.rst | 5 +- .../polywrap_manifest.errors.rst | 7 + .../polywrap-manifest/polywrap_manifest.rst | 1 + .../polywrap_msgpack.errors.rst} | 4 +- .../polywrap-msgpack/polywrap_msgpack.rst | 1 + ...gin.resolution_context_override_client.rst | 7 + .../polywrap-plugin/polywrap_plugin.rst | 1 + ...rap_uri_resolvers.resolvers.aggregator.rst | 1 + ...ggregator.uri_resolver_aggregator_base.rst | 7 + ...solvers.resolvers.cache.cache_resolver.rst | 7 - ...cache.resolution_result_cache_resolver.rst | 7 + ...polywrap_uri_resolvers.resolvers.cache.rst | 3 +- ...rs.legacy.package_to_wrapper_resolver.rst} | 4 +- ...olywrap_uri_resolvers.resolvers.legacy.rst | 10 + ....wrapper_cache.in_memory_wrapper_cache.rst | 7 + ...solvers.resolvers.legacy.wrapper_cache.rst | 19 + ...ers.legacy.wrapper_cache.wrapper_cache.rst | 7 + ...esolvers.legacy.wrapper_cache_resolver.rst | 7 + ...rs.package.package_to_wrapper_resolver.rst | 7 - ...lywrap_uri_resolvers.resolvers.package.rst | 1 - .../polywrap_uri_resolvers.rst | 1 - ...rs.types.cache.in_memory_wrapper_cache.rst | 7 - ...ache.in_memory_resolution_result_cache.rst | 7 + ...n_result_cache.resolution_result_cache.rst | 7 + ...rs.types.cache.resolution_result_cache.rst | 19 + .../polywrap_uri_resolvers.types.cache.rst | 7 +- ...ri_resolvers.types.cache.wrapper_cache.rst | 7 - .../polywrap_uri_resolvers.types.rst | 1 - ...resolvers.types.uri_resolution_context.rst | 19 - ...olution_context.uri_resolution_context.rst | 7 - ...resolution_context.uri_resolution_step.rst | 7 - ...esolvers.utils.build_clean_uri_history.rst | 7 - ...solvers.utils.get_env_from_uri_history.rst | 7 - ...esolvers.utils.get_uri_resolution_path.rst | 7 - .../polywrap_uri_resolvers.utils.rst | 20 - .../polywrap-wasm/polywrap_wasm.imports.rst | 1 - .../polywrap_wasm.imports.utils.rst | 18 - ...ywrap_wasm.imports.utils.unsync_invoke.rst | 7 - docs/tox.ini | 29 + .../configures/base_configure.py | 8 +- 60 files changed, 333 insertions(+), 602 deletions(-) create mode 100644 docs/build.sh create mode 100644 docs/clean.sh create mode 100644 docs/docgen.sh delete mode 100644 docs/source/polywrap-core/polywrap_core.types.invoke_args.rst create mode 100644 docs/source/polywrap-core/polywrap_core.types.invoke_options.rst delete mode 100644 docs/source/polywrap-core/polywrap_core.types.options.file_options.rst delete mode 100644 docs/source/polywrap-core/polywrap_core.types.options.invoke_options.rst delete mode 100644 docs/source/polywrap-core/polywrap_core.types.options.manifest_options.rst delete mode 100644 docs/source/polywrap-core/polywrap_core.types.options.rst delete mode 100644 docs/source/polywrap-core/polywrap_core.types.options.uri_resolver_options.rst delete mode 100644 docs/source/polywrap-core/polywrap_core.types.uri_like.rst create mode 100644 docs/source/polywrap-core/polywrap_core.utils.build_clean_uri_history.rst create mode 100644 docs/source/polywrap-core/polywrap_core.utils.get_env_from_resolution_path.rst create mode 100644 docs/source/polywrap-core/polywrap_core.utils.get_implementations.rst delete mode 100644 docs/source/polywrap-core/polywrap_core.utils.instance_of.rst delete mode 100644 docs/source/polywrap-core/polywrap_core.utils.maybe_async.rst create mode 100644 docs/source/polywrap-manifest/polywrap_manifest.errors.rst rename docs/source/{polywrap-core/polywrap_core.types.env.rst => polywrap-msgpack/polywrap_msgpack.errors.rst} (54%) create mode 100644 docs/source/polywrap-plugin/polywrap_plugin.resolution_context_override_client.rst create mode 100644 docs/source/polywrap-uri-resolvers/polywrap_uri_resolvers.resolvers.aggregator.uri_resolver_aggregator_base.rst delete mode 100644 docs/source/polywrap-uri-resolvers/polywrap_uri_resolvers.resolvers.cache.cache_resolver.rst create mode 100644 docs/source/polywrap-uri-resolvers/polywrap_uri_resolvers.resolvers.cache.resolution_result_cache_resolver.rst rename docs/source/polywrap-uri-resolvers/{polywrap_uri_resolvers.resolvers.cache.request_synchronizer_resolver.rst => polywrap_uri_resolvers.resolvers.legacy.package_to_wrapper_resolver.rst} (50%) create mode 100644 docs/source/polywrap-uri-resolvers/polywrap_uri_resolvers.resolvers.legacy.wrapper_cache.in_memory_wrapper_cache.rst create mode 100644 docs/source/polywrap-uri-resolvers/polywrap_uri_resolvers.resolvers.legacy.wrapper_cache.rst create mode 100644 docs/source/polywrap-uri-resolvers/polywrap_uri_resolvers.resolvers.legacy.wrapper_cache.wrapper_cache.rst create mode 100644 docs/source/polywrap-uri-resolvers/polywrap_uri_resolvers.resolvers.legacy.wrapper_cache_resolver.rst delete mode 100644 docs/source/polywrap-uri-resolvers/polywrap_uri_resolvers.resolvers.package.package_to_wrapper_resolver.rst delete mode 100644 docs/source/polywrap-uri-resolvers/polywrap_uri_resolvers.types.cache.in_memory_wrapper_cache.rst create mode 100644 docs/source/polywrap-uri-resolvers/polywrap_uri_resolvers.types.cache.resolution_result_cache.in_memory_resolution_result_cache.rst create mode 100644 docs/source/polywrap-uri-resolvers/polywrap_uri_resolvers.types.cache.resolution_result_cache.resolution_result_cache.rst create mode 100644 docs/source/polywrap-uri-resolvers/polywrap_uri_resolvers.types.cache.resolution_result_cache.rst delete mode 100644 docs/source/polywrap-uri-resolvers/polywrap_uri_resolvers.types.cache.wrapper_cache.rst delete mode 100644 docs/source/polywrap-uri-resolvers/polywrap_uri_resolvers.types.uri_resolution_context.rst delete mode 100644 docs/source/polywrap-uri-resolvers/polywrap_uri_resolvers.types.uri_resolution_context.uri_resolution_context.rst delete mode 100644 docs/source/polywrap-uri-resolvers/polywrap_uri_resolvers.types.uri_resolution_context.uri_resolution_step.rst delete mode 100644 docs/source/polywrap-uri-resolvers/polywrap_uri_resolvers.utils.build_clean_uri_history.rst delete mode 100644 docs/source/polywrap-uri-resolvers/polywrap_uri_resolvers.utils.get_env_from_uri_history.rst delete mode 100644 docs/source/polywrap-uri-resolvers/polywrap_uri_resolvers.utils.get_uri_resolution_path.rst delete mode 100644 docs/source/polywrap-uri-resolvers/polywrap_uri_resolvers.utils.rst delete mode 100644 docs/source/polywrap-wasm/polywrap_wasm.imports.utils.rst delete mode 100644 docs/source/polywrap-wasm/polywrap_wasm.imports.utils.unsync_invoke.rst create mode 100644 docs/tox.ini diff --git a/docs/build.sh b/docs/build.sh new file mode 100644 index 00000000..44432917 --- /dev/null +++ b/docs/build.sh @@ -0,0 +1 @@ +sphinx-build source/ build diff --git a/docs/clean.sh b/docs/clean.sh new file mode 100644 index 00000000..e0b9d282 --- /dev/null +++ b/docs/clean.sh @@ -0,0 +1 @@ +rm -Rf ./source/**/*.rst diff --git a/docs/docgen.sh b/docs/docgen.sh new file mode 100644 index 00000000..d8eeb376 --- /dev/null +++ b/docs/docgen.sh @@ -0,0 +1,8 @@ +sphinx-apidoc ../packages/polywrap-msgpack/polywrap_msgpack -o ./source/polywrap-msgpack -e +sphinx-apidoc ../packages/polywrap-manifest/polywrap_manifest -o ./source/polywrap-manifest -e +sphinx-apidoc ../packages/polywrap-core/polywrap_core -o ./source/polywrap-core -e +sphinx-apidoc ../packages/polywrap-wasm/polywrap_wasm -o ./source/polywrap-wasm -e +sphinx-apidoc ../packages/polywrap-plugin/polywrap_plugin -o ./source/polywrap-plugin -e +sphinx-apidoc ../packages/polywrap-uri-resolvers/polywrap_uri_resolvers -o ./source/polywrap-uri-resolvers -e +sphinx-apidoc ../packages/polywrap-client/polywrap_client -o ./source/polywrap-client -e +sphinx-apidoc ../packages/polywrap-client-config-builder/polywrap_client_config_builder -o ./source/polywrap-client-config-builder -e diff --git a/docs/poetry.lock b/docs/poetry.lock index 6474e47e..a0abc76f 100644 --- a/docs/poetry.lock +++ b/docs/poetry.lock @@ -24,28 +24,16 @@ files = [ {file = "Babel-2.12.1.tar.gz", hash = "sha256:cc2d99999cd01d44420ae725a21c9e3711b3aadc7976d6147f622d8581963455"}, ] -[[package]] -name = "backoff" -version = "2.2.1" -description = "Function decoration for backoff and retry" -category = "main" -optional = false -python-versions = ">=3.7,<4.0" -files = [ - {file = "backoff-2.2.1-py3-none-any.whl", hash = "sha256:63579f9a0628e06278f7e47b7d7d5b6ce20dc65c5e96a6f3ca99a6adca0396e8"}, - {file = "backoff-2.2.1.tar.gz", hash = "sha256:03f829f5bb1923180821643f8753b0502c3b682293992485b0eef2807afa5cba"}, -] - [[package]] name = "certifi" -version = "2022.12.7" +version = "2023.5.7" description = "Python package for providing Mozilla's CA Bundle." category = "dev" optional = false python-versions = ">=3.6" files = [ - {file = "certifi-2022.12.7-py3-none-any.whl", hash = "sha256:4ad3232f5e926d6718ec31cfc1fcadfde020920e278684144551c91769c7bc18"}, - {file = "certifi-2022.12.7.tar.gz", hash = "sha256:35824b4c3a97115964b408844d64aa14db1cc518f6562e8d7261699d1350a9e3"}, + {file = "certifi-2023.5.7-py3-none-any.whl", hash = "sha256:c6c2e98f5c7869efca1f8916fed228dd91539f9f1b444c314c06eef02980c716"}, + {file = "certifi-2023.5.7.tar.gz", hash = "sha256:0f0d56dc5a6ad56fd4ba36484d6cc34451e1c6548c61daad8c320169f91eddc7"}, ] [[package]] @@ -157,50 +145,11 @@ files = [ {file = "docutils-0.18.1.tar.gz", hash = "sha256:679987caf361a7539d76e584cbeddc311e3aee937877c87346f31debc63e9d06"}, ] -[[package]] -name = "gql" -version = "3.4.0" -description = "GraphQL client for Python" -category = "main" -optional = false -python-versions = "*" -files = [ - {file = "gql-3.4.0-py2.py3-none-any.whl", hash = "sha256:59c8a0b8f0a2f3b0b2ff970c94de86f82f65cb1da3340bfe57143e5f7ea82f71"}, - {file = "gql-3.4.0.tar.gz", hash = "sha256:ca81aa8314fa88a8c57dd1ce34941278e0c352d762eb721edcba0387829ea7c0"}, -] - -[package.dependencies] -backoff = ">=1.11.1,<3.0" -graphql-core = ">=3.2,<3.3" -yarl = ">=1.6,<2.0" - -[package.extras] -aiohttp = ["aiohttp (>=3.7.1,<3.9.0)"] -all = ["aiohttp (>=3.7.1,<3.9.0)", "botocore (>=1.21,<2)", "requests (>=2.26,<3)", "requests-toolbelt (>=0.9.1,<1)", "urllib3 (>=1.26)", "websockets (>=10,<11)", "websockets (>=9,<10)"] -botocore = ["botocore (>=1.21,<2)"] -dev = ["aiofiles", "aiohttp (>=3.7.1,<3.9.0)", "black (==22.3.0)", "botocore (>=1.21,<2)", "check-manifest (>=0.42,<1)", "flake8 (==3.8.1)", "isort (==4.3.21)", "mock (==4.0.2)", "mypy (==0.910)", "parse (==1.15.0)", "pytest (==6.2.5)", "pytest-asyncio (==0.16.0)", "pytest-console-scripts (==1.3.1)", "pytest-cov (==3.0.0)", "requests (>=2.26,<3)", "requests-toolbelt (>=0.9.1,<1)", "sphinx (>=3.0.0,<4)", "sphinx-argparse (==0.2.5)", "sphinx-rtd-theme (>=0.4,<1)", "types-aiofiles", "types-mock", "types-requests", "urllib3 (>=1.26)", "vcrpy (==4.0.2)", "websockets (>=10,<11)", "websockets (>=9,<10)"] -requests = ["requests (>=2.26,<3)", "requests-toolbelt (>=0.9.1,<1)", "urllib3 (>=1.26)"] -test = ["aiofiles", "aiohttp (>=3.7.1,<3.9.0)", "botocore (>=1.21,<2)", "mock (==4.0.2)", "parse (==1.15.0)", "pytest (==6.2.5)", "pytest-asyncio (==0.16.0)", "pytest-console-scripts (==1.3.1)", "pytest-cov (==3.0.0)", "requests (>=2.26,<3)", "requests-toolbelt (>=0.9.1,<1)", "urllib3 (>=1.26)", "vcrpy (==4.0.2)", "websockets (>=10,<11)", "websockets (>=9,<10)"] -test-no-transport = ["aiofiles", "mock (==4.0.2)", "parse (==1.15.0)", "pytest (==6.2.5)", "pytest-asyncio (==0.16.0)", "pytest-console-scripts (==1.3.1)", "pytest-cov (==3.0.0)", "vcrpy (==4.0.2)"] -websockets = ["websockets (>=10,<11)", "websockets (>=9,<10)"] - -[[package]] -name = "graphql-core" -version = "3.2.3" -description = "GraphQL implementation for Python, a port of GraphQL.js, the JavaScript reference implementation for GraphQL." -category = "main" -optional = false -python-versions = ">=3.6,<4" -files = [ - {file = "graphql-core-3.2.3.tar.gz", hash = "sha256:06d2aad0ac723e35b1cb47885d3e5c45e956a53bc1b209a9fc5369007fe46676"}, - {file = "graphql_core-3.2.3-py3-none-any.whl", hash = "sha256:5766780452bd5ec8ba133f8bf287dc92713e3868ddd83aee4faab9fc3e303dc3"}, -] - [[package]] name = "idna" version = "3.4" description = "Internationalized Domain Names in Applications (IDNA)" -category = "main" +category = "dev" optional = false python-versions = ">=3.5" files = [ @@ -240,62 +189,62 @@ i18n = ["Babel (>=2.7)"] [[package]] name = "markupsafe" -version = "2.1.2" +version = "2.1.3" description = "Safely add untrusted strings to HTML/XML markup." category = "dev" optional = false python-versions = ">=3.7" files = [ - {file = "MarkupSafe-2.1.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:665a36ae6f8f20a4676b53224e33d456a6f5a72657d9c83c2aa00765072f31f7"}, - {file = "MarkupSafe-2.1.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:340bea174e9761308703ae988e982005aedf427de816d1afe98147668cc03036"}, - {file = "MarkupSafe-2.1.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:22152d00bf4a9c7c83960521fc558f55a1adbc0631fbb00a9471e097b19d72e1"}, - {file = "MarkupSafe-2.1.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:28057e985dace2f478e042eaa15606c7efccb700797660629da387eb289b9323"}, - {file = "MarkupSafe-2.1.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ca244fa73f50a800cf8c3ebf7fd93149ec37f5cb9596aa8873ae2c1d23498601"}, - {file = "MarkupSafe-2.1.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:d9d971ec1e79906046aa3ca266de79eac42f1dbf3612a05dc9368125952bd1a1"}, - {file = "MarkupSafe-2.1.2-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:7e007132af78ea9df29495dbf7b5824cb71648d7133cf7848a2a5dd00d36f9ff"}, - {file = "MarkupSafe-2.1.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:7313ce6a199651c4ed9d7e4cfb4aa56fe923b1adf9af3b420ee14e6d9a73df65"}, - {file = "MarkupSafe-2.1.2-cp310-cp310-win32.whl", hash = "sha256:c4a549890a45f57f1ebf99c067a4ad0cb423a05544accaf2b065246827ed9603"}, - {file = "MarkupSafe-2.1.2-cp310-cp310-win_amd64.whl", hash = "sha256:835fb5e38fd89328e9c81067fd642b3593c33e1e17e2fdbf77f5676abb14a156"}, - {file = "MarkupSafe-2.1.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:2ec4f2d48ae59bbb9d1f9d7efb9236ab81429a764dedca114f5fdabbc3788013"}, - {file = "MarkupSafe-2.1.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:608e7073dfa9e38a85d38474c082d4281f4ce276ac0010224eaba11e929dd53a"}, - {file = "MarkupSafe-2.1.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:65608c35bfb8a76763f37036547f7adfd09270fbdbf96608be2bead319728fcd"}, - {file = "MarkupSafe-2.1.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f2bfb563d0211ce16b63c7cb9395d2c682a23187f54c3d79bfec33e6705473c6"}, - {file = "MarkupSafe-2.1.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:da25303d91526aac3672ee6d49a2f3db2d9502a4a60b55519feb1a4c7714e07d"}, - {file = "MarkupSafe-2.1.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:9cad97ab29dfc3f0249b483412c85c8ef4766d96cdf9dcf5a1e3caa3f3661cf1"}, - {file = "MarkupSafe-2.1.2-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:085fd3201e7b12809f9e6e9bc1e5c96a368c8523fad5afb02afe3c051ae4afcc"}, - {file = "MarkupSafe-2.1.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:1bea30e9bf331f3fef67e0a3877b2288593c98a21ccb2cf29b74c581a4eb3af0"}, - {file = "MarkupSafe-2.1.2-cp311-cp311-win32.whl", hash = "sha256:7df70907e00c970c60b9ef2938d894a9381f38e6b9db73c5be35e59d92e06625"}, - {file = "MarkupSafe-2.1.2-cp311-cp311-win_amd64.whl", hash = "sha256:e55e40ff0cc8cc5c07996915ad367fa47da6b3fc091fdadca7f5403239c5fec3"}, - {file = "MarkupSafe-2.1.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:a6e40afa7f45939ca356f348c8e23048e02cb109ced1eb8420961b2f40fb373a"}, - {file = "MarkupSafe-2.1.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cf877ab4ed6e302ec1d04952ca358b381a882fbd9d1b07cccbfd61783561f98a"}, - {file = "MarkupSafe-2.1.2-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:63ba06c9941e46fa389d389644e2d8225e0e3e5ebcc4ff1ea8506dce646f8c8a"}, - {file = "MarkupSafe-2.1.2-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f1cd098434e83e656abf198f103a8207a8187c0fc110306691a2e94a78d0abb2"}, - {file = "MarkupSafe-2.1.2-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:55f44b440d491028addb3b88f72207d71eeebfb7b5dbf0643f7c023ae1fba619"}, - {file = "MarkupSafe-2.1.2-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:a6f2fcca746e8d5910e18782f976489939d54a91f9411c32051b4aab2bd7c513"}, - {file = "MarkupSafe-2.1.2-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:0b462104ba25f1ac006fdab8b6a01ebbfbce9ed37fd37fd4acd70c67c973e460"}, - {file = "MarkupSafe-2.1.2-cp37-cp37m-win32.whl", hash = "sha256:7668b52e102d0ed87cb082380a7e2e1e78737ddecdde129acadb0eccc5423859"}, - {file = "MarkupSafe-2.1.2-cp37-cp37m-win_amd64.whl", hash = "sha256:6d6607f98fcf17e534162f0709aaad3ab7a96032723d8ac8750ffe17ae5a0666"}, - {file = "MarkupSafe-2.1.2-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:a806db027852538d2ad7555b203300173dd1b77ba116de92da9afbc3a3be3eed"}, - {file = "MarkupSafe-2.1.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:a4abaec6ca3ad8660690236d11bfe28dfd707778e2442b45addd2f086d6ef094"}, - {file = "MarkupSafe-2.1.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f03a532d7dee1bed20bc4884194a16160a2de9ffc6354b3878ec9682bb623c54"}, - {file = "MarkupSafe-2.1.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4cf06cdc1dda95223e9d2d3c58d3b178aa5dacb35ee7e3bbac10e4e1faacb419"}, - {file = "MarkupSafe-2.1.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:22731d79ed2eb25059ae3df1dfc9cb1546691cc41f4e3130fe6bfbc3ecbbecfa"}, - {file = "MarkupSafe-2.1.2-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:f8ffb705ffcf5ddd0e80b65ddf7bed7ee4f5a441ea7d3419e861a12eaf41af58"}, - {file = "MarkupSafe-2.1.2-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:8db032bf0ce9022a8e41a22598eefc802314e81b879ae093f36ce9ddf39ab1ba"}, - {file = "MarkupSafe-2.1.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:2298c859cfc5463f1b64bd55cb3e602528db6fa0f3cfd568d3605c50678f8f03"}, - {file = "MarkupSafe-2.1.2-cp38-cp38-win32.whl", hash = "sha256:50c42830a633fa0cf9e7d27664637532791bfc31c731a87b202d2d8ac40c3ea2"}, - {file = "MarkupSafe-2.1.2-cp38-cp38-win_amd64.whl", hash = "sha256:bb06feb762bade6bf3c8b844462274db0c76acc95c52abe8dbed28ae3d44a147"}, - {file = "MarkupSafe-2.1.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:99625a92da8229df6d44335e6fcc558a5037dd0a760e11d84be2260e6f37002f"}, - {file = "MarkupSafe-2.1.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:8bca7e26c1dd751236cfb0c6c72d4ad61d986e9a41bbf76cb445f69488b2a2bd"}, - {file = "MarkupSafe-2.1.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:40627dcf047dadb22cd25ea7ecfe9cbf3bbbad0482ee5920b582f3809c97654f"}, - {file = "MarkupSafe-2.1.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:40dfd3fefbef579ee058f139733ac336312663c6706d1163b82b3003fb1925c4"}, - {file = "MarkupSafe-2.1.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:090376d812fb6ac5f171e5938e82e7f2d7adc2b629101cec0db8b267815c85e2"}, - {file = "MarkupSafe-2.1.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:2e7821bffe00aa6bd07a23913b7f4e01328c3d5cc0b40b36c0bd81d362faeb65"}, - {file = "MarkupSafe-2.1.2-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:c0a33bc9f02c2b17c3ea382f91b4db0e6cde90b63b296422a939886a7a80de1c"}, - {file = "MarkupSafe-2.1.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:b8526c6d437855442cdd3d87eede9c425c4445ea011ca38d937db299382e6fa3"}, - {file = "MarkupSafe-2.1.2-cp39-cp39-win32.whl", hash = "sha256:137678c63c977754abe9086a3ec011e8fd985ab90631145dfb9294ad09c102a7"}, - {file = "MarkupSafe-2.1.2-cp39-cp39-win_amd64.whl", hash = "sha256:0576fe974b40a400449768941d5d0858cc624e3249dfd1e0c33674e5c7ca7aed"}, - {file = "MarkupSafe-2.1.2.tar.gz", hash = "sha256:abcabc8c2b26036d62d4c746381a6f7cf60aafcc653198ad678306986b09450d"}, + {file = "MarkupSafe-2.1.3-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:cd0f502fe016460680cd20aaa5a76d241d6f35a1c3350c474bac1273803893fa"}, + {file = "MarkupSafe-2.1.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e09031c87a1e51556fdcb46e5bd4f59dfb743061cf93c4d6831bf894f125eb57"}, + {file = "MarkupSafe-2.1.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:68e78619a61ecf91e76aa3e6e8e33fc4894a2bebe93410754bd28fce0a8a4f9f"}, + {file = "MarkupSafe-2.1.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:65c1a9bcdadc6c28eecee2c119465aebff8f7a584dd719facdd9e825ec61ab52"}, + {file = "MarkupSafe-2.1.3-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:525808b8019e36eb524b8c68acdd63a37e75714eac50e988180b169d64480a00"}, + {file = "MarkupSafe-2.1.3-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:962f82a3086483f5e5f64dbad880d31038b698494799b097bc59c2edf392fce6"}, + {file = "MarkupSafe-2.1.3-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:aa7bd130efab1c280bed0f45501b7c8795f9fdbeb02e965371bbef3523627779"}, + {file = "MarkupSafe-2.1.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:c9c804664ebe8f83a211cace637506669e7890fec1b4195b505c214e50dd4eb7"}, + {file = "MarkupSafe-2.1.3-cp310-cp310-win32.whl", hash = "sha256:10bbfe99883db80bdbaff2dcf681dfc6533a614f700da1287707e8a5d78a8431"}, + {file = "MarkupSafe-2.1.3-cp310-cp310-win_amd64.whl", hash = "sha256:1577735524cdad32f9f694208aa75e422adba74f1baee7551620e43a3141f559"}, + {file = "MarkupSafe-2.1.3-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:ad9e82fb8f09ade1c3e1b996a6337afac2b8b9e365f926f5a61aacc71adc5b3c"}, + {file = "MarkupSafe-2.1.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:3c0fae6c3be832a0a0473ac912810b2877c8cb9d76ca48de1ed31e1c68386575"}, + {file = "MarkupSafe-2.1.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b076b6226fb84157e3f7c971a47ff3a679d837cf338547532ab866c57930dbee"}, + {file = "MarkupSafe-2.1.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bfce63a9e7834b12b87c64d6b155fdd9b3b96191b6bd334bf37db7ff1fe457f2"}, + {file = "MarkupSafe-2.1.3-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:338ae27d6b8745585f87218a3f23f1512dbf52c26c28e322dbe54bcede54ccb9"}, + {file = "MarkupSafe-2.1.3-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:e4dd52d80b8c83fdce44e12478ad2e85c64ea965e75d66dbeafb0a3e77308fcc"}, + {file = "MarkupSafe-2.1.3-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:df0be2b576a7abbf737b1575f048c23fb1d769f267ec4358296f31c2479db8f9"}, + {file = "MarkupSafe-2.1.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:5bbe06f8eeafd38e5d0a4894ffec89378b6c6a625ff57e3028921f8ff59318ac"}, + {file = "MarkupSafe-2.1.3-cp311-cp311-win32.whl", hash = "sha256:dd15ff04ffd7e05ffcb7fe79f1b98041b8ea30ae9234aed2a9168b5797c3effb"}, + {file = "MarkupSafe-2.1.3-cp311-cp311-win_amd64.whl", hash = "sha256:134da1eca9ec0ae528110ccc9e48041e0828d79f24121a1a146161103c76e686"}, + {file = "MarkupSafe-2.1.3-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:8e254ae696c88d98da6555f5ace2279cf7cd5b3f52be2b5cf97feafe883b58d2"}, + {file = "MarkupSafe-2.1.3-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cb0932dc158471523c9637e807d9bfb93e06a95cbf010f1a38b98623b929ef2b"}, + {file = "MarkupSafe-2.1.3-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9402b03f1a1b4dc4c19845e5c749e3ab82d5078d16a2a4c2cd2df62d57bb0707"}, + {file = "MarkupSafe-2.1.3-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ca379055a47383d02a5400cb0d110cef0a776fc644cda797db0c5696cfd7e18e"}, + {file = "MarkupSafe-2.1.3-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:b7ff0f54cb4ff66dd38bebd335a38e2c22c41a8ee45aa608efc890ac3e3931bc"}, + {file = "MarkupSafe-2.1.3-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:c011a4149cfbcf9f03994ec2edffcb8b1dc2d2aede7ca243746df97a5d41ce48"}, + {file = "MarkupSafe-2.1.3-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:56d9f2ecac662ca1611d183feb03a3fa4406469dafe241673d521dd5ae92a155"}, + {file = "MarkupSafe-2.1.3-cp37-cp37m-win32.whl", hash = "sha256:8758846a7e80910096950b67071243da3e5a20ed2546e6392603c096778d48e0"}, + {file = "MarkupSafe-2.1.3-cp37-cp37m-win_amd64.whl", hash = "sha256:787003c0ddb00500e49a10f2844fac87aa6ce977b90b0feaaf9de23c22508b24"}, + {file = "MarkupSafe-2.1.3-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:2ef12179d3a291be237280175b542c07a36e7f60718296278d8593d21ca937d4"}, + {file = "MarkupSafe-2.1.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:2c1b19b3aaacc6e57b7e25710ff571c24d6c3613a45e905b1fde04d691b98ee0"}, + {file = "MarkupSafe-2.1.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8afafd99945ead6e075b973fefa56379c5b5c53fd8937dad92c662da5d8fd5ee"}, + {file = "MarkupSafe-2.1.3-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8c41976a29d078bb235fea9b2ecd3da465df42a562910f9022f1a03107bd02be"}, + {file = "MarkupSafe-2.1.3-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d080e0a5eb2529460b30190fcfcc4199bd7f827663f858a226a81bc27beaa97e"}, + {file = "MarkupSafe-2.1.3-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:69c0f17e9f5a7afdf2cc9fb2d1ce6aabdb3bafb7f38017c0b77862bcec2bbad8"}, + {file = "MarkupSafe-2.1.3-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:504b320cd4b7eff6f968eddf81127112db685e81f7e36e75f9f84f0df46041c3"}, + {file = "MarkupSafe-2.1.3-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:42de32b22b6b804f42c5d98be4f7e5e977ecdd9ee9b660fda1a3edf03b11792d"}, + {file = "MarkupSafe-2.1.3-cp38-cp38-win32.whl", hash = "sha256:ceb01949af7121f9fc39f7d27f91be8546f3fb112c608bc4029aef0bab86a2a5"}, + {file = "MarkupSafe-2.1.3-cp38-cp38-win_amd64.whl", hash = "sha256:1b40069d487e7edb2676d3fbdb2b0829ffa2cd63a2ec26c4938b2d34391b4ecc"}, + {file = "MarkupSafe-2.1.3-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:8023faf4e01efadfa183e863fefde0046de576c6f14659e8782065bcece22198"}, + {file = "MarkupSafe-2.1.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:6b2b56950d93e41f33b4223ead100ea0fe11f8e6ee5f641eb753ce4b77a7042b"}, + {file = "MarkupSafe-2.1.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9dcdfd0eaf283af041973bff14a2e143b8bd64e069f4c383416ecd79a81aab58"}, + {file = "MarkupSafe-2.1.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:05fb21170423db021895e1ea1e1f3ab3adb85d1c2333cbc2310f2a26bc77272e"}, + {file = "MarkupSafe-2.1.3-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:282c2cb35b5b673bbcadb33a585408104df04f14b2d9b01d4c345a3b92861c2c"}, + {file = "MarkupSafe-2.1.3-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:ab4a0df41e7c16a1392727727e7998a467472d0ad65f3ad5e6e765015df08636"}, + {file = "MarkupSafe-2.1.3-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:7ef3cb2ebbf91e330e3bb937efada0edd9003683db6b57bb108c4001f37a02ea"}, + {file = "MarkupSafe-2.1.3-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:0a4e4a1aff6c7ac4cd55792abf96c915634c2b97e3cc1c7129578aa68ebd754e"}, + {file = "MarkupSafe-2.1.3-cp39-cp39-win32.whl", hash = "sha256:fec21693218efe39aa7f8599346e90c705afa52c5b31ae019b2e57e8f6542bb2"}, + {file = "MarkupSafe-2.1.3-cp39-cp39-win_amd64.whl", hash = "sha256:3fd4abcb888d15a94f32b75d8fd18ee162ca0c064f35b11134be77050296d6ba"}, + {file = "MarkupSafe-2.1.3.tar.gz", hash = "sha256:af598ed32d6ae86f1b747b82783958b1a4ab8f617b06fe68795c7f026abbdcad"}, ] [[package]] @@ -371,105 +320,21 @@ files = [ {file = "msgpack-1.0.5.tar.gz", hash = "sha256:c075544284eadc5cddc70f4757331d99dcbc16b2bbd4849d15f8aae4cf36d31c"}, ] -[[package]] -name = "multidict" -version = "6.0.4" -description = "multidict implementation" -category = "main" -optional = false -python-versions = ">=3.7" -files = [ - {file = "multidict-6.0.4-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:0b1a97283e0c85772d613878028fec909f003993e1007eafa715b24b377cb9b8"}, - {file = "multidict-6.0.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:eeb6dcc05e911516ae3d1f207d4b0520d07f54484c49dfc294d6e7d63b734171"}, - {file = "multidict-6.0.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:d6d635d5209b82a3492508cf5b365f3446afb65ae7ebd755e70e18f287b0adf7"}, - {file = "multidict-6.0.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c048099e4c9e9d615545e2001d3d8a4380bd403e1a0578734e0d31703d1b0c0b"}, - {file = "multidict-6.0.4-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ea20853c6dbbb53ed34cb4d080382169b6f4554d394015f1bef35e881bf83547"}, - {file = "multidict-6.0.4-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:16d232d4e5396c2efbbf4f6d4df89bfa905eb0d4dc5b3549d872ab898451f569"}, - {file = "multidict-6.0.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:36c63aaa167f6c6b04ef2c85704e93af16c11d20de1d133e39de6a0e84582a93"}, - {file = "multidict-6.0.4-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:64bdf1086b6043bf519869678f5f2757f473dee970d7abf6da91ec00acb9cb98"}, - {file = "multidict-6.0.4-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:43644e38f42e3af682690876cff722d301ac585c5b9e1eacc013b7a3f7b696a0"}, - {file = "multidict-6.0.4-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:7582a1d1030e15422262de9f58711774e02fa80df0d1578995c76214f6954988"}, - {file = "multidict-6.0.4-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:ddff9c4e225a63a5afab9dd15590432c22e8057e1a9a13d28ed128ecf047bbdc"}, - {file = "multidict-6.0.4-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:ee2a1ece51b9b9e7752e742cfb661d2a29e7bcdba2d27e66e28a99f1890e4fa0"}, - {file = "multidict-6.0.4-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:a2e4369eb3d47d2034032a26c7a80fcb21a2cb22e1173d761a162f11e562caa5"}, - {file = "multidict-6.0.4-cp310-cp310-win32.whl", hash = "sha256:574b7eae1ab267e5f8285f0fe881f17efe4b98c39a40858247720935b893bba8"}, - {file = "multidict-6.0.4-cp310-cp310-win_amd64.whl", hash = "sha256:4dcbb0906e38440fa3e325df2359ac6cb043df8e58c965bb45f4e406ecb162cc"}, - {file = "multidict-6.0.4-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:0dfad7a5a1e39c53ed00d2dd0c2e36aed4650936dc18fd9a1826a5ae1cad6f03"}, - {file = "multidict-6.0.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:64da238a09d6039e3bd39bb3aee9c21a5e34f28bfa5aa22518581f910ff94af3"}, - {file = "multidict-6.0.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:ff959bee35038c4624250473988b24f846cbeb2c6639de3602c073f10410ceba"}, - {file = "multidict-6.0.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:01a3a55bd90018c9c080fbb0b9f4891db37d148a0a18722b42f94694f8b6d4c9"}, - {file = "multidict-6.0.4-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c5cb09abb18c1ea940fb99360ea0396f34d46566f157122c92dfa069d3e0e982"}, - {file = "multidict-6.0.4-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:666daae833559deb2d609afa4490b85830ab0dfca811a98b70a205621a6109fe"}, - {file = "multidict-6.0.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:11bdf3f5e1518b24530b8241529d2050014c884cf18b6fc69c0c2b30ca248710"}, - {file = "multidict-6.0.4-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7d18748f2d30f94f498e852c67d61261c643b349b9d2a581131725595c45ec6c"}, - {file = "multidict-6.0.4-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:458f37be2d9e4c95e2d8866a851663cbc76e865b78395090786f6cd9b3bbf4f4"}, - {file = "multidict-6.0.4-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:b1a2eeedcead3a41694130495593a559a668f382eee0727352b9a41e1c45759a"}, - {file = "multidict-6.0.4-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:7d6ae9d593ef8641544d6263c7fa6408cc90370c8cb2bbb65f8d43e5b0351d9c"}, - {file = "multidict-6.0.4-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:5979b5632c3e3534e42ca6ff856bb24b2e3071b37861c2c727ce220d80eee9ed"}, - {file = "multidict-6.0.4-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:dcfe792765fab89c365123c81046ad4103fcabbc4f56d1c1997e6715e8015461"}, - {file = "multidict-6.0.4-cp311-cp311-win32.whl", hash = "sha256:3601a3cece3819534b11d4efc1eb76047488fddd0c85a3948099d5da4d504636"}, - {file = "multidict-6.0.4-cp311-cp311-win_amd64.whl", hash = "sha256:81a4f0b34bd92df3da93315c6a59034df95866014ac08535fc819f043bfd51f0"}, - {file = "multidict-6.0.4-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:67040058f37a2a51ed8ea8f6b0e6ee5bd78ca67f169ce6122f3e2ec80dfe9b78"}, - {file = "multidict-6.0.4-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:853888594621e6604c978ce2a0444a1e6e70c8d253ab65ba11657659dcc9100f"}, - {file = "multidict-6.0.4-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:39ff62e7d0f26c248b15e364517a72932a611a9b75f35b45be078d81bdb86603"}, - {file = "multidict-6.0.4-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:af048912e045a2dc732847d33821a9d84ba553f5c5f028adbd364dd4765092ac"}, - {file = "multidict-6.0.4-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b1e8b901e607795ec06c9e42530788c45ac21ef3aaa11dbd0c69de543bfb79a9"}, - {file = "multidict-6.0.4-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:62501642008a8b9871ddfccbf83e4222cf8ac0d5aeedf73da36153ef2ec222d2"}, - {file = "multidict-6.0.4-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:99b76c052e9f1bc0721f7541e5e8c05db3941eb9ebe7b8553c625ef88d6eefde"}, - {file = "multidict-6.0.4-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:509eac6cf09c794aa27bcacfd4d62c885cce62bef7b2c3e8b2e49d365b5003fe"}, - {file = "multidict-6.0.4-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:21a12c4eb6ddc9952c415f24eef97e3e55ba3af61f67c7bc388dcdec1404a067"}, - {file = "multidict-6.0.4-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:5cad9430ab3e2e4fa4a2ef4450f548768400a2ac635841bc2a56a2052cdbeb87"}, - {file = "multidict-6.0.4-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:ab55edc2e84460694295f401215f4a58597f8f7c9466faec545093045476327d"}, - {file = "multidict-6.0.4-cp37-cp37m-win32.whl", hash = "sha256:5a4dcf02b908c3b8b17a45fb0f15b695bf117a67b76b7ad18b73cf8e92608775"}, - {file = "multidict-6.0.4-cp37-cp37m-win_amd64.whl", hash = "sha256:6ed5f161328b7df384d71b07317f4d8656434e34591f20552c7bcef27b0ab88e"}, - {file = "multidict-6.0.4-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:5fc1b16f586f049820c5c5b17bb4ee7583092fa0d1c4e28b5239181ff9532e0c"}, - {file = "multidict-6.0.4-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:1502e24330eb681bdaa3eb70d6358e818e8e8f908a22a1851dfd4e15bc2f8161"}, - {file = "multidict-6.0.4-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:b692f419760c0e65d060959df05f2a531945af31fda0c8a3b3195d4efd06de11"}, - {file = "multidict-6.0.4-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:45e1ecb0379bfaab5eef059f50115b54571acfbe422a14f668fc8c27ba410e7e"}, - {file = "multidict-6.0.4-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ddd3915998d93fbcd2566ddf9cf62cdb35c9e093075f862935573d265cf8f65d"}, - {file = "multidict-6.0.4-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:59d43b61c59d82f2effb39a93c48b845efe23a3852d201ed2d24ba830d0b4cf2"}, - {file = "multidict-6.0.4-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cc8e1d0c705233c5dd0c5e6460fbad7827d5d36f310a0fadfd45cc3029762258"}, - {file = "multidict-6.0.4-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d6aa0418fcc838522256761b3415822626f866758ee0bc6632c9486b179d0b52"}, - {file = "multidict-6.0.4-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:6748717bb10339c4760c1e63da040f5f29f5ed6e59d76daee30305894069a660"}, - {file = "multidict-6.0.4-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:4d1a3d7ef5e96b1c9e92f973e43aa5e5b96c659c9bc3124acbbd81b0b9c8a951"}, - {file = "multidict-6.0.4-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:4372381634485bec7e46718edc71528024fcdc6f835baefe517b34a33c731d60"}, - {file = "multidict-6.0.4-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:fc35cb4676846ef752816d5be2193a1e8367b4c1397b74a565a9d0389c433a1d"}, - {file = "multidict-6.0.4-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:4b9d9e4e2b37daddb5c23ea33a3417901fa7c7b3dee2d855f63ee67a0b21e5b1"}, - {file = "multidict-6.0.4-cp38-cp38-win32.whl", hash = "sha256:e41b7e2b59679edfa309e8db64fdf22399eec4b0b24694e1b2104fb789207779"}, - {file = "multidict-6.0.4-cp38-cp38-win_amd64.whl", hash = "sha256:d6c254ba6e45d8e72739281ebc46ea5eb5f101234f3ce171f0e9f5cc86991480"}, - {file = "multidict-6.0.4-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:16ab77bbeb596e14212e7bab8429f24c1579234a3a462105cda4a66904998664"}, - {file = "multidict-6.0.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:bc779e9e6f7fda81b3f9aa58e3a6091d49ad528b11ed19f6621408806204ad35"}, - {file = "multidict-6.0.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:4ceef517eca3e03c1cceb22030a3e39cb399ac86bff4e426d4fc6ae49052cc60"}, - {file = "multidict-6.0.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:281af09f488903fde97923c7744bb001a9b23b039a909460d0f14edc7bf59706"}, - {file = "multidict-6.0.4-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:52f2dffc8acaba9a2f27174c41c9e57f60b907bb9f096b36b1a1f3be71c6284d"}, - {file = "multidict-6.0.4-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b41156839806aecb3641f3208c0dafd3ac7775b9c4c422d82ee2a45c34ba81ca"}, - {file = "multidict-6.0.4-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d5e3fc56f88cc98ef8139255cf8cd63eb2c586531e43310ff859d6bb3a6b51f1"}, - {file = "multidict-6.0.4-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8316a77808c501004802f9beebde51c9f857054a0c871bd6da8280e718444449"}, - {file = "multidict-6.0.4-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:f70b98cd94886b49d91170ef23ec5c0e8ebb6f242d734ed7ed677b24d50c82cf"}, - {file = "multidict-6.0.4-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:bf6774e60d67a9efe02b3616fee22441d86fab4c6d335f9d2051d19d90a40063"}, - {file = "multidict-6.0.4-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:e69924bfcdda39b722ef4d9aa762b2dd38e4632b3641b1d9a57ca9cd18f2f83a"}, - {file = "multidict-6.0.4-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:6b181d8c23da913d4ff585afd1155a0e1194c0b50c54fcfe286f70cdaf2b7176"}, - {file = "multidict-6.0.4-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:52509b5be062d9eafc8170e53026fbc54cf3b32759a23d07fd935fb04fc22d95"}, - {file = "multidict-6.0.4-cp39-cp39-win32.whl", hash = "sha256:27c523fbfbdfd19c6867af7346332b62b586eed663887392cff78d614f9ec313"}, - {file = "multidict-6.0.4-cp39-cp39-win_amd64.whl", hash = "sha256:33029f5734336aa0d4c0384525da0387ef89148dc7191aae00ca5fb23d7aafc2"}, - {file = "multidict-6.0.4.tar.gz", hash = "sha256:3666906492efb76453c0e7b97f2cf459b0682e7402c0489a95484965dbc1da49"}, -] - [[package]] name = "packaging" -version = "23.0" +version = "23.1" description = "Core utilities for Python packages" category = "dev" optional = false python-versions = ">=3.7" files = [ - {file = "packaging-23.0-py3-none-any.whl", hash = "sha256:714ac14496c3e68c99c29b00845f7a2b85f3bb6f1078fd9f72fd20f0570002b2"}, - {file = "packaging-23.0.tar.gz", hash = "sha256:b6ad297f8907de0fa2fe1ccbd26fdaf387f5f47c7275fedf8cce89f99446cf97"}, + {file = "packaging-23.1-py3-none-any.whl", hash = "sha256:994793af429502c4ea2ebf6bf664629d07c1a9fe974af92966e4b8d2df7edc61"}, + {file = "packaging-23.1.tar.gz", hash = "sha256:a392980d2b6cffa644431898be54b0045151319d1e7ec34f0cfed48767dd334f"}, ] [[package]] name = "polywrap-client" -version = "0.1.0" +version = "0.1.0a29" description = "" category = "main" optional = false @@ -481,7 +346,6 @@ develop = true polywrap-core = {path = "../polywrap-core", develop = true} polywrap-manifest = {path = "../polywrap-manifest", develop = true} polywrap-msgpack = {path = "../polywrap-msgpack", develop = true} -polywrap-uri-resolvers = {path = "../polywrap-uri-resolvers", develop = true} [package.source] type = "directory" @@ -489,7 +353,7 @@ url = "../packages/polywrap-client" [[package]] name = "polywrap-client-config-builder" -version = "0.1.0" +version = "0.1.0a29" description = "" category = "main" optional = false @@ -499,6 +363,7 @@ develop = true [package.dependencies] polywrap-core = {path = "../polywrap-core", develop = true} +polywrap-uri-resolvers = {path = "../polywrap-uri-resolvers", develop = true} [package.source] type = "directory" @@ -506,7 +371,7 @@ url = "../packages/polywrap-client-config-builder" [[package]] name = "polywrap-core" -version = "0.1.0" +version = "0.1.0a29" description = "" category = "main" optional = false @@ -515,11 +380,8 @@ files = [] develop = true [package.dependencies] -gql = "3.4.0" -graphql-core = "^3.2.1" polywrap-manifest = {path = "../polywrap-manifest", develop = true} polywrap-msgpack = {path = "../polywrap-msgpack", develop = true} -pydantic = "^1.10.2" [package.source] type = "directory" @@ -527,7 +389,7 @@ url = "../packages/polywrap-core" [[package]] name = "polywrap-manifest" -version = "0.1.0" +version = "0.1.0a29" description = "WRAP manifest" category = "main" optional = false @@ -545,7 +407,7 @@ url = "../packages/polywrap-manifest" [[package]] name = "polywrap-msgpack" -version = "0.1.0" +version = "0.1.0a29" description = "WRAP msgpack encoding" category = "main" optional = false @@ -562,7 +424,7 @@ url = "../packages/polywrap-msgpack" [[package]] name = "polywrap-plugin" -version = "0.1.0" +version = "0.1.0a29" description = "Plugin package" category = "main" optional = false @@ -571,9 +433,9 @@ files = [] develop = true [package.dependencies] -polywrap_core = {path = "../polywrap-core"} -polywrap_manifest = {path = "../polywrap-manifest"} -polywrap_msgpack = {path = "../polywrap-msgpack"} +polywrap-core = {path = "../polywrap-core", develop = true} +polywrap-manifest = {path = "../polywrap-manifest", develop = true} +polywrap-msgpack = {path = "../polywrap-msgpack", develop = true} [package.source] type = "directory" @@ -581,7 +443,7 @@ url = "../packages/polywrap-plugin" [[package]] name = "polywrap-uri-resolvers" -version = "0.1.0" +version = "0.1.0a29" description = "" category = "main" optional = false @@ -599,7 +461,7 @@ url = "../packages/polywrap-uri-resolvers" [[package]] name = "polywrap-wasm" -version = "0.1.0" +version = "0.1.0a29" description = "" category = "main" optional = false @@ -621,48 +483,48 @@ url = "../packages/polywrap-wasm" [[package]] name = "pydantic" -version = "1.10.7" +version = "1.10.9" description = "Data validation and settings management using python type hints" category = "main" optional = false python-versions = ">=3.7" files = [ - {file = "pydantic-1.10.7-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e79e999e539872e903767c417c897e729e015872040e56b96e67968c3b918b2d"}, - {file = "pydantic-1.10.7-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:01aea3a42c13f2602b7ecbbea484a98169fb568ebd9e247593ea05f01b884b2e"}, - {file = "pydantic-1.10.7-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:516f1ed9bc2406a0467dd777afc636c7091d71f214d5e413d64fef45174cfc7a"}, - {file = "pydantic-1.10.7-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ae150a63564929c675d7f2303008d88426a0add46efd76c3fc797cd71cb1b46f"}, - {file = "pydantic-1.10.7-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:ecbbc51391248116c0a055899e6c3e7ffbb11fb5e2a4cd6f2d0b93272118a209"}, - {file = "pydantic-1.10.7-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:f4a2b50e2b03d5776e7f21af73e2070e1b5c0d0df255a827e7c632962f8315af"}, - {file = "pydantic-1.10.7-cp310-cp310-win_amd64.whl", hash = "sha256:a7cd2251439988b413cb0a985c4ed82b6c6aac382dbaff53ae03c4b23a70e80a"}, - {file = "pydantic-1.10.7-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:68792151e174a4aa9e9fc1b4e653e65a354a2fa0fed169f7b3d09902ad2cb6f1"}, - {file = "pydantic-1.10.7-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:dfe2507b8ef209da71b6fb5f4e597b50c5a34b78d7e857c4f8f3115effaef5fe"}, - {file = "pydantic-1.10.7-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:10a86d8c8db68086f1e30a530f7d5f83eb0685e632e411dbbcf2d5c0150e8dcd"}, - {file = "pydantic-1.10.7-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d75ae19d2a3dbb146b6f324031c24f8a3f52ff5d6a9f22f0683694b3afcb16fb"}, - {file = "pydantic-1.10.7-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:464855a7ff7f2cc2cf537ecc421291b9132aa9c79aef44e917ad711b4a93163b"}, - {file = "pydantic-1.10.7-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:193924c563fae6ddcb71d3f06fa153866423ac1b793a47936656e806b64e24ca"}, - {file = "pydantic-1.10.7-cp311-cp311-win_amd64.whl", hash = "sha256:b4a849d10f211389502059c33332e91327bc154acc1845f375a99eca3afa802d"}, - {file = "pydantic-1.10.7-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:cc1dde4e50a5fc1336ee0581c1612215bc64ed6d28d2c7c6f25d2fe3e7c3e918"}, - {file = "pydantic-1.10.7-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e0cfe895a504c060e5d36b287ee696e2fdad02d89e0d895f83037245218a87fe"}, - {file = "pydantic-1.10.7-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:670bb4683ad1e48b0ecb06f0cfe2178dcf74ff27921cdf1606e527d2617a81ee"}, - {file = "pydantic-1.10.7-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:950ce33857841f9a337ce07ddf46bc84e1c4946d2a3bba18f8280297157a3fd1"}, - {file = "pydantic-1.10.7-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:c15582f9055fbc1bfe50266a19771bbbef33dd28c45e78afbe1996fd70966c2a"}, - {file = "pydantic-1.10.7-cp37-cp37m-win_amd64.whl", hash = "sha256:82dffb306dd20bd5268fd6379bc4bfe75242a9c2b79fec58e1041fbbdb1f7914"}, - {file = "pydantic-1.10.7-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:8c7f51861d73e8b9ddcb9916ae7ac39fb52761d9ea0df41128e81e2ba42886cd"}, - {file = "pydantic-1.10.7-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:6434b49c0b03a51021ade5c4daa7d70c98f7a79e95b551201fff682fc1661245"}, - {file = "pydantic-1.10.7-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:64d34ab766fa056df49013bb6e79921a0265204c071984e75a09cbceacbbdd5d"}, - {file = "pydantic-1.10.7-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:701daea9ffe9d26f97b52f1d157e0d4121644f0fcf80b443248434958fd03dc3"}, - {file = "pydantic-1.10.7-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:cf135c46099ff3f919d2150a948ce94b9ce545598ef2c6c7bf55dca98a304b52"}, - {file = "pydantic-1.10.7-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:b0f85904f73161817b80781cc150f8b906d521fa11e3cdabae19a581c3606209"}, - {file = "pydantic-1.10.7-cp38-cp38-win_amd64.whl", hash = "sha256:9f6f0fd68d73257ad6685419478c5aece46432f4bdd8d32c7345f1986496171e"}, - {file = "pydantic-1.10.7-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:c230c0d8a322276d6e7b88c3f7ce885f9ed16e0910354510e0bae84d54991143"}, - {file = "pydantic-1.10.7-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:976cae77ba6a49d80f461fd8bba183ff7ba79f44aa5cfa82f1346b5626542f8e"}, - {file = "pydantic-1.10.7-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7d45fc99d64af9aaf7e308054a0067fdcd87ffe974f2442312372dfa66e1001d"}, - {file = "pydantic-1.10.7-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d2a5ebb48958754d386195fe9e9c5106f11275867051bf017a8059410e9abf1f"}, - {file = "pydantic-1.10.7-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:abfb7d4a7cd5cc4e1d1887c43503a7c5dd608eadf8bc615413fc498d3e4645cd"}, - {file = "pydantic-1.10.7-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:80b1fab4deb08a8292d15e43a6edccdffa5377a36a4597bb545b93e79c5ff0a5"}, - {file = "pydantic-1.10.7-cp39-cp39-win_amd64.whl", hash = "sha256:d71e69699498b020ea198468e2480a2f1e7433e32a3a99760058c6520e2bea7e"}, - {file = "pydantic-1.10.7-py3-none-any.whl", hash = "sha256:0cd181f1d0b1d00e2b705f1bf1ac7799a2d938cce3376b8007df62b29be3c2c6"}, - {file = "pydantic-1.10.7.tar.gz", hash = "sha256:cfc83c0678b6ba51b0532bea66860617c4cd4251ecf76e9846fa5a9f3454e97e"}, + {file = "pydantic-1.10.9-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e692dec4a40bfb40ca530e07805b1208c1de071a18d26af4a2a0d79015b352ca"}, + {file = "pydantic-1.10.9-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:3c52eb595db83e189419bf337b59154bdcca642ee4b2a09e5d7797e41ace783f"}, + {file = "pydantic-1.10.9-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:939328fd539b8d0edf244327398a667b6b140afd3bf7e347cf9813c736211896"}, + {file = "pydantic-1.10.9-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b48d3d634bca23b172f47f2335c617d3fcb4b3ba18481c96b7943a4c634f5c8d"}, + {file = "pydantic-1.10.9-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:f0b7628fb8efe60fe66fd4adadd7ad2304014770cdc1f4934db41fe46cc8825f"}, + {file = "pydantic-1.10.9-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:e1aa5c2410769ca28aa9a7841b80d9d9a1c5f223928ca8bec7e7c9a34d26b1d4"}, + {file = "pydantic-1.10.9-cp310-cp310-win_amd64.whl", hash = "sha256:eec39224b2b2e861259d6f3c8b6290d4e0fbdce147adb797484a42278a1a486f"}, + {file = "pydantic-1.10.9-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:d111a21bbbfd85c17248130deac02bbd9b5e20b303338e0dbe0faa78330e37e0"}, + {file = "pydantic-1.10.9-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:2e9aec8627a1a6823fc62fb96480abe3eb10168fd0d859ee3d3b395105ae19a7"}, + {file = "pydantic-1.10.9-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:07293ab08e7b4d3c9d7de4949a0ea571f11e4557d19ea24dd3ae0c524c0c334d"}, + {file = "pydantic-1.10.9-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7ee829b86ce984261d99ff2fd6e88f2230068d96c2a582f29583ed602ef3fc2c"}, + {file = "pydantic-1.10.9-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:4b466a23009ff5cdd7076eb56aca537c745ca491293cc38e72bf1e0e00de5b91"}, + {file = "pydantic-1.10.9-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:7847ca62e581e6088d9000f3c497267868ca2fa89432714e21a4fb33a04d52e8"}, + {file = "pydantic-1.10.9-cp311-cp311-win_amd64.whl", hash = "sha256:7845b31959468bc5b78d7b95ec52fe5be32b55d0d09983a877cca6aedc51068f"}, + {file = "pydantic-1.10.9-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:517a681919bf880ce1dac7e5bc0c3af1e58ba118fd774da2ffcd93c5f96eaece"}, + {file = "pydantic-1.10.9-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:67195274fd27780f15c4c372f4ba9a5c02dad6d50647b917b6a92bf00b3d301a"}, + {file = "pydantic-1.10.9-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2196c06484da2b3fded1ab6dbe182bdabeb09f6318b7fdc412609ee2b564c49a"}, + {file = "pydantic-1.10.9-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:6257bb45ad78abacda13f15bde5886efd6bf549dd71085e64b8dcf9919c38b60"}, + {file = "pydantic-1.10.9-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:3283b574b01e8dbc982080d8287c968489d25329a463b29a90d4157de4f2baaf"}, + {file = "pydantic-1.10.9-cp37-cp37m-win_amd64.whl", hash = "sha256:5f8bbaf4013b9a50e8100333cc4e3fa2f81214033e05ac5aa44fa24a98670a29"}, + {file = "pydantic-1.10.9-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:b9cd67fb763248cbe38f0593cd8611bfe4b8ad82acb3bdf2b0898c23415a1f82"}, + {file = "pydantic-1.10.9-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:f50e1764ce9353be67267e7fd0da08349397c7db17a562ad036aa7c8f4adfdb6"}, + {file = "pydantic-1.10.9-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:73ef93e5e1d3c8e83f1ff2e7fdd026d9e063c7e089394869a6e2985696693766"}, + {file = "pydantic-1.10.9-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:128d9453d92e6e81e881dd7e2484e08d8b164da5507f62d06ceecf84bf2e21d3"}, + {file = "pydantic-1.10.9-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:ad428e92ab68798d9326bb3e5515bc927444a3d71a93b4a2ca02a8a5d795c572"}, + {file = "pydantic-1.10.9-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:fab81a92f42d6d525dd47ced310b0c3e10c416bbfae5d59523e63ea22f82b31e"}, + {file = "pydantic-1.10.9-cp38-cp38-win_amd64.whl", hash = "sha256:963671eda0b6ba6926d8fc759e3e10335e1dc1b71ff2a43ed2efd6996634dafb"}, + {file = "pydantic-1.10.9-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:970b1bdc6243ef663ba5c7e36ac9ab1f2bfecb8ad297c9824b542d41a750b298"}, + {file = "pydantic-1.10.9-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:7e1d5290044f620f80cf1c969c542a5468f3656de47b41aa78100c5baa2b8276"}, + {file = "pydantic-1.10.9-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:83fcff3c7df7adff880622a98022626f4f6dbce6639a88a15a3ce0f96466cb60"}, + {file = "pydantic-1.10.9-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0da48717dc9495d3a8f215e0d012599db6b8092db02acac5e0d58a65248ec5bc"}, + {file = "pydantic-1.10.9-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:0a2aabdc73c2a5960e87c3ffebca6ccde88665616d1fd6d3db3178ef427b267a"}, + {file = "pydantic-1.10.9-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:9863b9420d99dfa9c064042304868e8ba08e89081428a1c471858aa2af6f57c4"}, + {file = "pydantic-1.10.9-cp39-cp39-win_amd64.whl", hash = "sha256:e7c9900b43ac14110efa977be3da28931ffc74c27e96ee89fbcaaf0b0fe338e1"}, + {file = "pydantic-1.10.9-py3-none-any.whl", hash = "sha256:6cafde02f6699ce4ff643417d1a9223716ec25e228ddc3b436fe7e2d25a1f305"}, + {file = "pydantic-1.10.9.tar.gz", hash = "sha256:95c70da2cd3b6ddf3b9645ecaa8d98f3d80c606624b6d245558d202cd23ea3be"}, ] [package.dependencies] @@ -674,14 +536,14 @@ email = ["email-validator (>=1.0.3)"] [[package]] name = "pygments" -version = "2.14.0" +version = "2.15.1" description = "Pygments is a syntax highlighting package written in Python." category = "dev" optional = false -python-versions = ">=3.6" +python-versions = ">=3.7" files = [ - {file = "Pygments-2.14.0-py3-none-any.whl", hash = "sha256:fa7bd7bd2771287c0de303af8bfdfc731f51bd2c6a47ab69d117138893b82717"}, - {file = "Pygments-2.14.0.tar.gz", hash = "sha256:b3ed06a9e8ac9a9aae5a6f5dbe78a8a58655d17b43b93c078f094ddc476ae297"}, + {file = "Pygments-2.15.1-py3-none-any.whl", hash = "sha256:db2db3deb4b4179f399a09054b023b6a586b76499d36965813c71aa8ed7b5fd1"}, + {file = "Pygments-2.15.1.tar.gz", hash = "sha256:8ace4d3c1dd481894b2005f560ead0f9f19ee64fe983366be1a21e171d12775c"}, ] [package.extras] @@ -689,21 +551,21 @@ plugins = ["importlib-metadata"] [[package]] name = "requests" -version = "2.28.2" +version = "2.31.0" description = "Python HTTP for Humans." category = "dev" optional = false -python-versions = ">=3.7, <4" +python-versions = ">=3.7" files = [ - {file = "requests-2.28.2-py3-none-any.whl", hash = "sha256:64299f4909223da747622c030b781c0d7811e359c37124b4bd368fb8c6518baa"}, - {file = "requests-2.28.2.tar.gz", hash = "sha256:98b1b2782e3c6c4904938b84c0eb932721069dfdb9134313beff7c83c2df24bf"}, + {file = "requests-2.31.0-py3-none-any.whl", hash = "sha256:58cd2187c01e70e6e26505bca751777aa9f2ee0b7f4300988b709f44e013003f"}, + {file = "requests-2.31.0.tar.gz", hash = "sha256:942c5a758f98d790eaed1a29cb6eefc7ffb0d1cf7af05c3d2791656dbd6ad1e1"}, ] [package.dependencies] certifi = ">=2017.4.17" charset-normalizer = ">=2,<4" idna = ">=2.5,<4" -urllib3 = ">=1.21.1,<1.27" +urllib3 = ">=1.21.1,<3" [package.extras] socks = ["PySocks (>=1.5.6,!=1.5.7)"] @@ -723,21 +585,21 @@ files = [ [[package]] name = "sphinx" -version = "6.1.3" +version = "6.2.1" description = "Python documentation generator" category = "dev" optional = false python-versions = ">=3.8" files = [ - {file = "Sphinx-6.1.3.tar.gz", hash = "sha256:0dac3b698538ffef41716cf97ba26c1c7788dba73ce6f150c1ff5b4720786dd2"}, - {file = "sphinx-6.1.3-py3-none-any.whl", hash = "sha256:807d1cb3d6be87eb78a381c3e70ebd8d346b9a25f3753e9947e866b2786865fc"}, + {file = "Sphinx-6.2.1.tar.gz", hash = "sha256:6d56a34697bb749ffa0152feafc4b19836c755d90a7c59b72bc7dfd371b9cc6b"}, + {file = "sphinx-6.2.1-py3-none-any.whl", hash = "sha256:97787ff1fa3256a3eef9eda523a63dbf299f7b47e053cfcf684a1c2a8380c912"}, ] [package.dependencies] alabaster = ">=0.7,<0.8" babel = ">=2.9" colorama = {version = ">=0.4.5", markers = "sys_platform == \"win32\""} -docutils = ">=0.18,<0.20" +docutils = ">=0.18.1,<0.20" imagesize = ">=1.3" Jinja2 = ">=3.0" packaging = ">=21.0" @@ -754,24 +616,24 @@ sphinxcontrib-serializinghtml = ">=1.1.5" [package.extras] docs = ["sphinxcontrib-websupport"] lint = ["docutils-stubs", "flake8 (>=3.5.0)", "flake8-simplify", "isort", "mypy (>=0.990)", "ruff", "sphinx-lint", "types-requests"] -test = ["cython", "html5lib", "pytest (>=4.6)"] +test = ["cython", "filelock", "html5lib", "pytest (>=4.6)"] [[package]] name = "sphinx-rtd-theme" -version = "1.2.0" +version = "1.2.2" description = "Read the Docs theme for Sphinx" category = "dev" optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,>=2.7" files = [ - {file = "sphinx_rtd_theme-1.2.0-py2.py3-none-any.whl", hash = "sha256:f823f7e71890abe0ac6aaa6013361ea2696fc8d3e1fa798f463e82bdb77eeff2"}, - {file = "sphinx_rtd_theme-1.2.0.tar.gz", hash = "sha256:a0d8bd1a2ed52e0b338cbe19c4b2eef3c5e7a048769753dac6a9f059c7b641b8"}, + {file = "sphinx_rtd_theme-1.2.2-py2.py3-none-any.whl", hash = "sha256:6a7e7d8af34eb8fc57d52a09c6b6b9c46ff44aea5951bc831eeb9245378f3689"}, + {file = "sphinx_rtd_theme-1.2.2.tar.gz", hash = "sha256:01c5c5a72e2d025bd23d1f06c59a4831b06e6ce6c01fdd5ebfe9986c0a880fc7"}, ] [package.dependencies] docutils = "<0.19" sphinx = ">=1.6,<7" -sphinxcontrib-jquery = {version = ">=2.0.0,<3.0.0 || >3.0.0", markers = "python_version > \"3\""} +sphinxcontrib-jquery = ">=4,<5" [package.extras] dev = ["bump2version", "sphinxcontrib-httpdomain", "transifex-client", "wheel"] @@ -888,14 +750,14 @@ test = ["pytest"] [[package]] name = "typing-extensions" -version = "4.5.0" +version = "4.6.3" description = "Backported and Experimental Type Hints for Python 3.7+" category = "main" optional = false python-versions = ">=3.7" files = [ - {file = "typing_extensions-4.5.0-py3-none-any.whl", hash = "sha256:fb33085c39dd998ac16d1431ebc293a8b3eedd00fd4a32de0ff79002c19511b4"}, - {file = "typing_extensions-4.5.0.tar.gz", hash = "sha256:5cb5f4a79139d699607b3ef622a1dedafa84e115ab0024e0d9c044a9479ca7cb"}, + {file = "typing_extensions-4.6.3-py3-none-any.whl", hash = "sha256:88a4153d8505aabbb4e13aacb7c486c2b4a33ca3b3f807914a9b4c844c471c26"}, + {file = "typing_extensions-4.6.3.tar.gz", hash = "sha256:d91d5919357fe7f681a9f2b5b4cb2a5f1ef0a1e9f59c4d8ff0d3491e05c0ffd5"}, ] [[package]] @@ -923,20 +785,21 @@ files = [ [[package]] name = "urllib3" -version = "1.26.15" +version = "2.0.3" description = "HTTP library with thread-safe connection pooling, file post, and more." category = "dev" optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*" +python-versions = ">=3.7" files = [ - {file = "urllib3-1.26.15-py2.py3-none-any.whl", hash = "sha256:aa751d169e23c7479ce47a0cb0da579e3ede798f994f5816a74e4f4500dcea42"}, - {file = "urllib3-1.26.15.tar.gz", hash = "sha256:8a388717b9476f934a21484e8c8e61875ab60644d29b9b39e11e4b9dc1c6b305"}, + {file = "urllib3-2.0.3-py3-none-any.whl", hash = "sha256:48e7fafa40319d358848e1bc6809b208340fafe2096f1725d05d67443d0483d1"}, + {file = "urllib3-2.0.3.tar.gz", hash = "sha256:bee28b5e56addb8226c96f7f13ac28cb4c301dd5ea8a6ca179c0b9835e032825"}, ] [package.extras] -brotli = ["brotli (>=1.0.9)", "brotlicffi (>=0.8.0)", "brotlipy (>=0.6.0)"] -secure = ["certifi", "cryptography (>=1.3.4)", "idna (>=2.0.0)", "ipaddress", "pyOpenSSL (>=0.14)", "urllib3-secure-extra"] -socks = ["PySocks (>=1.5.6,!=1.5.7,<2.0)"] +brotli = ["brotli (>=1.0.9)", "brotlicffi (>=0.8.0)"] +secure = ["certifi", "cryptography (>=1.9)", "idna (>=2.0.0)", "pyopenssl (>=17.1.0)", "urllib3-secure-extra"] +socks = ["pysocks (>=1.5.6,!=1.5.7,<2.0)"] +zstd = ["zstandard (>=0.18.0)"] [[package]] name = "wasmtime" @@ -957,94 +820,6 @@ files = [ [package.extras] testing = ["coverage", "flake8 (==4.0.1)", "pycparser", "pytest", "pytest-flake8", "pytest-mypy"] -[[package]] -name = "yarl" -version = "1.8.2" -description = "Yet another URL library" -category = "main" -optional = false -python-versions = ">=3.7" -files = [ - {file = "yarl-1.8.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:bb81f753c815f6b8e2ddd2eef3c855cf7da193b82396ac013c661aaa6cc6b0a5"}, - {file = "yarl-1.8.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:47d49ac96156f0928f002e2424299b2c91d9db73e08c4cd6742923a086f1c863"}, - {file = "yarl-1.8.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:3fc056e35fa6fba63248d93ff6e672c096f95f7836938241ebc8260e062832fe"}, - {file = "yarl-1.8.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:58a3c13d1c3005dbbac5c9f0d3210b60220a65a999b1833aa46bd6677c69b08e"}, - {file = "yarl-1.8.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:10b08293cda921157f1e7c2790999d903b3fd28cd5c208cf8826b3b508026996"}, - {file = "yarl-1.8.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:de986979bbd87272fe557e0a8fcb66fd40ae2ddfe28a8b1ce4eae22681728fef"}, - {file = "yarl-1.8.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6c4fcfa71e2c6a3cb568cf81aadc12768b9995323186a10827beccf5fa23d4f8"}, - {file = "yarl-1.8.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ae4d7ff1049f36accde9e1ef7301912a751e5bae0a9d142459646114c70ecba6"}, - {file = "yarl-1.8.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:bf071f797aec5b96abfc735ab97da9fd8f8768b43ce2abd85356a3127909d146"}, - {file = "yarl-1.8.2-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:74dece2bfc60f0f70907c34b857ee98f2c6dd0f75185db133770cd67300d505f"}, - {file = "yarl-1.8.2-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:df60a94d332158b444301c7f569659c926168e4d4aad2cfbf4bce0e8fb8be826"}, - {file = "yarl-1.8.2-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:63243b21c6e28ec2375f932a10ce7eda65139b5b854c0f6b82ed945ba526bff3"}, - {file = "yarl-1.8.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:cfa2bbca929aa742b5084fd4663dd4b87c191c844326fcb21c3afd2d11497f80"}, - {file = "yarl-1.8.2-cp310-cp310-win32.whl", hash = "sha256:b05df9ea7496df11b710081bd90ecc3a3db6adb4fee36f6a411e7bc91a18aa42"}, - {file = "yarl-1.8.2-cp310-cp310-win_amd64.whl", hash = "sha256:24ad1d10c9db1953291f56b5fe76203977f1ed05f82d09ec97acb623a7976574"}, - {file = "yarl-1.8.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:2a1fca9588f360036242f379bfea2b8b44cae2721859b1c56d033adfd5893634"}, - {file = "yarl-1.8.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:f37db05c6051eff17bc832914fe46869f8849de5b92dc4a3466cd63095d23dfd"}, - {file = "yarl-1.8.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:77e913b846a6b9c5f767b14dc1e759e5aff05502fe73079f6f4176359d832581"}, - {file = "yarl-1.8.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0978f29222e649c351b173da2b9b4665ad1feb8d1daa9d971eb90df08702668a"}, - {file = "yarl-1.8.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:388a45dc77198b2460eac0aca1efd6a7c09e976ee768b0d5109173e521a19daf"}, - {file = "yarl-1.8.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2305517e332a862ef75be8fad3606ea10108662bc6fe08509d5ca99503ac2aee"}, - {file = "yarl-1.8.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:42430ff511571940d51e75cf42f1e4dbdded477e71c1b7a17f4da76c1da8ea76"}, - {file = "yarl-1.8.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3150078118f62371375e1e69b13b48288e44f6691c1069340081c3fd12c94d5b"}, - {file = "yarl-1.8.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:c15163b6125db87c8f53c98baa5e785782078fbd2dbeaa04c6141935eb6dab7a"}, - {file = "yarl-1.8.2-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:4d04acba75c72e6eb90745447d69f84e6c9056390f7a9724605ca9c56b4afcc6"}, - {file = "yarl-1.8.2-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:e7fd20d6576c10306dea2d6a5765f46f0ac5d6f53436217913e952d19237efc4"}, - {file = "yarl-1.8.2-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:75c16b2a900b3536dfc7014905a128a2bea8fb01f9ee26d2d7d8db0a08e7cb2c"}, - {file = "yarl-1.8.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:6d88056a04860a98341a0cf53e950e3ac9f4e51d1b6f61a53b0609df342cc8b2"}, - {file = "yarl-1.8.2-cp311-cp311-win32.whl", hash = "sha256:fb742dcdd5eec9f26b61224c23baea46c9055cf16f62475e11b9b15dfd5c117b"}, - {file = "yarl-1.8.2-cp311-cp311-win_amd64.whl", hash = "sha256:8c46d3d89902c393a1d1e243ac847e0442d0196bbd81aecc94fcebbc2fd5857c"}, - {file = "yarl-1.8.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:ceff9722e0df2e0a9e8a79c610842004fa54e5b309fe6d218e47cd52f791d7ef"}, - {file = "yarl-1.8.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3f6b4aca43b602ba0f1459de647af954769919c4714706be36af670a5f44c9c1"}, - {file = "yarl-1.8.2-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1684a9bd9077e922300ecd48003ddae7a7474e0412bea38d4631443a91d61077"}, - {file = "yarl-1.8.2-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ebb78745273e51b9832ef90c0898501006670d6e059f2cdb0e999494eb1450c2"}, - {file = "yarl-1.8.2-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3adeef150d528ded2a8e734ebf9ae2e658f4c49bf413f5f157a470e17a4a2e89"}, - {file = "yarl-1.8.2-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:57a7c87927a468e5a1dc60c17caf9597161d66457a34273ab1760219953f7f4c"}, - {file = "yarl-1.8.2-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:efff27bd8cbe1f9bd127e7894942ccc20c857aa8b5a0327874f30201e5ce83d0"}, - {file = "yarl-1.8.2-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:a783cd344113cb88c5ff7ca32f1f16532a6f2142185147822187913eb989f739"}, - {file = "yarl-1.8.2-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:705227dccbe96ab02c7cb2c43e1228e2826e7ead880bb19ec94ef279e9555b5b"}, - {file = "yarl-1.8.2-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:34c09b43bd538bf6c4b891ecce94b6fa4f1f10663a8d4ca589a079a5018f6ed7"}, - {file = "yarl-1.8.2-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:a48f4f7fea9a51098b02209d90297ac324241bf37ff6be6d2b0149ab2bd51b37"}, - {file = "yarl-1.8.2-cp37-cp37m-win32.whl", hash = "sha256:0414fd91ce0b763d4eadb4456795b307a71524dbacd015c657bb2a39db2eab89"}, - {file = "yarl-1.8.2-cp37-cp37m-win_amd64.whl", hash = "sha256:d881d152ae0007809c2c02e22aa534e702f12071e6b285e90945aa3c376463c5"}, - {file = "yarl-1.8.2-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:5df5e3d04101c1e5c3b1d69710b0574171cc02fddc4b23d1b2813e75f35a30b1"}, - {file = "yarl-1.8.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:7a66c506ec67eb3159eea5096acd05f5e788ceec7b96087d30c7d2865a243918"}, - {file = "yarl-1.8.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:2b4fa2606adf392051d990c3b3877d768771adc3faf2e117b9de7eb977741229"}, - {file = "yarl-1.8.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1e21fb44e1eff06dd6ef971d4bdc611807d6bd3691223d9c01a18cec3677939e"}, - {file = "yarl-1.8.2-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:93202666046d9edadfe9f2e7bf5e0782ea0d497b6d63da322e541665d65a044e"}, - {file = "yarl-1.8.2-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:fc77086ce244453e074e445104f0ecb27530d6fd3a46698e33f6c38951d5a0f1"}, - {file = "yarl-1.8.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:64dd68a92cab699a233641f5929a40f02a4ede8c009068ca8aa1fe87b8c20ae3"}, - {file = "yarl-1.8.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1b372aad2b5f81db66ee7ec085cbad72c4da660d994e8e590c997e9b01e44901"}, - {file = "yarl-1.8.2-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:e6f3515aafe0209dd17fb9bdd3b4e892963370b3de781f53e1746a521fb39fc0"}, - {file = "yarl-1.8.2-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:dfef7350ee369197106805e193d420b75467b6cceac646ea5ed3049fcc950a05"}, - {file = "yarl-1.8.2-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:728be34f70a190566d20aa13dc1f01dc44b6aa74580e10a3fb159691bc76909d"}, - {file = "yarl-1.8.2-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:ff205b58dc2929191f68162633d5e10e8044398d7a45265f90a0f1d51f85f72c"}, - {file = "yarl-1.8.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:baf211dcad448a87a0d9047dc8282d7de59473ade7d7fdf22150b1d23859f946"}, - {file = "yarl-1.8.2-cp38-cp38-win32.whl", hash = "sha256:272b4f1599f1b621bf2aabe4e5b54f39a933971f4e7c9aa311d6d7dc06965165"}, - {file = "yarl-1.8.2-cp38-cp38-win_amd64.whl", hash = "sha256:326dd1d3caf910cd26a26ccbfb84c03b608ba32499b5d6eeb09252c920bcbe4f"}, - {file = "yarl-1.8.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:f8ca8ad414c85bbc50f49c0a106f951613dfa5f948ab69c10ce9b128d368baf8"}, - {file = "yarl-1.8.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:418857f837347e8aaef682679f41e36c24250097f9e2f315d39bae3a99a34cbf"}, - {file = "yarl-1.8.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:ae0eec05ab49e91a78700761777f284c2df119376e391db42c38ab46fd662b77"}, - {file = "yarl-1.8.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:009a028127e0a1755c38b03244c0bea9d5565630db9c4cf9572496e947137a87"}, - {file = "yarl-1.8.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3edac5d74bb3209c418805bda77f973117836e1de7c000e9755e572c1f7850d0"}, - {file = "yarl-1.8.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:da65c3f263729e47351261351b8679c6429151ef9649bba08ef2528ff2c423b2"}, - {file = "yarl-1.8.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0ef8fb25e52663a1c85d608f6dd72e19bd390e2ecaf29c17fb08f730226e3a08"}, - {file = "yarl-1.8.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bcd7bb1e5c45274af9a1dd7494d3c52b2be5e6bd8d7e49c612705fd45420b12d"}, - {file = "yarl-1.8.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:44ceac0450e648de86da8e42674f9b7077d763ea80c8ceb9d1c3e41f0f0a9951"}, - {file = "yarl-1.8.2-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:97209cc91189b48e7cfe777237c04af8e7cc51eb369004e061809bcdf4e55220"}, - {file = "yarl-1.8.2-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:48dd18adcf98ea9cd721a25313aef49d70d413a999d7d89df44f469edfb38a06"}, - {file = "yarl-1.8.2-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:e59399dda559688461762800d7fb34d9e8a6a7444fd76ec33220a926c8be1516"}, - {file = "yarl-1.8.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:d617c241c8c3ad5c4e78a08429fa49e4b04bedfc507b34b4d8dceb83b4af3588"}, - {file = "yarl-1.8.2-cp39-cp39-win32.whl", hash = "sha256:cb6d48d80a41f68de41212f3dfd1a9d9898d7841c8f7ce6696cf2fd9cb57ef83"}, - {file = "yarl-1.8.2-cp39-cp39-win_amd64.whl", hash = "sha256:6604711362f2dbf7160df21c416f81fac0de6dbcf0b5445a2ef25478ecc4c778"}, - {file = "yarl-1.8.2.tar.gz", hash = "sha256:49d43402c6e3013ad0978602bf6bf5328535c48d192304b91b97a3c6790b1562"}, -] - -[package.dependencies] -idna = ">=2.0" -multidict = ">=4.0" - [metadata] lock-version = "2.0" python-versions = "^3.10" diff --git a/docs/pyproject.toml b/docs/pyproject.toml index a768f043..da55d67d 100644 --- a/docs/pyproject.toml +++ b/docs/pyproject.toml @@ -7,7 +7,6 @@ name = "docs" version = "0.1.0" description = "" authors = ["Niraj "] -readme = "README.md" [tool.poetry.dependencies] python = "^3.10" @@ -22,5 +21,4 @@ polywrap-client-config-builder = { path = "../packages/polywrap-client-config-bu [tool.poetry.group.dev.dependencies] sphinx = "^6.1.3" -sphinx-rtd-theme = "^1.2.0" - +sphinx-rtd-theme = "^1.2.0" \ No newline at end of file diff --git a/docs/source/index.rst b/docs/source/index.rst index 807e75a0..6e9966c8 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -20,7 +20,6 @@ Welcome to polywrap-client's documentation! polywrap-client-config-builder/modules.rst - Indices and tables ================== diff --git a/docs/source/polywrap-core/polywrap_core.types.invoke_args.rst b/docs/source/polywrap-core/polywrap_core.types.invoke_args.rst deleted file mode 100644 index 60dd0555..00000000 --- a/docs/source/polywrap-core/polywrap_core.types.invoke_args.rst +++ /dev/null @@ -1,7 +0,0 @@ -polywrap\_core.types.invoke\_args module -======================================== - -.. automodule:: polywrap_core.types.invoke_args - :members: - :undoc-members: - :show-inheritance: diff --git a/docs/source/polywrap-core/polywrap_core.types.invoke_options.rst b/docs/source/polywrap-core/polywrap_core.types.invoke_options.rst new file mode 100644 index 00000000..0b1f0cc6 --- /dev/null +++ b/docs/source/polywrap-core/polywrap_core.types.invoke_options.rst @@ -0,0 +1,7 @@ +polywrap\_core.types.invoke\_options module +=========================================== + +.. automodule:: polywrap_core.types.invoke_options + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/source/polywrap-core/polywrap_core.types.options.file_options.rst b/docs/source/polywrap-core/polywrap_core.types.options.file_options.rst deleted file mode 100644 index 129a7ba2..00000000 --- a/docs/source/polywrap-core/polywrap_core.types.options.file_options.rst +++ /dev/null @@ -1,7 +0,0 @@ -polywrap\_core.types.options.file\_options module -================================================= - -.. automodule:: polywrap_core.types.options.file_options - :members: - :undoc-members: - :show-inheritance: diff --git a/docs/source/polywrap-core/polywrap_core.types.options.invoke_options.rst b/docs/source/polywrap-core/polywrap_core.types.options.invoke_options.rst deleted file mode 100644 index b625e1c6..00000000 --- a/docs/source/polywrap-core/polywrap_core.types.options.invoke_options.rst +++ /dev/null @@ -1,7 +0,0 @@ -polywrap\_core.types.options.invoke\_options module -=================================================== - -.. automodule:: polywrap_core.types.options.invoke_options - :members: - :undoc-members: - :show-inheritance: diff --git a/docs/source/polywrap-core/polywrap_core.types.options.manifest_options.rst b/docs/source/polywrap-core/polywrap_core.types.options.manifest_options.rst deleted file mode 100644 index 5919f120..00000000 --- a/docs/source/polywrap-core/polywrap_core.types.options.manifest_options.rst +++ /dev/null @@ -1,7 +0,0 @@ -polywrap\_core.types.options.manifest\_options module -===================================================== - -.. automodule:: polywrap_core.types.options.manifest_options - :members: - :undoc-members: - :show-inheritance: diff --git a/docs/source/polywrap-core/polywrap_core.types.options.rst b/docs/source/polywrap-core/polywrap_core.types.options.rst deleted file mode 100644 index b23ed796..00000000 --- a/docs/source/polywrap-core/polywrap_core.types.options.rst +++ /dev/null @@ -1,21 +0,0 @@ -polywrap\_core.types.options package -==================================== - -Submodules ----------- - -.. toctree:: - :maxdepth: 4 - - polywrap_core.types.options.file_options - polywrap_core.types.options.invoke_options - polywrap_core.types.options.manifest_options - polywrap_core.types.options.uri_resolver_options - -Module contents ---------------- - -.. automodule:: polywrap_core.types.options - :members: - :undoc-members: - :show-inheritance: diff --git a/docs/source/polywrap-core/polywrap_core.types.options.uri_resolver_options.rst b/docs/source/polywrap-core/polywrap_core.types.options.uri_resolver_options.rst deleted file mode 100644 index 3ee58897..00000000 --- a/docs/source/polywrap-core/polywrap_core.types.options.uri_resolver_options.rst +++ /dev/null @@ -1,7 +0,0 @@ -polywrap\_core.types.options.uri\_resolver\_options module -========================================================== - -.. automodule:: polywrap_core.types.options.uri_resolver_options - :members: - :undoc-members: - :show-inheritance: diff --git a/docs/source/polywrap-core/polywrap_core.types.rst b/docs/source/polywrap-core/polywrap_core.types.rst index ceaf51db..b17083c9 100644 --- a/docs/source/polywrap-core/polywrap_core.types.rst +++ b/docs/source/polywrap-core/polywrap_core.types.rst @@ -1,14 +1,6 @@ polywrap\_core.types package ============================ -Subpackages ------------ - -.. toctree:: - :maxdepth: 4 - - polywrap_core.types.options - Submodules ---------- @@ -17,15 +9,13 @@ Submodules polywrap_core.types.client polywrap_core.types.config - polywrap_core.types.env polywrap_core.types.errors polywrap_core.types.file_reader polywrap_core.types.invocable - polywrap_core.types.invoke_args + polywrap_core.types.invoke_options polywrap_core.types.invoker polywrap_core.types.invoker_client polywrap_core.types.uri - polywrap_core.types.uri_like polywrap_core.types.uri_package polywrap_core.types.uri_package_wrapper polywrap_core.types.uri_resolution_context diff --git a/docs/source/polywrap-core/polywrap_core.types.uri_like.rst b/docs/source/polywrap-core/polywrap_core.types.uri_like.rst deleted file mode 100644 index bef58a58..00000000 --- a/docs/source/polywrap-core/polywrap_core.types.uri_like.rst +++ /dev/null @@ -1,7 +0,0 @@ -polywrap\_core.types.uri\_like module -===================================== - -.. automodule:: polywrap_core.types.uri_like - :members: - :undoc-members: - :show-inheritance: diff --git a/docs/source/polywrap-core/polywrap_core.utils.build_clean_uri_history.rst b/docs/source/polywrap-core/polywrap_core.utils.build_clean_uri_history.rst new file mode 100644 index 00000000..c37becef --- /dev/null +++ b/docs/source/polywrap-core/polywrap_core.utils.build_clean_uri_history.rst @@ -0,0 +1,7 @@ +polywrap\_core.utils.build\_clean\_uri\_history module +====================================================== + +.. automodule:: polywrap_core.utils.build_clean_uri_history + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/source/polywrap-core/polywrap_core.utils.get_env_from_resolution_path.rst b/docs/source/polywrap-core/polywrap_core.utils.get_env_from_resolution_path.rst new file mode 100644 index 00000000..7ef6d385 --- /dev/null +++ b/docs/source/polywrap-core/polywrap_core.utils.get_env_from_resolution_path.rst @@ -0,0 +1,7 @@ +polywrap\_core.utils.get\_env\_from\_resolution\_path module +============================================================ + +.. automodule:: polywrap_core.utils.get_env_from_resolution_path + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/source/polywrap-core/polywrap_core.utils.get_implementations.rst b/docs/source/polywrap-core/polywrap_core.utils.get_implementations.rst new file mode 100644 index 00000000..debcead7 --- /dev/null +++ b/docs/source/polywrap-core/polywrap_core.utils.get_implementations.rst @@ -0,0 +1,7 @@ +polywrap\_core.utils.get\_implementations module +================================================ + +.. automodule:: polywrap_core.utils.get_implementations + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/source/polywrap-core/polywrap_core.utils.instance_of.rst b/docs/source/polywrap-core/polywrap_core.utils.instance_of.rst deleted file mode 100644 index e742eb66..00000000 --- a/docs/source/polywrap-core/polywrap_core.utils.instance_of.rst +++ /dev/null @@ -1,7 +0,0 @@ -polywrap\_core.utils.instance\_of module -======================================== - -.. automodule:: polywrap_core.utils.instance_of - :members: - :undoc-members: - :show-inheritance: diff --git a/docs/source/polywrap-core/polywrap_core.utils.maybe_async.rst b/docs/source/polywrap-core/polywrap_core.utils.maybe_async.rst deleted file mode 100644 index b0bb88c0..00000000 --- a/docs/source/polywrap-core/polywrap_core.utils.maybe_async.rst +++ /dev/null @@ -1,7 +0,0 @@ -polywrap\_core.utils.maybe\_async module -======================================== - -.. automodule:: polywrap_core.utils.maybe_async - :members: - :undoc-members: - :show-inheritance: diff --git a/docs/source/polywrap-core/polywrap_core.utils.rst b/docs/source/polywrap-core/polywrap_core.utils.rst index 32d08123..803ce5ec 100644 --- a/docs/source/polywrap-core/polywrap_core.utils.rst +++ b/docs/source/polywrap-core/polywrap_core.utils.rst @@ -7,8 +7,9 @@ Submodules .. toctree:: :maxdepth: 4 - polywrap_core.utils.instance_of - polywrap_core.utils.maybe_async + polywrap_core.utils.build_clean_uri_history + polywrap_core.utils.get_env_from_resolution_path + polywrap_core.utils.get_implementations Module contents --------------- diff --git a/docs/source/polywrap-manifest/polywrap_manifest.errors.rst b/docs/source/polywrap-manifest/polywrap_manifest.errors.rst new file mode 100644 index 00000000..6e4530c3 --- /dev/null +++ b/docs/source/polywrap-manifest/polywrap_manifest.errors.rst @@ -0,0 +1,7 @@ +polywrap\_manifest.errors module +================================ + +.. automodule:: polywrap_manifest.errors + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/source/polywrap-manifest/polywrap_manifest.rst b/docs/source/polywrap-manifest/polywrap_manifest.rst index 3e16dae8..0e754aa4 100644 --- a/docs/source/polywrap-manifest/polywrap_manifest.rst +++ b/docs/source/polywrap-manifest/polywrap_manifest.rst @@ -8,6 +8,7 @@ Submodules :maxdepth: 4 polywrap_manifest.deserialize + polywrap_manifest.errors polywrap_manifest.manifest polywrap_manifest.wrap_0_1 diff --git a/docs/source/polywrap-core/polywrap_core.types.env.rst b/docs/source/polywrap-msgpack/polywrap_msgpack.errors.rst similarity index 54% rename from docs/source/polywrap-core/polywrap_core.types.env.rst rename to docs/source/polywrap-msgpack/polywrap_msgpack.errors.rst index 0b30f8c2..e96e074b 100644 --- a/docs/source/polywrap-core/polywrap_core.types.env.rst +++ b/docs/source/polywrap-msgpack/polywrap_msgpack.errors.rst @@ -1,7 +1,7 @@ -polywrap\_core.types.env module +polywrap\_msgpack.errors module =============================== -.. automodule:: polywrap_core.types.env +.. automodule:: polywrap_msgpack.errors :members: :undoc-members: :show-inheritance: diff --git a/docs/source/polywrap-msgpack/polywrap_msgpack.rst b/docs/source/polywrap-msgpack/polywrap_msgpack.rst index 7e00f143..56cce48c 100644 --- a/docs/source/polywrap-msgpack/polywrap_msgpack.rst +++ b/docs/source/polywrap-msgpack/polywrap_msgpack.rst @@ -17,6 +17,7 @@ Submodules polywrap_msgpack.decoder polywrap_msgpack.encoder + polywrap_msgpack.errors polywrap_msgpack.sanitize Module contents diff --git a/docs/source/polywrap-plugin/polywrap_plugin.resolution_context_override_client.rst b/docs/source/polywrap-plugin/polywrap_plugin.resolution_context_override_client.rst new file mode 100644 index 00000000..a3d865bc --- /dev/null +++ b/docs/source/polywrap-plugin/polywrap_plugin.resolution_context_override_client.rst @@ -0,0 +1,7 @@ +polywrap\_plugin.resolution\_context\_override\_client module +============================================================= + +.. automodule:: polywrap_plugin.resolution_context_override_client + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/source/polywrap-plugin/polywrap_plugin.rst b/docs/source/polywrap-plugin/polywrap_plugin.rst index 211a3be5..2b94eb4c 100644 --- a/docs/source/polywrap-plugin/polywrap_plugin.rst +++ b/docs/source/polywrap-plugin/polywrap_plugin.rst @@ -9,6 +9,7 @@ Submodules polywrap_plugin.module polywrap_plugin.package + polywrap_plugin.resolution_context_override_client polywrap_plugin.wrapper Module contents diff --git a/docs/source/polywrap-uri-resolvers/polywrap_uri_resolvers.resolvers.aggregator.rst b/docs/source/polywrap-uri-resolvers/polywrap_uri_resolvers.resolvers.aggregator.rst index ae02c87c..fe3e9fa9 100644 --- a/docs/source/polywrap-uri-resolvers/polywrap_uri_resolvers.resolvers.aggregator.rst +++ b/docs/source/polywrap-uri-resolvers/polywrap_uri_resolvers.resolvers.aggregator.rst @@ -8,6 +8,7 @@ Submodules :maxdepth: 4 polywrap_uri_resolvers.resolvers.aggregator.uri_resolver_aggregator + polywrap_uri_resolvers.resolvers.aggregator.uri_resolver_aggregator_base Module contents --------------- diff --git a/docs/source/polywrap-uri-resolvers/polywrap_uri_resolvers.resolvers.aggregator.uri_resolver_aggregator_base.rst b/docs/source/polywrap-uri-resolvers/polywrap_uri_resolvers.resolvers.aggregator.uri_resolver_aggregator_base.rst new file mode 100644 index 00000000..c960ea16 --- /dev/null +++ b/docs/source/polywrap-uri-resolvers/polywrap_uri_resolvers.resolvers.aggregator.uri_resolver_aggregator_base.rst @@ -0,0 +1,7 @@ +polywrap\_uri\_resolvers.resolvers.aggregator.uri\_resolver\_aggregator\_base module +==================================================================================== + +.. automodule:: polywrap_uri_resolvers.resolvers.aggregator.uri_resolver_aggregator_base + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/source/polywrap-uri-resolvers/polywrap_uri_resolvers.resolvers.cache.cache_resolver.rst b/docs/source/polywrap-uri-resolvers/polywrap_uri_resolvers.resolvers.cache.cache_resolver.rst deleted file mode 100644 index a094efff..00000000 --- a/docs/source/polywrap-uri-resolvers/polywrap_uri_resolvers.resolvers.cache.cache_resolver.rst +++ /dev/null @@ -1,7 +0,0 @@ -polywrap\_uri\_resolvers.resolvers.cache.cache\_resolver module -=============================================================== - -.. automodule:: polywrap_uri_resolvers.resolvers.cache.cache_resolver - :members: - :undoc-members: - :show-inheritance: diff --git a/docs/source/polywrap-uri-resolvers/polywrap_uri_resolvers.resolvers.cache.resolution_result_cache_resolver.rst b/docs/source/polywrap-uri-resolvers/polywrap_uri_resolvers.resolvers.cache.resolution_result_cache_resolver.rst new file mode 100644 index 00000000..741007da --- /dev/null +++ b/docs/source/polywrap-uri-resolvers/polywrap_uri_resolvers.resolvers.cache.resolution_result_cache_resolver.rst @@ -0,0 +1,7 @@ +polywrap\_uri\_resolvers.resolvers.cache.resolution\_result\_cache\_resolver module +=================================================================================== + +.. automodule:: polywrap_uri_resolvers.resolvers.cache.resolution_result_cache_resolver + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/source/polywrap-uri-resolvers/polywrap_uri_resolvers.resolvers.cache.rst b/docs/source/polywrap-uri-resolvers/polywrap_uri_resolvers.resolvers.cache.rst index fd8a3c05..ddabb0e6 100644 --- a/docs/source/polywrap-uri-resolvers/polywrap_uri_resolvers.resolvers.cache.rst +++ b/docs/source/polywrap-uri-resolvers/polywrap_uri_resolvers.resolvers.cache.rst @@ -7,8 +7,7 @@ Submodules .. toctree:: :maxdepth: 4 - polywrap_uri_resolvers.resolvers.cache.cache_resolver - polywrap_uri_resolvers.resolvers.cache.request_synchronizer_resolver + polywrap_uri_resolvers.resolvers.cache.resolution_result_cache_resolver Module contents --------------- diff --git a/docs/source/polywrap-uri-resolvers/polywrap_uri_resolvers.resolvers.cache.request_synchronizer_resolver.rst b/docs/source/polywrap-uri-resolvers/polywrap_uri_resolvers.resolvers.legacy.package_to_wrapper_resolver.rst similarity index 50% rename from docs/source/polywrap-uri-resolvers/polywrap_uri_resolvers.resolvers.cache.request_synchronizer_resolver.rst rename to docs/source/polywrap-uri-resolvers/polywrap_uri_resolvers.resolvers.legacy.package_to_wrapper_resolver.rst index 9aa31026..87287791 100644 --- a/docs/source/polywrap-uri-resolvers/polywrap_uri_resolvers.resolvers.cache.request_synchronizer_resolver.rst +++ b/docs/source/polywrap-uri-resolvers/polywrap_uri_resolvers.resolvers.legacy.package_to_wrapper_resolver.rst @@ -1,7 +1,7 @@ -polywrap\_uri\_resolvers.resolvers.cache.request\_synchronizer\_resolver module +polywrap\_uri\_resolvers.resolvers.legacy.package\_to\_wrapper\_resolver module =============================================================================== -.. automodule:: polywrap_uri_resolvers.resolvers.cache.request_synchronizer_resolver +.. automodule:: polywrap_uri_resolvers.resolvers.legacy.package_to_wrapper_resolver :members: :undoc-members: :show-inheritance: diff --git a/docs/source/polywrap-uri-resolvers/polywrap_uri_resolvers.resolvers.legacy.rst b/docs/source/polywrap-uri-resolvers/polywrap_uri_resolvers.resolvers.legacy.rst index 6783e920..6635f853 100644 --- a/docs/source/polywrap-uri-resolvers/polywrap_uri_resolvers.resolvers.legacy.rst +++ b/docs/source/polywrap-uri-resolvers/polywrap_uri_resolvers.resolvers.legacy.rst @@ -1,6 +1,14 @@ polywrap\_uri\_resolvers.resolvers.legacy package ================================================= +Subpackages +----------- + +.. toctree:: + :maxdepth: 4 + + polywrap_uri_resolvers.resolvers.legacy.wrapper_cache + Submodules ---------- @@ -9,7 +17,9 @@ Submodules polywrap_uri_resolvers.resolvers.legacy.base_resolver polywrap_uri_resolvers.resolvers.legacy.fs_resolver + polywrap_uri_resolvers.resolvers.legacy.package_to_wrapper_resolver polywrap_uri_resolvers.resolvers.legacy.redirect_resolver + polywrap_uri_resolvers.resolvers.legacy.wrapper_cache_resolver Module contents --------------- diff --git a/docs/source/polywrap-uri-resolvers/polywrap_uri_resolvers.resolvers.legacy.wrapper_cache.in_memory_wrapper_cache.rst b/docs/source/polywrap-uri-resolvers/polywrap_uri_resolvers.resolvers.legacy.wrapper_cache.in_memory_wrapper_cache.rst new file mode 100644 index 00000000..00418271 --- /dev/null +++ b/docs/source/polywrap-uri-resolvers/polywrap_uri_resolvers.resolvers.legacy.wrapper_cache.in_memory_wrapper_cache.rst @@ -0,0 +1,7 @@ +polywrap\_uri\_resolvers.resolvers.legacy.wrapper\_cache.in\_memory\_wrapper\_cache module +========================================================================================== + +.. automodule:: polywrap_uri_resolvers.resolvers.legacy.wrapper_cache.in_memory_wrapper_cache + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/source/polywrap-uri-resolvers/polywrap_uri_resolvers.resolvers.legacy.wrapper_cache.rst b/docs/source/polywrap-uri-resolvers/polywrap_uri_resolvers.resolvers.legacy.wrapper_cache.rst new file mode 100644 index 00000000..f2483595 --- /dev/null +++ b/docs/source/polywrap-uri-resolvers/polywrap_uri_resolvers.resolvers.legacy.wrapper_cache.rst @@ -0,0 +1,19 @@ +polywrap\_uri\_resolvers.resolvers.legacy.wrapper\_cache package +================================================================ + +Submodules +---------- + +.. toctree:: + :maxdepth: 4 + + polywrap_uri_resolvers.resolvers.legacy.wrapper_cache.in_memory_wrapper_cache + polywrap_uri_resolvers.resolvers.legacy.wrapper_cache.wrapper_cache + +Module contents +--------------- + +.. automodule:: polywrap_uri_resolvers.resolvers.legacy.wrapper_cache + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/source/polywrap-uri-resolvers/polywrap_uri_resolvers.resolvers.legacy.wrapper_cache.wrapper_cache.rst b/docs/source/polywrap-uri-resolvers/polywrap_uri_resolvers.resolvers.legacy.wrapper_cache.wrapper_cache.rst new file mode 100644 index 00000000..50295264 --- /dev/null +++ b/docs/source/polywrap-uri-resolvers/polywrap_uri_resolvers.resolvers.legacy.wrapper_cache.wrapper_cache.rst @@ -0,0 +1,7 @@ +polywrap\_uri\_resolvers.resolvers.legacy.wrapper\_cache.wrapper\_cache module +============================================================================== + +.. automodule:: polywrap_uri_resolvers.resolvers.legacy.wrapper_cache.wrapper_cache + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/source/polywrap-uri-resolvers/polywrap_uri_resolvers.resolvers.legacy.wrapper_cache_resolver.rst b/docs/source/polywrap-uri-resolvers/polywrap_uri_resolvers.resolvers.legacy.wrapper_cache_resolver.rst new file mode 100644 index 00000000..3b8f9000 --- /dev/null +++ b/docs/source/polywrap-uri-resolvers/polywrap_uri_resolvers.resolvers.legacy.wrapper_cache_resolver.rst @@ -0,0 +1,7 @@ +polywrap\_uri\_resolvers.resolvers.legacy.wrapper\_cache\_resolver module +========================================================================= + +.. automodule:: polywrap_uri_resolvers.resolvers.legacy.wrapper_cache_resolver + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/source/polywrap-uri-resolvers/polywrap_uri_resolvers.resolvers.package.package_to_wrapper_resolver.rst b/docs/source/polywrap-uri-resolvers/polywrap_uri_resolvers.resolvers.package.package_to_wrapper_resolver.rst deleted file mode 100644 index 26c46951..00000000 --- a/docs/source/polywrap-uri-resolvers/polywrap_uri_resolvers.resolvers.package.package_to_wrapper_resolver.rst +++ /dev/null @@ -1,7 +0,0 @@ -polywrap\_uri\_resolvers.resolvers.package.package\_to\_wrapper\_resolver module -================================================================================ - -.. automodule:: polywrap_uri_resolvers.resolvers.package.package_to_wrapper_resolver - :members: - :undoc-members: - :show-inheritance: diff --git a/docs/source/polywrap-uri-resolvers/polywrap_uri_resolvers.resolvers.package.rst b/docs/source/polywrap-uri-resolvers/polywrap_uri_resolvers.resolvers.package.rst index 028fbabd..0355c124 100644 --- a/docs/source/polywrap-uri-resolvers/polywrap_uri_resolvers.resolvers.package.rst +++ b/docs/source/polywrap-uri-resolvers/polywrap_uri_resolvers.resolvers.package.rst @@ -8,7 +8,6 @@ Submodules :maxdepth: 4 polywrap_uri_resolvers.resolvers.package.package_resolver - polywrap_uri_resolvers.resolvers.package.package_to_wrapper_resolver Module contents --------------- diff --git a/docs/source/polywrap-uri-resolvers/polywrap_uri_resolvers.rst b/docs/source/polywrap-uri-resolvers/polywrap_uri_resolvers.rst index 325c2026..0681ef4c 100644 --- a/docs/source/polywrap-uri-resolvers/polywrap_uri_resolvers.rst +++ b/docs/source/polywrap-uri-resolvers/polywrap_uri_resolvers.rst @@ -9,7 +9,6 @@ Subpackages polywrap_uri_resolvers.resolvers polywrap_uri_resolvers.types - polywrap_uri_resolvers.utils Submodules ---------- diff --git a/docs/source/polywrap-uri-resolvers/polywrap_uri_resolvers.types.cache.in_memory_wrapper_cache.rst b/docs/source/polywrap-uri-resolvers/polywrap_uri_resolvers.types.cache.in_memory_wrapper_cache.rst deleted file mode 100644 index 68ce2d79..00000000 --- a/docs/source/polywrap-uri-resolvers/polywrap_uri_resolvers.types.cache.in_memory_wrapper_cache.rst +++ /dev/null @@ -1,7 +0,0 @@ -polywrap\_uri\_resolvers.types.cache.in\_memory\_wrapper\_cache module -====================================================================== - -.. automodule:: polywrap_uri_resolvers.types.cache.in_memory_wrapper_cache - :members: - :undoc-members: - :show-inheritance: diff --git a/docs/source/polywrap-uri-resolvers/polywrap_uri_resolvers.types.cache.resolution_result_cache.in_memory_resolution_result_cache.rst b/docs/source/polywrap-uri-resolvers/polywrap_uri_resolvers.types.cache.resolution_result_cache.in_memory_resolution_result_cache.rst new file mode 100644 index 00000000..62251c5d --- /dev/null +++ b/docs/source/polywrap-uri-resolvers/polywrap_uri_resolvers.types.cache.resolution_result_cache.in_memory_resolution_result_cache.rst @@ -0,0 +1,7 @@ +polywrap\_uri\_resolvers.types.cache.resolution\_result\_cache.in\_memory\_resolution\_result\_cache module +=========================================================================================================== + +.. automodule:: polywrap_uri_resolvers.types.cache.resolution_result_cache.in_memory_resolution_result_cache + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/source/polywrap-uri-resolvers/polywrap_uri_resolvers.types.cache.resolution_result_cache.resolution_result_cache.rst b/docs/source/polywrap-uri-resolvers/polywrap_uri_resolvers.types.cache.resolution_result_cache.resolution_result_cache.rst new file mode 100644 index 00000000..fbe1f990 --- /dev/null +++ b/docs/source/polywrap-uri-resolvers/polywrap_uri_resolvers.types.cache.resolution_result_cache.resolution_result_cache.rst @@ -0,0 +1,7 @@ +polywrap\_uri\_resolvers.types.cache.resolution\_result\_cache.resolution\_result\_cache module +=============================================================================================== + +.. automodule:: polywrap_uri_resolvers.types.cache.resolution_result_cache.resolution_result_cache + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/source/polywrap-uri-resolvers/polywrap_uri_resolvers.types.cache.resolution_result_cache.rst b/docs/source/polywrap-uri-resolvers/polywrap_uri_resolvers.types.cache.resolution_result_cache.rst new file mode 100644 index 00000000..5fc52a7c --- /dev/null +++ b/docs/source/polywrap-uri-resolvers/polywrap_uri_resolvers.types.cache.resolution_result_cache.rst @@ -0,0 +1,19 @@ +polywrap\_uri\_resolvers.types.cache.resolution\_result\_cache package +====================================================================== + +Submodules +---------- + +.. toctree:: + :maxdepth: 4 + + polywrap_uri_resolvers.types.cache.resolution_result_cache.in_memory_resolution_result_cache + polywrap_uri_resolvers.types.cache.resolution_result_cache.resolution_result_cache + +Module contents +--------------- + +.. automodule:: polywrap_uri_resolvers.types.cache.resolution_result_cache + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/source/polywrap-uri-resolvers/polywrap_uri_resolvers.types.cache.rst b/docs/source/polywrap-uri-resolvers/polywrap_uri_resolvers.types.cache.rst index ebc84ccd..10d242c6 100644 --- a/docs/source/polywrap-uri-resolvers/polywrap_uri_resolvers.types.cache.rst +++ b/docs/source/polywrap-uri-resolvers/polywrap_uri_resolvers.types.cache.rst @@ -1,14 +1,13 @@ polywrap\_uri\_resolvers.types.cache package ============================================ -Submodules ----------- +Subpackages +----------- .. toctree:: :maxdepth: 4 - polywrap_uri_resolvers.types.cache.in_memory_wrapper_cache - polywrap_uri_resolvers.types.cache.wrapper_cache + polywrap_uri_resolvers.types.cache.resolution_result_cache Module contents --------------- diff --git a/docs/source/polywrap-uri-resolvers/polywrap_uri_resolvers.types.cache.wrapper_cache.rst b/docs/source/polywrap-uri-resolvers/polywrap_uri_resolvers.types.cache.wrapper_cache.rst deleted file mode 100644 index 552de53a..00000000 --- a/docs/source/polywrap-uri-resolvers/polywrap_uri_resolvers.types.cache.wrapper_cache.rst +++ /dev/null @@ -1,7 +0,0 @@ -polywrap\_uri\_resolvers.types.cache.wrapper\_cache module -========================================================== - -.. automodule:: polywrap_uri_resolvers.types.cache.wrapper_cache - :members: - :undoc-members: - :show-inheritance: diff --git a/docs/source/polywrap-uri-resolvers/polywrap_uri_resolvers.types.rst b/docs/source/polywrap-uri-resolvers/polywrap_uri_resolvers.types.rst index 5d186106..bb871a45 100644 --- a/docs/source/polywrap-uri-resolvers/polywrap_uri_resolvers.types.rst +++ b/docs/source/polywrap-uri-resolvers/polywrap_uri_resolvers.types.rst @@ -8,7 +8,6 @@ Subpackages :maxdepth: 4 polywrap_uri_resolvers.types.cache - polywrap_uri_resolvers.types.uri_resolution_context Submodules ---------- diff --git a/docs/source/polywrap-uri-resolvers/polywrap_uri_resolvers.types.uri_resolution_context.rst b/docs/source/polywrap-uri-resolvers/polywrap_uri_resolvers.types.uri_resolution_context.rst deleted file mode 100644 index 413cf7e9..00000000 --- a/docs/source/polywrap-uri-resolvers/polywrap_uri_resolvers.types.uri_resolution_context.rst +++ /dev/null @@ -1,19 +0,0 @@ -polywrap\_uri\_resolvers.types.uri\_resolution\_context package -=============================================================== - -Submodules ----------- - -.. toctree:: - :maxdepth: 4 - - polywrap_uri_resolvers.types.uri_resolution_context.uri_resolution_context - polywrap_uri_resolvers.types.uri_resolution_context.uri_resolution_step - -Module contents ---------------- - -.. automodule:: polywrap_uri_resolvers.types.uri_resolution_context - :members: - :undoc-members: - :show-inheritance: diff --git a/docs/source/polywrap-uri-resolvers/polywrap_uri_resolvers.types.uri_resolution_context.uri_resolution_context.rst b/docs/source/polywrap-uri-resolvers/polywrap_uri_resolvers.types.uri_resolution_context.uri_resolution_context.rst deleted file mode 100644 index 6b5887ce..00000000 --- a/docs/source/polywrap-uri-resolvers/polywrap_uri_resolvers.types.uri_resolution_context.uri_resolution_context.rst +++ /dev/null @@ -1,7 +0,0 @@ -polywrap\_uri\_resolvers.types.uri\_resolution\_context.uri\_resolution\_context module -======================================================================================= - -.. automodule:: polywrap_uri_resolvers.types.uri_resolution_context.uri_resolution_context - :members: - :undoc-members: - :show-inheritance: diff --git a/docs/source/polywrap-uri-resolvers/polywrap_uri_resolvers.types.uri_resolution_context.uri_resolution_step.rst b/docs/source/polywrap-uri-resolvers/polywrap_uri_resolvers.types.uri_resolution_context.uri_resolution_step.rst deleted file mode 100644 index b6c68a07..00000000 --- a/docs/source/polywrap-uri-resolvers/polywrap_uri_resolvers.types.uri_resolution_context.uri_resolution_step.rst +++ /dev/null @@ -1,7 +0,0 @@ -polywrap\_uri\_resolvers.types.uri\_resolution\_context.uri\_resolution\_step module -==================================================================================== - -.. automodule:: polywrap_uri_resolvers.types.uri_resolution_context.uri_resolution_step - :members: - :undoc-members: - :show-inheritance: diff --git a/docs/source/polywrap-uri-resolvers/polywrap_uri_resolvers.utils.build_clean_uri_history.rst b/docs/source/polywrap-uri-resolvers/polywrap_uri_resolvers.utils.build_clean_uri_history.rst deleted file mode 100644 index 0d210b38..00000000 --- a/docs/source/polywrap-uri-resolvers/polywrap_uri_resolvers.utils.build_clean_uri_history.rst +++ /dev/null @@ -1,7 +0,0 @@ -polywrap\_uri\_resolvers.utils.build\_clean\_uri\_history module -================================================================ - -.. automodule:: polywrap_uri_resolvers.utils.build_clean_uri_history - :members: - :undoc-members: - :show-inheritance: diff --git a/docs/source/polywrap-uri-resolvers/polywrap_uri_resolvers.utils.get_env_from_uri_history.rst b/docs/source/polywrap-uri-resolvers/polywrap_uri_resolvers.utils.get_env_from_uri_history.rst deleted file mode 100644 index 276e1cba..00000000 --- a/docs/source/polywrap-uri-resolvers/polywrap_uri_resolvers.utils.get_env_from_uri_history.rst +++ /dev/null @@ -1,7 +0,0 @@ -polywrap\_uri\_resolvers.utils.get\_env\_from\_uri\_history module -================================================================== - -.. automodule:: polywrap_uri_resolvers.utils.get_env_from_uri_history - :members: - :undoc-members: - :show-inheritance: diff --git a/docs/source/polywrap-uri-resolvers/polywrap_uri_resolvers.utils.get_uri_resolution_path.rst b/docs/source/polywrap-uri-resolvers/polywrap_uri_resolvers.utils.get_uri_resolution_path.rst deleted file mode 100644 index 1e90a114..00000000 --- a/docs/source/polywrap-uri-resolvers/polywrap_uri_resolvers.utils.get_uri_resolution_path.rst +++ /dev/null @@ -1,7 +0,0 @@ -polywrap\_uri\_resolvers.utils.get\_uri\_resolution\_path module -================================================================ - -.. automodule:: polywrap_uri_resolvers.utils.get_uri_resolution_path - :members: - :undoc-members: - :show-inheritance: diff --git a/docs/source/polywrap-uri-resolvers/polywrap_uri_resolvers.utils.rst b/docs/source/polywrap-uri-resolvers/polywrap_uri_resolvers.utils.rst deleted file mode 100644 index bedd0f05..00000000 --- a/docs/source/polywrap-uri-resolvers/polywrap_uri_resolvers.utils.rst +++ /dev/null @@ -1,20 +0,0 @@ -polywrap\_uri\_resolvers.utils package -====================================== - -Submodules ----------- - -.. toctree:: - :maxdepth: 4 - - polywrap_uri_resolvers.utils.build_clean_uri_history - polywrap_uri_resolvers.utils.get_env_from_uri_history - polywrap_uri_resolvers.utils.get_uri_resolution_path - -Module contents ---------------- - -.. automodule:: polywrap_uri_resolvers.utils - :members: - :undoc-members: - :show-inheritance: diff --git a/docs/source/polywrap-wasm/polywrap_wasm.imports.rst b/docs/source/polywrap-wasm/polywrap_wasm.imports.rst index 5e814e8d..535cc5f0 100644 --- a/docs/source/polywrap-wasm/polywrap_wasm.imports.rst +++ b/docs/source/polywrap-wasm/polywrap_wasm.imports.rst @@ -8,7 +8,6 @@ Subpackages :maxdepth: 4 polywrap_wasm.imports.types - polywrap_wasm.imports.utils Submodules ---------- diff --git a/docs/source/polywrap-wasm/polywrap_wasm.imports.utils.rst b/docs/source/polywrap-wasm/polywrap_wasm.imports.utils.rst deleted file mode 100644 index 7a040966..00000000 --- a/docs/source/polywrap-wasm/polywrap_wasm.imports.utils.rst +++ /dev/null @@ -1,18 +0,0 @@ -polywrap\_wasm.imports.utils package -==================================== - -Submodules ----------- - -.. toctree:: - :maxdepth: 4 - - polywrap_wasm.imports.utils.unsync_invoke - -Module contents ---------------- - -.. automodule:: polywrap_wasm.imports.utils - :members: - :undoc-members: - :show-inheritance: diff --git a/docs/source/polywrap-wasm/polywrap_wasm.imports.utils.unsync_invoke.rst b/docs/source/polywrap-wasm/polywrap_wasm.imports.utils.unsync_invoke.rst deleted file mode 100644 index 34db2358..00000000 --- a/docs/source/polywrap-wasm/polywrap_wasm.imports.utils.unsync_invoke.rst +++ /dev/null @@ -1,7 +0,0 @@ -polywrap\_wasm.imports.utils.unsync\_invoke module -================================================== - -.. automodule:: polywrap_wasm.imports.utils.unsync_invoke - :members: - :undoc-members: - :show-inheritance: diff --git a/docs/tox.ini b/docs/tox.ini new file mode 100644 index 00000000..b34fa320 --- /dev/null +++ b/docs/tox.ini @@ -0,0 +1,29 @@ +[tox] +isolated_build = True +envlist = py310 + + +[testenv] +commands = + echo "Run tox -e clean to clean the old docs" + echo "Run tox -e docgen to auto extract docs" + echo "Run tox -e build to build the docs" + +[testenv:clean] +commands = + rm -Rf ./source/**/*.rst + +[testenv:docgen] +commands = + sphinx-apidoc ../packages/polywrap-msgpack/polywrap_msgpack -o ./source/polywrap-msgpack -e + sphinx-apidoc ../packages/polywrap-manifest/polywrap_manifest -o ./source/polywrap-manifest -e + sphinx-apidoc ../packages/polywrap-core/polywrap_core -o ./source/polywrap-core -e + sphinx-apidoc ../packages/polywrap-wasm/polywrap_wasm -o ./source/polywrap-wasm -e + sphinx-apidoc ../packages/polywrap-plugin/polywrap_plugin -o ./source/polywrap-plugin -e + sphinx-apidoc ../packages/polywrap-uri-resolvers/polywrap_uri_resolvers -o ./source/polywrap-uri-resolvers -e + sphinx-apidoc ../packages/polywrap-client/polywrap_client -o ./source/polywrap-client -e + sphinx-apidoc ../packages/polywrap-client-config-builder/polywrap_client_config_builder -o ./source/polywrap-client-config-builder -e + +[testenv:build] +commands = + sphinx-build source/ build diff --git a/packages/polywrap-client-config-builder/polywrap_client_config_builder/configures/base_configure.py b/packages/polywrap-client-config-builder/polywrap_client_config_builder/configures/base_configure.py index 0dfcb7e1..6e23b1b9 100644 --- a/packages/polywrap-client-config-builder/polywrap_client_config_builder/configures/base_configure.py +++ b/packages/polywrap-client-config-builder/polywrap_client_config_builder/configures/base_configure.py @@ -4,12 +4,8 @@ from ..types import BuilderConfig, ClientConfigBuilder -class BaseConfigure(ClientConfigBuilder, ABC): - """BaseConfigure is the base configure class for the client config builder. - - Attributes: - config (BuilderConfig): The internal configuration. - """ +class BaseConfigure(ClientConfigBuilder): + """BaseConfigure is the base configure class for the client config builder.""" config: BuilderConfig From 088fd650cbe49c880346b634f0f7bab7376d293a Mon Sep 17 00:00:00 2001 From: Niraj Kamdar Date: Sun, 11 Jun 2023 20:23:51 +0530 Subject: [PATCH 27/47] chore: remove unnecessary tox file --- docs/tox.ini | 29 ----------------------------- 1 file changed, 29 deletions(-) delete mode 100644 docs/tox.ini diff --git a/docs/tox.ini b/docs/tox.ini deleted file mode 100644 index b34fa320..00000000 --- a/docs/tox.ini +++ /dev/null @@ -1,29 +0,0 @@ -[tox] -isolated_build = True -envlist = py310 - - -[testenv] -commands = - echo "Run tox -e clean to clean the old docs" - echo "Run tox -e docgen to auto extract docs" - echo "Run tox -e build to build the docs" - -[testenv:clean] -commands = - rm -Rf ./source/**/*.rst - -[testenv:docgen] -commands = - sphinx-apidoc ../packages/polywrap-msgpack/polywrap_msgpack -o ./source/polywrap-msgpack -e - sphinx-apidoc ../packages/polywrap-manifest/polywrap_manifest -o ./source/polywrap-manifest -e - sphinx-apidoc ../packages/polywrap-core/polywrap_core -o ./source/polywrap-core -e - sphinx-apidoc ../packages/polywrap-wasm/polywrap_wasm -o ./source/polywrap-wasm -e - sphinx-apidoc ../packages/polywrap-plugin/polywrap_plugin -o ./source/polywrap-plugin -e - sphinx-apidoc ../packages/polywrap-uri-resolvers/polywrap_uri_resolvers -o ./source/polywrap-uri-resolvers -e - sphinx-apidoc ../packages/polywrap-client/polywrap_client -o ./source/polywrap-client -e - sphinx-apidoc ../packages/polywrap-client-config-builder/polywrap_client_config_builder -o ./source/polywrap-client-config-builder -e - -[testenv:build] -commands = - sphinx-build source/ build From 316a3eed5d6ba53aa1d736c896f84110fb8ae376 Mon Sep 17 00:00:00 2001 From: Niraj Kamdar Date: Sun, 11 Jun 2023 20:34:37 +0530 Subject: [PATCH 28/47] feat: add readthedocs.yaml --- .readthedocs.yaml | 43 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) create mode 100644 .readthedocs.yaml diff --git a/.readthedocs.yaml b/.readthedocs.yaml new file mode 100644 index 00000000..c87840ba --- /dev/null +++ b/.readthedocs.yaml @@ -0,0 +1,43 @@ +# .readthedocs.yaml +# Read the Docs configuration file +# See https://docs.readthedocs.io/en/stable/config-file/v2.html for details + +# Required +version: 2 + +# Set the OS, Python version and other tools you might need +build: + os: ubuntu-22.04 + tools: + python: "3.10" + # You can also specify other tool versions: + # nodejs: "19" + # rust: "1.64" + # golang: "1.19" + jobs: + post_create_environment: + # Install poetry + # https://python-poetry.org/docs/#installing-manually + - curl -sSL https://install.python-poetry.org | python3 - + # Tell poetry to not use a virtual environment + - poetry config virtualenvs.create false + post_install: + # Install dependencies with 'docs' dependency group + # https://python-poetry.org/docs/managing-dependencies/#dependency-groups + - poetry install + +# Build documentation in the "docs/" directory with Sphinx +sphinx: + configuration: docs/conf.py + +# Optionally build your docs in additional formats such as PDF and ePub +# formats: +# - pdf +# - epub + +# Optional but recommended, declare the Python requirements required +# to build your documentation +# See https://docs.readthedocs.io/en/stable/guides/reproducible-builds.html +# python: +# install: +# - requirements: docs/requirements.txt From 0ad13a552821bae9459afddfad414c933adfbc4b Mon Sep 17 00:00:00 2001 From: Niraj Kamdar Date: Sun, 11 Jun 2023 20:37:22 +0530 Subject: [PATCH 29/47] debug: try fix --- .readthedocs.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.readthedocs.yaml b/.readthedocs.yaml index c87840ba..34806786 100644 --- a/.readthedocs.yaml +++ b/.readthedocs.yaml @@ -18,7 +18,7 @@ build: post_create_environment: # Install poetry # https://python-poetry.org/docs/#installing-manually - - curl -sSL https://install.python-poetry.org | python3 - + - pip install poetry # Tell poetry to not use a virtual environment - poetry config virtualenvs.create false post_install: From 755eb3c79ccb65bc5a7c91e1178100c0ae5ce282 Mon Sep 17 00:00:00 2001 From: Niraj Kamdar Date: Sun, 11 Jun 2023 20:41:25 +0530 Subject: [PATCH 30/47] debug --- .readthedocs.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.readthedocs.yaml b/.readthedocs.yaml index 34806786..d0e86648 100644 --- a/.readthedocs.yaml +++ b/.readthedocs.yaml @@ -24,7 +24,7 @@ build: post_install: # Install dependencies with 'docs' dependency group # https://python-poetry.org/docs/managing-dependencies/#dependency-groups - - poetry install + - cd docs && poetry install && cd .. # Build documentation in the "docs/" directory with Sphinx sphinx: From 85c84a6422e32be2436c118c7c2e33b7e93a6870 Mon Sep 17 00:00:00 2001 From: Niraj Kamdar Date: Sun, 11 Jun 2023 20:44:18 +0530 Subject: [PATCH 31/47] debug --- .readthedocs.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.readthedocs.yaml b/.readthedocs.yaml index d0e86648..7ab672fa 100644 --- a/.readthedocs.yaml +++ b/.readthedocs.yaml @@ -28,7 +28,7 @@ build: # Build documentation in the "docs/" directory with Sphinx sphinx: - configuration: docs/conf.py + configuration: docs/source/conf.py # Optionally build your docs in additional formats such as PDF and ePub # formats: From d4429a698c850a68506f5bcd4d459e6288b4bd96 Mon Sep 17 00:00:00 2001 From: Niraj Kamdar Date: Tue, 13 Jun 2023 14:40:39 +0530 Subject: [PATCH 32/47] feat: add examples and doctest to test those --- .../polywrap_msgpack/decoder.py | 17 ++++++++++- .../polywrap_msgpack/encoder.py | 16 +++++++++- .../extensions/generic_map.py | 29 ++++++++++++++++++- .../polywrap_msgpack/sanitize.py | 23 +++++++++++++++ .../polywrap-msgpack/tests/run_doctest.py | 24 +++++++++++++++ 5 files changed, 106 insertions(+), 3 deletions(-) create mode 100644 packages/polywrap-msgpack/tests/run_doctest.py diff --git a/packages/polywrap-msgpack/polywrap_msgpack/decoder.py b/packages/polywrap-msgpack/polywrap_msgpack/decoder.py index a768be9b..65bc1bf9 100644 --- a/packages/polywrap-msgpack/polywrap_msgpack/decoder.py +++ b/packages/polywrap-msgpack/polywrap_msgpack/decoder.py @@ -30,7 +30,7 @@ def decode_ext_hook(code: int, data: bytes) -> Any: def msgpack_decode(val: bytes) -> Any: - """Decode msgpack bytes into a valid python object. + r"""Decode msgpack bytes into a valid python object. Args: val (bytes): msgpack encoded bytes @@ -41,6 +41,21 @@ def msgpack_decode(val: bytes) -> Any: Returns: Any: any python object + + Examples: + >>> from polywrap_msgpack import msgpack_encode + >>> from polywrap_msgpack import msgpack_decode + >>> from polywrap_msgpack import GenericMap + >>> msgpack_decode(msgpack_encode({"a": 1})) + {'a': 1} + >>> msgpack_decode(msgpack_encode(GenericMap({"a": 1}))) + GenericMap({'a': 1}) + >>> msgpack_decode(msgpack_encode([{"a": 2}, {"b": 4}])) + [{'a': 2}, {'b': 4}] + >>> msgpack_decode(b"\xc1") + Traceback (most recent call last): + ... + polywrap_msgpack.errors.MsgpackDecodeError: Failed to decode msgpack data """ try: return msgpack.unpackb( # pyright: ignore[reportUnknownMemberType] diff --git a/packages/polywrap-msgpack/polywrap_msgpack/encoder.py b/packages/polywrap-msgpack/polywrap_msgpack/encoder.py index 71ea9c16..b9f25f6e 100644 --- a/packages/polywrap-msgpack/polywrap_msgpack/encoder.py +++ b/packages/polywrap-msgpack/polywrap_msgpack/encoder.py @@ -38,17 +38,31 @@ def encode_ext_hook(obj: Any) -> ExtType: def msgpack_encode(value: Any) -> bytes: - """Encode any python object into msgpack bytes. + r"""Encode any python object into msgpack bytes. Args: value (Any): any valid python object Raises: + MsgpackExtError: when given object is not a supported extension type MsgpackEncodeError: when sanitized object is not msgpack serializable MsgpackSanitizeError: when given object is not sanitizable Returns: bytes: encoded msgpack value + + Examples: + >>> from polywrap_msgpack import msgpack_encode + >>> from polywrap_msgpack import msgpack_decode + >>> from polywrap_msgpack import GenericMap + >>> msgpack_encode({"a": 1}) + b'\x81\xa1a\x01' + >>> msgpack_encode(GenericMap({"a": 1})) + b'\xd6\x01\x81\xa1a\x01' + >>> msgpack_encode({1.0: 1}) + Traceback (most recent call last): + ... + polywrap_msgpack.errors.MsgpackSanitizeError: Failed to sanitize object """ try: sanitized = sanitize(value) diff --git a/packages/polywrap-msgpack/polywrap_msgpack/extensions/generic_map.py b/packages/polywrap-msgpack/polywrap_msgpack/extensions/generic_map.py index ec6c294f..01bb974e 100644 --- a/packages/polywrap-msgpack/polywrap_msgpack/extensions/generic_map.py +++ b/packages/polywrap-msgpack/polywrap_msgpack/extensions/generic_map.py @@ -6,7 +6,34 @@ class GenericMap(MutableMapping[K, V]): - """GenericMap is a type that can be used to represent generic map extension type in msgpack.""" + """GenericMap is a type that can be used to represent generic map extension type in msgpack. + + Examples: + >>> from polywrap_msgpack import GenericMap + >>> GenericMap({1: 2, 3: 4}) + GenericMap({1: 2, 3: 4}) + >>> map = GenericMap({1: 2, 3: 4}) + >>> map[5] = 6 + >>> map + GenericMap({1: 2, 3: 4, 5: 6}) + >>> map[7] + Traceback (most recent call last): + ... + KeyError: 7 + >>> 7 in map + False + >>> 1 in map + True + >>> len(map) + 3 + >>> del map[1] + >>> map + GenericMap({3: 4, 5: 6}) + >>> del map[7] + Traceback (most recent call last): + ... + KeyError: 7 + """ _map: Dict[K, V] diff --git a/packages/polywrap-msgpack/polywrap_msgpack/sanitize.py b/packages/polywrap-msgpack/polywrap_msgpack/sanitize.py index 93d8ba1b..bb655d92 100644 --- a/packages/polywrap-msgpack/polywrap_msgpack/sanitize.py +++ b/packages/polywrap-msgpack/polywrap_msgpack/sanitize.py @@ -18,6 +18,29 @@ def sanitize(value: Any) -> Any: Returns: Any: msgpack compatible sanitized value + + Examples: + >>> sanitize({"a": 1}) + {'a': 1} + >>> sanitize({1, 2, 3}) + [1, 2, 3] + >>> sanitize((1, 2, 3)) + [1, 2, 3] + >>> sanitize([{1}, (2, 3), [4]]) + [[1], [2, 3], [4]] + >>> class Foo: pass + >>> foo = Foo() + >>> foo.bar = 1 + >>> sanitize(foo) + {'bar': 1} + >>> sanitize({1: 1}) + Traceback (most recent call last): + ... + ValueError: Dict key must be string, got 1 of type + >>> sanitize(GenericMap({1: 2})) + Traceback (most recent call last): + ... + ValueError: GenericMap key must be string, got 1 of type """ if isinstance(value, GenericMap): dictionary: Dict[Any, Any] = cast( diff --git a/packages/polywrap-msgpack/tests/run_doctest.py b/packages/polywrap-msgpack/tests/run_doctest.py new file mode 100644 index 00000000..0d4f401e --- /dev/null +++ b/packages/polywrap-msgpack/tests/run_doctest.py @@ -0,0 +1,24 @@ +# test_all.py +import doctest +from typing import Any +import unittest +import pkgutil +import polywrap_msgpack # replace with your actual package name + +def load_tests(loader: Any, tests: Any, ignore: Any) -> Any: + """Load doctests and return TestSuite object.""" + modules = pkgutil.walk_packages( + path=polywrap_msgpack.__path__, + prefix=f"{polywrap_msgpack.__name__}.", + onerror=lambda x: None, + ) + for _, modname, _ in modules: + try: + module = __import__(modname, fromlist="dummy") + tests.addTests(doctest.DocTestSuite(module)) + except (ImportError, ValueError, AttributeError): + continue + return tests + +if __name__ == "__main__": + unittest.main() From e02d8bab5f0739ee8be38baf2f4005670da90baf Mon Sep 17 00:00:00 2001 From: Niraj Kamdar Date: Tue, 13 Jun 2023 16:28:17 +0530 Subject: [PATCH 33/47] docs: improve msgpack docs --- .../polywrap_msgpack/__init__.py | 21 ------------------- .../polywrap_msgpack/decoder.py | 9 ++++++-- .../polywrap_msgpack/encoder.py | 9 ++++++-- .../polywrap_msgpack/errors.py | 9 ++++++++ .../polywrap_msgpack/sanitize.py | 3 +++ 5 files changed, 26 insertions(+), 25 deletions(-) diff --git a/packages/polywrap-msgpack/polywrap_msgpack/__init__.py b/packages/polywrap-msgpack/polywrap_msgpack/__init__.py index 096032d9..2f317563 100644 --- a/packages/polywrap-msgpack/polywrap_msgpack/__init__.py +++ b/packages/polywrap-msgpack/polywrap_msgpack/__init__.py @@ -9,26 +9,5 @@ """ from .decoder import * from .encoder import * -from .errors import * from .extensions import * from .sanitize import * - -__all__ = [ - # Serializer - "msgpack_decode", - "msgpack_encode", - # Extensions - "decode_ext_hook", - "encode_ext_hook", - "ExtensionTypes", - # Sanitizers - "sanitize", - # Extention types - "GenericMap", - # Errors - "MsgpackError", - "MsgpackDecodeError", - "MsgpackEncodeError", - "MsgpackExtError", - "MsgpackSanitizeError", -] diff --git a/packages/polywrap-msgpack/polywrap_msgpack/decoder.py b/packages/polywrap-msgpack/polywrap_msgpack/decoder.py index 65bc1bf9..5de64824 100644 --- a/packages/polywrap-msgpack/polywrap_msgpack/decoder.py +++ b/packages/polywrap-msgpack/polywrap_msgpack/decoder.py @@ -10,7 +10,7 @@ from .extensions import ExtensionTypes, GenericMap -def decode_ext_hook(code: int, data: bytes) -> Any: +def _decode_ext_hook(code: int, data: bytes) -> Any: """Extension hook for extending the msgpack supported types. Args: @@ -59,7 +59,12 @@ def msgpack_decode(val: bytes) -> Any: """ try: return msgpack.unpackb( # pyright: ignore[reportUnknownMemberType] - val, ext_hook=decode_ext_hook + val, ext_hook=_decode_ext_hook ) except Exception as e: raise MsgpackDecodeError("Failed to decode msgpack data") from e + + +__all__ = [ + "msgpack_decode", +] diff --git a/packages/polywrap-msgpack/polywrap_msgpack/encoder.py b/packages/polywrap-msgpack/polywrap_msgpack/encoder.py index b9f25f6e..a210ca0e 100644 --- a/packages/polywrap-msgpack/polywrap_msgpack/encoder.py +++ b/packages/polywrap-msgpack/polywrap_msgpack/encoder.py @@ -12,7 +12,7 @@ from .sanitize import sanitize -def encode_ext_hook(obj: Any) -> ExtType: +def _encode_ext_hook(obj: Any) -> ExtType: """Extension hook for extending the msgpack supported types. Args: @@ -70,6 +70,11 @@ def msgpack_encode(value: Any) -> bytes: raise MsgpackSanitizeError("Failed to sanitize object") from e try: - return msgpack.packb(sanitized, default=encode_ext_hook, use_bin_type=True) + return msgpack.packb(sanitized, default=_encode_ext_hook, use_bin_type=True) except Exception as e: raise MsgpackEncodeError("Failed to encode object") from e + + +__all__ = [ + "msgpack_encode", +] diff --git a/packages/polywrap-msgpack/polywrap_msgpack/errors.py b/packages/polywrap-msgpack/polywrap_msgpack/errors.py index c008c6e0..ab0540bd 100644 --- a/packages/polywrap-msgpack/polywrap_msgpack/errors.py +++ b/packages/polywrap-msgpack/polywrap_msgpack/errors.py @@ -20,3 +20,12 @@ class MsgpackExtError(MsgpackError): class MsgpackSanitizeError(MsgpackError): """Raised when there is an error sanitizing a python object\ into a msgpack encoder compatible format.""" + + +__all__ = [ + "MsgpackError", + "MsgpackDecodeError", + "MsgpackEncodeError", + "MsgpackExtError", + "MsgpackSanitizeError", +] diff --git a/packages/polywrap-msgpack/polywrap_msgpack/sanitize.py b/packages/polywrap-msgpack/polywrap_msgpack/sanitize.py index bb655d92..6c7407a2 100644 --- a/packages/polywrap-msgpack/polywrap_msgpack/sanitize.py +++ b/packages/polywrap-msgpack/polywrap_msgpack/sanitize.py @@ -84,3 +84,6 @@ def sanitize(value: Any) -> Any: if hasattr(value, "__dict__"): return {k: sanitize(v) for k, v in cast(Dict[Any, Any], vars(value)).items()} return value + + +__all__ = ["sanitize"] From 4c7c4ca5259bd5d70b61f4e2fb179046d0706554 Mon Sep 17 00:00:00 2001 From: Niraj Kamdar Date: Tue, 13 Jun 2023 16:29:17 +0530 Subject: [PATCH 34/47] chore: updating core for better docs --- .../polywrap_core/types/config.py | 1 - .../polywrap_core/types/errors.py | 8 +------- .../polywrap_core/types/invocable.py | 2 +- .../types/uri_package_wrapper.py | 20 ++++++++++++++++++- 4 files changed, 21 insertions(+), 10 deletions(-) diff --git a/packages/polywrap-core/polywrap_core/types/config.py b/packages/polywrap-core/polywrap_core/types/config.py index 4b124877..300d7ffc 100644 --- a/packages/polywrap-core/polywrap_core/types/config.py +++ b/packages/polywrap-core/polywrap_core/types/config.py @@ -20,7 +20,6 @@ class ClientConfig: and value is list of implementation URIs. resolver (UriResolver): URI resolver. """ - envs: Dict[Uri, Any] = field(default_factory=dict) interfaces: Dict[Uri, List[Uri]] = field(default_factory=dict) resolver: UriResolver diff --git a/packages/polywrap-core/polywrap_core/types/errors.py b/packages/polywrap-core/polywrap_core/types/errors.py index e89e9ea0..74a13228 100644 --- a/packages/polywrap-core/polywrap_core/types/errors.py +++ b/packages/polywrap-core/polywrap_core/types/errors.py @@ -88,13 +88,7 @@ def __init__( class WrapInvocationError(WrapAbortError): - """Raises when there is an error invoking a wrapper. - - Attributes: - invoke_options (InvokeOptions): InvokeOptions for the invocation \ - that was aborted. - message: The message provided by the wrapper. - """ + """Raises when there is an error invoking a wrapper.""" class WrapGetImplementationsError(WrapError): diff --git a/packages/polywrap-core/polywrap_core/types/invocable.py b/packages/polywrap-core/polywrap_core/types/invocable.py index 847cfdae..ad3c3d8a 100644 --- a/packages/polywrap-core/polywrap_core/types/invocable.py +++ b/packages/polywrap-core/polywrap_core/types/invocable.py @@ -15,7 +15,7 @@ class InvocableResult: """Result of a wrapper invocation. - Args: + Attributes: result (Any): Invocation result. The type of this value is \ the return type of the method. encoded (Optional[bool]): It will be set true if result is encoded diff --git a/packages/polywrap-core/polywrap_core/types/uri_package_wrapper.py b/packages/polywrap-core/polywrap_core/types/uri_package_wrapper.py index a4c3e5da..4d4a80d5 100644 --- a/packages/polywrap-core/polywrap_core/types/uri_package_wrapper.py +++ b/packages/polywrap-core/polywrap_core/types/uri_package_wrapper.py @@ -1,4 +1,22 @@ -"""UriPackageOrWrapper is a Union type alias for a URI, a package, or a wrapper.""" +"""UriPackageOrWrapper is a Union type alias for a URI, a package, or a wrapper. + +UriPackageOrWrapper = Union[Uri, UriWrapper, UriPackage] + +Examples: + >>> from polywrap_core.types import UriPackageOrWrapper + >>> from polywrap_core.types import Uri + >>> from polywrap_core.types import UriPackage + >>> from polywrap_core.types import UriWrapper + >>> result: UriPackageOrWrapper = Uri("authority", "path") + >>> match result: + ... case Uri(uri): + ... print(uri) + ... case _: + ... print("Not a URI") + ... + wrap://authority/path + +""" from __future__ import annotations from typing import Union From 2c358f3198d183e5727378887e014814912c67d5 Mon Sep 17 00:00:00 2001 From: Niraj Kamdar Date: Tue, 13 Jun 2023 17:36:22 +0530 Subject: [PATCH 35/47] wip:docs --- .../polywrap_uri_resolvers.types.rst | 1 - ..._uri_resolvers.types.uri_resolver_like.rst | 7 ----- .../types/build_options.py | 2 +- .../types/builder_config.py | 2 +- .../polywrap_core/types/config.py | 3 +- .../polywrap_core/types/errors.py | 26 ++++++++++++++--- .../polywrap_core/types/invocable.py | 2 +- .../polywrap-core/polywrap_core/types/uri.py | 20 ++++++++----- .../polywrap_core/types/uri_package.py | 9 ++++-- .../types/uri_resolution_context.py | 18 +++++------- .../types/uri_resolution_step.py | 2 +- .../polywrap_core/types/uri_wrapper.py | 4 +-- .../utils/build_clean_uri_history.py | 4 +-- .../utils/get_env_from_resolution_path.py | 4 +-- .../polywrap_manifest/manifest.py | 2 +- .../polywrap-plugin/polywrap_plugin/module.py | 10 +++---- .../polywrap_plugin/package.py | 2 +- .../polywrap_plugin/wrapper.py | 6 ++-- .../tests/test_plugin_module.py | 4 +-- .../polywrap_uri_resolvers/errors.py | 28 +++++++++--------- .../aggregator/uri_resolver_aggregator.py | 10 ++----- .../cache/resolution_result_cache_resolver.py | 17 +++++------ .../extensions/extendable_uri_resolver.py | 24 +++++++-------- .../extension_wrapper_uri_resolver.py | 9 ++---- .../uri_resolver_extension_file_reader.py | 15 +++++----- .../resolvers/legacy/base_resolver.py | 14 ++++----- .../resolvers/legacy/fs_resolver.py | 12 ++++---- .../legacy/package_to_wrapper_resolver.py | 11 ++----- .../resolvers/legacy/redirect_resolver.py | 12 ++++---- .../wrapper_cache/in_memory_wrapper_cache.py | 7 ++--- .../legacy/wrapper_cache_resolver.py | 14 +++------ .../resolvers/package/package_resolver.py | 14 ++++----- .../resolvers/recursive/recursive_resolver.py | 6 +--- .../resolvers/redirect/redirect_resolver.py | 9 ++---- .../resolvers/static/static_resolver.py | 8 ++--- .../resolvers/wrapper/wrapper_resolver.py | 8 +---- .../polywrap_uri_resolvers/types/__init__.py | 1 - .../in_memory_resolution_result_cache.py | 8 ++--- .../types/uri_redirect.py | 2 +- .../types/uri_resolver_like.py | 29 ------------------- .../polywrap-wasm/polywrap_wasm/constants.py | 4 +++ .../polywrap-wasm/polywrap_wasm/exports.py | 28 ++++++++---------- .../polywrap_wasm/imports/wrap_imports.py | 15 +++++----- .../polywrap_wasm/inmemory_file_reader.py | 9 +++--- .../polywrap_wasm/linker/wrap_linker.py | 11 ++++--- .../polywrap_wasm/types/state.py | 12 ++++---- .../polywrap_wasm/wasm_package.py | 11 ++++--- .../polywrap_wasm/wasm_wrapper.py | 6 ++-- 48 files changed, 210 insertions(+), 272 deletions(-) delete mode 100644 docs/source/polywrap-uri-resolvers/polywrap_uri_resolvers.types.uri_resolver_like.rst delete mode 100644 packages/polywrap-uri-resolvers/polywrap_uri_resolvers/types/uri_resolver_like.py diff --git a/docs/source/polywrap-uri-resolvers/polywrap_uri_resolvers.types.rst b/docs/source/polywrap-uri-resolvers/polywrap_uri_resolvers.types.rst index bb871a45..f40bfc8f 100644 --- a/docs/source/polywrap-uri-resolvers/polywrap_uri_resolvers.types.rst +++ b/docs/source/polywrap-uri-resolvers/polywrap_uri_resolvers.types.rst @@ -17,7 +17,6 @@ Submodules polywrap_uri_resolvers.types.static_resolver_like polywrap_uri_resolvers.types.uri_redirect - polywrap_uri_resolvers.types.uri_resolver_like Module contents --------------- diff --git a/docs/source/polywrap-uri-resolvers/polywrap_uri_resolvers.types.uri_resolver_like.rst b/docs/source/polywrap-uri-resolvers/polywrap_uri_resolvers.types.uri_resolver_like.rst deleted file mode 100644 index e5c0fcf0..00000000 --- a/docs/source/polywrap-uri-resolvers/polywrap_uri_resolvers.types.uri_resolver_like.rst +++ /dev/null @@ -1,7 +0,0 @@ -polywrap\_uri\_resolvers.types.uri\_resolver\_like module -========================================================= - -.. automodule:: polywrap_uri_resolvers.types.uri_resolver_like - :members: - :undoc-members: - :show-inheritance: diff --git a/packages/polywrap-client-config-builder/polywrap_client_config_builder/types/build_options.py b/packages/polywrap-client-config-builder/polywrap_client_config_builder/types/build_options.py index a9ff21a8..d146483e 100644 --- a/packages/polywrap-client-config-builder/polywrap_client_config_builder/types/build_options.py +++ b/packages/polywrap-client-config-builder/polywrap_client_config_builder/types/build_options.py @@ -10,7 +10,7 @@ class BuildOptions: """BuildOptions defines the options for build method of the client config builder. - Attributes: + Args: resolution_result_cache: The Resolution Result Cache. resolver: The URI resolver. """ diff --git a/packages/polywrap-client-config-builder/polywrap_client_config_builder/types/builder_config.py b/packages/polywrap-client-config-builder/polywrap_client_config_builder/types/builder_config.py index d94ac526..3f671c06 100644 --- a/packages/polywrap-client-config-builder/polywrap_client_config_builder/types/builder_config.py +++ b/packages/polywrap-client-config-builder/polywrap_client_config_builder/types/builder_config.py @@ -9,7 +9,7 @@ class BuilderConfig: """BuilderConfig defines the internal configuration for the client config builder. - Attributes: + Args: envs (Dict[Uri, Any]): The environment variables for the wrappers. interfaces (Dict[Uri, List[Uri]]): The interfaces and their implementations. wrappers (Dict[Uri, Wrapper]): The wrappers. diff --git a/packages/polywrap-core/polywrap_core/types/config.py b/packages/polywrap-core/polywrap_core/types/config.py index 300d7ffc..0e269477 100644 --- a/packages/polywrap-core/polywrap_core/types/config.py +++ b/packages/polywrap-core/polywrap_core/types/config.py @@ -12,7 +12,7 @@ class ClientConfig: """Client configuration. - Attributes: + Args: envs (Dict[Uri, Any]): Dictionary of environments \ where key is URI and value is env. interfaces (Dict[Uri, List[Uri]]): Dictionary of interfaces \ @@ -20,6 +20,7 @@ class ClientConfig: and value is list of implementation URIs. resolver (UriResolver): URI resolver. """ + envs: Dict[Uri, Any] = field(default_factory=dict) interfaces: Dict[Uri, List[Uri]] = field(default_factory=dict) resolver: UriResolver diff --git a/packages/polywrap-core/polywrap_core/types/errors.py b/packages/polywrap-core/polywrap_core/types/errors.py index 74a13228..54732eff 100644 --- a/packages/polywrap-core/polywrap_core/types/errors.py +++ b/packages/polywrap-core/polywrap_core/types/errors.py @@ -28,17 +28,26 @@ class WrapError(Exception): class WrapAbortError(WrapError): """Raises when a wrapper aborts execution. - Attributes: + Args: invoke_options (InvokeOptions): InvokeOptions for the invocation\ that was aborted. message: The message provided by the wrapper. """ uri: Uri + """The URI of the wrapper.""" + method: str + """The method that was invoked.""" + message: str + """The message provided by the wrapper.""" + invoke_args: Optional[str] = None + """The arguments that were passed to the wrapper.""" + invoke_env: Optional[str] = None + """The environment variables that were passed to the wrapper.""" def __init__( self, @@ -88,19 +97,28 @@ def __init__( class WrapInvocationError(WrapAbortError): - """Raises when there is an error invoking a wrapper.""" + """Raises when there is an error invoking a wrapper. + + Args: + invoke_options (InvokeOptions): InvokeOptions for the invocation\ + that was aborted. + message: The message provided by the wrapper. + """ class WrapGetImplementationsError(WrapError): """Raises when there is an error getting implementations of an interface. - Attributes: + Args: uri (Uri): URI of the interface. - message: The message provided by the wrapper. + message (str): The message provided by the wrapper. """ uri: Uri + """The URI of the interface.""" + message: str + """The message provided by the wrapper.""" def __init__(self, uri: Uri, message: str): """Initialize a new instance of WrapGetImplementationsError.""" diff --git a/packages/polywrap-core/polywrap_core/types/invocable.py b/packages/polywrap-core/polywrap_core/types/invocable.py index ad3c3d8a..847cfdae 100644 --- a/packages/polywrap-core/polywrap_core/types/invocable.py +++ b/packages/polywrap-core/polywrap_core/types/invocable.py @@ -15,7 +15,7 @@ class InvocableResult: """Result of a wrapper invocation. - Attributes: + Args: result (Any): Invocation result. The type of this value is \ the return type of the method. encoded (Optional[bool]): It will be set true if result is encoded diff --git a/packages/polywrap-core/polywrap_core/types/uri.py b/packages/polywrap-core/polywrap_core/types/uri.py index 425b7a9a..4d1ef475 100644 --- a/packages/polywrap-core/polywrap_core/types/uri.py +++ b/packages/polywrap-core/polywrap_core/types/uri.py @@ -17,7 +17,16 @@ class Uri: `:///` where the scheme is always "wrap" and the \ authority is the URI scheme of the underlying wrapper. + Args: + authority (str): The authority of the URI. This is used to determine \ + which URI resolver to use. + path (str): The path of the URI. This is used to determine the \ + location of the wrapper. + Examples: + >>> uri = Uri("ipfs", "QmHASH") + >>> uri.uri + "wrap://ipfs/QmHASH" >>> uri = Uri.from_str("ipfs/QmHASH") >>> uri.uri "wrap://ipfs/QmHASH" @@ -40,14 +49,6 @@ class Uri: Traceback (most recent call last): ... TypeError: expected string or bytes-like object - - Attributes: - scheme (str): The scheme of the URI. Defaults to "wrap". This helps \ - differentiate Polywrap URIs from other URI schemes. - authority (str): The authority of the URI. This is used to determine \ - which URI resolver to use. - path (str): The path of the URI. This is used to determine the \ - location of the wrapper. """ URI_REGEX = re.compile( @@ -55,6 +56,9 @@ class Uri: ) # https://www.rfc-editor.org/rfc/rfc3986#appendix-B scheme = "wrap" + """The scheme of the URI. Defaults to "wrap". This helps \ + differentiate Polywrap URIs from other URI schemes.""" + _authority: str _path: str diff --git a/packages/polywrap-core/polywrap_core/types/uri_package.py b/packages/polywrap-core/polywrap_core/types/uri_package.py index 63b61948..b86bb9fe 100644 --- a/packages/polywrap-core/polywrap_core/types/uri_package.py +++ b/packages/polywrap-core/polywrap_core/types/uri_package.py @@ -11,13 +11,16 @@ class UriPackage: """UriPackage is a dataclass that contains a URI and a package. - Attributes: - uri (Uri): The URI. - package (Package): The package. + Args: + uri (Uri): The URI of the wrap package. + package (WrapPackage): The wrap package. """ uri: Uri + """The URI of the wrap package.""" + package: WrapPackage + """The wrap package.""" __all__ = ["UriPackage"] diff --git a/packages/polywrap-core/polywrap_core/types/uri_resolution_context.py b/packages/polywrap-core/polywrap_core/types/uri_resolution_context.py index 4b852595..bffb103e 100644 --- a/packages/polywrap-core/polywrap_core/types/uri_resolution_context.py +++ b/packages/polywrap-core/polywrap_core/types/uri_resolution_context.py @@ -8,7 +8,7 @@ class UriResolutionContext: """Represents the context of a uri resolution. - Attributes: + Args: resolving_uri_set (Set[Uri]): A set of uris that\ are currently being resolved. resolution_path (List[Uri]): A list of uris in the order that\ @@ -18,8 +18,13 @@ class UriResolutionContext: """ resolving_uri_set: Set[Uri] + """A set of uris that are currently being resolved.""" + resolution_path: List[Uri] + """A list of uris in the order that they are being resolved.""" + history: List[UriResolutionStep] + """A list of steps that have been taken to resolve the uri.""" __slots__ = ("resolving_uri_set", "resolution_path", "history") @@ -29,16 +34,7 @@ def __init__( resolution_path: Optional[List[Uri]] = None, history: Optional[List[UriResolutionStep]] = None, ): - """Initialize a new instance of UriResolutionContext. - - Args: - resolving_uri_set (Optional[Set[Uri]]): A set of uris that\ - are currently being resolved. - resolution_path (Optional[List[Uri]]): A list of uris in the order that\ - they are being resolved. - history (Optional[List[UriResolutionStep]]): A list of steps \ - that have been taken to resolve the uri. - """ + """Initialize a new instance of UriResolutionContext.""" self.resolving_uri_set = resolving_uri_set or set() self.resolution_path = resolution_path or [] self.history = history or [] diff --git a/packages/polywrap-core/polywrap_core/types/uri_resolution_step.py b/packages/polywrap-core/polywrap_core/types/uri_resolution_step.py index 4ababc33..b2ef95aa 100644 --- a/packages/polywrap-core/polywrap_core/types/uri_resolution_step.py +++ b/packages/polywrap-core/polywrap_core/types/uri_resolution_step.py @@ -11,7 +11,7 @@ class UriResolutionStep: """Represents a single step in the resolution of a uri. - Attributes: + Args: source_uri (Uri): The uri that was resolved. result (Any): The result of the resolution. description (Optional[str]): A description of the resolution step. diff --git a/packages/polywrap-core/polywrap_core/types/uri_wrapper.py b/packages/polywrap-core/polywrap_core/types/uri_wrapper.py index 8930220e..0cab0fc0 100644 --- a/packages/polywrap-core/polywrap_core/types/uri_wrapper.py +++ b/packages/polywrap-core/polywrap_core/types/uri_wrapper.py @@ -11,8 +11,8 @@ class UriWrapper: """UriWrapper is a dataclass that contains a URI and a wrapper. - Attributes: - uri (Uri): The URI. + Args: + uri (Uri): The URI of the wrapper. wrapper (Wrapper): The wrapper. """ diff --git a/packages/polywrap-core/polywrap_core/utils/build_clean_uri_history.py b/packages/polywrap-core/polywrap_core/utils/build_clean_uri_history.py index a22dd0f1..75f3d729 100644 --- a/packages/polywrap-core/polywrap_core/utils/build_clean_uri_history.py +++ b/packages/polywrap-core/polywrap_core/utils/build_clean_uri_history.py @@ -12,8 +12,8 @@ def build_clean_uri_history( """Build a clean history of the URI resolution steps. Args: - history: A list of URI resolution steps. - depth: The depth of the history to build. + history (List[UriResolutionStep]): A list of URI resolution steps. + depth (Optional[int]): The depth of the history to build. Returns: CleanResolutionStep: A clean history of the URI resolution steps. diff --git a/packages/polywrap-core/polywrap_core/utils/get_env_from_resolution_path.py b/packages/polywrap-core/polywrap_core/utils/get_env_from_resolution_path.py index 33bc4ac2..5e12030f 100644 --- a/packages/polywrap-core/polywrap_core/utils/get_env_from_resolution_path.py +++ b/packages/polywrap-core/polywrap_core/utils/get_env_from_resolution_path.py @@ -10,8 +10,8 @@ def get_env_from_resolution_path( """Get environment variable from URI resolution history. Args: - uri_history: List of URIs from the URI resolution history - client: Polywrap client instance to use for getting the env by URI + uri_history (List[Uri]): List of URIs from the URI resolution history + client (Client): Polywrap client instance to use for getting the env by URI Returns: env if found, None otherwise diff --git a/packages/polywrap-manifest/polywrap_manifest/manifest.py b/packages/polywrap-manifest/polywrap_manifest/manifest.py index d0be947c..5e21da18 100644 --- a/packages/polywrap-manifest/polywrap_manifest/manifest.py +++ b/packages/polywrap-manifest/polywrap_manifest/manifest.py @@ -15,7 +15,7 @@ class DeserializeManifestOptions: """Options for deserializing a manifest from msgpack encoded bytes. - Attributes: + Args: no_validate: If true, do not validate the manifest. """ diff --git a/packages/polywrap-plugin/polywrap_plugin/module.py b/packages/polywrap-plugin/polywrap_plugin/module.py index fea82e2e..414ad402 100644 --- a/packages/polywrap-plugin/polywrap_plugin/module.py +++ b/packages/polywrap-plugin/polywrap_plugin/module.py @@ -17,10 +17,10 @@ @dataclass(kw_only=True, slots=True) -class InvokeOptions: - """InvokeOptions is a dataclass that holds the options for an invocation. +class PluginInvokeOptions: + """PluginInvokeOptions is a dataclass that holds the options for an invocation. - Attributes: + Args: uri: The URI of the wrapper. method: The method to invoke. args: The arguments to pass to the method. @@ -40,7 +40,7 @@ class InvokeOptions: class PluginModule(Generic[TConfig], ABC): """PluginModule is the base class for all plugin modules. - Attributes: + Args: config: The configuration of the plugin. """ @@ -56,7 +56,7 @@ def __init__(self, config: TConfig): def __wrap_invoke__( self, - options: InvokeOptions, + options: PluginInvokeOptions, ) -> Any: """Invoke a method on the plugin. diff --git a/packages/polywrap-plugin/polywrap_plugin/package.py b/packages/polywrap-plugin/polywrap_plugin/package.py index 4592a348..d960db72 100644 --- a/packages/polywrap-plugin/polywrap_plugin/package.py +++ b/packages/polywrap-plugin/polywrap_plugin/package.py @@ -14,7 +14,7 @@ class PluginPackage(WrapPackage, Generic[TConfig]): """PluginPackage implements IWrapPackage interface for the plugin. - Attributes: + Args: module: The plugin module. manifest: The manifest of the plugin. """ diff --git a/packages/polywrap-plugin/polywrap_plugin/wrapper.py b/packages/polywrap-plugin/polywrap_plugin/wrapper.py index ac947758..e2710d0f 100644 --- a/packages/polywrap-plugin/polywrap_plugin/wrapper.py +++ b/packages/polywrap-plugin/polywrap_plugin/wrapper.py @@ -12,7 +12,7 @@ ) from polywrap_manifest import AnyWrapManifest -from .module import InvokeOptions, PluginModule +from .module import PluginInvokeOptions, PluginModule from .resolution_context_override_client import ResolutionContextOverrideClient TConfig = TypeVar("TConfig") @@ -22,7 +22,7 @@ class PluginWrapper(Wrapper, Generic[TConfig]): """PluginWrapper implements the Wrapper interface for plugin wrappers. - Attributes: + Args: module: The plugin module. manifest: The manifest of the plugin. """ @@ -65,7 +65,7 @@ def invoke( Returns: InvocableResult: Result of the invocation. """ - options = InvokeOptions( + options = PluginInvokeOptions( uri=uri, method=method, args=args, diff --git a/packages/polywrap-plugin/tests/test_plugin_module.py b/packages/polywrap-plugin/tests/test_plugin_module.py index a308a276..c61d619c 100644 --- a/packages/polywrap-plugin/tests/test_plugin_module.py +++ b/packages/polywrap-plugin/tests/test_plugin_module.py @@ -1,13 +1,13 @@ from polywrap_core import InvokerClient, Uri from polywrap_plugin import PluginModule -from polywrap_plugin.module import InvokeOptions +from polywrap_plugin.module import PluginInvokeOptions def test_plugin_module( greeting_module: PluginModule[None], client: InvokerClient ): result = greeting_module.__wrap_invoke__( - InvokeOptions( + PluginInvokeOptions( uri=Uri.from_str("plugin/greeting"), method="greeting", args={"name": "Joe"}, client=client ), ) diff --git a/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/errors.py b/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/errors.py index ed4e1b0d..e05c93ca 100644 --- a/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/errors.py +++ b/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/errors.py @@ -10,18 +10,18 @@ class UriResolutionError(Exception): class InfiniteLoopError(UriResolutionError): - """Raised when an infinite loop is detected while resolving a URI.""" + """Raised when an infinite loop is detected while resolving a URI. + + Args: + uri (Uri): The URI that caused the infinite loop. + history (List[UriResolutionStep]): The resolution history. + """ uri: Uri history: List[UriResolutionStep] def __init__(self, uri: Uri, history: List[UriResolutionStep]): - """Initialize a new InfiniteLoopError instance. - - Args: - uri (Uri): The URI that caused the infinite loop. - history (List[UriResolutionStep]): The resolution history. - """ + """Initialize a new InfiniteLoopError instance.""" self.uri = uri self.history = history super().__init__( @@ -35,18 +35,18 @@ class UriResolverExtensionError(UriResolutionError): class UriResolverExtensionNotFoundError(UriResolverExtensionError): - """Raised when an extension resolver wrapper could not be found for a URI.""" + """Raised when an extension resolver wrapper could not be found for a URI. + + Args: + uri (Uri): The URI that caused the error. + history (List[UriResolutionStep]): The resolution history. + """ uri: Uri history: List[UriResolutionStep] def __init__(self, uri: Uri, history: List[UriResolutionStep]): - """Initialize a new UriResolverExtensionNotFoundError instance. - - Args: - uri (Uri): The URI that caused the error. - history (List[UriResolutionStep]): The resolution history. - """ + """Initialize a new UriResolverExtensionNotFoundError instance.""" self.uri = uri self.history = history super().__init__( diff --git a/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/resolvers/aggregator/uri_resolver_aggregator.py b/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/resolvers/aggregator/uri_resolver_aggregator.py index 4d6ecc3b..3a9eed33 100644 --- a/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/resolvers/aggregator/uri_resolver_aggregator.py +++ b/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/resolvers/aggregator/uri_resolver_aggregator.py @@ -13,7 +13,7 @@ class UriResolverAggregator(UriResolverAggregatorBase): the uri with each of them. If a resolver returns a value\ other than the resolving uri, the value is returned. - Attributes: + Args: resolvers (List[UriResolver]): The list of resolvers to aggregate. step_description (Optional[str]): The description of the resolution\ step. Defaults to the class name. @@ -27,13 +27,7 @@ class UriResolverAggregator(UriResolverAggregatorBase): def __init__( self, resolvers: List[UriResolver], step_description: Optional[str] = None ): - """Initialize a new UriResolverAggregator instance. - - Args: - resolvers (List[UriResolver]): The list of resolvers to aggregate. - step_description (Optional[str]): The description of the resolution\ - step. Defaults to the class name. - """ + """Initialize a new UriResolverAggregator instance.""" self._step_description = step_description or self.__class__.__name__ self._resolvers = resolvers super().__init__() diff --git a/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/resolvers/cache/resolution_result_cache_resolver.py b/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/resolvers/cache/resolution_result_cache_resolver.py index 247ccde2..42fcb77d 100644 --- a/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/resolvers/cache/resolution_result_cache_resolver.py +++ b/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/resolvers/cache/resolution_result_cache_resolver.py @@ -19,17 +19,22 @@ class ResolutionResultCacheResolver(UriResolver): The URI resolution result can be a URI, IWrapPackage, Wrapper, or Error. Errors are not cached by default and can be cached by setting the cache_errors option to True. - Attributes: + Args: resolver_to_cache (UriResolver): The URI resolver to cache. cache (ResolutionResultCache): The resolution result cache. - options (ResolutionResultCacheResolverOptions): The options to use. + cache_errors (bool): Whether to cache errors. """ __slots__ = ("resolver_to_cache", "cache", "cache_errors") resolver_to_cache: UriResolver + """The URI resolver to cache.""" + cache: ResolutionResultCache + """The resolution result cache.""" + cache_errors: bool + """Whether to cache errors.""" def __init__( self, @@ -37,13 +42,7 @@ def __init__( cache: ResolutionResultCache, cache_errors: bool = False, ): - """Initialize a new ResolutionResultCacheResolver instance. - - Args: - resolver_to_cache (UriResolver): The URI resolver to cache. - cache (ResolutionResultCache): The resolution result cache. - options (ResolutionResultCacheResolverOptions): The options to use. - """ + """Initialize a new ResolutionResultCacheResolver instance.""" self.resolver_to_cache = resolver_to_cache self.cache = cache self.cache_errors = cache_errors diff --git a/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/resolvers/extensions/extendable_uri_resolver.py b/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/resolvers/extensions/extendable_uri_resolver.py index e2c27b9e..205ce3ab 100644 --- a/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/resolvers/extensions/extendable_uri_resolver.py +++ b/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/resolvers/extensions/extendable_uri_resolver.py @@ -16,34 +16,32 @@ class ExtendableUriResolver(UriResolverAggregatorBase): The aggregated extension wrapper resolver is then used to resolve\ the uri to a wrapper. - Attributes: - DEFAULT_EXT_INTERFACE_URIS (List[Uri]): The default list of extension\ + Args: + ext_interface_uris (Optional[List[Uri]]): The list of extension\ + interface uris. Defaults to the default list of extension\ interface uris. - ext_interface_uris (List[Uri]): The list of extension interface uris. - resolver_name (str): The name of the resolver. + resolver_name (Optional[str]): The name of the resolver. Defaults\ + to the class name. """ DEFAULT_EXT_INTERFACE_URIS = [ Uri.from_str("wrap://ens/wraps.eth:uri-resolver-ext@1.1.0"), Uri.from_str("wrap://ens/wraps.eth:uri-resolver-ext@1.0.0"), ] + """The default list of extension interface uris.""" + ext_interface_uris: List[Uri] + """The list of extension interface uris.""" + resolver_name: str + """The name of the resolver.""" def __init__( self, ext_interface_uris: Optional[List[Uri]] = None, resolver_name: Optional[str] = None, ): - """Initialize a new ExtendableUriResolver instance. - - Args: - ext_interface_uris (Optional[List[Uri]]): The list of extension\ - interface uris. Defaults to the default list of extension\ - interface uris. - resolver_name (Optional[str]): The name of the resolver. Defaults\ - to the class name. - """ + """Initialize a new ExtendableUriResolver instance.""" self.ext_interface_uris = ext_interface_uris or self.DEFAULT_EXT_INTERFACE_URIS self.resolver_name = resolver_name or self.__class__.__name__ super().__init__() diff --git a/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/resolvers/extensions/extension_wrapper_uri_resolver.py b/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/resolvers/extensions/extension_wrapper_uri_resolver.py index 5862b99a..2970a53e 100644 --- a/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/resolvers/extensions/extension_wrapper_uri_resolver.py +++ b/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/resolvers/extensions/extension_wrapper_uri_resolver.py @@ -42,20 +42,17 @@ class ExtensionWrapperUriResolver(UriResolver): The extension wrapper is resolved using the extension wrapper uri resolver.\ The extension wrapper is then used to resolve the uri to a wrapper. - Attributes: + Args: extension_wrapper_uri (Uri): The uri of the extension wrapper. """ __slots__ = ("extension_wrapper_uri",) extension_wrapper_uri: Uri + """The uri of the extension wrapper.""" def __init__(self, extension_wrapper_uri: Uri): - """Initialize a new ExtensionWrapperUriResolver instance. - - Args: - extension_wrapper_uri (Uri): The uri of the extension wrapper. - """ + """Initialize a new ExtensionWrapperUriResolver instance.""" self.extension_wrapper_uri = extension_wrapper_uri def get_step_description(self) -> str: diff --git a/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/resolvers/extensions/uri_resolver_extension_file_reader.py b/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/resolvers/extensions/uri_resolver_extension_file_reader.py index c5106917..31f846cb 100644 --- a/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/resolvers/extensions/uri_resolver_extension_file_reader.py +++ b/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/resolvers/extensions/uri_resolver_extension_file_reader.py @@ -11,15 +11,20 @@ class UriResolverExtensionFileReader(FileReader): The extension wrapper is used to read files by invoking the getFile method.\ The getFile method is invoked with the path of the file to read. - Attributes: + Args: extension_uri (Uri): The uri of the extension wrapper. wrapper_uri (Uri): The uri of the wrapper that uses the extension wrapper. invoker (Invoker): The invoker used to invoke the getFile method. """ extension_uri: Uri + """The uri of the extension wrapper.""" + wrapper_uri: Uri + """The uri of the wrapper that uses the extension wrapper.""" + invoker: Invoker + """The invoker used to invoke the getFile method.""" def __init__( self, @@ -27,13 +32,7 @@ def __init__( wrapper_uri: Uri, invoker: Invoker, ): - """Initialize a new UriResolverExtensionFileReader instance. - - Args: - extension_uri (Uri): The uri of the extension wrapper. - wrapper_uri (Uri): The uri of the wrapper that uses the extension wrapper. - invoker (Invoker): The invoker used to invoke the getFile method. - """ + """Initialize a new UriResolverExtensionFileReader instance.""" self.extension_uri = extension_uri self.wrapper_uri = wrapper_uri self.invoker = invoker diff --git a/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/resolvers/legacy/base_resolver.py b/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/resolvers/legacy/base_resolver.py index fd3c8582..16b12fed 100644 --- a/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/resolvers/legacy/base_resolver.py +++ b/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/resolvers/legacy/base_resolver.py @@ -15,18 +15,18 @@ class BaseUriResolver(UriResolver): - """Defines the base URI resolver.""" + """Defines the base URI resolver. + + Args: + file_reader (FileReader): The file reader to use. + redirects (Dict[Uri, Uri]): The redirects to use. + """ _fs_resolver: FsUriResolver _redirect_resolver: RedirectUriResolver def __init__(self, file_reader: FileReader, redirects: Dict[Uri, Uri]): - """Initialize a new BaseUriResolver instance. - - Args: - file_reader (FileReader): The file reader to use. - redirects (Dict[Uri, Uri]): The redirects to use. - """ + """Initialize a new BaseUriResolver instance.""" self._fs_resolver = FsUriResolver(file_reader) self._redirect_resolver = RedirectUriResolver(redirects) diff --git a/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/resolvers/legacy/fs_resolver.py b/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/resolvers/legacy/fs_resolver.py index ade7ff60..fa8c158c 100644 --- a/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/resolvers/legacy/fs_resolver.py +++ b/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/resolvers/legacy/fs_resolver.py @@ -31,16 +31,16 @@ def read_file(self, file_path: str) -> bytes: class FsUriResolver(UriResolver): - """Defines a URI resolver that resolves file system URIs.""" + """Defines a URI resolver that resolves file system URIs. + + Args: + file_reader (FileReader): The file reader used to read files. + """ file_reader: FileReader def __init__(self, file_reader: FileReader): - """Initialize a new FsUriResolver instance. - - Args: - file_reader (FileReader): The file reader used to read files. - """ + """Initialize a new FsUriResolver instance.""" self.file_reader = file_reader def try_resolve_uri( diff --git a/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/resolvers/legacy/package_to_wrapper_resolver.py b/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/resolvers/legacy/package_to_wrapper_resolver.py index 7cc45eea..a3012d72 100644 --- a/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/resolvers/legacy/package_to_wrapper_resolver.py +++ b/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/resolvers/legacy/package_to_wrapper_resolver.py @@ -21,7 +21,7 @@ class PackageToWrapperResolverOptions: """Defines the options for the PackageToWrapperResolver. - Attributes: + Args: deserialize_manifest_options (DeserializeManifestOptions): The options\ to use when deserializing the manifest. """ @@ -37,7 +37,7 @@ class PackageToWrapperResolver(ResolverWithHistory): If result is a wrapper, it returns it back.\ In case of a package, it creates a wrapper and returns it back. - Attributes: + Args: resolver (UriResolver): The URI resolver to cache. options (PackageToWrapperResolverOptions): The options to use. """ @@ -50,12 +50,7 @@ def __init__( resolver: UriResolver, options: Optional[PackageToWrapperResolverOptions] = None, ) -> None: - """Initialize a new PackageToWrapperResolver instance. - - Args: - resolver (UriResolver): The URI resolver to cache. - options (PackageToWrapperResolverOptions): The options to use. - """ + """Initialize a new PackageToWrapperResolver instance.""" self.resolver = resolver self.options = options super().__init__() diff --git a/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/resolvers/legacy/redirect_resolver.py b/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/resolvers/legacy/redirect_resolver.py index 3e34ab67..d40c3223 100644 --- a/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/resolvers/legacy/redirect_resolver.py +++ b/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/resolvers/legacy/redirect_resolver.py @@ -5,16 +5,16 @@ class RedirectUriResolver(UriResolver): - """Defines the redirect URI resolver.""" + """Defines the redirect URI resolver. + + Args: + redirects (Dict[Uri, Uri]): The redirects to use. + """ _redirects: Dict[Uri, Uri] def __init__(self, redirects: Dict[Uri, Uri]): - """Initialize a new RedirectUriResolver instance. - - Args: - redirects (Dict[Uri, Uri]): The redirects to use. - """ + """Initialize a new RedirectUriResolver instance.""" self._redirects = redirects def try_resolve_uri( diff --git a/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/resolvers/legacy/wrapper_cache/in_memory_wrapper_cache.py b/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/resolvers/legacy/wrapper_cache/in_memory_wrapper_cache.py index 16975e64..87b452ae 100644 --- a/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/resolvers/legacy/wrapper_cache/in_memory_wrapper_cache.py +++ b/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/resolvers/legacy/wrapper_cache/in_memory_wrapper_cache.py @@ -7,13 +7,12 @@ class InMemoryWrapperCache(WrapperCache): - """InMemoryWrapperCache is an in-memory implementation of the wrapper cache interface. - - Attributes: - map (Dict[Uri, UriWrapper]): The map of uris to wrappers. + """InMemoryWrapperCache is an in-memory implementation\ + of the wrapper cache interface. """ map: Dict[Uri, UriWrapper] + """The map of uris to wrappers.""" def __init__(self): """Initialize a new InMemoryWrapperCache instance.""" diff --git a/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/resolvers/legacy/wrapper_cache_resolver.py b/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/resolvers/legacy/wrapper_cache_resolver.py index 08ac0748..71fbf557 100644 --- a/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/resolvers/legacy/wrapper_cache_resolver.py +++ b/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/resolvers/legacy/wrapper_cache_resolver.py @@ -20,7 +20,7 @@ class WrapperCacheResolverOptions: """Defines the options for the WrapperCacheResolver. - Attributes: + Args: deserialize_manifest_options (DeserializeManifestOptions): The options\ to use when deserializing the manifest. end_on_redirect (Optional[bool]): Whether to end the resolution\ @@ -38,10 +38,10 @@ class WrapperCacheResolver(UriResolver): If result is an uri or package, it returns it back without caching.\ If result is a wrapper, it caches the wrapper and returns it back. - Attributes: + Args: resolver_to_cache (UriResolver): The URI resolver to cache. cache (WrapperCache): The cache to use. - options (CacheResolverOptions): The options to use. + options (Optional[WrapperCacheResolverOptions]): The options to use. """ __slots__ = ("resolver_to_cache", "cache", "options") @@ -56,13 +56,7 @@ def __init__( cache: WrapperCache, options: Optional[WrapperCacheResolverOptions] = None, ): - """Initialize a new PackageToWrapperCacheResolver instance. - - Args: - resolver_to_cache (UriResolver): The URI resolver to cache. - cache (WrapperCache): The cache to use. - options (CacheResolverOptions): The options to use. - """ + """Initialize a new PackageToWrapperCacheResolver instance.""" self.resolver_to_cache = resolver_to_cache self.cache = cache self.options = options diff --git a/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/resolvers/package/package_resolver.py b/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/resolvers/package/package_resolver.py index 496aa659..cbc40ace 100644 --- a/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/resolvers/package/package_resolver.py +++ b/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/resolvers/package/package_resolver.py @@ -12,7 +12,12 @@ class PackageResolver(ResolverWithHistory): - """Defines a resolver that resolves a uri to a package.""" + """Defines a resolver that resolves a uri to a package. + + Args: + uri (Uri): The uri to resolve. + package (WrapPackage): The wrap package to return. + """ __slots__ = ("uri", "package") @@ -20,12 +25,7 @@ class PackageResolver(ResolverWithHistory): package: WrapPackage def __init__(self, uri: Uri, package: WrapPackage): - """Initialize a new PackageResolver instance. - - Args: - uri (Uri): The uri to resolve. - package (WrapPackage): The wrap package to return. - """ + """Initialize a new PackageResolver instance.""" self.uri = uri self.package = package super().__init__() diff --git a/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/resolvers/recursive/recursive_resolver.py b/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/resolvers/recursive/recursive_resolver.py index 06a69e13..1f4bf465 100644 --- a/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/resolvers/recursive/recursive_resolver.py +++ b/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/resolvers/recursive/recursive_resolver.py @@ -25,11 +25,7 @@ class RecursiveResolver(UriResolver): resolver: UriResolver def __init__(self, resolver: UriResolver): - """Initialize a new RecursiveResolver instance. - - Args: - resolver (UriResolver): The resolver to use. - """ + """Initialize a new RecursiveResolver instance.""" self.resolver = resolver def try_resolve_uri( diff --git a/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/resolvers/redirect/redirect_resolver.py b/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/resolvers/redirect/redirect_resolver.py index 837d53ed..abc52359 100644 --- a/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/resolvers/redirect/redirect_resolver.py +++ b/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/resolvers/redirect/redirect_resolver.py @@ -11,7 +11,7 @@ class RedirectResolver(ResolverWithHistory): uri to redirect from, the uri to redirect to is returned. Otherwise, the uri to resolve\ is returned. - Attributes: + Args: from_uri (Uri): The uri to redirect from. to_uri (Uri): The uri to redirect to. """ @@ -22,12 +22,7 @@ class RedirectResolver(ResolverWithHistory): to_uri: Uri def __init__(self, from_uri: Uri, to_uri: Uri) -> None: - """Initialize a new RedirectResolver instance. - - Args: - from_uri (Uri): The uri to redirect from. - to_uri (Uri): The uri to redirect to. - """ + """Initialize a new RedirectResolver instance.""" self.from_uri = from_uri self.to_uri = to_uri super().__init__() diff --git a/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/resolvers/static/static_resolver.py b/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/resolvers/static/static_resolver.py index cd1db81d..8352d19c 100644 --- a/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/resolvers/static/static_resolver.py +++ b/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/resolvers/static/static_resolver.py @@ -16,7 +16,7 @@ class StaticResolver(UriResolver): """Defines the static URI resolver. - Attributes: + Args: uri_map (StaticResolverLike): The URI map to use. """ @@ -25,11 +25,7 @@ class StaticResolver(UriResolver): uri_map: StaticResolverLike def __init__(self, uri_map: StaticResolverLike): - """Initialize a new StaticResolver instance. - - Args: - uri_map (StaticResolverLike): The URI map to use. - """ + """Initialize a new StaticResolver instance.""" self.uri_map = uri_map def try_resolve_uri( diff --git a/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/resolvers/wrapper/wrapper_resolver.py b/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/resolvers/wrapper/wrapper_resolver.py index 4d39d230..a7e29309 100644 --- a/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/resolvers/wrapper/wrapper_resolver.py +++ b/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/resolvers/wrapper/wrapper_resolver.py @@ -14,7 +14,7 @@ class WrapperResolver(ResolverWithHistory): """Defines the wrapper resolver. - Attributes: + Args: uri (Uri): The uri to resolve. wrapper (Wrapper): The wrapper to use. """ @@ -25,12 +25,6 @@ class WrapperResolver(ResolverWithHistory): wrapper: Wrapper def __init__(self, uri: Uri, wrapper: Wrapper): - """Initialize a new WrapperResolver instance. - - Args: - uri (Uri): The uri to resolve. - wrapper (Wrapper): The wrapper to use. - """ self.uri = uri self.wrapper = wrapper super().__init__() diff --git a/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/types/__init__.py b/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/types/__init__.py index b5019260..af3dc381 100644 --- a/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/types/__init__.py +++ b/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/types/__init__.py @@ -2,4 +2,3 @@ from .cache import * from .static_resolver_like import * from .uri_redirect import * -from .uri_resolver_like import * diff --git a/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/types/cache/resolution_result_cache/in_memory_resolution_result_cache.py b/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/types/cache/resolution_result_cache/in_memory_resolution_result_cache.py index 035833e6..6c36e99e 100644 --- a/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/types/cache/resolution_result_cache/in_memory_resolution_result_cache.py +++ b/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/types/cache/resolution_result_cache/in_memory_resolution_result_cache.py @@ -9,14 +9,10 @@ class InMemoryResolutionResultCache(ResolutionResultCache): """InMemoryResolutionResultCache is an in-memory implementation \ - of the resolution result cache interface. - - Attributes: - map (Dict[Uri, Union[UriPackageOrWrapper, UriResolutionError]]):\ - The map of uris to resolution result. - """ + of the resolution result cache interface.""" map: Dict[Uri, Union[UriPackageOrWrapper, UriResolutionError]] + """The map of uris to resolution result.""" def __init__(self): """Initialize a new InMemoryResolutionResultCache instance.""" diff --git a/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/types/uri_redirect.py b/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/types/uri_redirect.py index 27268492..65c49d91 100644 --- a/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/types/uri_redirect.py +++ b/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/types/uri_redirect.py @@ -8,7 +8,7 @@ class UriRedirect: """UriRedirect is a type that represents a redirect from one uri to another. - Attributes: + Args: from_uri (Uri): The uri to redirect from. to_uri (Uri): The uri to redirect to. """ diff --git a/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/types/uri_resolver_like.py b/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/types/uri_resolver_like.py deleted file mode 100644 index 2a64d1ba..00000000 --- a/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/types/uri_resolver_like.py +++ /dev/null @@ -1,29 +0,0 @@ -"""This module contains the type definition for UriResolverLike. - -UriResolverLike is a type that represents a union of types\ - that can be used as a UriResolver. - ->>> UriResolverLike = Union[ -... StaticResolverLike, -... UriPackageOrWrapper, -... UriRedirect, -... UriResolver, -... List[UriResolverLike], -... ] -""" -from __future__ import annotations - -from typing import List, Union - -from polywrap_core import UriPackageOrWrapper, UriResolver - -from .static_resolver_like import StaticResolverLike -from .uri_redirect import UriRedirect - -UriResolverLike = Union[ - StaticResolverLike, - UriPackageOrWrapper, - UriRedirect, - UriResolver, - List["UriResolverLike"], -] diff --git a/packages/polywrap-wasm/polywrap_wasm/constants.py b/packages/polywrap-wasm/polywrap_wasm/constants.py index 3fcc99cd..67ccd309 100644 --- a/packages/polywrap-wasm/polywrap_wasm/constants.py +++ b/packages/polywrap-wasm/polywrap_wasm/constants.py @@ -1,5 +1,9 @@ """This module contains the constants used by polywrap-wasm package.""" + WRAP_MANIFEST_PATH = "wrap.info" +"""Default path to the wrap manifest file.""" + WRAP_MODULE_PATH = "wrap.wasm" +"""Default path to the wrap module file.""" __all__ = ["WRAP_MANIFEST_PATH", "WRAP_MODULE_PATH"] diff --git a/packages/polywrap-wasm/polywrap_wasm/exports.py b/packages/polywrap-wasm/polywrap_wasm/exports.py index 12f13e6d..2af6878b 100644 --- a/packages/polywrap-wasm/polywrap_wasm/exports.py +++ b/packages/polywrap-wasm/polywrap_wasm/exports.py @@ -7,10 +7,14 @@ class WrapExports: """WrapExports is a class that contains the exports of the Wasm wrapper module. - Attributes: - _instance: The Wasm instance. - _store: The Wasm store. - _wrap_invoke: exported _wrap_invoke Wasm function. + Args: + instance: The Wasm instance. + store: The Wasm store. + _wrap_invoke: The exported _wrap_invoke Wasm function. + + Raises: + WasmExportNotFoundError: If the _wrap_invoke function is not exported\ + from the Wasm module. """ _instance: Instance @@ -18,15 +22,7 @@ class WrapExports: _wrap_invoke: Func def __init__(self, instance: Instance, store: Store): - """Initialize the WrapExports class. - - Args: - instance: The Wasm instance. - store: The Wasm store. - - Raises: - ExportNotFoundError: if the _wrap_invoke export is not found in the Wasm module. - """ + """Initialize the WrapExports class.""" self._instance = instance self._store = store exports = instance.exports(store) @@ -43,9 +39,9 @@ def __wrap_invoke__( """Call the exported _wrap_invoke Wasm function. Args: - method_length: The length of the method. - args_length: The length of the args. - env_length: The length of the env. + method_length (int): The length of the method. + args_length (int): The length of the args. + env_length (int): The length of the env. Returns: True if the invoke call was successful, False otherwise. diff --git a/packages/polywrap-wasm/polywrap_wasm/imports/wrap_imports.py b/packages/polywrap-wasm/polywrap_wasm/imports/wrap_imports.py index 7246dbf6..bc696557 100644 --- a/packages/polywrap-wasm/polywrap_wasm/imports/wrap_imports.py +++ b/packages/polywrap-wasm/polywrap_wasm/imports/wrap_imports.py @@ -29,6 +29,12 @@ class WrapImports( This class is responsible for providing all the Wasm imports to the Wasm module. + Args: + memory: The Wasm memory instance. + store: The Wasm store instance. + state: The state of the Wasm module. + invoker: The invoker instance. + Attributes: memory: The Wasm memory instance. store: The Wasm store instance. @@ -43,14 +49,7 @@ def __init__( state: State, invoker: Optional[Invoker], ) -> None: - """Initialize the WrapImports instance. - - Args: - memory: The Wasm memory instance. - store: The Wasm store instance. - state: The state of the Wasm module. - invoker: The invoker instance. - """ + """Initialize the WrapImports instance.""" self.memory = memory self.store = store self.state = state diff --git a/packages/polywrap-wasm/polywrap_wasm/inmemory_file_reader.py b/packages/polywrap-wasm/polywrap_wasm/inmemory_file_reader.py index da5c90d5..39ca996e 100644 --- a/packages/polywrap-wasm/polywrap_wasm/inmemory_file_reader.py +++ b/packages/polywrap-wasm/polywrap_wasm/inmemory_file_reader.py @@ -10,10 +10,11 @@ class InMemoryFileReader(FileReader): """InMemoryFileReader is an implementation of the IFileReader interface\ that reads files from memory. - Attributes: - _wasm_module: The Wasm module file of the wrapper. - _wasm_manifest: The manifest of the wrapper. - _base_file_reader: The base file reader used to read any files. + Args: + base_file_reader (FileReader): The base file reader\ + used to read any files. + wasm_module (Optional[bytes]): The Wasm module file of the wrapper. + wasm_manifest (Optional[bytes]): The manifest of the wrapper. """ _wasm_manifest: Optional[bytes] diff --git a/packages/polywrap-wasm/polywrap_wasm/linker/wrap_linker.py b/packages/polywrap-wasm/polywrap_wasm/linker/wrap_linker.py index 04da52fd..0b00600f 100644 --- a/packages/polywrap-wasm/polywrap_wasm/linker/wrap_linker.py +++ b/packages/polywrap-wasm/polywrap_wasm/linker/wrap_linker.py @@ -25,18 +25,17 @@ class WrapLinker( This class is responsible for linking all the Wasm imports to the Wasm module. + Args: + linker: The Wasm linker instance. + wrap_imports: The Wasm imports instance. + Attributes: linker: The Wasm linker instance. wrap_imports: The Wasm imports instance. """ def __init__(self, linker: Linker, wrap_imports: WrapImports) -> None: - """Initialize the WrapLinker instance. - - Args: - linker: The Wasm linker instance. - wrap_imports: The Wasm imports instance. - """ + """Initialize the WrapLinker instance.""" self.linker = linker self.wrap_imports = wrap_imports diff --git a/packages/polywrap-wasm/polywrap_wasm/types/state.py b/packages/polywrap-wasm/polywrap_wasm/types/state.py index a09ecad6..e6f63b97 100644 --- a/packages/polywrap-wasm/polywrap_wasm/types/state.py +++ b/packages/polywrap-wasm/polywrap_wasm/types/state.py @@ -8,10 +8,10 @@ @dataclass(kw_only=True, slots=True) -class InvokeOptions: - """InvokeOptions is a dataclass that holds the options for an invocation. +class WasmInvokeOptions: + """WasmInvokeOptions is a dataclass that holds the options for an invocation. - Attributes: + Args: uri: The URI of the wrapper. method: The method to invoke. args: The arguments to pass to the method. @@ -30,7 +30,7 @@ class InvokeOptions: class InvokeResult(Generic[E]): """InvokeResult is a dataclass that holds the result of an invocation. - Attributes: + Args: result: The result of an invocation. error: The error of an invocation. """ @@ -50,7 +50,7 @@ def __post_init__(self): class State: """State is a dataclass that holds the state of a Wasm wrapper. - Attributes: + Args: invoke_options: The options used for the invocation. invoke_result: The result of an invocation. subinvoke_result: The result of a subinvocation. @@ -58,7 +58,7 @@ class State: get_implementations_result: The result of a get implementations call. """ - invoke_options: InvokeOptions + invoke_options: WasmInvokeOptions invoke_result: Optional[InvokeResult[str]] = None subinvoke_result: Optional[InvokeResult[Exception]] = None get_implementations_result: Optional[bytes] = None diff --git a/packages/polywrap-wasm/polywrap_wasm/wasm_package.py b/packages/polywrap-wasm/polywrap_wasm/wasm_package.py index 7ab92c74..b246cf13 100644 --- a/packages/polywrap-wasm/polywrap_wasm/wasm_package.py +++ b/packages/polywrap-wasm/polywrap_wasm/wasm_package.py @@ -16,10 +16,13 @@ class WasmPackage(WrapPackage): """WasmPackage is a type that represents a Wasm WRAP package. - Attributes: - file_reader: The file reader used to read the package files. - manifest: The manifest of the wrapper. - wasm_module: The Wasm module file of the wrapper. + Args: + file_reader (FileReader): The file reader used to read\ + the package files. + manifest (Optional[Union[bytes, AnyWrapManifest]]): \ + The manifest of the wrapper. + wasm_module (Optional[bytes]): The Wasm module file\ + of the wrapper. """ file_reader: FileReader diff --git a/packages/polywrap-wasm/polywrap_wasm/wasm_wrapper.py b/packages/polywrap-wasm/polywrap_wasm/wasm_wrapper.py index a15fab67..d2f64dd8 100644 --- a/packages/polywrap-wasm/polywrap_wasm/wasm_wrapper.py +++ b/packages/polywrap-wasm/polywrap_wasm/wasm_wrapper.py @@ -19,13 +19,13 @@ from .exports import WrapExports from .instance import create_instance -from .types.state import InvokeOptions, State +from .types.state import WasmInvokeOptions, State class WasmWrapper(Wrapper): """WasmWrapper implements the Wrapper interface for Wasm wrappers. - Attributes: + Args: file_reader: The file reader used to read the wrapper files. wasm_module: The Wasm module file of the wrapper. manifest: The manifest of the wrapper. @@ -115,7 +115,7 @@ def invoke( ) state = State( - invoke_options=InvokeOptions( + invoke_options=WasmInvokeOptions( uri=uri, method=method, args=args, From e5c3599b938f19f6f0af57a6de97e52b3966f6f1 Mon Sep 17 00:00:00 2001 From: Niraj Kamdar Date: Tue, 13 Jun 2023 18:02:31 +0530 Subject: [PATCH 36/47] fix: docs --- .../polywrap-client/polywrap_client/client.py | 28 +++++++++++-------- .../polywrap-plugin/polywrap_plugin/module.py | 26 ++++++++--------- .../polywrap_plugin/package.py | 11 ++------ .../resolution_context_override_client.py | 3 +- .../polywrap_plugin/wrapper.py | 11 ++------ 5 files changed, 38 insertions(+), 41 deletions(-) diff --git a/packages/polywrap-client/polywrap_client/client.py b/packages/polywrap-client/polywrap_client/client.py index 6b29321b..b6002700 100644 --- a/packages/polywrap-client/polywrap_client/client.py +++ b/packages/polywrap-client/polywrap_client/client.py @@ -27,18 +27,14 @@ class PolywrapClient(Client): """Defines the Polywrap client. - Attributes: - _config (ClientConfig): The client configuration. + Args: + config (ClientConfig): The polywrap client config. """ _config: ClientConfig def __init__(self, config: ClientConfig): - """Initialize a new PolywrapClient instance. - - Args: - config (ClientConfig): The polywrap client config. - """ + """Initialize a new PolywrapClient instance.""" self._config = config def get_config(self) -> ClientConfig: @@ -86,6 +82,7 @@ def get_implementations( Args: uri (Uri): URI of the interface. apply_resolution (bool): If True, apply resolution to the URI and interfaces. + resolution_context (Optional[UriResolutionContext]): A URI resolution context Returns: Optional[List[Uri]]: List of implementations or None if not found. @@ -114,7 +111,8 @@ def get_file( Args: uri (Uri): The wrapper URI. - (GetFile: The for getting the file. + path (str): The path to the file. + encoding (Optional[str]): The encoding of the file. Returns: Union[bytes, str]: The file contents. @@ -129,7 +127,7 @@ def get_manifest( Args: uri (Uri): The wrapper URI. - (Optional[GetManifest): The for getting the manifest. + options (Optional[DeserializeManifestOptions]): The manifest options. Returns: AnyWrapManifest: The manifest. @@ -143,7 +141,9 @@ def try_resolve_uri( """Try to resolve the given URI. Args: - (TryResolveUriUriPackageOrWrapper]): The for resolving the URI. + uri (Uri): The URI to resolve. + resolution_context (Optional[UriResolutionContext]):\ + The resolution context. Returns: UriPackageOrWrapper: The resolved URI, package or wrapper. @@ -208,7 +208,13 @@ def invoke( """Invoke the given wrapper URI. Args: - (InvokerUriPackageOrWrapper]): The for invoking the wrapper. + uri (Uri): The wrapper URI. + method (str): The method to invoke. + args (Optional[Any]): The arguments to pass to the method. + env (Optional[Any]): The environment variables to pass. + resolution_context (Optional[UriResolutionContext]):\ + The resolution context. + encode_result (Optional[bool]): If True, encode the result. Returns: Any: The result of the invocation. diff --git a/packages/polywrap-plugin/polywrap_plugin/module.py b/packages/polywrap-plugin/polywrap_plugin/module.py index 414ad402..0708058a 100644 --- a/packages/polywrap-plugin/polywrap_plugin/module.py +++ b/packages/polywrap-plugin/polywrap_plugin/module.py @@ -21,12 +21,15 @@ class PluginInvokeOptions: """PluginInvokeOptions is a dataclass that holds the options for an invocation. Args: - uri: The URI of the wrapper. - method: The method to invoke. - args: The arguments to pass to the method. - env: The environment variables to set for the invocation. - resolution_context: A URI resolution context. - client: The client to use for subinvocations. + uri (URI): The URI of the wrapper. + method (str): The method to invoke. + args (Optional[Any]): The arguments to pass to the method. + env (Optional[Any]): The environment variables to set\ + for the invocation. + resolution_context (Optional[UriResolutionContext]): \ + A URI resolution context. + client (Optional[InvokerClient]): The client to use\ + for subinvocations. """ uri: Uri @@ -41,17 +44,13 @@ class PluginModule(Generic[TConfig], ABC): """PluginModule is the base class for all plugin modules. Args: - config: The configuration of the plugin. + config (TConfig): The configuration of the plugin. """ config: TConfig def __init__(self, config: TConfig): - """Initialize a new PluginModule instance. - - Args: - config: The configuration of the plugin. - """ + """Initialize a new PluginModule instance.""" self.config = config def __wrap_invoke__( @@ -61,7 +60,8 @@ def __wrap_invoke__( """Invoke a method on the plugin. Args: - options: The options to use when invoking the plugin. + options (PluginInvokeOptions): The options\ + to use when invoking the plugin. Returns: The result of the plugin method invocation. diff --git a/packages/polywrap-plugin/polywrap_plugin/package.py b/packages/polywrap-plugin/polywrap_plugin/package.py index d960db72..ef18d9c5 100644 --- a/packages/polywrap-plugin/polywrap_plugin/package.py +++ b/packages/polywrap-plugin/polywrap_plugin/package.py @@ -15,20 +15,15 @@ class PluginPackage(WrapPackage, Generic[TConfig]): """PluginPackage implements IWrapPackage interface for the plugin. Args: - module: The plugin module. - manifest: The manifest of the plugin. + module (PluginModule[TConfig]): The plugin module. + manifest (AnyWrapManifest): The manifest of the plugin. """ module: PluginModule[TConfig] manifest: AnyWrapManifest def __init__(self, module: PluginModule[TConfig], manifest: AnyWrapManifest): - """Initialize a new PluginPackage instance. - - Args: - module: The plugin module. - manifest: The manifest of the plugin. - """ + """Initialize a new PluginPackage instance.""" self.module = module self.manifest = manifest diff --git a/packages/polywrap-plugin/polywrap_plugin/resolution_context_override_client.py b/packages/polywrap-plugin/polywrap_plugin/resolution_context_override_client.py index 3700f72f..356d7310 100644 --- a/packages/polywrap-plugin/polywrap_plugin/resolution_context_override_client.py +++ b/packages/polywrap-plugin/polywrap_plugin/resolution_context_override_client.py @@ -9,7 +9,8 @@ class ResolutionContextOverrideClient(InvokerClient): Args: client (InvokerClient): The wrapped client. - resolution_context (Optional[UriResolutionContext]): The resolution context to use. + resolution_context (Optional[UriResolutionContext]): \ + The resolution context to use. """ client: InvokerClient diff --git a/packages/polywrap-plugin/polywrap_plugin/wrapper.py b/packages/polywrap-plugin/polywrap_plugin/wrapper.py index e2710d0f..eac2115b 100644 --- a/packages/polywrap-plugin/polywrap_plugin/wrapper.py +++ b/packages/polywrap-plugin/polywrap_plugin/wrapper.py @@ -23,8 +23,8 @@ class PluginWrapper(Wrapper, Generic[TConfig]): """PluginWrapper implements the Wrapper interface for plugin wrappers. Args: - module: The plugin module. - manifest: The manifest of the plugin. + module (PluginModule[TConfig]): The plugin module. + manifest (AnyWrapManifest): The manifest of the plugin. """ module: PluginModule[TConfig] @@ -33,12 +33,7 @@ class PluginWrapper(Wrapper, Generic[TConfig]): def __init__( self, module: PluginModule[TConfig], manifest: AnyWrapManifest ) -> None: - """Initialize a new PluginWrapper instance. - - Args: - module: The plugin module. - manifest: The manifest of the plugin. - """ + """Initialize a new PluginWrapper instance.""" self.module = module self.manifest = manifest From a90b90d7b5b5d027489125b8a52aedbfc6b6bf29 Mon Sep 17 00:00:00 2001 From: Niraj Kamdar Date: Tue, 13 Jun 2023 23:10:12 +0530 Subject: [PATCH 37/47] docs: improve documentation --- docs/source/index.rst | 2 +- .../polywrap_uri_resolvers.types.rst | 1 - ...ywrap_uri_resolvers.types.uri_redirect.rst | 7 - .../polywrap_wasm.types.invoke_result.rst | 7 + .../polywrap-wasm/polywrap_wasm.types.rst | 2 + ...olywrap_wasm.types.wasm_invoke_options.rst | 7 + .../polywrap-client/polywrap_client/client.py | 6 +- .../polywrap_core/types/client.py | 2 +- .../polywrap_core/types/config.py | 2 +- .../polywrap_core/types/file_reader.py | 2 +- .../polywrap_core/types/invocable.py | 2 +- .../polywrap_core/types/invoke_options.py | 5 +- .../polywrap_core/types/invoker.py | 2 +- .../polywrap_core/types/invoker_client.py | 2 +- .../polywrap_core/types/uri_resolver.py | 2 +- .../types/uri_resolver_handler.py | 2 +- .../polywrap_core/types/wrap_package.py | 2 +- .../polywrap_core/types/wrapper.py | 2 +- .../utils/build_clean_uri_history.py | 3 + .../utils/get_env_from_resolution_path.py | 3 + .../utils/get_implementations.py | 3 + .../polywrap-uri-resolvers/assets/style.css | 186 ------------------ .../polywrap_uri_resolvers/errors.py | 8 + .../resolvers/abc/resolver_with_history.py | 3 + .../resolvers/aggregator/__init__.py | 1 + .../aggregator/uri_resolver_aggregator.py | 3 + .../uri_resolver_aggregator_base.py | 3 + .../cache/resolution_result_cache_resolver.py | 3 + .../extensions/extendable_uri_resolver.py | 3 + .../extension_wrapper_uri_resolver.py | 3 + .../uri_resolver_extension_file_reader.py | 3 + .../resolvers/legacy/base_resolver.py | 3 + .../resolvers/legacy/fs_resolver.py | 3 + .../legacy/package_to_wrapper_resolver.py | 3 + .../resolvers/legacy/redirect_resolver.py | 3 + .../wrapper_cache/in_memory_wrapper_cache.py | 3 + .../legacy/wrapper_cache/wrapper_cache.py | 3 + .../legacy/wrapper_cache_resolver.py | 3 + .../resolvers/package/package_resolver.py | 3 + .../resolvers/recursive/recursive_resolver.py | 3 + .../resolvers/redirect/redirect_resolver.py | 3 + .../resolvers/static/static_resolver.py | 3 + .../resolvers/wrapper/wrapper_resolver.py | 3 + .../polywrap_uri_resolvers/types/__init__.py | 1 - .../in_memory_resolution_result_cache.py | 5 +- .../resolution_result_cache.py | 5 +- .../types/uri_redirect.py | 17 -- .../polywrap-wasm/polywrap_wasm/buffer.py | 42 ++-- .../polywrap-wasm/polywrap_wasm/exports.py | 6 +- .../polywrap_wasm/imports/abort.py | 12 +- .../polywrap_wasm/imports/debug.py | 4 +- .../polywrap_wasm/imports/env.py | 2 +- .../imports/get_implementations.py | 4 +- .../polywrap_wasm/imports/invoke.py | 12 +- .../polywrap_wasm/imports/subinvoke.py | 16 +- .../polywrap_wasm/imports/wrap_imports.py | 16 +- .../polywrap_wasm/inmemory_file_reader.py | 2 +- .../polywrap-wasm/polywrap_wasm/instance.py | 8 +- .../polywrap-wasm/polywrap_wasm/memory.py | 4 +- .../polywrap_wasm/types/__init__.py | 2 + .../polywrap_wasm/types/invoke_result.py | 25 +++ .../polywrap_wasm/types/state.py | 59 ++---- .../types/wasm_invoke_options.py | 25 +++ .../polywrap_wasm/wasm_package.py | 5 +- .../polywrap_wasm/wasm_wrapper.py | 20 +- 65 files changed, 261 insertions(+), 349 deletions(-) delete mode 100644 docs/source/polywrap-uri-resolvers/polywrap_uri_resolvers.types.uri_redirect.rst create mode 100644 docs/source/polywrap-wasm/polywrap_wasm.types.invoke_result.rst create mode 100644 docs/source/polywrap-wasm/polywrap_wasm.types.wasm_invoke_options.rst delete mode 100644 packages/polywrap-uri-resolvers/assets/style.css delete mode 100644 packages/polywrap-uri-resolvers/polywrap_uri_resolvers/types/uri_redirect.py create mode 100644 packages/polywrap-wasm/polywrap_wasm/types/invoke_result.py create mode 100644 packages/polywrap-wasm/polywrap_wasm/types/wasm_invoke_options.py diff --git a/docs/source/index.rst b/docs/source/index.rst index 6e9966c8..e8923b1f 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -7,7 +7,7 @@ Welcome to polywrap-client's documentation! =========================================== .. toctree:: - :maxdepth: 2 + :maxdepth: 1 :caption: Contents: polywrap-msgpack/modules.rst diff --git a/docs/source/polywrap-uri-resolvers/polywrap_uri_resolvers.types.rst b/docs/source/polywrap-uri-resolvers/polywrap_uri_resolvers.types.rst index f40bfc8f..35b270a8 100644 --- a/docs/source/polywrap-uri-resolvers/polywrap_uri_resolvers.types.rst +++ b/docs/source/polywrap-uri-resolvers/polywrap_uri_resolvers.types.rst @@ -16,7 +16,6 @@ Submodules :maxdepth: 4 polywrap_uri_resolvers.types.static_resolver_like - polywrap_uri_resolvers.types.uri_redirect Module contents --------------- diff --git a/docs/source/polywrap-uri-resolvers/polywrap_uri_resolvers.types.uri_redirect.rst b/docs/source/polywrap-uri-resolvers/polywrap_uri_resolvers.types.uri_redirect.rst deleted file mode 100644 index ad6f2d20..00000000 --- a/docs/source/polywrap-uri-resolvers/polywrap_uri_resolvers.types.uri_redirect.rst +++ /dev/null @@ -1,7 +0,0 @@ -polywrap\_uri\_resolvers.types.uri\_redirect module -=================================================== - -.. automodule:: polywrap_uri_resolvers.types.uri_redirect - :members: - :undoc-members: - :show-inheritance: diff --git a/docs/source/polywrap-wasm/polywrap_wasm.types.invoke_result.rst b/docs/source/polywrap-wasm/polywrap_wasm.types.invoke_result.rst new file mode 100644 index 00000000..07b07c8b --- /dev/null +++ b/docs/source/polywrap-wasm/polywrap_wasm.types.invoke_result.rst @@ -0,0 +1,7 @@ +polywrap\_wasm.types.invoke\_result module +========================================== + +.. automodule:: polywrap_wasm.types.invoke_result + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/source/polywrap-wasm/polywrap_wasm.types.rst b/docs/source/polywrap-wasm/polywrap_wasm.types.rst index 0e2faa7a..842a37de 100644 --- a/docs/source/polywrap-wasm/polywrap_wasm.types.rst +++ b/docs/source/polywrap-wasm/polywrap_wasm.types.rst @@ -7,7 +7,9 @@ Submodules .. toctree:: :maxdepth: 4 + polywrap_wasm.types.invoke_result polywrap_wasm.types.state + polywrap_wasm.types.wasm_invoke_options Module contents --------------- diff --git a/docs/source/polywrap-wasm/polywrap_wasm.types.wasm_invoke_options.rst b/docs/source/polywrap-wasm/polywrap_wasm.types.wasm_invoke_options.rst new file mode 100644 index 00000000..d7504249 --- /dev/null +++ b/docs/source/polywrap-wasm/polywrap_wasm.types.wasm_invoke_options.rst @@ -0,0 +1,7 @@ +polywrap\_wasm.types.wasm\_invoke\_options module +================================================= + +.. automodule:: polywrap_wasm.types.wasm_invoke_options + :members: + :undoc-members: + :show-inheritance: diff --git a/packages/polywrap-client/polywrap_client/client.py b/packages/polywrap-client/polywrap_client/client.py index b6002700..f70658ca 100644 --- a/packages/polywrap-client/polywrap_client/client.py +++ b/packages/polywrap-client/polywrap_client/client.py @@ -18,10 +18,12 @@ build_clean_uri_history, get_env_from_resolution_path, ) -from polywrap_core import get_implementations as core_get_implementations +from polywrap_core import ( + get_implementations as core_get_implementations, + UriResolutionContext, +) from polywrap_manifest import AnyWrapManifest, DeserializeManifestOptions from polywrap_msgpack import msgpack_decode, msgpack_encode -from polywrap_uri_resolvers import UriResolutionContext class PolywrapClient(Client): diff --git a/packages/polywrap-core/polywrap_core/types/client.py b/packages/polywrap-core/polywrap_core/types/client.py index 5df1f119..02dc27dd 100644 --- a/packages/polywrap-core/polywrap_core/types/client.py +++ b/packages/polywrap-core/polywrap_core/types/client.py @@ -11,7 +11,7 @@ class Client(InvokerClient, Protocol): - """Client interface defines core set of functionalities\ + """Client protocol defines core set of functionalities\ for interacting with a wrapper.""" def get_interfaces(self) -> Dict[Uri, List[Uri]]: diff --git a/packages/polywrap-core/polywrap_core/types/config.py b/packages/polywrap-core/polywrap_core/types/config.py index 0e269477..9673fcaf 100644 --- a/packages/polywrap-core/polywrap_core/types/config.py +++ b/packages/polywrap-core/polywrap_core/types/config.py @@ -10,7 +10,7 @@ @dataclass(slots=True, kw_only=True) class ClientConfig: - """Client configuration. + """Defines Client configuration dataclass. Args: envs (Dict[Uri, Any]): Dictionary of environments \ diff --git a/packages/polywrap-core/polywrap_core/types/file_reader.py b/packages/polywrap-core/polywrap_core/types/file_reader.py index 848c69fd..268a7eb1 100644 --- a/packages/polywrap-core/polywrap_core/types/file_reader.py +++ b/packages/polywrap-core/polywrap_core/types/file_reader.py @@ -5,7 +5,7 @@ class FileReader(Protocol): - """File reader interface.""" + """FileReader protocol used by UriResolver.""" def read_file(self, file_path: str) -> bytes: """Read a file from the given file path. diff --git a/packages/polywrap-core/polywrap_core/types/invocable.py b/packages/polywrap-core/polywrap_core/types/invocable.py index 847cfdae..efb15102 100644 --- a/packages/polywrap-core/polywrap_core/types/invocable.py +++ b/packages/polywrap-core/polywrap_core/types/invocable.py @@ -26,7 +26,7 @@ class InvocableResult: class Invocable(Protocol): - """Invocable interface.""" + """Defines Invocable protocol.""" def invoke( self, diff --git a/packages/polywrap-core/polywrap_core/types/invoke_options.py b/packages/polywrap-core/polywrap_core/types/invoke_options.py index 8cab91d6..0db5df23 100644 --- a/packages/polywrap-core/polywrap_core/types/invoke_options.py +++ b/packages/polywrap-core/polywrap_core/types/invoke_options.py @@ -6,7 +6,7 @@ class InvokeOptions(Protocol): - """InvokeOptions holds the options for an invocation.""" + """InvokeOptions protocol exposes the core options for an invocation.""" @property def uri(self) -> Uri: @@ -32,3 +32,6 @@ def env(self) -> Any: def resolution_context(self) -> Optional[UriResolutionContext]: """A URI resolution context.""" ... + + +__all__ = ["InvokeOptions"] diff --git a/packages/polywrap-core/polywrap_core/types/invoker.py b/packages/polywrap-core/polywrap_core/types/invoker.py index 16083a5c..37db229b 100644 --- a/packages/polywrap-core/polywrap_core/types/invoker.py +++ b/packages/polywrap-core/polywrap_core/types/invoker.py @@ -10,7 +10,7 @@ class Invoker(Protocol): - """Invoker interface defines the methods for invoking a wrapper.""" + """Invoker protocol defines the methods for invoking a wrapper.""" def invoke( self, diff --git a/packages/polywrap-core/polywrap_core/types/invoker_client.py b/packages/polywrap-core/polywrap_core/types/invoker_client.py index 66d3eaff..ff41a43a 100644 --- a/packages/polywrap-core/polywrap_core/types/invoker_client.py +++ b/packages/polywrap-core/polywrap_core/types/invoker_client.py @@ -8,7 +8,7 @@ class InvokerClient(Invoker, UriResolverHandler, Protocol): - """InvokerClient interface defines core set of functionalities\ + """InvokerClient protocol defines core set of functionalities\ for resolving and invoking a wrapper.""" diff --git a/packages/polywrap-core/polywrap_core/types/uri_resolver.py b/packages/polywrap-core/polywrap_core/types/uri_resolver.py index 0de1f60a..1df16efb 100644 --- a/packages/polywrap-core/polywrap_core/types/uri_resolver.py +++ b/packages/polywrap-core/polywrap_core/types/uri_resolver.py @@ -10,7 +10,7 @@ class UriResolver(Protocol): - """Defines interface for wrapper uri resolver.""" + """Defines protocol for wrapper uri resolver.""" def try_resolve_uri( self, diff --git a/packages/polywrap-core/polywrap_core/types/uri_resolver_handler.py b/packages/polywrap-core/polywrap_core/types/uri_resolver_handler.py index ca1140b5..8dd67a87 100644 --- a/packages/polywrap-core/polywrap_core/types/uri_resolver_handler.py +++ b/packages/polywrap-core/polywrap_core/types/uri_resolver_handler.py @@ -8,7 +8,7 @@ class UriResolverHandler(Protocol): - """Uri resolver handler interface.""" + """Uri resolver handler protocol.""" def try_resolve_uri( self, uri: Uri, resolution_context: Optional[UriResolutionContext] = None diff --git a/packages/polywrap-core/polywrap_core/types/wrap_package.py b/packages/polywrap-core/polywrap_core/types/wrap_package.py index e9f4b30e..c7171c10 100644 --- a/packages/polywrap-core/polywrap_core/types/wrap_package.py +++ b/packages/polywrap-core/polywrap_core/types/wrap_package.py @@ -9,7 +9,7 @@ class WrapPackage(Protocol): - """Wrapper package interface.""" + """Defines protocol for representing the wrap package.""" def create_wrapper(self) -> Wrapper: """Create a new wrapper instance from the wrapper package. diff --git a/packages/polywrap-core/polywrap_core/types/wrapper.py b/packages/polywrap-core/polywrap_core/types/wrapper.py index 303893e6..1b45f766 100644 --- a/packages/polywrap-core/polywrap_core/types/wrapper.py +++ b/packages/polywrap-core/polywrap_core/types/wrapper.py @@ -9,7 +9,7 @@ class Wrapper(Invocable, Protocol): - """Defines the interface for a wrapper.""" + """Defines the protocol for a wrapper.""" def get_file( self, path: str, encoding: Optional[str] = "utf-8" diff --git a/packages/polywrap-core/polywrap_core/utils/build_clean_uri_history.py b/packages/polywrap-core/polywrap_core/utils/build_clean_uri_history.py index 75f3d729..70e13f62 100644 --- a/packages/polywrap-core/polywrap_core/utils/build_clean_uri_history.py +++ b/packages/polywrap-core/polywrap_core/utils/build_clean_uri_history.py @@ -71,3 +71,6 @@ def _build_clean_history_step(step: UriResolutionStep) -> str: if step.description else f"{step.source_uri} => uri ({uri})" ) + + +__all__ = ["build_clean_uri_history"] diff --git a/packages/polywrap-core/polywrap_core/utils/get_env_from_resolution_path.py b/packages/polywrap-core/polywrap_core/utils/get_env_from_resolution_path.py index 5e12030f..fe97c80d 100644 --- a/packages/polywrap-core/polywrap_core/utils/get_env_from_resolution_path.py +++ b/packages/polywrap-core/polywrap_core/utils/get_env_from_resolution_path.py @@ -20,3 +20,6 @@ def get_env_from_resolution_path( if env := client.get_env_by_uri(uri): return env return None + + +__all__ = ["get_env_from_resolution_path"] diff --git a/packages/polywrap-core/polywrap_core/utils/get_implementations.py b/packages/polywrap-core/polywrap_core/utils/get_implementations.py index 53c39231..4f35d9e6 100644 --- a/packages/polywrap-core/polywrap_core/utils/get_implementations.py +++ b/packages/polywrap-core/polywrap_core/utils/get_implementations.py @@ -47,3 +47,6 @@ def get_implementations( final_implementations = final_implementations.union(impls) return list(final_implementations) if final_implementations else None + + +__all__ = ["get_implementations"] diff --git a/packages/polywrap-uri-resolvers/assets/style.css b/packages/polywrap-uri-resolvers/assets/style.css deleted file mode 100644 index 3edac88e..00000000 --- a/packages/polywrap-uri-resolvers/assets/style.css +++ /dev/null @@ -1,186 +0,0 @@ -body { - font-family: Helvetica, Arial, sans-serif; - font-size: 12px; - /* do not increase min-width as some may use split screens */ - min-width: 800px; - color: #999; -} - -h1 { - font-size: 24px; - color: black; -} - -h2 { - font-size: 16px; - color: black; -} - -p { - color: black; -} - -a { - color: #999; -} - -table { - border-collapse: collapse; -} - -/****************************** - * SUMMARY INFORMATION - ******************************/ -#environment td { - padding: 5px; - border: 1px solid #E6E6E6; -} -#environment tr:nth-child(odd) { - background-color: #f6f6f6; -} - -/****************************** - * TEST RESULT COLORS - ******************************/ -span.passed, -.passed .col-result { - color: green; -} - -span.skipped, -span.xfailed, -span.rerun, -.skipped .col-result, -.xfailed .col-result, -.rerun .col-result { - color: orange; -} - -span.error, -span.failed, -span.xpassed, -.error .col-result, -.failed .col-result, -.xpassed .col-result { - color: red; -} - -/****************************** - * RESULTS TABLE - * - * 1. Table Layout - * 2. Extra - * 3. Sorting items - * - ******************************/ -/*------------------ - * 1. Table Layout - *------------------*/ -#results-table { - border: 1px solid #e6e6e6; - color: #999; - font-size: 12px; - width: 100%; -} -#results-table th, -#results-table td { - padding: 5px; - border: 1px solid #E6E6E6; - text-align: left; -} -#results-table th { - font-weight: bold; -} - -/*------------------ - * 2. Extra - *------------------*/ -.log { - background-color: #e6e6e6; - border: 1px solid #e6e6e6; - color: black; - display: block; - font-family: "Courier New", Courier, monospace; - height: 230px; - overflow-y: scroll; - padding: 5px; - white-space: pre-wrap; -} -.log:only-child { - height: inherit; -} - -div.image { - border: 1px solid #e6e6e6; - float: right; - height: 240px; - margin-left: 5px; - overflow: hidden; - width: 320px; -} -div.image img { - width: 320px; -} - -div.video { - border: 1px solid #e6e6e6; - float: right; - height: 240px; - margin-left: 5px; - overflow: hidden; - width: 320px; -} -div.video video { - overflow: hidden; - width: 320px; - height: 240px; -} - -.collapsed { - display: none; -} - -.expander::after { - content: " (show details)"; - color: #BBB; - font-style: italic; - cursor: pointer; -} - -.collapser::after { - content: " (hide details)"; - color: #BBB; - font-style: italic; - cursor: pointer; -} - -/*------------------ - * 3. Sorting items - *------------------*/ -.sortable { - cursor: pointer; -} - -.sort-icon { - font-size: 0px; - float: left; - margin-right: 5px; - margin-top: 5px; - /*triangle*/ - width: 0; - height: 0; - border-left: 8px solid transparent; - border-right: 8px solid transparent; -} -.inactive .sort-icon { - /*finish triangle*/ - border-top: 8px solid #E6E6E6; -} -.asc.active .sort-icon { - /*finish triangle*/ - border-bottom: 8px solid #999; -} -.desc.active .sort-icon { - /*finish triangle*/ - border-top: 8px solid #999; -} diff --git a/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/errors.py b/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/errors.py index e05c93ca..27e23cdf 100644 --- a/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/errors.py +++ b/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/errors.py @@ -53,3 +53,11 @@ def __init__(self, uri: Uri, history: List[UriResolutionStep]): f"Could not find an extension resolver wrapper for the URI: {uri.uri}\n" f"History: {json.dumps(build_clean_uri_history(history), indent=2)}" ) + + +__all__ = [ + "UriResolutionError", + "InfiniteLoopError", + "UriResolverExtensionError", + "UriResolverExtensionNotFoundError", +] \ No newline at end of file diff --git a/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/resolvers/abc/resolver_with_history.py b/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/resolvers/abc/resolver_with_history.py index 5755cf50..5cf67df6 100644 --- a/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/resolvers/abc/resolver_with_history.py +++ b/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/resolvers/abc/resolver_with_history.py @@ -70,3 +70,6 @@ def _try_resolve_uri( resolution_context (IUriResolutionContext[UriPackageOrWrapper]):\ The resolution context to update. """ + + +__all__ = ["ResolverWithHistory"] diff --git a/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/resolvers/aggregator/__init__.py b/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/resolvers/aggregator/__init__.py index dd95cc95..74139217 100644 --- a/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/resolvers/aggregator/__init__.py +++ b/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/resolvers/aggregator/__init__.py @@ -1,2 +1,3 @@ """This package contains the resolvers for aggregator resolvers.""" from .uri_resolver_aggregator import * +from .uri_resolver_aggregator_base import * diff --git a/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/resolvers/aggregator/uri_resolver_aggregator.py b/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/resolvers/aggregator/uri_resolver_aggregator.py index 3a9eed33..d27f57f4 100644 --- a/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/resolvers/aggregator/uri_resolver_aggregator.py +++ b/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/resolvers/aggregator/uri_resolver_aggregator.py @@ -41,3 +41,6 @@ def get_resolvers( ) -> List[UriResolver]: """Get the list of resolvers to aggregate.""" return self._resolvers + + +__all__ = ["UriResolverAggregator"] diff --git a/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/resolvers/aggregator/uri_resolver_aggregator_base.py b/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/resolvers/aggregator/uri_resolver_aggregator_base.py index 98d47488..53ceafb0 100644 --- a/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/resolvers/aggregator/uri_resolver_aggregator_base.py +++ b/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/resolvers/aggregator/uri_resolver_aggregator_base.py @@ -79,3 +79,6 @@ def try_resolve_uri( ) resolution_context.track_step(step) return uri + + +__all__ = ["UriResolverAggregatorBase"] diff --git a/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/resolvers/cache/resolution_result_cache_resolver.py b/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/resolvers/cache/resolution_result_cache_resolver.py index 42fcb77d..cb3dd7d5 100644 --- a/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/resolvers/cache/resolution_result_cache_resolver.py +++ b/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/resolvers/cache/resolution_result_cache_resolver.py @@ -111,3 +111,6 @@ def try_resolve_uri( ) ) return result + + +__all__ = ["ResolutionResultCacheResolver"] diff --git a/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/resolvers/extensions/extendable_uri_resolver.py b/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/resolvers/extensions/extendable_uri_resolver.py index 205ce3ab..c89d931c 100644 --- a/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/resolvers/extensions/extendable_uri_resolver.py +++ b/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/resolvers/extensions/extendable_uri_resolver.py @@ -63,3 +63,6 @@ def get_resolvers( ) return [ExtensionWrapperUriResolver(uri) for uri in uri_resolvers_uris] + + +__all__ = ["ExtendableUriResolver"] diff --git a/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/resolvers/extensions/extension_wrapper_uri_resolver.py b/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/resolvers/extensions/extension_wrapper_uri_resolver.py index 2970a53e..3cb22b99 100644 --- a/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/resolvers/extensions/extension_wrapper_uri_resolver.py +++ b/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/resolvers/extensions/extension_wrapper_uri_resolver.py @@ -156,3 +156,6 @@ def _try_resolve_uri_with_extension( return UriPackage(uri=uri, package=package) return uri + + +__all__ = ["ExtensionWrapperUriResolver"] diff --git a/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/resolvers/extensions/uri_resolver_extension_file_reader.py b/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/resolvers/extensions/uri_resolver_extension_file_reader.py index 31f846cb..b045248e 100644 --- a/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/resolvers/extensions/uri_resolver_extension_file_reader.py +++ b/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/resolvers/extensions/uri_resolver_extension_file_reader.py @@ -56,3 +56,6 @@ def read_file(self, file_path: str) -> bytes: f"File not found at path: {path}, using resolver: {self.extension_uri}" ) return result + + +__all__ = ["UriResolverExtensionFileReader"] diff --git a/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/resolvers/legacy/base_resolver.py b/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/resolvers/legacy/base_resolver.py index 16b12fed..ec372fac 100644 --- a/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/resolvers/legacy/base_resolver.py +++ b/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/resolvers/legacy/base_resolver.py @@ -53,3 +53,6 @@ def try_resolve_uri( return self._fs_resolver.try_resolve_uri( redirected_uri, client, resolution_context ) + + +__all__ = ["BaseUriResolver"] diff --git a/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/resolvers/legacy/fs_resolver.py b/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/resolvers/legacy/fs_resolver.py index fa8c158c..b4ff5922 100644 --- a/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/resolvers/legacy/fs_resolver.py +++ b/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/resolvers/legacy/fs_resolver.py @@ -76,3 +76,6 @@ def try_resolve_uri( file_reader=self.file_reader, ), ) + + +__all__ = ["FsUriResolver"] diff --git a/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/resolvers/legacy/package_to_wrapper_resolver.py b/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/resolvers/legacy/package_to_wrapper_resolver.py index a3012d72..23c96768 100644 --- a/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/resolvers/legacy/package_to_wrapper_resolver.py +++ b/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/resolvers/legacy/package_to_wrapper_resolver.py @@ -95,3 +95,6 @@ def get_step_description(self) -> str: str: The description of the resolution step. """ return self.__class__.__name__ + + +__all__ = ["PackageToWrapperResolver", "PackageToWrapperResolverOptions"] diff --git a/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/resolvers/legacy/redirect_resolver.py b/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/resolvers/legacy/redirect_resolver.py index d40c3223..5b46d97c 100644 --- a/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/resolvers/legacy/redirect_resolver.py +++ b/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/resolvers/legacy/redirect_resolver.py @@ -34,3 +34,6 @@ def try_resolve_uri( Uri: The resolved URI. """ return self._redirects[uri] if uri in self._redirects else uri + + +__all__ = ["RedirectUriResolver"] diff --git a/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/resolvers/legacy/wrapper_cache/in_memory_wrapper_cache.py b/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/resolvers/legacy/wrapper_cache/in_memory_wrapper_cache.py index 87b452ae..925cb08c 100644 --- a/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/resolvers/legacy/wrapper_cache/in_memory_wrapper_cache.py +++ b/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/resolvers/legacy/wrapper_cache/in_memory_wrapper_cache.py @@ -25,3 +25,6 @@ def get(self, uri: Uri) -> Union[UriWrapper, None]: def set(self, uri: Uri, wrapper: UriWrapper) -> None: """Set a wrapper in the cache by its uri.""" self.map[uri] = wrapper + + +__all__ = ["InMemoryWrapperCache"] diff --git a/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/resolvers/legacy/wrapper_cache/wrapper_cache.py b/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/resolvers/legacy/wrapper_cache/wrapper_cache.py index 9825b59b..89ab55cf 100644 --- a/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/resolvers/legacy/wrapper_cache/wrapper_cache.py +++ b/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/resolvers/legacy/wrapper_cache/wrapper_cache.py @@ -18,3 +18,6 @@ def get(self, uri: Uri) -> Union[UriWrapper, None]: @abstractmethod def set(self, uri: Uri, wrapper: UriWrapper) -> None: """Set a wrapper in the cache by its uri.""" + + +__all__ = ["WrapperCache"] diff --git a/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/resolvers/legacy/wrapper_cache_resolver.py b/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/resolvers/legacy/wrapper_cache_resolver.py index 71fbf557..e6498274 100644 --- a/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/resolvers/legacy/wrapper_cache_resolver.py +++ b/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/resolvers/legacy/wrapper_cache_resolver.py @@ -123,3 +123,6 @@ def try_resolve_uri( ) ) return result + + +__all__ = ["WrapperCacheResolver", "WrapperCacheResolverOptions"] diff --git a/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/resolvers/package/package_resolver.py b/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/resolvers/package/package_resolver.py index cbc40ace..b44793f1 100644 --- a/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/resolvers/package/package_resolver.py +++ b/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/resolvers/package/package_resolver.py @@ -61,3 +61,6 @@ def _try_resolve_uri( UriPackageOrWrapper: The resolved URI package, wrapper, or URI. """ return uri if uri != self.uri else UriPackage(uri=uri, package=self.package) + + +__all__ = ["PackageResolver"] \ No newline at end of file diff --git a/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/resolvers/recursive/recursive_resolver.py b/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/resolvers/recursive/recursive_resolver.py index 1f4bf465..6b4f05bb 100644 --- a/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/resolvers/recursive/recursive_resolver.py +++ b/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/resolvers/recursive/recursive_resolver.py @@ -63,3 +63,6 @@ def try_resolve_uri( resolution_context.stop_resolving(uri) return uri_package_or_wrapper + + +__all__ = ["RecursiveResolver"] diff --git a/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/resolvers/redirect/redirect_resolver.py b/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/resolvers/redirect/redirect_resolver.py index abc52359..5bf2ae7d 100644 --- a/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/resolvers/redirect/redirect_resolver.py +++ b/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/resolvers/redirect/redirect_resolver.py @@ -56,3 +56,6 @@ def _try_resolve_uri( UriPackageOrWrapper: The resolved URI package, wrapper, or URI. """ return uri if uri != self.from_uri else self.to_uri + + +__all__ = ["RedirectResolver"] diff --git a/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/resolvers/static/static_resolver.py b/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/resolvers/static/static_resolver.py index 8352d19c..4a2e9e09 100644 --- a/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/resolvers/static/static_resolver.py +++ b/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/resolvers/static/static_resolver.py @@ -65,3 +65,6 @@ def try_resolve_uri( ) resolution_context.track_step(step) return uri_package_or_wrapper + + +__all__ = ["StaticResolver"] diff --git a/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/resolvers/wrapper/wrapper_resolver.py b/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/resolvers/wrapper/wrapper_resolver.py index a7e29309..2d6a3a76 100644 --- a/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/resolvers/wrapper/wrapper_resolver.py +++ b/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/resolvers/wrapper/wrapper_resolver.py @@ -54,3 +54,6 @@ def _try_resolve_uri( UriPackageOrWrapper: The resolved URI, wrap package, or wrapper. """ return uri if uri != self.uri else UriWrapper(uri=uri, wrapper=self.wrapper) + + +__all__ = ["WrapperResolver"] diff --git a/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/types/__init__.py b/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/types/__init__.py index af3dc381..eab11c6a 100644 --- a/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/types/__init__.py +++ b/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/types/__init__.py @@ -1,4 +1,3 @@ """This package contains the types used by the polywrap-uri-resolvers package.""" from .cache import * from .static_resolver_like import * -from .uri_redirect import * diff --git a/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/types/cache/resolution_result_cache/in_memory_resolution_result_cache.py b/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/types/cache/resolution_result_cache/in_memory_resolution_result_cache.py index 6c36e99e..780b15f8 100644 --- a/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/types/cache/resolution_result_cache/in_memory_resolution_result_cache.py +++ b/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/types/cache/resolution_result_cache/in_memory_resolution_result_cache.py @@ -9,7 +9,7 @@ class InMemoryResolutionResultCache(ResolutionResultCache): """InMemoryResolutionResultCache is an in-memory implementation \ - of the resolution result cache interface.""" + of the resolution result cache protocol.""" map: Dict[Uri, Union[UriPackageOrWrapper, UriResolutionError]] """The map of uris to resolution result.""" @@ -31,3 +31,6 @@ def set( def __str__(self) -> str: """Display cache as a string.""" return f"{self.map}" + + +__all__ = ["InMemoryResolutionResultCache"] diff --git a/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/types/cache/resolution_result_cache/resolution_result_cache.py b/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/types/cache/resolution_result_cache/resolution_result_cache.py index 154eb71c..15534198 100644 --- a/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/types/cache/resolution_result_cache/resolution_result_cache.py +++ b/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/types/cache/resolution_result_cache/resolution_result_cache.py @@ -8,7 +8,7 @@ class ResolutionResultCache(Protocol): - """Defines a cache interface for caching resolution results by uri. + """Defines a cache protocol for caching resolution results by uri. This is used by the resolution result resolver to cache resolution results\ for a given uri. @@ -27,3 +27,6 @@ def set( def __str__(self) -> str: """Display cache as a string.""" ... + + +__all__ = ["ResolutionResultCache"] diff --git a/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/types/uri_redirect.py b/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/types/uri_redirect.py deleted file mode 100644 index 65c49d91..00000000 --- a/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/types/uri_redirect.py +++ /dev/null @@ -1,17 +0,0 @@ -"""This module contains the UriRedirect type.""" -from dataclasses import dataclass - -from polywrap_core import Uri - - -@dataclass(slots=True, kw_only=True) -class UriRedirect: - """UriRedirect is a type that represents a redirect from one uri to another. - - Args: - from_uri (Uri): The uri to redirect from. - to_uri (Uri): The uri to redirect to. - """ - - from_uri: Uri - to_uri: Uri diff --git a/packages/polywrap-wasm/polywrap_wasm/buffer.py b/packages/polywrap-wasm/polywrap_wasm/buffer.py index d61f8f65..0593403f 100644 --- a/packages/polywrap-wasm/polywrap_wasm/buffer.py +++ b/packages/polywrap-wasm/polywrap_wasm/buffer.py @@ -20,10 +20,10 @@ def read_bytes( """Read bytes from a memory buffer. Args: - memory_pointer: The pointer to the memory buffer. - memory_length: The length of the memory buffer. - offset: The offset to start reading from. - length: The number of bytes to read. + memory_pointer (BufferPointer): The pointer to the memory buffer. + memory_length (int): The length of the memory buffer. + offset (Optional[int]): The offset to start reading from. + length (Optional[int]): The number of bytes to read. """ result = bytearray(memory_length) buffer = (ctypes.c_ubyte * memory_length).from_buffer(result) @@ -38,10 +38,10 @@ def read_string( """Read a UTF-8 encoded string from a memory buffer. Args: - memory_pointer: The pointer to the memory buffer. - memory_length: The length of the memory buffer. - offset: The offset to start reading from. - length: The number of bytes to read. + memory_pointer (BufferPointer): The pointer to the memory buffer. + memory_length (int): The length of the memory buffer. + offset (int): The offset to start reading from. + length (int): The number of bytes to read. """ value = read_bytes(memory_pointer, memory_length, offset, length) return value.decode("utf-8") @@ -56,10 +56,10 @@ def write_bytes( """Write bytes to a memory buffer. Args: - memory_pointer: The pointer to the memory buffer. - memory_length: The length of the memory buffer. - value: The bytes to write. - value_offset: The offset to start writing to. + memory_pointer (BufferPointer): The pointer to the memory buffer. + memory_length (int): The length of the memory buffer. + value (bytes): The bytes to write. + value_offset (int): The offset to start writing to. """ mem_cpy(memory_pointer, memory_length, bytearray(value), len(value), value_offset) @@ -73,10 +73,10 @@ def write_string( """Write a UTF-8 encoded string to a memory buffer. Args: - memory_pointer: The pointer to the memory buffer. - memory_length: The length of the memory buffer. - value: The string to write. - value_offset: The offset to start writing to. + memory_pointer (BufferPointer): The pointer to the memory buffer. + memory_length (int): The length of the memory buffer. + value (str): The string to write. + value_offset (int): The offset to start writing to. """ value_buffer = value.encode("utf-8") write_bytes( @@ -97,11 +97,11 @@ def mem_cpy( """Copy bytearray from the given value to a memory buffer. Args: - memory_pointer: The pointer to the memory buffer. - memory_length: The length of the memory buffer. - value: The bytearray to copy. - value_length: The length of the bytearray to copy. - value_offset: The offset to start copying from. + memory_pointer (BufferPointer): The pointer to the memory buffer. + memory_length (int): The length of the memory buffer. + value (bytearray): The bytearray to copy. + value_length (int): The length of the bytearray to copy. + value_offset (int): The offset to start copying from. """ current_value = bytearray( read_bytes( diff --git a/packages/polywrap-wasm/polywrap_wasm/exports.py b/packages/polywrap-wasm/polywrap_wasm/exports.py index 2af6878b..0e5d0516 100644 --- a/packages/polywrap-wasm/polywrap_wasm/exports.py +++ b/packages/polywrap-wasm/polywrap_wasm/exports.py @@ -8,9 +8,9 @@ class WrapExports: """WrapExports is a class that contains the exports of the Wasm wrapper module. Args: - instance: The Wasm instance. - store: The Wasm store. - _wrap_invoke: The exported _wrap_invoke Wasm function. + instance (Instance): The Wasm instance. + store (Store): The Wasm store. + _wrap_invoke (Func): The exported _wrap_invoke Wasm function. Raises: WasmExportNotFoundError: If the _wrap_invoke function is not exported\ diff --git a/packages/polywrap-wasm/polywrap_wasm/imports/abort.py b/packages/polywrap-wasm/polywrap_wasm/imports/abort.py index 0d0d5df0..1b92325a 100644 --- a/packages/polywrap-wasm/polywrap_wasm/imports/abort.py +++ b/packages/polywrap-wasm/polywrap_wasm/imports/abort.py @@ -19,12 +19,12 @@ def wrap_abort( """Abort the Wasm module and raise an exception. Args: - msg_ptr: The pointer to the message string in memory. - msg_len: The length of the message string in memory. - file_ptr: The pointer to the filename string in memory. - file_len: The length of the filename string in memory. - line: The line of the file at where the abort occured. - column: The column of the file at where the abort occured. + msg_ptr (int): The pointer to the message string in memory. + msg_len (int): The length of the message string in memory. + file_ptr (int): The pointer to the filename string in memory. + file_len (int): The length of the filename string in memory. + line (int): The line of the file at where the abort occured. + column (int): The column of the file at where the abort occured. Raises: WasmAbortError: since the Wasm module aborted during invocation. diff --git a/packages/polywrap-wasm/polywrap_wasm/imports/debug.py b/packages/polywrap-wasm/polywrap_wasm/imports/debug.py index 36755e32..1a75b1ea 100644 --- a/packages/polywrap-wasm/polywrap_wasm/imports/debug.py +++ b/packages/polywrap-wasm/polywrap_wasm/imports/debug.py @@ -9,8 +9,8 @@ def wrap_debug_log(self, msg_ptr: int, msg_len: int) -> None: """Print the transmitted message from the Wasm module to host stdout. Args: - ptr: The pointer to the message string in memory. - len: The length of the message string in memory. + msg_ptr (int): The pointer to the message string in memory. + msg_len (int): The length of the message string in memory. """ msg = self.read_string(msg_ptr, msg_len) print(msg) diff --git a/packages/polywrap-wasm/polywrap_wasm/imports/env.py b/packages/polywrap-wasm/polywrap_wasm/imports/env.py index df7d78b7..bf40ea91 100644 --- a/packages/polywrap-wasm/polywrap_wasm/imports/env.py +++ b/packages/polywrap-wasm/polywrap_wasm/imports/env.py @@ -12,7 +12,7 @@ def wrap_load_env(self, ptr: int) -> None: """Write the env in the shared memory at Wasm allocated empty env slot. Args: - ptr: The pointer to the empty env slot in memory. + ptr (int): The pointer to the empty env slot in memory. Raises: WasmAbortError: if the env is not set from the host. diff --git a/packages/polywrap-wasm/polywrap_wasm/imports/get_implementations.py b/packages/polywrap-wasm/polywrap_wasm/imports/get_implementations.py index 994ff671..c8b95c31 100644 --- a/packages/polywrap-wasm/polywrap_wasm/imports/get_implementations.py +++ b/packages/polywrap-wasm/polywrap_wasm/imports/get_implementations.py @@ -15,8 +15,8 @@ def wrap_get_implementations(self, uri_ptr: int, uri_len: int) -> bool: from the invoker and store it in the state. Args: - uri_ptr: The pointer to the interface URI bytes in memory. - uri_len: The length of the interface URI bytes in memory. + uri_ptr (int): The pointer to the interface URI bytes in memory. + uri_len (int): The length of the interface URI bytes in memory. """ uri = Uri.from_str( self.read_string( diff --git a/packages/polywrap-wasm/polywrap_wasm/imports/invoke.py b/packages/polywrap-wasm/polywrap_wasm/imports/invoke.py index 045cdf01..1e3f49d3 100644 --- a/packages/polywrap-wasm/polywrap_wasm/imports/invoke.py +++ b/packages/polywrap-wasm/polywrap_wasm/imports/invoke.py @@ -14,8 +14,8 @@ def wrap_invoke_args(self, method_ptr: int, args_ptr: int) -> None: at Wasm allocated empty method and args slots. Args: - method_ptr: The pointer to the empty method name string slot in memory. - args_ptr: The pointer to the empty method args bytes slot in memory. + method_ptr (int): The pointer to the empty method name string slot in memory. + args_ptr (int): The pointer to the empty method args bytes slot in memory. Raises: WasmAbortError: if the method or args are not set from the host. @@ -41,8 +41,8 @@ def wrap_invoke_result(self, ptr: int, length: int) -> None: in the shared memory by the Wasm module in the state. Args: - ptr: The pointer to the result bytes in memory. - length: The length of the result bytes in memory. + ptr (int): The pointer to the result bytes in memory. + length (int): The length of the result bytes in memory. """ result = self.read_bytes( ptr, @@ -55,8 +55,8 @@ def wrap_invoke_error(self, ptr: int, length: int): in the shared memory by the Wasm module in the state. Args: - ptr: The pointer to the error string in memory. - length: The length of the error string in memory. + ptr (int): The pointer to the error string in memory. + length (int): The length of the error string in memory. """ error = self.read_string( ptr, diff --git a/packages/polywrap-wasm/polywrap_wasm/imports/subinvoke.py b/packages/polywrap-wasm/polywrap_wasm/imports/subinvoke.py index a1cdd5aa..126c1f85 100644 --- a/packages/polywrap-wasm/polywrap_wasm/imports/subinvoke.py +++ b/packages/polywrap-wasm/polywrap_wasm/imports/subinvoke.py @@ -21,12 +21,12 @@ def wrap_subinvoke( """Subinvoke a function of any wrapper from the Wasm module. Args: - uri_ptr: The pointer to the uri string in memory. - uri_len: The length of the uri string in memory. - method_ptr: The pointer to the method string in memory. - method_len: The length of the method string in memory. - args_ptr: The pointer to the args bytes in memory. - args_len: The length of the args bytes in memory. + uri_ptr (int): The pointer to the uri string in memory. + uri_len (int): The length of the uri string in memory. + method_ptr (int): The pointer to the method string in memory. + method_len (int): The length of the method string in memory. + args_ptr (int): The pointer to the args bytes in memory. + args_len (int): The length of the args bytes in memory. Returns: True if the subinvocation was successful, False otherwise. @@ -68,7 +68,7 @@ def wrap_subinvoke_result(self, ptr: int) -> None: """Write the result of the subinvocation to shared memory. Args: - ptr: The pointer to the empty result bytes slot in memory. + ptr (int): The pointer to the empty result bytes slot in memory. """ result = self._get_subinvoke_result("__wrap_subinvoke_result") self.write_bytes(ptr, result) @@ -84,7 +84,7 @@ def wrap_subinvoke_error(self, ptr: int) -> None: at pointer to the Wasm allocated empty error message slot. Args: - ptr: The pointer to the empty error message slot in memory. + ptr (int): The pointer to the empty error message slot in memory. """ error = self._get_subinvoke_error("__wrap_subinvoke_error") error_message = repr(error) diff --git a/packages/polywrap-wasm/polywrap_wasm/imports/wrap_imports.py b/packages/polywrap-wasm/polywrap_wasm/imports/wrap_imports.py index bc696557..9ac495f3 100644 --- a/packages/polywrap-wasm/polywrap_wasm/imports/wrap_imports.py +++ b/packages/polywrap-wasm/polywrap_wasm/imports/wrap_imports.py @@ -30,16 +30,16 @@ class WrapImports( This class is responsible for providing all the Wasm imports to the Wasm module. Args: - memory: The Wasm memory instance. - store: The Wasm store instance. - state: The state of the Wasm module. - invoker: The invoker instance. + memory (Memory): The Wasm memory instance. + store (Store): The Wasm store instance. + state (State): The state of the Wasm module. + invoker (Invoker): The invoker instance. Attributes: - memory: The Wasm memory instance. - store: The Wasm store instance. - state: The state of the Wasm module. - invoker: The invoker instance. + memory (Memory): The Wasm memory instance. + store (Store): The Wasm store instance. + state (State): The state of the Wasm module. + invoker (Invoker): The invoker instance. """ def __init__( diff --git a/packages/polywrap-wasm/polywrap_wasm/inmemory_file_reader.py b/packages/polywrap-wasm/polywrap_wasm/inmemory_file_reader.py index 39ca996e..24e916b4 100644 --- a/packages/polywrap-wasm/polywrap_wasm/inmemory_file_reader.py +++ b/packages/polywrap-wasm/polywrap_wasm/inmemory_file_reader.py @@ -7,7 +7,7 @@ class InMemoryFileReader(FileReader): - """InMemoryFileReader is an implementation of the IFileReader interface\ + """InMemoryFileReader is an implementation of the FileReader protocol\ that reads files from memory. Args: diff --git a/packages/polywrap-wasm/polywrap_wasm/instance.py b/packages/polywrap-wasm/polywrap_wasm/instance.py index c1f4de53..090113b8 100644 --- a/packages/polywrap-wasm/polywrap_wasm/instance.py +++ b/packages/polywrap-wasm/polywrap_wasm/instance.py @@ -19,10 +19,10 @@ def create_instance( """Create a Wasm instance for a Wasm module. Args: - store: The Wasm store. - module: The Wasm module. - state: The state of the Wasm module. - invoker: The invoker to use for subinvocations. + store (Store): The Wasm store. + module (bytes): The Wasm module. + state (State): The state of the Wasm module. + invoker (Optional[Invoker]): The invoker to use for subinvocations. Returns: Instance: The Wasm instance. diff --git a/packages/polywrap-wasm/polywrap_wasm/memory.py b/packages/polywrap-wasm/polywrap_wasm/memory.py index 3dd34404..071cc7c9 100644 --- a/packages/polywrap-wasm/polywrap_wasm/memory.py +++ b/packages/polywrap-wasm/polywrap_wasm/memory.py @@ -14,8 +14,8 @@ def create_memory( """Create a host allocated shared memory instance for a Wasm module. Args: - store: The Wasm store. - module: The Wasm module. + store (Store): The Wasm store. + module (bytes): The Wasm module. Raises: WasmMemoryError: if the memory import is not found in the Wasm module. diff --git a/packages/polywrap-wasm/polywrap_wasm/types/__init__.py b/packages/polywrap-wasm/polywrap_wasm/types/__init__.py index 80b0f679..07609f43 100644 --- a/packages/polywrap-wasm/polywrap_wasm/types/__init__.py +++ b/packages/polywrap-wasm/polywrap_wasm/types/__init__.py @@ -1,2 +1,4 @@ """This module contains the core types, interfaces, and utilities of polywrap-wasm package.""" from .state import * +from .invoke_result import * +from .wasm_invoke_options import * diff --git a/packages/polywrap-wasm/polywrap_wasm/types/invoke_result.py b/packages/polywrap-wasm/polywrap_wasm/types/invoke_result.py new file mode 100644 index 00000000..0c97bf81 --- /dev/null +++ b/packages/polywrap-wasm/polywrap_wasm/types/invoke_result.py @@ -0,0 +1,25 @@ + +from dataclasses import dataclass +from typing import Generic, Optional, TypeVar + +E = TypeVar("E") + + +@dataclass(kw_only=True, slots=True) +class InvokeResult(Generic[E]): + """InvokeResult is a dataclass that holds the result of an invocation. + + Args: + result (Optional[bytes]): The result of an invocation. + error (Optional[E]): The error of an invocation. + """ + + result: Optional[bytes] = None + error: Optional[E] = None + + def __post_init__(self): + """Validate that either result or error is set.""" + if self.result is None and self.error is None: + raise ValueError( + "Either result or error must be set in InvokeResult instance." + ) diff --git a/packages/polywrap-wasm/polywrap_wasm/types/state.py b/packages/polywrap-wasm/polywrap_wasm/types/state.py index e6f63b97..f253c627 100644 --- a/packages/polywrap-wasm/polywrap_wasm/types/state.py +++ b/packages/polywrap-wasm/polywrap_wasm/types/state.py @@ -1,49 +1,9 @@ """This module contains the State type for holding the state of a Wasm wrapper.""" from dataclasses import dataclass -from typing import Any, Generic, Optional, TypeVar +from typing import Optional -from polywrap_core import Uri, UriResolutionContext - -E = TypeVar("E") - - -@dataclass(kw_only=True, slots=True) -class WasmInvokeOptions: - """WasmInvokeOptions is a dataclass that holds the options for an invocation. - - Args: - uri: The URI of the wrapper. - method: The method to invoke. - args: The arguments to pass to the method. - env: The environment variables to set for the invocation. - resolution_context: A URI resolution context. - """ - - uri: Uri - method: str - args: Optional[dict[str, Any]] = None - env: Optional[dict[str, Any]] = None - resolution_context: Optional[UriResolutionContext] = None - - -@dataclass(kw_only=True, slots=True) -class InvokeResult(Generic[E]): - """InvokeResult is a dataclass that holds the result of an invocation. - - Args: - result: The result of an invocation. - error: The error of an invocation. - """ - - result: Optional[bytes] = None - error: Optional[E] = None - - def __post_init__(self): - """Validate that either result or error is set.""" - if self.result is None and self.error is None: - raise ValueError( - "Either result or error must be set in InvokeResult instance." - ) +from .invoke_result import InvokeResult +from .wasm_invoke_options import WasmInvokeOptions @dataclass(kw_only=True, slots=True) @@ -51,11 +11,14 @@ class State: """State is a dataclass that holds the state of a Wasm wrapper. Args: - invoke_options: The options used for the invocation. - invoke_result: The result of an invocation. - subinvoke_result: The result of a subinvocation. - subinvoke_implementation_result: The result of a subinvoke implementation invoke call. - get_implementations_result: The result of a get implementations call. + invoke_options (WasmInvokeOptions): \ + The options used for the invocation. + invoke_result (Optional[InvokeResult[str]]): \ + The result of an invocation. + subinvoke_result (Optional[InvokeResult[Exception]]): \ + The result of a subinvocation. + get_implementations_result (Optional[bytes]) : \ + The result of a get implementations call. """ invoke_options: WasmInvokeOptions diff --git a/packages/polywrap-wasm/polywrap_wasm/types/wasm_invoke_options.py b/packages/polywrap-wasm/polywrap_wasm/types/wasm_invoke_options.py new file mode 100644 index 00000000..829e3207 --- /dev/null +++ b/packages/polywrap-wasm/polywrap_wasm/types/wasm_invoke_options.py @@ -0,0 +1,25 @@ +from dataclasses import dataclass +from typing import Any, Optional + +from polywrap_core import Uri, UriResolutionContext + + +@dataclass(kw_only=True, slots=True) +class WasmInvokeOptions: + """WasmInvokeOptions is a dataclass that holds the options for an invocation. + + Args: + uri (Uri): The URI of the wrapper. + method (str): The method to invoke. + args (Optional[dict[str, Any]]): The arguments to pass to the method. + env (Optional[dict[str, Any]]): The environment variables to set\ + for the invocation. + resolution_context (Optional[UriResolutionContext]): \ + A URI resolution context. + """ + + uri: Uri + method: str + args: Optional[dict[str, Any]] = None + env: Optional[dict[str, Any]] = None + resolution_context: Optional[UriResolutionContext] = None diff --git a/packages/polywrap-wasm/polywrap_wasm/wasm_package.py b/packages/polywrap-wasm/polywrap_wasm/wasm_package.py index b246cf13..02594155 100644 --- a/packages/polywrap-wasm/polywrap_wasm/wasm_package.py +++ b/packages/polywrap-wasm/polywrap_wasm/wasm_package.py @@ -14,7 +14,7 @@ class WasmPackage(WrapPackage): - """WasmPackage is a type that represents a Wasm WRAP package. + """WasmPackage implements the WRAP package protocol for a Wasm WRAP package. Args: file_reader (FileReader): The file reader used to read\ @@ -50,7 +50,8 @@ def get_manifest( """Get the manifest of the wrapper. Args: - options: The options to use when getting the manifest. + options (Optional[DeserializeManifestOptions]): The options\ + to use when getting the manifest. """ if isinstance(self.manifest, AnyWrapManifest): return self.manifest diff --git a/packages/polywrap-wasm/polywrap_wasm/wasm_wrapper.py b/packages/polywrap-wasm/polywrap_wasm/wasm_wrapper.py index d2f64dd8..af4ae4c1 100644 --- a/packages/polywrap-wasm/polywrap_wasm/wasm_wrapper.py +++ b/packages/polywrap-wasm/polywrap_wasm/wasm_wrapper.py @@ -23,7 +23,7 @@ class WasmWrapper(Wrapper): - """WasmWrapper implements the Wrapper interface for Wasm wrappers. + """WasmWrapper implements the Wrapper protocol for Wasm wrappers. Args: file_reader: The file reader used to read the wrapper files. @@ -57,7 +57,8 @@ def get_file( """Get a file from the wrapper. Args: - options: The options to use when getting the file. + path (str): The path of the file to get. + encoding (Optional[str]): The encoding to use when reading the file. Returns: The file contents as string or bytes according to encoding or an error. @@ -71,9 +72,9 @@ def create_wasm_instance( """Create a new Wasm instance for the wrapper. Args: - store: The Wasm store to use when creating the instance. - state: The Wasm wrapper state to use when creating the instance. - client: The client to use when creating the instance. + store (Store): The Wasm store to use when creating the instance. + state (State): The Wasm wrapper state to use when creating the instance. + client (Optional[Invoker]): The client to use when creating the instance. Returns: The Wasm instance of the wrapper Wasm module. @@ -97,8 +98,13 @@ def invoke( """Invoke the wrapper. Args: - options: The options to use when invoking the wrapper. - client: The client to use when invoking the wrapper. + uri (Uri): The Wasm wrapper uri. + method (str): The method to invoke. + args (Optional[Dict[str, Any]]): The args to invoke with. + env (Optional[Dict[str, Any]]): The env to use when invoking. + resolution_context (Optional[UriResolutionContext]): \ + The URI resolution context to use during invocation. + client (Optional[Invoker]): The invoker to use during invocation. Returns: The result of the invocation or an error. From 78d917f9bc5e0be3eddb3f41e5af335ae49898f8 Mon Sep 17 00:00:00 2001 From: Niraj Kamdar Date: Wed, 14 Jun 2023 17:11:45 +0530 Subject: [PATCH 38/47] feat: improve docs --- .../polywrap_client_config_builder.py | 22 +++++++++++++++++ .../tests/run_doctest.py | 24 +++++++++++++++++++ packages/polywrap-core/tests/run_doctest.py | 24 +++++++++++++++++++ .../polywrap-msgpack/tests/run_doctest.py | 2 +- .../polywrap_wasm/wasm_wrapper.py | 6 ++--- 5 files changed, 74 insertions(+), 4 deletions(-) create mode 100644 packages/polywrap-client-config-builder/tests/run_doctest.py create mode 100644 packages/polywrap-core/tests/run_doctest.py diff --git a/packages/polywrap-client-config-builder/polywrap_client_config_builder/polywrap_client_config_builder.py b/packages/polywrap-client-config-builder/polywrap_client_config_builder/polywrap_client_config_builder.py index d392c0fc..d08c1f68 100644 --- a/packages/polywrap-client-config-builder/polywrap_client_config_builder/polywrap_client_config_builder.py +++ b/packages/polywrap-client-config-builder/polywrap_client_config_builder/polywrap_client_config_builder.py @@ -43,6 +43,28 @@ class PolywrapClientConfigBuilder( PolywrapClientConfigBuilder provides a simple interface for setting\ the redirects, wrappers, packages, and other configuration options\ for the Polywrap Client. + + Examples: + >>> from polywrap_client_config_builder import PolywrapClientConfigBuilder + >>> from polywrap_uri_resolvers import RecursiveResolver + >>> from polywrap_core import Uri + >>> config = ( + ... PolywrapClientConfigBuilder() + ... .set_env(Uri.from_str("test/uri"), {"hello": "world"}) + ... .add_interface_implementations( + ... Uri.from_str("test/interface"), + ... [Uri.from_str("test/impl1"), Uri.from_str("test/impl2")], + ... ) + ... .set_redirect(Uri("test", "from"), Uri("test", "to")) + ... .set_env(Uri("test", "to"), {"foo": "bar"}) + ... .build() + ... ) + >>> config.envs + {Uri("test", "uri"): {'hello': 'world'}, Uri("test", "to"): {'foo': 'bar'}} + >>> config.interfaces + {Uri("test", "interface"): [Uri("test", "impl1"), Uri("test", "impl2")]} + >>> isinstance(config.resolver, RecursiveResolver) + True """ def __init__(self): diff --git a/packages/polywrap-client-config-builder/tests/run_doctest.py b/packages/polywrap-client-config-builder/tests/run_doctest.py new file mode 100644 index 00000000..ec9d73c5 --- /dev/null +++ b/packages/polywrap-client-config-builder/tests/run_doctest.py @@ -0,0 +1,24 @@ +# test_all.py +import doctest +from typing import Any +import unittest +import pkgutil +import polywrap_client_config_builder + +def load_tests(loader: Any, tests: Any, ignore: Any) -> Any: + """Load doctests and return TestSuite object.""" + modules = pkgutil.walk_packages( + path=polywrap_client_config_builder.__path__, + prefix=f"{polywrap_client_config_builder.__name__}.", + onerror=lambda x: None, + ) + for _, modname, _ in modules: + try: + module = __import__(modname, fromlist="dummy") + tests.addTests(doctest.DocTestSuite(module)) + except (ImportError, ValueError, AttributeError): + continue + return tests + +if __name__ == "__main__": + unittest.main() diff --git a/packages/polywrap-core/tests/run_doctest.py b/packages/polywrap-core/tests/run_doctest.py new file mode 100644 index 00000000..3fc4848e --- /dev/null +++ b/packages/polywrap-core/tests/run_doctest.py @@ -0,0 +1,24 @@ +# test_all.py +import doctest +from typing import Any +import unittest +import pkgutil +import polywrap_msgpack + +def load_tests(loader: Any, tests: Any, ignore: Any) -> Any: + """Load doctests and return TestSuite object.""" + modules = pkgutil.walk_packages( + path=polywrap_msgpack.__path__, + prefix=f"{polywrap_msgpack.__name__}.", + onerror=lambda x: None, + ) + for _, modname, _ in modules: + try: + module = __import__(modname, fromlist="dummy") + tests.addTests(doctest.DocTestSuite(module)) + except (ImportError, ValueError, AttributeError): + continue + return tests + +if __name__ == "__main__": + unittest.main() diff --git a/packages/polywrap-msgpack/tests/run_doctest.py b/packages/polywrap-msgpack/tests/run_doctest.py index 0d4f401e..3fc4848e 100644 --- a/packages/polywrap-msgpack/tests/run_doctest.py +++ b/packages/polywrap-msgpack/tests/run_doctest.py @@ -3,7 +3,7 @@ from typing import Any import unittest import pkgutil -import polywrap_msgpack # replace with your actual package name +import polywrap_msgpack def load_tests(loader: Any, tests: Any, ignore: Any) -> Any: """Load doctests and return TestSuite object.""" diff --git a/packages/polywrap-wasm/polywrap_wasm/wasm_wrapper.py b/packages/polywrap-wasm/polywrap_wasm/wasm_wrapper.py index af4ae4c1..51c2b419 100644 --- a/packages/polywrap-wasm/polywrap_wasm/wasm_wrapper.py +++ b/packages/polywrap-wasm/polywrap_wasm/wasm_wrapper.py @@ -26,9 +26,9 @@ class WasmWrapper(Wrapper): """WasmWrapper implements the Wrapper protocol for Wasm wrappers. Args: - file_reader: The file reader used to read the wrapper files. - wasm_module: The Wasm module file of the wrapper. - manifest: The manifest of the wrapper. + file_reader (FileReader): The file reader used to read the wrapper files. + wasm_module (bytes): The Wasm module file of the wrapper. + manifest (AnyWrapManifest): The manifest of the wrapper. """ file_reader: FileReader From 73421513f3fc59ac2ce160ec742a86131593ce7a Mon Sep 17 00:00:00 2001 From: Niraj Kamdar Date: Wed, 14 Jun 2023 17:37:55 +0530 Subject: [PATCH 39/47] feat: improve docs --- packages/polywrap-client/polywrap_client/client.py | 6 ++---- packages/polywrap-core/polywrap_core/types/__init__.py | 1 + .../polywrap_core/types/clean_resolution_step.py | 4 ++++ .../polywrap_core/utils/build_clean_uri_history.py | 6 ++---- .../polywrap-uri-resolvers/polywrap_uri_resolvers/errors.py | 2 +- .../legacy/wrapper_cache/in_memory_wrapper_cache.py | 3 +-- .../resolvers/package/package_resolver.py | 2 +- .../resolvers/wrapper/wrapper_resolver.py | 1 + .../polywrap-wasm/polywrap_wasm/imports/wrap_imports.py | 2 +- packages/polywrap-wasm/polywrap_wasm/types/__init__.py | 2 +- packages/polywrap-wasm/polywrap_wasm/types/invoke_result.py | 2 +- .../polywrap_wasm/types/wasm_invoke_options.py | 1 + packages/polywrap-wasm/polywrap_wasm/wasm_wrapper.py | 2 +- 13 files changed, 18 insertions(+), 16 deletions(-) create mode 100644 packages/polywrap-core/polywrap_core/types/clean_resolution_step.py diff --git a/packages/polywrap-client/polywrap_client/client.py b/packages/polywrap-client/polywrap_client/client.py index f70658ca..edc95400 100644 --- a/packages/polywrap-client/polywrap_client/client.py +++ b/packages/polywrap-client/polywrap_client/client.py @@ -11,6 +11,7 @@ Uri, UriPackage, UriPackageOrWrapper, + UriResolutionContext, UriResolutionStep, UriResolver, UriWrapper, @@ -18,10 +19,7 @@ build_clean_uri_history, get_env_from_resolution_path, ) -from polywrap_core import ( - get_implementations as core_get_implementations, - UriResolutionContext, -) +from polywrap_core import get_implementations as core_get_implementations from polywrap_manifest import AnyWrapManifest, DeserializeManifestOptions from polywrap_msgpack import msgpack_decode, msgpack_encode diff --git a/packages/polywrap-core/polywrap_core/types/__init__.py b/packages/polywrap-core/polywrap_core/types/__init__.py index 1ce2c342..4559c269 100644 --- a/packages/polywrap-core/polywrap_core/types/__init__.py +++ b/packages/polywrap-core/polywrap_core/types/__init__.py @@ -1,4 +1,5 @@ """This module contains all the core types used in the various polywrap packages.""" +from .clean_resolution_step import * from .client import * from .config import * from .errors import * diff --git a/packages/polywrap-core/polywrap_core/types/clean_resolution_step.py b/packages/polywrap-core/polywrap_core/types/clean_resolution_step.py new file mode 100644 index 00000000..9b14e766 --- /dev/null +++ b/packages/polywrap-core/polywrap_core/types/clean_resolution_step.py @@ -0,0 +1,4 @@ +"""This module contains CleanResolutionStep type.""" +from typing import List, Union + +CleanResolutionStep = List[Union[str, "CleanResolutionStep"]] diff --git a/packages/polywrap-core/polywrap_core/utils/build_clean_uri_history.py b/packages/polywrap-core/polywrap_core/utils/build_clean_uri_history.py index 70e13f62..7a32fa1e 100644 --- a/packages/polywrap-core/polywrap_core/utils/build_clean_uri_history.py +++ b/packages/polywrap-core/polywrap_core/utils/build_clean_uri_history.py @@ -1,9 +1,7 @@ """This module contains an utility function for building a clean history of URI resolution steps.""" -from typing import List, Optional, Union +from typing import List, Optional -from ..types import UriPackage, UriResolutionStep, UriWrapper - -CleanResolutionStep = List[Union[str, "CleanResolutionStep"]] +from ..types import CleanResolutionStep, UriPackage, UriResolutionStep, UriWrapper def build_clean_uri_history( diff --git a/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/errors.py b/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/errors.py index 27e23cdf..c25490d5 100644 --- a/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/errors.py +++ b/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/errors.py @@ -60,4 +60,4 @@ def __init__(self, uri: Uri, history: List[UriResolutionStep]): "InfiniteLoopError", "UriResolverExtensionError", "UriResolverExtensionNotFoundError", -] \ No newline at end of file +] diff --git a/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/resolvers/legacy/wrapper_cache/in_memory_wrapper_cache.py b/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/resolvers/legacy/wrapper_cache/in_memory_wrapper_cache.py index 925cb08c..cd61684a 100644 --- a/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/resolvers/legacy/wrapper_cache/in_memory_wrapper_cache.py +++ b/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/resolvers/legacy/wrapper_cache/in_memory_wrapper_cache.py @@ -8,8 +8,7 @@ class InMemoryWrapperCache(WrapperCache): """InMemoryWrapperCache is an in-memory implementation\ - of the wrapper cache interface. - """ + of the wrapper cache interface.""" map: Dict[Uri, UriWrapper] """The map of uris to wrappers.""" diff --git a/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/resolvers/package/package_resolver.py b/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/resolvers/package/package_resolver.py index b44793f1..abb82b4f 100644 --- a/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/resolvers/package/package_resolver.py +++ b/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/resolvers/package/package_resolver.py @@ -63,4 +63,4 @@ def _try_resolve_uri( return uri if uri != self.uri else UriPackage(uri=uri, package=self.package) -__all__ = ["PackageResolver"] \ No newline at end of file +__all__ = ["PackageResolver"] diff --git a/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/resolvers/wrapper/wrapper_resolver.py b/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/resolvers/wrapper/wrapper_resolver.py index 2d6a3a76..fdd97983 100644 --- a/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/resolvers/wrapper/wrapper_resolver.py +++ b/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/resolvers/wrapper/wrapper_resolver.py @@ -25,6 +25,7 @@ class WrapperResolver(ResolverWithHistory): wrapper: Wrapper def __init__(self, uri: Uri, wrapper: Wrapper): + """Initialize a new WrapperResolver instance.""" self.uri = uri self.wrapper = wrapper super().__init__() diff --git a/packages/polywrap-wasm/polywrap_wasm/imports/wrap_imports.py b/packages/polywrap-wasm/polywrap_wasm/imports/wrap_imports.py index 9ac495f3..33e9485f 100644 --- a/packages/polywrap-wasm/polywrap_wasm/imports/wrap_imports.py +++ b/packages/polywrap-wasm/polywrap_wasm/imports/wrap_imports.py @@ -34,7 +34,7 @@ class WrapImports( store (Store): The Wasm store instance. state (State): The state of the Wasm module. invoker (Invoker): The invoker instance. - + Attributes: memory (Memory): The Wasm memory instance. store (Store): The Wasm store instance. diff --git a/packages/polywrap-wasm/polywrap_wasm/types/__init__.py b/packages/polywrap-wasm/polywrap_wasm/types/__init__.py index 07609f43..d5fa8523 100644 --- a/packages/polywrap-wasm/polywrap_wasm/types/__init__.py +++ b/packages/polywrap-wasm/polywrap_wasm/types/__init__.py @@ -1,4 +1,4 @@ """This module contains the core types, interfaces, and utilities of polywrap-wasm package.""" -from .state import * from .invoke_result import * +from .state import * from .wasm_invoke_options import * diff --git a/packages/polywrap-wasm/polywrap_wasm/types/invoke_result.py b/packages/polywrap-wasm/polywrap_wasm/types/invoke_result.py index 0c97bf81..10403232 100644 --- a/packages/polywrap-wasm/polywrap_wasm/types/invoke_result.py +++ b/packages/polywrap-wasm/polywrap_wasm/types/invoke_result.py @@ -1,4 +1,4 @@ - +"""This module contains the InvokeResult type.""" from dataclasses import dataclass from typing import Generic, Optional, TypeVar diff --git a/packages/polywrap-wasm/polywrap_wasm/types/wasm_invoke_options.py b/packages/polywrap-wasm/polywrap_wasm/types/wasm_invoke_options.py index 829e3207..217f806a 100644 --- a/packages/polywrap-wasm/polywrap_wasm/types/wasm_invoke_options.py +++ b/packages/polywrap-wasm/polywrap_wasm/types/wasm_invoke_options.py @@ -1,3 +1,4 @@ +"""This module contains the InvokeOptions type for a Wasm wrapper.""" from dataclasses import dataclass from typing import Any, Optional diff --git a/packages/polywrap-wasm/polywrap_wasm/wasm_wrapper.py b/packages/polywrap-wasm/polywrap_wasm/wasm_wrapper.py index 51c2b419..8e585f5f 100644 --- a/packages/polywrap-wasm/polywrap_wasm/wasm_wrapper.py +++ b/packages/polywrap-wasm/polywrap_wasm/wasm_wrapper.py @@ -19,7 +19,7 @@ from .exports import WrapExports from .instance import create_instance -from .types.state import WasmInvokeOptions, State +from .types.state import State, WasmInvokeOptions class WasmWrapper(Wrapper): From 71c0b64c7cb77daf85d5c1358297a65b2e2f4063 Mon Sep 17 00:00:00 2001 From: Niraj Kamdar Date: Wed, 14 Jun 2023 18:11:01 +0530 Subject: [PATCH 40/47] feat: export errors from polywrap msgpack --- packages/polywrap-msgpack/polywrap_msgpack/__init__.py | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/polywrap-msgpack/polywrap_msgpack/__init__.py b/packages/polywrap-msgpack/polywrap_msgpack/__init__.py index 2f317563..e74be5a4 100644 --- a/packages/polywrap-msgpack/polywrap_msgpack/__init__.py +++ b/packages/polywrap-msgpack/polywrap_msgpack/__init__.py @@ -11,3 +11,4 @@ from .encoder import * from .extensions import * from .sanitize import * +from .errors import * From 231c526e39a10293ef892e885d925ca630472aac Mon Sep 17 00:00:00 2001 From: Niraj Kamdar Date: Wed, 14 Jun 2023 18:14:59 +0530 Subject: [PATCH 41/47] feat: remove pycln from polywrap-msgpack --- packages/polywrap-msgpack/polywrap_msgpack/__init__.py | 2 +- packages/polywrap-msgpack/tox.ini | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/polywrap-msgpack/polywrap_msgpack/__init__.py b/packages/polywrap-msgpack/polywrap_msgpack/__init__.py index e74be5a4..5d8019c8 100644 --- a/packages/polywrap-msgpack/polywrap_msgpack/__init__.py +++ b/packages/polywrap-msgpack/polywrap_msgpack/__init__.py @@ -9,6 +9,6 @@ """ from .decoder import * from .encoder import * +from .errors import * from .extensions import * from .sanitize import * -from .errors import * diff --git a/packages/polywrap-msgpack/tox.ini b/packages/polywrap-msgpack/tox.ini index 3f8af3b6..aab2128e 100644 --- a/packages/polywrap-msgpack/tox.ini +++ b/packages/polywrap-msgpack/tox.ini @@ -10,7 +10,7 @@ commands = commands = isort --check-only polywrap_msgpack black --check polywrap_msgpack - pycln --check polywrap_msgpack --disable-all-dunder-policy + ; pycln --check polywrap_msgpack --disable-all-dunder-policy pylint polywrap_msgpack pydocstyle polywrap_msgpack @@ -26,4 +26,4 @@ commands = commands = isort polywrap_msgpack black polywrap_msgpack - pycln polywrap_msgpack --disable-all-dunder-policy + ; pycln polywrap_msgpack --disable-all-dunder-policy From 09d1d4e84614b6428322d41790f12dfbdf477ef3 Mon Sep 17 00:00:00 2001 From: Niraj Kamdar Date: Wed, 14 Jun 2023 18:40:22 +0530 Subject: [PATCH 42/47] fix: client-config-builder types --- .../configures/base_configure.py | 2 - .../types/client_config_builder.py | 73 +++++++++---------- .../pyproject.toml | 2 +- 3 files changed, 37 insertions(+), 40 deletions(-) diff --git a/packages/polywrap-client-config-builder/polywrap_client_config_builder/configures/base_configure.py b/packages/polywrap-client-config-builder/polywrap_client_config_builder/configures/base_configure.py index 6e23b1b9..a40fffa3 100644 --- a/packages/polywrap-client-config-builder/polywrap_client_config_builder/configures/base_configure.py +++ b/packages/polywrap-client-config-builder/polywrap_client_config_builder/configures/base_configure.py @@ -1,6 +1,4 @@ """This module contains the base configure class for the client config builder.""" -from abc import ABC - from ..types import BuilderConfig, ClientConfigBuilder diff --git a/packages/polywrap-client-config-builder/polywrap_client_config_builder/types/client_config_builder.py b/packages/polywrap-client-config-builder/polywrap_client_config_builder/types/client_config_builder.py index bb0bcebd..b13d2c40 100644 --- a/packages/polywrap-client-config-builder/polywrap_client_config_builder/types/client_config_builder.py +++ b/packages/polywrap-client-config-builder/polywrap_client_config_builder/types/client_config_builder.py @@ -1,6 +1,5 @@ """This module contains the client config builder class.""" # pylint: disable=too-many-public-methods -from abc import abstractmethod from typing import Any, Dict, List, Optional, Protocol, Union from polywrap_core import ClientConfig, Uri, UriResolver, WrapPackage, Wrapper @@ -14,171 +13,171 @@ class ClientConfigBuilder(Protocol): config: BuilderConfig - @abstractmethod def build(self, options: Optional[BuildOptions] = None) -> ClientConfig: """Build the ClientConfig object from the builder's config.""" + ... - @abstractmethod def add(self, config: BuilderConfig) -> "ClientConfigBuilder": """Add the values from the given config to the builder's config.""" + ... # ENV CONFIGURE - @abstractmethod def get_env(self, uri: Uri) -> Union[Any, None]: """Return the env for the given uri.""" + ... - @abstractmethod def get_envs(self) -> Dict[Uri, Any]: """Return the envs from the builder's config.""" + ... - @abstractmethod def set_env(self, uri: Uri, env: Any) -> "ClientConfigBuilder": """Set the env by uri in the builder's config, overiding any existing values.""" + ... - @abstractmethod def set_envs(self, uri_envs: Dict[Uri, Any]) -> "ClientConfigBuilder": """Set the envs in the builder's config, overiding any existing values.""" + ... - @abstractmethod def add_env(self, uri: Uri, env: Any) -> "ClientConfigBuilder": """Add an env for the given uri. If an Any is already associated with the uri, it is modified. """ + ... - @abstractmethod def add_envs(self, uri_envs: Dict[Uri, Any]) -> "ClientConfigBuilder": """Add a list of envs to the builder's config.""" + ... - @abstractmethod def remove_env(self, uri: Uri) -> "ClientConfigBuilder": """Remove the env for the given uri.""" + ... - @abstractmethod def remove_envs(self, uris: List[Uri]) -> "ClientConfigBuilder": """Remove the envs for the given uris.""" + ... # INTERFACE IMPLEMENTATIONS CONFIGURE - @abstractmethod def get_interfaces(self) -> Dict[Uri, List[Uri]]: """Return all registered interface and its implementations from the builder's config.""" + ... - @abstractmethod def get_interface_implementations(self, uri: Uri) -> Union[List[Uri], None]: """Return the interface for the given uri.""" + ... - @abstractmethod def add_interface_implementations( self, interface_uri: Uri, implementations_uris: List[Uri] ) -> "ClientConfigBuilder": """Add a list of implementation URIs for the given interface URI to the builder's config.""" + ... - @abstractmethod def remove_interface_implementations( self, interface_uri: Uri, implementations_uris: List[Uri] ) -> "ClientConfigBuilder": """Remove the implementations for the given interface uri.""" + ... - @abstractmethod def remove_interface(self, interface_uri: Uri) -> "ClientConfigBuilder": """Remove the interface for the given uri.""" + ... # PACKAGE CONFIGURE - @abstractmethod def get_package(self, uri: Uri) -> Union[WrapPackage, None]: """Return the package for the given uri.""" + ... - @abstractmethod def get_packages(self) -> Dict[Uri, WrapPackage]: """Return the packages from the builder's config.""" + ... - @abstractmethod def set_package(self, uri: Uri, package: WrapPackage) -> "ClientConfigBuilder": """Set the package by uri in the builder's config, overiding any existing values.""" + ... - @abstractmethod def set_packages( self, uri_packages: Dict[Uri, WrapPackage] ) -> "ClientConfigBuilder": """Set the packages in the builder's config, overiding any existing values.""" + ... - @abstractmethod def remove_package(self, uri: Uri) -> "ClientConfigBuilder": """Remove the package for the given uri.""" + ... - @abstractmethod def remove_packages(self, uris: List[Uri]) -> "ClientConfigBuilder": """Remove the packages for the given uris.""" + ... # REDIRECT CONFIGURE - @abstractmethod def get_redirect(self, uri: Uri) -> Union[Uri, None]: """Return the redirect for the given uri.""" + ... - @abstractmethod def get_redirects(self) -> Dict[Uri, Uri]: """Return the redirects from the builder's config.""" + ... - @abstractmethod def set_redirect(self, from_uri: Uri, to_uri: Uri) -> "ClientConfigBuilder": """Set the redirect from a URI to another URI in the builder's config,\ overiding any existing values.""" + ... - @abstractmethod def set_redirects(self, uri_redirects: Dict[Uri, Uri]) -> "ClientConfigBuilder": """Set the redirects in the builder's config, overiding any existing values.""" + ... - @abstractmethod def remove_redirect(self, uri: Uri) -> "ClientConfigBuilder": """Remove the redirect for the given uri.""" + ... - @abstractmethod def remove_redirects(self, uris: List[Uri]) -> "ClientConfigBuilder": """Remove the redirects for the given uris.""" + ... # RESOLVER CONFIGURE - @abstractmethod def get_resolvers(self) -> List[UriResolver]: """Return the resolvers from the builder's config.""" + ... - @abstractmethod def add_resolver(self, resolver: UriResolver) -> "ClientConfigBuilder": """Add a resolver to the builder's config.""" + ... - @abstractmethod def add_resolvers(self, resolvers_list: List[UriResolver]) -> "ClientConfigBuilder": """Add a list of resolvers to the builder's config.""" + ... # WRAPPER CONFIGURE - @abstractmethod def get_wrapper(self, uri: Uri) -> Union[Wrapper, None]: """Return the set wrapper for the given uri.""" + ... - @abstractmethod def get_wrappers(self) -> Dict[Uri, Wrapper]: """Return the wrappers from the builder's config.""" + ... - @abstractmethod def set_wrapper(self, uri: Uri, wrapper: Wrapper) -> "ClientConfigBuilder": """Set the wrapper by uri in the builder's config, overiding any existing values.""" + ... - @abstractmethod def set_wrappers(self, uri_wrappers: Dict[Uri, Wrapper]) -> "ClientConfigBuilder": """Set the wrappers in the builder's config, overiding any existing values.""" + ... - @abstractmethod def remove_wrapper(self, uri: Uri) -> "ClientConfigBuilder": """Remove the wrapper for the given uri.""" + ... - @abstractmethod def remove_wrappers(self, uris: List[Uri]) -> "ClientConfigBuilder": """Remove the wrappers for the given uris.""" + ... __all__ = ["ClientConfigBuilder"] diff --git a/packages/polywrap-client-config-builder/pyproject.toml b/packages/polywrap-client-config-builder/pyproject.toml index 59bbc3d0..96e713b7 100644 --- a/packages/polywrap-client-config-builder/pyproject.toml +++ b/packages/polywrap-client-config-builder/pyproject.toml @@ -45,7 +45,7 @@ testpaths = [ [tool.pylint] disable = [ - + "unnecessary-ellipsis" ] ignore = [ "tests/" From 7e60731ea753b5d6b3c1694d903645e8f7d0eead Mon Sep 17 00:00:00 2001 From: Niraj Kamdar Date: Wed, 14 Jun 2023 19:05:26 +0530 Subject: [PATCH 43/47] fix: typing and linting issues --- .../configures/base_configure.py | 6 ++++-- .../configures/env_configure.py | 15 +++++++-------- .../configures/interface_configure.py | 11 +++++------ .../configures/package_configure.py | 13 ++++++------- .../configures/redirect_configure.py | 13 ++++++------- .../configures/resolver_configure.py | 9 ++++----- .../configures/wrapper_configure.py | 13 ++++++------- .../polywrap_client_config_builder.py | 3 ++- .../polywrap-client-config-builder/pyproject.toml | 3 ++- 9 files changed, 42 insertions(+), 44 deletions(-) diff --git a/packages/polywrap-client-config-builder/polywrap_client_config_builder/configures/base_configure.py b/packages/polywrap-client-config-builder/polywrap_client_config_builder/configures/base_configure.py index a40fffa3..2cd2109f 100644 --- a/packages/polywrap-client-config-builder/polywrap_client_config_builder/configures/base_configure.py +++ b/packages/polywrap-client-config-builder/polywrap_client_config_builder/configures/base_configure.py @@ -1,8 +1,10 @@ """This module contains the base configure class for the client config builder.""" +from typing import cast + from ..types import BuilderConfig, ClientConfigBuilder -class BaseConfigure(ClientConfigBuilder): +class BaseConfigure: """BaseConfigure is the base configure class for the client config builder.""" config: BuilderConfig @@ -21,4 +23,4 @@ def add(self, config: BuilderConfig) -> ClientConfigBuilder: self.config.wrappers.update(config.wrappers) if config.packages: self.config.packages.update(config.packages) - return self + return cast(ClientConfigBuilder, self) diff --git a/packages/polywrap-client-config-builder/polywrap_client_config_builder/configures/env_configure.py b/packages/polywrap-client-config-builder/polywrap_client_config_builder/configures/env_configure.py index 6157c3c0..dc97a60f 100644 --- a/packages/polywrap-client-config-builder/polywrap_client_config_builder/configures/env_configure.py +++ b/packages/polywrap-client-config-builder/polywrap_client_config_builder/configures/env_configure.py @@ -1,5 +1,4 @@ """This module contains the env configure class for the client config builder.""" -from abc import ABC from typing import Any, Dict, List, Union, cast from polywrap_core import Uri @@ -7,7 +6,7 @@ from ..types import BuilderConfig, ClientConfigBuilder -class EnvConfigure(ClientConfigBuilder, ABC): +class EnvConfigure: """Allows configuring the environment variables.""" config: BuilderConfig @@ -23,12 +22,12 @@ def get_envs(self) -> Dict[Uri, Any]: def set_env(self, uri: Uri, env: Any) -> ClientConfigBuilder: """Set the env by uri in the builder's config, overiding any existing values.""" self.config.envs[uri] = env - return self + return cast(ClientConfigBuilder, self) def set_envs(self, uri_envs: Dict[Uri, Any]) -> ClientConfigBuilder: """Set the envs in the builder's config, overiding any existing values.""" self.config.envs.update(uri_envs) - return self + return cast(ClientConfigBuilder, self) def add_env(self, uri: Uri, env: Any) -> ClientConfigBuilder: """Add an env for the given uri. @@ -40,24 +39,24 @@ def add_env(self, uri: Uri, env: Any) -> ClientConfigBuilder: self.config.envs[uri] = new_env else: self.config.envs[uri] = env - return self + return cast(ClientConfigBuilder, self) def add_envs(self, uri_envs: Dict[Uri, Any]) -> ClientConfigBuilder: """Add a list of envs to the builder's config.""" for uri, env in uri_envs.items(): self.add_env(uri, env) - return self + return cast(ClientConfigBuilder, self) def remove_env(self, uri: Uri) -> ClientConfigBuilder: """Remove the env for the given uri.""" self.config.envs.pop(uri, None) - return self + return cast(ClientConfigBuilder, self) def remove_envs(self, uris: List[Uri]) -> ClientConfigBuilder: """Remove the envs for the given uris.""" for uri in uris: self.remove_env(uri) - return self + return cast(ClientConfigBuilder, self) @staticmethod def _merge_envs(env1: Dict[str, Any], env2: Dict[str, Any]) -> Dict[str, Any]: diff --git a/packages/polywrap-client-config-builder/polywrap_client_config_builder/configures/interface_configure.py b/packages/polywrap-client-config-builder/polywrap_client_config_builder/configures/interface_configure.py index 7fb81ebb..a3087b54 100644 --- a/packages/polywrap-client-config-builder/polywrap_client_config_builder/configures/interface_configure.py +++ b/packages/polywrap-client-config-builder/polywrap_client_config_builder/configures/interface_configure.py @@ -1,13 +1,12 @@ """This module contains the interface configure class for the client config builder.""" -from abc import ABC -from typing import Dict, List, Union +from typing import Dict, List, Union, cast from polywrap_core import Uri from ..types import BuilderConfig, ClientConfigBuilder -class InterfaceConfigure(ClientConfigBuilder, ABC): +class InterfaceConfigure: """Allows configuring the interface-implementations.""" config: BuilderConfig @@ -32,7 +31,7 @@ def add_interface_implementations( self.config.interfaces[interface_uri].append(implementation_uri) else: self.config.interfaces[interface_uri] = implementations_uris - return self + return cast(ClientConfigBuilder, self) def remove_interface_implementations( self, interface_uri: Uri, implementations_uris: List[Uri] @@ -43,9 +42,9 @@ def remove_interface_implementations( for uri in self.config.interfaces[interface_uri] if uri not in implementations_uris ] - return self + return cast(ClientConfigBuilder, self) def remove_interface(self, interface_uri: Uri) -> ClientConfigBuilder: """Remove the interface for the given uri.""" self.config.interfaces.pop(interface_uri, None) - return self + return cast(ClientConfigBuilder, self) diff --git a/packages/polywrap-client-config-builder/polywrap_client_config_builder/configures/package_configure.py b/packages/polywrap-client-config-builder/polywrap_client_config_builder/configures/package_configure.py index e8de2f14..1568538a 100644 --- a/packages/polywrap-client-config-builder/polywrap_client_config_builder/configures/package_configure.py +++ b/packages/polywrap-client-config-builder/polywrap_client_config_builder/configures/package_configure.py @@ -1,13 +1,12 @@ """This module contains the package configure class for the client config builder.""" -from abc import ABC -from typing import Dict, List, Union +from typing import Dict, List, Union, cast from polywrap_core import Uri, WrapPackage from ..types import BuilderConfig, ClientConfigBuilder -class PackageConfigure(ClientConfigBuilder, ABC): +class PackageConfigure: """Allows configuring the WRAP packages.""" config: BuilderConfig @@ -23,20 +22,20 @@ def get_packages(self) -> Dict[Uri, WrapPackage]: def set_package(self, uri: Uri, package: WrapPackage) -> ClientConfigBuilder: """Set the package by uri in the builder's config, overiding any existing values.""" self.config.packages[uri] = package - return self + return cast(ClientConfigBuilder, self) def set_packages(self, uri_packages: Dict[Uri, WrapPackage]) -> ClientConfigBuilder: """Set the packages in the builder's config, overiding any existing values.""" self.config.packages.update(uri_packages) - return self + return cast(ClientConfigBuilder, self) def remove_package(self, uri: Uri) -> ClientConfigBuilder: """Remove the package for the given uri.""" self.config.packages.pop(uri, None) - return self + return cast(ClientConfigBuilder, self) def remove_packages(self, uris: List[Uri]) -> ClientConfigBuilder: """Remove the packages for the given uris.""" for uri in uris: self.remove_package(uri) - return self + return cast(ClientConfigBuilder, self) diff --git a/packages/polywrap-client-config-builder/polywrap_client_config_builder/configures/redirect_configure.py b/packages/polywrap-client-config-builder/polywrap_client_config_builder/configures/redirect_configure.py index 0b2b5aff..dd5f989f 100644 --- a/packages/polywrap-client-config-builder/polywrap_client_config_builder/configures/redirect_configure.py +++ b/packages/polywrap-client-config-builder/polywrap_client_config_builder/configures/redirect_configure.py @@ -1,13 +1,12 @@ """This module contains the redirect configure class for the client config builder.""" -from abc import ABC -from typing import Dict, List, Union +from typing import Dict, List, Union, cast from polywrap_core import Uri from ..types import BuilderConfig, ClientConfigBuilder -class RedirectConfigure(ClientConfigBuilder, ABC): +class RedirectConfigure: """Allows configuring the URI redirects.""" config: BuilderConfig @@ -24,20 +23,20 @@ def set_redirect(self, from_uri: Uri, to_uri: Uri) -> ClientConfigBuilder: """Set the redirect from a URI to another URI in the builder's config,\ overiding any existing values.""" self.config.redirects[from_uri] = to_uri - return self + return cast(ClientConfigBuilder, self) def set_redirects(self, uri_redirects: Dict[Uri, Uri]) -> ClientConfigBuilder: """Set the redirects in the builder's config, overiding any existing values.""" self.config.redirects.update(uri_redirects) - return self + return cast(ClientConfigBuilder, self) def remove_redirect(self, uri: Uri) -> ClientConfigBuilder: """Remove the redirect for the given uri.""" self.config.redirects.pop(uri, None) - return self + return cast(ClientConfigBuilder, self) def remove_redirects(self, uris: List[Uri]) -> ClientConfigBuilder: """Remove the redirects for the given uris.""" for uri in uris: self.remove_redirect(uri) - return self + return cast(ClientConfigBuilder, self) diff --git a/packages/polywrap-client-config-builder/polywrap_client_config_builder/configures/resolver_configure.py b/packages/polywrap-client-config-builder/polywrap_client_config_builder/configures/resolver_configure.py index 8134d81f..9a6401f1 100644 --- a/packages/polywrap-client-config-builder/polywrap_client_config_builder/configures/resolver_configure.py +++ b/packages/polywrap-client-config-builder/polywrap_client_config_builder/configures/resolver_configure.py @@ -1,13 +1,12 @@ """This module contains the resolver configure class for the client config builder.""" -from abc import ABC -from typing import List +from typing import List, cast from polywrap_core import UriResolver from ..types import BuilderConfig, ClientConfigBuilder -class ResolverConfigure(ClientConfigBuilder, ABC): +class ResolverConfigure: """Allows configuring the URI resolvers.""" config: BuilderConfig @@ -19,10 +18,10 @@ def get_resolvers(self) -> List[UriResolver]: def add_resolver(self, resolver: UriResolver) -> ClientConfigBuilder: """Add a resolver to the builder's config.""" self.config.resolvers.append(resolver) - return self + return cast(ClientConfigBuilder, self) def add_resolvers(self, resolvers_list: List[UriResolver]) -> ClientConfigBuilder: """Add a list of resolvers to the builder's config.""" for resolver in resolvers_list: self.add_resolver(resolver) - return self + return cast(ClientConfigBuilder, self) diff --git a/packages/polywrap-client-config-builder/polywrap_client_config_builder/configures/wrapper_configure.py b/packages/polywrap-client-config-builder/polywrap_client_config_builder/configures/wrapper_configure.py index e0572ce8..1abd86c1 100644 --- a/packages/polywrap-client-config-builder/polywrap_client_config_builder/configures/wrapper_configure.py +++ b/packages/polywrap-client-config-builder/polywrap_client_config_builder/configures/wrapper_configure.py @@ -1,13 +1,12 @@ """This module contains the wrapper configure class for the client config builder.""" -from abc import ABC -from typing import Dict, List, Union +from typing import Dict, List, Union, cast from polywrap_core import Uri, Wrapper from ..types import BuilderConfig, ClientConfigBuilder -class WrapperConfigure(ClientConfigBuilder, ABC): +class WrapperConfigure: """Allows configuring the wrappers.""" config: BuilderConfig @@ -23,20 +22,20 @@ def get_wrappers(self) -> Dict[Uri, Wrapper]: def set_wrapper(self, uri: Uri, wrapper: Wrapper) -> ClientConfigBuilder: """Set the wrapper by uri in the builder's config, overiding any existing values.""" self.config.wrappers[uri] = wrapper - return self + return cast(ClientConfigBuilder, self) def set_wrappers(self, uri_wrappers: Dict[Uri, Wrapper]) -> ClientConfigBuilder: """Set the wrappers in the builder's config, overiding any existing values.""" self.config.wrappers.update(uri_wrappers) - return self + return cast(ClientConfigBuilder, self) def remove_wrapper(self, uri: Uri) -> ClientConfigBuilder: """Remove the wrapper for the given uri.""" self.config.wrappers.pop(uri, None) - return self + return cast(ClientConfigBuilder, self) def remove_wrappers(self, uris: List[Uri]) -> ClientConfigBuilder: """Remove the wrappers for the given uris.""" for uri in uris: self.remove_wrapper(uri) - return self + return cast(ClientConfigBuilder, self) diff --git a/packages/polywrap-client-config-builder/polywrap_client_config_builder/polywrap_client_config_builder.py b/packages/polywrap-client-config-builder/polywrap_client_config_builder/polywrap_client_config_builder.py index d08c1f68..edf3bb29 100644 --- a/packages/polywrap-client-config-builder/polywrap_client_config_builder/polywrap_client_config_builder.py +++ b/packages/polywrap-client-config-builder/polywrap_client_config_builder/polywrap_client_config_builder.py @@ -23,7 +23,7 @@ ResolverConfigure, WrapperConfigure, ) -from .types import BuilderConfig, BuildOptions +from .types import BuilderConfig, BuildOptions, ClientConfigBuilder class PolywrapClientConfigBuilder( @@ -34,6 +34,7 @@ class PolywrapClientConfigBuilder( RedirectConfigure, ResolverConfigure, WrapperConfigure, + ClientConfigBuilder, ): """Defines the default polywrap client config builder for\ building a ClientConfig object for the Polywrap Client. diff --git a/packages/polywrap-client-config-builder/pyproject.toml b/packages/polywrap-client-config-builder/pyproject.toml index 96e713b7..c7ada229 100644 --- a/packages/polywrap-client-config-builder/pyproject.toml +++ b/packages/polywrap-client-config-builder/pyproject.toml @@ -45,7 +45,8 @@ testpaths = [ [tool.pylint] disable = [ - "unnecessary-ellipsis" + "unnecessary-ellipsis", + "too-few-public-methods" ] ignore = [ "tests/" From 09dabaacdc64d12c99f482326a21583cef7da9dc Mon Sep 17 00:00:00 2001 From: Niraj Kamdar Date: Wed, 14 Jun 2023 19:11:13 +0530 Subject: [PATCH 44/47] fix: typing issue --- packages/polywrap-core/tests/test_get_implementations.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/polywrap-core/tests/test_get_implementations.py b/packages/polywrap-core/tests/test_get_implementations.py index b8e3cd84..37cb7647 100644 --- a/packages/polywrap-core/tests/test_get_implementations.py +++ b/packages/polywrap-core/tests/test_get_implementations.py @@ -1,9 +1,9 @@ from polywrap_core import ( - Any, Client, Uri, get_implementations, ) +from typing import Any import pytest interface_1 = Uri.from_str("wrap://ens/interface-1.eth") From aa09e71a4d879efe65af82b19ade0823e7d5b6f6 Mon Sep 17 00:00:00 2001 From: Niraj Kamdar Date: Wed, 14 Jun 2023 19:23:29 +0530 Subject: [PATCH 45/47] fix: typing issues in polywrap-uri-resolvers --- .../extensions/extension_wrapper_uri_resolver.py | 2 +- .../resolvers/legacy/fs_resolver.py | 2 +- .../tests/integration/extension_resolver/mocker.py | 11 +++++------ .../resolution_result_cache_resolver/conftest.py | 2 +- 4 files changed, 8 insertions(+), 9 deletions(-) diff --git a/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/resolvers/extensions/extension_wrapper_uri_resolver.py b/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/resolvers/extensions/extension_wrapper_uri_resolver.py index 3cb22b99..54b09854 100644 --- a/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/resolvers/extensions/extension_wrapper_uri_resolver.py +++ b/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/resolvers/extensions/extension_wrapper_uri_resolver.py @@ -158,4 +158,4 @@ def _try_resolve_uri_with_extension( return uri -__all__ = ["ExtensionWrapperUriResolver"] +__all__ = ["ExtensionWrapperUriResolver", "MaybeUriOrManifest"] diff --git a/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/resolvers/legacy/fs_resolver.py b/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/resolvers/legacy/fs_resolver.py index b4ff5922..87c738bb 100644 --- a/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/resolvers/legacy/fs_resolver.py +++ b/packages/polywrap-uri-resolvers/polywrap_uri_resolvers/resolvers/legacy/fs_resolver.py @@ -78,4 +78,4 @@ def try_resolve_uri( ) -__all__ = ["FsUriResolver"] +__all__ = ["FsUriResolver", "SimpleFileReader"] diff --git a/packages/polywrap-uri-resolvers/tests/integration/extension_resolver/mocker.py b/packages/polywrap-uri-resolvers/tests/integration/extension_resolver/mocker.py index 6108f930..62b39297 100644 --- a/packages/polywrap-uri-resolvers/tests/integration/extension_resolver/mocker.py +++ b/packages/polywrap-uri-resolvers/tests/integration/extension_resolver/mocker.py @@ -1,13 +1,12 @@ import os -from typing import Dict, Optional -from polywrap_core import Any, InvokerClient, Uri, UriPackage +from typing import Any, Dict, Optional +from polywrap_core import InvokerClient, Uri, UriPackage from polywrap_plugin import PluginModule, PluginPackage -from polywrap_uri_resolvers import ( - MaybeUriOrManifest, - WasmPackage, -) from polywrap_test_cases import get_path_to_test_wrappers +from polywrap_uri_resolvers import MaybeUriOrManifest +from polywrap_wasm import WasmPackage + class MockPluginExtensionResolver(PluginModule[None]): URI = Uri.from_str("wrap://package/test-resolver") diff --git a/packages/polywrap-uri-resolvers/tests/integration/resolution_result_cache_resolver/conftest.py b/packages/polywrap-uri-resolvers/tests/integration/resolution_result_cache_resolver/conftest.py index 1ceebe11..cb436ee7 100644 --- a/packages/polywrap-uri-resolvers/tests/integration/resolution_result_cache_resolver/conftest.py +++ b/packages/polywrap-uri-resolvers/tests/integration/resolution_result_cache_resolver/conftest.py @@ -8,13 +8,13 @@ UriResolutionStep, UriWrapper, UriPackage, + UriResolver, ) from polywrap_client import PolywrapClient from polywrap_uri_resolvers import ( RecursiveResolver, ResolutionResultCacheResolver, UriResolutionError, - UriResolver, InMemoryResolutionResultCache, ) From cb79ccf87b9fb3deb5f1e52d3651332d84fa0cd9 Mon Sep 17 00:00:00 2001 From: Niraj Kamdar Date: Wed, 14 Jun 2023 23:01:57 +0530 Subject: [PATCH 46/47] feat: add errors in the docstring --- .../polywrap-client/polywrap_client/client.py | 17 ++++++++++++++ .../utils/get_implementations.py | 3 +++ .../polywrap-plugin/polywrap_plugin/module.py | 6 +++++ .../resolution_context_override_client.py | 6 +++++ .../polywrap_plugin/wrapper.py | 9 ++++++++ .../polywrap_wasm/wasm_package.py | 23 ++++++++++++++++++- .../polywrap_wasm/wasm_wrapper.py | 4 ++++ 7 files changed, 67 insertions(+), 1 deletion(-) diff --git a/packages/polywrap-client/polywrap_client/client.py b/packages/polywrap-client/polywrap_client/client.py index edc95400..8e26cf48 100644 --- a/packages/polywrap-client/polywrap_client/client.py +++ b/packages/polywrap-client/polywrap_client/client.py @@ -86,6 +86,9 @@ def get_implementations( Returns: Optional[List[Uri]]: List of implementations or None if not found. + + Raises: + WrapGetImplementationsError: If the URI cannot be resolved. """ interfaces: Dict[Uri, List[Uri]] = self.get_interfaces() if not apply_resolution: @@ -147,6 +150,9 @@ def try_resolve_uri( Returns: UriPackageOrWrapper: The resolved URI, package or wrapper. + + Raises: + UriResolutionError: If the URI cannot be resolved. """ uri_resolver = self._config.resolver resolution_context = resolution_context or UriResolutionContext() @@ -167,6 +173,10 @@ def load_wrapper( Returns: Wrapper: initialized wrapper instance. + + Raises: + UriResolutionError: If the URI cannot be resolved. + RuntimeError: If the URI cannot be resolved. """ resolution_context = resolution_context or UriResolutionContext() @@ -218,6 +228,13 @@ def invoke( Returns: Any: The result of the invocation. + + Raises: + RuntimeError: If the URI cannot be resolved. + MsgpackError: If the data cannot be encoded/decoded. + ManifestError: If the manifest is invalid. + WrapError: If something went wrong during the invocation. + UriResolutionError: If the URI cannot be resolved. """ resolution_context = resolution_context or UriResolutionContext() load_wrapper_context = resolution_context.create_sub_history_context() diff --git a/packages/polywrap-core/polywrap_core/utils/get_implementations.py b/packages/polywrap-core/polywrap_core/utils/get_implementations.py index 4f35d9e6..0f8a7544 100644 --- a/packages/polywrap-core/polywrap_core/utils/get_implementations.py +++ b/packages/polywrap-core/polywrap_core/utils/get_implementations.py @@ -32,6 +32,9 @@ def get_implementations( client (Optional[InvokerClient]): The client to use for resolving the URI. resolution_context (Optional[UriResolutionContext]): The resolution context to use. + Raises: + WrapGetImplementationsError: If the URI cannot be resolved. + Returns: Optional[List[Uri]]: List of implementations or None if not found. """ diff --git a/packages/polywrap-plugin/polywrap_plugin/module.py b/packages/polywrap-plugin/polywrap_plugin/module.py index 0708058a..4af8484b 100644 --- a/packages/polywrap-plugin/polywrap_plugin/module.py +++ b/packages/polywrap-plugin/polywrap_plugin/module.py @@ -65,6 +65,12 @@ def __wrap_invoke__( Returns: The result of the plugin method invocation. + + Raises: + WrapInvocationError: If the plugin method is not defined\ + or is not callable. + WrapAbortError: If the plugin method raises an exception. + MsgpackDecodeError: If the plugin method returns invalid msgpack. """ if not hasattr(self, options.method): raise WrapInvocationError( diff --git a/packages/polywrap-plugin/polywrap_plugin/resolution_context_override_client.py b/packages/polywrap-plugin/polywrap_plugin/resolution_context_override_client.py index 356d7310..53456685 100644 --- a/packages/polywrap-plugin/polywrap_plugin/resolution_context_override_client.py +++ b/packages/polywrap-plugin/polywrap_plugin/resolution_context_override_client.py @@ -46,6 +46,12 @@ def invoke( Returns: Any: invocation result. + + Raises: + WrapInvocationError: If the plugin method is not defined\ + or is not callable. + WrapAbortError: If the plugin method raises an exception. + MsgpackDecodeError: If the plugin method returns invalid msgpack. """ return self.client.invoke( uri, diff --git a/packages/polywrap-plugin/polywrap_plugin/wrapper.py b/packages/polywrap-plugin/polywrap_plugin/wrapper.py index eac2115b..d8b9dd9d 100644 --- a/packages/polywrap-plugin/polywrap_plugin/wrapper.py +++ b/packages/polywrap-plugin/polywrap_plugin/wrapper.py @@ -59,6 +59,12 @@ def invoke( Returns: InvocableResult: Result of the invocation. + + Raises: + WrapInvocationError: If the plugin method is not defined\ + or is not callable. + WrapAbortError: If the plugin method raises an exception. + MsgpackDecodeError: If the plugin method returns invalid msgpack. """ options = PluginInvokeOptions( uri=uri, @@ -84,6 +90,9 @@ def get_file( Returns: Union[str, bytes]: The file contents + + Raises: + NotImplementedError: This method is not implemented for plugins. """ raise NotImplementedError("client.get_file(..) is not implemented for plugins") diff --git a/packages/polywrap-wasm/polywrap_wasm/wasm_package.py b/packages/polywrap-wasm/polywrap_wasm/wasm_package.py index 02594155..11d7cf0d 100644 --- a/packages/polywrap-wasm/polywrap_wasm/wasm_package.py +++ b/packages/polywrap-wasm/polywrap_wasm/wasm_package.py @@ -52,6 +52,14 @@ def get_manifest( Args: options (Optional[DeserializeManifestOptions]): The options\ to use when getting the manifest. + + Returns: + AnyWrapManifest: The manifest of the wrapper. + + Raises: + OSError: If the manifest file could not be read due to system errors. + MsgpackDecodeError: If the encoded manifest fails to decode. + ManifestError: If the manifest is not valid. """ if isinstance(self.manifest, AnyWrapManifest): return self.manifest @@ -65,6 +73,9 @@ def get_manifest( def get_wasm_module(self) -> bytes: """Get the Wasm module of the wrapper if it exists or return an error. + Raises: + OSError: If the wasm module file could not be read due to system errors. + Returns: The Wasm module of the wrapper or an error. """ @@ -76,7 +87,17 @@ def get_wasm_module(self) -> bytes: return self.wasm_module def create_wrapper(self) -> Wrapper: - """Create a new WasmWrapper instance.""" + """Create a new WasmWrapper instance. + + Returns: + WasmWrapper: The Wasm wrapper instance. + + Raises: + OSError: If the wasm module or manifest could not be read\ + due to system errors. + MsgpackDecodeError: If the encoded manifest fails to decode. + ManifestError: If the manifest is not valid. + """ wasm_module = self.get_wasm_module() wasm_manifest = self.get_manifest() diff --git a/packages/polywrap-wasm/polywrap_wasm/wasm_wrapper.py b/packages/polywrap-wasm/polywrap_wasm/wasm_wrapper.py index 8e585f5f..a886673d 100644 --- a/packages/polywrap-wasm/polywrap_wasm/wasm_wrapper.py +++ b/packages/polywrap-wasm/polywrap_wasm/wasm_wrapper.py @@ -106,6 +106,10 @@ def invoke( The URI resolution context to use during invocation. client (Optional[Invoker]): The invoker to use during invocation. + Raises: + WrapError: If the invocation uri or method are not defined. + MsgpackError: If failed to encode/decode data to/from msgpack. + Returns: The result of the invocation or an error. """ From f3fd32d18d55214c57ed2f49cbeed4d4af422d26 Mon Sep 17 00:00:00 2001 From: Niraj Kamdar Date: Wed, 14 Jun 2023 23:23:07 +0530 Subject: [PATCH 47/47] chore: remove the unnecessary files --- packages/polywrap-client/tests/test_plugin_wrapper.py | 1 - packages/polywrap-client/tests/test_wasm_wrapper.py | 0 2 files changed, 1 deletion(-) delete mode 100644 packages/polywrap-client/tests/test_plugin_wrapper.py delete mode 100644 packages/polywrap-client/tests/test_wasm_wrapper.py diff --git a/packages/polywrap-client/tests/test_plugin_wrapper.py b/packages/polywrap-client/tests/test_plugin_wrapper.py deleted file mode 100644 index 9906e2b8..00000000 --- a/packages/polywrap-client/tests/test_plugin_wrapper.py +++ /dev/null @@ -1 +0,0 @@ -# Encode - Decode need to be tested \ No newline at end of file diff --git a/packages/polywrap-client/tests/test_wasm_wrapper.py b/packages/polywrap-client/tests/test_wasm_wrapper.py deleted file mode 100644 index e69de29b..00000000