##// END OF EJS Templates
Removed ANSI coloring for kernel exception hook.
epatters -
Show More
@@ -1,201 +1,199 b''
1 """ Defines helper functions for creating kernel entry points and process
1 """ Defines helper functions for creating kernel entry points and process
2 launchers.
2 launchers.
3 """
3 """
4
4
5 # Standard library imports.
5 # Standard library imports.
6 import os
6 import os
7 import socket
7 import socket
8 from subprocess import Popen
8 from subprocess import Popen
9 import sys
9 import sys
10
10
11 # System library imports.
11 # System library imports.
12 import zmq
12 import zmq
13
13
14 # Local imports.
14 # Local imports.
15 from IPython.core.ultratb import FormattedTB
15 from IPython.core.ultratb import FormattedTB
16 from IPython.external.argparse import ArgumentParser
16 from IPython.external.argparse import ArgumentParser
17 from IPython.utils import io
17 from IPython.utils import io
18 from exitpoller import ExitPollerUnix, ExitPollerWindows
18 from exitpoller import ExitPollerUnix, ExitPollerWindows
19 from displayhook import DisplayHook
19 from displayhook import DisplayHook
20 from iostream import OutStream
20 from iostream import OutStream
21 from session import Session
21 from session import Session
22
22
23
23
24 def bind_port(socket, ip, port):
24 def bind_port(socket, ip, port):
25 """ Binds the specified ZMQ socket. If the port is zero, a random port is
25 """ Binds the specified ZMQ socket. If the port is zero, a random port is
26 chosen. Returns the port that was bound.
26 chosen. Returns the port that was bound.
27 """
27 """
28 connection = 'tcp://%s' % ip
28 connection = 'tcp://%s' % ip
29 if port <= 0:
29 if port <= 0:
30 port = socket.bind_to_random_port(connection)
30 port = socket.bind_to_random_port(connection)
31 else:
31 else:
32 connection += ':%i' % port
32 connection += ':%i' % port
33 socket.bind(connection)
33 socket.bind(connection)
34 return port
34 return port
35
35
36
36
37 def make_argument_parser():
37 def make_argument_parser():
38 """ Creates an ArgumentParser for the generic arguments supported by all
38 """ Creates an ArgumentParser for the generic arguments supported by all
39 kernel entry points.
39 kernel entry points.
40 """
40 """
41 parser = ArgumentParser()
41 parser = ArgumentParser()
42 parser.add_argument('--ip', type=str, default='127.0.0.1',
42 parser.add_argument('--ip', type=str, default='127.0.0.1',
43 help='set the kernel\'s IP address [default: local]')
43 help='set the kernel\'s IP address [default: local]')
44 parser.add_argument('--xrep', type=int, metavar='PORT', default=0,
44 parser.add_argument('--xrep', type=int, metavar='PORT', default=0,
45 help='set the XREP channel port [default: random]')
45 help='set the XREP channel port [default: random]')
46 parser.add_argument('--pub', type=int, metavar='PORT', default=0,
46 parser.add_argument('--pub', type=int, metavar='PORT', default=0,
47 help='set the PUB channel port [default: random]')
47 help='set the PUB channel port [default: random]')
48 parser.add_argument('--req', type=int, metavar='PORT', default=0,
48 parser.add_argument('--req', type=int, metavar='PORT', default=0,
49 help='set the REQ channel port [default: random]')
49 help='set the REQ channel port [default: random]')
50
50
51 if sys.platform == 'win32':
51 if sys.platform == 'win32':
52 parser.add_argument('--parent', type=int, metavar='HANDLE',
52 parser.add_argument('--parent', type=int, metavar='HANDLE',
53 default=0, help='kill this process if the process '
53 default=0, help='kill this process if the process '
54 'with HANDLE dies')
54 'with HANDLE dies')
55 else:
55 else:
56 parser.add_argument('--parent', action='store_true',
56 parser.add_argument('--parent', action='store_true',
57 help='kill this process if its parent dies')
57 help='kill this process if its parent dies')
58
58
59 return parser
59 return parser
60
60
61
61
62 def make_kernel(namespace, kernel_factory,
62 def make_kernel(namespace, kernel_factory,
63 out_stream_factory=None, display_hook_factory=None):
63 out_stream_factory=None, display_hook_factory=None):
64 """ Creates a kernel.
64 """ Creates a kernel.
65 """
65 """
66 # Install minimal exception handling
66 # Install minimal exception handling
67 color_scheme = 'LightBG' if sys.platform == 'darwin' else 'Linux'
67 sys.excepthook = FormattedTB(mode='Verbose', color_scheme='NoColor',
68 sys.excepthook = FormattedTB(
68 ostream=sys.__stdout__)
69 mode='Verbose', color_scheme=color_scheme, ostream=sys.__stdout__
70 )
71
69
72 # Create a context, a session, and the kernel sockets.
70 # Create a context, a session, and the kernel sockets.
73 io.raw_print("Starting the kernel...")
71 io.raw_print("Starting the kernel...")
74 context = zmq.Context()
72 context = zmq.Context()
75 session = Session(username=u'kernel')
73 session = Session(username=u'kernel')
76
74
77 reply_socket = context.socket(zmq.XREP)
75 reply_socket = context.socket(zmq.XREP)
78 xrep_port = bind_port(reply_socket, namespace.ip, namespace.xrep)
76 xrep_port = bind_port(reply_socket, namespace.ip, namespace.xrep)
79 io.raw_print("XREP Channel on port", xrep_port)
77 io.raw_print("XREP Channel on port", xrep_port)
80
78
81 pub_socket = context.socket(zmq.PUB)
79 pub_socket = context.socket(zmq.PUB)
82 pub_port = bind_port(pub_socket, namespace.ip, namespace.pub)
80 pub_port = bind_port(pub_socket, namespace.ip, namespace.pub)
83 io.raw_print("PUB Channel on port", pub_port)
81 io.raw_print("PUB Channel on port", pub_port)
84
82
85 req_socket = context.socket(zmq.XREQ)
83 req_socket = context.socket(zmq.XREQ)
86 req_port = bind_port(req_socket, namespace.ip, namespace.req)
84 req_port = bind_port(req_socket, namespace.ip, namespace.req)
87 io.raw_print("REQ Channel on port", req_port)
85 io.raw_print("REQ Channel on port", req_port)
88
86
89 # Redirect input streams and set a display hook.
87 # Redirect input streams and set a display hook.
90 if out_stream_factory:
88 if out_stream_factory:
91 pass
89 pass
92 sys.stdout = out_stream_factory(session, pub_socket, u'stdout')
90 sys.stdout = out_stream_factory(session, pub_socket, u'stdout')
93 sys.stderr = out_stream_factory(session, pub_socket, u'stderr')
91 sys.stderr = out_stream_factory(session, pub_socket, u'stderr')
94 if display_hook_factory:
92 if display_hook_factory:
95 sys.displayhook = display_hook_factory(session, pub_socket)
93 sys.displayhook = display_hook_factory(session, pub_socket)
96
94
97 # Create the kernel.
95 # Create the kernel.
98 return kernel_factory(session=session, reply_socket=reply_socket,
96 return kernel_factory(session=session, reply_socket=reply_socket,
99 pub_socket=pub_socket, req_socket=req_socket)
97 pub_socket=pub_socket, req_socket=req_socket)
100
98
101
99
102 def start_kernel(namespace, kernel):
100 def start_kernel(namespace, kernel):
103 """ Starts a kernel.
101 """ Starts a kernel.
104 """
102 """
105 # Configure this kernel/process to die on parent termination, if necessary.
103 # Configure this kernel/process to die on parent termination, if necessary.
106 if namespace.parent:
104 if namespace.parent:
107 if sys.platform == 'win32':
105 if sys.platform == 'win32':
108 poller = ExitPollerWindows(namespace.parent)
106 poller = ExitPollerWindows(namespace.parent)
109 else:
107 else:
110 poller = ExitPollerUnix()
108 poller = ExitPollerUnix()
111 poller.start()
109 poller.start()
112
110
113 # Start the kernel mainloop.
111 # Start the kernel mainloop.
114 kernel.start()
112 kernel.start()
115
113
116
114
117 def make_default_main(kernel_factory):
115 def make_default_main(kernel_factory):
118 """ Creates the simplest possible kernel entry point.
116 """ Creates the simplest possible kernel entry point.
119 """
117 """
120 def main():
118 def main():
121 namespace = make_argument_parser().parse_args()
119 namespace = make_argument_parser().parse_args()
122 kernel = make_kernel(namespace, kernel_factory, OutStream, DisplayHook)
120 kernel = make_kernel(namespace, kernel_factory, OutStream, DisplayHook)
123 start_kernel(namespace, kernel)
121 start_kernel(namespace, kernel)
124 return main
122 return main
125
123
126
124
127 def base_launch_kernel(code, xrep_port=0, pub_port=0, req_port=0,
125 def base_launch_kernel(code, xrep_port=0, pub_port=0, req_port=0,
128 independent=False, extra_arguments=[]):
126 independent=False, extra_arguments=[]):
129 """ Launches a localhost kernel, binding to the specified ports.
127 """ Launches a localhost kernel, binding to the specified ports.
130
128
131 Parameters
129 Parameters
132 ----------
130 ----------
133 code : str,
131 code : str,
134 A string of Python code that imports and executes a kernel entry point.
132 A string of Python code that imports and executes a kernel entry point.
135
133
136 xrep_port : int, optional
134 xrep_port : int, optional
137 The port to use for XREP channel.
135 The port to use for XREP channel.
138
136
139 pub_port : int, optional
137 pub_port : int, optional
140 The port to use for the SUB channel.
138 The port to use for the SUB channel.
141
139
142 req_port : int, optional
140 req_port : int, optional
143 The port to use for the REQ (raw input) channel.
141 The port to use for the REQ (raw input) channel.
144
142
145 independent : bool, optional (default False)
143 independent : bool, optional (default False)
146 If set, the kernel process is guaranteed to survive if this process
144 If set, the kernel process is guaranteed to survive if this process
147 dies. If not set, an effort is made to ensure that the kernel is killed
145 dies. If not set, an effort is made to ensure that the kernel is killed
148 when this process dies. Note that in this case it is still good practice
146 when this process dies. Note that in this case it is still good practice
149 to kill kernels manually before exiting.
147 to kill kernels manually before exiting.
150
148
151 extra_arguments = list, optional
149 extra_arguments = list, optional
152 A list of extra arguments to pass when executing the launch code.
150 A list of extra arguments to pass when executing the launch code.
153
151
154 Returns
152 Returns
155 -------
153 -------
156 A tuple of form:
154 A tuple of form:
157 (kernel_process, xrep_port, pub_port, req_port)
155 (kernel_process, xrep_port, pub_port, req_port)
158 where kernel_process is a Popen object and the ports are integers.
156 where kernel_process is a Popen object and the ports are integers.
159 """
157 """
160 # Find open ports as necessary.
158 # Find open ports as necessary.
161 ports = []
159 ports = []
162 ports_needed = int(xrep_port <= 0) + int(pub_port <= 0) + int(req_port <= 0)
160 ports_needed = int(xrep_port <= 0) + int(pub_port <= 0) + int(req_port <= 0)
163 for i in xrange(ports_needed):
161 for i in xrange(ports_needed):
164 sock = socket.socket()
162 sock = socket.socket()
165 sock.bind(('', 0))
163 sock.bind(('', 0))
166 ports.append(sock)
164 ports.append(sock)
167 for i, sock in enumerate(ports):
165 for i, sock in enumerate(ports):
168 port = sock.getsockname()[1]
166 port = sock.getsockname()[1]
169 sock.close()
167 sock.close()
170 ports[i] = port
168 ports[i] = port
171 if xrep_port <= 0:
169 if xrep_port <= 0:
172 xrep_port = ports.pop(0)
170 xrep_port = ports.pop(0)
173 if pub_port <= 0:
171 if pub_port <= 0:
174 pub_port = ports.pop(0)
172 pub_port = ports.pop(0)
175 if req_port <= 0:
173 if req_port <= 0:
176 req_port = ports.pop(0)
174 req_port = ports.pop(0)
177
175
178 # Build the kernel launch command.
176 # Build the kernel launch command.
179 arguments = [ sys.executable, '-c', code, '--xrep', str(xrep_port),
177 arguments = [ sys.executable, '-c', code, '--xrep', str(xrep_port),
180 '--pub', str(pub_port), '--req', str(req_port) ]
178 '--pub', str(pub_port), '--req', str(req_port) ]
181 arguments.extend(extra_arguments)
179 arguments.extend(extra_arguments)
182
180
183 # Spawn a kernel.
181 # Spawn a kernel.
184 if independent:
182 if independent:
185 if sys.platform == 'win32':
183 if sys.platform == 'win32':
186 proc = Popen(['start', '/b'] + arguments, shell=True)
184 proc = Popen(['start', '/b'] + arguments, shell=True)
187 else:
185 else:
188 proc = Popen(arguments, preexec_fn=lambda: os.setsid())
186 proc = Popen(arguments, preexec_fn=lambda: os.setsid())
189 else:
187 else:
190 if sys.platform == 'win32':
188 if sys.platform == 'win32':
191 from _subprocess import DuplicateHandle, GetCurrentProcess, \
189 from _subprocess import DuplicateHandle, GetCurrentProcess, \
192 DUPLICATE_SAME_ACCESS
190 DUPLICATE_SAME_ACCESS
193 pid = GetCurrentProcess()
191 pid = GetCurrentProcess()
194 handle = DuplicateHandle(pid, pid, pid, 0,
192 handle = DuplicateHandle(pid, pid, pid, 0,
195 True, # Inheritable by new processes.
193 True, # Inheritable by new processes.
196 DUPLICATE_SAME_ACCESS)
194 DUPLICATE_SAME_ACCESS)
197 proc = Popen(arguments + ['--parent', str(int(handle))])
195 proc = Popen(arguments + ['--parent', str(int(handle))])
198 else:
196 else:
199 proc = Popen(arguments + ['--parent'])
197 proc = Popen(arguments + ['--parent'])
200
198
201 return proc, xrep_port, pub_port, req_port
199 return proc, xrep_port, pub_port, req_port
General Comments 0
You need to be logged in to leave comments. Login now