@@ -122,6 +122,9 @@ def __subclasshook__(cls, C):
122122HELP_CATEGORY = 'help_category'
123123HELP_SUMMARY = 'help_summary'
124124
125+ # All command functions start with this
126+ COMMAND_PREFIX = 'do_'
127+
125128
126129def categorize (func : Union [Callable , Iterable ], category : str ) -> None :
127130 """Categorize a function.
@@ -400,7 +403,7 @@ def __init__(self, completekey: str='tab', stdin=None, stdout=None, persistent_h
400403 self .pystate = {}
401404 self .py_history = []
402405 self .pyscript_name = 'app'
403- self .keywords = self .reserved_words + [ fname [ 3 :] for fname in dir ( self ) if fname . startswith ( 'do_' )]
406+ self .keywords = self .reserved_words + self . get_all_commands ()
404407 self .statement_parser = StatementParser (
405408 allow_redirection = self .allow_redirection ,
406409 terminators = self .terminators ,
@@ -1471,16 +1474,15 @@ def complete(self, text: str, state: int) -> Optional[str]:
14711474 # Check if a valid command was entered
14721475 if command in self .get_all_commands ():
14731476 # Get the completer function for this command
1474- try :
1475- compfunc = getattr ( self , 'complete_' + command )
1476- except AttributeError :
1477+ compfunc = getattr ( self , 'complete_' + command , None )
1478+
1479+ if compfunc is None :
14771480 # There's no completer function, next see if the command uses argparser
1478- try :
1479- cmd_func = getattr (self , 'do_' + command )
1480- argparser = getattr (cmd_func , 'argparser' )
1481- # Command uses argparser, switch to the default argparse completer
1482- compfunc = functools .partial (self ._autocomplete_default , argparser = argparser )
1483- except AttributeError :
1481+ cmd_func = self ._cmd_func (command )
1482+ if cmd_func and hasattr (cmd_func , 'argparser' ):
1483+ compfunc = functools .partial (self ._autocomplete_default ,
1484+ argparser = getattr (cmd_func , 'argparser' ))
1485+ else :
14841486 compfunc = self .completedefault
14851487
14861488 # Check if a macro was entered
@@ -1596,8 +1598,8 @@ def _autocomplete_default(self, text: str, line: str, begidx: int, endidx: int,
15961598
15971599 def get_all_commands (self ) -> List [str ]:
15981600 """Returns a list of all commands."""
1599- return [name [3 :] for name in self .get_names ()
1600- if name .startswith ('do_' ) and callable (getattr (self , name ))]
1601+ return [name [len ( COMMAND_PREFIX ) :] for name in self .get_names ()
1602+ if name .startswith (COMMAND_PREFIX ) and callable (getattr (self , name ))]
16011603
16021604 def get_visible_commands (self ) -> List [str ]:
16031605 """Returns a list of commands that have not been hidden."""
@@ -1663,13 +1665,10 @@ def complete_help(self, text: str, line: str, begidx: int, endidx: int) -> List[
16631665
16641666 # check if the command uses argparser
16651667 elif index >= subcmd_index :
1666- try :
1667- cmd_func = getattr (self , 'do_' + tokens [cmd_index ])
1668- parser = getattr (cmd_func , 'argparser' )
1669- completer = AutoCompleter (parser , cmd2_app = self )
1668+ cmd_func = self ._cmd_func (tokens [cmd_index ])
1669+ if cmd_func and hasattr (cmd_func , 'argparser' ):
1670+ completer = AutoCompleter (getattr (cmd_func , 'argparser' ), cmd2_app = self )
16701671 matches = completer .complete_command_help (tokens [1 :], text , line , begidx , endidx )
1671- except AttributeError :
1672- pass
16731672
16741673 return matches
16751674
@@ -2003,13 +2002,23 @@ def _restore_output(self, statement: Statement) -> None:
20032002
20042003 self .redirecting = False
20052004
2006- def _func_named (self , arg : str ) -> str :
2007- """Gets the method name associated with a given command.
2005+ def _cmd_func (self , command : str ) -> Optional [Callable ]:
2006+ """
2007+ Get the function for a command
2008+ :param arg: the name of the command
2009+ """
2010+ func_name = self ._cmd_func_name (command )
2011+ if func_name :
2012+ return getattr (self , func_name )
2013+ return None
2014+
2015+ def _cmd_func_name (self , command : str ) -> str :
2016+ """Get the method name associated with a given command.
20082017
20092018 :param arg: command to look up method name which implements it
20102019 :return: method name which implements the given command
20112020 """
2012- target = 'do_' + arg
2021+ target = COMMAND_PREFIX + command
20132022 return target if callable (getattr (self , target , None )) else ''
20142023
20152024 def onecmd (self , statement : Union [Statement , str ]) -> bool :
@@ -2029,10 +2038,9 @@ def onecmd(self, statement: Union[Statement, str]) -> bool:
20292038 if statement .command in self .macros :
20302039 stop = self ._run_macro (statement )
20312040 else :
2032- funcname = self ._func_named (statement .command )
2033- if funcname :
2034- func = getattr (self , funcname )
2035- stop = func (statement )
2041+ cmd_func = self ._cmd_func (statement .command )
2042+ if cmd_func :
2043+ stop = cmd_func (statement )
20362044
20372045 # Since we have a valid command store it in the history
20382046 if statement .command not in self .exclude_from_history :
@@ -2588,20 +2596,18 @@ def do_help(self, arglist: List[str]) -> None:
25882596 self ._help_menu (verbose )
25892597 else :
25902598 # Getting help for a specific command
2591- funcname = self ._func_named (arglist [0 ])
2592- if funcname :
2599+ cmd_func = self ._cmd_func (arglist [0 ])
2600+ if cmd_func :
25932601 # Check to see if this function was decorated with an argparse ArgumentParser
2594- func = getattr (self , funcname )
2595- if hasattr (func , 'argparser' ):
2596- completer = AutoCompleter (getattr (func , 'argparser' ), cmd2_app = self )
2597-
2602+ if hasattr (cmd_func , 'argparser' ):
2603+ completer = AutoCompleter (getattr (cmd_func , 'argparser' ), cmd2_app = self )
25982604 self .poutput (completer .format_help (arglist ))
25992605 else :
26002606 # No special behavior needed, delegate to cmd base class do_help()
2601- cmd . Cmd . do_help (self , funcname [ 3 : ])
2607+ super (). do_help (arglist [ 0 ])
26022608 else :
26032609 # This could be a help topic
2604- cmd . Cmd . do_help (self , arglist [0 ])
2610+ super (). do_help (arglist [0 ])
26052611
26062612 def _help_menu (self , verbose : bool = False ) -> None :
26072613 """Show a list of commands which help can be displayed for.
@@ -2617,11 +2623,12 @@ def _help_menu(self, verbose: bool=False) -> None:
26172623 cmds_cats = {}
26182624
26192625 for command in visible_commands :
2620- if command in help_topics or getattr (self , self ._func_named (command )).__doc__ :
2626+ cmd_func = self ._cmd_func (command )
2627+ if command in help_topics or cmd_func .__doc__ :
26212628 if command in help_topics :
26222629 help_topics .remove (command )
2623- if hasattr (getattr ( self , self . _func_named ( command )) , HELP_CATEGORY ):
2624- category = getattr (getattr ( self , self . _func_named ( command )) , HELP_CATEGORY )
2630+ if hasattr (cmd_func , HELP_CATEGORY ):
2631+ category = getattr (cmd_func , HELP_CATEGORY )
26252632 cmds_cats .setdefault (category , [])
26262633 cmds_cats [category ].append (command )
26272634 else :
@@ -2674,12 +2681,13 @@ def _print_topics(self, header: str, cmds: List[str], verbose: bool) -> None:
26742681 func = getattr (self , 'help_' + command )
26752682 except AttributeError :
26762683 # Couldn't find a help function
2684+ cmd_func = self ._cmd_func (command )
26772685 try :
26782686 # Now see if help_summary has been set
2679- doc = getattr ( self , self . _func_named ( command )) .help_summary
2687+ doc = cmd_func .help_summary
26802688 except AttributeError :
26812689 # Last, try to directly access the function's doc-string
2682- doc = getattr ( self , self . _func_named ( command )) .__doc__
2690+ doc = cmd_func .__doc__
26832691 else :
26842692 # we found the help function
26852693 result = io .StringIO ()
0 commit comments