##// END OF EJS Templates
Don't eat comm close error silently.
Jonathan Frederic -
Show More
@@ -1,156 +1,157 b''
1 1 """Base class to manage comms"""
2 2
3 3 # Copyright (c) IPython Development Team.
4 4 # Distributed under the terms of the Modified BSD License.
5 5
6 6 import sys
7 7
8 8 from IPython.config import LoggingConfigurable
9 9 from IPython.core.prompts import LazyEvaluate
10 10 from IPython.core.getipython import get_ipython
11 11
12 12 from IPython.utils.importstring import import_item
13 13 from IPython.utils.py3compat import string_types
14 14 from IPython.utils.traitlets import Instance, Unicode, Dict, Any
15 15
16 16 from .comm import Comm
17 17
18 18
19 19 def lazy_keys(dikt):
20 20 """Return lazy-evaluated string representation of a dictionary's keys
21 21
22 22 Key list is only constructed if it will actually be used.
23 23 Used for debug-logging.
24 24 """
25 25 return LazyEvaluate(lambda d: list(d.keys()))
26 26
27 27
28 28 class CommManager(LoggingConfigurable):
29 29 """Manager for Comms in the Kernel"""
30 30
31 31 # If this is instantiated by a non-IPython kernel, shell will be None
32 32 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC',
33 33 allow_none=True)
34 34 kernel = Instance('IPython.kernel.zmq.kernelbase.Kernel')
35 35
36 36 iopub_socket = Any()
37 37 def _iopub_socket_default(self):
38 38 return self.kernel.iopub_socket
39 39 session = Instance('IPython.kernel.zmq.session.Session')
40 40 def _session_default(self):
41 41 return self.kernel.session
42 42
43 43 comms = Dict()
44 44 targets = Dict()
45 45
46 46 # Public APIs
47 47
48 48 def register_target(self, target_name, f):
49 49 """Register a callable f for a given target name
50 50
51 51 f will be called with two arguments when a comm_open message is received with `target`:
52 52
53 53 - the Comm instance
54 54 - the `comm_open` message itself.
55 55
56 56 f can be a Python callable or an import string for one.
57 57 """
58 58 if isinstance(f, string_types):
59 59 f = import_item(f)
60 60
61 61 self.targets[target_name] = f
62 62
63 63 def unregister_target(self, target_name, f):
64 64 """Unregister a callable registered with register_target"""
65 65 return self.targets.pop(target_name);
66 66
67 67 def register_comm(self, comm):
68 68 """Register a new comm"""
69 69 comm_id = comm.comm_id
70 70 comm.shell = self.shell
71 71 comm.kernel = self.kernel
72 72 comm.iopub_socket = self.iopub_socket
73 73 self.comms[comm_id] = comm
74 74 return comm_id
75 75
76 76 def unregister_comm(self, comm):
77 77 """Unregister a comm, and close its counterpart"""
78 78 # unlike get_comm, this should raise a KeyError
79 79 comm = self.comms.pop(comm.comm_id)
80 80
81 81 def get_comm(self, comm_id):
82 82 """Get a comm with a particular id
83 83
84 84 Returns the comm if found, otherwise None.
85 85
86 86 This will not raise an error,
87 87 it will log messages if the comm cannot be found.
88 88 """
89 89 if comm_id not in self.comms:
90 90 self.log.error("No such comm: %s", comm_id)
91 91 self.log.debug("Current comms: %s", lazy_keys(self.comms))
92 92 return
93 93 # call, because we store weakrefs
94 94 comm = self.comms[comm_id]
95 95 return comm
96 96
97 97 # Message handlers
98 98 def comm_open(self, stream, ident, msg):
99 99 """Handler for comm_open messages"""
100 100 content = msg['content']
101 101 comm_id = content['comm_id']
102 102 target_name = content['target_name']
103 103 f = self.targets.get(target_name, None)
104 104 comm = Comm(comm_id=comm_id,
105 105 shell=self.shell,
106 106 kernel=self.kernel,
107 107 iopub_socket=self.iopub_socket,
108 108 primary=False,
109 109 )
110 110 self.register_comm(comm)
111 111 if f is None:
112 112 self.log.error("No such comm target registered: %s", target_name)
113 113 else:
114 114 try:
115 115 f(comm, msg)
116 116 return
117 117 except Exception:
118 118 self.log.error("Exception opening comm with target: %s", target_name, exc_info=True)
119 119
120 120 # Failure.
121 121 try:
122 122 comm.close()
123 123 except:
124 pass # Eat errors, nomnomnom
124 self.log.error("""Could not close comm during `comm_open` failure
125 clean-up. The comm may not have been opened yet.""", exc_info=True)
125 126
126 127 def comm_msg(self, stream, ident, msg):
127 128 """Handler for comm_msg messages"""
128 129 content = msg['content']
129 130 comm_id = content['comm_id']
130 131 comm = self.get_comm(comm_id)
131 132 if comm is None:
132 133 # no such comm
133 134 return
134 135 try:
135 136 comm.handle_msg(msg)
136 137 except Exception:
137 138 self.log.error("Exception in comm_msg for %s", comm_id, exc_info=True)
138 139
139 140 def comm_close(self, stream, ident, msg):
140 141 """Handler for comm_close messages"""
141 142 content = msg['content']
142 143 comm_id = content['comm_id']
143 144 comm = self.get_comm(comm_id)
144 145 if comm is None:
145 146 # no such comm
146 147 self.log.debug("No such comm to close: %s", comm_id)
147 148 return
148 149 del self.comms[comm_id]
149 150
150 151 try:
151 152 comm.handle_close(msg)
152 153 except Exception:
153 154 self.log.error("Exception handling comm_close for %s", comm_id, exc_info=True)
154 155
155 156
156 157 __all__ = ['CommManager']
General Comments 0
You need to be logged in to leave comments. Login now