##// END OF EJS Templates
split base_launch_kernel into make_kernel_cmd / launch_kernel
MinRK -
Show More
@@ -2,8 +2,7 b''
2 2 launchers.
3 3 """
4 4
5 # Standard library imports.
6 import atexit
5 # Standard library imports
7 6 import json
8 7 import os
9 8 import socket
@@ -17,7 +16,7 b' import tempfile'
17 16 from IPython.utils.localinterfaces import LOCALHOST
18 17 from IPython.utils.py3compat import bytes_to_str
19 18
20 # Local imports.
19 # Local imports
21 20 from parentpoller import ParentPollerWindows
22 21
23 22 def write_connection_file(fname=None, shell_port=0, iopub_port=0, stdin_port=0, hb_port=0,
@@ -98,9 +97,7 b' def write_connection_file(fname=None, shell_port=0, iopub_port=0, stdin_port=0, '
98 97 return fname, cfg
99 98
100 99
101 def base_launch_kernel(code, fname, stdin=None, stdout=None, stderr=None,
102 executable=None, independent=False, extra_arguments=[],
103 cwd=None):
100 def make_kernel_cmd(code, executable=None, extra_arguments=[], **kw):
104 101 """ Launches a localhost kernel, binding to the specified ports.
105 102
106 103 Parameters
@@ -108,17 +105,54 b' def base_launch_kernel(code, fname, stdin=None, stdout=None, stderr=None,'
108 105 code : str,
109 106 A string of Python code that imports and executes a kernel entry point.
110 107
111 stdin, stdout, stderr : optional (default None)
112 Standards streams, as defined in subprocess.Popen.
108 executable : str, optional (default sys.executable)
109 The Python executable to use for the kernel process.
110
111 extra_arguments : list, optional
112 A list of extra arguments to pass when executing the launch code.
113
114 Returns
115 -------
116
117 A Popen command list
118 """
119
120 # Build the kernel launch command.
121 if executable is None:
122 executable = sys.executable
123 arguments = [ executable, '-c', code, '-f', '{connection_file}' ]
124 arguments.extend(extra_arguments)
113 125
114 fname : unicode, optional
115 The JSON connector file, containing ip/port/hmac key information.
126 # Spawn a kernel.
127 if sys.platform == 'win32':
116 128
117 key : str, optional
118 The Session key used for HMAC authentication.
129 # If the kernel is running on pythonw and stdout/stderr are not been
130 # re-directed, it will crash when more than 4KB of data is written to
131 # stdout or stderr. This is a bug that has been with Python for a very
132 # long time; see http://bugs.python.org/issue706263.
133 # A cleaner solution to this problem would be to pass os.devnull to
134 # Popen directly. Unfortunately, that does not work.
135 if executable.endswith('pythonw.exe'):
136 arguments.append('--no-stdout')
137 arguments.append('--no-stderr')
119 138
120 executable : str, optional (default sys.executable)
121 The Python executable to use for the kernel process.
139 return arguments
140
141
142 def launch_kernel(cmd, stdin=None, stdout=None, stderr=None,
143 independent=False,
144 cwd=None, ipython_kernel=True,
145 **kw
146 ):
147 """ Launches a localhost kernel, binding to the specified ports.
148
149 Parameters
150 ----------
151 cmd : Popen list,
152 A string of Python code that imports and executes a kernel entry point.
153
154 stdin, stdout, stderr : optional (default None)
155 Standards streams, as defined in subprocess.Popen.
122 156
123 157 independent : bool, optional (default False)
124 158 If set, the kernel process is guaranteed to survive if this process
@@ -126,24 +160,18 b' def base_launch_kernel(code, fname, stdin=None, stdout=None, stderr=None,'
126 160 when this process dies. Note that in this case it is still good practice
127 161 to kill kernels manually before exiting.
128 162
129 extra_arguments : list, optional
130 A list of extra arguments to pass when executing the launch code.
131
132 163 cwd : path, optional
133 164 The working dir of the kernel process (default: cwd of this process).
134 165
166 ipython_kernel : bool, optional
167 Whether the kernel is an official IPython one,
168 and should get a bit of special treatment.
169
135 170 Returns
136 171 -------
137 A tuple of form:
138 (kernel_process, shell_port, iopub_port, stdin_port, hb_port)
139 where kernel_process is a Popen object and the ports are integers.
140 """
141 172
142 # Build the kernel launch command.
143 if executable is None:
144 executable = sys.executable
145 arguments = [ executable, '-c', code, '-f', fname ]
146 arguments.extend(extra_arguments)
173 Popen instance for the kernel subprocess
174 """
147 175
148 176 # Popen will fail (sometimes with a deadlock) if stdin, stdout, and stderr
149 177 # are invalid. Unfortunately, there is in general no way to detect whether
@@ -167,50 +195,58 b' def base_launch_kernel(code, fname, stdin=None, stdout=None, stderr=None,'
167 195
168 196 # Spawn a kernel.
169 197 if sys.platform == 'win32':
198
170 199 # Create a Win32 event for interrupting the kernel.
171 200 interrupt_event = ParentPollerWindows.create_interrupt_event()
172 arguments += [ '--interrupt=%i'%interrupt_event ]
173
174 # If the kernel is running on pythonw and stdout/stderr are not been
175 # re-directed, it will crash when more than 4KB of data is written to
176 # stdout or stderr. This is a bug that has been with Python for a very
177 # long time; see http://bugs.python.org/issue706263.
178 # A cleaner solution to this problem would be to pass os.devnull to
179 # Popen directly. Unfortunately, that does not work.
180 if executable.endswith('pythonw.exe'):
181 if stdout is None:
182 arguments.append('--no-stdout')
183 if stderr is None:
184 arguments.append('--no-stderr')
201 if ipython_kernel:
202 cmd += [ '--interrupt=%i' % interrupt_event ]
203
204 # If the kernel is running on pythonw and stdout/stderr are not been
205 # re-directed, it will crash when more than 4KB of data is written to
206 # stdout or stderr. This is a bug that has been with Python for a very
207 # long time; see http://bugs.python.org/issue706263.
208 # A cleaner solution to this problem would be to pass os.devnull to
209 # Popen directly. Unfortunately, that does not work.
210 if cmd[0].endswith('pythonw.exe'):
211 if stdout is None:
212 cmd.append('--no-stdout')
213 if stderr is None:
214 cmd.append('--no-stderr')
185 215
186 216 # Launch the kernel process.
187 217 if independent:
188 proc = Popen(arguments,
218 proc = Popen(cmd,
189 219 creationflags=512, # CREATE_NEW_PROCESS_GROUP
190 220 stdin=_stdin, stdout=_stdout, stderr=_stderr)
191 221 else:
192 try:
193 from _winapi import DuplicateHandle, GetCurrentProcess, \
194 DUPLICATE_SAME_ACCESS
195 except:
196 from _subprocess import DuplicateHandle, GetCurrentProcess, \
197 DUPLICATE_SAME_ACCESS
198 pid = GetCurrentProcess()
199 handle = DuplicateHandle(pid, pid, pid, 0,
200 True, # Inheritable by new processes.
201 DUPLICATE_SAME_ACCESS)
202 proc = Popen(arguments + ['--parent=%i'%int(handle)],
203 stdin=_stdin, stdout=_stdout, stderr=_stderr)
222 if ipython_kernel:
223 try:
224 from _winapi import DuplicateHandle, GetCurrentProcess, \
225 DUPLICATE_SAME_ACCESS
226 except:
227 from _subprocess import DuplicateHandle, GetCurrentProcess, \
228 DUPLICATE_SAME_ACCESS
229 pid = GetCurrentProcess()
230 handle = DuplicateHandle(pid, pid, pid, 0,
231 True, # Inheritable by new processes.
232 DUPLICATE_SAME_ACCESS)
233 cmd +=[ '--parent=%i' % handle ]
234
235
236 proc = Popen(cmd,
237 stdin=_stdin, stdout=_stdout, stderr=_stderr, cwd=cwd)
204 238
205 239 # Attach the interrupt event to the Popen objet so it can be used later.
206 240 proc.win32_interrupt_event = interrupt_event
207 241
208 242 else:
209 243 if independent:
210 proc = Popen(arguments, preexec_fn=lambda: os.setsid(),
244 proc = Popen(cmd, preexec_fn=lambda: os.setsid(),
211 245 stdin=_stdin, stdout=_stdout, stderr=_stderr, cwd=cwd)
212 246 else:
213 proc = Popen(arguments + ['--parent=1'],
247 if ipython_kernel:
248 cmd += ['--parent=1']
249 proc = Popen(cmd,
214 250 stdin=_stdin, stdout=_stdout, stderr=_stderr, cwd=cwd)
215 251
216 252 # Clean up pipes created to work around Popen bug.
General Comments 0
You need to be logged in to leave comments. Login now