##// END OF EJS Templates
Fix extensions test suite (small, but now it runs and passes!)
Fix extensions test suite (small, but now it runs and passes!)

File last commit:

r2415:21955d0e
r2415:21955d0e
Show More
pretty.py
167 lines | 5.8 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.component import Component
from IPython.utils.traitlets import Bool, List
from IPython.utils.genutils import Term
from IPython.utils.autoattr import auto_attr
from IPython.utils.importstring import import_item
#-----------------------------------------------------------------------------
# Code
#-----------------------------------------------------------------------------
_loaded = False
class PrettyResultDisplay(Component):
"""A component for pretty printing on steroids."""
verbose = Bool(False, config=True)
# 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, parent, name=None, config=None):
super(PrettyResultDisplay, self).__init__(parent, name=name, 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)
# Access other components like this rather than by a regular attribute.
# This won't lookup the InteractiveShell object until it is used and
# then it is cached. This is both efficient and couples this class
# more loosely to InteractiveShell.
@auto_attr
def shell(self):
return Component.get_instances(
root=self.root,
klass='IPython.core.iplib.InteractiveShell')[0]
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.
Term.cout.write('\n')
print >>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=None):
"""Load the extension in IPython as a hook."""
if ip is None: ip = get_ipython()
global _loaded
if not _loaded:
prd = PrettyResultDisplay(ip, name='pretty_result_display')
ip.set_hook('result_display', prd, priority=99)
_loaded = True
return prd
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, '])')