1# -*- coding: utf-8 -*-
2"""Top-level display functions for displaying object in different formats."""
3
4# Copyright (c) IPython Development Team.
5# Distributed under the terms of the Modified BSD License.
6
7from __future__ import print_function
8
9try:
10    from base64 import encodebytes as base64_encode
11except ImportError:
12    from base64 import encodestring as base64_encode
13
14from binascii import b2a_hex, hexlify
15import json
16import mimetypes
17import os
18import struct
19import sys
20import warnings
21
22from IPython.utils.py3compat import (string_types, cast_bytes_py2, cast_unicode,
23                                     unicode_type)
24from IPython.testing.skipdoctest import skip_doctest
25
26__all__ = ['display', 'display_pretty', 'display_html', 'display_markdown',
27'display_svg', 'display_png', 'display_jpeg', 'display_latex', 'display_json',
28'display_javascript', 'display_pdf', 'DisplayObject', 'TextDisplayObject',
29'Pretty', 'HTML', 'Markdown', 'Math', 'Latex', 'SVG', 'ProgressBar', 'JSON', 'Javascript',
30'Image', 'clear_output', 'set_matplotlib_formats', 'set_matplotlib_close',
31'publish_display_data', 'update_display', 'DisplayHandle']
32
33#-----------------------------------------------------------------------------
34# utility functions
35#-----------------------------------------------------------------------------
36
37def _safe_exists(path):
38    """Check path, but don't let exceptions raise"""
39    try:
40        return os.path.exists(path)
41    except Exception:
42        return False
43
44def _merge(d1, d2):
45    """Like update, but merges sub-dicts instead of clobbering at the top level.
46
47    Updates d1 in-place
48    """
49
50    if not isinstance(d2, dict) or not isinstance(d1, dict):
51        return d2
52    for key, value in d2.items():
53        d1[key] = _merge(d1.get(key), value)
54    return d1
55
56def _display_mimetype(mimetype, objs, raw=False, metadata=None):
57    """internal implementation of all display_foo methods
58
59    Parameters
60    ----------
61    mimetype : str
62        The mimetype to be published (e.g. 'image/png')
63    objs : tuple of objects
64        The Python objects to display, or if raw=True raw text data to
65        display.
66    raw : bool
67        Are the data objects raw data or Python objects that need to be
68        formatted before display? [default: False]
69    metadata : dict (optional)
70        Metadata to be associated with the specific mimetype output.
71    """
72    if metadata:
73        metadata = {mimetype: metadata}
74    if raw:
75        # turn list of pngdata into list of { 'image/png': pngdata }
76        objs = [ {mimetype: obj} for obj in objs ]
77    display(*objs, raw=raw, metadata=metadata, include=[mimetype])
78
79#-----------------------------------------------------------------------------
80# Main functions
81#-----------------------------------------------------------------------------
82# use * to indicate transient is keyword-only
83def publish_display_data(data, metadata=None, source=None, **kwargs):
84    """Publish data and metadata to all frontends.
85
86    See the ``display_data`` message in the messaging documentation for
87    more details about this message type.
88
89    The following MIME types are currently implemented:
90
91    * text/plain
92    * text/html
93    * text/markdown
94    * text/latex
95    * application/json
96    * application/javascript
97    * image/png
98    * image/jpeg
99    * image/svg+xml
100
101    Parameters
102    ----------
103    data : dict
104        A dictionary having keys that are valid MIME types (like
105        'text/plain' or 'image/svg+xml') and values that are the data for
106        that MIME type. The data itself must be a JSON'able data
107        structure. Minimally all data should have the 'text/plain' data,
108        which can be displayed by all frontends. If more than the plain
109        text is given, it is up to the frontend to decide which
110        representation to use.
111    metadata : dict
112        A dictionary for metadata related to the data. This can contain
113        arbitrary key, value pairs that frontends can use to interpret
114        the data. mime-type keys matching those in data can be used
115        to specify metadata about particular representations.
116    source : str, deprecated
117        Unused.
118    transient : dict, keyword-only
119        A dictionary of transient data, such as display_id.
120        """
121    from IPython.core.interactiveshell import InteractiveShell
122
123    display_pub = InteractiveShell.instance().display_pub
124
125    # only pass transient if supplied,
126    # to avoid errors with older ipykernel.
127    # TODO: We could check for ipykernel version and provide a detailed upgrade message.
128
129    display_pub.publish(
130        data=data,
131        metadata=metadata,
132        **kwargs
133    )
134
135
136def _new_id():
137    """Generate a new random text id with urandom"""
138    return b2a_hex(os.urandom(16)).decode('ascii')
139
140
141def display(*objs, **kwargs):
142    """Display a Python object in all frontends.
143
144    By default all representations will be computed and sent to the frontends.
145    Frontends can decide which representation is used and how.
146
147    In terminal IPython this will be similar to using :func:`print`, for use in richer
148    frontends see Jupyter notebook examples with rich display logic.
149
150    Parameters
151    ----------
152    objs : tuple of objects
153        The Python objects to display.
154    raw : bool, optional
155        Are the objects to be displayed already mimetype-keyed dicts of raw display data,
156        or Python objects that need to be formatted before display? [default: False]
157    include : list, tuple or set, optional
158        A list of format type strings (MIME types) to include in the
159        format data dict. If this is set *only* the format types included
160        in this list will be computed.
161    exclude : list, tuple or set, optional
162        A list of format type strings (MIME types) to exclude in the format
163        data dict. If this is set all format types will be computed,
164        except for those included in this argument.
165    metadata : dict, optional
166        A dictionary of metadata to associate with the output.
167        mime-type keys in this dictionary will be associated with the individual
168        representation formats, if they exist.
169    transient : dict, optional
170        A dictionary of transient data to associate with the output.
171        Data in this dict should not be persisted to files (e.g. notebooks).
172    display_id : str, bool optional
173        Set an id for the display.
174        This id can be used for updating this display area later via update_display.
175        If given as `True`, generate a new `display_id`
176    kwargs: additional keyword-args, optional
177        Additional keyword-arguments are passed through to the display publisher.
178
179    Returns
180    -------
181
182    handle: DisplayHandle
183        Returns a handle on updatable displays for use with :func:`update_display`,
184        if `display_id` is given. Returns :any:`None` if no `display_id` is given
185        (default).
186
187    Examples
188    --------
189
190    >>> class Json(object):
191    ...     def __init__(self, json):
192    ...         self.json = json
193    ...     def _repr_pretty_(self, pp, cycle):
194    ...         import json
195    ...         pp.text(json.dumps(self.json, indent=2))
196    ...     def __repr__(self):
197    ...         return str(self.json)
198    ...
199
200    >>> d = Json({1:2, 3: {4:5}})
201
202    >>> print(d)
203    {1: 2, 3: {4: 5}}
204
205    >>> display(d)
206    {
207      "1": 2,
208      "3": {
209        "4": 5
210      }
211    }
212
213    >>> def int_formatter(integer, pp, cycle):
214    ...     pp.text('I'*integer)
215
216    >>> plain = get_ipython().display_formatter.formatters['text/plain']
217    >>> plain.for_type(int, int_formatter)
218    <function _repr_pprint at 0x...>
219    >>> display(7-5)
220    II
221
222    >>> del plain.type_printers[int]
223    >>> display(7-5)
224    2
225
226    See Also
227    --------
228
229    :func:`update_display`
230
231    Notes
232    -----
233
234    In Python, objects can declare their textual representation using the
235    `__repr__` method. IPython expands on this idea and allows objects to declare
236    other, rich representations including:
237
238      - HTML
239      - JSON
240      - PNG
241      - JPEG
242      - SVG
243      - LaTeX
244
245    A single object can declare some or all of these representations; all are
246    handled by IPython's display system.
247
248    The main idea of the first approach is that you have to implement special
249    display methods when you define your class, one for each representation you
250    want to use. Here is a list of the names of the special methods and the
251    values they must return:
252
253      - `_repr_html_`: return raw HTML as a string
254      - `_repr_json_`: return a JSONable dict
255      - `_repr_jpeg_`: return raw JPEG data
256      - `_repr_png_`: return raw PNG data
257      - `_repr_svg_`: return raw SVG data as a string
258      - `_repr_latex_`: return LaTeX commands in a string surrounded by "$".
259      - `_repr_mimebundle_`: return a full mimebundle containing the mapping
260      from all mimetypes to data
261
262    When you are directly writing your own classes, you can adapt them for
263    display in IPython by following the above approach. But in practice, you
264    often need to work with existing classes that you can't easily modify.
265
266    You can refer to the documentation on IPython display formatters in order to
267    register custom formatters for already existing types.
268
269    .. versionadded:: 5.4 display available without import
270    .. versionadded:: 6.1 display available without import
271
272    Since IPython 5.4 and 6.1 :func:`display` is automatically made available to
273    the user without import. If you are using display in a document that might
274    be used in a pure python context or with older version of IPython, use the
275    following import at the top of your file::
276
277        from IPython.display import display
278
279    """
280    from IPython.core.interactiveshell import InteractiveShell
281
282    if not InteractiveShell.initialized():
283        # Directly print objects.
284        print(*objs)
285        return
286
287    raw = kwargs.pop('raw', False)
288    include = kwargs.pop('include', None)
289    exclude = kwargs.pop('exclude', None)
290    metadata = kwargs.pop('metadata', None)
291    transient = kwargs.pop('transient', None)
292    display_id = kwargs.pop('display_id', None)
293    if transient is None:
294        transient = {}
295    if display_id:
296        if display_id is True:
297            display_id = _new_id()
298        transient['display_id'] = display_id
299    if kwargs.get('update') and 'display_id' not in transient:
300        raise TypeError('display_id required for update_display')
301    if transient:
302        kwargs['transient'] = transient
303
304    if not raw:
305        format = InteractiveShell.instance().display_formatter.format
306
307    for obj in objs:
308        if raw:
309            publish_display_data(data=obj, metadata=metadata, **kwargs)
310        else:
311            format_dict, md_dict = format(obj, include=include, exclude=exclude)
312            if not format_dict:
313                # nothing to display (e.g. _ipython_display_ took over)
314                continue
315            if metadata:
316                # kwarg-specified metadata gets precedence
317                _merge(md_dict, metadata)
318            publish_display_data(data=format_dict, metadata=md_dict, **kwargs)
319    if display_id:
320        return DisplayHandle(display_id)
321
322
323# use * for keyword-only display_id arg
324def update_display(obj, **kwargs):
325    """Update an existing display by id
326
327    Parameters
328    ----------
329
330    obj:
331        The object with which to update the display
332    display_id: keyword-only
333        The id of the display to update
334
335    See Also
336    --------
337
338    :func:`display`
339    """
340    sentinel = object()
341    display_id = kwargs.pop('display_id', sentinel)
342    if display_id is sentinel:
343        raise TypeError("update_display() missing 1 required keyword-only argument: 'display_id'")
344    kwargs['update'] = True
345    display(obj, display_id=display_id, **kwargs)
346
347
348class DisplayHandle(object):
349    """A handle on an updatable display
350
351    Call `.update(obj)` to display a new object.
352
353    Call `.display(obj`) to add a new instance of this display,
354    and update existing instances.
355
356    See Also
357    --------
358
359        :func:`display`, :func:`update_display`
360
361    """
362
363    def __init__(self, display_id=None):
364        if display_id is None:
365            display_id = _new_id()
366        self.display_id = display_id
367
368    def __repr__(self):
369        return "<%s display_id=%s>" % (self.__class__.__name__, self.display_id)
370
371    def display(self, obj, **kwargs):
372        """Make a new display with my id, updating existing instances.
373
374        Parameters
375        ----------
376
377        obj:
378            object to display
379        **kwargs:
380            additional keyword arguments passed to display
381        """
382        display(obj, display_id=self.display_id, **kwargs)
383
384    def update(self, obj, **kwargs):
385        """Update existing displays with my id
386
387        Parameters
388        ----------
389
390        obj:
391            object to display
392        **kwargs:
393            additional keyword arguments passed to update_display
394        """
395        update_display(obj, display_id=self.display_id, **kwargs)
396
397
398def display_pretty(*objs, **kwargs):
399    """Display the pretty (default) representation of an object.
400
401    Parameters
402    ----------
403    objs : tuple of objects
404        The Python objects to display, or if raw=True raw text data to
405        display.
406    raw : bool
407        Are the data objects raw data or Python objects that need to be
408        formatted before display? [default: False]
409    metadata : dict (optional)
410        Metadata to be associated with the specific mimetype output.
411    """
412    _display_mimetype('text/plain', objs, **kwargs)
413
414
415def display_html(*objs, **kwargs):
416    """Display the HTML representation of an object.
417
418    Note: If raw=False and the object does not have a HTML
419    representation, no HTML will be shown.
420
421    Parameters
422    ----------
423    objs : tuple of objects
424        The Python objects to display, or if raw=True raw HTML data to
425        display.
426    raw : bool
427        Are the data objects raw data or Python objects that need to be
428        formatted before display? [default: False]
429    metadata : dict (optional)
430        Metadata to be associated with the specific mimetype output.
431    """
432    _display_mimetype('text/html', objs, **kwargs)
433
434
435def display_markdown(*objs, **kwargs):
436    """Displays the Markdown representation of an object.
437
438    Parameters
439    ----------
440    objs : tuple of objects
441        The Python objects to display, or if raw=True raw markdown data to
442        display.
443    raw : bool
444        Are the data objects raw data or Python objects that need to be
445        formatted before display? [default: False]
446    metadata : dict (optional)
447        Metadata to be associated with the specific mimetype output.
448    """
449
450    _display_mimetype('text/markdown', objs, **kwargs)
451
452
453def display_svg(*objs, **kwargs):
454    """Display the SVG representation of an object.
455
456    Parameters
457    ----------
458    objs : tuple of objects
459        The Python objects to display, or if raw=True raw svg data to
460        display.
461    raw : bool
462        Are the data objects raw data or Python objects that need to be
463        formatted before display? [default: False]
464    metadata : dict (optional)
465        Metadata to be associated with the specific mimetype output.
466    """
467    _display_mimetype('image/svg+xml', objs, **kwargs)
468
469
470def display_png(*objs, **kwargs):
471    """Display the PNG representation of an object.
472
473    Parameters
474    ----------
475    objs : tuple of objects
476        The Python objects to display, or if raw=True raw png data to
477        display.
478    raw : bool
479        Are the data objects raw data or Python objects that need to be
480        formatted before display? [default: False]
481    metadata : dict (optional)
482        Metadata to be associated with the specific mimetype output.
483    """
484    _display_mimetype('image/png', objs, **kwargs)
485
486
487def display_jpeg(*objs, **kwargs):
488    """Display the JPEG representation of an object.
489
490    Parameters
491    ----------
492    objs : tuple of objects
493        The Python objects to display, or if raw=True raw JPEG data to
494        display.
495    raw : bool
496        Are the data objects raw data or Python objects that need to be
497        formatted before display? [default: False]
498    metadata : dict (optional)
499        Metadata to be associated with the specific mimetype output.
500    """
501    _display_mimetype('image/jpeg', objs, **kwargs)
502
503
504def display_latex(*objs, **kwargs):
505    """Display the LaTeX representation of an object.
506
507    Parameters
508    ----------
509    objs : tuple of objects
510        The Python objects to display, or if raw=True raw latex data to
511        display.
512    raw : bool
513        Are the data objects raw data or Python objects that need to be
514        formatted before display? [default: False]
515    metadata : dict (optional)
516        Metadata to be associated with the specific mimetype output.
517    """
518    _display_mimetype('text/latex', objs, **kwargs)
519
520
521def display_json(*objs, **kwargs):
522    """Display the JSON representation of an object.
523
524    Note that not many frontends support displaying JSON.
525
526    Parameters
527    ----------
528    objs : tuple of objects
529        The Python objects to display, or if raw=True raw json data to
530        display.
531    raw : bool
532        Are the data objects raw data or Python objects that need to be
533        formatted before display? [default: False]
534    metadata : dict (optional)
535        Metadata to be associated with the specific mimetype output.
536    """
537    _display_mimetype('application/json', objs, **kwargs)
538
539
540def display_javascript(*objs, **kwargs):
541    """Display the Javascript representation of an object.
542
543    Parameters
544    ----------
545    objs : tuple of objects
546        The Python objects to display, or if raw=True raw javascript data to
547        display.
548    raw : bool
549        Are the data objects raw data or Python objects that need to be
550        formatted before display? [default: False]
551    metadata : dict (optional)
552        Metadata to be associated with the specific mimetype output.
553    """
554    _display_mimetype('application/javascript', objs, **kwargs)
555
556
557def display_pdf(*objs, **kwargs):
558    """Display the PDF representation of an object.
559
560    Parameters
561    ----------
562    objs : tuple of objects
563        The Python objects to display, or if raw=True raw javascript data to
564        display.
565    raw : bool
566        Are the data objects raw data or Python objects that need to be
567        formatted before display? [default: False]
568    metadata : dict (optional)
569        Metadata to be associated with the specific mimetype output.
570    """
571    _display_mimetype('application/pdf', objs, **kwargs)
572
573
574#-----------------------------------------------------------------------------
575# Smart classes
576#-----------------------------------------------------------------------------
577
578
579class DisplayObject(object):
580    """An object that wraps data to be displayed."""
581
582    _read_flags = 'r'
583    _show_mem_addr = False
584
585    def __init__(self, data=None, url=None, filename=None):
586        """Create a display object given raw data.
587
588        When this object is returned by an expression or passed to the
589        display function, it will result in the data being displayed
590        in the frontend. The MIME type of the data should match the
591        subclasses used, so the Png subclass should be used for 'image/png'
592        data. If the data is a URL, the data will first be downloaded
593        and then displayed. If
594
595        Parameters
596        ----------
597        data : unicode, str or bytes
598            The raw data or a URL or file to load the data from
599        url : unicode
600            A URL to download the data from.
601        filename : unicode
602            Path to a local file to load the data from.
603        """
604        if data is not None and isinstance(data, string_types):
605            if data.startswith('http') and url is None:
606                url = data
607                filename = None
608                data = None
609            elif _safe_exists(data) and filename is None:
610                url = None
611                filename = data
612                data = None
613
614        self.data = data
615        self.url = url
616        self.filename = None if filename is None else unicode_type(filename)
617
618        self.reload()
619        self._check_data()
620
621    def __repr__(self):
622        if not self._show_mem_addr:
623            cls = self.__class__
624            r = "<%s.%s object>" % (cls.__module__, cls.__name__)
625        else:
626            r = super(DisplayObject, self).__repr__()
627        return r
628
629    def _check_data(self):
630        """Override in subclasses if there's something to check."""
631        pass
632
633    def reload(self):
634        """Reload the raw data from file or URL."""
635        if self.filename is not None:
636            with open(self.filename, self._read_flags) as f:
637                self.data = f.read()
638        elif self.url is not None:
639            try:
640                try:
641                    from urllib.request import urlopen  # Py3
642                except ImportError:
643                    from urllib2 import urlopen
644                response = urlopen(self.url)
645                self.data = response.read()
646                # extract encoding from header, if there is one:
647                encoding = None
648                for sub in response.headers['content-type'].split(';'):
649                    sub = sub.strip()
650                    if sub.startswith('charset'):
651                        encoding = sub.split('=')[-1].strip()
652                        break
653                # decode data, if an encoding was specified
654                if encoding:
655                    self.data = self.data.decode(encoding, 'replace')
656            except:
657                self.data = None
658
659class TextDisplayObject(DisplayObject):
660    """Validate that display data is text"""
661    def _check_data(self):
662        if self.data is not None and not isinstance(self.data, string_types):
663            raise TypeError("%s expects text, not %r" % (self.__class__.__name__, self.data))
664
665class Pretty(TextDisplayObject):
666
667    def _repr_pretty_(self, pp, cycle):
668        return pp.text(self.data)
669
670
671class HTML(TextDisplayObject):
672
673    def _repr_html_(self):
674        return self.data
675
676    def __html__(self):
677        """
678        This method exists to inform other HTML-using modules (e.g. Markupsafe,
679        htmltag, etc) that this object is HTML and does not need things like
680        special characters (<>&) escaped.
681        """
682        return self._repr_html_()
683
684
685class Markdown(TextDisplayObject):
686
687    def _repr_markdown_(self):
688        return self.data
689
690
691class Math(TextDisplayObject):
692
693    def _repr_latex_(self):
694        s = self.data.strip('$')
695        return "$$%s$$" % s
696
697
698class Latex(TextDisplayObject):
699
700    def _repr_latex_(self):
701        return self.data
702
703
704class SVG(DisplayObject):
705
706    _read_flags = 'rb'
707    # wrap data in a property, which extracts the <svg> tag, discarding
708    # document headers
709    _data = None
710
711    @property
712    def data(self):
713        return self._data
714
715    @data.setter
716    def data(self, svg):
717        if svg is None:
718            self._data = None
719            return
720        # parse into dom object
721        from xml.dom import minidom
722        svg = cast_bytes_py2(svg)
723        x = minidom.parseString(svg)
724        # get svg tag (should be 1)
725        found_svg = x.getElementsByTagName('svg')
726        if found_svg:
727            svg = found_svg[0].toxml()
728        else:
729            # fallback on the input, trust the user
730            # but this is probably an error.
731            pass
732        svg = cast_unicode(svg)
733        self._data = svg
734
735    def _repr_svg_(self):
736        return self.data
737
738class ProgressBar(DisplayObject):
739    """Progressbar supports displaying a progressbar like element
740    """
741    def __init__(self, total):
742        """Creates a new progressbar
743
744        Parameters
745        ----------
746        total : int
747            maximum size of the progressbar
748        """
749        self.total = total
750        self._progress = 0
751        self.html_width = '60ex'
752        self.text_width = 60
753        self._display_id = hexlify(os.urandom(8)).decode('ascii')
754
755    def __repr__(self):
756        fraction = self.progress / self.total
757        filled = '=' * int(fraction * self.text_width)
758        rest = ' ' * (self.text_width - len(filled))
759        return '[{}{}] {}/{}'.format(
760            filled, rest,
761            self.progress, self.total,
762        )
763
764    def _repr_html_(self):
765        return "<progress style='width:{}' max='{}' value='{}'></progress>".format(
766            self.html_width, self.total, self.progress)
767
768    def display(self):
769        display(self, display_id=self._display_id)
770
771    def update(self):
772        display(self, display_id=self._display_id, update=True)
773
774    @property
775    def progress(self):
776        return self._progress
777
778    @progress.setter
779    def progress(self, value):
780        self._progress = value
781        self.update()
782
783    def __iter__(self):
784        self.display()
785        self._progress = -1 # First iteration is 0
786        return self
787
788    def __next__(self):
789        """Returns current value and increments display by one."""
790        self.progress += 1
791        if self.progress < self.total:
792            return self.progress
793        else:
794            raise StopIteration()
795
796    def next(self):
797        """Python 2 compatibility"""
798        return self.__next__()
799
800class JSON(DisplayObject):
801    """JSON expects a JSON-able dict or list
802
803    not an already-serialized JSON string.
804
805    Scalar types (None, number, string) are not allowed, only dict or list containers.
806    """
807    # wrap data in a property, which warns about passing already-serialized JSON
808    _data = None
809    def _check_data(self):
810        if self.data is not None and not isinstance(self.data, (dict, list)):
811            raise TypeError("%s expects JSONable dict or list, not %r" % (self.__class__.__name__, self.data))
812
813    @property
814    def data(self):
815        return self._data
816
817    @data.setter
818    def data(self, data):
819        if isinstance(data, string_types):
820            warnings.warn("JSON expects JSONable dict or list, not JSON strings")
821            data = json.loads(data)
822        self._data = data
823
824    def _repr_json_(self):
825        return self.data
826
827css_t = """$("head").append($("<link/>").attr({
828  rel:  "stylesheet",
829  type: "text/css",
830  href: "%s"
831}));
832"""
833
834lib_t1 = """$.getScript("%s", function () {
835"""
836lib_t2 = """});
837"""
838
839class Javascript(TextDisplayObject):
840
841    def __init__(self, data=None, url=None, filename=None, lib=None, css=None):
842        """Create a Javascript display object given raw data.
843
844        When this object is returned by an expression or passed to the
845        display function, it will result in the data being displayed
846        in the frontend. If the data is a URL, the data will first be
847        downloaded and then displayed.
848
849        In the Notebook, the containing element will be available as `element`,
850        and jQuery will be available.  Content appended to `element` will be
851        visible in the output area.
852
853        Parameters
854        ----------
855        data : unicode, str or bytes
856            The Javascript source code or a URL to download it from.
857        url : unicode
858            A URL to download the data from.
859        filename : unicode
860            Path to a local file to load the data from.
861        lib : list or str
862            A sequence of Javascript library URLs to load asynchronously before
863            running the source code. The full URLs of the libraries should
864            be given. A single Javascript library URL can also be given as a
865            string.
866        css: : list or str
867            A sequence of css files to load before running the source code.
868            The full URLs of the css files should be given. A single css URL
869            can also be given as a string.
870        """
871        if isinstance(lib, string_types):
872            lib = [lib]
873        elif lib is None:
874            lib = []
875        if isinstance(css, string_types):
876            css = [css]
877        elif css is None:
878            css = []
879        if not isinstance(lib, (list,tuple)):
880            raise TypeError('expected sequence, got: %r' % lib)
881        if not isinstance(css, (list,tuple)):
882            raise TypeError('expected sequence, got: %r' % css)
883        self.lib = lib
884        self.css = css
885        super(Javascript, self).__init__(data=data, url=url, filename=filename)
886
887    def _repr_javascript_(self):
888        r = ''
889        for c in self.css:
890            r += css_t % c
891        for l in self.lib:
892            r += lib_t1 % l
893        r += self.data
894        r += lib_t2*len(self.lib)
895        return r
896
897# constants for identifying png/jpeg data
898_PNG = b'\x89PNG\r\n\x1a\n'
899_JPEG = b'\xff\xd8'
900
901def _pngxy(data):
902    """read the (width, height) from a PNG header"""
903    ihdr = data.index(b'IHDR')
904    # next 8 bytes are width/height
905    w4h4 = data[ihdr+4:ihdr+12]
906    return struct.unpack('>ii', w4h4)
907
908def _jpegxy(data):
909    """read the (width, height) from a JPEG header"""
910    # adapted from http://www.64lines.com/jpeg-width-height
911
912    idx = 4
913    while True:
914        block_size = struct.unpack('>H', data[idx:idx+2])[0]
915        idx = idx + block_size
916        if data[idx:idx+2] == b'\xFF\xC0':
917            # found Start of Frame
918            iSOF = idx
919            break
920        else:
921            # read another block
922            idx += 2
923
924    h, w = struct.unpack('>HH', data[iSOF+5:iSOF+9])
925    return w, h
926
927class Image(DisplayObject):
928
929    _read_flags = 'rb'
930    _FMT_JPEG = u'jpeg'
931    _FMT_PNG = u'png'
932    _ACCEPTABLE_EMBEDDINGS = [_FMT_JPEG, _FMT_PNG]
933
934    def __init__(self, data=None, url=None, filename=None, format=None,
935                 embed=None, width=None, height=None, retina=False,
936                 unconfined=False, metadata=None):
937        """Create a PNG/JPEG image object given raw data.
938
939        When this object is returned by an input cell or passed to the
940        display function, it will result in the image being displayed
941        in the frontend.
942
943        Parameters
944        ----------
945        data : unicode, str or bytes
946            The raw image data or a URL or filename to load the data from.
947            This always results in embedded image data.
948        url : unicode
949            A URL to download the data from. If you specify `url=`,
950            the image data will not be embedded unless you also specify `embed=True`.
951        filename : unicode
952            Path to a local file to load the data from.
953            Images from a file are always embedded.
954        format : unicode
955            The format of the image data (png/jpeg/jpg). If a filename or URL is given
956            for format will be inferred from the filename extension.
957        embed : bool
958            Should the image data be embedded using a data URI (True) or be
959            loaded using an <img> tag. Set this to True if you want the image
960            to be viewable later with no internet connection in the notebook.
961
962            Default is `True`, unless the keyword argument `url` is set, then
963            default value is `False`.
964
965            Note that QtConsole is not able to display images if `embed` is set to `False`
966        width : int
967            Width in pixels to which to constrain the image in html
968        height : int
969            Height in pixels to which to constrain the image in html
970        retina : bool
971            Automatically set the width and height to half of the measured
972            width and height.
973            This only works for embedded images because it reads the width/height
974            from image data.
975            For non-embedded images, you can just set the desired display width
976            and height directly.
977        unconfined: bool
978            Set unconfined=True to disable max-width confinement of the image.
979        metadata: dict
980            Specify extra metadata to attach to the image.
981
982        Examples
983        --------
984        # embedded image data, works in qtconsole and notebook
985        # when passed positionally, the first arg can be any of raw image data,
986        # a URL, or a filename from which to load image data.
987        # The result is always embedding image data for inline images.
988        Image('http://www.google.fr/images/srpr/logo3w.png')
989        Image('/path/to/image.jpg')
990        Image(b'RAW_PNG_DATA...')
991
992        # Specifying Image(url=...) does not embed the image data,
993        # it only generates `<img>` tag with a link to the source.
994        # This will not work in the qtconsole or offline.
995        Image(url='http://www.google.fr/images/srpr/logo3w.png')
996
997        """
998        if filename is not None:
999            ext = self._find_ext(filename)
1000        elif url is not None:
1001            ext = self._find_ext(url)
1002        elif data is None:
1003            raise ValueError("No image data found. Expecting filename, url, or data.")
1004        elif isinstance(data, string_types) and (
1005            data.startswith('http') or _safe_exists(data)
1006        ):
1007            ext = self._find_ext(data)
1008        else:
1009            ext = None
1010
1011        if format is None:
1012            if ext is not None:
1013                if ext == u'jpg' or ext == u'jpeg':
1014                    format = self._FMT_JPEG
1015                elif ext == u'png':
1016                    format = self._FMT_PNG
1017                else:
1018                    format = ext.lower()
1019            elif isinstance(data, bytes):
1020                # infer image type from image data header,
1021                # only if format has not been specified.
1022                if data[:2] == _JPEG:
1023                    format = self._FMT_JPEG
1024
1025        # failed to detect format, default png
1026        if format is None:
1027            format = 'png'
1028
1029        if format.lower() == 'jpg':
1030            # jpg->jpeg
1031            format = self._FMT_JPEG
1032
1033        self.format = unicode_type(format).lower()
1034        self.embed = embed if embed is not None else (url is None)
1035
1036        if self.embed and self.format not in self._ACCEPTABLE_EMBEDDINGS:
1037            raise ValueError("Cannot embed the '%s' image format" % (self.format))
1038        self.width = width
1039        self.height = height
1040        self.retina = retina
1041        self.unconfined = unconfined
1042        self.metadata = metadata
1043        super(Image, self).__init__(data=data, url=url, filename=filename)
1044
1045        if retina:
1046            self._retina_shape()
1047
1048    def _retina_shape(self):
1049        """load pixel-doubled width and height from image data"""
1050        if not self.embed:
1051            return
1052        if self.format == 'png':
1053            w, h = _pngxy(self.data)
1054        elif self.format == 'jpeg':
1055            w, h = _jpegxy(self.data)
1056        else:
1057            # retina only supports png
1058            return
1059        self.width = w // 2
1060        self.height = h // 2
1061
1062    def reload(self):
1063        """Reload the raw data from file or URL."""
1064        if self.embed:
1065            super(Image,self).reload()
1066            if self.retina:
1067                self._retina_shape()
1068
1069    def _repr_html_(self):
1070        if not self.embed:
1071            width = height = klass = ''
1072            if self.width:
1073                width = ' width="%d"' % self.width
1074            if self.height:
1075                height = ' height="%d"' % self.height
1076            if self.unconfined:
1077                klass = ' class="unconfined"'
1078            return u'<img src="{url}"{width}{height}{klass}/>'.format(
1079                url=self.url,
1080                width=width,
1081                height=height,
1082                klass=klass,
1083            )
1084
1085    def _data_and_metadata(self):
1086        """shortcut for returning metadata with shape information, if defined"""
1087        md = {}
1088        if self.width:
1089            md['width'] = self.width
1090        if self.height:
1091            md['height'] = self.height
1092        if self.unconfined:
1093            md['unconfined'] = self.unconfined
1094        if self.metadata:
1095            md.update(self.metadata)
1096        if md:
1097            return self.data, md
1098        else:
1099            return self.data
1100
1101    def _repr_png_(self):
1102        if self.embed and self.format == u'png':
1103            return self._data_and_metadata()
1104
1105    def _repr_jpeg_(self):
1106        if self.embed and (self.format == u'jpeg' or self.format == u'jpg'):
1107            return self._data_and_metadata()
1108
1109    def _find_ext(self, s):
1110        return unicode_type(s.split('.')[-1].lower())
1111
1112class Video(DisplayObject):
1113
1114    def __init__(self, data=None, url=None, filename=None, embed=False, mimetype=None):
1115        """Create a video object given raw data or an URL.
1116
1117        When this object is returned by an input cell or passed to the
1118        display function, it will result in the video being displayed
1119        in the frontend.
1120
1121        Parameters
1122        ----------
1123        data : unicode, str or bytes
1124            The raw video data or a URL or filename to load the data from.
1125            Raw data will require passing `embed=True`.
1126        url : unicode
1127            A URL for the video. If you specify `url=`,
1128            the image data will not be embedded.
1129        filename : unicode
1130            Path to a local file containing the video.
1131            Will be interpreted as a local URL unless `embed=True`.
1132        embed : bool
1133            Should the video be embedded using a data URI (True) or be
1134            loaded using a <video> tag (False).
1135
1136            Since videos are large, embedding them should be avoided, if possible.
1137            You must confirm embedding as your intention by passing `embed=True`.
1138
1139            Local files can be displayed with URLs without embedding the content, via::
1140
1141                Video('./video.mp4')
1142
1143        mimetype: unicode
1144            Specify the mimetype for embedded videos.
1145            Default will be guessed from file extension, if available.
1146
1147        Examples
1148        --------
1149
1150        Video('https://archive.org/download/Sita_Sings_the_Blues/Sita_Sings_the_Blues_small.mp4')
1151        Video('path/to/video.mp4')
1152        Video('path/to/video.mp4', embed=True)
1153        Video(b'raw-videodata', embed=True)
1154        """
1155        if url is None and isinstance(data, string_types) and data.startswith(('http:', 'https:')):
1156            url = data
1157            data = None
1158        elif os.path.exists(data):
1159            filename = data
1160            data = None
1161
1162        if data and not embed:
1163            msg = ''.join([
1164                "To embed videos, you must pass embed=True ",
1165                "(this may make your notebook files huge)\n",
1166                "Consider passing Video(url='...')",
1167            ])
1168            raise ValueError(msg)
1169
1170        self.mimetype = mimetype
1171        self.embed = embed
1172        super(Video, self).__init__(data=data, url=url, filename=filename)
1173
1174    def _repr_html_(self):
1175        # External URLs and potentially local files are not embedded into the
1176        # notebook output.
1177        if not self.embed:
1178            url = self.url if self.url is not None else self.filename
1179            output = """<video src="{0}" controls>
1180      Your browser does not support the <code>video</code> element.
1181    </video>""".format(url)
1182            return output
1183
1184        # Embedded videos are base64-encoded.
1185        mimetype = self.mimetype
1186        if self.filename is not None:
1187            if not mimetype:
1188                mimetype, _ = mimetypes.guess_type(self.filename)
1189
1190            with open(self.filename, 'rb') as f:
1191                video = f.read()
1192        else:
1193            video = self.data
1194        if isinstance(video, unicode_type):
1195            # unicode input is already b64-encoded
1196            b64_video = video
1197        else:
1198            b64_video = base64_encode(video).decode('ascii').rstrip()
1199
1200        output = """<video controls>
1201 <source src="data:{0};base64,{1}" type="{0}">
1202 Your browser does not support the video tag.
1203 </video>""".format(mimetype, b64_video)
1204        return output
1205
1206    def reload(self):
1207        # TODO
1208        pass
1209
1210    def _repr_png_(self):
1211        # TODO
1212        pass
1213    def _repr_jpeg_(self):
1214        # TODO
1215        pass
1216
1217def clear_output(wait=False):
1218    """Clear the output of the current cell receiving output.
1219
1220    Parameters
1221    ----------
1222    wait : bool [default: false]
1223        Wait to clear the output until new output is available to replace it."""
1224    from IPython.core.interactiveshell import InteractiveShell
1225    if InteractiveShell.initialized():
1226        InteractiveShell.instance().display_pub.clear_output(wait)
1227    else:
1228        print('\033[2K\r', end='')
1229        sys.stdout.flush()
1230        print('\033[2K\r', end='')
1231        sys.stderr.flush()
1232
1233
1234@skip_doctest
1235def set_matplotlib_formats(*formats, **kwargs):
1236    """Select figure formats for the inline backend. Optionally pass quality for JPEG.
1237
1238    For example, this enables PNG and JPEG output with a JPEG quality of 90%::
1239
1240        In [1]: set_matplotlib_formats('png', 'jpeg', quality=90)
1241
1242    To set this in your config files use the following::
1243
1244        c.InlineBackend.figure_formats = {'png', 'jpeg'}
1245        c.InlineBackend.print_figure_kwargs.update({'quality' : 90})
1246
1247    Parameters
1248    ----------
1249    *formats : strs
1250        One or more figure formats to enable: 'png', 'retina', 'jpeg', 'svg', 'pdf'.
1251    **kwargs :
1252        Keyword args will be relayed to ``figure.canvas.print_figure``.
1253    """
1254    from IPython.core.interactiveshell import InteractiveShell
1255    from IPython.core.pylabtools import select_figure_formats
1256    # build kwargs, starting with InlineBackend config
1257    kw = {}
1258    from ipykernel.pylab.config import InlineBackend
1259    cfg = InlineBackend.instance()
1260    kw.update(cfg.print_figure_kwargs)
1261    kw.update(**kwargs)
1262    shell = InteractiveShell.instance()
1263    select_figure_formats(shell, formats, **kw)
1264
1265@skip_doctest
1266def set_matplotlib_close(close=True):
1267    """Set whether the inline backend closes all figures automatically or not.
1268
1269    By default, the inline backend used in the IPython Notebook will close all
1270    matplotlib figures automatically after each cell is run. This means that
1271    plots in different cells won't interfere. Sometimes, you may want to make
1272    a plot in one cell and then refine it in later cells. This can be accomplished
1273    by::
1274
1275        In [1]: set_matplotlib_close(False)
1276
1277    To set this in your config files use the following::
1278
1279        c.InlineBackend.close_figures = False
1280
1281    Parameters
1282    ----------
1283    close : bool
1284        Should all matplotlib figures be automatically closed after each cell is
1285        run?
1286    """
1287    from ipykernel.pylab.config import InlineBackend
1288    cfg = InlineBackend.instance()
1289    cfg.close_figures = close
1290
1291