diff options
| author | Kevin Van Brunt <kmvanbrunt@gmail.com> | 2021-03-24 13:39:54 -0400 |
|---|---|---|
| committer | Kevin Van Brunt <kmvanbrunt@gmail.com> | 2021-03-24 16:33:27 -0400 |
| commit | fc3c9b9e17e3cb89f771cc618517ebd968730938 (patch) | |
| tree | fabbd6858c6090c78e80a037b3fbfdfd13f02123 | |
| parent | ae03c59de609878e068920380667c5fd45f26650 (diff) | |
| download | cmd2-git-fc3c9b9e17e3cb89f771cc618517ebd968730938.tar.gz | |
Removed ipy's access to the CLI's globals() dictionary
| -rw-r--r-- | cmd2/cmd2.py | 55 | ||||
| -rw-r--r-- | docs/features/embedded_python_shells.rst | 13 |
2 files changed, 33 insertions, 35 deletions
diff --git a/cmd2/cmd2.py b/cmd2/cmd2.py index b6c44eb3..b04b7771 100644 --- a/cmd2/cmd2.py +++ b/cmd2/cmd2.py @@ -168,7 +168,7 @@ ipython_available = True try: # noinspection PyUnresolvedReferences,PyPackageRequirements from IPython import ( # type: ignore[import] - embed, + start_ipython, ) except ImportError: # pragma: no cover ipython_available = False @@ -4197,34 +4197,21 @@ class Cmd(cmd.Cmd): :return: True if running of commands should stop """ + # noinspection PyPackageRequirements + from IPython.terminal.interactiveshell import ( + TerminalInteractiveShell, + ) + from IPython.terminal.ipapp import ( + TerminalIPythonApp, + ) + from traitlets.config.loader import ( + Config as TraitletsConfig, + ) + from .py_bridge import ( PyBridge, ) - def load_ipy(ipy_locals: Dict[str, Any]) -> None: - """ - Embed an IPython shell in an environment that is restricted to only the variables in this function - - :param ipy_locals: locals dictionary for the IPython environment - """ - # Copy ipy_locals into this function's locals - for key, val in ipy_locals.items(): - locals()[key] = val - - # Delete these names from the environment so IPython won't see them - del key - del val - del ipy_locals - - # Start ipy shell - embed( - banner1=( - 'Entering an embedded IPython shell. Type quit or <Ctrl>-d to exit.\n' - 'Run Python code from external files with: run filename.py\n' - ), - exit_msg='Leaving IPython, back to {}'.format(sys.argv[0]), - ) - if self.in_pyscript(): self.perror("Recursively entering interactive Python shells is not allowed") return @@ -4241,7 +4228,23 @@ class Cmd(cmd.Cmd): if self.self_in_py: local_vars['self'] = self - load_ipy(local_vars) + # Configure IPython + config = TraitletsConfig() + config.InteractiveShell.banner2 = ( + 'Entering an embedded IPython shell. Type quit or <Ctrl>-d to exit.\n' + 'Run Python code from external files with: run filename.py\n' + ) + + # Start IPython + start_ipython(config=config, argv=[], user_ns=local_vars) + + # The IPython application is a singleton and won't be recreated next time + # this function runs. That's a problem since the contents of local_vars + # may need to be changed. Therefore we must destroy all instances of the + # relevant classes. + TerminalIPythonApp.clear_instance() + TerminalInteractiveShell.clear_instance() + return py_bridge.stop finally: self._in_py = False diff --git a/docs/features/embedded_python_shells.rst b/docs/features/embedded_python_shells.rst index 71fb8197..cbedf992 100644 --- a/docs/features/embedded_python_shells.rst +++ b/docs/features/embedded_python_shells.rst @@ -12,6 +12,9 @@ You may optionally enable full access to to your application by setting python session, which is a reference to your ``cmd2`` application. This can be useful for debugging your application. +Any local or global variable created within the Python session will not persist +in the CLI's environment. + Anything in ``self.py_locals`` is always available in the Python environment. The ``app`` object (or your custom name) provides access to application @@ -48,14 +51,6 @@ More Python examples: >>> quit() Python was here > -Using the ``py`` command is tightly integrated with your main ``cmd2`` -application and any variables created or changed will persist for the life of -the application:: - - (Cmd) py x = 5 - (Cmd) py print(x) - 5 - The ``py`` command also allows you to run Python scripts via ``py run('myscript.py')``. This provides a more complicated and more powerful scripting capability than that provided by the simple text file scripts @@ -113,7 +108,7 @@ The ``ipy`` command enters an interactive IPython_ session. Similar to an interactive Python session, this shell can access your application instance via ``self`` if ``self.self_in_py`` is ``True`` and any changes to your application made via ``self`` will persist. However, any local or global variable created -within the ``ipy`` shell will not persist. +within the ``ipy`` shell will not persist in the CLI's environment Also, as in the interactive Python session, the ``ipy`` shell has access to the contents of ``self.py_locals`` and can call back into the application using the |
