Skip to content

Commit 6460d57

Browse files
committed
Made following changes to onecmd_plus_hooks()
1. Added SystemExit handling by warning the user it's occured and setting stop to True 2. KeyboardInterrupts won't be raised if stop is already set to True.
1 parent c50db52 commit 6460d57

File tree

2 files changed

+29
-21
lines changed

2 files changed

+29
-21
lines changed

cmd2/cmd2.py

Lines changed: 25 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -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,37 @@ 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
16731670
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+
self.pwarning("Caught SystemExit. Attempting to stop command loop...")
1682+
stop = True
16801683
except Exception as ex:
16811684
self.pexcept(ex)
16821685
finally:
1683-
stop = self._run_cmdfinalization_hooks(stop, statement)
1686+
try:
1687+
stop = self._run_cmdfinalization_hooks(stop, statement)
1688+
except KeyboardInterrupt as ex:
1689+
if raise_keyboard_interrupt and not stop:
1690+
raise ex
1691+
except SystemExit:
1692+
self.pwarning("Caught SystemExit. Attempting to stop command loop...")
1693+
stop = True
1694+
except Exception as ex:
1695+
self.pexcept(ex)
16841696

16851697
return stop
16861698

16871699
def _run_cmdfinalization_hooks(self, stop: bool, statement: Optional[Statement]) -> bool:
16881700
"""Run the command finalization hooks"""
1689-
16901701
with self.sigint_protection:
16911702
if not sys.platform.startswith('win') and self.stdin.isatty():
16921703
# Before the next command runs, fix any terminal problems like those
@@ -1695,15 +1706,12 @@ def _run_cmdfinalization_hooks(self, stop: bool, statement: Optional[Statement])
16951706
proc = subprocess.Popen(['stty', 'sane'])
16961707
proc.communicate()
16971708

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)
1709+
data = plugin.CommandFinalizationData(stop, statement)
1710+
for func in self._cmdfinalization_hooks:
1711+
data = func(data)
1712+
# retrieve the final value of stop, ignoring any
1713+
# modifications to the statement
1714+
return data.stop
17071715

17081716
def runcmds_plus_hooks(self, cmds: List[Union[HistoryItem, str]], *, add_to_history: bool = True,
17091717
stop_on_keyboard_interrupt: bool = True) -> bool:

cmd2/exceptions.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,10 @@ class SkipPostcommandHooks(Exception):
1616

1717
class Cmd2ArgparseError(SkipPostcommandHooks):
1818
"""
19-
A ``SkipPostcommandHooks`` exception for when a command fails parsing its arguments.
20-
This is raised by argparse decorators but can also be raised by command functions.
21-
If a command function still needs to run post command hooks when parsing fails,
22-
just return instead of raising an exception.
19+
A ``SkipPostcommandHooks`` exception for when a command fails to parse its arguments.
20+
Normally argparse raises a SystemExit exception in these cases. To avoid stopping the command
21+
loop, catch the SystemExit and raise this instead. If you still need to run post command hooks
22+
after parsing fails, just return instead of raising an exception.
2323
"""
2424
pass
2525

0 commit comments

Comments
 (0)