displaypub.py 5.0 KB

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