visualizer: Restore ipython support
Changes are based on [1].
Dropped compatibility code for ipython versions < 5.0.0.
[1] 68e4f4bbec/plugins/ipython_view.py
This commit is contained in:
committed by
Gabriel Ferreira
parent
11a6696ead
commit
b8d8c64e0e
@@ -69,7 +69,7 @@ else:
|
||||
_import_error = None
|
||||
|
||||
try:
|
||||
import ipython_viewxxxxxxxxxx
|
||||
from . import ipython_view
|
||||
except ImportError:
|
||||
ipython_view = None
|
||||
|
||||
|
||||
@@ -13,15 +13,21 @@ is available at U{http://www.opensource.org/licenses/bsd-license.php}
|
||||
# this file is a modified version of source code from the Accerciser project
|
||||
# https://wiki.gnome.org/Apps/Accerciser
|
||||
|
||||
import gtk, gobject
|
||||
import gi
|
||||
gi.require_version('Gtk', '3.0')
|
||||
from gi.repository import Gtk
|
||||
from gi.repository import Gdk
|
||||
from gi.repository import GLib
|
||||
from gi.repository import Pango
|
||||
|
||||
from pkg_resources import parse_version
|
||||
|
||||
import re
|
||||
import sys
|
||||
import os
|
||||
from gi.repository import Pango
|
||||
from StringIO import StringIO
|
||||
import IPython
|
||||
|
||||
from pkg_resources import parse_version
|
||||
from io import StringIO
|
||||
from functools import reduce
|
||||
|
||||
## Try to import IPython
|
||||
try:
|
||||
@@ -41,6 +47,12 @@ class IterableIPShell:
|
||||
# history level
|
||||
## @var complete_sep
|
||||
# separators
|
||||
## @var no_input_splitter
|
||||
# no input splitter
|
||||
## @var lines
|
||||
# lines
|
||||
## @var indent_spaces
|
||||
# indent spaces
|
||||
## @var prompt
|
||||
# prompt
|
||||
## @var header
|
||||
@@ -52,8 +64,8 @@ class IterableIPShell:
|
||||
## @var raw_input
|
||||
# raw input
|
||||
## Constructor
|
||||
def __init__(self,argv=None,user_ns=None,user_global_ns=None,
|
||||
cin=None, cout=None,cerr=None, input_func=None):
|
||||
def __init__(self, argv=[], user_ns=None, user_global_ns=None,
|
||||
cin=None, cout=None, cerr=None, input_func=None):
|
||||
"""! Initializer
|
||||
|
||||
@param self: this object
|
||||
@@ -67,45 +79,47 @@ class IterableIPShell:
|
||||
"""
|
||||
io = IPython.utils.io
|
||||
if input_func:
|
||||
if parse_version(IPython.release.version) >= parse_version("1.2.1"):
|
||||
IPython.terminal.interactiveshell.raw_input_original = input_func
|
||||
else:
|
||||
IPython.frontend.terminal.interactiveshell.raw_input_original = input_func
|
||||
if cin:
|
||||
io.stdin = io.IOStream(cin)
|
||||
if cout:
|
||||
io.stdout = io.IOStream(cout)
|
||||
if cerr:
|
||||
io.stderr = io.IOStream(cerr)
|
||||
IPython.terminal.interactiveshell.raw_input_original = input_func
|
||||
if IPython.version_info < (8,):
|
||||
if cin:
|
||||
io.stdin = io.IOStream(cin)
|
||||
if cout:
|
||||
io.stdout = io.IOStream(cout)
|
||||
if cerr:
|
||||
io.stderr = io.IOStream(cerr)
|
||||
else:
|
||||
if cin:
|
||||
sys.stdin = cin
|
||||
if cout:
|
||||
sys.stdout = cout
|
||||
if cerr:
|
||||
sys.stderr = cerr
|
||||
|
||||
# This is to get rid of the blockage that occurs during
|
||||
# IPython.Shell.InteractiveShell.user_setup()
|
||||
|
||||
io.raw_input = lambda x: None
|
||||
|
||||
os.environ['TERM'] = 'dumb'
|
||||
excepthook = sys.excepthook
|
||||
|
||||
from IPython.config.loader import Config
|
||||
from traitlets.config.loader import Config
|
||||
cfg = Config()
|
||||
cfg.InteractiveShell.colors = "Linux"
|
||||
cfg.Completer.use_jedi = False
|
||||
|
||||
# InteractiveShell's __init__ overwrites io.stdout,io.stderr with
|
||||
# sys.stdout, sys.stderr, this makes sure they are right
|
||||
#
|
||||
old_stdout, old_stderr = sys.stdout, sys.stderr
|
||||
sys.stdout, sys.stderr = io.stdout.stream, io.stderr.stream
|
||||
if IPython.version_info < (8,):
|
||||
# InteractiveShell's __init__ overwrites io.stdout,io.stderr with
|
||||
# sys.stdout, sys.stderr, this makes sure they are right
|
||||
old_stdout, old_stderr = sys.stdout, sys.stderr
|
||||
sys.stdout, sys.stderr = io.stdout.stream, io.stderr.stream
|
||||
|
||||
# InteractiveShell inherits from SingletonConfigurable, so use instance()
|
||||
#
|
||||
if parse_version(IPython.release.version) >= parse_version("1.2.1"):
|
||||
self.IP = IPython.terminal.embed.InteractiveShellEmbed.instance(\
|
||||
config=cfg, user_ns=user_ns)
|
||||
else:
|
||||
self.IP = IPython.frontend.terminal.embed.InteractiveShellEmbed.instance(\
|
||||
self.IP = IPython.terminal.embed.InteractiveShellEmbed.instance(\
|
||||
config=cfg, user_ns=user_ns)
|
||||
|
||||
sys.stdout, sys.stderr = old_stdout, old_stderr
|
||||
if IPython.version_info < (8,):
|
||||
sys.stdout, sys.stderr = old_stdout, old_stderr
|
||||
|
||||
self.IP.system = lambda cmd: self.shell(self.IP.var_expand(cmd),
|
||||
header='IPython system call: ')
|
||||
@@ -120,11 +134,17 @@ class IterableIPShell:
|
||||
self.complete_sep = re.compile('[\s\{\}\[\]\(\)]')
|
||||
self.updateNamespace({'exit':lambda:None})
|
||||
self.updateNamespace({'quit':lambda:None})
|
||||
self.IP.readline_startup_hook(self.IP.pre_readline)
|
||||
# Workaround for updating namespace with sys.modules
|
||||
#
|
||||
self.__update_namespace()
|
||||
|
||||
# Avoid using input splitter when not really needed.
|
||||
# Perhaps it could work even before 5.8.0
|
||||
# But it definitely does not work any more with >= 7.0.0
|
||||
self.no_input_splitter = parse_version(IPython.release.version) >= parse_version('5.8.0')
|
||||
self.lines = []
|
||||
self.indent_spaces = ''
|
||||
|
||||
def __update_namespace(self):
|
||||
"""!
|
||||
Update self.IP namespace for autocompletion with sys.modules
|
||||
@@ -140,11 +160,17 @@ class IterableIPShell:
|
||||
@return none
|
||||
"""
|
||||
self.history_level = 0
|
||||
orig_stdout = sys.stdout
|
||||
sys.stdout = IPython.utils.io.stdout
|
||||
|
||||
orig_stdin = sys.stdin
|
||||
sys.stdin = IPython.utils.io.stdin;
|
||||
if IPython.version_info < (8,):
|
||||
# this is needed because some functions in IPython use 'print' to print
|
||||
# output (like 'who')
|
||||
|
||||
orig_stdout = sys.stdout
|
||||
sys.stdout = IPython.utils.io.stdout
|
||||
|
||||
orig_stdin = sys.stdin
|
||||
sys.stdin = IPython.utils.io.stdin
|
||||
|
||||
self.prompt = self.generatePrompt(self.iter_more)
|
||||
|
||||
self.IP.hooks.pre_prompt_hook()
|
||||
@@ -160,21 +186,26 @@ class IterableIPShell:
|
||||
line = self.IP.raw_input(self.prompt)
|
||||
except KeyboardInterrupt:
|
||||
self.IP.write('\nKeyboardInterrupt\n')
|
||||
self.IP.input_splitter.reset()
|
||||
if self.no_input_splitter:
|
||||
self.lines = []
|
||||
else:
|
||||
self.IP.input_splitter.reset()
|
||||
except:
|
||||
self.IP.showtraceback()
|
||||
else:
|
||||
self.IP.input_splitter.push(line)
|
||||
self.iter_more = self.IP.input_splitter.push_accepts_more()
|
||||
self.prompt = self.generatePrompt(self.iter_more)
|
||||
if (self.IP.SyntaxTB.last_syntax_error and
|
||||
self.IP.autoedit_syntax):
|
||||
self.IP.edit_syntax_error()
|
||||
if self.no_input_splitter:
|
||||
self.lines.append(line)
|
||||
(status, self.indent_spaces) = self.IP.check_complete('\n'.join(self.lines))
|
||||
self.iter_more = status == 'incomplete'
|
||||
else:
|
||||
self.IP.input_splitter.push(line)
|
||||
self.iter_more = self.IP.input_splitter.push_accepts_more()
|
||||
if not self.iter_more:
|
||||
if parse_version(IPython.release.version) >= parse_version("2.0.0-dev"):
|
||||
source_raw = self.IP.input_splitter.raw_reset()
|
||||
if self.no_input_splitter:
|
||||
source_raw = '\n'.join(self.lines)
|
||||
self.lines = []
|
||||
else:
|
||||
source_raw = self.IP.input_splitter.source_raw_reset()[1]
|
||||
source_raw = self.IP.input_splitter.raw_reset()
|
||||
self.IP.run_cell(source_raw, store_history=True)
|
||||
self.IP.rl_do_indent = False
|
||||
else:
|
||||
@@ -182,9 +213,11 @@ class IterableIPShell:
|
||||
#
|
||||
self.IP.rl_do_indent = True
|
||||
pass
|
||||
self.prompt = self.generatePrompt(self.iter_more)
|
||||
|
||||
sys.stdout = orig_stdout
|
||||
sys.stdin = orig_stdin
|
||||
if IPython.version_info < (8,):
|
||||
sys.stdout = orig_stdout
|
||||
sys.stdin = orig_stdin
|
||||
|
||||
def generatePrompt(self, is_continuation):
|
||||
"""!
|
||||
@@ -195,17 +228,10 @@ class IterableIPShell:
|
||||
|
||||
"""
|
||||
|
||||
# Backwards compatibility with ipyton-0.11
|
||||
#
|
||||
ver = IPython.__version__
|
||||
if '0.11' in ver:
|
||||
prompt = self.IP.hooks.generate_prompt(is_continuation)
|
||||
if is_continuation:
|
||||
prompt = '... '
|
||||
else:
|
||||
if is_continuation:
|
||||
prompt = self.IP.prompt_manager.render('in2')
|
||||
else:
|
||||
prompt = self.IP.prompt_manager.render('in')
|
||||
|
||||
prompt = '>>> '
|
||||
return prompt
|
||||
|
||||
|
||||
@@ -281,7 +307,7 @@ class IterableIPShell:
|
||||
return str1[:i]
|
||||
return str1
|
||||
if possibilities[1]:
|
||||
common_prefix = reduce(_commonPrefix, possibilities[1]) or line[-1]
|
||||
common_prefix = reduce(_commonPrefix, possibilities[1]) or split_line[-1]
|
||||
completed = line[:-len(split_line[-1])]+common_prefix
|
||||
else:
|
||||
completed = line
|
||||
@@ -324,7 +350,8 @@ class ConsoleView(Gtk.TextView):
|
||||
"""
|
||||
Specialized text view for console-like workflow.
|
||||
|
||||
@cvar ANSI_COLORS: Mapping of terminal colors to X11 names.
|
||||
@cvar ANSI_COLORS: Mapping of terminal control sequence values to
|
||||
tuples containing foreground and background color names.
|
||||
@type ANSI_COLORS: dictionary
|
||||
|
||||
@ivar text_buffer: Widget's text buffer.
|
||||
@@ -336,20 +363,35 @@ class ConsoleView(Gtk.TextView):
|
||||
@ivar line_start: Start of command line mark.
|
||||
@type line_start: Gtk.TextMark
|
||||
"""
|
||||
ANSI_COLORS = {'0;30': 'Black', '0;31': 'Red',
|
||||
'0;32': 'Green', '0;33': 'Brown',
|
||||
'0;34': 'Blue', '0;35': 'Purple',
|
||||
'0;36': 'Cyan', '0;37': 'LightGray',
|
||||
'1;30': 'DarkGray', '1;31': 'DarkRed',
|
||||
'1;32': 'SeaGreen', '1;33': 'Yellow',
|
||||
'1;34': 'LightBlue', '1;35': 'MediumPurple',
|
||||
'1;36': 'LightCyan', '1;37': 'White'}
|
||||
ANSI_COLORS = {'0;30': ('Black', None),
|
||||
'0;31': ('Red', None),
|
||||
'0;32': ('Green', None),
|
||||
'0;33': ('Brown', None),
|
||||
'0;34': ('Blue', None),
|
||||
'0;35': ('Purple', None),
|
||||
'0;36': ('Cyan', None),
|
||||
'0;37': ('LightGray', None),
|
||||
'1;30': ('DarkGray', None),
|
||||
'1;31': ('DarkRed', None),
|
||||
'1;32': ('SeaGreen', None),
|
||||
'1;33': ('Yellow', None),
|
||||
'1;34': ('LightBlue', None),
|
||||
'1;35': ('MediumPurple', None),
|
||||
'1;36': ('LightCyan', None),
|
||||
'1;37': ('White', None),
|
||||
'38;5;124;43': ('DarkRed', 'Yellow'),
|
||||
'38;5;241': ('Gray', None),
|
||||
'38;5;241;43': ('Gray', 'Yellow'),
|
||||
'39': ('Black', None),
|
||||
'39;49': ('Red', 'White'),
|
||||
'43': (None, 'Yellow'),
|
||||
'49': (None, 'White')}
|
||||
|
||||
def __init__(self):
|
||||
"""
|
||||
Initialize console view.
|
||||
"""
|
||||
GObject.GObject.__init__(self)
|
||||
Gtk.TextView.__init__(self)
|
||||
self.modify_font(Pango.FontDescription('Mono'))
|
||||
self.set_cursor_visible(True)
|
||||
self.text_buffer = self.get_buffer()
|
||||
@@ -358,7 +400,8 @@ class ConsoleView(Gtk.TextView):
|
||||
False)
|
||||
for code in self.ANSI_COLORS:
|
||||
self.text_buffer.create_tag(code,
|
||||
foreground=self.ANSI_COLORS[code],
|
||||
foreground=self.ANSI_COLORS[code][0],
|
||||
background=self.ANSI_COLORS[code][1],
|
||||
weight=700)
|
||||
self.text_buffer.create_tag('0')
|
||||
self.text_buffer.create_tag('notouch', editable=False)
|
||||
@@ -376,7 +419,7 @@ class ConsoleView(Gtk.TextView):
|
||||
@param editable: If true, added text is editable.
|
||||
@return none
|
||||
"""
|
||||
GObject.idle_add(self._write, text, editable)
|
||||
GLib.idle_add(self._write, text, editable)
|
||||
|
||||
def _write(self, text, editable=False):
|
||||
"""!
|
||||
@@ -414,7 +457,7 @@ class ConsoleView(Gtk.TextView):
|
||||
@param prompt: Prompt to print.
|
||||
@return none
|
||||
"""
|
||||
GObject.idle_add(self._showPrompt, prompt)
|
||||
GLib.idle_add(self._showPrompt, prompt)
|
||||
|
||||
def _showPrompt(self, prompt):
|
||||
"""!
|
||||
@@ -434,7 +477,7 @@ class ConsoleView(Gtk.TextView):
|
||||
@param text: Text to use as replacement.
|
||||
@return none
|
||||
"""
|
||||
GObject.idle_add(self._changeLine, text)
|
||||
GLib.idle_add(self._changeLine, text)
|
||||
|
||||
def _changeLine(self, text):
|
||||
"""!
|
||||
@@ -466,7 +509,7 @@ class ConsoleView(Gtk.TextView):
|
||||
@param text: Text to show.
|
||||
@return none
|
||||
"""
|
||||
GObject.idle_add(self._showReturned, text)
|
||||
GLib.idle_add(self._showReturned, text)
|
||||
|
||||
def _showReturned(self, text):
|
||||
"""!
|
||||
@@ -485,11 +528,14 @@ class ConsoleView(Gtk.TextView):
|
||||
if text:
|
||||
self._write('\n')
|
||||
self._showPrompt(self.prompt)
|
||||
self.text_buffer.move_mark(self.line_start,self.text_buffer.get_end_iter())
|
||||
self.text_buffer.move_mark(self.line_start, self.text_buffer.get_end_iter())
|
||||
self.text_buffer.place_cursor(self.text_buffer.get_end_iter())
|
||||
|
||||
if self.IP.rl_do_indent:
|
||||
indentation = self.IP.input_splitter.indent_spaces * ' '
|
||||
if self.no_input_splitter:
|
||||
indentation = self.indent_spaces
|
||||
else:
|
||||
indentation = self.IP.input_splitter.indent_spaces * ' '
|
||||
self.text_buffer.insert_at_cursor(indentation)
|
||||
|
||||
def onKeyPress(self, widget, event):
|
||||
@@ -508,9 +554,9 @@ class ConsoleView(Gtk.TextView):
|
||||
selection_iter = self.text_buffer.get_iter_at_mark(selection_mark)
|
||||
start_iter = self.text_buffer.get_iter_at_mark(self.line_start)
|
||||
if event.keyval == Gdk.KEY_Home:
|
||||
if event.get_state() & Gdk.ModifierType.CONTROL_MASK or event.get_state() & Gdk.ModifierType.MOD1_MASK:
|
||||
if event.state & Gdk.ModifierType.CONTROL_MASK or event.state & Gdk.ModifierType.MOD1_MASK:
|
||||
pass
|
||||
elif event.get_state() & Gdk.ModifierType.SHIFT_MASK:
|
||||
elif event.state & Gdk.ModifierType.SHIFT_MASK:
|
||||
self.text_buffer.move_mark(insert_mark, start_iter)
|
||||
return True
|
||||
else:
|
||||
@@ -520,6 +566,24 @@ class ConsoleView(Gtk.TextView):
|
||||
insert_iter.backward_cursor_position()
|
||||
if not insert_iter.editable(True):
|
||||
return True
|
||||
elif event.state & Gdk.ModifierType.CONTROL_MASK and event.keyval in [ord('L'), ord('l')]:
|
||||
# clear previous output on Ctrl+L, but remember current input line + cursor position
|
||||
cursor_offset = self.text_buffer.get_property('cursor-position')
|
||||
cursor_pos_in_line = cursor_offset - start_iter.get_offset() + len(self.prompt)
|
||||
current_input = self.text_buffer.get_text(start_iter, self.text_buffer.get_end_iter(), False)
|
||||
self.text_buffer.set_text(self.prompt + current_input)
|
||||
self.text_buffer.move_mark(self.line_start, self.text_buffer.get_iter_at_offset(len(self.prompt)))
|
||||
self.text_buffer.place_cursor(self.text_buffer.get_iter_at_offset(cursor_pos_in_line))
|
||||
return True
|
||||
elif event.state & Gdk.ModifierType.CONTROL_MASK and event.keyval in [Gdk.KEY_k, Gdk.KEY_K]:
|
||||
# clear text after input cursor on Ctrl+K
|
||||
if insert_iter.editable(True):
|
||||
self.text_buffer.delete(insert_iter, self.text_buffer.get_end_iter())
|
||||
return True
|
||||
elif event.state & Gdk.ModifierType.CONTROL_MASK and event.keyval == Gdk.KEY_C:
|
||||
# copy selection on Ctrl+C (upper-case 'C' only)
|
||||
self.text_buffer.copy_clipboard(Gtk.Clipboard.get(Gdk.SELECTION_CLIPBOARD))
|
||||
return True
|
||||
elif not event.string:
|
||||
pass
|
||||
elif start_iter.compare(insert_iter) <= 0 and \
|
||||
@@ -569,7 +633,7 @@ class IPythonView(ConsoleView, IterableIPShell):
|
||||
"""
|
||||
ConsoleView.__init__(self)
|
||||
self.cout = StringIO()
|
||||
IterableIPShell.__init__(self, cout=self.cout,cerr=self.cout,
|
||||
IterableIPShell.__init__(self, cout=self.cout, cerr=self.cout,
|
||||
input_func=self.raw_input)
|
||||
self.interrupt = False
|
||||
self.execute()
|
||||
|
||||
Reference in New Issue
Block a user