2626# import this module, many of these imports are lazy-loaded
2727# i.e. we only import the module when we use it.
2828import argparse
29- import cmd
3029import contextlib
3130import copy
3231import functools
@@ -286,7 +285,7 @@ def remove(self, command_method: CommandFunc) -> None:
286285 del self ._parsers [full_method_name ]
287286
288287
289- class Cmd ( cmd . Cmd ) :
288+ class Cmd :
290289 """An easy but powerful framework for writing line-oriented command interpreters.
291290
292291 Extends the Python Standard Library's cmd package by adding a lot of useful features
@@ -304,6 +303,9 @@ class Cmd(cmd.Cmd):
304303 # List for storing transcript test file names
305304 testfiles : ClassVar [list [str ]] = []
306305
306+ DEFAULT_PROMPT = '(Cmd) '
307+ IDENTCHARS = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_'
308+
307309 def __init__ (
308310 self ,
309311 completekey : str = 'tab' ,
@@ -326,6 +328,7 @@ def __init__(
326328 auto_load_commands : bool = False ,
327329 allow_clipboard : bool = True ,
328330 suggest_similar_command : bool = False ,
331+ intro : str = '' ,
329332 ) -> None :
330333 """Easy but powerful framework for writing line-oriented command interpreters, extends Python's cmd package.
331334
@@ -376,6 +379,7 @@ def __init__(
376379 :param suggest_similar_command: If ``True``, ``cmd2`` will attempt to suggest the most
377380 similar command when the user types a command that does
378381 not exist. Default: ``False``.
382+ "param intro: Intro banner to print when starting the application.
379383 """
380384 # Check if py or ipy need to be disabled in this instance
381385 if not include_py :
@@ -384,11 +388,29 @@ def __init__(
384388 setattr (self , 'do_ipy' , None ) # noqa: B010
385389
386390 # initialize plugin system
387- # needs to be done before we call __init__(0)
391+ # needs to be done before we most of the other stuff below
388392 self ._initialize_plugin_system ()
389393
390- # Call super class constructor
391- super ().__init__ (completekey = completekey , stdin = stdin , stdout = stdout )
394+ # Configure a few defaults
395+ self .prompt = Cmd .DEFAULT_PROMPT
396+ self .identchars = Cmd .IDENTCHARS
397+ self .intro = intro
398+ self .use_rawinput = True
399+
400+ # What to use for standard input
401+ if stdin is not None :
402+ self .stdin = stdin
403+ else :
404+ self .stdin = sys .stdin
405+
406+ # What to use for standard output
407+ if stdout is not None :
408+ self .stdout = stdout
409+ else :
410+ self .stdout = sys .stdout
411+
412+ # Key used for tab completion
413+ self .completekey = completekey
392414
393415 # Attributes which should NOT be dynamically settable via the set command at runtime
394416 self .default_to_shell = False # Attempt to run unrecognized commands as shell commands
@@ -3086,7 +3108,7 @@ def _redirect_output(self, statement: Statement) -> utils.RedirectionSavedState:
30863108
30873109 # Initialize the redirection saved state
30883110 redir_saved_state = utils .RedirectionSavedState (
3089- cast ( TextIO , self .stdout ) , stdouts_match , self ._cur_pipe_proc_reader , self ._redirecting
3111+ self .stdout , stdouts_match , self ._cur_pipe_proc_reader , self ._redirecting
30903112 )
30913113
30923114 # The ProcReader for this command
@@ -3141,7 +3163,7 @@ def _redirect_output(self, statement: Statement) -> utils.RedirectionSavedState:
31413163 new_stdout .close ()
31423164 raise RedirectionError (f'Pipe process exited with code { proc .returncode } before command could run' )
31433165 redir_saved_state .redirecting = True
3144- cmd_pipe_proc_reader = utils .ProcReader (proc , cast ( TextIO , self .stdout ) , sys .stderr )
3166+ cmd_pipe_proc_reader = utils .ProcReader (proc , self .stdout , sys .stderr )
31453167
31463168 self .stdout = new_stdout
31473169 if stdouts_match :
@@ -3293,6 +3315,19 @@ def default(self, statement: Statement) -> bool | None: # type: ignore[override
32933315 self .perror (err_msg , style = None )
32943316 return None
32953317
3318+ def completedefault (self , * _ignored : list [str ]) -> list [str ]:
3319+ """Call to complete an input line when no command-specific complete_*() method is available.
3320+
3321+ By default, it returns an empty list.
3322+
3323+ """
3324+ return []
3325+
3326+ def completenames (self , text : str , * _ignored : list [str ]) -> list [str ]:
3327+ """Help provide tab-completion options for command names."""
3328+ dotext = 'do_' + text
3329+ return [a [3 :] for a in self .get_names () if a .startswith (dotext )]
3330+
32963331 def _suggest_similar_command (self , command : str ) -> str | None :
32973332 return suggest_similar (command , self .get_visible_commands ())
32983333
@@ -4131,10 +4166,6 @@ def _build_help_parser(cls) -> Cmd2ArgumentParser:
41314166 )
41324167 return help_parser
41334168
4134- # Get rid of cmd's complete_help() functions so ArgparseCompleter will complete the help command
4135- if getattr (cmd .Cmd , 'complete_help' , None ) is not None :
4136- delattr (cmd .Cmd , 'complete_help' )
4137-
41384169 @with_argparser (_build_help_parser )
41394170 def do_help (self , args : argparse .Namespace ) -> None :
41404171 """List available commands or provide detailed help for a specific command."""
@@ -4640,7 +4671,7 @@ def do_shell(self, args: argparse.Namespace) -> None:
46404671 ** kwargs ,
46414672 )
46424673
4643- proc_reader = utils .ProcReader (proc , cast ( TextIO , self .stdout ) , sys .stderr )
4674+ proc_reader = utils .ProcReader (proc , self .stdout , sys .stderr )
46444675 proc_reader .wait ()
46454676
46464677 # Save the return code of the application for use in a pyscript
@@ -5359,7 +5390,7 @@ def _generate_transcript(
53595390 transcript += command
53605391
53615392 # Use a StdSim object to capture output
5362- stdsim = utils .StdSim (cast ( TextIO , self .stdout ) )
5393+ stdsim = utils .StdSim (self .stdout )
53635394 self .stdout = cast (TextIO , stdsim )
53645395
53655396 # then run the command and let the output go into our buffer
@@ -5385,7 +5416,7 @@ def _generate_transcript(
53855416 with self .sigint_protection :
53865417 # Restore altered attributes to their original state
53875418 self .echo = saved_echo
5388- self .stdout = cast ( TextIO , saved_stdout )
5419+ self .stdout = saved_stdout
53895420
53905421 # Check if all commands ran
53915422 if commands_run < len (history ):
@@ -5880,7 +5911,7 @@ def _report_disabled_command_usage(self, *_args: Any, message_to_print: str, **_
58805911 """
58815912 self .perror (message_to_print , style = None )
58825913
5883- def cmdloop (self , intro : str | None = None ) -> int : # type: ignore[override]
5914+ def cmdloop (self , intro : str = '' ) -> int : # type: ignore[override]
58845915 """Deal with extra features provided by cmd2, this is an outer wrapper around _cmdloop().
58855916
58865917 _cmdloop() provides the main loop equivalent to cmd.cmdloop(). This is a wrapper around that which deals with
@@ -5922,11 +5953,11 @@ def cmdloop(self, intro: str | None = None) -> int: # type: ignore[override]
59225953 self ._run_transcript_tests ([os .path .expanduser (tf ) for tf in self ._transcript_files ])
59235954 else :
59245955 # If an intro was supplied in the method call, allow it to override the default
5925- if intro is not None :
5956+ if intro :
59265957 self .intro = intro
59275958
59285959 # Print the intro, if there is one, right after the preloop
5929- if self .intro is not None :
5960+ if self .intro :
59305961 self .poutput (self .intro )
59315962
59325963 # And then call _cmdloop() to enter the main loop
0 commit comments