##// END OF EJS Templates
Initial version of system command out/err forwarding.
Brian Granger -
Show More
@@ -0,0 +1,20 b''
1 import sys
2 from subprocess import Popen, PIPE
3 from IPython.core.interactiveshell import InteractiveShell, InteractiveShellABC
4
5
6 class ZMQInteractiveShell(InteractiveShell):
7 """A subclass of InteractiveShell for ZMQ."""
8
9 def system(self, cmd):
10 cmd = self.var_expand(cmd, depth=2)
11 p = Popen(cmd, shell=True, stdout=PIPE, stderr=PIPE)
12 for line in p.stdout.read().split('\n'):
13 if len(line) > 0:
14 print line
15 for line in p.stderr.read().split('\n'):
16 if len(line) > 0:
17 print line
18 return p.wait()
19
20 InteractiveShellABC.register(ZMQInteractiveShell)
@@ -1,364 +1,364 b''
1 #!/usr/bin/env python
1 #!/usr/bin/env python
2 """A simple interactive kernel that talks to a frontend over 0MQ.
2 """A simple interactive kernel that talks to a frontend over 0MQ.
3
3
4 Things to do:
4 Things to do:
5
5
6 * Implement `set_parent` logic. Right before doing exec, the Kernel should
6 * Implement `set_parent` logic. Right before doing exec, the Kernel should
7 call set_parent on all the PUB objects with the message about to be executed.
7 call set_parent on all the PUB objects with the message about to be executed.
8 * Implement random port and security key logic.
8 * Implement random port and security key logic.
9 * Implement control messages.
9 * Implement control messages.
10 * Implement event loop and poll version.
10 * Implement event loop and poll version.
11 """
11 """
12
12
13 #-----------------------------------------------------------------------------
13 #-----------------------------------------------------------------------------
14 # Imports
14 # Imports
15 #-----------------------------------------------------------------------------
15 #-----------------------------------------------------------------------------
16
16
17 # Standard library imports.
17 # Standard library imports.
18 import __builtin__
18 import __builtin__
19 from code import CommandCompiler
19 from code import CommandCompiler
20 import os
20 import os
21 import sys
21 import sys
22 import time
22 import time
23 import traceback
23 import traceback
24
24
25 # System library imports.
25 # System library imports.
26 import zmq
26 import zmq
27
27
28 # Local imports.
28 # Local imports.
29 from IPython.config.configurable import Configurable
29 from IPython.config.configurable import Configurable
30 from IPython.core.interactiveshell import InteractiveShell, InteractiveShellABC
30 from IPython.zmq.zmqshell import ZMQInteractiveShell
31 from IPython.external.argparse import ArgumentParser
31 from IPython.external.argparse import ArgumentParser
32 from IPython.utils.traitlets import Instance
32 from IPython.utils.traitlets import Instance
33 from IPython.zmq.session import Session, Message
33 from IPython.zmq.session import Session, Message
34 from completer import KernelCompleter
34 from completer import KernelCompleter
35 from iostream import OutStream
35 from iostream import OutStream
36 from displayhook import DisplayHook
36 from displayhook import DisplayHook
37 from exitpoller import ExitPollerUnix, ExitPollerWindows
37 from exitpoller import ExitPollerUnix, ExitPollerWindows
38
38
39 #-----------------------------------------------------------------------------
39 #-----------------------------------------------------------------------------
40 # Main kernel class
40 # Main kernel class
41 #-----------------------------------------------------------------------------
41 #-----------------------------------------------------------------------------
42
42
43 class Kernel(Configurable):
43 class Kernel(Configurable):
44
44
45 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC')
45 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC')
46 session = Instance('IPython.zmq.session.Session')
46 session = Instance('IPython.zmq.session.Session')
47 reply_socket = Instance('zmq.Socket')
47 reply_socket = Instance('zmq.Socket')
48 pub_socket = Instance('zmq.Socket')
48 pub_socket = Instance('zmq.Socket')
49 req_socket = Instance('zmq.Socket')
49 req_socket = Instance('zmq.Socket')
50
50
51 def __init__(self, **kwargs):
51 def __init__(self, **kwargs):
52 super(Kernel, self).__init__(**kwargs)
52 super(Kernel, self).__init__(**kwargs)
53 self.shell = InteractiveShell.instance()
53 self.shell = ZMQInteractiveShell.instance()
54
54
55 # Build dict of handlers for message types
55 # Build dict of handlers for message types
56 msg_types = [ 'execute_request', 'complete_request',
56 msg_types = [ 'execute_request', 'complete_request',
57 'object_info_request' ]
57 'object_info_request' ]
58 self.handlers = {}
58 self.handlers = {}
59 for msg_type in msg_types:
59 for msg_type in msg_types:
60 self.handlers[msg_type] = getattr(self, msg_type)
60 self.handlers[msg_type] = getattr(self, msg_type)
61
61
62 def abort_queue(self):
62 def abort_queue(self):
63 while True:
63 while True:
64 try:
64 try:
65 ident = self.reply_socket.recv(zmq.NOBLOCK)
65 ident = self.reply_socket.recv(zmq.NOBLOCK)
66 except zmq.ZMQError, e:
66 except zmq.ZMQError, e:
67 if e.errno == zmq.EAGAIN:
67 if e.errno == zmq.EAGAIN:
68 break
68 break
69 else:
69 else:
70 assert self.reply_socket.rcvmore(), "Unexpected missing message part."
70 assert self.reply_socket.rcvmore(), "Unexpected missing message part."
71 msg = self.reply_socket.recv_json()
71 msg = self.reply_socket.recv_json()
72 print>>sys.__stdout__, "Aborting:"
72 print>>sys.__stdout__, "Aborting:"
73 print>>sys.__stdout__, Message(msg)
73 print>>sys.__stdout__, Message(msg)
74 msg_type = msg['msg_type']
74 msg_type = msg['msg_type']
75 reply_type = msg_type.split('_')[0] + '_reply'
75 reply_type = msg_type.split('_')[0] + '_reply'
76 reply_msg = self.session.msg(reply_type, {'status' : 'aborted'}, msg)
76 reply_msg = self.session.msg(reply_type, {'status' : 'aborted'}, msg)
77 print>>sys.__stdout__, Message(reply_msg)
77 print>>sys.__stdout__, Message(reply_msg)
78 self.reply_socket.send(ident,zmq.SNDMORE)
78 self.reply_socket.send(ident,zmq.SNDMORE)
79 self.reply_socket.send_json(reply_msg)
79 self.reply_socket.send_json(reply_msg)
80 # We need to wait a bit for requests to come in. This can probably
80 # We need to wait a bit for requests to come in. This can probably
81 # be set shorter for true asynchronous clients.
81 # be set shorter for true asynchronous clients.
82 time.sleep(0.1)
82 time.sleep(0.1)
83
83
84 def execute_request(self, ident, parent):
84 def execute_request(self, ident, parent):
85 try:
85 try:
86 code = parent[u'content'][u'code']
86 code = parent[u'content'][u'code']
87 except:
87 except:
88 print>>sys.__stderr__, "Got bad msg: "
88 print>>sys.__stderr__, "Got bad msg: "
89 print>>sys.__stderr__, Message(parent)
89 print>>sys.__stderr__, Message(parent)
90 return
90 return
91 pyin_msg = self.session.msg(u'pyin',{u'code':code}, parent=parent)
91 pyin_msg = self.session.msg(u'pyin',{u'code':code}, parent=parent)
92 self.pub_socket.send_json(pyin_msg)
92 self.pub_socket.send_json(pyin_msg)
93
93
94 try:
94 try:
95 # Replace raw_input. Note that is not sufficient to replace
95 # Replace raw_input. Note that is not sufficient to replace
96 # raw_input in the user namespace.
96 # raw_input in the user namespace.
97 raw_input = lambda prompt='': self.raw_input(prompt, ident, parent)
97 raw_input = lambda prompt='': self.raw_input(prompt, ident, parent)
98 __builtin__.raw_input = raw_input
98 __builtin__.raw_input = raw_input
99
99
100 # Configure the display hook.
100 # Configure the display hook.
101 sys.displayhook.set_parent(parent)
101 sys.displayhook.set_parent(parent)
102
102
103 self.shell.runlines(code)
103 self.shell.runlines(code)
104 # exec comp_code in self.user_ns, self.user_ns
104 # exec comp_code in self.user_ns, self.user_ns
105 except:
105 except:
106 etype, evalue, tb = sys.exc_info()
106 etype, evalue, tb = sys.exc_info()
107 tb = traceback.format_exception(etype, evalue, tb)
107 tb = traceback.format_exception(etype, evalue, tb)
108 exc_content = {
108 exc_content = {
109 u'status' : u'error',
109 u'status' : u'error',
110 u'traceback' : tb,
110 u'traceback' : tb,
111 u'ename' : unicode(etype.__name__),
111 u'ename' : unicode(etype.__name__),
112 u'evalue' : unicode(evalue)
112 u'evalue' : unicode(evalue)
113 }
113 }
114 exc_msg = self.session.msg(u'pyerr', exc_content, parent)
114 exc_msg = self.session.msg(u'pyerr', exc_content, parent)
115 self.pub_socket.send_json(exc_msg)
115 self.pub_socket.send_json(exc_msg)
116 reply_content = exc_content
116 reply_content = exc_content
117 else:
117 else:
118 reply_content = {'status' : 'ok'}
118 reply_content = {'status' : 'ok'}
119
119
120 # Flush output before sending the reply.
120 # Flush output before sending the reply.
121 sys.stderr.flush()
121 sys.stderr.flush()
122 sys.stdout.flush()
122 sys.stdout.flush()
123
123
124 # Send the reply.
124 # Send the reply.
125 reply_msg = self.session.msg(u'execute_reply', reply_content, parent)
125 reply_msg = self.session.msg(u'execute_reply', reply_content, parent)
126 print>>sys.__stdout__, Message(reply_msg)
126 print>>sys.__stdout__, Message(reply_msg)
127 self.reply_socket.send(ident, zmq.SNDMORE)
127 self.reply_socket.send(ident, zmq.SNDMORE)
128 self.reply_socket.send_json(reply_msg)
128 self.reply_socket.send_json(reply_msg)
129 if reply_msg['content']['status'] == u'error':
129 if reply_msg['content']['status'] == u'error':
130 self.abort_queue()
130 self.abort_queue()
131
131
132 def raw_input(self, prompt, ident, parent):
132 def raw_input(self, prompt, ident, parent):
133 # Flush output before making the request.
133 # Flush output before making the request.
134 sys.stderr.flush()
134 sys.stderr.flush()
135 sys.stdout.flush()
135 sys.stdout.flush()
136
136
137 # Send the input request.
137 # Send the input request.
138 content = dict(prompt=prompt)
138 content = dict(prompt=prompt)
139 msg = self.session.msg(u'input_request', content, parent)
139 msg = self.session.msg(u'input_request', content, parent)
140 self.req_socket.send_json(msg)
140 self.req_socket.send_json(msg)
141
141
142 # Await a response.
142 # Await a response.
143 reply = self.req_socket.recv_json()
143 reply = self.req_socket.recv_json()
144 try:
144 try:
145 value = reply['content']['value']
145 value = reply['content']['value']
146 except:
146 except:
147 print>>sys.__stderr__, "Got bad raw_input reply: "
147 print>>sys.__stderr__, "Got bad raw_input reply: "
148 print>>sys.__stderr__, Message(parent)
148 print>>sys.__stderr__, Message(parent)
149 value = ''
149 value = ''
150 return value
150 return value
151
151
152 def complete_request(self, ident, parent):
152 def complete_request(self, ident, parent):
153 matches = {'matches' : self.complete(parent),
153 matches = {'matches' : self.complete(parent),
154 'status' : 'ok'}
154 'status' : 'ok'}
155 completion_msg = self.session.send(self.reply_socket, 'complete_reply',
155 completion_msg = self.session.send(self.reply_socket, 'complete_reply',
156 matches, parent, ident)
156 matches, parent, ident)
157 print >> sys.__stdout__, completion_msg
157 print >> sys.__stdout__, completion_msg
158
158
159 def complete(self, msg):
159 def complete(self, msg):
160 return self.shell.complete(msg.content.line)
160 return self.shell.complete(msg.content.line)
161
161
162 def object_info_request(self, ident, parent):
162 def object_info_request(self, ident, parent):
163 context = parent['content']['oname'].split('.')
163 context = parent['content']['oname'].split('.')
164 object_info = self.object_info(context)
164 object_info = self.object_info(context)
165 msg = self.session.send(self.reply_socket, 'object_info_reply',
165 msg = self.session.send(self.reply_socket, 'object_info_reply',
166 object_info, parent, ident)
166 object_info, parent, ident)
167 print >> sys.__stdout__, msg
167 print >> sys.__stdout__, msg
168
168
169 def object_info(self, context):
169 def object_info(self, context):
170 symbol, leftover = self.symbol_from_context(context)
170 symbol, leftover = self.symbol_from_context(context)
171 if symbol is not None and not leftover:
171 if symbol is not None and not leftover:
172 doc = getattr(symbol, '__doc__', '')
172 doc = getattr(symbol, '__doc__', '')
173 else:
173 else:
174 doc = ''
174 doc = ''
175 object_info = dict(docstring = doc)
175 object_info = dict(docstring = doc)
176 return object_info
176 return object_info
177
177
178 def symbol_from_context(self, context):
178 def symbol_from_context(self, context):
179 if not context:
179 if not context:
180 return None, context
180 return None, context
181
181
182 base_symbol_string = context[0]
182 base_symbol_string = context[0]
183 symbol = self.shell.user_ns.get(base_symbol_string, None)
183 symbol = self.shell.user_ns.get(base_symbol_string, None)
184 if symbol is None:
184 if symbol is None:
185 symbol = __builtin__.__dict__.get(base_symbol_string, None)
185 symbol = __builtin__.__dict__.get(base_symbol_string, None)
186 if symbol is None:
186 if symbol is None:
187 return None, context
187 return None, context
188
188
189 context = context[1:]
189 context = context[1:]
190 for i, name in enumerate(context):
190 for i, name in enumerate(context):
191 new_symbol = getattr(symbol, name, None)
191 new_symbol = getattr(symbol, name, None)
192 if new_symbol is None:
192 if new_symbol is None:
193 return symbol, context[i:]
193 return symbol, context[i:]
194 else:
194 else:
195 symbol = new_symbol
195 symbol = new_symbol
196
196
197 return symbol, []
197 return symbol, []
198
198
199 def start(self):
199 def start(self):
200 while True:
200 while True:
201 ident = self.reply_socket.recv()
201 ident = self.reply_socket.recv()
202 assert self.reply_socket.rcvmore(), "Missing message part."
202 assert self.reply_socket.rcvmore(), "Missing message part."
203 msg = self.reply_socket.recv_json()
203 msg = self.reply_socket.recv_json()
204 omsg = Message(msg)
204 omsg = Message(msg)
205 print>>sys.__stdout__
205 print>>sys.__stdout__
206 print>>sys.__stdout__, omsg
206 print>>sys.__stdout__, omsg
207 handler = self.handlers.get(omsg.msg_type, None)
207 handler = self.handlers.get(omsg.msg_type, None)
208 if handler is None:
208 if handler is None:
209 print >> sys.__stderr__, "UNKNOWN MESSAGE TYPE:", omsg
209 print >> sys.__stderr__, "UNKNOWN MESSAGE TYPE:", omsg
210 else:
210 else:
211 handler(ident, omsg)
211 handler(ident, omsg)
212
212
213 #-----------------------------------------------------------------------------
213 #-----------------------------------------------------------------------------
214 # Kernel main and launch functions
214 # Kernel main and launch functions
215 #-----------------------------------------------------------------------------
215 #-----------------------------------------------------------------------------
216
216
217 def bind_port(socket, ip, port):
217 def bind_port(socket, ip, port):
218 """ Binds the specified ZMQ socket. If the port is less than zero, a random
218 """ Binds the specified ZMQ socket. If the port is less than zero, a random
219 port is chosen. Returns the port that was bound.
219 port is chosen. Returns the port that was bound.
220 """
220 """
221 connection = 'tcp://%s' % ip
221 connection = 'tcp://%s' % ip
222 if port <= 0:
222 if port <= 0:
223 port = socket.bind_to_random_port(connection)
223 port = socket.bind_to_random_port(connection)
224 else:
224 else:
225 connection += ':%i' % port
225 connection += ':%i' % port
226 socket.bind(connection)
226 socket.bind(connection)
227 return port
227 return port
228
228
229
229
230 def main():
230 def main():
231 """ Main entry point for launching a kernel.
231 """ Main entry point for launching a kernel.
232 """
232 """
233 # Parse command line arguments.
233 # Parse command line arguments.
234 parser = ArgumentParser()
234 parser = ArgumentParser()
235 parser.add_argument('--ip', type=str, default='127.0.0.1',
235 parser.add_argument('--ip', type=str, default='127.0.0.1',
236 help='set the kernel\'s IP address [default: local]')
236 help='set the kernel\'s IP address [default: local]')
237 parser.add_argument('--xrep', type=int, metavar='PORT', default=0,
237 parser.add_argument('--xrep', type=int, metavar='PORT', default=0,
238 help='set the XREP channel port [default: random]')
238 help='set the XREP channel port [default: random]')
239 parser.add_argument('--pub', type=int, metavar='PORT', default=0,
239 parser.add_argument('--pub', type=int, metavar='PORT', default=0,
240 help='set the PUB channel port [default: random]')
240 help='set the PUB channel port [default: random]')
241 parser.add_argument('--req', type=int, metavar='PORT', default=0,
241 parser.add_argument('--req', type=int, metavar='PORT', default=0,
242 help='set the REQ channel port [default: random]')
242 help='set the REQ channel port [default: random]')
243 if sys.platform == 'win32':
243 if sys.platform == 'win32':
244 parser.add_argument('--parent', type=int, metavar='HANDLE',
244 parser.add_argument('--parent', type=int, metavar='HANDLE',
245 default=0, help='kill this process if the process '
245 default=0, help='kill this process if the process '
246 'with HANDLE dies')
246 'with HANDLE dies')
247 else:
247 else:
248 parser.add_argument('--parent', action='store_true',
248 parser.add_argument('--parent', action='store_true',
249 help='kill this process if its parent dies')
249 help='kill this process if its parent dies')
250 namespace = parser.parse_args()
250 namespace = parser.parse_args()
251
251
252 # Create a context, a session, and the kernel sockets.
252 # Create a context, a session, and the kernel sockets.
253 print >>sys.__stdout__, "Starting the kernel..."
253 print >>sys.__stdout__, "Starting the kernel..."
254 context = zmq.Context()
254 context = zmq.Context()
255 session = Session(username=u'kernel')
255 session = Session(username=u'kernel')
256
256
257 reply_socket = context.socket(zmq.XREP)
257 reply_socket = context.socket(zmq.XREP)
258 xrep_port = bind_port(reply_socket, namespace.ip, namespace.xrep)
258 xrep_port = bind_port(reply_socket, namespace.ip, namespace.xrep)
259 print >>sys.__stdout__, "XREP Channel on port", xrep_port
259 print >>sys.__stdout__, "XREP Channel on port", xrep_port
260
260
261 pub_socket = context.socket(zmq.PUB)
261 pub_socket = context.socket(zmq.PUB)
262 pub_port = bind_port(pub_socket, namespace.ip, namespace.pub)
262 pub_port = bind_port(pub_socket, namespace.ip, namespace.pub)
263 print >>sys.__stdout__, "PUB Channel on port", pub_port
263 print >>sys.__stdout__, "PUB Channel on port", pub_port
264
264
265 req_socket = context.socket(zmq.XREQ)
265 req_socket = context.socket(zmq.XREQ)
266 req_port = bind_port(req_socket, namespace.ip, namespace.req)
266 req_port = bind_port(req_socket, namespace.ip, namespace.req)
267 print >>sys.__stdout__, "REQ Channel on port", req_port
267 print >>sys.__stdout__, "REQ Channel on port", req_port
268
268
269 # Redirect input streams and set a display hook.
269 # Redirect input streams and set a display hook.
270 sys.stdout = OutStream(session, pub_socket, u'stdout')
270 sys.stdout = OutStream(session, pub_socket, u'stdout')
271 sys.stderr = OutStream(session, pub_socket, u'stderr')
271 sys.stderr = OutStream(session, pub_socket, u'stderr')
272 sys.displayhook = DisplayHook(session, pub_socket)
272 sys.displayhook = DisplayHook(session, pub_socket)
273
273
274 # Create the kernel.
274 # Create the kernel.
275 kernel = Kernel(
275 kernel = Kernel(
276 session=session, reply_socket=reply_socket,
276 session=session, reply_socket=reply_socket,
277 pub_socket=pub_socket, req_socket=req_socket
277 pub_socket=pub_socket, req_socket=req_socket
278 )
278 )
279
279
280 # Configure this kernel/process to die on parent termination, if necessary.
280 # Configure this kernel/process to die on parent termination, if necessary.
281 if namespace.parent:
281 if namespace.parent:
282 if sys.platform == 'win32':
282 if sys.platform == 'win32':
283 poller = ExitPollerWindows(namespace.parent)
283 poller = ExitPollerWindows(namespace.parent)
284 else:
284 else:
285 poller = ExitPollerUnix()
285 poller = ExitPollerUnix()
286 poller.start()
286 poller.start()
287
287
288 # Start the kernel mainloop.
288 # Start the kernel mainloop.
289 kernel.start()
289 kernel.start()
290
290
291
291
292 def launch_kernel(xrep_port=0, pub_port=0, req_port=0, independent=False):
292 def launch_kernel(xrep_port=0, pub_port=0, req_port=0, independent=False):
293 """ Launches a localhost kernel, binding to the specified ports.
293 """ Launches a localhost kernel, binding to the specified ports.
294
294
295 Parameters
295 Parameters
296 ----------
296 ----------
297 xrep_port : int, optional
297 xrep_port : int, optional
298 The port to use for XREP channel.
298 The port to use for XREP channel.
299
299
300 pub_port : int, optional
300 pub_port : int, optional
301 The port to use for the SUB channel.
301 The port to use for the SUB channel.
302
302
303 req_port : int, optional
303 req_port : int, optional
304 The port to use for the REQ (raw input) channel.
304 The port to use for the REQ (raw input) channel.
305
305
306 independent : bool, optional (default False)
306 independent : bool, optional (default False)
307 If set, the kernel process is guaranteed to survive if this process
307 If set, the kernel process is guaranteed to survive if this process
308 dies. If not set, an effort is made to ensure that the kernel is killed
308 dies. If not set, an effort is made to ensure that the kernel is killed
309 when this process dies. Note that in this case it is still good practice
309 when this process dies. Note that in this case it is still good practice
310 to kill kernels manually before exiting.
310 to kill kernels manually before exiting.
311
311
312 Returns
312 Returns
313 -------
313 -------
314 A tuple of form:
314 A tuple of form:
315 (kernel_process, xrep_port, pub_port, req_port)
315 (kernel_process, xrep_port, pub_port, req_port)
316 where kernel_process is a Popen object and the ports are integers.
316 where kernel_process is a Popen object and the ports are integers.
317 """
317 """
318 import socket
318 import socket
319 from subprocess import Popen
319 from subprocess import Popen
320
320
321 # Find open ports as necessary.
321 # Find open ports as necessary.
322 ports = []
322 ports = []
323 ports_needed = int(xrep_port <= 0) + int(pub_port <= 0) + int(req_port <= 0)
323 ports_needed = int(xrep_port <= 0) + int(pub_port <= 0) + int(req_port <= 0)
324 for i in xrange(ports_needed):
324 for i in xrange(ports_needed):
325 sock = socket.socket()
325 sock = socket.socket()
326 sock.bind(('', 0))
326 sock.bind(('', 0))
327 ports.append(sock)
327 ports.append(sock)
328 for i, sock in enumerate(ports):
328 for i, sock in enumerate(ports):
329 port = sock.getsockname()[1]
329 port = sock.getsockname()[1]
330 sock.close()
330 sock.close()
331 ports[i] = port
331 ports[i] = port
332 if xrep_port <= 0:
332 if xrep_port <= 0:
333 xrep_port = ports.pop(0)
333 xrep_port = ports.pop(0)
334 if pub_port <= 0:
334 if pub_port <= 0:
335 pub_port = ports.pop(0)
335 pub_port = ports.pop(0)
336 if req_port <= 0:
336 if req_port <= 0:
337 req_port = ports.pop(0)
337 req_port = ports.pop(0)
338
338
339 # Spawn a kernel.
339 # Spawn a kernel.
340 command = 'from IPython.zmq.ipkernel import main; main()'
340 command = 'from IPython.zmq.ipkernel import main; main()'
341 arguments = [ sys.executable, '-c', command, '--xrep', str(xrep_port),
341 arguments = [ sys.executable, '-c', command, '--xrep', str(xrep_port),
342 '--pub', str(pub_port), '--req', str(req_port) ]
342 '--pub', str(pub_port), '--req', str(req_port) ]
343 if independent:
343 if independent:
344 if sys.platform == 'win32':
344 if sys.platform == 'win32':
345 proc = Popen(['start', '/b'] + arguments, shell=True)
345 proc = Popen(['start', '/b'] + arguments, shell=True)
346 else:
346 else:
347 proc = Popen(arguments, preexec_fn=lambda: os.setsid())
347 proc = Popen(arguments, preexec_fn=lambda: os.setsid())
348 else:
348 else:
349 if sys.platform == 'win32':
349 if sys.platform == 'win32':
350 from _subprocess import DuplicateHandle, GetCurrentProcess, \
350 from _subprocess import DuplicateHandle, GetCurrentProcess, \
351 DUPLICATE_SAME_ACCESS
351 DUPLICATE_SAME_ACCESS
352 pid = GetCurrentProcess()
352 pid = GetCurrentProcess()
353 handle = DuplicateHandle(pid, pid, pid, 0,
353 handle = DuplicateHandle(pid, pid, pid, 0,
354 True, # Inheritable by new processes.
354 True, # Inheritable by new processes.
355 DUPLICATE_SAME_ACCESS)
355 DUPLICATE_SAME_ACCESS)
356 proc = Popen(arguments + ['--parent', str(int(handle))])
356 proc = Popen(arguments + ['--parent', str(int(handle))])
357 else:
357 else:
358 proc = Popen(arguments + ['--parent'])
358 proc = Popen(arguments + ['--parent'])
359
359
360 return proc, xrep_port, pub_port, req_port
360 return proc, xrep_port, pub_port, req_port
361
361
362
362
363 if __name__ == '__main__':
363 if __name__ == '__main__':
364 main()
364 main()
General Comments 0
You need to be logged in to leave comments. Login now