From b173f4f5b982f3428faf10ea9186d545d84b48b7 Mon Sep 17 00:00:00 2001 From: Drew Risinger Date: Fri, 2 Nov 2018 20:15:48 -0400 Subject: [PATCH] pc_rpc: fix #1186. annotations -> str(annotations) Turn annotations into a string which PYON can encode. --- artiq/protocols/pc_rpc.py | 24 +++++++++++++++++------- 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/artiq/protocols/pc_rpc.py b/artiq/protocols/pc_rpc.py index adecf25df..084538b81 100644 --- a/artiq/protocols/pc_rpc.py +++ b/artiq/protocols/pc_rpc.py @@ -11,12 +11,13 @@ client passes a list as a parameter of an RPC method, and that method client's list. """ -import socket import asyncio +import inspect +import logging +import socket import threading import time -import logging -import inspect +import typing from operator import itemgetter from artiq.monkey_patches import * @@ -24,7 +25,6 @@ from artiq.protocols import pyon from artiq.protocols.asyncio_server import AsyncioServer as _AsyncioServer from artiq.protocols.packed_exceptions import * - logger = logging.getLogger(__name__) @@ -487,6 +487,17 @@ class Server(_AsyncioServer): else: self._noparallel = asyncio.Lock() + @staticmethod + def _document_function(function: typing.Callable) -> typing.Tuple[dict, str]: + """Turn a function into a tuple of its arguments and documentation. + + Allows remote inspection of what methods are available on a local device.""" + argspec_dict = dict(inspect.getfullargspec(function)._asdict()) + # Fix issue #1186: PYON can't serialize type annotations. + if any(argspec_dict.get("annotations", {})): + argspec_dict["annotations"] = str(argspec_dict["annotations"]) + return (argspec_dict, inspect.getdoc(function)) + async def _process_action(self, target, obj): if self._noparallel is not None: await self._noparallel.acquire() @@ -501,9 +512,7 @@ class Server(_AsyncioServer): if name.startswith("_"): continue method = getattr(target, name) - argspec = inspect.getfullargspec(method) - doc["methods"][name] = (dict(argspec._asdict()), - inspect.getdoc(method)) + doc["methods"][name] = self._document_function(method) if self.builtin_terminate: doc["methods"]["terminate"] = ( { @@ -515,6 +524,7 @@ class Server(_AsyncioServer): "kwonlydefaults": [], }, "Terminate the server.") + logger.debug("RPC docs for %s: %s", target, doc) return {"status": "ok", "ret": doc} elif obj["action"] == "call": logger.debug("calling %s", _PrettyPrintCall(obj))