33# Copyright (c) IPython Development Team.
44# Distributed under the terms of the Modified BSD License.
55
6- import uuid
7-
8- from traitlets import Any , Bool , Bytes , Dict , Instance , Unicode , default
9- from traitlets .config import LoggingConfigurable
6+ from comm .base_comm import BaseComm
107
118from ipykernel .jsonutil import json_clean
129from ipykernel .kernelbase import Kernel
1310
1411
15- class Comm (LoggingConfigurable ):
12+ class Comm (BaseComm ):
1613 """Class for communicating between a Frontend and a Kernel"""
1714
18- kernel = Instance ("ipykernel.kernelbase.Kernel" , allow_none = True )
19-
20- @default ("kernel" )
21- def _default_kernel (self ):
22- if Kernel .initialized ():
23- return Kernel .instance ()
24-
25- comm_id = Unicode ()
26-
27- @default ("comm_id" )
28- def _default_comm_id (self ):
29- return uuid .uuid4 ().hex
30-
31- primary = Bool (True , help = "Am I the primary or secondary Comm?" )
32-
33- target_name = Unicode ("comm" )
34- target_module = Unicode (
35- None ,
36- allow_none = True ,
37- help = """requirejs module from
38- which to load comm target.""" ,
39- )
40-
41- topic = Bytes ()
42-
43- @default ("topic" )
44- def _default_topic (self ):
45- return ("comm-%s" % self .comm_id ).encode ("ascii" )
46-
47- _open_data = Dict (help = "data dict, if any, to be included in comm_open" )
48- _close_data = Dict (help = "data dict, if any, to be included in comm_close" )
49-
50- _msg_callback = Any ()
51- _close_callback = Any ()
15+ def __init__ (self , * args , ** kwargs ):
16+ self .kernel = None
5217
53- _closed = Bool ( True )
18+ super (). __init__ ( * args , ** kwargs )
5419
55- def __init__ (self , target_name = "" , data = None , metadata = None , buffers = None , ** kwargs ):
56- if target_name :
57- kwargs ["target_name" ] = target_name
58- super ().__init__ (** kwargs )
59- if self .kernel :
60- if self .primary :
61- # I am primary, open my peer.
62- self .open (data = data , metadata = metadata , buffers = buffers )
63- else :
64- self ._closed = False
65-
66- def _publish_msg (self , msg_type , data = None , metadata = None , buffers = None , ** keys ):
20+ def publish_msg (self , msg_type , data = None , metadata = None , buffers = None , ** keys ):
6721 """Helper for sending a comm message on IOPub"""
22+ if not Kernel .initialized ():
23+ return
24+
6825 data = {} if data is None else data
6926 metadata = {} if metadata is None else metadata
7027 content = json_clean (dict (data = data , comm_id = self .comm_id , ** keys ))
28+
29+ if self .kernel is None :
30+ self .kernel = Kernel .instance ()
31+
7132 self .kernel .session .send (
7233 self .kernel .iopub_socket ,
7334 msg_type ,
@@ -78,107 +39,5 @@ def _publish_msg(self, msg_type, data=None, metadata=None, buffers=None, **keys)
7839 buffers = buffers ,
7940 )
8041
81- def __del__ (self ):
82- """trigger close on gc"""
83- self .close (deleting = True )
84-
85- # publishing messages
86-
87- def open (self , data = None , metadata = None , buffers = None ):
88- """Open the frontend-side version of this comm"""
89- if data is None :
90- data = self ._open_data
91- comm_manager = getattr (self .kernel , "comm_manager" , None )
92- if comm_manager is None :
93- raise RuntimeError (
94- "Comms cannot be opened without a kernel "
95- "and a comm_manager attached to that kernel."
96- )
97-
98- comm_manager .register_comm (self )
99- try :
100- self ._publish_msg (
101- "comm_open" ,
102- data = data ,
103- metadata = metadata ,
104- buffers = buffers ,
105- target_name = self .target_name ,
106- target_module = self .target_module ,
107- )
108- self ._closed = False
109- except Exception :
110- comm_manager .unregister_comm (self )
111- raise
112-
113- def close (self , data = None , metadata = None , buffers = None , deleting = False ):
114- """Close the frontend-side version of this comm"""
115- if self ._closed :
116- # only close once
117- return
118- self ._closed = True
119- # nothing to send if we have no kernel
120- # can be None during interpreter cleanup
121- if not self .kernel :
122- return
123- if data is None :
124- data = self ._close_data
125- self ._publish_msg (
126- "comm_close" ,
127- data = data ,
128- metadata = metadata ,
129- buffers = buffers ,
130- )
131- if not deleting :
132- # If deleting, the comm can't be registered
133- self .kernel .comm_manager .unregister_comm (self )
134-
135- def send (self , data = None , metadata = None , buffers = None ):
136- """Send a message to the frontend-side version of this comm"""
137- self ._publish_msg (
138- "comm_msg" ,
139- data = data ,
140- metadata = metadata ,
141- buffers = buffers ,
142- )
143-
144- # registering callbacks
145-
146- def on_close (self , callback ):
147- """Register a callback for comm_close
148-
149- Will be called with the `data` of the close message.
150-
151- Call `on_close(None)` to disable an existing callback.
152- """
153- self ._close_callback = callback
154-
155- def on_msg (self , callback ):
156- """Register a callback for comm_msg
157-
158- Will be called with the `data` of any comm_msg messages.
159-
160- Call `on_msg(None)` to disable an existing callback.
161- """
162- self ._msg_callback = callback
163-
164- # handling of incoming messages
165-
166- def handle_close (self , msg ):
167- """Handle a comm_close message"""
168- self .log .debug ("handle_close[%s](%s)" , self .comm_id , msg )
169- if self ._close_callback :
170- self ._close_callback (msg )
171-
172- def handle_msg (self , msg ):
173- """Handle a comm_msg message"""
174- self .log .debug ("handle_msg[%s](%s)" , self .comm_id , msg )
175- if self ._msg_callback :
176- shell = self .kernel .shell
177- if shell :
178- shell .events .trigger ("pre_execute" )
179- self ._msg_callback (msg )
180- if shell :
181- shell .events .trigger ("post_execute" )
182-
18342
18443__all__ = ["Comm" ]
0 commit comments