diff options
author | Todd Leonhardt <todd.leonhardt@gmail.com> | 2019-02-06 20:18:26 -0500 |
---|---|---|
committer | GitHub <noreply@github.com> | 2019-02-06 20:18:26 -0500 |
commit | 911d9651dd5370f4432b45ba1e481309d01178d5 (patch) | |
tree | bb6b61e6b3e0faae41e66be167d7ca7e6dc79734 | |
parent | 7d93134ff806a1adb2af55343dc69dcddb4c110c (diff) | |
parent | 555f023c6a494a867d75959276c8a4c0746f2fbb (diff) | |
download | cmd2-git-911d9651dd5370f4432b45ba1e481309d01178d5.tar.gz |
Merge pull request #623 from python-cmd2/pyscript_quit
Fixed issue where calling exit() or quit() from a pyscript would close the whole console
-rw-r--r-- | CHANGELOG.md | 5 | ||||
-rw-r--r-- | cmd2/cmd2.py | 63 | ||||
-rw-r--r-- | examples/scripts/conditional.py | 4 |
3 files changed, 46 insertions, 26 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md index 58813e41..fc91dfbf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,7 +1,10 @@ -## 0.9.8 (TBD, 2019) +## 0.9.8 (February 06, 2019) * Bug Fixes * Fixed issue with echoing strings in StdSim. Because they were being sent to a binary buffer, line buffering was being ignored. +* Enhancements + * Made quit() and exit() functions available to scripts run with pyscript. This allows those scripts to exit + back to the console's prompt instead of exiting the whole application. ## 0.9.7 (January 08, 2019) * Bug Fixes diff --git a/cmd2/cmd2.py b/cmd2/cmd2.py index cbb79323..c690aef9 100644 --- a/cmd2/cmd2.py +++ b/cmd2/cmd2.py @@ -2957,14 +2957,13 @@ class Cmd(cmd.Cmd): self.perror(err, traceback_war=False) self._last_result = CommandResult('', err) return False - self._in_py = True - # noinspection PyBroadException try: + self._in_py = True + # Support the run command even if called prior to invoking an interactive interpreter - def run(filename: str): + def py_run(filename: str): """Run a Python script file in the interactive console. - :param filename: filename of *.py script file to run """ expanded_filename = os.path.expanduser(filename) @@ -2979,9 +2978,16 @@ class Cmd(cmd.Cmd): error_msg = "Error opening script file '{}': {}".format(expanded_filename, ex) self.perror(error_msg, traceback_war=False) + def py_quit(): + """Function callable from the interactive Python console to exit that environment""" + raise EmbeddedConsoleExit + + # Set up Python environment bridge = PyscriptBridge(self) - self.pystate['run'] = run self.pystate[self.pyscript_name] = bridge + self.pystate['run'] = py_run + self.pystate['quit'] = py_quit + self.pystate['exit'] = py_quit if self.locals_in_py: self.pystate['self'] = self @@ -3002,18 +3008,16 @@ class Cmd(cmd.Cmd): # Set cmd_echo to True so PyscriptBridge statements like: py app('help') # run at the command line will print their output. bridge.cmd_echo = True - interp.runcode(full_command) + + # noinspection PyBroadException + try: + interp.runcode(full_command) + except BaseException: + # We don't care about any exception that happened in the interactive console + pass # If there are no args, then we will open an interactive Python console else: - # noinspection PyShadowingBuiltins - def quit(): - """Function callable from the interactive Python console to exit that environment""" - raise EmbeddedConsoleExit - - self.pystate['quit'] = quit - self.pystate['exit'] = quit - # Set up readline for Python console if rl_type != RlType.NONE: # Save cmd2 history @@ -3072,10 +3076,12 @@ class Cmd(cmd.Cmd): 'Run Python code from external script files with: run("script.py")' .format(self.pyscript_name)) + # noinspection PyBroadException try: interp.interact(banner="Python {} on {}\n{}\n\n{}\n". format(sys.version, sys.platform, cprt, instructions)) - except EmbeddedConsoleExit: + except BaseException: + # We don't care about any exception that happened in the interactive console pass finally: @@ -3109,10 +3115,12 @@ class Cmd(cmd.Cmd): else: sys.modules['readline'] = saved_readline - except Exception: + except KeyboardInterrupt: pass + finally: self._in_py = False + return self._should_quit pyscript_parser = ACArgumentParser() @@ -3123,21 +3131,30 @@ class Cmd(cmd.Cmd): ACTION_ARG_CHOICES, ('path_complete',)) @with_argparser(pyscript_parser) - def do_pyscript(self, args: argparse.Namespace) -> None: + def do_pyscript(self, args: argparse.Namespace) -> bool: """Run a Python script file inside the console""" script_path = os.path.expanduser(args.script_path) + py_return = False # Save current command line arguments orig_args = sys.argv - # Overwrite sys.argv to allow the script to take command line arguments - sys.argv = [script_path] + args.script_arguments + try: + # Overwrite sys.argv to allow the script to take command line arguments + sys.argv = [script_path] + args.script_arguments + + # Run the script - use repr formatting to escape things which + # need to be escaped to prevent issues on Windows + py_return = self.do_py("run({!r})".format(script_path)) - # Run the script - use repr formatting to escape things which need to be escaped to prevent issues on Windows - self.do_py("run({!r})".format(script_path)) + except KeyboardInterrupt: + pass + + finally: + # Restore command line arguments to original state + sys.argv = orig_args - # Restore command line arguments to original state - sys.argv = orig_args + return py_return # Only include the do_ipy() method if IPython is available on the system if ipython_available: # pragma: no cover diff --git a/examples/scripts/conditional.py b/examples/scripts/conditional.py index faac3947..8a4f14de 100644 --- a/examples/scripts/conditional.py +++ b/examples/scripts/conditional.py @@ -7,8 +7,8 @@ To run it you should do the following: ./python_scripting.py pyscript scripts/conditional.py directory_path -Note: The "cmd" function is defined within the cmd2 embedded Python environment and in there "self" is your cmd2 -application instance. +Note: The "app" function is defined within the cmd2 embedded Python environment and in there "self" is your cmd2 +application instance. Note: self only exists in this environment if locals_in_py is True. """ import os import sys |