From 2973d7f1de4922a051f03a7dd978cb94f57284a3 Mon Sep 17 00:00:00 2001 From: Tyler Goodlet Date: Fri, 21 Sep 2018 00:31:30 -0400 Subject: [PATCH 1/3] Await async funcs properly in `LocalPortal.run()` --- tractor/_actor.py | 2 +- tractor/_portal.py | 7 ++++++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/tractor/_actor.py b/tractor/_actor.py index c9daa81..2e08b12 100644 --- a/tractor/_actor.py +++ b/tractor/_actor.py @@ -768,7 +768,7 @@ async def wait_for_actor( ) -> typing.AsyncGenerator[Portal, None]: """Wait on an actor to register with the arbiter. - A portal to the first actor which registered is be returned. + A portal to the first registered actor is returned. """ actor = current_actor() async with get_arbiter(*arbiter_sockaddr or actor._arb_addr) as arb_portal: diff --git a/tractor/_portal.py b/tractor/_portal.py index f8a01ac..6eaab31 100644 --- a/tractor/_portal.py +++ b/tractor/_portal.py @@ -2,6 +2,7 @@ Portal api """ import importlib +import inspect import typing from typing import Tuple, Any, Dict, Optional @@ -220,7 +221,11 @@ class LocalPortal: """Run a requested function locally and return it's result. """ obj = self.actor if ns == 'self' else importlib.import_module(ns) - return getattr(obj, func)(**kwargs) + func = getattr(obj, func) + if inspect.iscoroutinefunction(func): + return await func(**kwargs) + else: + return func(**kwargs) @asynccontextmanager From 034146f2b1abf59429cf8d6532c8111cbf7a1b93 Mon Sep 17 00:00:00 2001 From: Tyler Goodlet Date: Fri, 21 Sep 2018 00:32:23 -0400 Subject: [PATCH 2/3] Verify arbiter self registration --- tests/test_local.py | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/tests/test_local.py b/tests/test_local.py index 3f41301..2f9e5ee 100644 --- a/tests/test_local.py +++ b/tests/test_local.py @@ -31,6 +31,26 @@ def test_no_main(): tractor.run(None) +@tractor_test +async def test_self_is_registered(): + "Verify waiting on the arbiter to register itself using the standard api." + actor = tractor.current_actor() + assert actor.is_arbiter + async with tractor.wait_for_actor('arbiter') as portal: + assert portal.channel.uid[0] == 'arbiter' + + +@tractor_test +async def test_self_is_registered_localportal(arb_addr): + "Verify waiting on the arbiter to register itself using a local portal." + actor = tractor.current_actor() + assert actor.is_arbiter + async with tractor.get_arbiter(*arb_addr) as portal: + assert isinstance(portal, tractor._portal.LocalPortal) + sockaddr = await portal.run('self', 'wait_for_actor', name='arbiter') + assert sockaddr[0] == arb_addr + + def test_local_actor_async_func(arb_addr): """Verify a simple async function in-process. """ From 109b5971ed82b291f8d7cef8c84b45c36ce64d31 Mon Sep 17 00:00:00 2001 From: Tyler Goodlet Date: Fri, 21 Sep 2018 09:46:01 -0400 Subject: [PATCH 3/3] Don't overload `func` arg --- tractor/_portal.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tractor/_portal.py b/tractor/_portal.py index 6eaab31..9dc0cba 100644 --- a/tractor/_portal.py +++ b/tractor/_portal.py @@ -217,11 +217,11 @@ class LocalPortal: ) -> None: self.actor = actor - async def run(self, ns: str, func: str, **kwargs) -> Any: + async def run(self, ns: str, func_name: str, **kwargs) -> Any: """Run a requested function locally and return it's result. """ obj = self.actor if ns == 'self' else importlib.import_module(ns) - func = getattr(obj, func) + func = getattr(obj, func_name) if inspect.iscoroutinefunction(func): return await func(**kwargs) else: