Format: text/x-python
⬇ Download File (3.1 KB)
   1  """Replacements for sys.displayhook that publish over ZMQ."""
   2  
   3  # Copyright (c) IPython Development Team.
   4  # Distributed under the terms of the Modified BSD License.
   5  from __future__ import annotations
   6  
   7  import builtins
   8  import sys
   9  import typing as t
  10  
  11  from IPython.core.displayhook import DisplayHook
  12  from jupyter_client.session import Session, extract_header
  13  from traitlets import Any, Dict, Instance
  14  
  15  from ipykernel.jsonutil import encode_images, json_clean
  16  
  17  
  18  class ZMQDisplayHook:
  19      """A simple displayhook that publishes the object's repr over a ZeroMQ
  20      socket."""
  21  
  22      topic = b"execute_result"
  23  
  24      def __init__(self, session, pub_socket):
  25          """Initialize the hook."""
  26          self.session = session
  27          self.pub_socket = pub_socket
  28          self.parent_header = {}
  29  
  30      def get_execution_count(self):
  31          """This method is replaced in kernelapp"""
  32          return 0
  33  
  34      def __call__(self, obj):
  35          """Handle a hook call."""
  36          if obj is None:
  37              return
  38  
  39          builtins._ = obj  # type:ignore[attr-defined]
  40          sys.stdout.flush()
  41          sys.stderr.flush()
  42          contents = {
  43              "execution_count": self.get_execution_count(),
  44              "data": {"text/plain": repr(obj)},
  45              "metadata": {},
  46          }
  47          self.session.send(
  48              self.pub_socket, "execute_result", contents, parent=self.parent_header, ident=self.topic
  49          )
  50  
  51      def set_parent(self, parent):
  52          """Set the parent header."""
  53          self.parent_header = extract_header(parent)
  54  
  55  
  56  class ZMQShellDisplayHook(DisplayHook):
  57      """A displayhook subclass that publishes data using ZeroMQ. This is intended
  58      to work with an InteractiveShell instance. It sends a dict of different
  59      representations of the object."""
  60  
  61      topic = None
  62  
  63      session = Instance(Session, allow_none=True)
  64      pub_socket = Any(allow_none=True)
  65      parent_header = Dict({})
  66      msg: dict[str, t.Any] | None
  67  
  68      def set_parent(self, parent):
  69          """Set the parent for outbound messages."""
  70          self.parent_header = extract_header(parent)
  71  
  72      def start_displayhook(self):
  73          """Start the display hook."""
  74          if self.session:
  75              self.msg = self.session.msg(
  76                  "execute_result",
  77                  {
  78                      "data": {},
  79                      "metadata": {},
  80                  },
  81                  parent=self.parent_header,
  82              )
  83  
  84      def write_output_prompt(self):
  85          """Write the output prompt."""
  86          if self.msg:
  87              self.msg["content"]["execution_count"] = self.prompt_count
  88  
  89      def write_format_data(self, format_dict, md_dict=None):
  90          """Write format data to the message."""
  91          if self.msg:
  92              self.msg["content"]["data"] = json_clean(encode_images(format_dict))
  93              self.msg["content"]["metadata"] = md_dict
  94  
  95      def finish_displayhook(self):
  96          """Finish up all displayhook activities."""
  97          sys.stdout.flush()
  98          sys.stderr.flush()
  99          if self.msg and self.msg["content"]["data"] and self.session:
 100              self.session.send(self.pub_socket, self.msg, ident=self.topic)
 101          self.msg = None
 102