pretty.py
157 lines
| 5.4 KiB
| text/x-python
|
PythonLexer
|
r2281 | """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'] | ||||
|
r2282 | def dict_pprinter(obj, p, cycle): | ||
return p.text("<dict>") | ||||
|
r2281 | c.PrettyResultDisplay.verbose = True | ||
|
r2282 | c.PrettyResultDisplay.defaults_for_type = [ | ||
(dict, dict_pprinter) | ||||
] | ||||
c.PrettyResultDisplay.defaults_for_type_by_name = [ | ||||
|
r2281 | ('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 | ||||
|
r2738 | from IPython.core.plugin import Plugin | ||
|
r2732 | from IPython.utils.traitlets import Bool, List, Instance | ||
|
r2775 | import IPython.utils.io | ||
|
r2281 | from IPython.utils.autoattr import auto_attr | ||
from IPython.utils.importstring import import_item | ||||
#----------------------------------------------------------------------------- | ||||
# Code | ||||
#----------------------------------------------------------------------------- | ||||
|
r2282 | |||
|
r2281 | _loaded = False | ||
|
r2738 | class PrettyResultDisplay(Plugin): | ||
|
r2282 | """A component for pretty printing on steroids.""" | ||
|
r2281 | |||
verbose = Bool(False, config=True) | ||||
|
r2760 | shell = Instance('IPython.core.interactiveshell.InteractiveShellABC') | ||
|
r2282 | |||
# 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) | ||||
|
r2281 | # A list of (module_name, type_name, func_name), like | ||
# [('numpy', 'dtype', 'IPython.extensions.pretty.dtype_pprinter')] | ||||
|
r2282 | # The final argument can also be a callable | ||
defaults_for_type_by_name = List(default_value=[], config=True) | ||||
|
r2281 | |||
|
r2740 | def __init__(self, shell=None, config=None): | ||
super(PrettyResultDisplay, self).__init__(shell=shell, config=config) | ||||
|
r2282 | self._setup_defaults() | ||
|
r2281 | |||
|
r2282 | def _setup_defaults(self): | ||
|
r2281 | """Initialize the default pretty printers.""" | ||
|
r2282 | 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) | ||||
|
r2281 | self.for_type_by_name(type_module, type_name, func) | ||
|
r2282 | 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) | ||||
|
r2281 | 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. | ||||
|
r2775 | IPython.utils.io.Term.cout.write('\n') | ||
print >>IPython.utils.io.Term.cout, out | ||||
|
r2281 | 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.""" | ||||
|
r2282 | return pretty.for_type_by_name(type_module, type_name, func) | ||
|
r2281 | |||
#----------------------------------------------------------------------------- | ||||
# Initialization code for the extension | ||||
#----------------------------------------------------------------------------- | ||||
|
r2499 | def load_ipython_extension(ip): | ||
|
r2282 | """Load the extension in IPython as a hook.""" | ||
|
r2281 | global _loaded | ||
if not _loaded: | ||||
|
r2740 | plugin = PrettyResultDisplay(shell=ip, config=ip.config) | ||
|
r2738 | ip.set_hook('result_display', plugin, priority=99) | ||
|
r2281 | _loaded = True | ||
|
r2738 | ip.plugin_manager.register_plugin('pretty_result_display', plugin) | ||
|
r2281 | |||
def unload_ipython_extension(ip): | ||||
|
r2282 | """Unload the extension.""" | ||
|
r2281 | # 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(...)') | ||||
|
r2282 | 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, '])') | ||||