From 40c551f7ef93befa468a64d2add3d258d49541f2 2017-05-30 18:48:25 From: Kyle Kelley Date: 2017-05-30 18:48:25 Subject: [PATCH] Backport PR #10596 on branch 5.x Merge pull request #10596 from Carreau/display-builtin Inject display into builtins --- diff --git a/IPython/core/display.py b/IPython/core/display.py index 748c3b5..e52c815 100644 --- a/IPython/core/display.py +++ b/IPython/core/display.py @@ -144,6 +144,9 @@ def display(*objs, **kwargs): By default all representations will be computed and sent to the frontends. Frontends can decide which representation is used and how. + In terminal IPython this will be similar to using :func:`print`, for use in richer + frontends see Jupyter notebook examples with rich display logic. + Parameters ---------- objs : tuple of objects @@ -151,11 +154,11 @@ def display(*objs, **kwargs): raw : bool, optional Are the objects to be displayed already mimetype-keyed dicts of raw display data, or Python objects that need to be formatted before display? [default: False] - include : list or tuple, optional + include : list, tuple or set, 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 + exclude : list, tuple or set, optional A list of format type strings (MIME types) to exclude in the format data dict. If this is set all format types will be computed, except for those included in this argument. @@ -166,19 +169,113 @@ def display(*objs, **kwargs): transient : dict, optional A dictionary of transient data to associate with the output. Data in this dict should not be persisted to files (e.g. notebooks). - display_id : str, optional + display_id : str, bool optional Set an id for the display. This id can be used for updating this display area later via update_display. - If given as True, generate a new display_id + If given as `True`, generate a new `display_id` kwargs: additional keyword-args, optional Additional keyword-arguments are passed through to the display publisher. - + Returns ------- - + handle: DisplayHandle - Returns a handle on updatable displays, if display_id is given. - Returns None if no display_id is given (default). + Returns a handle on updatable displays for use with :func:`update_display`, + if `display_id` is given. Returns :any:`None` if no `display_id` is given + (default). + + Examples + -------- + + >>> class Json(object): + ... def __init__(self, json): + ... self.json = json + ... def _repr_pretty_(self, pp, cycle): + ... import json + ... pp.text(json.dumps(self.json, indent=2)) + ... def __repr__(self): + ... return str(self.json) + ... + + >>> d = Json({1:2, 3: {4:5}}) + + >>> print(d) + {1: 2, 3: {4: 5}} + + >>> display(d) + { + "1": 2, + "3": { + "4": 5 + } + } + + >>> def int_formatter(integer, pp, cycle): + ... pp.text('I'*integer) + + >>> plain = get_ipython().display_formatter.formatters['text/plain'] + >>> plain.for_type(int, int_formatter) + + >>> display(7-5) + II + + >>> del plain.type_printers[int] + >>> display(7-5) + 2 + + See Also + -------- + + :func:`update_display` + + Notes + ----- + + In Python, objects can declare their textual representation using the + `__repr__` method. IPython expands on this idea and allows objects to declare + other, rich representations including: + + - HTML + - JSON + - PNG + - JPEG + - SVG + - LaTeX + + A single object can declare some or all of these representations; all are + handled by IPython's display system. + + The main idea of the first approach is that you have to implement special + display methods when you define your class, one for each representation you + want to use. Here is a list of the names of the special methods and the + values they must return: + + - `_repr_html_`: return raw HTML as a string + - `_repr_json_`: return a JSONable dict + - `_repr_jpeg_`: return raw JPEG data + - `_repr_png_`: return raw PNG data + - `_repr_svg_`: return raw SVG data as a string + - `_repr_latex_`: return LaTeX commands in a string surrounded by "$". + - `_repr_mimebundle_`: return a full mimebundle containing the mapping + from all mimetypes to data + + When you are directly writing your own classes, you can adapt them for + display in IPython by following the above approach. But in practice, you + often need to work with existing classes that you can't easily modify. + + You can refer to the documentation on IPython display formatters in order to + register custom formatters for already existing types. + + .. versionadded:: 5.4 display available without import + .. versionadded:: 6.1 display available without import + + Since IPython 5.4 and 6.1 :func:`display` is automatically made available to + the user without import. If you are using display in a document that might + be used in a pure python context or with older version of IPython, use the + following import at the top of your file:: + + from IPython.display import display + """ raw = kwargs.pop('raw', False) include = kwargs.pop('include', None) @@ -189,7 +286,7 @@ def display(*objs, **kwargs): if transient is None: transient = {} if display_id: - if display_id == True: + if display_id is True: display_id = _new_id() transient['display_id'] = display_id if kwargs.get('update') and 'display_id' not in transient: @@ -229,6 +326,11 @@ def update_display(obj, **kwargs): The object with which to update the display display_id: keyword-only The id of the display to update + + See Also + -------- + + :func:`display` """ sentinel = object() display_id = kwargs.pop('display_id', sentinel) @@ -241,10 +343,16 @@ def update_display(obj, **kwargs): class DisplayHandle(object): """A handle on an updatable display - Call .update(obj) to display a new object. + Call `.update(obj)` to display a new object. - Call .display(obj) to add a new instance of this display, + Call `.display(obj`) to add a new instance of this display, and update existing instances. + + See Also + -------- + + :func:`display`, :func:`update_display` + """ def __init__(self, display_id=None): diff --git a/IPython/core/interactiveshell.py b/IPython/core/interactiveshell.py index efbe365..51040bc 100644 --- a/IPython/core/interactiveshell.py +++ b/IPython/core/interactiveshell.py @@ -58,6 +58,7 @@ from IPython.core.prefilter import PrefilterManager from IPython.core.profiledir import ProfileDir from IPython.core.usage import default_banner from IPython.testing.skipdoctest import skip_doctest_py2, skip_doctest +from IPython.display import display from IPython.utils import PyColorize from IPython.utils import io from IPython.utils import py3compat @@ -636,6 +637,7 @@ class InteractiveShell(SingletonConfigurable): # removing on exit or representing the existence of more than one # IPython at a time. builtin_mod.__dict__['__IPYTHON__'] = True + builtin_mod.__dict__['display'] = display self.builtin_trap = BuiltinTrap(shell=self) diff --git a/IPython/core/tests/test_display.py b/IPython/core/tests/test_display.py index 6dacd93..c6631d1 100644 --- a/IPython/core/tests/test_display.py +++ b/IPython/core/tests/test_display.py @@ -12,6 +12,7 @@ from IPython.core import display from IPython.core.getipython import get_ipython from IPython.utils.tempdir import NamedFileInTemporaryDirectory from IPython import paths as ipath +from IPython.testing.tools import AssertPrints, AssertNotPrints import IPython.testing.decorators as dec @@ -123,6 +124,25 @@ def test_set_matplotlib_formats_kwargs(): expected.update(cfg.print_figure_kwargs) nt.assert_equal(cell, expected) +def test_display_available(): + """ + Test that display is available without import + + We don't really care if it's in builtin or anything else, but it should + always be available. + """ + ip = get_ipython() + with AssertNotPrints('NameError'): + ip.run_cell('display') + try: + ip.run_cell('del display') + except NameError: + pass # it's ok, it might be in builtins + # even if deleted it should be back + with AssertNotPrints('NameError'): + ip.run_cell('display') + + def test_displayobject_repr(): h = display.HTML('
') nt.assert_equal(repr(h), '') diff --git a/docs/source/interactive/plotting.rst b/docs/source/interactive/plotting.rst index 8d243d8..2bf67b4 100644 --- a/docs/source/interactive/plotting.rst +++ b/docs/source/interactive/plotting.rst @@ -1,7 +1,32 @@ .. _plotting: +Rich Outputs +------------ + +One of the main feature of IPython when used as a kernel is its ability to +show rich output. This means that object that can be representing as image, +sounds, animation, (etc...) can be shown this way if the frontend support it. + +In order for this to be possible, you need to use the ``display()`` function, +that should be available by default on IPython 5.4+ and 6.1+, or that you can +import with ``from IPython.display import display``. Then use ``display()`` instead of ``print()``, and if possible your object will be displayed +with a richer representation. In the terminal of course, there wont be much +difference as object are most of the time represented by text, but in notebook +and similar interface you will get richer outputs. + + Plotting -------- + +.. note:: + + Starting with IPython 5.0 and matplotlib 2.0 you can avoid the use of + IPython's specific magic and use + ``matplotlib.pyplot.ion()``/``matplotlib.pyplot.ioff()`` which have the + advantages of working outside of IPython as well. + + One major feature of the IPython kernel is the ability to display plots that are the output of running code cells. The IPython kernel is designed to work seamlessly with the matplotlib_ plotting library to provide this functionality. diff --git a/docs/source/whatsnew/version5.rst b/docs/source/whatsnew/version5.rst index a2ff1a0..f715603 100644 --- a/docs/source/whatsnew/version5.rst +++ b/docs/source/whatsnew/version5.rst @@ -50,6 +50,19 @@ Implement display id and ability to update a given display. This should greatly simplify a lot of code by removing the need for widgets and allow other frontend to implement things like progress-bars. See :ghpull:`10048` +Display function +---------------- + +The :func:`display() ` function is now available by +default in an IPython session, meaning users can call it on any object to see +their rich representation. This should allow for better interactivity both at +the REPL and in notebook environment. + +Scripts and library that rely on display and may be run outside of IPython still +need to import the display function using ``from IPython.display import +display``. See :ghpull:`10596` + + Miscs -----