Skip to content

interoperability with asyncio (part 3): refactor with aiohttp #176

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 35 commits into from
Jun 20, 2024
Merged
Changes from 1 commit
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
4a34c1c
aiohttp: refactor internals to use asyncio throughout the SDK
achille-roussel Jun 7, 2024
935ffdc
all tests pass using new APIs
achille-roussel Jun 11, 2024
42810bc
port http tests to generic dispatch test suite
achille-roussel Jun 12, 2024
731d96d
fix slow FastAPI tests
achille-roussel Jun 12, 2024
69e05bc
port some of the tests from TestCoroutine to TestCase + fix bugs
achille-roussel Jun 12, 2024
a674f07
fix compatibility with Python 3.8
achille-roussel Jun 12, 2024
8dfc03a
fix for Python 3.8: asyncio.Task is not a generic type
achille-roussel Jun 12, 2024
529823d
refactor: use composition, default registry, function service
achille-roussel Jun 14, 2024
6bfb086
remove unused variables
achille-roussel Jun 14, 2024
ecb9d33
enable nested function call test
achille-roussel Jun 14, 2024
d9e73d4
fix formatting check for registry endpoint
achille-roussel Jun 14, 2024
b894337
fix PrimitiveFunction.__call__, the method cannot be async
achille-roussel Jun 14, 2024
b4e2db4
more fixes after rebase
achille-roussel Jun 14, 2024
3d0b0bb
cleanup
achille-roussel Jun 15, 2024
f0a54e2
cleanup
achille-roussel Jun 15, 2024
60c2312
try fixing compat with 3.8
achille-roussel Jun 17, 2024
c053298
fix python version check
achille-roussel Jun 17, 2024
d6fa555
emulate wait capability
achille-roussel Jun 17, 2024
ccc4ab8
rewrite examples to use dispatch.run
achille-roussel Jun 17, 2024
2803551
fix emulation of call results (don't end on temporary errors)
achille-roussel Jun 17, 2024
0c186a3
handle client connection errors
achille-roussel Jun 17, 2024
6799ab3
fix formatting
achille-roussel Jun 17, 2024
a406d2a
remove type annotations from examples so they are compatible with Pyt…
achille-roussel Jun 17, 2024
d5f5848
use context varaibles instead of thread locals
achille-roussel Jun 18, 2024
0918918
update README
achille-roussel Jun 18, 2024
d016221
fix running examples as tests
achille-roussel Jun 18, 2024
cf363d0
switch pytest.mark.asyncio position because maybe that's why the test…
achille-roussel Jun 18, 2024
debe5d8
fix tests for Python 3.9
achille-roussel Jun 18, 2024
8487159
fix formatting
achille-roussel Jun 18, 2024
672b1a1
re-enable the batch API
achille-roussel Jun 18, 2024
fea85a8
remove unused files
achille-roussel Jun 18, 2024
8394ee5
fix formatting
achille-roussel Jun 18, 2024
d448489
add documentation
achille-roussel Jun 18, 2024
e340938
support both asyncio and blocking modes with different abstractions
achille-roussel Jun 18, 2024
41c6ad3
Merge pull request #178 from dispatchrun/asyncio-or-blocking
achille-roussel Jun 19, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
fix PrimitiveFunction.__call__, the method cannot be async
Signed-off-by: Achille Roussel <achille.roussel@gmail.com>
  • Loading branch information
achille-roussel committed Jun 14, 2024
commit b894337c0d4a1195bb46e1c087442a76d9818ca7
29 changes: 21 additions & 8 deletions src/dispatch/function.py
Original file line number Diff line number Diff line change
@@ -132,17 +132,30 @@ def __init__(
async def _call_async(self, *args: P.args, **kwargs: P.kwargs) -> T:
return await dispatch.coroutine.call(self.build_call(*args, **kwargs))

async def __call__(self, *args: P.args, **kwargs: P.kwargs) -> T:
async def _call_dispatch(self, *args: P.args, **kwargs: P.kwargs) -> T:
call = self.build_call(*args, **kwargs)
client = self.registry.client
[dispatch_id] = await client.dispatch([call])
return await client.wait(dispatch_id)

def __call__(self, *args: P.args, **kwargs: P.kwargs) -> Coroutine[Any, Any, T]:
"""Call the function asynchronously (through Dispatch), and return a
coroutine that can be awaited to retrieve the call result."""
# Note: this method cannot be made `async`, otherwise Python creates
# ont additional wrapping layer of native coroutine that cannot be
# pickled and breaks serialization.
#
# The durable coroutine returned by calling _func_indirect must be
# returned as is.
#
# For cases where this method is called outside the context of a
# dispatch function, it still returns a native coroutine object,
# but that doesn't matter since there is no state serialization in
# that case.
if in_function_call():
return await self._func_indirect(*args, **kwargs)

call = self.build_call(*args, **kwargs)

[dispatch_id] = await self.registry.client.dispatch([call])

return await self.registry.client.wait(dispatch_id)
return self._func_indirect(*args, **kwargs)
else:
return self._call_dispatch(*args, **kwargs)

def dispatch(self, *args: P.args, **kwargs: P.kwargs) -> DispatchID:
"""Dispatch an asynchronous call to the function without
37 changes: 11 additions & 26 deletions src/dispatch/test/__init__.py
Original file line number Diff line number Diff line change
@@ -348,7 +348,7 @@ def echo(name: str) -> str:


@_registry.function
async def echo2(name: str) -> str:
async def echo_nested(name: str) -> str:
return await echo(name)


@@ -362,6 +362,11 @@ def broken() -> str:
raise ValueError("something went wrong!")


@_registry.function
async def broken_nested(name: str) -> str:
return await broken()


set_default_registry(_registry)


@@ -481,34 +486,14 @@ async def test_call_two_functions(self):
self.assertEqual(await echo("hello"), "hello")
self.assertEqual(await length("hello"), 5)

# TODO:
#
# The declaration of nested functions in these tests causes CPython to
# generate cell objects since the local variables are referenced by multiple
# scopes.
#
# Maybe time to revisit https://github.com/dispatchrun/dispatch-py/pull/121
#
# Alternatively, we could rewrite the test suite to use a global registry
# where we register each function once in the globla scope, so no cells need
# to be created.

@aiotest
async def test_call_nested_function_with_result(self):
self.assertEqual(await echo2("hello"), "hello")
self.assertEqual(await echo_nested("hello"), "hello")

# @aiotest
# async def test_call_nested_function_with_error(self):
# @self.dispatch.function
# def broken_function(name: str) -> str:
# raise ValueError("something went wrong!")

# @self.dispatch.function
# async def working_function(name: str) -> str:
# return await broken_function(name)

# with self.assertRaises(ValueError) as e:
# await working_function("hello")
@aiotest
async def test_call_nested_function_with_error(self):
with self.assertRaises(ValueError) as e:
await broken_nested("hello")


class ClientRequestContentLengthMissing(aiohttp.ClientRequest):