diff options
author | Kevin Van Brunt <kmvanbrunt@gmail.com> | 2021-03-23 14:31:04 -0400 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-03-23 14:31:04 -0400 |
commit | d8c3c7c7eee472f89ace3e77f80825a0ce3df85f (patch) | |
tree | 3a80de210c8fc8fe49a0597e7b45bd638699a231 | |
parent | fabe4cd01b339d628ffd0b8d9b202a4a41555b8b (diff) | |
parent | 3126eb792816e09ce56f24262447077df1bdc0c3 (diff) | |
download | cmd2-git-d8c3c7c7eee472f89ace3e77f80825a0ce3df85f.tar.gz |
Merge pull request #1078 from python-cmd2/exit_code
onecmd_plus_hooks() now sets self.exit_code when a SystemExit handled
-rw-r--r-- | CHANGELOG.md | 4 | ||||
-rw-r--r-- | cmd2/cmd2.py | 10 | ||||
-rw-r--r-- | docs/features/commands.rst | 5 | ||||
-rwxr-xr-x | examples/exit_code.py | 2 | ||||
-rwxr-xr-x | examples/pirate.py | 2 | ||||
-rwxr-xr-x | tests/test_cmd2.py | 7 | ||||
-rw-r--r-- | tests/test_plugin.py | 3 |
7 files changed, 23 insertions, 10 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md index 9f1739c6..4f3b9472 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -21,6 +21,7 @@ * Settables now have new initialization parameters. It is now a required parameter to supply the reference to the object that holds the settable attribute. `cmd2.Cmd.settables` is no longer a public dict attribute - it is now a property that aggregates all Settables across all registered CommandSets. + * Failed transcript testing now sets self.exit_code to 1 instead of -1. * Enhancements * Added support for custom tab completion and up-arrow input history to `cmd2.Cmd2.read_input`. See [read_input.py](https://github.com/python-cmd2/cmd2/blob/master/examples/read_input.py) @@ -34,6 +35,9 @@ may have a prepended prefix. * Settables now allow changes to be applied to any arbitrary object attribute. It no longer needs to match an attribute added to the cmd2 instance itself. + * Raising ``SystemExit`` or calling ``sys.exit()`` in a command or hook function will set ``self.exit_code`` + to the exit code used in those calls. It will also result in the command loop stopping. + ## 1.5.0 (January 31, 2021) * Bug Fixes * Fixed bug where setting `always_show_hint=True` did not show a hint when completing `Settables` diff --git a/cmd2/cmd2.py b/cmd2/cmd2.py index f7188cb4..68ad8201 100644 --- a/cmd2/cmd2.py +++ b/cmd2/cmd2.py @@ -2362,7 +2362,8 @@ class Cmd(cmd.Cmd): except KeyboardInterrupt as ex: if raise_keyboard_interrupt and not stop: raise ex - except SystemExit: + except SystemExit as ex: + self.exit_code = ex.code stop = True except PassThroughException as ex: raise ex.wrapped_ex @@ -2374,7 +2375,8 @@ class Cmd(cmd.Cmd): except KeyboardInterrupt as ex: if raise_keyboard_interrupt and not stop: raise ex - except SystemExit: + except SystemExit as ex: + self.exit_code = ex.code stop = True except PassThroughException as ex: raise ex.wrapped_ex @@ -4748,7 +4750,7 @@ class Cmd(cmd.Cmd): transcripts_expanded = utils.files_from_glob_patterns(transcript_paths, access=os.R_OK) if not transcripts_expanded: self.perror('No test files found - nothing to test') - self.exit_code = -1 + self.exit_code = 1 return verinfo = ".".join(map(str, sys.version_info[:3])) @@ -4785,7 +4787,7 @@ class Cmd(cmd.Cmd): self.perror(error_str[start:]) # Return a failure error code to support automated transcript-based testing - self.exit_code = -1 + self.exit_code = 1 def async_alert(self, alert_msg: str, new_prompt: Optional[str] = None) -> None: # pragma: no cover """ diff --git a/docs/features/commands.rst b/docs/features/commands.rst index cc603f70..66745469 100644 --- a/docs/features/commands.rst +++ b/docs/features/commands.rst @@ -142,7 +142,7 @@ The ``cmd2.Cmd`` object sets an ``exit_code`` attribute to zero when it is instantiated. The value of this attribute is returned from the ``cmdloop()`` call. Therefore, if you don't do anything with this attribute in your code, ``cmdloop()`` will (almost) always return zero. There are a few built-in -``cmd2`` commands which set ``exit_code`` to ``-1`` if an error occurs. +``cmd2`` commands which set ``exit_code`` to ``1`` if an error occurs. You can use this capability to easily return your own values to the operating system shell:: @@ -175,6 +175,9 @@ the following interaction:: 2 +Raising ``SystemExit(code)`` or calling ``sys.exit(code)`` in a command +or hook function also sets ``self.exit_code`` and stops the program. + Exception Handling ------------------ diff --git a/examples/exit_code.py b/examples/exit_code.py index 80cef62f..440fc595 100755 --- a/examples/exit_code.py +++ b/examples/exit_code.py @@ -28,7 +28,7 @@ class ReplWithExitCode(cmd2.Cmd): self.exit_code = int(arg_list[0]) except ValueError: self.perror("{} isn't a valid integer exit code".format(arg_list[0])) - self.exit_code = -1 + self.exit_code = 1 return True diff --git a/examples/pirate.py b/examples/pirate.py index f91b99d7..3a9b7b36 100755 --- a/examples/pirate.py +++ b/examples/pirate.py @@ -46,7 +46,7 @@ class Pirate(cmd2.Cmd): self.poutput('Now we gots {0} doubloons'.format(self.gold)) if self.gold < 0: self.poutput("Off to debtorrr's prison.") - self.exit_code = -1 + self.exit_code = 1 stop = True return stop diff --git a/tests/test_cmd2.py b/tests/test_cmd2.py index 91815d50..44d2b304 100755 --- a/tests/test_cmd2.py +++ b/tests/test_cmd2.py @@ -537,13 +537,16 @@ def test_system_exit_in_command(base_app, capsys): """Test raising SystemExit in a command""" import types + exit_code = 5 + def do_system_exit(self, _): - raise SystemExit + raise SystemExit(exit_code) setattr(base_app, 'do_system_exit', types.MethodType(do_system_exit, base_app)) stop = base_app.onecmd_plus_hooks('system_exit') assert stop + assert base_app.exit_code == exit_code def test_passthrough_exception_in_command(base_app): @@ -2323,7 +2326,7 @@ class ReplWithExitCode(cmd2.Cmd): self.exit_code = int(arg_list[0]) except ValueError: self.perror("{} isn't a valid integer exit code".format(arg_list[0])) - self.exit_code = -1 + self.exit_code = 1 # Return True to stop the command loop return True diff --git a/tests/test_plugin.py b/tests/test_plugin.py index 1e12d655..61b140ab 100644 --- a/tests/test_plugin.py +++ b/tests/test_plugin.py @@ -229,7 +229,7 @@ class Plugin: ) -> cmd2.plugin.CommandFinalizationData: """A command finalization hook which raises a SystemExit""" self.called_cmdfinalization += 1 - raise SystemExit + raise SystemExit(5) def cmdfinalization_hook_keyboard_interrupt( self, data: cmd2.plugin.CommandFinalizationData @@ -930,6 +930,7 @@ def test_cmdfinalization_hook_system_exit(): stop = app.onecmd_plus_hooks('say hello') assert stop assert app.called_cmdfinalization == 1 + assert app.exit_code == 5 def test_cmdfinalization_hook_keyboard_interrupt(): |