Format: text/x-python
⬇ Download File (5.0 KB)
   1  """An interface for publishing rich data to frontends.
   2  
   3  There are two components of the display system:
   4  
   5  * Display formatters, which take a Python object and compute the
   6    representation of the object in various formats (text, HTML, SVG, etc.).
   7  * The display publisher that is used to send the representation data to the
   8    various frontends.
   9  
  10  This module defines the logic display publishing. The display publisher uses
  11  the ``display_data`` message type that is defined in the IPython messaging
  12  spec.
  13  """
  14  
  15  # Copyright (c) IPython Development Team.
  16  # Distributed under the terms of the Modified BSD License.
  17  
  18  
  19  import sys
  20  
  21  from traitlets.config.configurable import Configurable
  22  from traitlets import List
  23  
  24  # This used to be defined here - it is imported for backwards compatibility
  25  from .display_functions import publish_display_data
  26  
  27  import typing as t
  28  
  29  # -----------------------------------------------------------------------------
  30  # Main payload class
  31  #-----------------------------------------------------------------------------
  32  
  33  
  34  class DisplayPublisher(Configurable):
  35      """A traited class that publishes display data to frontends.
  36  
  37      Instances of this class are created by the main IPython object and should
  38      be accessed there.
  39      """
  40  
  41      def __init__(self, shell=None, *args, **kwargs):
  42          self.shell = shell
  43          super().__init__(*args, **kwargs)
  44  
  45      def _validate_data(self, data, metadata=None):
  46          """Validate the display data.
  47  
  48          Parameters
  49          ----------
  50          data : dict
  51              The formata data dictionary.
  52          metadata : dict
  53              Any metadata for the data.
  54          """
  55  
  56          if not isinstance(data, dict):
  57              raise TypeError('data must be a dict, got: %r' % data)
  58          if metadata is not None:
  59              if not isinstance(metadata, dict):
  60                  raise TypeError('metadata must be a dict, got: %r' % data)
  61  
  62      # use * to indicate transient, update are keyword-only
  63      def publish(self, data, metadata=None, source=None, *, transient=None, update=False, **kwargs) -> None:
  64          """Publish data and metadata to all frontends.
  65  
  66          See the ``display_data`` message in the messaging documentation for
  67          more details about this message type.
  68  
  69          The following MIME types are currently implemented:
  70  
  71          * text/plain
  72          * text/html
  73          * text/markdown
  74          * text/latex
  75          * application/json
  76          * application/javascript
  77          * image/png
  78          * image/jpeg
  79          * image/svg+xml
  80  
  81          Parameters
  82          ----------
  83          data : dict
  84              A dictionary having keys that are valid MIME types (like
  85              'text/plain' or 'image/svg+xml') and values that are the data for
  86              that MIME type. The data itself must be a JSON'able data
  87              structure. Minimally all data should have the 'text/plain' data,
  88              which can be displayed by all frontends. If more than the plain
  89              text is given, it is up to the frontend to decide which
  90              representation to use.
  91          metadata : dict
  92              A dictionary for metadata related to the data. This can contain
  93              arbitrary key, value pairs that frontends can use to interpret
  94              the data.  Metadata specific to each mime-type can be specified
  95              in the metadata dict with the same mime-type keys as
  96              the data itself.
  97          source : str, deprecated
  98              Unused.
  99          transient : dict, keyword-only
 100              A dictionary for transient data.
 101              Data in this dictionary should not be persisted as part of saving this output.
 102              Examples include 'display_id'.
 103          update : bool, keyword-only, default: False
 104              If True, only update existing outputs with the same display_id,
 105              rather than creating a new output.
 106          """
 107  
 108          handlers: t.Dict = {}
 109          if self.shell is not None:
 110              handlers = getattr(self.shell, "mime_renderers", {})
 111  
 112          for mime, handler in handlers.items():
 113              if mime in data:
 114                  handler(data[mime], metadata.get(mime, None))
 115                  return
 116  
 117          if 'text/plain' in data:
 118              print(data['text/plain'])
 119  
 120      def clear_output(self, wait=False):
 121          """Clear the output of the cell receiving output."""
 122          print('\033[2K\r', end='')
 123          sys.stdout.flush()
 124          print('\033[2K\r', end='')
 125          sys.stderr.flush()
 126  
 127  
 128  class CapturingDisplayPublisher(DisplayPublisher):
 129      """A DisplayPublisher that stores"""
 130  
 131      outputs: List = List()
 132  
 133      def publish(
 134          self, data, metadata=None, source=None, *, transient=None, update=False
 135      ):
 136          self.outputs.append(
 137              {
 138                  "data": data,
 139                  "metadata": metadata,
 140                  "transient": transient,
 141                  "update": update,
 142              }
 143          )
 144  
 145      def clear_output(self, wait=False):
 146          super(CapturingDisplayPublisher, self).clear_output(wait)
 147  
 148          # empty the list, *do not* reassign a new list
 149          self.outputs.clear()
 150