4646from .argparse_custom import DEFAULT_ARGUMENT_PARSER , CompletionItem
4747from .clipboard import can_clip , get_paste_buffer , write_to_paste_buffer
4848from .decorators import with_argparser
49- from .exceptions import Cmd2ArgparseError , Cmd2ShlexError , EmbeddedConsoleExit , EmptyStatement , RedirectionError
49+ from .exceptions import Cmd2ShlexError , EmbeddedConsoleExit , EmptyStatement , RedirectionError , SkipPostcommandHooks
5050from .history import History , HistoryItem
5151from .parsing import Macro , MacroArg , Statement , StatementParser , shlex_split
5252from .rl_utils import RlType , rl_get_point , rl_make_safe_prompt , rl_set_prompt , rl_type , rl_warning , vt100_support
@@ -1587,9 +1587,9 @@ def onecmd_plus_hooks(self, line: str, *, add_to_history: bool = True,
15871587
15881588 :param line: command line to run
15891589 :param add_to_history: If True, then add this command to history. Defaults to True.
1590- :param raise_keyboard_interrupt: if True, then KeyboardInterrupt exceptions will be raised. This is used when
1591- running commands in a loop to be able to stop the whole loop and not just
1592- the current command. Defaults to False.
1590+ :param raise_keyboard_interrupt: if True, then KeyboardInterrupt exceptions will be raised if stop isn't already
1591+ True. This is used when running commands in a loop to be able to stop the whole
1592+ loop and not just the current command. Defaults to False.
15931593 :param py_bridge_call: This should only ever be set to True by PyBridge to signify the beginning
15941594 of an app() call from Python. It is used to enable/disable the storage of the
15951595 command's stdout.
@@ -1667,26 +1667,35 @@ def onecmd_plus_hooks(self, line: str, *, add_to_history: bool = True,
16671667 if py_bridge_call :
16681668 # Stop saving command's stdout before command finalization hooks run
16691669 self .stdout .pause_storage = True
1670- except KeyboardInterrupt as ex :
1671- if raise_keyboard_interrupt :
1672- raise ex
1673- except (Cmd2ArgparseError , EmptyStatement ):
1670+ except (SkipPostcommandHooks , EmptyStatement ):
16741671 # Don't do anything, but do allow command finalization hooks to run
16751672 pass
16761673 except Cmd2ShlexError as ex :
16771674 self .perror ("Invalid syntax: {}" .format (ex ))
16781675 except RedirectionError as ex :
16791676 self .perror (ex )
1677+ except KeyboardInterrupt as ex :
1678+ if raise_keyboard_interrupt and not stop :
1679+ raise ex
1680+ except SystemExit :
1681+ stop = True
16801682 except Exception as ex :
16811683 self .pexcept (ex )
16821684 finally :
1683- stop = self ._run_cmdfinalization_hooks (stop , statement )
1685+ try :
1686+ stop = self ._run_cmdfinalization_hooks (stop , statement )
1687+ except KeyboardInterrupt as ex :
1688+ if raise_keyboard_interrupt and not stop :
1689+ raise ex
1690+ except SystemExit :
1691+ stop = True
1692+ except Exception as ex :
1693+ self .pexcept (ex )
16841694
16851695 return stop
16861696
16871697 def _run_cmdfinalization_hooks (self , stop : bool , statement : Optional [Statement ]) -> bool :
16881698 """Run the command finalization hooks"""
1689-
16901699 with self .sigint_protection :
16911700 if not sys .platform .startswith ('win' ) and self .stdin .isatty ():
16921701 # Before the next command runs, fix any terminal problems like those
@@ -1695,15 +1704,12 @@ def _run_cmdfinalization_hooks(self, stop: bool, statement: Optional[Statement])
16951704 proc = subprocess .Popen (['stty' , 'sane' ])
16961705 proc .communicate ()
16971706
1698- try :
1699- data = plugin .CommandFinalizationData (stop , statement )
1700- for func in self ._cmdfinalization_hooks :
1701- data = func (data )
1702- # retrieve the final value of stop, ignoring any
1703- # modifications to the statement
1704- return data .stop
1705- except Exception as ex :
1706- self .pexcept (ex )
1707+ data = plugin .CommandFinalizationData (stop , statement )
1708+ for func in self ._cmdfinalization_hooks :
1709+ data = func (data )
1710+ # retrieve the final value of stop, ignoring any
1711+ # modifications to the statement
1712+ return data .stop
17071713
17081714 def runcmds_plus_hooks (self , cmds : List [Union [HistoryItem , str ]], * , add_to_history : bool = True ,
17091715 stop_on_keyboard_interrupt : bool = True ) -> bool :
@@ -3894,7 +3900,7 @@ def async_alert(self, alert_msg: str, new_prompt: Optional[str] = None) -> None:
38943900
38953901 IMPORTANT: This function will not print an alert unless it can acquire self.terminal_lock to ensure
38963902 a prompt is onscreen. Therefore it is best to acquire the lock before calling this function
3897- to guarantee the alert prints.
3903+ to guarantee the alert prints and to avoid raising a RuntimeError .
38983904
38993905 :param alert_msg: the message to display to the user
39003906 :param new_prompt: if you also want to change the prompt that is displayed, then include it here
@@ -3956,7 +3962,7 @@ def async_update_prompt(self, new_prompt: str) -> None: # pragma: no cover
39563962
39573963 IMPORTANT: This function will not update the prompt unless it can acquire self.terminal_lock to ensure
39583964 a prompt is onscreen. Therefore it is best to acquire the lock before calling this function
3959- to guarantee the prompt changes.
3965+ to guarantee the prompt changes and to avoid raising a RuntimeError .
39603966
39613967 If user is at a continuation prompt while entering a multiline command, the onscreen prompt will
39623968 not change. However self.prompt will still be updated and display immediately after the multiline
@@ -3971,9 +3977,9 @@ def set_window_title(self, title: str) -> None: # pragma: no cover
39713977
39723978 Raises a `RuntimeError` if called while another thread holds `terminal_lock`.
39733979
3974- IMPORTANT: This function will not set the title unless it can acquire self.terminal_lock to avoid
3975- writing to stderr while a command is running. Therefore it is best to acquire the lock
3976- before calling this function to guarantee the title changes.
3980+ IMPORTANT: This function will not set the title unless it can acquire self.terminal_lock to avoid writing
3981+ to stderr while a command is running. Therefore it is best to acquire the lock before calling
3982+ this function to guarantee the title changes and to avoid raising a RuntimeError .
39773983
39783984 :param title: the new window title
39793985 """
0 commit comments