Use `pkgutils.resolve_name()` and a `str` subtype

Python 3.9's new object resolver + a `str` is much simpler then mucking
with tuples (and easier to serialize). Include a `.to_tuple()` formatter
since we still are passing the module namespace and function name
separately inside the runtime's message format but in theory we might be
able to simplify this depending on how we would change the support for
`enable_modules:list[str]` in the spawn API.

Thanks to @Fuyukai for pointing `resolve_name()` which I didn't know
about before!
nspaths
Tyler Goodlet 2022-01-27 13:39:46 -05:00
parent 949cb2c9fe
commit b6ae77b5ac
1 changed files with 19 additions and 27 deletions

View File

@ -20,8 +20,8 @@ concurrency linked tasks running in disparate memory domains.
''' '''
from __future__ import annotations from __future__ import annotations
from typing import NamedTuple
import importlib import importlib
from pkgutil import resolve_name
import inspect import inspect
from typing import ( from typing import (
Any, Optional, Any, Optional,
@ -68,20 +68,21 @@ async def maybe_open_nursery(
yield nursery yield nursery
class NamespacePath(NamedTuple): class NamespacePath(str):
''' '''
A serializeable description of a (function) object location A serializeable description of a (function) Python object location
described by the target's module path and its namespace key. described by the target's module path and its namespace key.
''' '''
mod: str def load_ref(self) -> object:
key: str return resolve_name(self)
def load(self) -> Callable: def to_tuple(
return getattr( self,
importlib.import_module(self.mod),
self.key ) -> tuple[str, str]:
) ref = self.load_ref()
return ref.__module__, ref.__name__
@classmethod @classmethod
def from_ref( def from_ref(
@ -89,17 +90,10 @@ class NamespacePath(NamedTuple):
obj, obj,
) -> NamespacePath: ) -> NamespacePath:
return cls( return cls(':'.join(
obj.__module__, (obj.__module__,
obj.__name__, obj.__name__,)
) ))
# def func_deats(func: Callable) -> NamespacePath[str, str]:
# return NamespacePath(
# func.__module__,
# func.__name__,
# )
def _unwrap_msg( def _unwrap_msg(
@ -346,8 +340,7 @@ class Portal:
raise TypeError( raise TypeError(
f'{func} must be a non-streaming async function!') f'{func} must be a non-streaming async function!')
# fn_mod_path, fn_name = func_deats(func) fn_mod_path, fn_name = NamespacePath.from_ref(func).to_tuple()
fn_mod_path, fn_name = NamespacePath.from_ref(func)
ctx = await self.actor.start_remote_task( ctx = await self.actor.start_remote_task(
self.channel, self.channel,
@ -377,8 +370,8 @@ class Portal:
raise TypeError( raise TypeError(
f'{async_gen_func} must be an async generator function!') f'{async_gen_func} must be an async generator function!')
# fn_mod_path, fn_name = func_deats(async_gen_func) fn_mod_path, fn_name = NamespacePath.from_ref(
fn_mod_path, fn_name = NamespacePath.from_ref(async_gen_func) async_gen_func).to_tuple()
ctx = await self.actor.start_remote_task( ctx = await self.actor.start_remote_task(
self.channel, self.channel,
fn_mod_path, fn_mod_path,
@ -444,8 +437,7 @@ class Portal:
raise TypeError( raise TypeError(
f'{func} must be an async generator function!') f'{func} must be an async generator function!')
# fn_mod_path, fn_name = func_deats(func) fn_mod_path, fn_name = NamespacePath.from_ref(func).to_tuple()
fn_mod_path, fn_name = NamespacePath.from_ref(func)
ctx = await self.actor.start_remote_task( ctx = await self.actor.start_remote_task(
self.channel, self.channel,