##// END OF EJS Templates
Multiple improvements to tab completion....
Multiple improvements to tab completion. I refactored the API quite a bit, to retain readline compatibility but make it more independent of readline. There's still more to do in cleaning up our init_readline() method, but now the completer objects have separate rlcomplete() and complete() methods. The former uses the quirky readline API with a state flag, while the latter is stateless, takes only text information, and is more suitable for GUIs and other frontends to call programatically. Made other minor fixes to ensure the test suite passes in full. While all this code is a bit messy, we're getting in the direction of the APIs we need in the long run.

File last commit:

r2775:c291d5fa
r2839:8cff4913
Show More
pretty.py
157 lines | 5.4 KiB | text/x-python | PythonLexer
"""Use pretty.py for configurable pretty-printing.
To enable this extension in your configuration
file, add the following to :file:`ipython_config.py`::
c.Global.extensions = ['IPython.extensions.pretty']
def dict_pprinter(obj, p, cycle):
return p.text("<dict>")
c.PrettyResultDisplay.verbose = True
c.PrettyResultDisplay.defaults_for_type = [
(dict, dict_pprinter)
]
c.PrettyResultDisplay.defaults_for_type_by_name = [
('numpy', 'dtype', 'IPython.extensions.pretty.dtype_pprinter')
]
This extension can also be loaded by using the ``%load_ext`` magic::
%load_ext IPython.extensions.pretty
If this extension is enabled, you can always add additional pretty printers
by doing::
ip = get_ipython()
prd = ip.get_component('pretty_result_display')
import numpy
from IPython.extensions.pretty import dtype_pprinter
prd.for_type(numpy.dtype, dtype_pprinter)
# If you don't want to have numpy imported until it needs to be:
prd.for_type_by_name('numpy', 'dtype', dtype_pprinter)
"""
#-----------------------------------------------------------------------------
# Imports
#-----------------------------------------------------------------------------
from IPython.core.error import TryNext
from IPython.external import pretty
from IPython.core.plugin import Plugin
from IPython.utils.traitlets import Bool, List, Instance
import IPython.utils.io
from IPython.utils.autoattr import auto_attr
from IPython.utils.importstring import import_item
#-----------------------------------------------------------------------------
# Code
#-----------------------------------------------------------------------------
_loaded = False
class PrettyResultDisplay(Plugin):
"""A component for pretty printing on steroids."""
verbose = Bool(False, config=True)
shell = Instance('IPython.core.interactiveshell.InteractiveShellABC')
# A list of (type, func_name), like
# [(dict, 'my_dict_printer')]
# The final argument can also be a callable
defaults_for_type = List(default_value=[], config=True)
# A list of (module_name, type_name, func_name), like
# [('numpy', 'dtype', 'IPython.extensions.pretty.dtype_pprinter')]
# The final argument can also be a callable
defaults_for_type_by_name = List(default_value=[], config=True)
def __init__(self, shell=None, config=None):
super(PrettyResultDisplay, self).__init__(shell=shell, config=config)
self._setup_defaults()
def _setup_defaults(self):
"""Initialize the default pretty printers."""
for typ, func_name in self.defaults_for_type:
func = self._resolve_func_name(func_name)
self.for_type(typ, func)
for type_module, type_name, func_name in self.defaults_for_type_by_name:
func = self._resolve_func_name(func_name)
self.for_type_by_name(type_module, type_name, func)
def _resolve_func_name(self, func_name):
if callable(func_name):
return func_name
elif isinstance(func_name, basestring):
return import_item(func_name)
else:
raise TypeError('func_name must be a str or callable, got: %r' % func_name)
def __call__(self, otherself, arg):
"""Uber-pretty-printing display hook.
Called for displaying the result to the user.
"""
if self.shell.pprint:
out = pretty.pretty(arg, verbose=self.verbose)
if '\n' in out:
# So that multi-line strings line up with the left column of
# the screen, instead of having the output prompt mess up
# their first line.
IPython.utils.io.Term.cout.write('\n')
print >>IPython.utils.io.Term.cout, out
else:
raise TryNext
def for_type(self, typ, func):
"""Add a pretty printer for a type."""
return pretty.for_type(typ, func)
def for_type_by_name(self, type_module, type_name, func):
"""Add a pretty printer for a type by its name and module name."""
return pretty.for_type_by_name(type_module, type_name, func)
#-----------------------------------------------------------------------------
# Initialization code for the extension
#-----------------------------------------------------------------------------
def load_ipython_extension(ip):
"""Load the extension in IPython as a hook."""
global _loaded
if not _loaded:
plugin = PrettyResultDisplay(shell=ip, config=ip.config)
ip.set_hook('result_display', plugin, priority=99)
_loaded = True
ip.plugin_manager.register_plugin('pretty_result_display', plugin)
def unload_ipython_extension(ip):
"""Unload the extension."""
# The hook system does not have a way to remove a hook so this is a pass
pass
#-----------------------------------------------------------------------------
# Example pretty printers
#-----------------------------------------------------------------------------
def dtype_pprinter(obj, p, cycle):
""" A pretty-printer for numpy dtype objects.
"""
if cycle:
return p.text('dtype(...)')
if hasattr(obj, 'fields'):
if obj.fields is None:
p.text(repr(obj))
else:
p.begin_group(7, 'dtype([')
for i, field in enumerate(obj.descr):
if i > 0:
p.text(',')
p.breakable()
p.pretty(field)
p.end_group(7, '])')