Is it possible to extract the function and arguments of a coroutine object in python3.6?
Context: currently I have something like this:
async def func(*args):
...
ret = await remotely(func, x, y)
Under the hood, remotely
pickles func
, x
, and y
, scp's that to a different server, where it unpickles them, executes func(x,y)
, pickles the result, scp's that back, and finally unpickles it into ret
.
This API feels distasteful to me, I'd prefer to have:
ret = await remotely(func(x, y))
I could do this if I could pickle the coroutine object represented by func(x, y)
, but when I tried that, I get:
TypeError: can't pickle coroutine objects
So my alternate hope is that I can extract f
, x
, and y
from f(x, y)
, hence this question.
So when you do ret = await remotely(func(x, y))
, you actually construct the coroutine object for func
. Fortunately, you can extract the information you need from coroutine objects, which you can send over for remote execution.
So first of all you can get the function name using the __qualname__
attribute. This will give you the fully qualified name, i.e. if the coroutine is nested, it will get you the full path to your function.
Next, you can extract the argument values from the frame object of the coroutine.
So this is how your remote
function would look like
async def remote(cr):
# Get the function name
fname = cr.__qualname__
# Get the argument values
frame = cr.cr_frame
args = frame.f_locals # dict object
result = await ... # your scp stuff
return result
There is just one caveat. You should indicate that the function should be only used the way that you have posted, i.e.
ret = await remotely(func(x, y))
...in other words, the coroutine should be "fresh", and not half-way executed (which is almost not possible if you initiate it right before passing it to remote
). Otherwise, the f_locals
value might include any other local variable that is defined before any await
s.