@@ -329,6 +329,26 @@ def device_class_counts(self) -> Dict[str, int]:
329329
330330HandlerFuncType = Callable [..., Tuple [int , str , str ]]
331331
332+ def _extract_target_func (
333+ f : HandlerFuncType
334+ ) -> Tuple [HandlerFuncType , Dict [str , Any ]]:
335+ """In order to interoperate with other decorated functions,
336+ we need to find the original function which will provide
337+ the main set of arguments. While we descend through the
338+ stack of wrapped functions, gather additional arguments
339+ the decorators may want to provide.
340+ """
341+ # use getattr to keep mypy happy
342+ wrapped = getattr (f , "__wrapped__" , None )
343+ if not wrapped :
344+ return f , {}
345+ extra_args = {}
346+ while wrapped is not None :
347+ extra_args .update (getattr (f , "extra_args" , {}))
348+ f = wrapped
349+ wrapped = getattr (f , "__wrapped__" , None )
350+ return f , extra_args
351+
332352
333353class CLICommand (object ):
334354 COMMANDS = {} # type: Dict[str, CLICommand]
@@ -346,8 +366,9 @@ def __init__(self,
346366
347367 KNOWN_ARGS = '_' , 'self' , 'mgr' , 'inbuf' , 'return'
348368
349- @staticmethod
350- def load_func_metadata (f : HandlerFuncType ) -> Tuple [str , Dict [str , Any ], int , str ]:
369+ @classmethod
370+ def _load_func_metadata (cls : Any , f : HandlerFuncType ) -> Tuple [str , Dict [str , Any ], int , str ]:
371+ f , extra_args = _extract_target_func (f )
351372 desc = (inspect .getdoc (f ) or '' ).replace ('\n ' , ' ' )
352373 full_argspec = inspect .getfullargspec (f )
353374 arg_spec = full_argspec .annotations
@@ -357,7 +378,7 @@ def load_func_metadata(f: HandlerFuncType) -> Tuple[str, Dict[str, Any], int, st
357378 args = []
358379 positional = True
359380 for index , arg in enumerate (full_argspec .args ):
360- if arg in CLICommand .KNOWN_ARGS :
381+ if arg in cls .KNOWN_ARGS :
361382 continue
362383 if arg == '_end_positional_' :
363384 positional = False
@@ -377,11 +398,19 @@ def load_func_metadata(f: HandlerFuncType) -> Tuple[str, Dict[str, Any], int, st
377398 dict (name = arg ),
378399 has_default ,
379400 positional ))
401+ for argname , argtype in extra_args .items ():
402+ # avoid shadowing args from the function
403+ if argname in arg_spec :
404+ continue
405+ arg_spec [argname ] = argtype
406+ args .append (CephArgtype .to_argdesc (
407+ argtype , dict (name = arg ), has_default = True , positional = False
408+ ))
380409 return desc , arg_spec , first_default , ' ' .join (args )
381410
382411 def store_func_metadata (self , f : HandlerFuncType ) -> None :
383412 self .desc , self .arg_spec , self .first_default , self .args = \
384- self .load_func_metadata (f )
413+ self ._load_func_metadata (f )
385414
386415 def __call__ (self , func : HandlerFuncType ) -> HandlerFuncType :
387416 self .store_func_metadata (func )
0 commit comments