##// END OF EJS Templates
Refactored htmlnotebook session and kernel manager....
Brian E. Granger -
Show More
@@ -0,0 +1,75 b''
1 """A manager for session and channels for a single kernel."""
2
3 import zmq
4 from zmq.eventloop.zmqstream import ZMQStream
5
6 from IPython.utils.traitlets import Instance, Dict, CBytes, Bool
7 from IPython.zmq.session import SessionFactory
8
9
10 class SessionManagerRunningError(Exception):
11 pass
12
13
14 class SessionManager(SessionFactory):
15 """Manages a session for a kernel.
16
17 The object manages a variety of things for a connection session to
18 a running kernel:
19
20 * The set of channels or connected ZMQ streams to the kernel.
21 * An IPython.zmq.session.Session object that manages send/recv logic
22 for those channels.
23 """
24
25 kernel_manager = Instance('IPython.frontend.html.notebook.kernelmanager.KernelManager')
26 kernel_id = CBytes(b'')
27 _session_streams = Dict()
28 _running = Bool(False)
29
30 def __init__(self, **kwargs):
31 kernel_id = kwargs.pop('kernel_id')
32 super(SessionManager, self).__init__(**kwargs)
33 self.kernel_id = kernel_id
34 self.start()
35
36 def __del__(self):
37 self.stop()
38
39 def start(self):
40 if not self._running:
41 ports = self.kernel_manager.get_kernel_ports(self.kernel_id)
42 iopub_stream = self.create_connected_stream(ports['iopub_port'], zmq.SUB)
43 iopub_stream.socket.setsockopt(zmq.SUBSCRIBE, b'')
44 shell_stream = self.create_connected_stream(ports['shell_port'], zmq.XREQ)
45 self._session_streams = dict(
46 iopub_stream = iopub_stream,
47 shell_stream = shell_stream
48 )
49 self._running = True
50 else:
51 raise SessionManagerRunningError(
52 'Session manager is already running, call stop() before start()'
53 )
54
55 def stop(self):
56 if self._running:
57 for name, stream in self._session_streams.items():
58 stream.close()
59 self._session_streams = {}
60 self._running = False
61
62 def create_connected_stream(self, port, socket_type):
63 sock = self.context.socket(socket_type)
64 addr = "tcp://%s:%i" % (self.kernel_manager.get_kernel_ip(self.kernel_id), port)
65 self.log.info("Connecting to: %s, %r" % (addr, socket_type))
66 sock.connect(addr)
67 return ZMQStream(sock)
68
69 def get_iopub_stream(self):
70 return self._session_streams['iopub_stream']
71
72 def get_shell_stream(self):
73 return self._session_streams['shell_stream']
74
75
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
1 NO CONTENT: new file 100644, binary diff hidden
NO CONTENT: new file 100644, binary diff hidden
@@ -0,0 +1,38 b''
1
2 from unittest import TestCase
3
4 from IPython.frontend.html.notebook.kernelmanager import KernelManager
5 from IPython.frontend.html.notebook.sessionmanager import SessionManagerRunningError
6
7 class TestKernelManager(TestCase):
8
9 def test_km_lifecycle(self):
10 km = KernelManager()
11 kid = km.start_kernel()
12 self.assert_(kid in km)
13 self.assertEquals(len(km),1)
14 km.kill_kernel(kid)
15 self.assert_(not kid in km)
16
17 kid = km.start_kernel()
18 self.assertEquals('127.0.0.1',km.get_kernel_ip(kid))
19 port_dict = km.get_kernel_ports(kid)
20 self.assert_('stdin_port' in port_dict)
21 self.assert_('iopub_port' in port_dict)
22 self.assert_('shell_port' in port_dict)
23 self.assert_('hb_port' in port_dict)
24 km.get_kernel_process(kid)
25
26 def test_session_manager(self):
27 km = KernelManager()
28 kid = km.start_kernel()
29 sm = km.create_session_manager(kid)
30 self.assert_(sm._running)
31 sm.stop()
32 self.assert_(not sm._running)
33 sm.start()
34 self.assertRaises(SessionManagerRunningError, sm.start)
35 sm.get_iopub_stream()
36 sm.get_shell_stream()
37 sm.session
38
@@ -1,28 +1,41 b''
1 """A kernel manager for multiple kernels."""
2
3 import logging
1 import signal
4 import signal
2 import sys
5 import sys
3 import uuid
6 import uuid
4
7
8 import zmq
9
10 from IPython.config.configurable import Configurable
5 from IPython.zmq.ipkernel import launch_kernel
11 from IPython.zmq.ipkernel import launch_kernel
6 from session import SessionManager
12 from IPython.utils.traitlets import Instance, Dict, Unicode
7
13
8
14
9 class DuplicateKernelError(Exception):
15 class DuplicateKernelError(Exception):
10 pass
16 pass
11
17
12
18
13 class KernelManager(object):
19 class KernelManager(Configurable):
20 """A class for managing multiple kernels."""
21
22 context = Instance('zmq.Context')
23 def _context_default(self):
24 return zmq.Context.instance()
14
25
15 ip = '127.0.0.1'
26 logname = Unicode('')
27 def _logname_changed(self, name, old, new):
28 self.log = logging.getLogger(new)
16
29
17 def __init__(self, context):
30 _kernels = Dict()
18 self.context = context
19 self._kernels = {}
20
31
21 @property
32 @property
22 def kernel_ids(self):
33 def kernel_ids(self):
34 """Return a list of the kernel ids of the active kernels."""
23 return self._kernels.keys()
35 return self._kernels.keys()
24
36
25 def __len__(self):
37 def __len__(self):
38 """Return the number of running kernels."""
26 return len(self.kernel_ids)
39 return len(self.kernel_ids)
27
40
28 def __contains__(self, kernel_id):
41 def __contains__(self, kernel_id):
@@ -31,21 +44,31 b' class KernelManager(object):'
31 else:
44 else:
32 return False
45 return False
33
46
34 def start_kernel(self):
47 def start_kernel(self, **kwargs):
48 """Start a new kernel."""
35 kernel_id = str(uuid.uuid4())
49 kernel_id = str(uuid.uuid4())
36 (process, shell_port, iopub_port, stdin_port, hb_port) = launch_kernel(pylab='inline')
50 (process, shell_port, iopub_port, stdin_port, hb_port) = launch_kernel(**kwargs)
51 # Store the information for contacting the kernel. This assumes the kernel is
52 # running on localhost.
37 d = dict(
53 d = dict(
38 process = process,
54 process = process,
39 stdin_port = stdin_port,
55 stdin_port = stdin_port,
40 iopub_port = iopub_port,
56 iopub_port = iopub_port,
41 shell_port = shell_port,
57 shell_port = shell_port,
42 hb_port = hb_port,
58 hb_port = hb_port,
43 session_manager = SessionManager(self, kernel_id, self.context)
59 ip = '127.0.0.1'
44 )
60 )
45 self._kernels[kernel_id] = d
61 self._kernels[kernel_id] = d
46 return kernel_id
62 return kernel_id
47
63
48 def kill_kernel(self, kernel_id):
64 def kill_kernel(self, kernel_id):
65 """Kill a kernel by its kernel uuid.
66
67 Parameters
68 ==========
69 kernel_id : uuid
70 The id of the kernel to kill.
71 """
49 kernel_process = self.get_kernel_process(kernel_id)
72 kernel_process = self.get_kernel_process(kernel_id)
50 if kernel_process is not None:
73 if kernel_process is not None:
51 # Attempt to kill the kernel.
74 # Attempt to kill the kernel.
@@ -59,6 +82,13 b' class KernelManager(object):'
59 del self._kernels[kernel_id]
82 del self._kernels[kernel_id]
60
83
61 def interrupt_kernel(self, kernel_id):
84 def interrupt_kernel(self, kernel_id):
85 """Interrupt (SIGINT) the kernel by its uuid.
86
87 Parameters
88 ==========
89 kernel_id : uuid
90 The id of the kernel to interrupt.
91 """
62 kernel_process = self.get_kernel_process(kernel_id)
92 kernel_process = self.get_kernel_process(kernel_id)
63 if kernel_process is not None:
93 if kernel_process is not None:
64 if sys.platform == 'win32':
94 if sys.platform == 'win32':
@@ -68,14 +98,28 b' class KernelManager(object):'
68 kernel_process.send_signal(signal.SIGINT)
98 kernel_process.send_signal(signal.SIGINT)
69
99
70 def signal_kernel(self, kernel_id, signum):
100 def signal_kernel(self, kernel_id, signum):
71 """ Sends a signal to the kernel. Note that since only SIGTERM is
101 """ Sends a signal to the kernel by its uuid.
72 supported on Windows, this function is only useful on Unix systems.
102
103 Note that since only SIGTERM is supported on Windows, this function
104 is only useful on Unix systems.
105
106 Parameters
107 ==========
108 kernel_id : uuid
109 The id of the kernel to signal.
73 """
110 """
74 kernel_process = self.get_kernel_process(kernel_id)
111 kernel_process = self.get_kernel_process(kernel_id)
75 if kernel_process is not None:
112 if kernel_process is not None:
76 kernel_process.send_signal(signum)
113 kernel_process.send_signal(signum)
77
114
78 def get_kernel_process(self, kernel_id):
115 def get_kernel_process(self, kernel_id):
116 """Get the process object for a kernel by its uuid.
117
118 Parameters
119 ==========
120 kernel_id : uuid
121 The id of the kernel.
122 """
79 d = self._kernels.get(kernel_id)
123 d = self._kernels.get(kernel_id)
80 if d is not None:
124 if d is not None:
81 return d['process']
125 return d['process']
@@ -83,20 +127,53 b' class KernelManager(object):'
83 raise KeyError("Kernel with id not found: %s" % kernel_id)
127 raise KeyError("Kernel with id not found: %s" % kernel_id)
84
128
85 def get_kernel_ports(self, kernel_id):
129 def get_kernel_ports(self, kernel_id):
130 """Return a dictionary of ports for a kernel.
131
132 Parameters
133 ==========
134 kernel_id : uuid
135 The id of the kernel.
136
137 Returns
138 =======
139 port_dict : dict
140 A dict of key, value pairs where the keys are the names
141 (stdin_port,iopub_port,shell_port) and the values are the
142 integer port numbers for those channels.
143 """
86 d = self._kernels.get(kernel_id)
144 d = self._kernels.get(kernel_id)
87 if d is not None:
145 if d is not None:
88 dcopy = d.copy()
146 dcopy = d.copy()
89 dcopy.pop('process')
147 dcopy.pop('process')
148 dcopy.pop('ip')
90 return dcopy
149 return dcopy
91 else:
150 else:
92 raise KeyError("Kernel with id not found: %s" % kernel_id)
151 raise KeyError("Kernel with id not found: %s" % kernel_id)
93
152
94 def get_session_manager(self, kernel_id):
153 def get_kernel_ip(self, kernel_id):
154 """Return ip address for a kernel.
155
156 Parameters
157 ==========
158 kernel_id : uuid
159 The id of the kernel.
160
161 Returns
162 =======
163 ip : str
164 The ip address of the kernel.
165 """
95 d = self._kernels.get(kernel_id)
166 d = self._kernels.get(kernel_id)
96 if d is not None:
167 if d is not None:
97 return d['session_manager']
168 return d['ip']
98 else:
169 else:
99 raise KeyError("Kernel with id not found: %s" % kernel_id)
170 raise KeyError("Kernel with id not found: %s" % kernel_id)
100
171
101
172 def create_session_manager(self, kernel_id):
173 """Create a new session manager for a kernel by its uuid."""
174 from sessionmanager import SessionManager
175 return SessionManager(
176 kernel_id=kernel_id, kernel_manager=self,
177 config=self.config, context=self.context, logname=self.logname
178 )
102
179
1 NO CONTENT: file was removed
NO CONTENT: file was removed
General Comments 0
You need to be logged in to leave comments. Login now