@@ -187,7 +187,7 @@ def __init__(self, completekey: str = 'tab', stdin=None, stdout=None, *,
187
187
188
188
# Attributes which should NOT be dynamically settable via the set command at runtime
189
189
self .default_to_shell = False # Attempt to run unrecognized commands as shell commands
190
- self .quit_on_sigint = False # Quit the loop on interrupt instead of just resetting prompt
190
+ self .quit_on_sigint = False # Ctrl-C at the prompt will quit the program instead of just resetting prompt
191
191
self .allow_redirection = allow_redirection # Security setting to prevent redirection of stdout
192
192
193
193
# Attributes which ARE dynamically settable via the set command at runtime
@@ -1584,11 +1584,15 @@ def parseline(self, line: str) -> Tuple[str, str, str]:
1584
1584
statement = self .statement_parser .parse_command_only (line )
1585
1585
return statement .command , statement .args , statement .command_and_args
1586
1586
1587
- def onecmd_plus_hooks (self , line : str , * , add_to_history : bool = True , py_bridge_call : bool = False ) -> bool :
1587
+ def onecmd_plus_hooks (self , line : str , * , add_to_history : bool = True ,
1588
+ raise_keyboard_interrupt : bool = False , py_bridge_call : bool = False ) -> bool :
1588
1589
"""Top-level function called by cmdloop() to handle parsing a line and running the command and all of its hooks.
1589
1590
1590
1591
:param line: command line to run
1591
1592
:param add_to_history: If True, then add this command to history. Defaults to True.
1593
+ :param raise_keyboard_interrupt: if True, then KeyboardInterrupt exceptions will be raised. This is used when
1594
+ running commands in a loop to be able to stop the whole loop and not just
1595
+ the current command. Defaults to False.
1592
1596
:param py_bridge_call: This should only ever be set to True by PyBridge to signify the beginning
1593
1597
of an app() call from Python. It is used to enable/disable the storage of the
1594
1598
command's stdout.
@@ -1681,14 +1685,18 @@ def onecmd_plus_hooks(self, line: str, *, add_to_history: bool = True, py_bridge
1681
1685
if py_bridge_call :
1682
1686
# Stop saving command's stdout before command finalization hooks run
1683
1687
self .stdout .pause_storage = True
1684
-
1688
+ except KeyboardInterrupt as ex :
1689
+ if raise_keyboard_interrupt :
1690
+ raise ex
1685
1691
except (Cmd2ArgparseError , EmptyStatement ):
1686
1692
# Don't do anything, but do allow command finalization hooks to run
1687
1693
pass
1688
1694
except Exception as ex :
1689
1695
self .pexcept (ex )
1690
1696
finally :
1691
- return self ._run_cmdfinalization_hooks (stop , statement )
1697
+ stop = self ._run_cmdfinalization_hooks (stop , statement )
1698
+
1699
+ return stop
1692
1700
1693
1701
def _run_cmdfinalization_hooks (self , stop : bool , statement : Optional [Statement ]) -> bool :
1694
1702
"""Run the command finalization hooks"""
@@ -1711,13 +1719,16 @@ def _run_cmdfinalization_hooks(self, stop: bool, statement: Optional[Statement])
1711
1719
except Exception as ex :
1712
1720
self .pexcept (ex )
1713
1721
1714
- def runcmds_plus_hooks (self , cmds : List [Union [HistoryItem , str ]], * , add_to_history : bool = True ) -> bool :
1722
+ def runcmds_plus_hooks (self , cmds : List [Union [HistoryItem , str ]], * , add_to_history : bool = True ,
1723
+ stop_on_keyboard_interrupt : bool = True ) -> bool :
1715
1724
"""
1716
1725
Used when commands are being run in an automated fashion like text scripts or history replays.
1717
1726
The prompt and command line for each command will be printed if echo is True.
1718
1727
1719
1728
:param cmds: commands to run
1720
1729
:param add_to_history: If True, then add these commands to history. Defaults to True.
1730
+ :param stop_on_keyboard_interrupt: stop command loop if Ctrl-C is pressed instead of just
1731
+ moving to the next command. Defaults to True.
1721
1732
:return: True if running of commands should stop
1722
1733
"""
1723
1734
for line in cmds :
@@ -1727,8 +1738,14 @@ def runcmds_plus_hooks(self, cmds: List[Union[HistoryItem, str]], *, add_to_hist
1727
1738
if self .echo :
1728
1739
self .poutput ('{}{}' .format (self .prompt , line ))
1729
1740
1730
- if self .onecmd_plus_hooks (line , add_to_history = add_to_history ):
1731
- return True
1741
+ try :
1742
+ if self .onecmd_plus_hooks (line , add_to_history = add_to_history ,
1743
+ raise_keyboard_interrupt = stop_on_keyboard_interrupt ):
1744
+ return True
1745
+ except KeyboardInterrupt as e :
1746
+ if stop_on_keyboard_interrupt :
1747
+ self .perror (e )
1748
+ break
1732
1749
1733
1750
return False
1734
1751
@@ -3269,9 +3286,6 @@ def py_quit():
3269
3286
if saved_cmd2_env is not None :
3270
3287
self ._restore_cmd2_env (saved_cmd2_env )
3271
3288
3272
- except KeyboardInterrupt :
3273
- pass
3274
-
3275
3289
finally :
3276
3290
with self .sigint_protection :
3277
3291
if saved_sys_path is not None :
@@ -3302,8 +3316,6 @@ def do_run_pyscript(self, args: argparse.Namespace) -> Optional[bool]:
3302
3316
if selection != 'Yes' :
3303
3317
return
3304
3318
3305
- py_return = False
3306
-
3307
3319
# Save current command line arguments
3308
3320
orig_args = sys .argv
3309
3321
@@ -3314,9 +3326,6 @@ def do_run_pyscript(self, args: argparse.Namespace) -> Optional[bool]:
3314
3326
# noinspection PyTypeChecker
3315
3327
py_return = self .do_py ('--pyscript {}' .format (utils .quote_string (args .script_path )))
3316
3328
3317
- except KeyboardInterrupt :
3318
- pass
3319
-
3320
3329
finally :
3321
3330
# Restore command line arguments to original state
3322
3331
sys .argv = orig_args
@@ -3629,7 +3638,12 @@ def _generate_transcript(self, history: List[Union[HistoryItem, str]], transcrip
3629
3638
self .stdout = utils .StdSim (self .stdout )
3630
3639
3631
3640
# then run the command and let the output go into our buffer
3632
- stop = self .onecmd_plus_hooks (history_item )
3641
+ try :
3642
+ stop = self .onecmd_plus_hooks (history_item , raise_keyboard_interrupt = True )
3643
+ except KeyboardInterrupt as e :
3644
+ self .perror (e )
3645
+ stop = True
3646
+
3633
3647
commands_run += 1
3634
3648
3635
3649
# add the regex-escaped output to the transcript
0 commit comments