diff --git a/IPython/core/magic.py b/IPython/core/magic.py index 40a3d92..65d3e57 100644 --- a/IPython/core/magic.py +++ b/IPython/core/magic.py @@ -327,22 +327,6 @@ class MagicsManager(Configurable): """Return descriptive string with automagic status.""" return self._auto_status[self.auto_magic] - def lsmagic_info(self): - """Return the magics as a list of dicts""" - magic_list = [] - for m_type in self.magics: - for m_name,mgc in self.magics[m_type].items(): - try: - magic_list.append({'name':m_name,'type':m_type,'class':mgc.im_class.__name__}) - except AttributeError: - magic_list.append({'name':m_name,'type':m_type,'class':'Other'}) - return magic_list - - def lsmagic_json(self): - """Wrap lsmagic_info() in a JSON object""" - from IPython.display import JSON - return JSON(json.dumps(self.lsmagic_info())) - def lsmagic(self): """Return a dict of currently available magic functions. diff --git a/IPython/core/magics/basic.py b/IPython/core/magics/basic.py index 59ec9fe..d803ea7 100644 --- a/IPython/core/magics/basic.py +++ b/IPython/core/magics/basic.py @@ -15,6 +15,7 @@ from __future__ import print_function # Stdlib import io +import json import sys from pprint import pformat @@ -33,6 +34,55 @@ from IPython.utils.warn import warn, error # Magics class implementation #----------------------------------------------------------------------------- +class MagicsDisplay(object): + def __init__(self, magics_manager): + self.magics_manager = magics_manager + + def _lsmagic(self): + """The main implementation of the %lsmagic""" + mesc = magic_escapes['line'] + cesc = magic_escapes['cell'] + mman = self.magics_manager + magics = mman.lsmagic() + out = ['Available line magics:', + mesc + (' '+mesc).join(sorted(magics['line'])), + '', + 'Available cell magics:', + cesc + (' '+cesc).join(sorted(magics['cell'])), + '', + mman.auto_status()] + return '\n'.join(out) + + def _repr_pretty_(self, p, cycle): + p.text(self._lsmagic()) + + def __str__(self): + return self._lsmagic() + + def _jsonable(self): + """turn magics dict into jsonable dict of the same structure + + replaces object instances with their class names as strings + """ + magic_dict = {} + mman = self.magics_manager + magics = mman.lsmagic() + for key, subdict in magics.items(): + d = {} + magic_dict[key] = d + for name, obj in subdict.items(): + try: + classname = obj.im_class.__name__ + except AttributeError: + classname = 'Other' + + d[name] = classname + return magic_dict + + def _repr_json_(self): + return json.dumps(self._jsonable()) + + @magics_class class BasicMagics(Magics): """Magics that provide central IPython functionality. @@ -124,24 +174,10 @@ class BasicMagics(Magics): magic_escapes['cell'], name, magic_escapes['cell'], target)) - def _lsmagic(self): - mesc = magic_escapes['line'] - cesc = magic_escapes['cell'] - mman = self.shell.magics_manager - magics = mman.lsmagic() - out = ['Available line magics:', - mesc + (' '+mesc).join(sorted(magics['line'])), - '', - 'Available cell magics:', - cesc + (' '+cesc).join(sorted(magics['cell'])), - '', - mman.auto_status()] - return '\n'.join(out) - @line_magic def lsmagic(self, parameter_s=''): """List currently available magic functions.""" - print(self._lsmagic()) + return MagicsDisplay(self.shell.magics_manager) def _magic_docs(self, brief=False, rest=False): """Return docstrings from magic functions.""" diff --git a/IPython/frontend/qt/console/mainwindow.py b/IPython/frontend/qt/console/mainwindow.py index 63070a5..553408e 100644 --- a/IPython/frontend/qt/console/mainwindow.py +++ b/IPython/frontend/qt/console/mainwindow.py @@ -29,6 +29,8 @@ from threading import Thread # System library imports from IPython.external.qt import QtGui,QtCore +from IPython.core.magic import magic_escapes + def background(f): """call a function in a simple thread, to prevent blocking""" t = Thread(target=f) @@ -621,8 +623,8 @@ class MainWindow(QtGui.QMainWindow): Parameters ---------- display_data : dict, - dict of display_data for the magics list. - Expects json data, as the result of MagicsManager.lsmagic_json() + dict of display_data for the magics dict of a MagicsManager. + Expects json data, as the result of %lsmagic """ for k,v in self._magic_menu_dict.items(): @@ -631,27 +633,26 @@ class MainWindow(QtGui.QMainWindow): if not display_data: return - - mlist = json.loads(display_data['data'].get('application/json', [])) - - for magic in mlist: - cell = (magic['type'] == 'cell') - name = magic['name'] - mclass = magic['class'] - if cell : - prefix='%%' - else : - prefix='%' - magic_menu = self._get_magic_menu(mclass) - - pmagic = '%s%s'%(prefix,name) - - xaction = QtGui.QAction(pmagic, - self, - triggered=self._make_dynamic_magic(pmagic) - ) - magic_menu.addAction(xaction) - self.all_magic_menu.addAction(xaction) + + if display_data['status'] != 'ok': + self.log.warn("%%lsmagic user-expression failed: %s" % display_data) + return + + mdict = json.loads(display_data['data'].get('application/json', {})) + + for mtype in sorted(mdict): + subdict = mdict[mtype] + prefix = magic_escapes[mtype] + for name in sorted(subdict): + mclass = subdict[name] + magic_menu = self._get_magic_menu(mclass) + pmagic = prefix + name + xaction = QtGui.QAction(pmagic, + self, + triggered=self._make_dynamic_magic(pmagic) + ) + magic_menu.addAction(xaction) + self.all_magic_menu.addAction(xaction) def update_all_magic_menu(self): """ Update the list of magics in the "All Magics..." Menu @@ -660,7 +661,7 @@ class MainWindow(QtGui.QMainWindow): menu with the list received back """ - self.active_frontend._silent_exec_callback('get_ipython().magics_manager.lsmagic_json()', + self.active_frontend._silent_exec_callback('get_ipython().magic("lsmagic")', self.populate_all_magic_menu) def _get_magic_menu(self,menuidentifier, menulabel=None):