@@ -335,11 +335,12 @@ class Cmd(cmd.Cmd):
335
335
DEFAULT_SHORTCUTS = {'?' : 'help' , '!' : 'shell' , '@' : 'load' , '@@' : '_relative_load' }
336
336
DEFAULT_EDITOR = utils .find_editor ()
337
337
338
- def __init__ (self , completekey : str = 'tab' , stdin = None , stdout = None , persistent_history_file : str = '' ,
339
- persistent_history_length : int = 1000 , startup_script : Optional [str ] = None , use_ipython : bool = False ,
340
- transcript_files : Optional [List [str ]] = None , allow_redirection : bool = True ,
341
- multiline_commands : Optional [List [str ]] = None , terminators : Optional [List [str ]] = None ,
342
- shortcuts : Optional [Dict [str , str ]] = None ) -> None :
338
+ def __init__ (self , completekey : str = 'tab' , stdin = None , stdout = None , * ,
339
+ persistent_history_file : str = '' , persistent_history_length : int = 1000 ,
340
+ startup_script : Optional [str ] = None , use_ipython : bool = False ,
341
+ allow_cli_args : bool = True , transcript_files : Optional [List [str ]] = None ,
342
+ allow_redirection : bool = True , multiline_commands : Optional [List [str ]] = None ,
343
+ terminators : Optional [List [str ]] = None , shortcuts : Optional [Dict [str , str ]] = None ) -> None :
343
344
"""An easy but powerful framework for writing line-oriented command interpreters, extends Python's cmd package.
344
345
345
346
:param completekey: (optional) readline name of a completion key, default to Tab
@@ -349,6 +350,9 @@ def __init__(self, completekey: str = 'tab', stdin=None, stdout=None, persistent
349
350
:param persistent_history_length: (optional) max number of history items to write to the persistent history file
350
351
:param startup_script: (optional) file path to a a script to load and execute at startup
351
352
:param use_ipython: (optional) should the "ipy" command be included for an embedded IPython shell
353
+ :param allow_cli_args: (optional) if True, then cmd2 will process command line arguments as either
354
+ commands to be run or, if -t is specified, transcript files to run.
355
+ This should be set to False if your application parses its own arguments.
352
356
:param transcript_files: (optional) allows running transcript tests when allow_cli_args is False
353
357
:param allow_redirection: (optional) should output redirection and pipes be allowed
354
358
:param multiline_commands: (optional) list of commands allowed to accept multi-line input
@@ -372,7 +376,6 @@ def __init__(self, completekey: str = 'tab', stdin=None, stdout=None, persistent
372
376
super ().__init__ (completekey = completekey , stdin = stdin , stdout = stdout )
373
377
374
378
# Attributes which should NOT be dynamically settable at runtime
375
- self .allow_cli_args = True # Should arguments passed on the command-line be processed as commands?
376
379
self .default_to_shell = False # Attempt to run unrecognized commands as shell commands
377
380
self .quit_on_sigint = False # Quit the loop on interrupt instead of just resetting prompt
378
381
@@ -423,7 +426,6 @@ def __init__(self, completekey: str = 'tab', stdin=None, stdout=None, persistent
423
426
terminators = terminators ,
424
427
multiline_commands = multiline_commands ,
425
428
shortcuts = shortcuts )
426
- self ._transcript_files = transcript_files
427
429
428
430
# True if running inside a Python script or interactive console, False otherwise
429
431
self ._in_py = False
@@ -460,11 +462,33 @@ def __init__(self, completekey: str = 'tab', stdin=None, stdout=None, persistent
460
462
# If this string is non-empty, then this warning message will print if a broken pipe error occurs while printing
461
463
self .broken_pipe_warning = ''
462
464
465
+ # Commands that will run at the beginning of the command loop
466
+ self ._startup_commands = []
467
+
463
468
# If a startup script is provided, then add it in the queue to load
464
469
if startup_script is not None :
465
470
startup_script = os .path .abspath (os .path .expanduser (startup_script ))
466
471
if os .path .exists (startup_script ) and os .path .getsize (startup_script ) > 0 :
467
- self .cmdqueue .append ("load '{}'" .format (startup_script ))
472
+ self ._startup_commands .append ("load '{}'" .format (startup_script ))
473
+
474
+ # Transcript files to run instead of interactive command loop
475
+ self ._transcript_files = None
476
+
477
+ # Check for command line args
478
+ if allow_cli_args :
479
+ parser = argparse .ArgumentParser ()
480
+ parser .add_argument ('-t' , '--test' , action = "store_true" ,
481
+ help = 'Test against transcript(s) in FILE (wildcards OK)' )
482
+ callopts , callargs = parser .parse_known_args ()
483
+
484
+ # If transcript testing was called for, use other arguments as transcript files
485
+ if callopts .test :
486
+ self ._transcript_files = callargs
487
+ # If commands were supplied at invocation, then add them to the command queue
488
+ elif callargs :
489
+ self ._startup_commands .extend (callargs )
490
+ elif transcript_files :
491
+ self ._transcript_files = transcript_files
468
492
469
493
# The default key for sorting tab completion matches. This only applies when the matches are not
470
494
# already marked as sorted by setting self.matches_sorted to True. Its default value performs a
@@ -2242,25 +2266,23 @@ def _cmdloop(self) -> None:
2242
2266
readline .parse_and_bind (self .completekey + ": complete" )
2243
2267
2244
2268
try :
2245
- stop = False
2269
+ # Run startup commands
2270
+ stop = self .runcmds_plus_hooks (self ._startup_commands )
2271
+ self ._startup_commands .clear ()
2272
+
2246
2273
while not stop :
2247
- if self .cmdqueue :
2248
- # Run commands out of cmdqueue if nonempty (populated by commands at invocation)
2249
- stop = self .runcmds_plus_hooks (self .cmdqueue )
2250
- self .cmdqueue .clear ()
2251
- else :
2252
- # Otherwise, read a command from stdin
2253
- try :
2254
- line = self .pseudo_raw_input (self .prompt )
2255
- except KeyboardInterrupt as ex :
2256
- if self .quit_on_sigint :
2257
- raise ex
2258
- else :
2259
- self .poutput ('^C' )
2260
- line = ''
2274
+ # Get commands from user
2275
+ try :
2276
+ line = self .pseudo_raw_input (self .prompt )
2277
+ except KeyboardInterrupt as ex :
2278
+ if self .quit_on_sigint :
2279
+ raise ex
2280
+ else :
2281
+ self .poutput ('^C' )
2282
+ line = ''
2261
2283
2262
- # Run the command along with all associated pre and post hooks
2263
- stop = self .onecmd_plus_hooks (line )
2284
+ # Run the command along with all associated pre and post hooks
2285
+ stop = self .onecmd_plus_hooks (line )
2264
2286
finally :
2265
2287
if self .use_rawinput and self .completekey and rl_type != RlType .NONE :
2266
2288
@@ -2274,7 +2296,6 @@ def _cmdloop(self) -> None:
2274
2296
elif rl_type == RlType .PYREADLINE :
2275
2297
# noinspection PyUnresolvedReferences
2276
2298
readline .rl .mode ._display_completions = orig_pyreadline_display
2277
- self .cmdqueue .clear ()
2278
2299
2279
2300
# ----- Alias sub-command functions -----
2280
2301
@@ -2889,10 +2910,8 @@ def cmdenvironment(self) -> str:
2889
2910
"""
2890
2911
read_only_settings = """
2891
2912
Commands may be terminated with: {}
2892
- Arguments at invocation allowed: {}
2893
2913
Output redirection and pipes allowed: {}"""
2894
- return read_only_settings .format (str (self .statement_parser .terminators ), self .allow_cli_args ,
2895
- self .allow_redirection )
2914
+ return read_only_settings .format (str (self .statement_parser .terminators ), self .allow_redirection )
2896
2915
2897
2916
def show (self , args : argparse .Namespace , parameter : str = '' ) -> None :
2898
2917
"""Shows current settings of parameters.
@@ -3991,7 +4010,6 @@ def cmdloop(self, intro: Optional[str] = None) -> int:
3991
4010
3992
4011
_cmdloop() provides the main loop equivalent to cmd.cmdloop(). This is a wrapper around that which deals with
3993
4012
the following extra features provided by cmd2:
3994
- - commands at invocation
3995
4013
- transcript testing
3996
4014
- intro banner
3997
4015
- exit code
@@ -4008,19 +4026,6 @@ def cmdloop(self, intro: Optional[str] = None) -> int:
4008
4026
original_sigint_handler = signal .getsignal (signal .SIGINT )
4009
4027
signal .signal (signal .SIGINT , self .sigint_handler )
4010
4028
4011
- if self .allow_cli_args :
4012
- parser = argparse .ArgumentParser ()
4013
- parser .add_argument ('-t' , '--test' , action = "store_true" ,
4014
- help = 'Test against transcript(s) in FILE (wildcards OK)' )
4015
- callopts , callargs = parser .parse_known_args ()
4016
-
4017
- # If transcript testing was called for, use other arguments as transcript files
4018
- if callopts .test :
4019
- self ._transcript_files = callargs
4020
- # If commands were supplied at invocation, then add them to the command queue
4021
- elif callargs :
4022
- self .cmdqueue .extend (callargs )
4023
-
4024
4029
# Grab terminal lock before the prompt has been drawn by readline
4025
4030
self .terminal_lock .acquire ()
4026
4031
0 commit comments