pc_rpc: fix #1186. annotations -> str(annotations)

Turn annotations into a string which PYON can encode.
This commit is contained in:
Drew Risinger 2018-11-02 20:15:48 -04:00
parent 0b43ec4719
commit b173f4f5b9

View File

@ -11,12 +11,13 @@ client passes a list as a parameter of an RPC method, and that method
client's list. client's list.
""" """
import socket
import asyncio import asyncio
import inspect
import logging
import socket
import threading import threading
import time import time
import logging import typing
import inspect
from operator import itemgetter from operator import itemgetter
from artiq.monkey_patches import * 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.asyncio_server import AsyncioServer as _AsyncioServer
from artiq.protocols.packed_exceptions import * from artiq.protocols.packed_exceptions import *
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@ -487,6 +487,17 @@ class Server(_AsyncioServer):
else: else:
self._noparallel = asyncio.Lock() 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): async def _process_action(self, target, obj):
if self._noparallel is not None: if self._noparallel is not None:
await self._noparallel.acquire() await self._noparallel.acquire()
@ -501,9 +512,7 @@ class Server(_AsyncioServer):
if name.startswith("_"): if name.startswith("_"):
continue continue
method = getattr(target, name) method = getattr(target, name)
argspec = inspect.getfullargspec(method) doc["methods"][name] = self._document_function(method)
doc["methods"][name] = (dict(argspec._asdict()),
inspect.getdoc(method))
if self.builtin_terminate: if self.builtin_terminate:
doc["methods"]["terminate"] = ( doc["methods"]["terminate"] = (
{ {
@ -515,6 +524,7 @@ class Server(_AsyncioServer):
"kwonlydefaults": [], "kwonlydefaults": [],
}, },
"Terminate the server.") "Terminate the server.")
logger.debug("RPC docs for %s: %s", target, doc)
return {"status": "ok", "ret": doc} return {"status": "ok", "ret": doc}
elif obj["action"] == "call": elif obj["action"] == "call":
logger.debug("calling %s", _PrettyPrintCall(obj)) logger.debug("calling %s", _PrettyPrintCall(obj))