From: John Mulligan Date: Mon, 11 Apr 2022 19:03:12 +0000 (-0400) Subject: pybind/mgr: enhance CLICommand to fetch extra args from wrapped funcs X-Git-Tag: v17.2.1~48^2~7 X-Git-Url: http://git-server-git.apps.pok.os.sepia.ceph.com/?a=commitdiff_plain;h=40c84ec426677f084f2bf20bf45844997587ca88;p=ceph.git pybind/mgr: enhance CLICommand to fetch extra args from wrapped funcs Previously, the CLICommand decorator "assumed" that the decorator was applied directly to a mgr module api endpoint function. Now that we plan on adding the Responder decorator into the mix we need a way of properly fetching the arguments of the endpoint function. In addition, the decorator itself needs to provide extra arguments to the mgr (in cases where the endpoint function doesn't explicitly ask for it). Thus we add a helper function to find the endpoint function when wrapped as well as extract extra arguments when "walking" the stack of __wrapped__ functions. Signed-off-by: John Mulligan (cherry picked from commit 2b22297f5664a2c778f6591dd1e1f3822fc5a3c1) --- diff --git a/src/pybind/mgr/mgr_module.py b/src/pybind/mgr/mgr_module.py index f8f85b7172d8..9110227efcc9 100644 --- a/src/pybind/mgr/mgr_module.py +++ b/src/pybind/mgr/mgr_module.py @@ -329,6 +329,26 @@ class CRUSHMap(ceph_module.BasePyCRUSH): HandlerFuncType = Callable[..., Tuple[int, str, str]] +def _extract_target_func( + f: HandlerFuncType +) -> Tuple[HandlerFuncType, Dict[str, Any]]: + """In order to interoperate with other decorated functions, + we need to find the original function which will provide + the main set of arguments. While we descend through the + stack of wrapped functions, gather additional arguments + the decorators may want to provide. + """ + # use getattr to keep mypy happy + wrapped = getattr(f, "__wrapped__", None) + if not wrapped: + return f, {} + extra_args = {} + while wrapped is not None: + extra_args.update(getattr(f, "extra_args", {})) + f = wrapped + wrapped = getattr(f, "__wrapped__", None) + return f, extra_args + class CLICommand(object): COMMANDS = {} # type: Dict[str, CLICommand] @@ -348,6 +368,7 @@ class CLICommand(object): @classmethod def _load_func_metadata(cls: Any, f: HandlerFuncType) -> Tuple[str, Dict[str, Any], int, str]: + f, extra_args = _extract_target_func(f) desc = (inspect.getdoc(f) or '').replace('\n', ' ') full_argspec = inspect.getfullargspec(f) arg_spec = full_argspec.annotations @@ -377,6 +398,14 @@ class CLICommand(object): dict(name=arg), has_default, positional)) + for argname, argtype in extra_args.items(): + # avoid shadowing args from the function + if argname in arg_spec: + continue + arg_spec[argname] = argtype + args.append(CephArgtype.to_argdesc( + argtype, dict(name=arg), has_default=True, positional=False + )) return desc, arg_spec, first_default, ' '.join(args) def store_func_metadata(self, f: HandlerFuncType) -> None: