Skip to content

Commit a5066d8

Browse files
committed
refactor polywrap-client and fix tests
1 parent 0671ddf commit a5066d8

81 files changed

Lines changed: 1140 additions & 2938 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

packages/polywrap-client/poetry.lock

Lines changed: 862 additions & 750 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

packages/polywrap-client/polywrap_client/client.py

Lines changed: 42 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -13,19 +13,17 @@
1313
GetManifestOptions,
1414
InvokerOptions,
1515
IUriResolutionContext,
16-
IUriResolver,
17-
IWrapPackage,
16+
UriPackage,
17+
UriResolver,
18+
UriWrapper,
1819
TryResolveUriOptions,
1920
Uri,
2021
UriPackageOrWrapper,
21-
UriResolutionContext,
2222
Wrapper,
23-
build_clean_uri_history,
2423
)
2524
from polywrap_manifest import AnyWrapManifest
2625
from polywrap_msgpack import msgpack_decode, msgpack_encode
27-
from polywrap_result import Err, Ok, Result
28-
from polywrap_uri_resolvers import FsUriResolver, SimpleFileReader
26+
from polywrap_uri_resolvers import UriResolutionContext, build_clean_uri_history
2927

3028

3129
@dataclass(slots=True, kw_only=True)
@@ -36,16 +34,13 @@ class PolywrapClientConfig(ClientConfig):
3634
class PolywrapClient(Client):
3735
_config: PolywrapClientConfig
3836

39-
def __init__(self, config: Optional[PolywrapClientConfig] = None):
40-
# TODO: this is naive solution need to use polywrap-client-config-builder once we have it
41-
self._config = config or PolywrapClientConfig(
42-
resolver=FsUriResolver(file_reader=SimpleFileReader())
43-
)
37+
def __init__(self, config: PolywrapClientConfig):
38+
self._config = config
4439

4540
def get_config(self):
4641
return self._config
4742

48-
def get_uri_resolver(self) -> IUriResolver:
43+
def get_uri_resolver(self) -> UriResolver:
4944
return self._config.resolver
5045

5146
def get_envs(self) -> Dict[Uri, Env]:
@@ -56,100 +51,81 @@ def get_interfaces(self) -> Dict[Uri, List[Uri]]:
5651
interfaces: Dict[Uri, List[Uri]] = self._config.interfaces
5752
return interfaces
5853

59-
def get_implementations(self, uri: Uri) -> Result[Union[List[Uri], None]]:
54+
def get_implementations(self, uri: Uri) -> Union[List[Uri], None]:
6055
interfaces: Dict[Uri, List[Uri]] = self.get_interfaces()
61-
if interfaces.get(uri):
62-
return Ok(interfaces.get(uri))
63-
else:
64-
return Err.from_str(f"Unable to find implementations for uri: {uri}")
56+
return interfaces.get(uri)
6557

6658
def get_env_by_uri(self, uri: Uri) -> Union[Env, None]:
6759
return self._config.envs.get(uri)
6860

69-
async def get_file(
70-
self, uri: Uri, options: GetFileOptions
71-
) -> Result[Union[bytes, str]]:
72-
loaded_wrapper = (await self.load_wrapper(uri)).unwrap()
61+
async def get_file(self, uri: Uri, options: GetFileOptions) -> Union[bytes, str]:
62+
loaded_wrapper = await self.load_wrapper(uri)
7363
return await loaded_wrapper.get_file(options)
7464

7565
async def get_manifest(
7666
self, uri: Uri, options: Optional[GetManifestOptions] = None
77-
) -> Result[AnyWrapManifest]:
78-
loaded_wrapper = (await self.load_wrapper(uri)).unwrap()
67+
) -> AnyWrapManifest:
68+
loaded_wrapper = await self.load_wrapper(uri)
7969
return loaded_wrapper.get_manifest()
8070

8171
async def try_resolve_uri(
82-
self, options: TryResolveUriOptions
83-
) -> Result[UriPackageOrWrapper]:
72+
self, options: TryResolveUriOptions[UriPackageOrWrapper]
73+
) -> UriPackageOrWrapper:
8474
uri = options.uri
8575
uri_resolver = self._config.resolver
8676
resolution_context = options.resolution_context or UriResolutionContext()
8777

8878
return await uri_resolver.try_resolve_uri(uri, self, resolution_context)
8979

9080
async def load_wrapper(
91-
self, uri: Uri, resolution_context: Optional[IUriResolutionContext] = None
92-
) -> Result[Wrapper]:
81+
self,
82+
uri: Uri,
83+
resolution_context: Optional[IUriResolutionContext[UriPackageOrWrapper]] = None,
84+
) -> Wrapper[UriPackageOrWrapper]:
9385
resolution_context = resolution_context or UriResolutionContext()
9486

95-
result = await self.try_resolve_uri(
87+
uri_package_or_wrapper = await self.try_resolve_uri(
9688
TryResolveUriOptions(uri=uri, resolution_context=resolution_context)
9789
)
98-
if result.is_err():
99-
return cast(Err, result)
100-
if result.is_ok() and result.ok() is None:
101-
return Err.from_str(
102-
dedent(
103-
f"""
104-
Error resolving URI "{uri.uri}"
105-
Resolution Stack: {json.dumps(build_clean_uri_history(resolution_context.get_history()), indent=2)}
106-
"""
107-
)
108-
)
10990

110-
uri_package_or_wrapper = result.unwrap()
111-
112-
if isinstance(uri_package_or_wrapper, Uri):
113-
return Err.from_str(
114-
dedent(
115-
f"""
116-
Error resolving URI "{uri.uri}"
117-
URI not found
118-
Resolution Stack: {json.dumps(build_clean_uri_history(resolution_context.get_history()), indent=2)}
119-
"""
120-
)
91+
if isinstance(uri_package_or_wrapper, UriPackage):
92+
return await cast(
93+
UriPackage[UriPackageOrWrapper], uri_package_or_wrapper
94+
).package.create_wrapper()
95+
96+
if isinstance(uri_package_or_wrapper, UriWrapper):
97+
return cast(UriWrapper[UriPackageOrWrapper], uri_package_or_wrapper).wrapper
98+
99+
raise RuntimeError(
100+
dedent(
101+
f"""
102+
Error resolving URI "{uri.uri}"
103+
URI not found
104+
Resolution Stack: {json.dumps(build_clean_uri_history(resolution_context.get_history()), indent=2)}
105+
"""
121106
)
107+
)
122108

123-
if isinstance(uri_package_or_wrapper, IWrapPackage):
124-
return await uri_package_or_wrapper.create_wrapper()
125-
126-
return Ok(uri_package_or_wrapper)
127109

128-
async def invoke(self, options: InvokerOptions) -> Result[Any]:
110+
async def invoke(self, options: InvokerOptions[UriPackageOrWrapper]) -> Any:
129111
resolution_context = options.resolution_context or UriResolutionContext()
130-
wrapper_result = await self.load_wrapper(
112+
wrapper = await self.load_wrapper(
131113
options.uri, resolution_context=resolution_context
132114
)
133-
if wrapper_result.is_err():
134-
return cast(Err, wrapper_result)
135-
wrapper = wrapper_result.unwrap()
136115
options.env = options.env or self.get_env_by_uri(options.uri)
137116

138-
result = await wrapper.invoke(options, invoker=self)
139-
if result.is_err():
140-
return cast(Err, result)
141-
invocable_result = result.unwrap()
117+
invocable_result = await wrapper.invoke(options, invoker=self)
142118

143119
if options.encode_result and not invocable_result.encoded:
144120
encoded = msgpack_encode(invocable_result.result)
145-
return Ok(encoded)
121+
return encoded
146122

147123
if (
148124
not options.encode_result
149125
and invocable_result.encoded
150126
and isinstance(invocable_result.result, (bytes, bytearray))
151127
):
152128
decoded: Any = msgpack_decode(invocable_result.result)
153-
return Ok(decoded)
129+
return decoded
154130

155-
return Ok(invocable_result.result)
131+
return invocable_result.result

packages/polywrap-client/polywrap_client/py.typed

Whitespace-only changes.

packages/polywrap-client/pyproject.toml

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,16 +11,10 @@ readme = "README.md"
1111

1212
[tool.poetry.dependencies]
1313
python = "^3.10"
14-
wasmtime = "^1.0.1"
15-
unsync = "^1.4.0"
1614
polywrap-core = { path = "../polywrap-core", develop = true }
1715
polywrap-msgpack = { path = "../polywrap-msgpack", develop = true }
1816
polywrap-manifest = { path = "../polywrap-manifest", develop = true }
19-
polywrap-result = { path = "../polywrap-result", develop = true }
2017
polywrap-uri-resolvers = { path = "../polywrap-uri-resolvers", develop = true }
21-
result = "^0.8.0"
22-
pysha3 = "^1.0.2"
23-
pycryptodome = "^3.14.1"
2418

2519
[tool.poetry.dev-dependencies]
2620
pytest = "^7.1.2"
@@ -34,6 +28,10 @@ isort = "^5.10.1"
3428
pyright = "^1.1.275"
3529
pydocstyle = "^6.1.1"
3630

31+
[tool.poetry.group.test.dependencies]
32+
pysha3 = "^1.0.2"
33+
pycryptodome = "^3.17"
34+
3735
[tool.bandit]
3836
exclude_dirs = ["tests"]
3937

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
2+
from pathlib import Path
3+
from polywrap_core import FileReader
4+
from polywrap_uri_resolvers import WRAP_MANIFEST_PATH, WRAP_MODULE_PATH, FsUriResolver, SimpleFileReader
5+
from polywrap_client import PolywrapClient, PolywrapClientConfig
6+
from pytest import fixture
7+
8+
9+
@fixture
10+
def client():
11+
config = PolywrapClientConfig(
12+
resolver=FsUriResolver(file_reader=SimpleFileReader())
13+
)
14+
return PolywrapClient(config)
15+
16+
@fixture
17+
def simple_wrap_module():
18+
wrap_path = Path(__file__).parent / "cases" / "simple-invoke" / "wrap.wasm"
19+
with open(wrap_path, "rb") as f:
20+
yield f.read()
21+
22+
23+
@fixture
24+
def simple_wrap_manifest():
25+
wrap_path = Path(__file__).parent / "cases" / "simple-invoke" / "wrap.info"
26+
with open(wrap_path, "rb") as f:
27+
yield f.read()
28+
29+
@fixture
30+
def simple_file_reader(simple_wrap_module: bytes, simple_wrap_manifest: bytes):
31+
class SimpleFileReader(FileReader):
32+
async def read_file(self, file_path: str) -> bytes:
33+
if file_path == WRAP_MODULE_PATH:
34+
return simple_wrap_module
35+
if file_path == WRAP_MANIFEST_PATH:
36+
return simple_wrap_manifest
37+
raise FileNotFoundError(f"FileNotFound: {file_path}")
38+
39+
yield SimpleFileReader()

packages/polywrap-client/tests/test_bignumber.py

Lines changed: 41 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -3,54 +3,69 @@
33

44
from pathlib import Path
55
from polywrap_client import PolywrapClient
6-
from polywrap_core import Uri, InvokerOptions
6+
from polywrap_core import Uri, InvokerOptions, UriPackageOrWrapper
77

88

9-
async def test_invoke_bignumber_1arg_and_1prop():
10-
client = PolywrapClient()
11-
uri = Uri(f'fs/{Path(__file__).parent.joinpath("cases", "big-number").absolute()}')
9+
async def test_invoke_bignumber_1arg_and_1prop(client: PolywrapClient):
10+
uri = Uri.from_str(
11+
f'fs/{Path(__file__).parent.joinpath("cases", "big-number").absolute()}'
12+
)
1213
args = {
1314
"arg1": "123", # The base number
1415
"obj": {
1516
"prop1": "1000", # multiply the base number by this factor
1617
},
1718
}
18-
options = InvokerOptions(uri=uri, method="method", args=args, encode_result=False)
19+
options: InvokerOptions[UriPackageOrWrapper] = InvokerOptions(
20+
uri=uri, method="method", args=args, encode_result=False
21+
)
1922
result = await client.invoke(options)
20-
assert result.unwrap() == "123000"
23+
assert result == "123000"
2124

2225

23-
async def test_invoke_bignumber_with_1arg_and_2props():
24-
client = PolywrapClient()
25-
uri = Uri(f'fs/{Path(__file__).parent.joinpath("cases", "big-number").absolute()}')
26+
async def test_invoke_bignumber_with_1arg_and_2props(client: PolywrapClient):
27+
uri = Uri.from_str(
28+
f'fs/{Path(__file__).parent.joinpath("cases", "big-number").absolute()}'
29+
)
2630
args = {"arg1": "123123", "obj": {"prop1": "1000", "prop2": "4"}}
27-
options = InvokerOptions(uri=uri, method="method", args=args, encode_result=False)
31+
options: InvokerOptions[UriPackageOrWrapper] = InvokerOptions(
32+
uri=uri, method="method", args=args, encode_result=False
33+
)
2834
result = await client.invoke(options)
29-
assert result.unwrap() == str(123123 * 1000 * 4)
35+
assert result == str(123123 * 1000 * 4)
3036

3137

32-
async def test_invoke_bignumber_with_2args_and_1prop():
33-
client = PolywrapClient()
34-
uri = Uri(f'fs/{Path(__file__).parent.joinpath("cases", "big-number").absolute()}')
38+
async def test_invoke_bignumber_with_2args_and_1prop(client: PolywrapClient):
39+
uri = Uri.from_str(
40+
f'fs/{Path(__file__).parent.joinpath("cases", "big-number").absolute()}'
41+
)
3542
args = {"arg1": "123123", "obj": {"prop1": "1000", "prop2": "444"}}
36-
options = InvokerOptions(uri=uri, method="method", args=args, encode_result=False)
43+
options: InvokerOptions[UriPackageOrWrapper] = InvokerOptions(
44+
uri=uri, method="method", args=args, encode_result=False
45+
)
3746
result = await client.invoke(options)
38-
assert result.unwrap() == str(123123 * 1000 * 444)
47+
assert result == str(123123 * 1000 * 444)
3948

4049

41-
async def test_invoke_bignumber_with_2args_and_2props():
42-
client = PolywrapClient()
43-
uri = Uri(f'fs/{Path(__file__).parent.joinpath("cases", "big-number").absolute()}')
50+
async def test_invoke_bignumber_with_2args_and_2props(client: PolywrapClient):
51+
uri = Uri.from_str(
52+
f'fs/{Path(__file__).parent.joinpath("cases", "big-number").absolute()}'
53+
)
4454
args = {"arg1": "123123", "arg2": "555", "obj": {"prop1": "1000", "prop2": "4"}}
45-
options = InvokerOptions(uri=uri, method="method", args=args, encode_result=False)
55+
options: InvokerOptions[UriPackageOrWrapper] = InvokerOptions(
56+
uri=uri, method="method", args=args, encode_result=False
57+
)
4658
result = await client.invoke(options)
47-
assert result.unwrap() == str(123123 * 555 * 1000 * 4)
59+
assert result == str(123123 * 555 * 1000 * 4)
4860

4961

50-
async def test_invoke_bignumber_with_2args_and_2props_floats():
51-
client = PolywrapClient()
52-
uri = Uri(f'fs/{Path(__file__).parent.joinpath("cases", "big-number").absolute()}')
62+
async def test_invoke_bignumber_with_2args_and_2props_floats(client: PolywrapClient):
63+
uri = Uri.from_str(
64+
f'fs/{Path(__file__).parent.joinpath("cases", "big-number").absolute()}'
65+
)
5366
args = {"arg1": "123.123", "arg2": "55.5", "obj": {"prop1": "10.001", "prop2": "4"}}
54-
options = InvokerOptions(uri=uri, method="method", args=args, encode_result=False)
67+
options: InvokerOptions[UriPackageOrWrapper] = InvokerOptions(
68+
uri=uri, method="method", args=args, encode_result=False
69+
)
5570
result = await client.invoke(options)
56-
assert result.unwrap() == str(123.123 * 55.5 * 10.001 * 4)
71+
assert result == str(123.123 * 55.5 * 10.001 * 4)

0 commit comments

Comments
 (0)