##// END OF EJS Templates
catch IOError in addition to OSError...
catch IOError in addition to OSError IOError is a subclass of OSError on py3, but not py2

File last commit:

r19486:9018a28a
r20489:fb6299ba
Show More
magic_helper.py
213 lines | 7.4 KiB | text/x-python | PythonLexer
Dimitry Kloper
Added more documentation for MagicHelper.
r16491 """MagicHelper - dockable widget showing magic commands for the MainWindow
Dimitry Kloper
Move Maigic Helper into separate class/module/file
r16483 """
Dimitry Kloper
Updated file headers according to IPython Copyright Policy
r16519 # Copyright (c) IPython Development Team.
# Distributed under the terms of the Modified BSD License.
Dimitry Kloper
Move Maigic Helper into separate class/module/file
r16483 #-----------------------------------------------------------------------------
# Imports
#-----------------------------------------------------------------------------
# stdlib imports
import json
import re
import sys
# System library imports
from IPython.external.qt import QtGui,QtCore
from IPython.core.magic import magic_escapes
class MagicHelper(QtGui.QDockWidget):
Dimitry Kloper
Added more documentation for MagicHelper.
r16491 """MagicHelper - dockable widget for convenient search and running of
magic command for IPython QtConsole.
"""
#---------------------------------------------------------------------------
# signals
#---------------------------------------------------------------------------
Dimitry Kloper
Move Maigic Helper into separate class/module/file
r16483
Dimitry Kloper
Rename pyqtSignal to Signal....
r16532 pasteRequested = QtCore.Signal(str, name = 'pasteRequested')
Dimitry Kloper
Added more documentation for MagicHelper.
r16491 """This signal is emitted when user wants to paste selected magic
command into the command line.
"""
Dimitry Kloper
Rename pyqtSignal to Signal....
r16532 runRequested = QtCore.Signal(str, name = 'runRequested')
Dimitry Kloper
Added more documentation for MagicHelper.
r16491 """This signal is emitted when user wants to execute selected magic command
"""
Dimitry Kloper
Rename pyqtSignal to Signal....
r16532 readyForUpdate = QtCore.Signal(name = 'readyForUpdate')
Dimitry Kloper
Added more documentation for MagicHelper.
r16491 """This signal is emitted when MagicHelper is ready to be populated.
Since kernel querying mechanisms are out of scope of this class,
it expects its owner to invoke MagicHelper.populate_magic_helper()
as a reaction on this event.
"""
Dimitry Kloper
Move Maigic Helper into separate class/module/file
r16483
#---------------------------------------------------------------------------
Dimitry Kloper
Added more documentation for MagicHelper.
r16491 # constructor
Dimitry Kloper
Move Maigic Helper into separate class/module/file
r16483 #---------------------------------------------------------------------------
def __init__(self, name, parent):
super(MagicHelper, self).__init__(name, parent)
self.data = None
class MinListWidget(QtGui.QListWidget):
Dimitry Kloper
Added more documentation for MagicHelper.
r16491 """Temp class to overide the default QListWidget size hint
in order to make MagicHelper narrow
"""
Dimitry Kloper
Move Maigic Helper into separate class/module/file
r16483 def sizeHint(self):
s = QtCore.QSize()
s.setHeight(super(MinListWidget,self).sizeHint().height())
s.setWidth(self.sizeHintForColumn(0))
return s
Dimitry Kloper
Added more documentation for MagicHelper.
r16491 # construct content
Dimitry Kloper
Move Maigic Helper into separate class/module/file
r16483 self.frame = QtGui.QFrame()
self.search_label = QtGui.QLabel("Search:")
self.search_line = QtGui.QLineEdit()
self.search_class = QtGui.QComboBox()
self.search_list = MinListWidget()
self.paste_button = QtGui.QPushButton("Paste")
self.run_button = QtGui.QPushButton("Run")
Dimitry Kloper
Added more documentation for MagicHelper.
r16491 # layout all the widgets
Dimitry Kloper
Move Maigic Helper into separate class/module/file
r16483 main_layout = QtGui.QVBoxLayout()
search_layout = QtGui.QHBoxLayout()
search_layout.addWidget(self.search_label)
search_layout.addWidget(self.search_line, 10)
main_layout.addLayout(search_layout)
main_layout.addWidget(self.search_class)
main_layout.addWidget(self.search_list, 10)
action_layout = QtGui.QHBoxLayout()
action_layout.addWidget(self.paste_button)
action_layout.addWidget(self.run_button)
main_layout.addLayout(action_layout)
self.frame.setLayout(main_layout)
self.setWidget(self.frame)
Dimitry Kloper
Added more documentation for MagicHelper.
r16491 # connect all the relevant signals to handlers
self.visibilityChanged[bool].connect( self._update_magic_helper )
Dimitry Kloper
Move Maigic Helper into separate class/module/file
r16483 self.search_class.activated[int].connect(
self.class_selected
)
self.search_line.textChanged[str].connect(
self.search_changed
)
Carlos Cordoba
qtconsole: Remove wrong overloaded signal call...
r19486 self.search_list.itemDoubleClicked.connect(
Dimitry Kloper
Move Maigic Helper into separate class/module/file
r16483 self.paste_requested
)
self.paste_button.clicked[bool].connect(
self.paste_requested
)
self.run_button.clicked[bool].connect(
self.run_requested
)
Dimitry Kloper
Added more documentation for MagicHelper.
r16491 #---------------------------------------------------------------------------
# implementation
#---------------------------------------------------------------------------
def _update_magic_helper(self, visible):
"""Start update sequence.
This method is called when MagicHelper becomes visible. It clears
the content and emits readyForUpdate signal. The owner of the
instance is expected to invoke populate_magic_helper() when magic
info is available.
"""
Boris Egorov
Use 'is' to compare with None...
r18172 if not visible or self.data is not None:
Dimitry Kloper
Move Maigic Helper into separate class/module/file
r16483 return
self.data = {}
self.search_class.clear()
self.search_class.addItem("Populating...")
Dimitry Kloper
Added more documentation for MagicHelper.
r16491 self.search_list.clear()
Dimitry Kloper
Eliminate main window logic from MagicHelper....
r16484 self.readyForUpdate.emit()
Dimitry Kloper
Move Maigic Helper into separate class/module/file
r16483
def populate_magic_helper(self, data):
Dimitry Kloper
Added more documentation for MagicHelper.
r16491 """Expects data returned by lsmagics query from kernel.
Populates the search_class and search_list with relevant items.
"""
Dimitry Kloper
Move Maigic Helper into separate class/module/file
r16483 self.search_class.clear()
self.search_list.clear()
self.data = json.loads(
data['data'].get('application/json', {})
)
self.search_class.addItem('All Magics', 'any')
classes = set()
for mtype in sorted(self.data):
subdict = self.data[mtype]
for name in sorted(subdict):
classes.add(subdict[name])
for cls in sorted(classes):
label = re.sub("([a-zA-Z]+)([A-Z][a-z])","\g<1> \g<2>", cls)
self.search_class.addItem(label, cls)
self.filter_magic_helper('.', 'any')
def class_selected(self, index):
Dimitry Kloper
Added more documentation for MagicHelper.
r16491 """Handle search_class selection changes
"""
Dimitry Kloper
Move Maigic Helper into separate class/module/file
r16483 item = self.search_class.itemData(index)
regex = self.search_line.text()
self.filter_magic_helper(regex = regex, cls = item)
def search_changed(self, search_string):
Dimitry Kloper
Added more documentation for MagicHelper.
r16491 """Handle search_line text changes.
The text is interpreted as a regular expression
"""
Dimitry Kloper
Move Maigic Helper into separate class/module/file
r16483 item = self.search_class.itemData(
self.search_class.currentIndex()
)
self.filter_magic_helper(regex = search_string, cls = item)
def _get_current_search_item(self, item = None):
Dimitry Kloper
Added more documentation for MagicHelper.
r16491 """Retrieve magic command currently selected in the search_list
"""
Dimitry Kloper
Move Maigic Helper into separate class/module/file
r16483 text = None
if not isinstance(item, QtGui.QListWidgetItem):
item = self.search_list.currentItem()
text = item.text()
return text
def paste_requested(self, item = None):
Dimitry Kloper
Added more documentation for MagicHelper.
r16491 """Emit pasteRequested signal with currently selected item text
"""
Dimitry Kloper
Move Maigic Helper into separate class/module/file
r16483 text = self._get_current_search_item(item)
Boris Egorov
Use 'is' to compare with None...
r18172 if text is not None:
Dimitry Kloper
Move Maigic Helper into separate class/module/file
r16483 self.pasteRequested.emit(text)
def run_requested(self, item = None):
Dimitry Kloper
Added more documentation for MagicHelper.
r16491 """Emit runRequested signal with currently selected item text
"""
Dimitry Kloper
Move Maigic Helper into separate class/module/file
r16483 text = self._get_current_search_item(item)
Boris Egorov
Use 'is' to compare with None...
r18172 if text is not None:
Dimitry Kloper
Move Maigic Helper into separate class/module/file
r16483 self.runRequested.emit(text)
def filter_magic_helper(self, regex, cls):
Dimitry Kloper
Added more documentation for MagicHelper.
r16491 """Update search_list with magic commands whose text match
regex and class match cls.
If cls equals 'any' - any class matches.
"""
Boris Egorov
Use 'is' to compare with None...
r18172 if regex == "" or regex is None:
Dimitry Kloper
Move Maigic Helper into separate class/module/file
r16483 regex = '.'
Boris Egorov
Use 'is' to compare with None...
r18172 if cls is None:
Dimitry Kloper
Move Maigic Helper into separate class/module/file
r16483 cls = 'any'
self.search_list.clear()
for mtype in sorted(self.data):
subdict = self.data[mtype]
prefix = magic_escapes[mtype]
for name in sorted(subdict):
mclass = subdict[name]
pmagic = prefix + name
if (re.match(regex, name) or re.match(regex, pmagic)) and \
(cls == 'any' or cls == mclass):
self.search_list.addItem(pmagic)