formatters.py
1024 lines
| 34.1 KiB
| text/x-python
|
PythonLexer
Robert Kern
|
r3209 | # -*- coding: utf-8 -*- | ||
Brian Granger
|
r3278 | """Display formatters. | ||
Thomas Kluyver
|
r8795 | Inheritance diagram: | ||
.. inheritance-diagram:: IPython.core.formatters | ||||
:parts: 3 | ||||
Robert Kern
|
r3209 | """ | ||
MinRK
|
r18025 | # Copyright (c) IPython Development Team. | ||
# Distributed under the terms of the Modified BSD License. | ||||
Brian Granger
|
r3279 | |||
Robert Kern
|
r3209 | import abc | ||
Min RK
|
r19557 | import json | ||
MinRK
|
r3352 | import sys | ||
Thomas Kluyver
|
r19105 | import traceback | ||
MinRK
|
r9813 | import warnings | ||
Srinivas Reddy Thatiparthy
|
r23119 | from io import StringIO | ||
Robert Kern
|
r3209 | |||
MinRK
|
r20813 | from decorator import decorator | ||
MinRK
|
r13977 | |||
Min RK
|
r21253 | from traitlets.config.configurable import Configurable | ||
MinRK
|
r18025 | from IPython.core.getipython import get_ipython | ||
Min RK
|
r21078 | from IPython.utils.sentinel import Sentinel | ||
Thomas Kluyver
|
r22148 | from IPython.utils.dir2 import get_real_method | ||
Thomas Spura
|
r3413 | from IPython.lib import pretty | ||
Min RK
|
r21253 | from traitlets import ( | ||
MinRK
|
r9811 | Bool, Dict, Integer, Unicode, CUnicode, ObjectName, List, | ||
Min RK
|
r19382 | ForwardDeclaredInstance, | ||
Min RK
|
r22340 | default, observe, | ||
MinRK
|
r9811 | ) | ||
Thomas Kluyver
|
r13366 | |||
Robert Kern
|
r3209 | |||
Brian Granger
|
r3278 | class DisplayFormatter(Configurable): | ||
Min RK
|
r22340 | active_types = List(Unicode(), | ||
MinRK
|
r10182 | help="""List of currently active mime-types to display. | ||
You can use this to set a white-list for formats to display. | ||||
Most users will not need to change this value. | ||||
Min RK
|
r22340 | """).tag(config=True) | ||
@default('active_types') | ||||
MinRK
|
r9811 | def _active_types_default(self): | ||
return self.format_types | ||||
Min RK
|
r22340 | |||
@observe('active_types') | ||||
def _active_types_changed(self, change): | ||||
MinRK
|
r10130 | for key, formatter in self.formatters.items(): | ||
Min RK
|
r22340 | if key in change['new']: | ||
MinRK
|
r10128 | formatter.enabled = True | ||
else: | ||||
formatter.enabled = False | ||||
Min RK
|
r23578 | |||
Min RK
|
r19382 | ipython_display_formatter = ForwardDeclaredInstance('FormatterABC') | ||
Min RK
|
r22340 | @default('ipython_display_formatter') | ||
def _default_formatter(self): | ||||
Min RK
|
r19382 | return IPythonDisplayFormatter(parent=self) | ||
Min RK
|
r23578 | |||
mimebundle_formatter = ForwardDeclaredInstance('FormatterABC') | ||||
@default('mimebundle_formatter') | ||||
def _default_mime_formatter(self): | ||||
return MimeBundleFormatter(parent=self) | ||||
Brian Granger
|
r3278 | # A dict of formatter whose keys are format types (MIME types) and whose | ||
# values are subclasses of BaseFormatter. | ||||
MinRK
|
r5228 | formatters = Dict() | ||
Min RK
|
r22340 | @default('formatters') | ||
Brian Granger
|
r3278 | def _formatters_default(self): | ||
"""Activate the default formatters.""" | ||||
formatter_classes = [ | ||||
PlainTextFormatter, | ||||
HTMLFormatter, | ||||
Andrew Jesaitis
|
r16364 | MarkdownFormatter, | ||
Brian Granger
|
r3278 | SVGFormatter, | ||
PNGFormatter, | ||||
Brian E. Granger
|
r15121 | PDFFormatter, | ||
Brian E. Granger
|
r4528 | JPEGFormatter, | ||
Brian Granger
|
r3278 | LatexFormatter, | ||
Brian Granger
|
r3878 | JSONFormatter, | ||
JavascriptFormatter | ||||
Brian Granger
|
r3278 | ] | ||
d = {} | ||||
for cls in formatter_classes: | ||||
MinRK
|
r11064 | f = cls(parent=self) | ||
Brian Granger
|
r3278 | d[f.format_type] = f | ||
return d | ||||
def format(self, obj, include=None, exclude=None): | ||||
"""Return a format data dict for an object. | ||||
By default all format types will be computed. | ||||
Matthias Bussonnier
|
r23612 | The following MIME types are usually implemented: | ||
Brian Granger
|
r3278 | |||
* text/plain | ||||
* text/html | ||||
Andrew Jesaitis
|
r16364 | * text/markdown | ||
Brian Granger
|
r3278 | * text/latex | ||
* application/json | ||||
Brian E. Granger
|
r4526 | * application/javascript | ||
Brian E. Granger
|
r15121 | * application/pdf | ||
Brian Granger
|
r3278 | * image/png | ||
Brian E. Granger
|
r4528 | * image/jpeg | ||
Brian E. Granger
|
r4526 | * image/svg+xml | ||
Brian Granger
|
r3278 | |||
Parameters | ||||
---------- | ||||
obj : object | ||||
The Python object whose format data will be computed. | ||||
Matthias Bussonnier
|
r23612 | include : list, tuple or set; optional | ||
Brian Granger
|
r3282 | A list of format type strings (MIME types) to include in the | ||
format data dict. If this is set *only* the format types included | ||||
in this list will be computed. | ||||
Matthias Bussonnier
|
r23612 | exclude : list, tuple or set; optional | ||
MinRK
|
r9811 | A list of format type string (MIME types) to exclude in the format | ||
Brian Granger
|
r3282 | data dict. If this is set all format types will be computed, | ||
except for those included in this argument. | ||||
Matthias Bussonnier
|
r23612 | Mimetypes present in exclude will take precedence over the ones in include | ||
Brian Granger
|
r3278 | |||
Returns | ||||
------- | ||||
MinRK
|
r10446 | (format_dict, metadata_dict) : tuple of two dicts | ||
format_dict is a dictionary of key/value pairs, one of each format that was | ||||
Brian Granger
|
r3278 | generated for the object. The keys are the format types, which | ||
will usually be MIME type strings and the values and JSON'able | ||||
data structure containing the raw data for the representation in | ||||
that format. | ||||
MinRK
|
r10446 | |||
metadata_dict is a dictionary of metadata about each mime-type output. | ||||
Its keys will be a strict subset of the keys in format_dict. | ||||
Matthias Bussonnier
|
r23612 | |||
Notes | ||||
----- | ||||
If an object implement `_repr_mimebundle_` as well as various | ||||
`_repr_*_`, the data returned by `_repr_mimebundle_` will take | ||||
precedence and the corresponding `_repr_*_` for this mimetype will | ||||
not be called. | ||||
Brian Granger
|
r3278 | """ | ||
format_dict = {} | ||||
MinRK
|
r10443 | md_dict = {} | ||
Min RK
|
r19381 | |||
Min RK
|
r19382 | if self.ipython_display_formatter(obj): | ||
Min RK
|
r19381 | # object handled itself, don't proceed | ||
return {}, {} | ||||
Min RK
|
r23578 | |||
Matthias Bussonnier
|
r23618 | format_dict, md_dict = self.mimebundle_formatter(obj, include=include, exclude=exclude) | ||
Min RK
|
r23578 | |||
Matthias Bussonnier
|
r23612 | if format_dict or md_dict: | ||
if include: | ||||
format_dict = {k:v for k,v in format_dict.items() if k in include} | ||||
md_dict = {k:v for k,v in md_dict.items() if k in include} | ||||
if exclude: | ||||
format_dict = {k:v for k,v in format_dict.items() if k not in exclude} | ||||
md_dict = {k:v for k,v in md_dict.items() if k not in exclude} | ||||
Brian Granger
|
r3278 | for format_type, formatter in self.formatters.items(): | ||
Min RK
|
r23578 | if format_type in format_dict: | ||
Min RK
|
r23839 | # already got it from mimebundle, maybe don't render again. | ||
# exception: manually registered per-mime renderer | ||||
# check priority: | ||||
# 1. user-registered per-mime formatter | ||||
# 2. mime-bundle (user-registered or repr method) | ||||
# 3. default per-mime formatter (e.g. repr method) | ||||
try: | ||||
formatter.lookup(obj) | ||||
except KeyError: | ||||
# no special formatter, use mime-bundle-provided value | ||||
continue | ||||
MinRK
|
r10129 | if include and format_type not in include: | ||
continue | ||||
if exclude and format_type in exclude: | ||||
MinRK
|
r9811 | continue | ||
MinRK
|
r10443 | |||
md = None | ||||
Brian Granger
|
r3278 | try: | ||
data = formatter(obj) | ||||
except: | ||||
# FIXME: log the exception | ||||
raise | ||||
MinRK
|
r10443 | |||
# formatters can return raw data or (data, metadata) | ||||
if isinstance(data, tuple) and len(data) == 2: | ||||
data, md = data | ||||
Brian Granger
|
r3278 | if data is not None: | ||
format_dict[format_type] = data | ||||
MinRK
|
r10443 | if md is not None: | ||
md_dict[format_type] = md | ||||
return format_dict, md_dict | ||||
Brian Granger
|
r3278 | |||
@property | ||||
def format_types(self): | ||||
"""Return the format types (MIME types) of the active formatters.""" | ||||
Thomas Kluyver
|
r13364 | return list(self.formatters.keys()) | ||
Brian Granger
|
r3278 | |||
#----------------------------------------------------------------------------- | ||||
# Formatters for specific format types (text, html, svg, etc.) | ||||
#----------------------------------------------------------------------------- | ||||
MinRK
|
r18025 | |||
def _safe_repr(obj): | ||||
"""Try to return a repr of an object | ||||
always returns a string, at least. | ||||
""" | ||||
try: | ||||
return repr(obj) | ||||
except Exception as e: | ||||
return "un-repr-able object (%r)" % e | ||||
MinRK
|
r14637 | class FormatterWarning(UserWarning): | ||
"""Warning class for errors in formatters""" | ||||
MinRK
|
r13977 | @decorator | ||
Min RK
|
r19929 | def catch_format_error(method, self, *args, **kwargs): | ||
"""show traceback on failed format call""" | ||||
MinRK
|
r13977 | try: | ||
MinRK
|
r14152 | r = method(self, *args, **kwargs) | ||
Thomas Kluyver
|
r19105 | except NotImplementedError: | ||
MinRK
|
r14635 | # don't warn on NotImplementedErrors | ||
return None | ||||
MinRK
|
r18025 | except Exception: | ||
exc_info = sys.exc_info() | ||||
ip = get_ipython() | ||||
if ip is not None: | ||||
ip.showtraceback(exc_info) | ||||
else: | ||||
traceback.print_exception(*exc_info) | ||||
MinRK
|
r13977 | return None | ||
Min RK
|
r19557 | return self._check_return(r, args[0]) | ||
MinRK
|
r13977 | |||
Thomas Kluyver
|
r23071 | class FormatterABC(metaclass=abc.ABCMeta): | ||
Brian Granger
|
r3278 | """ Abstract base class for Formatters. | ||
A formatter is a callable class that is responsible for computing the | ||||
raw format data for a particular format type (MIME type). For example, | ||||
an HTML formatter would have a format type of `text/html` and would return | ||||
the HTML representation of the object when called. | ||||
Robert Kern
|
r3209 | """ | ||
Brian Granger
|
r3278 | # The format type of the data returned, usually a MIME type. | ||
format_type = 'text/plain' | ||||
Robert Kern
|
r3209 | |||
Brian Granger
|
r3280 | # Is the formatter enabled... | ||
enabled = True | ||||
MinRK
|
r13977 | |||
Brian Granger
|
r3278 | @abc.abstractmethod | ||
def __call__(self, obj): | ||||
"""Return a JSON'able representation of the object. | ||||
MinRK
|
r13977 | If the object cannot be formatted by this formatter, | ||
warn and return None. | ||||
Brian Granger
|
r3278 | """ | ||
MinRK
|
r13977 | return repr(obj) | ||
Brian Granger
|
r3278 | |||
MinRK
|
r13781 | def _mod_name_key(typ): | ||
MinRK
|
r13788 | """Return a (__module__, __name__) tuple for a type. | ||
Used as key in Formatter.deferred_printers. | ||||
""" | ||||
MinRK
|
r13781 | module = getattr(typ, '__module__', None) | ||
name = getattr(typ, '__name__', None) | ||||
return (module, name) | ||||
def _get_type(obj): | ||||
"""Return the type of an instance (old and new-style)""" | ||||
return getattr(obj, '__class__', None) or type(obj) | ||||
Matthias Bussonnier
|
r21045 | |||
_raise_key_error = Sentinel('_raise_key_error', __name__, | ||||
""" | ||||
Special value to raise a KeyError | ||||
Raise KeyError in `BaseFormatter.pop` if passed as the default value to `pop` | ||||
""") | ||||
MinRK
|
r13781 | |||
MinRK
|
r13977 | |||
Brian Granger
|
r3278 | class BaseFormatter(Configurable): | ||
"""A base formatter class that is configurable. | ||||
This formatter should usually be used as the base class of all formatters. | ||||
It is a traited :class:`Configurable` class and includes an extensible | ||||
API for users to determine how their objects are formatted. The following | ||||
logic is used to find a function to format an given object. | ||||
1. The object is introspected to see if it has a method with the name | ||||
:attr:`print_method`. If is does, that object is passed to that method | ||||
for formatting. | ||||
2. If no print method is found, three internal dictionaries are consulted | ||||
to find print method: :attr:`singleton_printers`, :attr:`type_printers` | ||||
and :attr:`deferred_printers`. | ||||
Brian Granger
|
r3288 | Users should use these dictionaries to register functions that will be | ||
used to compute the format data for their objects (if those objects don't | ||||
have the special print methods). The easiest way of using these | ||||
dictionaries is through the :meth:`for_type` and :meth:`for_type_by_name` | ||||
methods. | ||||
Brian Granger
|
r3278 | |||
If no function/callable is found to compute the format data, ``None`` is | ||||
returned and this format type is not used. | ||||
""" | ||||
Thomas Kluyver
|
r4046 | format_type = Unicode('text/plain') | ||
Srinivas Reddy Thatiparthy
|
r23037 | _return_type = str | ||
Brian Granger
|
r3278 | |||
Matthias Bussonnier
|
r22331 | enabled = Bool(True).tag(config=True) | ||
Brian Granger
|
r3280 | |||
Thomas Kluyver
|
r4047 | print_method = ObjectName('__repr__') | ||
Brian Granger
|
r3278 | |||
# The singleton printers. | ||||
# Maps the IDs of the builtin singleton objects to the format functions. | ||||
Matthias Bussonnier
|
r22331 | singleton_printers = Dict().tag(config=True) | ||
Brian Granger
|
r3278 | |||
# The type-specific printers. | ||||
# Map type objects to the format functions. | ||||
Matthias Bussonnier
|
r22331 | type_printers = Dict().tag(config=True) | ||
Brian Granger
|
r3278 | |||
# The deferred-import type-specific printers. | ||||
# Map (modulename, classname) pairs to the format functions. | ||||
Matthias Bussonnier
|
r22331 | deferred_printers = Dict().tag(config=True) | ||
MinRK
|
r14152 | |||
Min RK
|
r19929 | @catch_format_error | ||
Brian Granger
|
r3278 | def __call__(self, obj): | ||
"""Compute the format for an object.""" | ||||
Brian Granger
|
r3280 | if self.enabled: | ||
MinRK
|
r13977 | # lookup registered printer | ||
Brian Granger
|
r3278 | try: | ||
MinRK
|
r13977 | printer = self.lookup(obj) | ||
except KeyError: | ||||
Brian Granger
|
r3280 | pass | ||
MinRK
|
r13977 | else: | ||
return printer(obj) | ||||
# Finally look for special method names | ||||
Thomas Kluyver
|
r22148 | method = get_real_method(obj, self.print_method) | ||
MinRK
|
r15486 | if method is not None: | ||
MinRK
|
r13977 | return method() | ||
return None | ||||
Brian Granger
|
r3280 | else: | ||
Brian Granger
|
r3278 | return None | ||
MinRK
|
r13781 | |||
MinRK
|
r13788 | def __contains__(self, typ): | ||
"""map in to lookup_by_type""" | ||||
try: | ||||
self.lookup_by_type(typ) | ||||
except KeyError: | ||||
return False | ||||
else: | ||||
return True | ||||
Min RK
|
r19557 | def _check_return(self, r, obj): | ||
"""Check that a return value is appropriate | ||||
Return the value if so, None otherwise, warning if invalid. | ||||
""" | ||||
if r is None or isinstance(r, self._return_type) or \ | ||||
(isinstance(r, tuple) and r and isinstance(r[0], self._return_type)): | ||||
return r | ||||
else: | ||||
warnings.warn( | ||||
"%s formatter returned invalid type %s (expected %s) for object: %s" % \ | ||||
(self.format_type, type(r), self._return_type, _safe_repr(obj)), | ||||
FormatterWarning | ||||
) | ||||
MinRK
|
r13781 | def lookup(self, obj): | ||
"""Look up the formatter for a given instance. | ||||
Parameters | ||||
---------- | ||||
obj : object instance | ||||
Returns | ||||
------- | ||||
f : callable | ||||
MinRK
|
r13788 | The registered formatting callable for the type. | ||
MinRK
|
r13781 | |||
Raises | ||||
------ | ||||
KeyError if the type has not been registered. | ||||
""" | ||||
# look for singleton first | ||||
obj_id = id(obj) | ||||
if obj_id in self.singleton_printers: | ||||
return self.singleton_printers[obj_id] | ||||
# then lookup by type | ||||
return self.lookup_by_type(_get_type(obj)) | ||||
def lookup_by_type(self, typ): | ||||
MinRK
|
r13788 | """Look up the registered formatter for a type. | ||
MinRK
|
r13781 | |||
Parameters | ||||
---------- | ||||
MinRK
|
r13790 | typ : type or '__module__.__name__' string for a type | ||
MinRK
|
r13781 | |||
Returns | ||||
------- | ||||
f : callable | ||||
MinRK
|
r13788 | The registered formatting callable for the type. | ||
Brian Granger
|
r3278 | |||
MinRK
|
r13781 | Raises | ||
------ | ||||
KeyError if the type has not been registered. | ||||
""" | ||||
Srinivas Reddy Thatiparthy
|
r23037 | if isinstance(typ, str): | ||
MinRK
|
r13788 | typ_key = tuple(typ.rsplit('.',1)) | ||
if typ_key not in self.deferred_printers: | ||||
# We may have it cached in the type map. We will have to | ||||
# iterate over all of the types to check. | ||||
for cls in self.type_printers: | ||||
if _mod_name_key(cls) == typ_key: | ||||
return self.type_printers[cls] | ||||
else: | ||||
return self.deferred_printers[typ_key] | ||||
else: | ||||
for cls in pretty._get_mro(typ): | ||||
if cls in self.type_printers or self._in_deferred_types(cls): | ||||
return self.type_printers[cls] | ||||
MinRK
|
r13781 | |||
# If we have reached here, the lookup failed. | ||||
raise KeyError("No registered printer for {0!r}".format(typ)) | ||||
def for_type(self, typ, func=None): | ||||
Brian Granger
|
r3278 | """Add a format function for a given type. | ||
MinRK
|
r13654 | |||
Brian Granger
|
r3288 | Parameters | ||
Brian Granger
|
r3278 | ----------- | ||
MinRK
|
r13790 | typ : type or '__module__.__name__' string for a type | ||
Brian Granger
|
r3278 | The class of the object that will be formatted using `func`. | ||
func : callable | ||||
MinRK
|
r13654 | A callable for computing the format data. | ||
`func` will be called with the object to be formatted, | ||||
and will return the raw data in this formatter's format. | ||||
Subclasses may use a different call signature for the | ||||
Brian Granger
|
r3278 | `func` argument. | ||
MinRK
|
r13654 | |||
MinRK
|
r13781 | If `func` is None or not specified, there will be no change, | ||
MinRK
|
r13654 | only returning the current value. | ||
Returns | ||||
------- | ||||
oldfunc : callable | ||||
The currently registered callable. | ||||
If you are registering a new formatter, | ||||
this will be the previous value (to enable restoring later). | ||||
Brian Granger
|
r3278 | """ | ||
MinRK
|
r13781 | # if string given, interpret as 'pkg.module.class_name' | ||
Srinivas Reddy Thatiparthy
|
r23037 | if isinstance(typ, str): | ||
MinRK
|
r13781 | type_module, type_name = typ.rsplit('.', 1) | ||
return self.for_type_by_name(type_module, type_name, func) | ||||
try: | ||||
oldfunc = self.lookup_by_type(typ) | ||||
except KeyError: | ||||
oldfunc = None | ||||
if func is not None: | ||||
Brian Granger
|
r3278 | self.type_printers[typ] = func | ||
MinRK
|
r13781 | |||
Brian Granger
|
r3278 | return oldfunc | ||
MinRK
|
r13781 | def for_type_by_name(self, type_module, type_name, func=None): | ||
Brian Granger
|
r3278 | """Add a format function for a type specified by the full dotted | ||
module and name of the type, rather than the type of the object. | ||||
Parameters | ||||
---------- | ||||
type_module : str | ||||
The full dotted name of the module the type is defined in, like | ||||
``numpy``. | ||||
type_name : str | ||||
The name of the type (the class name), like ``dtype`` | ||||
func : callable | ||||
MinRK
|
r13654 | A callable for computing the format data. | ||
`func` will be called with the object to be formatted, | ||||
and will return the raw data in this formatter's format. | ||||
Subclasses may use a different call signature for the | ||||
Brian Granger
|
r3278 | `func` argument. | ||
MinRK
|
r13654 | |||
MinRK
|
r13781 | If `func` is None or unspecified, there will be no change, | ||
MinRK
|
r13654 | only returning the current value. | ||
Returns | ||||
------- | ||||
oldfunc : callable | ||||
The currently registered callable. | ||||
If you are registering a new formatter, | ||||
this will be the previous value (to enable restoring later). | ||||
Brian Granger
|
r3278 | """ | ||
key = (type_module, type_name) | ||||
MinRK
|
r13781 | |||
MinRK
|
r13788 | try: | ||
oldfunc = self.lookup_by_type("%s.%s" % key) | ||||
except KeyError: | ||||
oldfunc = None | ||||
MinRK
|
r13781 | if func is not None: | ||
Brian Granger
|
r3278 | self.deferred_printers[key] = func | ||
return oldfunc | ||||
MinRK
|
r13781 | |||
MinRK
|
r13788 | def pop(self, typ, default=_raise_key_error): | ||
"""Pop a formatter for the given type. | ||||
MinRK
|
r13781 | |||
Parameters | ||||
---------- | ||||
typ : type or '__module__.__name__' string for a type | ||||
MinRK
|
r13788 | default : object | ||
value to be returned if no formatter is registered for typ. | ||||
MinRK
|
r13781 | |||
Returns | ||||
------- | ||||
obj : object | ||||
The last registered object for the type. | ||||
Raises | ||||
------ | ||||
MinRK
|
r13788 | KeyError if the type is not registered and default is not specified. | ||
MinRK
|
r13781 | """ | ||
MinRK
|
r13788 | |||
Srinivas Reddy Thatiparthy
|
r23037 | if isinstance(typ, str): | ||
MinRK
|
r13781 | typ_key = tuple(typ.rsplit('.',1)) | ||
if typ_key not in self.deferred_printers: | ||||
# We may have it cached in the type map. We will have to | ||||
# iterate over all of the types to check. | ||||
for cls in self.type_printers: | ||||
if _mod_name_key(cls) == typ_key: | ||||
old = self.type_printers.pop(cls) | ||||
break | ||||
else: | ||||
MinRK
|
r13788 | old = default | ||
MinRK
|
r13781 | else: | ||
MinRK
|
r13783 | old = self.deferred_printers.pop(typ_key) | ||
MinRK
|
r13781 | else: | ||
if typ in self.type_printers: | ||||
old = self.type_printers.pop(typ) | ||||
else: | ||||
MinRK
|
r13788 | old = self.deferred_printers.pop(_mod_name_key(typ), default) | ||
if old is _raise_key_error: | ||||
raise KeyError("No registered value for {0!r}".format(typ)) | ||||
MinRK
|
r13781 | return old | ||
Brian Granger
|
r3278 | |||
Brian Granger
|
r3279 | def _in_deferred_types(self, cls): | ||
""" | ||||
Check if the given class is specified in the deferred type registry. | ||||
MinRK
|
r13781 | Successful matches will be moved to the regular type registry for future use. | ||
Brian Granger
|
r3279 | """ | ||
mod = getattr(cls, '__module__', None) | ||||
name = getattr(cls, '__name__', None) | ||||
key = (mod, name) | ||||
if key in self.deferred_printers: | ||||
# Move the printer over to the regular registry. | ||||
printer = self.deferred_printers.pop(key) | ||||
self.type_printers[cls] = printer | ||||
MinRK
|
r13781 | return True | ||
return False | ||||
Brian Granger
|
r3278 | |||
Brian Granger
|
r3280 | |||
Brian Granger
|
r3278 | class PlainTextFormatter(BaseFormatter): | ||
"""The default pretty-printer. | ||||
Robert Kern
|
r6292 | This uses :mod:`IPython.lib.pretty` to compute the format data of | ||
Brian Granger
|
r3278 | the object. If the object cannot be pretty printed, :func:`repr` is used. | ||
Robert Kern
|
r6292 | See the documentation of :mod:`IPython.lib.pretty` for details on | ||
Brian Granger
|
r3278 | how to write pretty printers. Here is a simple example:: | ||
def dtype_pprinter(obj, p, cycle): | ||||
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, '])') | ||||
""" | ||||
# The format type of data returned. | ||||
Thomas Kluyver
|
r4046 | format_type = Unicode('text/plain') | ||
Brian Granger
|
r3278 | |||
Brian Granger
|
r3280 | # This subclass ignores this attribute as it always need to return | ||
# something. | ||||
Matthias Bussonnier
|
r22331 | enabled = Bool(True).tag(config=False) | ||
Min RK
|
r18518 | |||
Min RK
|
r22340 | max_seq_length = Integer(pretty.MAX_SEQ_LENGTH, | ||
Min RK
|
r18518 | help="""Truncate large collections (lists, dicts, tuples, sets) to this size. | ||
Set to 0 to disable truncation. | ||||
""" | ||||
Min RK
|
r22340 | ).tag(config=True) | ||
Min RK
|
r18518 | |||
Brian Granger
|
r3879 | # Look for a _repr_pretty_ methods to use for pretty printing. | ||
Thomas Kluyver
|
r4047 | print_method = ObjectName('_repr_pretty_') | ||
Robert Kern
|
r3209 | |||
# Whether to pretty-print or not. | ||||
Matthias Bussonnier
|
r22331 | pprint = Bool(True).tag(config=True) | ||
Robert Kern
|
r3209 | |||
# Whether to be verbose or not. | ||||
Matthias Bussonnier
|
r22331 | verbose = Bool(False).tag(config=True) | ||
Robert Kern
|
r3209 | |||
# The maximum width. | ||||
Matthias Bussonnier
|
r22331 | max_width = Integer(79).tag(config=True) | ||
Robert Kern
|
r3209 | |||
# The newline character. | ||||
Matthias Bussonnier
|
r22331 | newline = Unicode('\n').tag(config=True) | ||
Bernardo B. Marques
|
r4872 | |||
MinRK
|
r3350 | # format-string for pprinting floats | ||
Thomas Kluyver
|
r4046 | float_format = Unicode('%r') | ||
MinRK
|
r3350 | # setter for float precision, either int or direct format-string | ||
Matthias Bussonnier
|
r22331 | float_precision = CUnicode('').tag(config=True) | ||
Bernardo B. Marques
|
r4872 | |||
Min RK
|
r22742 | @observe('float_precision') | ||
def _float_precision_changed(self, change): | ||||
MinRK
|
r3350 | """float_precision changed, set float_format accordingly. | ||
Bernardo B. Marques
|
r4872 | |||
MinRK
|
r3350 | float_precision can be set by int or str. | ||
This will set float_format, after interpreting input. | ||||
If numpy has been imported, numpy print precision will also be set. | ||||
Bernardo B. Marques
|
r4872 | |||
MinRK
|
r3350 | integer `n` sets format to '%.nf', otherwise, format set directly. | ||
Bernardo B. Marques
|
r4872 | |||
MinRK
|
r3350 | An empty string returns to defaults (repr for float, 8 for numpy). | ||
Bernardo B. Marques
|
r4872 | |||
MinRK
|
r3350 | This parameter can be set via the '%precision' magic. | ||
""" | ||||
Bernardo B. Marques
|
r4872 | |||
Min RK
|
r22742 | new = change['new'] | ||
MinRK
|
r3350 | if '%' in new: | ||
# got explicit format string | ||||
fmt = new | ||||
try: | ||||
fmt%3.14159 | ||||
except Exception: | ||||
raise ValueError("Precision must be int or format string, not %r"%new) | ||||
elif new: | ||||
# otherwise, should be an int | ||||
try: | ||||
i = int(new) | ||||
assert i >= 0 | ||||
except ValueError: | ||||
raise ValueError("Precision must be int or format string, not %r"%new) | ||||
except AssertionError: | ||||
raise ValueError("int precision must be non-negative, not %r"%i) | ||||
Bernardo B. Marques
|
r4872 | |||
MinRK
|
r3350 | fmt = '%%.%if'%i | ||
if 'numpy' in sys.modules: | ||||
# set numpy precision if it has been imported | ||||
import numpy | ||||
numpy.set_printoptions(precision=i) | ||||
else: | ||||
# default back to repr | ||||
fmt = '%r' | ||||
if 'numpy' in sys.modules: | ||||
import numpy | ||||
# numpy default is 8 | ||||
numpy.set_printoptions(precision=8) | ||||
self.float_format = fmt | ||||
Robert Kern
|
r3209 | |||
Robert Kern
|
r6292 | # Use the default pretty printers from IPython.lib.pretty. | ||
Min RK
|
r22340 | @default('singleton_printers') | ||
Brian Granger
|
r3278 | def _singleton_printers_default(self): | ||
Robert Kern
|
r3209 | return pretty._singleton_pprinters.copy() | ||
Min RK
|
r22340 | @default('type_printers') | ||
Brian Granger
|
r3278 | def _type_printers_default(self): | ||
MinRK
|
r3350 | d = pretty._type_pprinters.copy() | ||
d[float] = lambda obj,p,cycle: p.text(self.float_format%obj) | ||||
return d | ||||
Robert Kern
|
r3209 | |||
Min RK
|
r22340 | @default('deferred_printers') | ||
Brian Granger
|
r3278 | def _deferred_printers_default(self): | ||
Robert Kern
|
r3209 | return pretty._deferred_type_pprinters.copy() | ||
#### FormatterABC interface #### | ||||
Min RK
|
r19929 | @catch_format_error | ||
Robert Kern
|
r3209 | def __call__(self, obj): | ||
Brian Granger
|
r3278 | """Compute the pretty representation of the object.""" | ||
Robert Kern
|
r3209 | if not self.pprint: | ||
MinRK
|
r18025 | return repr(obj) | ||
Robert Kern
|
r3209 | else: | ||
Srinivas Reddy Thatiparthy
|
r23119 | stream = StringIO() | ||
Robert Kern
|
r3209 | printer = pretty.RepresentationPrinter(stream, self.verbose, | ||
Min RK
|
r20486 | self.max_width, self.newline, | ||
Min RK
|
r18518 | max_seq_length=self.max_seq_length, | ||
Brian Granger
|
r3278 | singleton_pprinters=self.singleton_printers, | ||
type_pprinters=self.type_printers, | ||||
deferred_pprinters=self.deferred_printers) | ||||
Robert Kern
|
r3209 | printer.pretty(obj) | ||
printer.flush() | ||||
return stream.getvalue() | ||||
Brian Granger
|
r3278 | class HTMLFormatter(BaseFormatter): | ||
"""An HTML formatter. | ||||
Robert Kern
|
r3209 | |||
Brian Granger
|
r3278 | To define the callables that compute the HTML representation of your | ||
Brian Granger
|
r3878 | objects, define a :meth:`_repr_html_` method or use the :meth:`for_type` | ||
Brian Granger
|
r3278 | or :meth:`for_type_by_name` methods to register functions that handle | ||
this. | ||||
Brian Granger
|
r3880 | |||
The return value of this formatter should be a valid HTML snippet that | ||||
Bernardo B. Marques
|
r4872 | could be injected into an existing DOM. It should *not* include the | ||
Brian Granger
|
r3880 | ```<html>`` or ```<body>`` tags. | ||
Brian Granger
|
r3278 | """ | ||
Thomas Kluyver
|
r4046 | format_type = Unicode('text/html') | ||
Robert Kern
|
r3209 | |||
Thomas Kluyver
|
r4047 | print_method = ObjectName('_repr_html_') | ||
Robert Kern
|
r3209 | |||
Andrew Jesaitis
|
r16364 | class MarkdownFormatter(BaseFormatter): | ||
"""A Markdown formatter. | ||||
To define the callables that compute the Markdown representation of your | ||||
objects, define a :meth:`_repr_markdown_` method or use the :meth:`for_type` | ||||
or :meth:`for_type_by_name` methods to register functions that handle | ||||
this. | ||||
The return value of this formatter should be a valid Markdown. | ||||
""" | ||||
format_type = Unicode('text/markdown') | ||||
print_method = ObjectName('_repr_markdown_') | ||||
Brian Granger
|
r3278 | class SVGFormatter(BaseFormatter): | ||
"""An SVG formatter. | ||||
To define the callables that compute the SVG representation of your | ||||
Brian Granger
|
r3878 | objects, define a :meth:`_repr_svg_` method or use the :meth:`for_type` | ||
Brian Granger
|
r3278 | or :meth:`for_type_by_name` methods to register functions that handle | ||
this. | ||||
Brian Granger
|
r3880 | |||
The return value of this formatter should be valid SVG enclosed in | ||||
```<svg>``` tags, that could be injected into an existing DOM. It should | ||||
*not* include the ```<html>`` or ```<body>`` tags. | ||||
Robert Kern
|
r3209 | """ | ||
Thomas Kluyver
|
r4046 | format_type = Unicode('image/svg+xml') | ||
Robert Kern
|
r3209 | |||
Thomas Kluyver
|
r4047 | print_method = ObjectName('_repr_svg_') | ||
Robert Kern
|
r3209 | |||
Brian Granger
|
r3278 | class PNGFormatter(BaseFormatter): | ||
"""A PNG formatter. | ||||
Robert Kern
|
r3214 | |||
Brian Granger
|
r3278 | To define the callables that compute the PNG representation of your | ||
Brian Granger
|
r3878 | objects, define a :meth:`_repr_png_` method or use the :meth:`for_type` | ||
Brian Granger
|
r3278 | or :meth:`for_type_by_name` methods to register functions that handle | ||
Brian Granger
|
r3878 | this. | ||
Brian Granger
|
r3880 | The return value of this formatter should be raw PNG data, *not* | ||
base64 encoded. | ||||
Brian Granger
|
r3278 | """ | ||
Thomas Kluyver
|
r4046 | format_type = Unicode('image/png') | ||
Brian Granger
|
r3278 | |||
Thomas Kluyver
|
r4047 | print_method = ObjectName('_repr_png_') | ||
MinRK
|
r14152 | |||
Srinivas Reddy Thatiparthy
|
r23044 | _return_type = (bytes, str) | ||
Brian Granger
|
r3278 | |||
Brian E. Granger
|
r4528 | class JPEGFormatter(BaseFormatter): | ||
"""A JPEG formatter. | ||||
To define the callables that compute the JPEG representation of your | ||||
objects, define a :meth:`_repr_jpeg_` method or use the :meth:`for_type` | ||||
or :meth:`for_type_by_name` methods to register functions that handle | ||||
this. | ||||
The return value of this formatter should be raw JPEG data, *not* | ||||
base64 encoded. | ||||
""" | ||||
format_type = Unicode('image/jpeg') | ||||
print_method = ObjectName('_repr_jpeg_') | ||||
Srinivas Reddy Thatiparthy
|
r23044 | _return_type = (bytes, str) | ||
MinRK
|
r14152 | |||
Brian E. Granger
|
r4528 | |||
Brian Granger
|
r3278 | class LatexFormatter(BaseFormatter): | ||
"""A LaTeX formatter. | ||||
To define the callables that compute the LaTeX representation of your | ||||
Brian Granger
|
r3878 | objects, define a :meth:`_repr_latex_` method or use the :meth:`for_type` | ||
Brian Granger
|
r3278 | or :meth:`for_type_by_name` methods to register functions that handle | ||
this. | ||||
Brian Granger
|
r3880 | |||
The return value of this formatter should be a valid LaTeX equation, | ||||
Brian Granger
|
r6065 | enclosed in either ```$```, ```$$``` or another LaTeX equation | ||
environment. | ||||
Brian Granger
|
r3278 | """ | ||
Thomas Kluyver
|
r4046 | format_type = Unicode('text/latex') | ||
Brian Granger
|
r3278 | |||
Thomas Kluyver
|
r4047 | print_method = ObjectName('_repr_latex_') | ||
Brian Granger
|
r3278 | |||
class JSONFormatter(BaseFormatter): | ||||
"""A JSON string formatter. | ||||
Min RK
|
r19557 | To define the callables that compute the JSONable representation of | ||
Brian Granger
|
r3878 | your objects, define a :meth:`_repr_json_` method or use the :meth:`for_type` | ||
Brian Granger
|
r3278 | or :meth:`for_type_by_name` methods to register functions that handle | ||
this. | ||||
Brian Granger
|
r3880 | |||
Min RK
|
r19557 | The return value of this formatter should be a JSONable list or dict. | ||
JSON scalars (None, number, string) are not allowed, only dict or list containers. | ||||
Brian Granger
|
r3278 | """ | ||
Thomas Kluyver
|
r4046 | format_type = Unicode('application/json') | ||
Min RK
|
r19557 | _return_type = (list, dict) | ||
Brian Granger
|
r3278 | |||
Thomas Kluyver
|
r4047 | print_method = ObjectName('_repr_json_') | ||
Min RK
|
r19557 | |||
def _check_return(self, r, obj): | ||||
"""Check that a return value is appropriate | ||||
Return the value if so, None otherwise, warning if invalid. | ||||
""" | ||||
if r is None: | ||||
return | ||||
md = None | ||||
if isinstance(r, tuple): | ||||
# unpack data, metadata tuple for type checking on first element | ||||
r, md = r | ||||
# handle deprecated JSON-as-string form from IPython < 3 | ||||
Srinivas Reddy Thatiparthy
|
r23037 | if isinstance(r, str): | ||
Min RK
|
r19557 | warnings.warn("JSON expects JSONable list/dict containers, not JSON strings", | ||
FormatterWarning) | ||||
r = json.loads(r) | ||||
if md is not None: | ||||
# put the tuple back together | ||||
r = (r, md) | ||||
return super(JSONFormatter, self)._check_return(r, obj) | ||||
Brian Granger
|
r3878 | |||
class JavascriptFormatter(BaseFormatter): | ||||
"""A Javascript formatter. | ||||
To define the callables that compute the Javascript representation of | ||||
Bernardo B. Marques
|
r4872 | your objects, define a :meth:`_repr_javascript_` method or use the | ||
Brian Granger
|
r3878 | :meth:`for_type` or :meth:`for_type_by_name` methods to register functions | ||
that handle this. | ||||
Brian Granger
|
r3880 | |||
The return value of this formatter should be valid Javascript code and | ||||
should *not* be enclosed in ```<script>``` tags. | ||||
Brian Granger
|
r3878 | """ | ||
Thomas Kluyver
|
r4046 | format_type = Unicode('application/javascript') | ||
Brian Granger
|
r3278 | |||
Thomas Kluyver
|
r4047 | print_method = ObjectName('_repr_javascript_') | ||
Brian Granger
|
r3278 | |||
Brian E. Granger
|
r15121 | |||
class PDFFormatter(BaseFormatter): | ||||
"""A PDF formatter. | ||||
Jim Garrison
|
r16283 | To define the callables that compute the PDF representation of your | ||
Brian E. Granger
|
r15121 | objects, define a :meth:`_repr_pdf_` method or use the :meth:`for_type` | ||
or :meth:`for_type_by_name` methods to register functions that handle | ||||
this. | ||||
The return value of this formatter should be raw PDF data, *not* | ||||
base64 encoded. | ||||
""" | ||||
format_type = Unicode('application/pdf') | ||||
print_method = ObjectName('_repr_pdf_') | ||||
Srinivas Reddy Thatiparthy
|
r23044 | _return_type = (bytes, str) | ||
MinRK
|
r18123 | |||
Min RK
|
r19382 | class IPythonDisplayFormatter(BaseFormatter): | ||
Min RK
|
r23578 | """An escape-hatch Formatter for objects that know how to display themselves. | ||
Min RK
|
r19381 | |||
To define the callables that compute the representation of your | ||||
objects, define a :meth:`_ipython_display_` method or use the :meth:`for_type` | ||||
or :meth:`for_type_by_name` methods to register functions that handle | ||||
this. Unlike mime-type displays, this method should not return anything, | ||||
instead calling any appropriate display methods itself. | ||||
This display formatter has highest priority. | ||||
If it fires, no other display formatter will be called. | ||||
Min RK
|
r23578 | |||
Prior to IPython 6.1, `_ipython_display_` was the only way to display custom mime-types | ||||
without registering a new Formatter. | ||||
IPython 6.1 introduces `_repr_mimebundle_` for displaying custom mime-types, | ||||
so `_ipython_display_` should only be used for objects that require unusual | ||||
display patterns, such as multiple display calls. | ||||
Min RK
|
r19381 | """ | ||
print_method = ObjectName('_ipython_display_') | ||||
_return_type = (type(None), bool) | ||||
Min RK
|
r19929 | @catch_format_error | ||
Min RK
|
r19381 | def __call__(self, obj): | ||
"""Compute the format for an object.""" | ||||
if self.enabled: | ||||
# lookup registered printer | ||||
try: | ||||
printer = self.lookup(obj) | ||||
except KeyError: | ||||
pass | ||||
else: | ||||
printer(obj) | ||||
return True | ||||
# Finally look for special method names | ||||
Thomas Kluyver
|
r22148 | method = get_real_method(obj, self.print_method) | ||
Min RK
|
r19381 | if method is not None: | ||
method() | ||||
return True | ||||
Brian E. Granger
|
r15121 | |||
Min RK
|
r23578 | class MimeBundleFormatter(BaseFormatter): | ||
"""A Formatter for arbitrary mime-types. | ||||
Unlike other `_repr_<mimetype>_` methods, | ||||
`_repr_mimebundle_` should return mime-bundle data, | ||||
either the mime-keyed `data` dictionary or the tuple `(data, metadata)`. | ||||
Any mime-type is valid. | ||||
To define the callables that compute the mime-bundle representation of your | ||||
objects, define a :meth:`_repr_mimebundle_` method or use the :meth:`for_type` | ||||
or :meth:`for_type_by_name` methods to register functions that handle | ||||
this. | ||||
.. versionadded:: 6.1 | ||||
""" | ||||
print_method = ObjectName('_repr_mimebundle_') | ||||
_return_type = dict | ||||
def _check_return(self, r, obj): | ||||
r = super(MimeBundleFormatter, self)._check_return(r, obj) | ||||
# always return (data, metadata): | ||||
if r is None: | ||||
return {}, {} | ||||
if not isinstance(r, tuple): | ||||
return r, {} | ||||
return r | ||||
Matthias Bussonnier
|
r23618 | @catch_format_error | ||
def __call__(self, obj, include=None, exclude=None): | ||||
"""Compute the format for an object. | ||||
Identical to parent's method but we pass extra parameters to the method. | ||||
Unlike other _repr_*_ `_repr_mimebundle_` should allow extra kwargs, in | ||||
particular `include` and `exclude`. | ||||
""" | ||||
if self.enabled: | ||||
# lookup registered printer | ||||
try: | ||||
printer = self.lookup(obj) | ||||
except KeyError: | ||||
pass | ||||
else: | ||||
return printer(obj) | ||||
# Finally look for special method names | ||||
method = get_real_method(obj, self.print_method) | ||||
if method is not None: | ||||
Min RK
|
r23849 | return method(include=include, exclude=exclude) | ||
Matthias Bussonnier
|
r23618 | return None | ||
else: | ||||
return None | ||||
Min RK
|
r23578 | |||
Brian Granger
|
r3278 | FormatterABC.register(BaseFormatter) | ||
FormatterABC.register(PlainTextFormatter) | ||||
FormatterABC.register(HTMLFormatter) | ||||
Andrew Jesaitis
|
r16364 | FormatterABC.register(MarkdownFormatter) | ||
Brian Granger
|
r3278 | FormatterABC.register(SVGFormatter) | ||
FormatterABC.register(PNGFormatter) | ||||
Brian E. Granger
|
r15121 | FormatterABC.register(PDFFormatter) | ||
Brian E. Granger
|
r4528 | FormatterABC.register(JPEGFormatter) | ||
Brian Granger
|
r3278 | FormatterABC.register(LatexFormatter) | ||
FormatterABC.register(JSONFormatter) | ||||
Brian Granger
|
r3878 | FormatterABC.register(JavascriptFormatter) | ||
Min RK
|
r19382 | FormatterABC.register(IPythonDisplayFormatter) | ||
Min RK
|
r23578 | FormatterABC.register(MimeBundleFormatter) | ||
Brian Granger
|
r3278 | |||
def format_display_data(obj, include=None, exclude=None): | ||||
"""Return a format data dict for an object. | ||||
By default all format types will be computed. | ||||
Parameters | ||||
---------- | ||||
obj : object | ||||
The Python object whose format data will be computed. | ||||
Returns | ||||
------- | ||||
format_dict : dict | ||||
A dictionary of key/value pairs, one or each format that was | ||||
generated for the object. The keys are the format types, which | ||||
will usually be MIME type strings and the values and JSON'able | ||||
data structure containing the raw data for the representation in | ||||
that format. | ||||
include : list or tuple, optional | ||||
A list of format type strings (MIME types) to include in the | ||||
format data dict. If this is set *only* the format types included | ||||
in this list will be computed. | ||||
exclude : list or tuple, optional | ||||
A list of format type string (MIME types) to exclue in the format | ||||
data dict. If this is set all format types will be computed, | ||||
except for those included in this argument. | ||||
""" | ||||
from IPython.core.interactiveshell import InteractiveShell | ||||
Robert Kern
|
r3209 | |||
Thomas Kluyver
|
r22250 | return InteractiveShell.instance().display_formatter.format( | ||
Brian Granger
|
r3278 | obj, | ||
include, | ||||
exclude | ||||
) | ||||