summaryrefslogtreecommitdiffstats
path: root/contrib/python/ipython/py2/IPython/terminal
diff options
context:
space:
mode:
authorDevtools Arcadia <[email protected]>2022-02-07 18:08:42 +0300
committerDevtools Arcadia <[email protected]>2022-02-07 18:08:42 +0300
commit1110808a9d39d4b808aef724c861a2e1a38d2a69 (patch)
treee26c9fed0de5d9873cce7e00bc214573dc2195b7 /contrib/python/ipython/py2/IPython/terminal
intermediate changes
ref:cde9a383711a11544ce7e107a78147fb96cc4029
Diffstat (limited to 'contrib/python/ipython/py2/IPython/terminal')
-rw-r--r--contrib/python/ipython/py2/IPython/terminal/__init__.py0
-rw-r--r--contrib/python/ipython/py2/IPython/terminal/console.py19
-rw-r--r--contrib/python/ipython/py2/IPython/terminal/debugger.py114
-rw-r--r--contrib/python/ipython/py2/IPython/terminal/embed.py395
-rw-r--r--contrib/python/ipython/py2/IPython/terminal/interactiveshell.py552
-rwxr-xr-xcontrib/python/ipython/py2/IPython/terminal/ipapp.py377
-rw-r--r--contrib/python/ipython/py2/IPython/terminal/magics.py208
-rw-r--r--contrib/python/ipython/py2/IPython/terminal/prompts.py80
-rw-r--r--contrib/python/ipython/py2/IPython/terminal/pt_inputhooks/__init__.py49
-rw-r--r--contrib/python/ipython/py2/IPython/terminal/pt_inputhooks/glut.py141
-rw-r--r--contrib/python/ipython/py2/IPython/terminal/pt_inputhooks/gtk.py59
-rw-r--r--contrib/python/ipython/py2/IPython/terminal/pt_inputhooks/gtk3.py12
-rw-r--r--contrib/python/ipython/py2/IPython/terminal/pt_inputhooks/osx.py137
-rw-r--r--contrib/python/ipython/py2/IPython/terminal/pt_inputhooks/pyglet.py68
-rw-r--r--contrib/python/ipython/py2/IPython/terminal/pt_inputhooks/qt.py49
-rw-r--r--contrib/python/ipython/py2/IPython/terminal/pt_inputhooks/tk.py95
-rw-r--r--contrib/python/ipython/py2/IPython/terminal/pt_inputhooks/wx.py148
-rw-r--r--contrib/python/ipython/py2/IPython/terminal/ptshell.py8
-rw-r--r--contrib/python/ipython/py2/IPython/terminal/ptutils.py115
-rw-r--r--contrib/python/ipython/py2/IPython/terminal/shortcuts.py206
20 files changed, 2832 insertions, 0 deletions
diff --git a/contrib/python/ipython/py2/IPython/terminal/__init__.py b/contrib/python/ipython/py2/IPython/terminal/__init__.py
new file mode 100644
index 00000000000..e69de29bb2d
--- /dev/null
+++ b/contrib/python/ipython/py2/IPython/terminal/__init__.py
diff --git a/contrib/python/ipython/py2/IPython/terminal/console.py b/contrib/python/ipython/py2/IPython/terminal/console.py
new file mode 100644
index 00000000000..65571a7572d
--- /dev/null
+++ b/contrib/python/ipython/py2/IPython/terminal/console.py
@@ -0,0 +1,19 @@
+"""
+Shim to maintain backwards compatibility with old IPython.terminal.console imports.
+"""
+# Copyright (c) IPython Development Team.
+# Distributed under the terms of the Modified BSD License.
+
+import sys
+from warnings import warn
+
+from IPython.utils.shimmodule import ShimModule, ShimWarning
+
+warn("The `IPython.terminal.console` package has been deprecated since IPython 4.0. "
+ "You should import from jupyter_console instead.", ShimWarning)
+
+# Unconditionally insert the shim into sys.modules so that further import calls
+# trigger the custom attribute access above
+
+sys.modules['IPython.terminal.console'] = ShimModule(
+ src='IPython.terminal.console', mirror='jupyter_console')
diff --git a/contrib/python/ipython/py2/IPython/terminal/debugger.py b/contrib/python/ipython/py2/IPython/terminal/debugger.py
new file mode 100644
index 00000000000..c68a3204a68
--- /dev/null
+++ b/contrib/python/ipython/py2/IPython/terminal/debugger.py
@@ -0,0 +1,114 @@
+import signal
+import sys
+
+from IPython.core.debugger import Pdb
+
+from IPython.core.completer import IPCompleter
+from .ptutils import IPythonPTCompleter
+from .shortcuts import suspend_to_bg, cursor_in_leading_ws
+
+from prompt_toolkit.enums import DEFAULT_BUFFER
+from prompt_toolkit.filters import (Condition, HasFocus, HasSelection,
+ ViInsertMode, EmacsInsertMode)
+from prompt_toolkit.keys import Keys
+from prompt_toolkit.key_binding.manager import KeyBindingManager
+from prompt_toolkit.key_binding.bindings.completion import display_completions_like_readline
+from prompt_toolkit.token import Token
+from prompt_toolkit.shortcuts import create_prompt_application
+from prompt_toolkit.interface import CommandLineInterface
+from prompt_toolkit.enums import EditingMode
+
+
+class TerminalPdb(Pdb):
+ def __init__(self, *args, **kwargs):
+ Pdb.__init__(self, *args, **kwargs)
+ self._ptcomp = None
+ self.pt_init()
+
+ def pt_init(self):
+ def get_prompt_tokens(cli):
+ return [(Token.Prompt, self.prompt)]
+
+ def patch_stdout(**kwargs):
+ return self.pt_cli.patch_stdout_context(**kwargs)
+
+ if self._ptcomp is None:
+ compl = IPCompleter(shell=self.shell,
+ namespace={},
+ global_namespace={},
+ use_readline=False,
+ parent=self.shell,
+ )
+ self._ptcomp = IPythonPTCompleter(compl, patch_stdout=patch_stdout)
+
+ kbmanager = KeyBindingManager.for_prompt()
+ supports_suspend = Condition(lambda cli: hasattr(signal, 'SIGTSTP'))
+ kbmanager.registry.add_binding(Keys.ControlZ, filter=supports_suspend
+ )(suspend_to_bg)
+
+ if self.shell.display_completions == 'readlinelike':
+ kbmanager.registry.add_binding(Keys.ControlI,
+ filter=(HasFocus(DEFAULT_BUFFER)
+ & ~HasSelection()
+ & ViInsertMode() | EmacsInsertMode()
+ & ~cursor_in_leading_ws
+ ))(display_completions_like_readline)
+ multicolumn = (self.shell.display_completions == 'multicolumn')
+
+ self._pt_app = create_prompt_application(
+ editing_mode=getattr(EditingMode, self.shell.editing_mode.upper()),
+ key_bindings_registry=kbmanager.registry,
+ history=self.shell.debugger_history,
+ completer= self._ptcomp,
+ enable_history_search=True,
+ mouse_support=self.shell.mouse_support,
+ get_prompt_tokens=get_prompt_tokens,
+ display_completions_in_columns=multicolumn,
+ style=self.shell.style
+ )
+ self.pt_cli = CommandLineInterface(self._pt_app, eventloop=self.shell._eventloop)
+
+ def cmdloop(self, intro=None):
+ """Repeatedly issue a prompt, accept input, parse an initial prefix
+ off the received input, and dispatch to action methods, passing them
+ the remainder of the line as argument.
+
+ override the same methods from cmd.Cmd to provide prompt toolkit replacement.
+ """
+ if not self.use_rawinput:
+ raise ValueError('Sorry ipdb does not support use_rawinput=False')
+
+ self.preloop()
+
+ try:
+ if intro is not None:
+ self.intro = intro
+ if self.intro:
+ self.stdout.write(str(self.intro)+"\n")
+ stop = None
+ while not stop:
+ if self.cmdqueue:
+ line = self.cmdqueue.pop(0)
+ else:
+ self._ptcomp.ipy_completer.namespace = self.curframe_locals
+ self._ptcomp.ipy_completer.global_namespace = self.curframe.f_globals
+ try:
+ line = self.pt_cli.run(reset_current_buffer=True).text
+ except EOFError:
+ line = 'EOF'
+ line = self.precmd(line)
+ stop = self.onecmd(line)
+ stop = self.postcmd(stop, line)
+ self.postloop()
+ except Exception:
+ raise
+
+
+def set_trace(frame=None):
+ """
+ Start debugging from `frame`.
+
+ If frame is not specified, debugging starts from caller's frame.
+ """
+ TerminalPdb().set_trace(frame or sys._getframe().f_back)
+
diff --git a/contrib/python/ipython/py2/IPython/terminal/embed.py b/contrib/python/ipython/py2/IPython/terminal/embed.py
new file mode 100644
index 00000000000..5ad70431e42
--- /dev/null
+++ b/contrib/python/ipython/py2/IPython/terminal/embed.py
@@ -0,0 +1,395 @@
+# encoding: utf-8
+"""
+An embedded IPython shell.
+"""
+# Copyright (c) IPython Development Team.
+# Distributed under the terms of the Modified BSD License.
+
+from __future__ import with_statement
+from __future__ import print_function
+
+import sys
+import warnings
+
+from IPython.core import ultratb, compilerop
+from IPython.core import magic_arguments
+from IPython.core.magic import Magics, magics_class, line_magic
+from IPython.core.interactiveshell import DummyMod, InteractiveShell
+from IPython.terminal.interactiveshell import TerminalInteractiveShell
+from IPython.terminal.ipapp import load_default_config
+
+from traitlets import Bool, CBool, Unicode
+from IPython.utils.io import ask_yes_no
+
+class KillEmbeded(Exception):pass
+
+# This is an additional magic that is exposed in embedded shells.
+@magics_class
+class EmbeddedMagics(Magics):
+
+ @line_magic
+ @magic_arguments.magic_arguments()
+ @magic_arguments.argument('-i', '--instance', action='store_true',
+ help='Kill instance instead of call location')
+ @magic_arguments.argument('-x', '--exit', action='store_true',
+ help='Also exit the current session')
+ @magic_arguments.argument('-y', '--yes', action='store_true',
+ help='Do not ask confirmation')
+ def kill_embedded(self, parameter_s=''):
+ """%kill_embedded : deactivate for good the current embedded IPython
+
+ This function (after asking for confirmation) sets an internal flag so
+ that an embedded IPython will never activate again for the given call
+ location. This is useful to permanently disable a shell that is being
+ called inside a loop: once you've figured out what you needed from it,
+ you may then kill it and the program will then continue to run without
+ the interactive shell interfering again.
+
+
+ Kill Instance Option
+ --------------------
+
+ If for some reasons you need to kill the location where the instance is
+ created and not called, for example if you create a single instance in
+ one place and debug in many locations, you can use the ``--instance``
+ option to kill this specific instance. Like for the ``call location``
+ killing an "instance" should work even if it is recreated within a
+ loop.
+
+ .. note::
+
+ This was the default behavior before IPython 5.2
+
+ """
+
+ args = magic_arguments.parse_argstring(self.kill_embedded, parameter_s)
+ print(args)
+ if args.instance:
+ # let no ask
+ if not args.yes:
+ kill = ask_yes_no(
+ "Are you sure you want to kill this embedded instance? [y/N] ", 'n')
+ else:
+ kill = True
+ if kill:
+ self.shell._disable_init_location()
+ print("This embedded IPython instance will not reactivate anymore "
+ "once you exit.")
+ else:
+ if not args.yes:
+ kill = ask_yes_no(
+ "Are you sure you want to kill this embedded call_location? [y/N] ", 'n')
+ else:
+ kill = True
+ if kill:
+ self.shell.embedded_active = False
+ print("This embedded IPython call location will not reactivate anymore "
+ "once you exit.")
+
+ if args.exit:
+ # Ask-exit does not really ask, it just set internals flags to exit
+ # on next loop.
+ self.shell.ask_exit()
+
+
+ @line_magic
+ def exit_raise(self, parameter_s=''):
+ """%exit_raise Make the current embedded kernel exit and raise and exception.
+
+ This function sets an internal flag so that an embedded IPython will
+ raise a `IPython.terminal.embed.KillEmbeded` Exception on exit, and then exit the current I. This is
+ useful to permanently exit a loop that create IPython embed instance.
+ """
+
+ self.shell.should_raise = True
+ self.shell.ask_exit()
+
+
+
+class InteractiveShellEmbed(TerminalInteractiveShell):
+
+ dummy_mode = Bool(False)
+ exit_msg = Unicode('')
+ embedded = CBool(True)
+ should_raise = CBool(False)
+ # Like the base class display_banner is not configurable, but here it
+ # is True by default.
+ display_banner = CBool(True)
+ exit_msg = Unicode()
+
+ # When embedding, by default we don't change the terminal title
+ term_title = Bool(False,
+ help="Automatically set the terminal title"
+ ).tag(config=True)
+
+ _inactive_locations = set()
+
+ @property
+ def embedded_active(self):
+ return (self._call_location_id not in InteractiveShellEmbed._inactive_locations)\
+ and (self._init_location_id not in InteractiveShellEmbed._inactive_locations)
+
+ def _disable_init_location(self):
+ """Disable the current Instance creation location"""
+ InteractiveShellEmbed._inactive_locations.add(self._init_location_id)
+
+ @embedded_active.setter
+ def embedded_active(self, value):
+ if value:
+ InteractiveShellEmbed._inactive_locations.discard(
+ self._call_location_id)
+ InteractiveShellEmbed._inactive_locations.discard(
+ self._init_location_id)
+ else:
+ InteractiveShellEmbed._inactive_locations.add(
+ self._call_location_id)
+
+ def __init__(self, **kw):
+ if kw.get('user_global_ns', None) is not None:
+ raise DeprecationWarning(
+ "Key word argument `user_global_ns` has been replaced by `user_module` since IPython 4.0.")
+
+ clid = kw.pop('_init_location_id', None)
+ if not clid:
+ frame = sys._getframe(1)
+ clid = '%s:%s' % (frame.f_code.co_filename, frame.f_lineno)
+ self._init_location_id = clid
+
+ super(InteractiveShellEmbed,self).__init__(**kw)
+
+ # don't use the ipython crash handler so that user exceptions aren't
+ # trapped
+ sys.excepthook = ultratb.FormattedTB(color_scheme=self.colors,
+ mode=self.xmode,
+ call_pdb=self.pdb)
+
+ def init_sys_modules(self):
+ """
+ Explicitly overwrite :mod:`IPython.core.interactiveshell` to do nothing.
+ """
+ pass
+
+ def init_magics(self):
+ super(InteractiveShellEmbed, self).init_magics()
+ self.register_magics(EmbeddedMagics)
+
+ def __call__(self, header='', local_ns=None, module=None, dummy=None,
+ stack_depth=1, global_ns=None, compile_flags=None, **kw):
+ """Activate the interactive interpreter.
+
+ __call__(self,header='',local_ns=None,module=None,dummy=None) -> Start
+ the interpreter shell with the given local and global namespaces, and
+ optionally print a header string at startup.
+
+ The shell can be globally activated/deactivated using the
+ dummy_mode attribute. This allows you to turn off a shell used
+ for debugging globally.
+
+ However, *each* time you call the shell you can override the current
+ state of dummy_mode with the optional keyword parameter 'dummy'. For
+ example, if you set dummy mode on with IPShell.dummy_mode = True, you
+ can still have a specific call work by making it as IPShell(dummy=False).
+ """
+
+ # we are called, set the underlying interactiveshell not to exit.
+ self.keep_running = True
+
+ # If the user has turned it off, go away
+ clid = kw.pop('_call_location_id', None)
+ if not clid:
+ frame = sys._getframe(1)
+ clid = '%s:%s' % (frame.f_code.co_filename, frame.f_lineno)
+ self._call_location_id = clid
+
+ if not self.embedded_active:
+ return
+
+ # Normal exits from interactive mode set this flag, so the shell can't
+ # re-enter (it checks this variable at the start of interactive mode).
+ self.exit_now = False
+
+ # Allow the dummy parameter to override the global __dummy_mode
+ if dummy or (dummy != 0 and self.dummy_mode):
+ return
+
+ # self.banner is auto computed
+ if header:
+ self.old_banner2 = self.banner2
+ self.banner2 = self.banner2 + '\n' + header + '\n'
+ else:
+ self.old_banner2 = ''
+
+ if self.display_banner:
+ self.show_banner()
+
+ # Call the embedding code with a stack depth of 1 so it can skip over
+ # our call and get the original caller's namespaces.
+ self.mainloop(local_ns, module, stack_depth=stack_depth,
+ global_ns=global_ns, compile_flags=compile_flags)
+
+ self.banner2 = self.old_banner2
+
+ if self.exit_msg is not None:
+ print(self.exit_msg)
+
+ if self.should_raise:
+ raise KillEmbeded('Embedded IPython raising error, as user requested.')
+
+
+ def mainloop(self, local_ns=None, module=None, stack_depth=0,
+ display_banner=None, global_ns=None, compile_flags=None):
+ """Embeds IPython into a running python program.
+
+ Parameters
+ ----------
+
+ local_ns, module
+ Working local namespace (a dict) and module (a module or similar
+ object). If given as None, they are automatically taken from the scope
+ where the shell was called, so that program variables become visible.
+
+ stack_depth : int
+ How many levels in the stack to go to looking for namespaces (when
+ local_ns or module is None). This allows an intermediate caller to
+ make sure that this function gets the namespace from the intended
+ level in the stack. By default (0) it will get its locals and globals
+ from the immediate caller.
+
+ compile_flags
+ A bit field identifying the __future__ features
+ that are enabled, as passed to the builtin :func:`compile` function.
+ If given as None, they are automatically taken from the scope where
+ the shell was called.
+
+ """
+
+ if (global_ns is not None) and (module is None):
+ raise DeprecationWarning("'global_ns' keyword argument is deprecated, and has been removed in IPython 5.0 use `module` keyword argument instead.")
+
+ if (display_banner is not None):
+ warnings.warn("The display_banner parameter is deprecated since IPython 4.0", DeprecationWarning)
+
+ # Get locals and globals from caller
+ if ((local_ns is None or module is None or compile_flags is None)
+ and self.default_user_namespaces):
+ call_frame = sys._getframe(stack_depth).f_back
+
+ if local_ns is None:
+ local_ns = call_frame.f_locals
+ if module is None:
+ global_ns = call_frame.f_globals
+ try:
+ module = sys.modules[global_ns['__name__']]
+ except KeyError:
+ warnings.warn("Failed to get module %s" % \
+ global_ns.get('__name__', 'unknown module')
+ )
+ module = DummyMod()
+ module.__dict__ = global_ns
+ if compile_flags is None:
+ compile_flags = (call_frame.f_code.co_flags &
+ compilerop.PyCF_MASK)
+
+ # Save original namespace and module so we can restore them after
+ # embedding; otherwise the shell doesn't shut down correctly.
+ orig_user_module = self.user_module
+ orig_user_ns = self.user_ns
+ orig_compile_flags = self.compile.flags
+
+ # Update namespaces and fire up interpreter
+
+ # The global one is easy, we can just throw it in
+ if module is not None:
+ self.user_module = module
+
+ # But the user/local one is tricky: ipython needs it to store internal
+ # data, but we also need the locals. We'll throw our hidden variables
+ # like _ih and get_ipython() into the local namespace, but delete them
+ # later.
+ if local_ns is not None:
+ reentrant_local_ns = {k: v for (k, v) in local_ns.items() if k not in self.user_ns_hidden.keys()}
+ self.user_ns = reentrant_local_ns
+ self.init_user_ns()
+
+ # Compiler flags
+ if compile_flags is not None:
+ self.compile.flags = compile_flags
+
+ # make sure the tab-completer has the correct frame information, so it
+ # actually completes using the frame's locals/globals
+ self.set_completer_frame()
+
+ with self.builtin_trap, self.display_trap:
+ self.interact()
+
+ # now, purge out the local namespace of IPython's hidden variables.
+ if local_ns is not None:
+ local_ns.update({k: v for (k, v) in self.user_ns.items() if k not in self.user_ns_hidden.keys()})
+
+
+ # Restore original namespace so shell can shut down when we exit.
+ self.user_module = orig_user_module
+ self.user_ns = orig_user_ns
+ self.compile.flags = orig_compile_flags
+
+
+def embed(**kwargs):
+ """Call this to embed IPython at the current point in your program.
+
+ The first invocation of this will create an :class:`InteractiveShellEmbed`
+ instance and then call it. Consecutive calls just call the already
+ created instance.
+
+ If you don't want the kernel to initialize the namespace
+ from the scope of the surrounding function,
+ and/or you want to load full IPython configuration,
+ you probably want `IPython.start_ipython()` instead.
+
+ Here is a simple example::
+
+ from IPython import embed
+ a = 10
+ b = 20
+ embed(header='First time')
+ c = 30
+ d = 40
+ embed()
+
+ Full customization can be done by passing a :class:`Config` in as the
+ config argument.
+ """
+ config = kwargs.get('config')
+ header = kwargs.pop('header', u'')
+ compile_flags = kwargs.pop('compile_flags', None)
+ if config is None:
+ config = load_default_config()
+ config.InteractiveShellEmbed = config.TerminalInteractiveShell
+ kwargs['config'] = config
+ #save ps1/ps2 if defined
+ ps1 = None
+ ps2 = None
+ try:
+ ps1 = sys.ps1
+ ps2 = sys.ps2
+ except AttributeError:
+ pass
+ #save previous instance
+ saved_shell_instance = InteractiveShell._instance
+ if saved_shell_instance is not None:
+ cls = type(saved_shell_instance)
+ cls.clear_instance()
+ frame = sys._getframe(1)
+ shell = InteractiveShellEmbed.instance(_init_location_id='%s:%s' % (
+ frame.f_code.co_filename, frame.f_lineno), **kwargs)
+ shell(header=header, stack_depth=2, compile_flags=compile_flags,
+ _call_location_id='%s:%s' % (frame.f_code.co_filename, frame.f_lineno))
+ InteractiveShellEmbed.clear_instance()
+ #restore previous instance
+ if saved_shell_instance is not None:
+ cls = type(saved_shell_instance)
+ cls.clear_instance()
+ for subclass in cls._walk_mro():
+ subclass._instance = saved_shell_instance
+ if ps1 is not None:
+ sys.ps1 = ps1
+ sys.ps2 = ps2
diff --git a/contrib/python/ipython/py2/IPython/terminal/interactiveshell.py b/contrib/python/ipython/py2/IPython/terminal/interactiveshell.py
new file mode 100644
index 00000000000..f67cc6b5020
--- /dev/null
+++ b/contrib/python/ipython/py2/IPython/terminal/interactiveshell.py
@@ -0,0 +1,552 @@
+"""IPython terminal interface using prompt_toolkit"""
+from __future__ import print_function
+
+import os
+import sys
+import warnings
+from warnings import warn
+
+from IPython.core.interactiveshell import InteractiveShell, InteractiveShellABC
+from IPython.utils import io
+from IPython.utils.py3compat import PY3, cast_unicode_py2, input, string_types
+from IPython.utils.terminal import toggle_set_term_title, set_term_title
+from IPython.utils.process import abbrev_cwd
+from traitlets import Bool, Unicode, Dict, Integer, observe, Instance, Type, default, Enum, Union
+
+from prompt_toolkit.document import Document
+from prompt_toolkit.enums import DEFAULT_BUFFER, EditingMode
+from prompt_toolkit.filters import (HasFocus, Condition, IsDone)
+from prompt_toolkit.history import InMemoryHistory
+from prompt_toolkit.shortcuts import create_prompt_application, create_eventloop, create_prompt_layout, create_output
+from prompt_toolkit.interface import CommandLineInterface
+from prompt_toolkit.key_binding.manager import KeyBindingManager
+from prompt_toolkit.layout.processors import ConditionalProcessor, HighlightMatchingBracketProcessor
+from prompt_toolkit.styles import PygmentsStyle, DynamicStyle
+
+from pygments.styles import get_style_by_name
+from pygments.style import Style
+from pygments.token import Token
+
+from .debugger import TerminalPdb, Pdb
+from .magics import TerminalMagics
+from .pt_inputhooks import get_inputhook_name_and_func
+from .prompts import Prompts, ClassicPrompts, RichPromptDisplayHook
+from .ptutils import IPythonPTCompleter, IPythonPTLexer
+from .shortcuts import register_ipython_shortcuts
+
+DISPLAY_BANNER_DEPRECATED = object()
+
+
+from pygments.style import Style
+
+class _NoStyle(Style): pass
+
+
+
+_style_overrides_light_bg = {
+ Token.Prompt: '#0000ff',
+ Token.PromptNum: '#0000ee bold',
+ Token.OutPrompt: '#cc0000',
+ Token.OutPromptNum: '#bb0000 bold',
+}
+
+_style_overrides_linux = {
+ Token.Prompt: '#00cc00',
+ Token.PromptNum: '#00bb00 bold',
+ Token.OutPrompt: '#cc0000',
+ Token.OutPromptNum: '#bb0000 bold',
+}
+
+
+
+def get_default_editor():
+ try:
+ ed = os.environ['EDITOR']
+ if not PY3:
+ ed = ed.decode()
+ return ed
+ except KeyError:
+ pass
+ except UnicodeError:
+ warn("$EDITOR environment variable is not pure ASCII. Using platform "
+ "default editor.")
+
+ if os.name == 'posix':
+ return 'vi' # the only one guaranteed to be there!
+ else:
+ return 'notepad' # same in Windows!
+
+# conservatively check for tty
+# overridden streams can result in things like:
+# - sys.stdin = None
+# - no isatty method
+for _name in ('stdin', 'stdout', 'stderr'):
+ _stream = getattr(sys, _name)
+ if not _stream or not hasattr(_stream, 'isatty') or not _stream.isatty():
+ _is_tty = False
+ break
+else:
+ _is_tty = True
+
+
+_use_simple_prompt = ('IPY_TEST_SIMPLE_PROMPT' in os.environ) or (not _is_tty)
+
+class TerminalInteractiveShell(InteractiveShell):
+ space_for_menu = Integer(6, help='Number of line at the bottom of the screen '
+ 'to reserve for the completion menu'
+ ).tag(config=True)
+
+ def _space_for_menu_changed(self, old, new):
+ self._update_layout()
+
+ pt_cli = None
+ debugger_history = None
+ _pt_app = None
+
+ simple_prompt = Bool(_use_simple_prompt,
+ help="""Use `raw_input` for the REPL, without completion and prompt colors.
+
+ Useful when controlling IPython as a subprocess, and piping STDIN/OUT/ERR. Known usage are:
+ IPython own testing machinery, and emacs inferior-shell integration through elpy.
+
+ This mode default to `True` if the `IPY_TEST_SIMPLE_PROMPT`
+ environment variable is set, or the current terminal is not a tty.
+
+ """
+ ).tag(config=True)
+
+ @property
+ def debugger_cls(self):
+ return Pdb if self.simple_prompt else TerminalPdb
+
+ confirm_exit = Bool(True,
+ help="""
+ Set to confirm when you try to exit IPython with an EOF (Control-D
+ in Unix, Control-Z/Enter in Windows). By typing 'exit' or 'quit',
+ you can force a direct exit without any confirmation.""",
+ ).tag(config=True)
+
+ editing_mode = Unicode('emacs',
+ help="Shortcut style to use at the prompt. 'vi' or 'emacs'.",
+ ).tag(config=True)
+
+ mouse_support = Bool(False,
+ help="Enable mouse support in the prompt"
+ ).tag(config=True)
+
+ # We don't load the list of styles for the help string, because loading
+ # Pygments plugins takes time and can cause unexpected errors.
+ highlighting_style = Union([Unicode('legacy'), Type(klass=Style)],
+ help="""The name or class of a Pygments style to use for syntax
+ highlighting. To see available styles, run `pygmentize -L styles`."""
+ ).tag(config=True)
+
+
+ @observe('highlighting_style')
+ @observe('colors')
+ def _highlighting_style_changed(self, change):
+ self.refresh_style()
+
+ def refresh_style(self):
+ self._style = self._make_style_from_name_or_cls(self.highlighting_style)
+
+
+ highlighting_style_overrides = Dict(
+ help="Override highlighting format for specific tokens"
+ ).tag(config=True)
+
+ true_color = Bool(False,
+ help=("Use 24bit colors instead of 256 colors in prompt highlighting. "
+ "If your terminal supports true color, the following command "
+ "should print 'TRUECOLOR' in orange: "
+ "printf \"\\x1b[38;2;255;100;0mTRUECOLOR\\x1b[0m\\n\"")
+ ).tag(config=True)
+
+ editor = Unicode(get_default_editor(),
+ help="Set the editor used by IPython (default to $EDITOR/vi/notepad)."
+ ).tag(config=True)
+
+ prompts_class = Type(Prompts, help='Class used to generate Prompt token for prompt_toolkit').tag(config=True)
+
+ prompts = Instance(Prompts)
+
+ @default('prompts')
+ def _prompts_default(self):
+ return self.prompts_class(self)
+
+ @observe('prompts')
+ def _(self, change):
+ self._update_layout()
+
+ @default('displayhook_class')
+ def _displayhook_class_default(self):
+ return RichPromptDisplayHook
+
+ term_title = Bool(True,
+ help="Automatically set the terminal title"
+ ).tag(config=True)
+
+ display_completions = Enum(('column', 'multicolumn','readlinelike'),
+ help= ( "Options for displaying tab completions, 'column', 'multicolumn', and "
+ "'readlinelike'. These options are for `prompt_toolkit`, see "
+ "`prompt_toolkit` documentation for more information."
+ ),
+ default_value='multicolumn').tag(config=True)
+
+ highlight_matching_brackets = Bool(True,
+ help="Highlight matching brackets.",
+ ).tag(config=True)
+
+ extra_open_editor_shortcuts = Bool(False,
+ help="Enable vi (v) or Emacs (C-X C-E) shortcuts to open an external editor. "
+ "This is in addition to the F2 binding, which is always enabled."
+ ).tag(config=True)
+
+ @observe('term_title')
+ def init_term_title(self, change=None):
+ # Enable or disable the terminal title.
+ if self.term_title:
+ toggle_set_term_title(True)
+ set_term_title('IPython: ' + abbrev_cwd())
+ else:
+ toggle_set_term_title(False)
+
+ def init_display_formatter(self):
+ super(TerminalInteractiveShell, self).init_display_formatter()
+ # terminal only supports plain text
+ self.display_formatter.active_types = ['text/plain']
+ # disable `_ipython_display_`
+ self.display_formatter.ipython_display_formatter.enabled = False
+
+ def init_prompt_toolkit_cli(self):
+ if self.simple_prompt:
+ # Fall back to plain non-interactive output for tests.
+ # This is very limited, and only accepts a single line.
+ def prompt():
+ isp = self.input_splitter
+ prompt_text = "".join(x[1] for x in self.prompts.in_prompt_tokens())
+ prompt_continuation = "".join(x[1] for x in self.prompts.continuation_prompt_tokens())
+ while isp.push_accepts_more():
+ line = cast_unicode_py2(input(prompt_text))
+ isp.push(line)
+ prompt_text = prompt_continuation
+ return isp.source_reset()
+ self.prompt_for_code = prompt
+ return
+
+ # Set up keyboard shortcuts
+ kbmanager = KeyBindingManager.for_prompt(
+ enable_open_in_editor=self.extra_open_editor_shortcuts,
+ )
+ register_ipython_shortcuts(kbmanager.registry, self)
+
+ # Pre-populate history from IPython's history database
+ history = InMemoryHistory()
+ last_cell = u""
+ for __, ___, cell in self.history_manager.get_tail(self.history_load_length,
+ include_latest=True):
+ # Ignore blank lines and consecutive duplicates
+ cell = cell.rstrip()
+ if cell and (cell != last_cell):
+ history.append(cell)
+ last_cell = cell
+
+ self._style = self._make_style_from_name_or_cls(self.highlighting_style)
+ self.style = DynamicStyle(lambda: self._style)
+
+ editing_mode = getattr(EditingMode, self.editing_mode.upper())
+
+ def patch_stdout(**kwargs):
+ return self.pt_cli.patch_stdout_context(**kwargs)
+
+ self._pt_app = create_prompt_application(
+ editing_mode=editing_mode,
+ key_bindings_registry=kbmanager.registry,
+ history=history,
+ completer=IPythonPTCompleter(shell=self,
+ patch_stdout=patch_stdout),
+ enable_history_search=True,
+ style=self.style,
+ mouse_support=self.mouse_support,
+ **self._layout_options()
+ )
+ self._eventloop = create_eventloop(self.inputhook)
+ self.pt_cli = CommandLineInterface(
+ self._pt_app, eventloop=self._eventloop,
+ output=create_output(true_color=self.true_color))
+
+ def _make_style_from_name_or_cls(self, name_or_cls):
+ """
+ Small wrapper that make an IPython compatible style from a style name
+
+ We need that to add style for prompt ... etc.
+ """
+ style_overrides = {}
+ if name_or_cls == 'legacy':
+ legacy = self.colors.lower()
+ if legacy == 'linux':
+ style_cls = get_style_by_name('monokai')
+ style_overrides = _style_overrides_linux
+ elif legacy == 'lightbg':
+ style_overrides = _style_overrides_light_bg
+ style_cls = get_style_by_name('pastie')
+ elif legacy == 'neutral':
+ # The default theme needs to be visible on both a dark background
+ # and a light background, because we can't tell what the terminal
+ # looks like. These tweaks to the default theme help with that.
+ style_cls = get_style_by_name('default')
+ style_overrides.update({
+ Token.Number: '#007700',
+ Token.Operator: 'noinherit',
+ Token.String: '#BB6622',
+ Token.Name.Function: '#2080D0',
+ Token.Name.Class: 'bold #2080D0',
+ Token.Name.Namespace: 'bold #2080D0',
+ Token.Prompt: '#009900',
+ Token.PromptNum: '#00ff00 bold',
+ Token.OutPrompt: '#990000',
+ Token.OutPromptNum: '#ff0000 bold',
+ })
+
+ # Hack: Due to limited color support on the Windows console
+ # the prompt colors will be wrong without this
+ if os.name == 'nt':
+ style_overrides.update({
+ Token.Prompt: '#ansidarkgreen',
+ Token.PromptNum: '#ansigreen bold',
+ Token.OutPrompt: '#ansidarkred',
+ Token.OutPromptNum: '#ansired bold',
+ })
+ elif legacy =='nocolor':
+ style_cls=_NoStyle
+ style_overrides = {}
+ else :
+ raise ValueError('Got unknown colors: ', legacy)
+ else :
+ if isinstance(name_or_cls, string_types):
+ style_cls = get_style_by_name(name_or_cls)
+ else:
+ style_cls = name_or_cls
+ style_overrides = {
+ Token.Prompt: '#009900',
+ Token.PromptNum: '#00ff00 bold',
+ Token.OutPrompt: '#990000',
+ Token.OutPromptNum: '#ff0000 bold',
+ }
+ style_overrides.update(self.highlighting_style_overrides)
+ style = PygmentsStyle.from_defaults(pygments_style_cls=style_cls,
+ style_dict=style_overrides)
+
+ return style
+
+ def _layout_options(self):
+ """
+ Return the current layout option for the current Terminal InteractiveShell
+ """
+ return {
+ 'lexer':IPythonPTLexer(),
+ 'reserve_space_for_menu':self.space_for_menu,
+ 'get_prompt_tokens':self.prompts.in_prompt_tokens,
+ 'get_continuation_tokens':self.prompts.continuation_prompt_tokens,
+ 'multiline':True,
+ 'display_completions_in_columns': (self.display_completions == 'multicolumn'),
+
+ # Highlight matching brackets, but only when this setting is
+ # enabled, and only when the DEFAULT_BUFFER has the focus.
+ 'extra_input_processors': [ConditionalProcessor(
+ processor=HighlightMatchingBracketProcessor(chars='[](){}'),
+ filter=HasFocus(DEFAULT_BUFFER) & ~IsDone() &
+ Condition(lambda cli: self.highlight_matching_brackets))],
+ }
+
+ def _update_layout(self):
+ """
+ Ask for a re computation of the application layout, if for example ,
+ some configuration options have changed.
+ """
+ if self._pt_app:
+ self._pt_app.layout = create_prompt_layout(**self._layout_options())
+
+ def prompt_for_code(self):
+ document = self.pt_cli.run(
+ pre_run=self.pre_prompt, reset_current_buffer=True)
+ return document.text
+
+ def enable_win_unicode_console(self):
+ if sys.version_info >= (3, 6):
+ # Since PEP 528, Python uses the unicode APIs for the Windows
+ # console by default, so WUC shouldn't be needed.
+ return
+
+ import win_unicode_console
+
+ if PY3:
+ win_unicode_console.enable()
+ else:
+ # https://github.com/ipython/ipython/issues/9768
+ from win_unicode_console.streams import (TextStreamWrapper,
+ stdout_text_transcoded, stderr_text_transcoded)
+
+ class LenientStrStreamWrapper(TextStreamWrapper):
+ def write(self, s):
+ if isinstance(s, bytes):
+ s = s.decode(self.encoding, 'replace')
+
+ self.base.write(s)
+
+ stdout_text_str = LenientStrStreamWrapper(stdout_text_transcoded)
+ stderr_text_str = LenientStrStreamWrapper(stderr_text_transcoded)
+
+ win_unicode_console.enable(stdout=stdout_text_str,
+ stderr=stderr_text_str)
+
+ def init_io(self):
+ if sys.platform not in {'win32', 'cli'}:
+ return
+
+ self.enable_win_unicode_console()
+
+ import colorama
+ colorama.init()
+
+ # For some reason we make these wrappers around stdout/stderr.
+ # For now, we need to reset them so all output gets coloured.
+ # https://github.com/ipython/ipython/issues/8669
+ # io.std* are deprecated, but don't show our own deprecation warnings
+ # during initialization of the deprecated API.
+ with warnings.catch_warnings():
+ warnings.simplefilter('ignore', DeprecationWarning)
+ io.stdout = io.IOStream(sys.stdout)
+ io.stderr = io.IOStream(sys.stderr)
+
+ def init_magics(self):
+ super(TerminalInteractiveShell, self).init_magics()
+ self.register_magics(TerminalMagics)
+
+ def init_alias(self):
+ # The parent class defines aliases that can be safely used with any
+ # frontend.
+ super(TerminalInteractiveShell, self).init_alias()
+
+ # Now define aliases that only make sense on the terminal, because they
+ # need direct access to the console in a way that we can't emulate in
+ # GUI or web frontend
+ if os.name == 'posix':
+ for cmd in ['clear', 'more', 'less', 'man']:
+ self.alias_manager.soft_define_alias(cmd, cmd)
+
+
+ def __init__(self, *args, **kwargs):
+ super(TerminalInteractiveShell, self).__init__(*args, **kwargs)
+ self.init_prompt_toolkit_cli()
+ self.init_term_title()
+ self.keep_running = True
+
+ self.debugger_history = InMemoryHistory()
+
+ def ask_exit(self):
+ self.keep_running = False
+
+ rl_next_input = None
+
+ def pre_prompt(self):
+ if self.rl_next_input:
+ # We can't set the buffer here, because it will be reset just after
+ # this. Adding a callable to pre_run_callables does what we need
+ # after the buffer is reset.
+ s = cast_unicode_py2(self.rl_next_input)
+ def set_doc():
+ self.pt_cli.application.buffer.document = Document(s)
+ if hasattr(self.pt_cli, 'pre_run_callables'):
+ self.pt_cli.pre_run_callables.append(set_doc)
+ else:
+ # Older version of prompt_toolkit; it's OK to set the document
+ # directly here.
+ set_doc()
+ self.rl_next_input = None
+
+ def interact(self, display_banner=DISPLAY_BANNER_DEPRECATED):
+
+ if display_banner is not DISPLAY_BANNER_DEPRECATED:
+ warn('interact `display_banner` argument is deprecated since IPython 5.0. Call `show_banner()` if needed.', DeprecationWarning, stacklevel=2)
+
+ self.keep_running = True
+ while self.keep_running:
+ print(self.separate_in, end='')
+
+ try:
+ code = self.prompt_for_code()
+ except EOFError:
+ if (not self.confirm_exit) \
+ or self.ask_yes_no('Do you really want to exit ([y]/n)?','y','n'):
+ self.ask_exit()
+
+ else:
+ if code:
+ self.run_cell(code, store_history=True)
+
+ def mainloop(self, display_banner=DISPLAY_BANNER_DEPRECATED):
+ # An extra layer of protection in case someone mashing Ctrl-C breaks
+ # out of our internal code.
+ if display_banner is not DISPLAY_BANNER_DEPRECATED:
+ warn('mainloop `display_banner` argument is deprecated since IPython 5.0. Call `show_banner()` if needed.', DeprecationWarning, stacklevel=2)
+ while True:
+ try:
+ self.interact()
+ break
+ except KeyboardInterrupt as e:
+ print("\n%s escaped interact()\n" % type(e).__name__)
+ finally:
+ # An interrupt during the eventloop will mess up the
+ # internal state of the prompt_toolkit library.
+ # Stopping the eventloop fixes this, see
+ # https://github.com/ipython/ipython/pull/9867
+ if hasattr(self, '_eventloop'):
+ self._eventloop.stop()
+
+ _inputhook = None
+ def inputhook(self, context):
+ if self._inputhook is not None:
+ self._inputhook(context)
+
+ active_eventloop = None
+ def enable_gui(self, gui=None):
+ if gui:
+ self.active_eventloop, self._inputhook =\
+ get_inputhook_name_and_func(gui)
+ else:
+ self.active_eventloop = self._inputhook = None
+
+ # Run !system commands directly, not through pipes, so terminal programs
+ # work correctly.
+ system = InteractiveShell.system_raw
+
+ def auto_rewrite_input(self, cmd):
+ """Overridden from the parent class to use fancy rewriting prompt"""
+ if not self.show_rewritten_input:
+ return
+
+ tokens = self.prompts.rewrite_prompt_tokens()
+ if self.pt_cli:
+ self.pt_cli.print_tokens(tokens)
+ print(cmd)
+ else:
+ prompt = ''.join(s for t, s in tokens)
+ print(prompt, cmd, sep='')
+
+ _prompts_before = None
+ def switch_doctest_mode(self, mode):
+ """Switch prompts to classic for %doctest_mode"""
+ if mode:
+ self._prompts_before = self.prompts
+ self.prompts = ClassicPrompts(self)
+ elif self._prompts_before:
+ self.prompts = self._prompts_before
+ self._prompts_before = None
+ self._update_layout()
+
+
+InteractiveShellABC.register(TerminalInteractiveShell)
+
+if __name__ == '__main__':
+ TerminalInteractiveShell.instance().interact()
diff --git a/contrib/python/ipython/py2/IPython/terminal/ipapp.py b/contrib/python/ipython/py2/IPython/terminal/ipapp.py
new file mode 100755
index 00000000000..6b25aaa3e36
--- /dev/null
+++ b/contrib/python/ipython/py2/IPython/terminal/ipapp.py
@@ -0,0 +1,377 @@
+#!/usr/bin/env python
+# encoding: utf-8
+"""
+The :class:`~IPython.core.application.Application` object for the command
+line :command:`ipython` program.
+"""
+
+# Copyright (c) IPython Development Team.
+# Distributed under the terms of the Modified BSD License.
+
+from __future__ import absolute_import
+from __future__ import print_function
+
+import logging
+import os
+import sys
+import warnings
+
+from traitlets.config.loader import Config
+from traitlets.config.application import boolean_flag, catch_config_error, Application
+from IPython.core import release
+from IPython.core import usage
+from IPython.core.completer import IPCompleter
+from IPython.core.crashhandler import CrashHandler
+from IPython.core.formatters import PlainTextFormatter
+from IPython.core.history import HistoryManager
+from IPython.core.application import (
+ ProfileDir, BaseIPythonApplication, base_flags, base_aliases
+)
+from IPython.core.magics import ScriptMagics
+from IPython.core.shellapp import (
+ InteractiveShellApp, shell_flags, shell_aliases
+)
+from IPython.extensions.storemagic import StoreMagics
+from .interactiveshell import TerminalInteractiveShell
+from IPython.paths import get_ipython_dir
+from traitlets import (
+ Bool, List, Dict, default, observe, Type
+)
+
+#-----------------------------------------------------------------------------
+# Globals, utilities and helpers
+#-----------------------------------------------------------------------------
+
+_examples = """
+ipython --matplotlib # enable matplotlib integration
+ipython --matplotlib=qt # enable matplotlib integration with qt4 backend
+
+ipython --log-level=DEBUG # set logging to DEBUG
+ipython --profile=foo # start with profile foo
+
+ipython profile create foo # create profile foo w/ default config files
+ipython help profile # show the help for the profile subcmd
+
+ipython locate # print the path to the IPython directory
+ipython locate profile foo # print the path to the directory for profile `foo`
+"""
+
+#-----------------------------------------------------------------------------
+# Crash handler for this application
+#-----------------------------------------------------------------------------
+
+class IPAppCrashHandler(CrashHandler):
+ """sys.excepthook for IPython itself, leaves a detailed report on disk."""
+
+ def __init__(self, app):
+ contact_name = release.author
+ contact_email = release.author_email
+ bug_tracker = 'https://github.com/ipython/ipython/issues'
+ super(IPAppCrashHandler,self).__init__(
+ app, contact_name, contact_email, bug_tracker
+ )
+
+ def make_report(self,traceback):
+ """Return a string containing a crash report."""
+
+ sec_sep = self.section_sep
+ # Start with parent report
+ report = [super(IPAppCrashHandler, self).make_report(traceback)]
+ # Add interactive-specific info we may have
+ rpt_add = report.append
+ try:
+ rpt_add(sec_sep+"History of session input:")
+ for line in self.app.shell.user_ns['_ih']:
+ rpt_add(line)
+ rpt_add('\n*** Last line of input (may not be in above history):\n')
+ rpt_add(self.app.shell._last_input_line+'\n')
+ except:
+ pass
+
+ return ''.join(report)
+
+#-----------------------------------------------------------------------------
+# Aliases and Flags
+#-----------------------------------------------------------------------------
+flags = dict(base_flags)
+flags.update(shell_flags)
+frontend_flags = {}
+addflag = lambda *args: frontend_flags.update(boolean_flag(*args))
+addflag('autoedit-syntax', 'TerminalInteractiveShell.autoedit_syntax',
+ 'Turn on auto editing of files with syntax errors.',
+ 'Turn off auto editing of files with syntax errors.'
+)
+addflag('simple-prompt', 'TerminalInteractiveShell.simple_prompt',
+ "Force simple minimal prompt using `raw_input`",
+ "Use a rich interactive prompt with prompt_toolkit",
+)
+
+addflag('banner', 'TerminalIPythonApp.display_banner',
+ "Display a banner upon starting IPython.",
+ "Don't display a banner upon starting IPython."
+)
+addflag('confirm-exit', 'TerminalInteractiveShell.confirm_exit',
+ """Set to confirm when you try to exit IPython with an EOF (Control-D
+ in Unix, Control-Z/Enter in Windows). By typing 'exit' or 'quit',
+ you can force a direct exit without any confirmation.""",
+ "Don't prompt the user when exiting."
+)
+addflag('term-title', 'TerminalInteractiveShell.term_title',
+ "Enable auto setting the terminal title.",
+ "Disable auto setting the terminal title."
+)
+classic_config = Config()
+classic_config.InteractiveShell.cache_size = 0
+classic_config.PlainTextFormatter.pprint = False
+classic_config.TerminalInteractiveShell.prompts_class='IPython.terminal.prompts.ClassicPrompts'
+classic_config.InteractiveShell.separate_in = ''
+classic_config.InteractiveShell.separate_out = ''
+classic_config.InteractiveShell.separate_out2 = ''
+classic_config.InteractiveShell.colors = 'NoColor'
+classic_config.InteractiveShell.xmode = 'Plain'
+
+frontend_flags['classic']=(
+ classic_config,
+ "Gives IPython a similar feel to the classic Python prompt."
+)
+# # log doesn't make so much sense this way anymore
+# paa('--log','-l',
+# action='store_true', dest='InteractiveShell.logstart',
+# help="Start logging to the default log file (./ipython_log.py).")
+#
+# # quick is harder to implement
+frontend_flags['quick']=(
+ {'TerminalIPythonApp' : {'quick' : True}},
+ "Enable quick startup with no config files."
+)
+
+frontend_flags['i'] = (
+ {'TerminalIPythonApp' : {'force_interact' : True}},
+ """If running code from the command line, become interactive afterwards.
+ It is often useful to follow this with `--` to treat remaining flags as
+ script arguments.
+ """
+)
+flags.update(frontend_flags)
+
+aliases = dict(base_aliases)
+aliases.update(shell_aliases)
+
+#-----------------------------------------------------------------------------
+# Main classes and functions
+#-----------------------------------------------------------------------------
+
+
+class LocateIPythonApp(BaseIPythonApplication):
+ description = """print the path to the IPython dir"""
+ subcommands = Dict(dict(
+ profile=('IPython.core.profileapp.ProfileLocate',
+ "print the path to an IPython profile directory",
+ ),
+ ))
+ def start(self):
+ if self.subapp is not None:
+ return self.subapp.start()
+ else:
+ print(self.ipython_dir)
+
+
+class TerminalIPythonApp(BaseIPythonApplication, InteractiveShellApp):
+ name = u'ipython'
+ description = usage.cl_usage
+ crash_handler_class = IPAppCrashHandler
+ examples = _examples
+
+ flags = Dict(flags)
+ aliases = Dict(aliases)
+ classes = List()
+
+ interactive_shell_class = Type(
+ klass=object, # use default_value otherwise which only allow subclasses.
+ default_value=TerminalInteractiveShell,
+ help="Class to use to instantiate the TerminalInteractiveShell object. Useful for custom Frontends"
+ ).tag(config=True)
+
+ @default('classes')
+ def _classes_default(self):
+ """This has to be in a method, for TerminalIPythonApp to be available."""
+ return [
+ InteractiveShellApp, # ShellApp comes before TerminalApp, because
+ self.__class__, # it will also affect subclasses (e.g. QtConsole)
+ TerminalInteractiveShell,
+ HistoryManager,
+ ProfileDir,
+ PlainTextFormatter,
+ IPCompleter,
+ ScriptMagics,
+ StoreMagics,
+ ]
+
+ deprecated_subcommands = dict(
+ qtconsole=('qtconsole.qtconsoleapp.JupyterQtConsoleApp',
+ """DEPRECATED, Will be removed in IPython 6.0 : Launch the Jupyter Qt Console."""
+ ),
+ notebook=('notebook.notebookapp.NotebookApp',
+ """DEPRECATED, Will be removed in IPython 6.0 : Launch the Jupyter HTML Notebook Server."""
+ ),
+ console=('jupyter_console.app.ZMQTerminalIPythonApp',
+ """DEPRECATED, Will be removed in IPython 6.0 : Launch the Jupyter terminal-based Console."""
+ ),
+ nbconvert=('nbconvert.nbconvertapp.NbConvertApp',
+ "DEPRECATED, Will be removed in IPython 6.0 : Convert notebooks to/from other formats."
+ ),
+ trust=('nbformat.sign.TrustNotebookApp',
+ "DEPRECATED, Will be removed in IPython 6.0 : Sign notebooks to trust their potentially unsafe contents at load."
+ ),
+ kernelspec=('jupyter_client.kernelspecapp.KernelSpecApp',
+ "DEPRECATED, Will be removed in IPython 6.0 : Manage Jupyter kernel specifications."
+ ),
+ )
+ subcommands = dict(
+ profile = ("IPython.core.profileapp.ProfileApp",
+ "Create and manage IPython profiles."
+ ),
+ kernel = ("ipykernel.kernelapp.IPKernelApp",
+ "Start a kernel without an attached frontend."
+ ),
+ locate=('IPython.terminal.ipapp.LocateIPythonApp',
+ LocateIPythonApp.description
+ ),
+ history=('IPython.core.historyapp.HistoryApp',
+ "Manage the IPython history database."
+ ),
+ )
+ deprecated_subcommands['install-nbextension'] = (
+ "notebook.nbextensions.InstallNBExtensionApp",
+ "DEPRECATED, Will be removed in IPython 6.0 : Install Jupyter notebook extension files"
+ )
+ subcommands.update(deprecated_subcommands)
+
+ # *do* autocreate requested profile, but don't create the config file.
+ auto_create=Bool(True)
+ # configurables
+ quick = Bool(False,
+ help="""Start IPython quickly by skipping the loading of config files."""
+ ).tag(config=True)
+ @observe('quick')
+ def _quick_changed(self, change):
+ if change['new']:
+ self.load_config_file = lambda *a, **kw: None
+
+ display_banner = Bool(True,
+ help="Whether to display a banner upon starting IPython."
+ ).tag(config=True)
+
+ # if there is code of files to run from the cmd line, don't interact
+ # unless the --i flag (App.force_interact) is true.
+ force_interact = Bool(False,
+ help="""If a command or file is given via the command-line,
+ e.g. 'ipython foo.py', start an interactive shell after executing the
+ file or command."""
+ ).tag(config=True)
+ @observe('force_interact')
+ def _force_interact_changed(self, change):
+ if change['new']:
+ self.interact = True
+
+ @observe('file_to_run', 'code_to_run', 'module_to_run')
+ def _file_to_run_changed(self, change):
+ new = change['new']
+ if new:
+ self.something_to_run = True
+ if new and not self.force_interact:
+ self.interact = False
+
+ # internal, not-configurable
+ something_to_run=Bool(False)
+
+ def parse_command_line(self, argv=None):
+ """override to allow old '-pylab' flag with deprecation warning"""
+
+ argv = sys.argv[1:] if argv is None else argv
+
+ if '-pylab' in argv:
+ # deprecated `-pylab` given,
+ # warn and transform into current syntax
+ argv = argv[:] # copy, don't clobber
+ idx = argv.index('-pylab')
+ warnings.warn("`-pylab` flag has been deprecated.\n"
+ " Use `--matplotlib <backend>` and import pylab manually.")
+ argv[idx] = '--pylab'
+
+ return super(TerminalIPythonApp, self).parse_command_line(argv)
+
+ @catch_config_error
+ def initialize(self, argv=None):
+ """Do actions after construct, but before starting the app."""
+ super(TerminalIPythonApp, self).initialize(argv)
+ if self.subapp is not None:
+ # don't bother initializing further, starting subapp
+ return
+ # print self.extra_args
+ if self.extra_args and not self.something_to_run:
+ self.file_to_run = self.extra_args[0]
+ self.init_path()
+ # create the shell
+ self.init_shell()
+ # and draw the banner
+ self.init_banner()
+ # Now a variety of things that happen after the banner is printed.
+ self.init_gui_pylab()
+ self.init_extensions()
+ self.init_code()
+
+ def init_shell(self):
+ """initialize the InteractiveShell instance"""
+ # Create an InteractiveShell instance.
+ # shell.display_banner should always be False for the terminal
+ # based app, because we call shell.show_banner() by hand below
+ # so the banner shows *before* all extension loading stuff.
+ self.shell = self.interactive_shell_class.instance(parent=self,
+ profile_dir=self.profile_dir,
+ ipython_dir=self.ipython_dir, user_ns=self.user_ns)
+ self.shell.configurables.append(self)
+
+ def init_banner(self):
+ """optionally display the banner"""
+ if self.display_banner and self.interact:
+ self.shell.show_banner()
+ # Make sure there is a space below the banner.
+ if self.log_level <= logging.INFO: print()
+
+ def _pylab_changed(self, name, old, new):
+ """Replace --pylab='inline' with --pylab='auto'"""
+ if new == 'inline':
+ warnings.warn("'inline' not available as pylab backend, "
+ "using 'auto' instead.")
+ self.pylab = 'auto'
+
+ def start(self):
+ if self.subapp is not None:
+ return self.subapp.start()
+ # perform any prexec steps:
+ if self.interact:
+ self.log.debug("Starting IPython's mainloop...")
+ self.shell.mainloop()
+ else:
+ self.log.debug("IPython not interactive...")
+
+def load_default_config(ipython_dir=None):
+ """Load the default config file from the default ipython_dir.
+
+ This is useful for embedded shells.
+ """
+ if ipython_dir is None:
+ ipython_dir = get_ipython_dir()
+
+ profile_dir = os.path.join(ipython_dir, 'profile_default')
+ app = TerminalIPythonApp()
+ app.config_file_paths.append(profile_dir)
+ app.load_config_file()
+ return app.config
+
+launch_new_instance = TerminalIPythonApp.launch_instance
+
+
+if __name__ == '__main__':
+ launch_new_instance()
diff --git a/contrib/python/ipython/py2/IPython/terminal/magics.py b/contrib/python/ipython/py2/IPython/terminal/magics.py
new file mode 100644
index 00000000000..3a844a03970
--- /dev/null
+++ b/contrib/python/ipython/py2/IPython/terminal/magics.py
@@ -0,0 +1,208 @@
+"""Extra magics for terminal use."""
+
+# Copyright (c) IPython Development Team.
+# Distributed under the terms of the Modified BSD License.
+
+from __future__ import print_function
+
+from logging import error
+import os
+import sys
+
+from IPython.core.error import TryNext, UsageError
+from IPython.core.inputsplitter import IPythonInputSplitter
+from IPython.core.magic import Magics, magics_class, line_magic
+from IPython.lib.clipboard import ClipboardEmpty
+from IPython.utils.text import SList, strip_email_quotes
+from IPython.utils import py3compat
+
+def get_pasted_lines(sentinel, l_input=py3compat.input, quiet=False):
+ """ Yield pasted lines until the user enters the given sentinel value.
+ """
+ if not quiet:
+ print("Pasting code; enter '%s' alone on the line to stop or use Ctrl-D." \
+ % sentinel)
+ prompt = ":"
+ else:
+ prompt = ""
+ while True:
+ try:
+ l = py3compat.str_to_unicode(l_input(prompt))
+ if l == sentinel:
+ return
+ else:
+ yield l
+ except EOFError:
+ print('<EOF>')
+ return
+
+
+@magics_class
+class TerminalMagics(Magics):
+ def __init__(self, shell):
+ super(TerminalMagics, self).__init__(shell)
+ self.input_splitter = IPythonInputSplitter()
+
+ def store_or_execute(self, block, name):
+ """ Execute a block, or store it in a variable, per the user's request.
+ """
+ if name:
+ # If storing it for further editing
+ self.shell.user_ns[name] = SList(block.splitlines())
+ print("Block assigned to '%s'" % name)
+ else:
+ b = self.preclean_input(block)
+ self.shell.user_ns['pasted_block'] = b
+ self.shell.using_paste_magics = True
+ try:
+ self.shell.run_cell(b)
+ finally:
+ self.shell.using_paste_magics = False
+
+ def preclean_input(self, block):
+ lines = block.splitlines()
+ while lines and not lines[0].strip():
+ lines = lines[1:]
+ return strip_email_quotes('\n'.join(lines))
+
+ def rerun_pasted(self, name='pasted_block'):
+ """ Rerun a previously pasted command.
+ """
+ b = self.shell.user_ns.get(name)
+
+ # Sanity checks
+ if b is None:
+ raise UsageError('No previous pasted block available')
+ if not isinstance(b, py3compat.string_types):
+ raise UsageError(
+ "Variable 'pasted_block' is not a string, can't execute")
+
+ print("Re-executing '%s...' (%d chars)"% (b.split('\n',1)[0], len(b)))
+ self.shell.run_cell(b)
+
+ @line_magic
+ def autoindent(self, parameter_s = ''):
+ """Toggle autoindent on/off (deprecated)"""
+ print("%autoindent is deprecated since IPython 5: you can now paste "
+ "multiple lines without turning autoindentation off.")
+ self.shell.set_autoindent()
+ print("Automatic indentation is:",['OFF','ON'][self.shell.autoindent])
+
+ @line_magic
+ def cpaste(self, parameter_s=''):
+ """Paste & execute a pre-formatted code block from clipboard.
+
+ You must terminate the block with '--' (two minus-signs) or Ctrl-D
+ alone on the line. You can also provide your own sentinel with '%paste
+ -s %%' ('%%' is the new sentinel for this operation).
+
+ The block is dedented prior to execution to enable execution of method
+ definitions. '>' and '+' characters at the beginning of a line are
+ ignored, to allow pasting directly from e-mails, diff files and
+ doctests (the '...' continuation prompt is also stripped). The
+ executed block is also assigned to variable named 'pasted_block' for
+ later editing with '%edit pasted_block'.
+
+ You can also pass a variable name as an argument, e.g. '%cpaste foo'.
+ This assigns the pasted block to variable 'foo' as string, without
+ dedenting or executing it (preceding >>> and + is still stripped)
+
+ '%cpaste -r' re-executes the block previously entered by cpaste.
+ '%cpaste -q' suppresses any additional output messages.
+
+ Do not be alarmed by garbled output on Windows (it's a readline bug).
+ Just press enter and type -- (and press enter again) and the block
+ will be what was just pasted.
+
+ IPython statements (magics, shell escapes) are not supported (yet).
+
+ See also
+ --------
+ paste: automatically pull code from clipboard.
+
+ Examples
+ --------
+ ::
+
+ In [8]: %cpaste
+ Pasting code; enter '--' alone on the line to stop.
+ :>>> a = ["world!", "Hello"]
+ :>>> print " ".join(sorted(a))
+ :--
+ Hello world!
+ """
+ opts, name = self.parse_options(parameter_s, 'rqs:', mode='string')
+ if 'r' in opts:
+ self.rerun_pasted()
+ return
+
+ quiet = ('q' in opts)
+
+ sentinel = opts.get('s', u'--')
+ block = '\n'.join(get_pasted_lines(sentinel, quiet=quiet))
+ self.store_or_execute(block, name)
+
+ @line_magic
+ def paste(self, parameter_s=''):
+ """Paste & execute a pre-formatted code block from clipboard.
+
+ The text is pulled directly from the clipboard without user
+ intervention and printed back on the screen before execution (unless
+ the -q flag is given to force quiet mode).
+
+ The block is dedented prior to execution to enable execution of method
+ definitions. '>' and '+' characters at the beginning of a line are
+ ignored, to allow pasting directly from e-mails, diff files and
+ doctests (the '...' continuation prompt is also stripped). The
+ executed block is also assigned to variable named 'pasted_block' for
+ later editing with '%edit pasted_block'.
+
+ You can also pass a variable name as an argument, e.g. '%paste foo'.
+ This assigns the pasted block to variable 'foo' as string, without
+ executing it (preceding >>> and + is still stripped).
+
+ Options:
+
+ -r: re-executes the block previously entered by cpaste.
+
+ -q: quiet mode: do not echo the pasted text back to the terminal.
+
+ IPython statements (magics, shell escapes) are not supported (yet).
+
+ See also
+ --------
+ cpaste: manually paste code into terminal until you mark its end.
+ """
+ opts, name = self.parse_options(parameter_s, 'rq', mode='string')
+ if 'r' in opts:
+ self.rerun_pasted()
+ return
+ try:
+ block = self.shell.hooks.clipboard_get()
+ except TryNext as clipboard_exc:
+ message = getattr(clipboard_exc, 'args')
+ if message:
+ error(message[0])
+ else:
+ error('Could not get text from the clipboard.')
+ return
+ except ClipboardEmpty:
+ raise UsageError("The clipboard appears to be empty")
+
+ # By default, echo back to terminal unless quiet mode is requested
+ if 'q' not in opts:
+ write = self.shell.write
+ write(self.shell.pycolorize(block))
+ if not block.endswith('\n'):
+ write('\n')
+ write("## -- End pasted text --\n")
+
+ self.store_or_execute(block, name)
+
+ # Class-level: add a '%cls' magic only on Windows
+ if sys.platform == 'win32':
+ @line_magic
+ def cls(self, s):
+ """Clear screen.
+ """
+ os.system("cls")
diff --git a/contrib/python/ipython/py2/IPython/terminal/prompts.py b/contrib/python/ipython/py2/IPython/terminal/prompts.py
new file mode 100644
index 00000000000..43c21705033
--- /dev/null
+++ b/contrib/python/ipython/py2/IPython/terminal/prompts.py
@@ -0,0 +1,80 @@
+"""Terminal input and output prompts."""
+from __future__ import print_function
+
+from pygments.token import Token
+import sys
+
+from IPython.core.displayhook import DisplayHook
+
+from prompt_toolkit.layout.utils import token_list_width
+
+class Prompts(object):
+ def __init__(self, shell):
+ self.shell = shell
+
+ def in_prompt_tokens(self, cli=None):
+ return [
+ (Token.Prompt, 'In ['),
+ (Token.PromptNum, str(self.shell.execution_count)),
+ (Token.Prompt, ']: '),
+ ]
+
+ def _width(self):
+ return token_list_width(self.in_prompt_tokens())
+
+ def continuation_prompt_tokens(self, cli=None, width=None):
+ if width is None:
+ width = self._width()
+ return [
+ (Token.Prompt, (' ' * (width - 5)) + '...: '),
+ ]
+
+ def rewrite_prompt_tokens(self):
+ width = self._width()
+ return [
+ (Token.Prompt, ('-' * (width - 2)) + '> '),
+ ]
+
+ def out_prompt_tokens(self):
+ return [
+ (Token.OutPrompt, 'Out['),
+ (Token.OutPromptNum, str(self.shell.execution_count)),
+ (Token.OutPrompt, ']: '),
+ ]
+
+class ClassicPrompts(Prompts):
+ def in_prompt_tokens(self, cli=None):
+ return [
+ (Token.Prompt, '>>> '),
+ ]
+
+ def continuation_prompt_tokens(self, cli=None, width=None):
+ return [
+ (Token.Prompt, '... ')
+ ]
+
+ def rewrite_prompt_tokens(self):
+ return []
+
+ def out_prompt_tokens(self):
+ return []
+
+class RichPromptDisplayHook(DisplayHook):
+ """Subclass of base display hook using coloured prompt"""
+ def write_output_prompt(self):
+ sys.stdout.write(self.shell.separate_out)
+ # If we're not displaying a prompt, it effectively ends with a newline,
+ # because the output will be left-aligned.
+ self.prompt_end_newline = True
+
+ if self.do_full_cache:
+ tokens = self.shell.prompts.out_prompt_tokens()
+ prompt_txt = ''.join(s for t, s in tokens)
+ if prompt_txt and not prompt_txt.endswith('\n'):
+ # Ask for a newline before multiline output
+ self.prompt_end_newline = False
+
+ if self.shell.pt_cli:
+ self.shell.pt_cli.print_tokens(tokens)
+ else:
+ sys.stdout.write(prompt_txt)
diff --git a/contrib/python/ipython/py2/IPython/terminal/pt_inputhooks/__init__.py b/contrib/python/ipython/py2/IPython/terminal/pt_inputhooks/__init__.py
new file mode 100644
index 00000000000..3766973e826
--- /dev/null
+++ b/contrib/python/ipython/py2/IPython/terminal/pt_inputhooks/__init__.py
@@ -0,0 +1,49 @@
+import importlib
+import os
+
+aliases = {
+ 'qt4': 'qt',
+ 'gtk2': 'gtk',
+}
+
+backends = [
+ 'qt', 'qt4', 'qt5',
+ 'gtk', 'gtk2', 'gtk3',
+ 'tk',
+ 'wx',
+ 'pyglet', 'glut',
+ 'osx',
+]
+
+registered = {}
+
+def register(name, inputhook):
+ """Register the function *inputhook* as an event loop integration."""
+ registered[name] = inputhook
+
+class UnknownBackend(KeyError):
+ def __init__(self, name):
+ self.name = name
+
+ def __str__(self):
+ return ("No event loop integration for {!r}. "
+ "Supported event loops are: {}").format(self.name,
+ ', '.join(backends + sorted(registered)))
+
+def get_inputhook_name_and_func(gui):
+ if gui in registered:
+ return gui, registered[gui]
+
+ if gui not in backends:
+ raise UnknownBackend(gui)
+
+ if gui in aliases:
+ return get_inputhook_name_and_func(aliases[gui])
+
+ gui_mod = gui
+ if gui == 'qt5':
+ os.environ['QT_API'] = 'pyqt5'
+ gui_mod = 'qt'
+
+ mod = importlib.import_module('IPython.terminal.pt_inputhooks.'+gui_mod)
+ return gui, mod.inputhook
diff --git a/contrib/python/ipython/py2/IPython/terminal/pt_inputhooks/glut.py b/contrib/python/ipython/py2/IPython/terminal/pt_inputhooks/glut.py
new file mode 100644
index 00000000000..f336e6830f5
--- /dev/null
+++ b/contrib/python/ipython/py2/IPython/terminal/pt_inputhooks/glut.py
@@ -0,0 +1,141 @@
+"""GLUT Input hook for interactive use with prompt_toolkit
+"""
+from __future__ import print_function
+
+
+# GLUT is quite an old library and it is difficult to ensure proper
+# integration within IPython since original GLUT does not allow to handle
+# events one by one. Instead, it requires for the mainloop to be entered
+# and never returned (there is not even a function to exit he
+# mainloop). Fortunately, there are alternatives such as freeglut
+# (available for linux and windows) and the OSX implementation gives
+# access to a glutCheckLoop() function that blocks itself until a new
+# event is received. This means we have to setup the idle callback to
+# ensure we got at least one event that will unblock the function.
+#
+# Furthermore, it is not possible to install these handlers without a window
+# being first created. We choose to make this window invisible. This means that
+# display mode options are set at this level and user won't be able to change
+# them later without modifying the code. This should probably be made available
+# via IPython options system.
+
+import sys
+import time
+import signal
+import OpenGL.GLUT as glut
+import OpenGL.platform as platform
+from timeit import default_timer as clock
+
+# Frame per second : 60
+# Should probably be an IPython option
+glut_fps = 60
+
+# Display mode : double buffeed + rgba + depth
+# Should probably be an IPython option
+glut_display_mode = (glut.GLUT_DOUBLE |
+ glut.GLUT_RGBA |
+ glut.GLUT_DEPTH)
+
+glutMainLoopEvent = None
+if sys.platform == 'darwin':
+ try:
+ glutCheckLoop = platform.createBaseFunction(
+ 'glutCheckLoop', dll=platform.GLUT, resultType=None,
+ argTypes=[],
+ doc='glutCheckLoop( ) -> None',
+ argNames=(),
+ )
+ except AttributeError:
+ raise RuntimeError(
+ '''Your glut implementation does not allow interactive sessions'''
+ '''Consider installing freeglut.''')
+ glutMainLoopEvent = glutCheckLoop
+elif glut.HAVE_FREEGLUT:
+ glutMainLoopEvent = glut.glutMainLoopEvent
+else:
+ raise RuntimeError(
+ '''Your glut implementation does not allow interactive sessions. '''
+ '''Consider installing freeglut.''')
+
+
+def glut_display():
+ # Dummy display function
+ pass
+
+def glut_idle():
+ # Dummy idle function
+ pass
+
+def glut_close():
+ # Close function only hides the current window
+ glut.glutHideWindow()
+ glutMainLoopEvent()
+
+def glut_int_handler(signum, frame):
+ # Catch sigint and print the defaultipyt message
+ signal.signal(signal.SIGINT, signal.default_int_handler)
+ print('\nKeyboardInterrupt')
+ # Need to reprint the prompt at this stage
+
+# Initialisation code
+glut.glutInit( sys.argv )
+glut.glutInitDisplayMode( glut_display_mode )
+# This is specific to freeglut
+if bool(glut.glutSetOption):
+ glut.glutSetOption( glut.GLUT_ACTION_ON_WINDOW_CLOSE,
+ glut.GLUT_ACTION_GLUTMAINLOOP_RETURNS )
+glut.glutCreateWindow( b'ipython' )
+glut.glutReshapeWindow( 1, 1 )
+glut.glutHideWindow( )
+glut.glutWMCloseFunc( glut_close )
+glut.glutDisplayFunc( glut_display )
+glut.glutIdleFunc( glut_idle )
+
+
+def inputhook(context):
+ """Run the pyglet event loop by processing pending events only.
+
+ This keeps processing pending events until stdin is ready. After
+ processing all pending events, a call to time.sleep is inserted. This is
+ needed, otherwise, CPU usage is at 100%. This sleep time should be tuned
+ though for best performance.
+ """
+ # We need to protect against a user pressing Control-C when IPython is
+ # idle and this is running. We trap KeyboardInterrupt and pass.
+
+ signal.signal(signal.SIGINT, glut_int_handler)
+
+ try:
+ t = clock()
+
+ # Make sure the default window is set after a window has been closed
+ if glut.glutGetWindow() == 0:
+ glut.glutSetWindow( 1 )
+ glutMainLoopEvent()
+ return 0
+
+ while not context.input_is_ready():
+ glutMainLoopEvent()
+ # We need to sleep at this point to keep the idle CPU load
+ # low. However, if sleep to long, GUI response is poor. As
+ # a compromise, we watch how often GUI events are being processed
+ # and switch between a short and long sleep time. Here are some
+ # stats useful in helping to tune this.
+ # time CPU load
+ # 0.001 13%
+ # 0.005 3%
+ # 0.01 1.5%
+ # 0.05 0.5%
+ used_time = clock() - t
+ if used_time > 10.0:
+ # print 'Sleep for 1 s' # dbg
+ time.sleep(1.0)
+ elif used_time > 0.1:
+ # Few GUI events coming in, so we can sleep longer
+ # print 'Sleep for 0.05 s' # dbg
+ time.sleep(0.05)
+ else:
+ # Many GUI events coming in, so sleep only very little
+ time.sleep(0.001)
+ except KeyboardInterrupt:
+ pass
diff --git a/contrib/python/ipython/py2/IPython/terminal/pt_inputhooks/gtk.py b/contrib/python/ipython/py2/IPython/terminal/pt_inputhooks/gtk.py
new file mode 100644
index 00000000000..8f27e12c46d
--- /dev/null
+++ b/contrib/python/ipython/py2/IPython/terminal/pt_inputhooks/gtk.py
@@ -0,0 +1,59 @@
+# Code borrowed from python-prompt-toolkit examples
+# https://github.com/jonathanslenders/python-prompt-toolkit/blob/77cdcfbc7f4b4c34a9d2f9a34d422d7152f16209/examples/inputhook.py
+
+# Copyright (c) 2014, Jonathan Slenders
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification,
+# are permitted provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this
+# list of conditions and the following disclaimer.
+#
+# * Redistributions in binary form must reproduce the above copyright notice, this
+# list of conditions and the following disclaimer in the documentation and/or
+# other materials provided with the distribution.
+#
+# * Neither the name of the {organization} nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+# ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+"""
+PyGTK input hook for prompt_toolkit.
+
+Listens on the pipe prompt_toolkit sets up for a notification that it should
+return control to the terminal event loop.
+"""
+from __future__ import absolute_import
+
+import gtk, gobject
+
+# Enable threading in GTK. (Otherwise, GTK will keep the GIL.)
+gtk.gdk.threads_init()
+
+def inputhook(context):
+ """
+ When the eventloop of prompt-toolkit is idle, call this inputhook.
+
+ This will run the GTK main loop until the file descriptor
+ `context.fileno()` becomes ready.
+
+ :param context: An `InputHookContext` instance.
+ """
+ def _main_quit(*a, **kw):
+ gtk.main_quit()
+ return False
+
+ gobject.io_add_watch(context.fileno(), gobject.IO_IN, _main_quit)
+ gtk.main()
diff --git a/contrib/python/ipython/py2/IPython/terminal/pt_inputhooks/gtk3.py b/contrib/python/ipython/py2/IPython/terminal/pt_inputhooks/gtk3.py
new file mode 100644
index 00000000000..5c6c545457b
--- /dev/null
+++ b/contrib/python/ipython/py2/IPython/terminal/pt_inputhooks/gtk3.py
@@ -0,0 +1,12 @@
+"""prompt_toolkit input hook for GTK 3
+"""
+
+from gi.repository import Gtk, GLib
+
+def _main_quit(*args, **kwargs):
+ Gtk.main_quit()
+ return False
+
+def inputhook(context):
+ GLib.io_add_watch(context.fileno(), GLib.IO_IN, _main_quit)
+ Gtk.main()
diff --git a/contrib/python/ipython/py2/IPython/terminal/pt_inputhooks/osx.py b/contrib/python/ipython/py2/IPython/terminal/pt_inputhooks/osx.py
new file mode 100644
index 00000000000..53f4e3838b8
--- /dev/null
+++ b/contrib/python/ipython/py2/IPython/terminal/pt_inputhooks/osx.py
@@ -0,0 +1,137 @@
+"""Inputhook for OS X
+
+Calls NSApp / CoreFoundation APIs via ctypes.
+"""
+
+# obj-c boilerplate from appnope, used under BSD 2-clause
+
+import ctypes
+import ctypes.util
+from threading import Event
+
+objc = ctypes.cdll.LoadLibrary(ctypes.util.find_library('objc'))
+
+void_p = ctypes.c_void_p
+
+objc.objc_getClass.restype = void_p
+objc.sel_registerName.restype = void_p
+objc.objc_msgSend.restype = void_p
+objc.objc_msgSend.argtypes = [void_p, void_p]
+
+msg = objc.objc_msgSend
+
+def _utf8(s):
+ """ensure utf8 bytes"""
+ if not isinstance(s, bytes):
+ s = s.encode('utf8')
+ return s
+
+def n(name):
+ """create a selector name (for ObjC methods)"""
+ return objc.sel_registerName(_utf8(name))
+
+def C(classname):
+ """get an ObjC Class by name"""
+ return objc.objc_getClass(_utf8(classname))
+
+# end obj-c boilerplate from appnope
+
+# CoreFoundation C-API calls we will use:
+CoreFoundation = ctypes.cdll.LoadLibrary(ctypes.util.find_library('CoreFoundation'))
+
+CFFileDescriptorCreate = CoreFoundation.CFFileDescriptorCreate
+CFFileDescriptorCreate.restype = void_p
+CFFileDescriptorCreate.argtypes = [void_p, ctypes.c_int, ctypes.c_bool, void_p]
+
+CFFileDescriptorGetNativeDescriptor = CoreFoundation.CFFileDescriptorGetNativeDescriptor
+CFFileDescriptorGetNativeDescriptor.restype = ctypes.c_int
+CFFileDescriptorGetNativeDescriptor.argtypes = [void_p]
+
+CFFileDescriptorEnableCallBacks = CoreFoundation.CFFileDescriptorEnableCallBacks
+CFFileDescriptorEnableCallBacks.restype = None
+CFFileDescriptorEnableCallBacks.argtypes = [void_p, ctypes.c_ulong]
+
+CFFileDescriptorCreateRunLoopSource = CoreFoundation.CFFileDescriptorCreateRunLoopSource
+CFFileDescriptorCreateRunLoopSource.restype = void_p
+CFFileDescriptorCreateRunLoopSource.argtypes = [void_p, void_p, void_p]
+
+CFRunLoopGetCurrent = CoreFoundation.CFRunLoopGetCurrent
+CFRunLoopGetCurrent.restype = void_p
+
+CFRunLoopAddSource = CoreFoundation.CFRunLoopAddSource
+CFRunLoopAddSource.restype = None
+CFRunLoopAddSource.argtypes = [void_p, void_p, void_p]
+
+CFRelease = CoreFoundation.CFRelease
+CFRelease.restype = None
+CFRelease.argtypes = [void_p]
+
+CFFileDescriptorInvalidate = CoreFoundation.CFFileDescriptorInvalidate
+CFFileDescriptorInvalidate.restype = None
+CFFileDescriptorInvalidate.argtypes = [void_p]
+
+# From CFFileDescriptor.h
+kCFFileDescriptorReadCallBack = 1
+kCFRunLoopCommonModes = void_p.in_dll(CoreFoundation, 'kCFRunLoopCommonModes')
+
+
+def _NSApp():
+ """Return the global NSApplication instance (NSApp)"""
+ return msg(C('NSApplication'), n('sharedApplication'))
+
+
+def _wake(NSApp):
+ """Wake the Application"""
+ event = msg(C('NSEvent'),
+ n('otherEventWithType:location:modifierFlags:'
+ 'timestamp:windowNumber:context:subtype:data1:data2:'),
+ 15, # Type
+ 0, # location
+ 0, # flags
+ 0, # timestamp
+ 0, # window
+ None, # context
+ 0, # subtype
+ 0, # data1
+ 0, # data2
+ )
+ msg(NSApp, n('postEvent:atStart:'), void_p(event), True)
+
+
+_triggered = Event()
+
+def _input_callback(fdref, flags, info):
+ """Callback to fire when there's input to be read"""
+ _triggered.set()
+ CFFileDescriptorInvalidate(fdref)
+ CFRelease(fdref)
+ NSApp = _NSApp()
+ msg(NSApp, n('stop:'), NSApp)
+ _wake(NSApp)
+
+_c_callback_func_type = ctypes.CFUNCTYPE(None, void_p, void_p, void_p)
+_c_input_callback = _c_callback_func_type(_input_callback)
+
+
+def _stop_on_read(fd):
+ """Register callback to stop eventloop when there's data on fd"""
+ _triggered.clear()
+ fdref = CFFileDescriptorCreate(None, fd, False, _c_input_callback, None)
+ CFFileDescriptorEnableCallBacks(fdref, kCFFileDescriptorReadCallBack)
+ source = CFFileDescriptorCreateRunLoopSource(None, fdref, 0)
+ loop = CFRunLoopGetCurrent()
+ CFRunLoopAddSource(loop, source, kCFRunLoopCommonModes)
+ CFRelease(source)
+
+
+def inputhook(context):
+ """Inputhook for Cocoa (NSApp)"""
+ NSApp = _NSApp()
+ _stop_on_read(context.fileno())
+ msg(NSApp, n('run'))
+ if not _triggered.is_set():
+ # app closed without firing callback,
+ # probably due to last window being closed.
+ # Run the loop manually in this case,
+ # since there may be events still to process (#9734)
+ CoreFoundation.CFRunLoopRun()
diff --git a/contrib/python/ipython/py2/IPython/terminal/pt_inputhooks/pyglet.py b/contrib/python/ipython/py2/IPython/terminal/pt_inputhooks/pyglet.py
new file mode 100644
index 00000000000..1c5ec442504
--- /dev/null
+++ b/contrib/python/ipython/py2/IPython/terminal/pt_inputhooks/pyglet.py
@@ -0,0 +1,68 @@
+"""Enable pyglet to be used interacively with prompt_toolkit
+"""
+from __future__ import absolute_import
+
+import os
+import sys
+import time
+from timeit import default_timer as clock
+import pyglet
+
+# On linux only, window.flip() has a bug that causes an AttributeError on
+# window close. For details, see:
+# http://groups.google.com/group/pyglet-users/browse_thread/thread/47c1aab9aa4a3d23/c22f9e819826799e?#c22f9e819826799e
+
+if sys.platform.startswith('linux'):
+ def flip(window):
+ try:
+ window.flip()
+ except AttributeError:
+ pass
+else:
+ def flip(window):
+ window.flip()
+
+
+def inputhook(context):
+ """Run the pyglet event loop by processing pending events only.
+
+ This keeps processing pending events until stdin is ready. After
+ processing all pending events, a call to time.sleep is inserted. This is
+ needed, otherwise, CPU usage is at 100%. This sleep time should be tuned
+ though for best performance.
+ """
+ # We need to protect against a user pressing Control-C when IPython is
+ # idle and this is running. We trap KeyboardInterrupt and pass.
+ try:
+ t = clock()
+ while not context.input_is_ready():
+ pyglet.clock.tick()
+ for window in pyglet.app.windows:
+ window.switch_to()
+ window.dispatch_events()
+ window.dispatch_event('on_draw')
+ flip(window)
+
+ # We need to sleep at this point to keep the idle CPU load
+ # low. However, if sleep to long, GUI response is poor. As
+ # a compromise, we watch how often GUI events are being processed
+ # and switch between a short and long sleep time. Here are some
+ # stats useful in helping to tune this.
+ # time CPU load
+ # 0.001 13%
+ # 0.005 3%
+ # 0.01 1.5%
+ # 0.05 0.5%
+ used_time = clock() - t
+ if used_time > 10.0:
+ # print 'Sleep for 1 s' # dbg
+ time.sleep(1.0)
+ elif used_time > 0.1:
+ # Few GUI events coming in, so we can sleep longer
+ # print 'Sleep for 0.05 s' # dbg
+ time.sleep(0.05)
+ else:
+ # Many GUI events coming in, so sleep only very little
+ time.sleep(0.001)
+ except KeyboardInterrupt:
+ pass
diff --git a/contrib/python/ipython/py2/IPython/terminal/pt_inputhooks/qt.py b/contrib/python/ipython/py2/IPython/terminal/pt_inputhooks/qt.py
new file mode 100644
index 00000000000..7395ac39ebe
--- /dev/null
+++ b/contrib/python/ipython/py2/IPython/terminal/pt_inputhooks/qt.py
@@ -0,0 +1,49 @@
+import sys
+import os
+from IPython.external.qt_for_kernel import QtCore, QtGui
+
+# If we create a QApplication, keep a reference to it so that it doesn't get
+# garbage collected.
+_appref = None
+_already_warned = False
+
+def inputhook(context):
+ global _appref
+ app = QtCore.QCoreApplication.instance()
+ if not app:
+ if sys.platform == 'linux':
+ if not os.environ.get('DISPLAY') \
+ and not os.environ.get('WAYLAND_DISPLAY'):
+ import warnings
+ global _already_warned
+ if not _already_warned:
+ _already_warned = True
+ warnings.warn(
+ 'The DISPLAY or WAYLAND_DISPLAY enviroment variable is '
+ 'not set or empty and Qt5 requires this enviroment '
+ 'variable. Deactivate Qt5 code.'
+ )
+ return
+ _appref = app = QtGui.QApplication([" "])
+ event_loop = QtCore.QEventLoop(app)
+
+ if sys.platform == 'win32':
+ # The QSocketNotifier method doesn't appear to work on Windows.
+ # Use polling instead.
+ timer = QtCore.QTimer()
+ timer.timeout.connect(event_loop.quit)
+ while not context.input_is_ready():
+ timer.start(50) # 50 ms
+ event_loop.exec_()
+ timer.stop()
+ else:
+ # On POSIX platforms, we can use a file descriptor to quit the event
+ # loop when there is input ready to read.
+ notifier = QtCore.QSocketNotifier(context.fileno(),
+ QtCore.QSocketNotifier.Read)
+ # connect the callback we care about before we turn it on
+ notifier.activated.connect(event_loop.exit)
+ notifier.setEnabled(True)
+ # only start the event loop we are not already flipped
+ if not context.input_is_ready():
+ event_loop.exec_()
diff --git a/contrib/python/ipython/py2/IPython/terminal/pt_inputhooks/tk.py b/contrib/python/ipython/py2/IPython/terminal/pt_inputhooks/tk.py
new file mode 100644
index 00000000000..db205b0d2c1
--- /dev/null
+++ b/contrib/python/ipython/py2/IPython/terminal/pt_inputhooks/tk.py
@@ -0,0 +1,95 @@
+# Code borrowed from ptpython
+# https://github.com/jonathanslenders/ptpython/blob/86b71a89626114b18898a0af463978bdb32eeb70/ptpython/eventloop.py
+
+# Copyright (c) 2015, Jonathan Slenders
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification,
+# are permitted provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this
+# list of conditions and the following disclaimer.
+#
+# * Redistributions in binary form must reproduce the above copyright notice, this
+# list of conditions and the following disclaimer in the documentation and/or
+# other materials provided with the distribution.
+#
+# * Neither the name of the {organization} nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+# ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+"""
+Wrapper around the eventloop that gives some time to the Tkinter GUI to process
+events when it's loaded and while we are waiting for input at the REPL. This
+way we don't block the UI of for instance ``turtle`` and other Tk libraries.
+
+(Normally Tkinter registeres it's callbacks in ``PyOS_InputHook`` to integrate
+in readline. ``prompt-toolkit`` doesn't understand that input hook, but this
+will fix it for Tk.)
+"""
+import time
+
+from IPython.utils.py3compat import PY3
+
+import _tkinter
+if PY3:
+ import tkinter
+else:
+ import Tkinter as tkinter # Python 2
+
+def inputhook(inputhook_context):
+ """
+ Inputhook for Tk.
+ Run the Tk eventloop until prompt-toolkit needs to process the next input.
+ """
+ # Get the current TK application.
+ root = tkinter._default_root
+
+ def wait_using_filehandler():
+ """
+ Run the TK eventloop until the file handler that we got from the
+ inputhook becomes readable.
+ """
+ # Add a handler that sets the stop flag when `prompt-toolkit` has input
+ # to process.
+ stop = [False]
+ def done(*a):
+ stop[0] = True
+
+ root.createfilehandler(inputhook_context.fileno(), _tkinter.READABLE, done)
+
+ # Run the TK event loop as long as we don't receive input.
+ while root.dooneevent(_tkinter.ALL_EVENTS):
+ if stop[0]:
+ break
+
+ root.deletefilehandler(inputhook_context.fileno())
+
+ def wait_using_polling():
+ """
+ Windows TK doesn't support 'createfilehandler'.
+ So, run the TK eventloop and poll until input is ready.
+ """
+ while not inputhook_context.input_is_ready():
+ while root.dooneevent(_tkinter.ALL_EVENTS | _tkinter.DONT_WAIT):
+ pass
+ # Sleep to make the CPU idle, but not too long, so that the UI
+ # stays responsive.
+ time.sleep(.01)
+
+ if root is not None:
+ if hasattr(root, 'createfilehandler'):
+ wait_using_filehandler()
+ else:
+ wait_using_polling()
diff --git a/contrib/python/ipython/py2/IPython/terminal/pt_inputhooks/wx.py b/contrib/python/ipython/py2/IPython/terminal/pt_inputhooks/wx.py
new file mode 100644
index 00000000000..4371b21cb47
--- /dev/null
+++ b/contrib/python/ipython/py2/IPython/terminal/pt_inputhooks/wx.py
@@ -0,0 +1,148 @@
+"""Enable wxPython to be used interacively in prompt_toolkit
+"""
+from __future__ import absolute_import
+
+import sys
+import signal
+import time
+from timeit import default_timer as clock
+import wx
+
+
+def inputhook_wx1(context):
+ """Run the wx event loop by processing pending events only.
+
+ This approach seems to work, but its performance is not great as it
+ relies on having PyOS_InputHook called regularly.
+ """
+ try:
+ app = wx.GetApp()
+ if app is not None:
+ assert wx.Thread_IsMain()
+
+ # Make a temporary event loop and process system events until
+ # there are no more waiting, then allow idle events (which
+ # will also deal with pending or posted wx events.)
+ evtloop = wx.EventLoop()
+ ea = wx.EventLoopActivator(evtloop)
+ while evtloop.Pending():
+ evtloop.Dispatch()
+ app.ProcessIdle()
+ del ea
+ except KeyboardInterrupt:
+ pass
+ return 0
+
+class EventLoopTimer(wx.Timer):
+
+ def __init__(self, func):
+ self.func = func
+ wx.Timer.__init__(self)
+
+ def Notify(self):
+ self.func()
+
+class EventLoopRunner(object):
+
+ def Run(self, time, input_is_ready):
+ self.input_is_ready = input_is_ready
+ self.evtloop = wx.EventLoop()
+ self.timer = EventLoopTimer(self.check_stdin)
+ self.timer.Start(time)
+ self.evtloop.Run()
+
+ def check_stdin(self):
+ if self.input_is_ready():
+ self.timer.Stop()
+ self.evtloop.Exit()
+
+def inputhook_wx2(context):
+ """Run the wx event loop, polling for stdin.
+
+ This version runs the wx eventloop for an undetermined amount of time,
+ during which it periodically checks to see if anything is ready on
+ stdin. If anything is ready on stdin, the event loop exits.
+
+ The argument to elr.Run controls how often the event loop looks at stdin.
+ This determines the responsiveness at the keyboard. A setting of 1000
+ enables a user to type at most 1 char per second. I have found that a
+ setting of 10 gives good keyboard response. We can shorten it further,
+ but eventually performance would suffer from calling select/kbhit too
+ often.
+ """
+ try:
+ app = wx.GetApp()
+ if app is not None:
+ assert wx.Thread_IsMain()
+ elr = EventLoopRunner()
+ # As this time is made shorter, keyboard response improves, but idle
+ # CPU load goes up. 10 ms seems like a good compromise.
+ elr.Run(time=10, # CHANGE time here to control polling interval
+ input_is_ready=context.input_is_ready)
+ except KeyboardInterrupt:
+ pass
+ return 0
+
+def inputhook_wx3(context):
+ """Run the wx event loop by processing pending events only.
+
+ This is like inputhook_wx1, but it keeps processing pending events
+ until stdin is ready. After processing all pending events, a call to
+ time.sleep is inserted. This is needed, otherwise, CPU usage is at 100%.
+ This sleep time should be tuned though for best performance.
+ """
+ # We need to protect against a user pressing Control-C when IPython is
+ # idle and this is running. We trap KeyboardInterrupt and pass.
+ try:
+ app = wx.GetApp()
+ if app is not None:
+ assert wx.Thread_IsMain()
+
+ # The import of wx on Linux sets the handler for signal.SIGINT
+ # to 0. This is a bug in wx or gtk. We fix by just setting it
+ # back to the Python default.
+ if not callable(signal.getsignal(signal.SIGINT)):
+ signal.signal(signal.SIGINT, signal.default_int_handler)
+
+ evtloop = wx.EventLoop()
+ ea = wx.EventLoopActivator(evtloop)
+ t = clock()
+ while not context.input_is_ready():
+ while evtloop.Pending():
+ t = clock()
+ evtloop.Dispatch()
+ app.ProcessIdle()
+ # We need to sleep at this point to keep the idle CPU load
+ # low. However, if sleep to long, GUI response is poor. As
+ # a compromise, we watch how often GUI events are being processed
+ # and switch between a short and long sleep time. Here are some
+ # stats useful in helping to tune this.
+ # time CPU load
+ # 0.001 13%
+ # 0.005 3%
+ # 0.01 1.5%
+ # 0.05 0.5%
+ used_time = clock() - t
+ if used_time > 10.0:
+ # print 'Sleep for 1 s' # dbg
+ time.sleep(1.0)
+ elif used_time > 0.1:
+ # Few GUI events coming in, so we can sleep longer
+ # print 'Sleep for 0.05 s' # dbg
+ time.sleep(0.05)
+ else:
+ # Many GUI events coming in, so sleep only very little
+ time.sleep(0.001)
+ del ea
+ except KeyboardInterrupt:
+ pass
+ return 0
+
+if sys.platform == 'darwin':
+ # On OSX, evtloop.Pending() always returns True, regardless of there being
+ # any events pending. As such we can't use implementations 1 or 3 of the
+ # inputhook as those depend on a pending/dispatch loop.
+ inputhook = inputhook_wx2
+else:
+ # This is our default implementation
+ inputhook = inputhook_wx3
diff --git a/contrib/python/ipython/py2/IPython/terminal/ptshell.py b/contrib/python/ipython/py2/IPython/terminal/ptshell.py
new file mode 100644
index 00000000000..666d3c5b514
--- /dev/null
+++ b/contrib/python/ipython/py2/IPython/terminal/ptshell.py
@@ -0,0 +1,8 @@
+raise DeprecationWarning("""DEPRECATED:
+
+After Popular request and decision from the BDFL:
+`IPython.terminal.ptshell` has been moved back to `IPython.terminal.interactiveshell`
+during the beta cycle (after IPython 5.0.beta3) Sorry about that.
+
+This file will be removed in 5.0 rc or final.
+""")
diff --git a/contrib/python/ipython/py2/IPython/terminal/ptutils.py b/contrib/python/ipython/py2/IPython/terminal/ptutils.py
new file mode 100644
index 00000000000..c9ff705642d
--- /dev/null
+++ b/contrib/python/ipython/py2/IPython/terminal/ptutils.py
@@ -0,0 +1,115 @@
+"""prompt-toolkit utilities
+
+Everything in this module is a private API,
+not to be used outside IPython.
+"""
+
+# Copyright (c) IPython Development Team.
+# Distributed under the terms of the Modified BSD License.
+
+import unicodedata
+from wcwidth import wcwidth
+
+from IPython.utils.py3compat import PY3
+
+from IPython.core.completer import IPCompleter
+from prompt_toolkit.completion import Completer, Completion
+from prompt_toolkit.layout.lexers import Lexer
+from prompt_toolkit.layout.lexers import PygmentsLexer
+
+import pygments.lexers as pygments_lexers
+
+
+class IPythonPTCompleter(Completer):
+ """Adaptor to provide IPython completions to prompt_toolkit"""
+ def __init__(self, ipy_completer=None, shell=None, patch_stdout=None):
+ if shell is None and ipy_completer is None:
+ raise TypeError("Please pass shell=an InteractiveShell instance.")
+ self._ipy_completer = ipy_completer
+ self.shell = shell
+ if patch_stdout is None:
+ raise TypeError("Please pass patch_stdout")
+ self.patch_stdout = patch_stdout
+
+ @property
+ def ipy_completer(self):
+ if self._ipy_completer:
+ return self._ipy_completer
+ else:
+ return self.shell.Completer
+
+ def get_completions(self, document, complete_event):
+ if not document.current_line.strip():
+ return
+
+ # Some bits of our completion system may print stuff (e.g. if a module
+ # is imported). This context manager ensures that doesn't interfere with
+ # the prompt.
+ with self.patch_stdout():
+ used, matches = self.ipy_completer.complete(
+ line_buffer=document.current_line,
+ cursor_pos=document.cursor_position_col
+ )
+ start_pos = -len(used)
+ for m in matches:
+ if not m:
+ # Guard against completion machinery giving us an empty string.
+ continue
+
+ m = unicodedata.normalize('NFC', m)
+
+ # When the first character of the completion has a zero length,
+ # then it's probably a decomposed unicode character. E.g. caused by
+ # the "\dot" completion. Try to compose again with the previous
+ # character.
+ if wcwidth(m[0]) == 0:
+ if document.cursor_position + start_pos > 0:
+ char_before = document.text[document.cursor_position + start_pos - 1]
+ m = unicodedata.normalize('NFC', char_before + m)
+
+ # Yield the modified completion instead, if this worked.
+ if wcwidth(m[0:1]) == 1:
+ yield Completion(m, start_position=start_pos - 1)
+ continue
+
+ # TODO: Use Jedi to determine meta_text
+ # (Jedi currently has a bug that results in incorrect information.)
+ # meta_text = ''
+ # yield Completion(m, start_position=start_pos,
+ # display_meta=meta_text)
+ yield Completion(m, start_position=start_pos)
+
+class IPythonPTLexer(Lexer):
+ """
+ Wrapper around PythonLexer and BashLexer.
+ """
+ def __init__(self):
+ l = pygments_lexers
+ self.python_lexer = PygmentsLexer(l.Python3Lexer if PY3 else l.PythonLexer)
+ self.shell_lexer = PygmentsLexer(l.BashLexer)
+
+ self.magic_lexers = {
+ 'HTML': PygmentsLexer(l.HtmlLexer),
+ 'html': PygmentsLexer(l.HtmlLexer),
+ 'javascript': PygmentsLexer(l.JavascriptLexer),
+ 'js': PygmentsLexer(l.JavascriptLexer),
+ 'perl': PygmentsLexer(l.PerlLexer),
+ 'ruby': PygmentsLexer(l.RubyLexer),
+ 'latex': PygmentsLexer(l.TexLexer),
+ }
+
+ def lex_document(self, cli, document):
+ text = document.text.lstrip()
+
+ lexer = self.python_lexer
+
+ if text.startswith('!') or text.startswith('%%bash'):
+ lexer = self.shell_lexer
+
+ elif text.startswith('%%'):
+ for magic, l in self.magic_lexers.items():
+ if text.startswith('%%' + magic):
+ lexer = l
+ break
+
+ return lexer.lex_document(cli, document)
diff --git a/contrib/python/ipython/py2/IPython/terminal/shortcuts.py b/contrib/python/ipython/py2/IPython/terminal/shortcuts.py
new file mode 100644
index 00000000000..8f0ae43e849
--- /dev/null
+++ b/contrib/python/ipython/py2/IPython/terminal/shortcuts.py
@@ -0,0 +1,206 @@
+import signal
+import sys
+
+from prompt_toolkit.enums import DEFAULT_BUFFER, SEARCH_BUFFER
+from prompt_toolkit.filters import (HasFocus, HasSelection, Condition,
+ ViInsertMode, EmacsInsertMode, HasCompletions)
+from prompt_toolkit.filters.cli import ViMode
+from prompt_toolkit.keys import Keys
+from prompt_toolkit.key_binding.bindings.completion import display_completions_like_readline
+
+from IPython.utils.decorators import undoc
+
+@Condition
+def cursor_in_leading_ws(cli):
+ before = cli.application.buffer.document.current_line_before_cursor
+ return (not before) or before.isspace()
+
+def register_ipython_shortcuts(registry, shell):
+ """Set up the prompt_toolkit keyboard shortcuts for IPython"""
+ insert_mode = ViInsertMode() | EmacsInsertMode()
+
+ # Ctrl+J == Enter, seemingly
+ registry.add_binding(Keys.ControlJ,
+ filter=(HasFocus(DEFAULT_BUFFER)
+ & ~HasSelection()
+ & insert_mode
+ ))(newline_or_execute_outer(shell))
+
+ registry.add_binding(Keys.ControlBackslash)(force_exit)
+
+ registry.add_binding(Keys.ControlP,
+ filter=(ViInsertMode() & HasFocus(DEFAULT_BUFFER)
+ ))(previous_history_or_previous_completion)
+
+ registry.add_binding(Keys.ControlN,
+ filter=(ViInsertMode() & HasFocus(DEFAULT_BUFFER)
+ ))(next_history_or_next_completion)
+
+ registry.add_binding(Keys.ControlG,
+ filter=(HasFocus(DEFAULT_BUFFER) & HasCompletions()
+ ))(dismiss_completion)
+
+ registry.add_binding(Keys.ControlC, filter=HasFocus(DEFAULT_BUFFER)
+ )(reset_buffer)
+
+ registry.add_binding(Keys.ControlC, filter=HasFocus(SEARCH_BUFFER)
+ )(reset_search_buffer)
+
+ supports_suspend = Condition(lambda cli: hasattr(signal, 'SIGTSTP'))
+ registry.add_binding(Keys.ControlZ, filter=supports_suspend
+ )(suspend_to_bg)
+
+ # Ctrl+I == Tab
+ registry.add_binding(Keys.ControlI,
+ filter=(HasFocus(DEFAULT_BUFFER)
+ & ~HasSelection()
+ & insert_mode
+ & cursor_in_leading_ws
+ ))(indent_buffer)
+
+ registry.add_binding(Keys.ControlO,
+ filter=(HasFocus(DEFAULT_BUFFER)
+ & EmacsInsertMode()))(newline_with_copy_margin)
+
+ registry.add_binding(Keys.F2,
+ filter=HasFocus(DEFAULT_BUFFER)
+ )(open_input_in_editor)
+
+ if shell.display_completions == 'readlinelike':
+ registry.add_binding(Keys.ControlI,
+ filter=(HasFocus(DEFAULT_BUFFER)
+ & ~HasSelection()
+ & insert_mode
+ & ~cursor_in_leading_ws
+ ))(display_completions_like_readline)
+
+ if sys.platform == 'win32':
+ registry.add_binding(Keys.ControlV,
+ filter=(
+ HasFocus(
+ DEFAULT_BUFFER) & ~ViMode()
+ ))(win_paste)
+
+
+def newline_or_execute_outer(shell):
+ def newline_or_execute(event):
+ """When the user presses return, insert a newline or execute the code."""
+ b = event.current_buffer
+ d = b.document
+
+ if b.complete_state:
+ cc = b.complete_state.current_completion
+ if cc:
+ b.apply_completion(cc)
+ else:
+ b.cancel_completion()
+ return
+
+ # If there's only one line, treat it as if the cursor is at the end.
+ # See https://github.com/ipython/ipython/issues/10425
+ if d.line_count == 1:
+ check_text = d.text
+ else:
+ check_text = d.text[:d.cursor_position]
+ status, indent = shell.input_splitter.check_complete(check_text + '\n')
+
+ if not (d.on_last_line or
+ d.cursor_position_row >= d.line_count - d.empty_line_count_at_the_end()
+ ):
+ b.insert_text('\n' + (' ' * (indent or 0)))
+ return
+
+ if (status != 'incomplete') and b.accept_action.is_returnable:
+ b.accept_action.validate_and_handle(event.cli, b)
+ else:
+ b.insert_text('\n' + (' ' * (indent or 0)))
+ return newline_or_execute
+
+
+def previous_history_or_previous_completion(event):
+ """
+ Control-P in vi edit mode on readline is history next, unlike default prompt toolkit.
+
+ If completer is open this still select previous completion.
+ """
+ event.current_buffer.auto_up()
+
+
+def next_history_or_next_completion(event):
+ """
+ Control-N in vi edit mode on readline is history previous, unlike default prompt toolkit.
+
+ If completer is open this still select next completion.
+ """
+ event.current_buffer.auto_down()
+
+
+def dismiss_completion(event):
+ b = event.current_buffer
+ if b.complete_state:
+ b.cancel_completion()
+
+
+def reset_buffer(event):
+ b = event.current_buffer
+ if b.complete_state:
+ b.cancel_completion()
+ else:
+ b.reset()
+
+
+def reset_search_buffer(event):
+ if event.current_buffer.document.text:
+ event.current_buffer.reset()
+ else:
+ event.cli.push_focus(DEFAULT_BUFFER)
+
+def suspend_to_bg(event):
+ event.cli.suspend_to_background()
+
+def force_exit(event):
+ """
+ Force exit (with a non-zero return value)
+ """
+ sys.exit("Quit")
+
+def indent_buffer(event):
+ event.current_buffer.insert_text(' ' * 4)
+
+def newline_with_copy_margin(event):
+ """
+ Preserve margin and cursor position when using
+ Control-O to insert a newline in EMACS mode
+ """
+ b = event.current_buffer
+ cursor_start_pos = b.document.cursor_position_col
+ b.newline(copy_margin=True)
+ b.cursor_up(count=1)
+ cursor_end_pos = b.document.cursor_position_col
+ if cursor_start_pos != cursor_end_pos:
+ pos_diff = cursor_start_pos - cursor_end_pos
+ b.cursor_right(count=pos_diff)
+
+def open_input_in_editor(event):
+ event.cli.current_buffer.tempfile_suffix = ".py"
+ event.cli.current_buffer.open_in_editor(event.cli)
+
+
+if sys.platform == 'win32':
+ from IPython.core.error import TryNext
+ from IPython.lib.clipboard import (ClipboardEmpty,
+ win32_clipboard_get,
+ tkinter_clipboard_get)
+
+ @undoc
+ def win_paste(event):
+ try:
+ text = win32_clipboard_get()
+ except TryNext:
+ try:
+ text = tkinter_clipboard_get()
+ except (TryNext, ClipboardEmpty):
+ return
+ except ClipboardEmpty:
+ return
+ event.current_buffer.insert_text(text.replace('\t', ' ' * 4))