Skip to content

Commit

Permalink
[HOTFIX]: Remote action support *args and *kwargs
Browse files Browse the repository at this point in the history
  • Loading branch information
amadolid committed Jul 27, 2023
1 parent c96eb75 commit 966adef
Show file tree
Hide file tree
Showing 3 changed files with 545 additions and 13 deletions.
36 changes: 29 additions & 7 deletions jaseci_core/jaseci/jsorc/live_actions.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,10 @@
import inspect
import importlib
import gc
import re

var_args = re.compile(r"^\*[^\*]")
var_kwargs = re.compile(r"^\*\*[^\*]")

live_actions = {} # {"act.func": func_obj, ...}
live_action_modules = {} # {__module__: ["act.func1", "act.func2", ...], ...}
Expand Down Expand Up @@ -305,14 +309,32 @@ def gen_remote_func_hook(url, act_name, param_names):

def func(*args, **kwargs):
params = {}
for i in range(len(param_names)):
if i < len(args):
params[param_names[i]] = args[i]
_args = list(args)
_param_names: list = param_names.copy()

args_len = len(args)
for idx, name in enumerate(param_names):
if idx >= args_len or not _args:
break
_param_names.remove(name)
if var_args.match(name):
if _args:
params[name] = _args
break
else:
params[param_names[i]] = None
for i in kwargs.keys():
if i in param_names:
params[i] = kwargs[i]
params[name] = _args.pop(0)

for name in _param_names:
if var_args.match(name):
if _args:
params[name] = _args
elif var_kwargs.match(name):
if kwargs:
params[name] = kwargs
break
elif name in kwargs:
params[name] = kwargs.pop(name)

# Remove any None-valued parameters to use the default value of the action def
params = dict([(k, v) for k, v in params.items() if v is not None])
act_url = f"{url.rstrip('/')}/{act_name.split('.')[-1]}"
Expand Down
63 changes: 57 additions & 6 deletions jaseci_core/jaseci/jsorc/remote_actions.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,12 @@
import inspect
import uvicorn
import os
import re

var_args = re.compile(r"^\*[^\*]")
var_kwargs = re.compile(r"^\*\*[^\*]")

args_kwargs = (2, 4)
remote_actions = {}
registered_apis = []
registered_endpoints = []
Expand Down Expand Up @@ -51,32 +56,78 @@ def action_list():
def gen_api_service(app, func, act_group, aliases, caller_globals):
"""Helper for jaseci_action decorator"""
# Construct list of action apis available
varnames = list(inspect.signature(func).parameters.keys())
act_group = (
[os.path.basename(inspect.getfile(func)).split(".")[0]]
if act_group is None
else act_group
)
varnames = []
for param in inspect.signature(func).parameters.values():
varnames.append(str(param) if param.kind in args_kwargs else param.name)

remote_actions[f"{'.'.join(act_group+[func.__name__])}"] = varnames

# Need to get pydatic model for func signature for fastAPI post
model = validate_arguments(func).model

# Keep only fields present in param list in base model
keep_fields = {}
for i in model.__fields__.keys():
if i in varnames:
keep_fields[i] = model.__fields__[i]
for name in varnames:
if var_args.match(name):
keep_fields[name] = model.__fields__[name[1:]]
keep_fields[name].name = name
keep_fields[name].alias = name
elif var_kwargs.match(name):
keep_fields[name] = model.__fields__[name[2:]]
keep_fields[name].name = name
keep_fields[name].alias = name
else:
field = model.__fields__.get(name)
if field:
keep_fields[name] = field
model.__fields__ = keep_fields

# Create duplicate funtion for api endpoint and inject in call site globals
@app.post(f"/{func.__name__}/")
def new_func(params: model = model.construct()):
pl_peek = str(dict(params.__dict__))[:128]
params: dict = params.__dict__
pl_peek = str(params)[:128]
logger.info(str(f"Incoming call to {func.__name__} with {pl_peek}"))
start_time = time()

ret = validate_arguments(func)(**(params.__dict__))
args = []
kwargs = {}
fp1 = inspect.signature(func).parameters.values()
fp2 = list(fp1)

# try to process args
for param in fp1:
_param = str(param) if param.kind in args_kwargs else param.name
if _param in params:
fp2.remove(param)
if var_args.match(_param):
for arg in params.get(_param) or []:
args.append(arg)
break
elif var_kwargs.match(_param):
kwargs.update(params.get(_param) or {})
break
args.append(params.get(_param))
else:
break

# try to process kwargs
for param in fp2:
param = str(param) if param.kind in args_kwargs else param.name
if param in params:
if var_kwargs.match(param):
kwargs.update(params.get(param) or {})
break
kwargs[param] = params.get(param)
else:
break

ret = validate_arguments(func)(*args, **kwargs)
tot_time = time() - start_time
logger.info(
str(
Expand Down
Loading

0 comments on commit 966adef

Please sign in to comment.