##// END OF EJS Templates
Merge pull request #7099 from minrk/parent-env...
Thomas Kluyver -
r19268:9c06d407 merge
parent child Browse files
Show More
@@ -101,25 +101,13 b" def make_ipkernel_cmd(mod='IPython.kernel', executable=None, extra_arguments=[],"
101 101 executable = sys.executable
102 102 arguments = [ executable, '-m', mod, '-f', '{connection_file}' ]
103 103 arguments.extend(extra_arguments)
104
105 if sys.platform == 'win32':
106
107 # If the kernel is running on pythonw and stdout/stderr are not been
108 # re-directed, it will crash when more than 4KB of data is written to
109 # stdout or stderr. This is a bug that has been with Python for a very
110 # long time; see http://bugs.python.org/issue706263.
111 # A cleaner solution to this problem would be to pass os.devnull to
112 # Popen directly. Unfortunately, that does not work.
113 if executable.endswith('pythonw.exe'):
114 arguments.append('--no-stdout')
115 arguments.append('--no-stderr')
116
104
117 105 return arguments
118 106
119 107
120 108 def launch_kernel(cmd, stdin=None, stdout=None, stderr=None, env=None,
121 109 independent=False,
122 cwd=None, ipython_kernel=True,
110 cwd=None,
123 111 **kw
124 112 ):
125 113 """ Launches a localhost kernel, binding to the specified ports.
@@ -141,10 +129,6 b' def launch_kernel(cmd, stdin=None, stdout=None, stderr=None, env=None,'
141 129 cwd : path, optional
142 130 The working dir of the kernel process (default: cwd of this process).
143 131
144 ipython_kernel : bool, optional
145 Whether the kernel is an official IPython one,
146 and should get a bit of special treatment.
147
148 132 Returns
149 133 -------
150 134
@@ -166,14 +150,22 b' def launch_kernel(cmd, stdin=None, stdout=None, stderr=None, env=None,'
166 150 # stderr are all invalid.
167 151 redirect_out = sys.executable.endswith('pythonw.exe')
168 152 if redirect_out:
169 _stdout = PIPE if stdout is None else stdout
170 _stderr = PIPE if stderr is None else stderr
153 blackhole = open(os.devnull, 'w')
154 _stdout = blackhole if stdout is None else stdout
155 _stderr = blackhole if stderr is None else stderr
171 156 else:
172 157 _stdout, _stderr = stdout, stderr
173 158
174 159 env = env if (env is not None) else os.environ.copy()
175 160
176 161 encoding = getdefaultencoding(prefer_stream=False)
162 kwargs = dict(
163 stdin=_stdin,
164 stdout=_stdout,
165 stderr=_stderr,
166 cwd=cwd,
167 env=env,
168 )
177 169
178 170 # Spawn a kernel.
179 171 if sys.platform == 'win32':
@@ -181,73 +173,49 b' def launch_kernel(cmd, stdin=None, stdout=None, stderr=None, env=None,'
181 173 cmd = [ cast_bytes_py2(c, encoding) for c in cmd ]
182 174 if cwd:
183 175 cwd = cast_bytes_py2(cwd, sys.getfilesystemencoding() or 'ascii')
176 kwargs['cwd'] = cwd
184 177
185 178 from IPython.kernel.zmq.parentpoller import ParentPollerWindows
186 # Create a Win32 event for interrupting the kernel.
179 # Create a Win32 event for interrupting the kernel
180 # and store it in an environment variable.
187 181 interrupt_event = ParentPollerWindows.create_interrupt_event()
188 # Store this in an environment variable for third party kernels, but at
189 # present, our own kernel expects this as a command line argument.
190 env["IPY_INTERRUPT_EVENT"] = str(interrupt_event)
191 if ipython_kernel:
192 cmd += [ '--interrupt=%i' % interrupt_event ]
193
194 # If the kernel is running on pythonw and stdout/stderr are not been
195 # re-directed, it will crash when more than 4KB of data is written to
196 # stdout or stderr. This is a bug that has been with Python for a very
197 # long time; see http://bugs.python.org/issue706263.
198 # A cleaner solution to this problem would be to pass os.devnull to
199 # Popen directly. Unfortunately, that does not work.
200 if cmd[0].endswith('pythonw.exe'):
201 if stdout is None:
202 cmd.append('--no-stdout')
203 if stderr is None:
204 cmd.append('--no-stderr')
205
206 # Launch the kernel process.
182 env["JPY_INTERRUPT_EVENT"] = str(interrupt_event)
183 # deprecated old env name:
184 env["IPY_INTERRUPT_EVENT"] = env["JPY_INTERRUPT_EVENT"]
185
186 try:
187 from _winapi import DuplicateHandle, GetCurrentProcess, \
188 DUPLICATE_SAME_ACCESS, CREATE_NEW_PROCESS_GROUP
189 except:
190 from _subprocess import DuplicateHandle, GetCurrentProcess, \
191 DUPLICATE_SAME_ACCESS, CREATE_NEW_PROCESS_GROUP
192 # Launch the kernel process
207 193 if independent:
208 proc = Popen(cmd,
209 creationflags=512, # CREATE_NEW_PROCESS_GROUP
210 stdin=_stdin, stdout=_stdout, stderr=_stderr, env=env)
194 kwargs['creationflags'] = CREATE_NEW_PROCESS_GROUP
211 195 else:
212 if ipython_kernel:
213 try:
214 from _winapi import DuplicateHandle, GetCurrentProcess, \
215 DUPLICATE_SAME_ACCESS
216 except:
217 from _subprocess import DuplicateHandle, GetCurrentProcess, \
218 DUPLICATE_SAME_ACCESS
219 pid = GetCurrentProcess()
220 handle = DuplicateHandle(pid, pid, pid, 0,
221 True, # Inheritable by new processes.
222 DUPLICATE_SAME_ACCESS)
223 cmd +=[ '--parent=%i' % handle ]
224
225
226 proc = Popen(cmd,
227 stdin=_stdin, stdout=_stdout, stderr=_stderr, cwd=cwd, env=env)
196 pid = GetCurrentProcess()
197 handle = DuplicateHandle(pid, pid, pid, 0,
198 True, # Inheritable by new processes.
199 DUPLICATE_SAME_ACCESS)
200 env['JPY_PARENT_PID'] = str(handle)
201
202 proc = Popen(cmd, **kwargs)
228 203
229 204 # Attach the interrupt event to the Popen objet so it can be used later.
230 205 proc.win32_interrupt_event = interrupt_event
231 206
232 207 else:
233 208 if independent:
234 proc = Popen(cmd, preexec_fn=lambda: os.setsid(),
235 stdin=_stdin, stdout=_stdout, stderr=_stderr, cwd=cwd, env=env)
209 kwargs['preexec_fn'] = lambda: os.setsid()
236 210 else:
237 if ipython_kernel:
238 cmd += ['--parent=1']
239 proc = Popen(cmd,
240 stdin=_stdin, stdout=_stdout, stderr=_stderr, cwd=cwd, env=env)
211 env['JPY_PARENT_PID'] = str(os.getpid())
212
213 proc = Popen(cmd, **kwargs)
241 214
242 215 # Clean up pipes created to work around Popen bug.
243 216 if redirect_in:
244 217 if stdin is None:
245 218 proc.stdin.close()
246 if redirect_out:
247 if stdout is None:
248 proc.stdout.close()
249 if stderr is None:
250 proc.stderr.close()
251 219
252 220 return proc
253 221
@@ -237,7 +237,6 b' class KernelManager(ConnectionFileMixin):'
237 237 env.update(self.kernel_spec.env or {})
238 238 # launch the kernel subprocess
239 239 self.kernel = self._launch_kernel(kernel_cmd, env=env,
240 ipython_kernel=self.ipython_kernel,
241 240 **kw)
242 241 self.start_restarter()
243 242 self._connect_control_socket()
@@ -53,11 +53,8 b' kernel_aliases.update({'
53 53 'stdin' : 'IPKernelApp.stdin_port',
54 54 'control' : 'IPKernelApp.control_port',
55 55 'f' : 'IPKernelApp.connection_file',
56 'parent': 'IPKernelApp.parent_handle',
57 56 'transport': 'IPKernelApp.transport',
58 57 })
59 if sys.platform.startswith('win'):
60 kernel_aliases['interrupt'] = 'IPKernelApp.interrupt'
61 58
62 59 kernel_flags = dict(base_flags)
63 60 kernel_flags.update({
@@ -133,11 +130,11 b' class IPKernelApp(BaseIPythonApplication, InteractiveShellApp,'
133 130 config=True, help="The importstring for the DisplayHook factory")
134 131
135 132 # polling
136 parent_handle = Integer(0, config=True,
133 parent_handle = Integer(int(os.environ.get('JPY_PARENT_PID') or 0), config=True,
137 134 help="""kill this process if its parent dies. On Windows, the argument
138 135 specifies the HANDLE of the parent process, otherwise it is simply boolean.
139 136 """)
140 interrupt = Integer(0, config=True,
137 interrupt = Integer(int(os.environ.get('JPY_INTERRUPT_EVENT') or 0), config=True,
141 138 help="""ONLY USED ON WINDOWS
142 139 Interrupt this process when the parent is signaled.
143 140 """)
General Comments 0
You need to be logged in to leave comments. Login now