Skip to content

Commit a336a98

Browse files
authored
Some documentations about custom formatters (ipython#14579)
2 parents 0615526 + 969bfa6 commit a336a98

File tree

2 files changed

+96
-35
lines changed

2 files changed

+96
-35
lines changed

IPython/core/formatters.py

Lines changed: 92 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,61 @@
11
# -*- coding: utf-8 -*-
22
"""Display formatters.
33
4+
This module defines the base instances in order to implement custom
5+
formatters/mimetypes
6+
got objects:
7+
8+
As we want to see internal IPython working we are going to use the following
9+
function to diaply objects instead of the normal print or display method:
10+
11+
>>> ip = get_ipython()
12+
>>> ip.display_formatter.format(...)
13+
({'text/plain': 'Ellipsis'}, {})
14+
15+
This return a tuple with the mimebumdle for the current object, and the
16+
associated metadata.
17+
18+
19+
We can now define our own formatter and register it:
20+
21+
22+
>>> from IPython.core.formatters import BaseFormatter, FormatterABC
23+
24+
25+
>>> class LLMFormatter(BaseFormatter):
26+
...
27+
... format_type = 'x-vendor/llm'
28+
... print_method = '_repr_llm_'
29+
... _return_type = (dict, str)
30+
31+
>>> llm_formatter = LLMFormatter(parent=ip.display_formatter)
32+
33+
>>> ip.display_formatter.formatters[LLMFormatter.format_type] = llm_formatter
34+
35+
Now any class that define `_repr_llm_` will return a x-vendor/llm as part of
36+
it's display data:
37+
38+
>>> class A:
39+
...
40+
... def _repr_llm_(self, *kwargs):
41+
... return 'This a A'
42+
...
43+
44+
>>> ip.display_formatter.format(A())
45+
({'text/plain': '<IPython.core.formatters.A at ...>', 'x-vendor/llm': 'This a A'}, {})
46+
47+
As usual, you can register methods for third party types (see
48+
:ref:`third_party_formatting`)
49+
50+
>>> def llm_int(obj):
51+
... return 'This is the integer %s, in between %s and %s'%(obj, obj-1, obj+1)
52+
53+
>>> llm_formatter.for_type(int, llm_int)
54+
55+
>>> ip.display_formatter.format(42)
56+
({'text/plain': '42', 'x-vendor/llm': 'This is the integer 42, in between 41 and 43'}, {})
57+
58+
459
Inheritance diagram:
560
661
.. inheritance-diagram:: IPython.core.formatters
@@ -37,9 +92,10 @@ class DisplayFormatter(Configurable):
3792
active_types = List(Unicode(),
3893
help="""List of currently active mime-types to display.
3994
You can use this to set a white-list for formats to display.
40-
95+
4196
Most users will not need to change this value.
42-
""").tag(config=True)
97+
""",
98+
).tag(config=True)
4399

44100
@default('active_types')
45101
def _active_types_default(self):
@@ -144,7 +200,7 @@ def format(self, obj, include=None, exclude=None):
144200
"""
145201
format_dict = {}
146202
md_dict = {}
147-
203+
148204
if self.ipython_display_formatter(obj):
149205
# object handled itself, don't proceed
150206
return {}, {}
@@ -176,18 +232,18 @@ def format(self, obj, include=None, exclude=None):
176232
continue
177233
if exclude and format_type in exclude:
178234
continue
179-
235+
180236
md = None
181237
try:
182238
data = formatter(obj)
183239
except:
184240
# FIXME: log the exception
185241
raise
186-
242+
187243
# formatters can return raw data or (data, metadata)
188244
if isinstance(data, tuple) and len(data) == 2:
189245
data, md = data
190-
246+
191247
if data is not None:
192248
format_dict[format_type] = data
193249
if md is not None:
@@ -252,7 +308,7 @@ class FormatterABC(metaclass=abc.ABCMeta):
252308

253309
# Is the formatter enabled...
254310
enabled = True
255-
311+
256312
@abc.abstractmethod
257313
def __call__(self, obj):
258314
"""Return a JSON'able representation of the object.
@@ -278,12 +334,15 @@ def _get_type(obj):
278334
return getattr(obj, '__class__', None) or type(obj)
279335

280336

281-
_raise_key_error = Sentinel('_raise_key_error', __name__,
282-
"""
337+
_raise_key_error = Sentinel(
338+
"_raise_key_error",
339+
__name__,
340+
"""
283341
Special value to raise a KeyError
284342
285343
Raise KeyError in `BaseFormatter.pop` if passed as the default value to `pop`
286-
""")
344+
""",
345+
)
287346

288347

289348
class BaseFormatter(Configurable):
@@ -329,7 +388,7 @@ class BaseFormatter(Configurable):
329388
# The deferred-import type-specific printers.
330389
# Map (modulename, classname) pairs to the format functions.
331390
deferred_printers = Dict().tag(config=True)
332-
391+
333392
@catch_format_error
334393
def __call__(self, obj):
335394
"""Compute the format for an object."""
@@ -348,7 +407,7 @@ def __call__(self, obj):
348407
return None
349408
else:
350409
return None
351-
410+
352411
def __contains__(self, typ):
353412
"""map in to lookup_by_type"""
354413
try:
@@ -357,7 +416,7 @@ def __contains__(self, typ):
357416
return False
358417
else:
359418
return True
360-
419+
361420
def _check_return(self, r, obj):
362421
"""Check that a return value is appropriate
363422
@@ -372,7 +431,7 @@ def _check_return(self, r, obj):
372431
(self.format_type, type(r), self._return_type, _safe_repr(obj)),
373432
FormatterWarning
374433
)
375-
434+
376435
def lookup(self, obj):
377436
"""Look up the formatter for a given instance.
378437
@@ -395,7 +454,7 @@ def lookup(self, obj):
395454
return self.singleton_printers[obj_id]
396455
# then lookup by type
397456
return self.lookup_by_type(_get_type(obj))
398-
457+
399458
def lookup_by_type(self, typ):
400459
"""Look up the registered formatter for a type.
401460
@@ -426,7 +485,7 @@ def lookup_by_type(self, typ):
426485
for cls in pretty._get_mro(typ):
427486
if cls in self.type_printers or self._in_deferred_types(cls):
428487
return self.type_printers[cls]
429-
488+
430489
# If we have reached here, the lookup failed.
431490
raise KeyError("No registered printer for {0!r}".format(typ))
432491

@@ -459,15 +518,15 @@ def for_type(self, typ, func=None):
459518
if isinstance(typ, str):
460519
type_module, type_name = typ.rsplit('.', 1)
461520
return self.for_type_by_name(type_module, type_name, func)
462-
521+
463522
try:
464523
oldfunc = self.lookup_by_type(typ)
465524
except KeyError:
466525
oldfunc = None
467-
526+
468527
if func is not None:
469528
self.type_printers[typ] = func
470-
529+
471530
return oldfunc
472531

473532
def for_type_by_name(self, type_module, type_name, func=None):
@@ -501,16 +560,16 @@ def for_type_by_name(self, type_module, type_name, func=None):
501560
this will be the previous value (to enable restoring later).
502561
"""
503562
key = (type_module, type_name)
504-
563+
505564
try:
506565
oldfunc = self.lookup_by_type("%s.%s" % key)
507566
except KeyError:
508567
oldfunc = None
509-
568+
510569
if func is not None:
511570
self.deferred_printers[key] = func
512571
return oldfunc
513-
572+
514573
def pop(self, typ, default=_raise_key_error):
515574
"""Pop a formatter for the given type.
516575
@@ -529,7 +588,7 @@ def pop(self, typ, default=_raise_key_error):
529588
------
530589
KeyError if the type is not registered and default is not specified.
531590
"""
532-
591+
533592
if isinstance(typ, str):
534593
typ_key = tuple(typ.rsplit('.',1))
535594
if typ_key not in self.deferred_printers:
@@ -599,14 +658,14 @@ def dtype_pprinter(obj, p, cycle):
599658
# This subclass ignores this attribute as it always need to return
600659
# something.
601660
enabled = Bool(True).tag(config=False)
602-
661+
603662
max_seq_length = Integer(pretty.MAX_SEQ_LENGTH,
604663
help="""Truncate large collections (lists, dicts, tuples, sets) to this size.
605-
664+
606665
Set to 0 to disable truncation.
607-
"""
666+
""",
608667
).tag(config=True)
609-
668+
610669
# Look for a _repr_pretty_ methods to use for pretty printing.
611670
print_method = ObjectName('_repr_pretty_')
612671

@@ -775,7 +834,7 @@ class PNGFormatter(BaseFormatter):
775834
format_type = Unicode('image/png')
776835

777836
print_method = ObjectName('_repr_png_')
778-
837+
779838
_return_type = (bytes, str)
780839

781840

@@ -829,7 +888,7 @@ class JSONFormatter(BaseFormatter):
829888
_return_type = (list, dict)
830889

831890
print_method = ObjectName('_repr_json_')
832-
891+
833892
def _check_return(self, r, obj):
834893
"""Check that a return value is appropriate
835894
@@ -887,19 +946,19 @@ class PDFFormatter(BaseFormatter):
887946

888947
class IPythonDisplayFormatter(BaseFormatter):
889948
"""An escape-hatch Formatter for objects that know how to display themselves.
890-
949+
891950
To define the callables that compute the representation of your
892951
objects, define a :meth:`_ipython_display_` method or use the :meth:`for_type`
893952
or :meth:`for_type_by_name` methods to register functions that handle
894953
this. Unlike mime-type displays, this method should not return anything,
895954
instead calling any appropriate display methods itself.
896-
955+
897956
This display formatter has highest priority.
898957
If it fires, no other display formatter will be called.
899958
900959
Prior to IPython 6.1, `_ipython_display_` was the only way to display custom mime-types
901960
without registering a new Formatter.
902-
961+
903962
IPython 6.1 introduces `_repr_mimebundle_` for displaying custom mime-types,
904963
so `_ipython_display_` should only be used for objects that require unusual
905964
display patterns, such as multiple display calls.
@@ -943,7 +1002,7 @@ class MimeBundleFormatter(BaseFormatter):
9431002
"""
9441003
print_method = ObjectName('_repr_mimebundle_')
9451004
_return_type = dict
946-
1005+
9471006
def _check_return(self, r, obj):
9481007
r = super(MimeBundleFormatter, self)._check_return(r, obj)
9491008
# always return (data, metadata):

docs/source/config/integrating.rst

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ Tab completion
99

1010
To change the attributes displayed by tab-completing your object, define a
1111
``__dir__(self)`` method for it. For more details, see the documentation of the
12-
built-in `dir() function <http://docs.python.org/library/functions.html#dir>`_.
12+
built-in :external+python:py:func:`dir`
1313

1414
You can also customise key completions for your objects, e.g. pressing tab after
1515
``obj["a``. To do so, define a method ``_ipython_key_completions_()``, which
@@ -25,7 +25,7 @@ Rich display
2525
============
2626

2727
Custom methods
28-
----------------------
28+
--------------
2929

3030
IPython can display richer representations of objects.
3131
To do this, you can define ``_ipython_display_()``, or any of a number of
@@ -154,6 +154,8 @@ to inform the frontend how to size the image.
154154

155155

156156

157+
.. _third_party_formatting:
158+
157159
Formatters for third-party types
158160
--------------------------------
159161

0 commit comments

Comments
 (0)