Show More
@@ -102,24 +102,12 b" def make_ipkernel_cmd(mod='IPython.kernel', executable=None, extra_arguments=[]," | |||||
102 | arguments = [ executable, '-m', mod, '-f', '{connection_file}' ] |
|
102 | arguments = [ executable, '-m', mod, '-f', '{connection_file}' ] | |
103 | arguments.extend(extra_arguments) |
|
103 | arguments.extend(extra_arguments) | |
104 |
|
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 |
|
||||
117 | return arguments |
|
105 | return arguments | |
118 |
|
106 | |||
119 |
|
107 | |||
120 | def launch_kernel(cmd, stdin=None, stdout=None, stderr=None, env=None, |
|
108 | def launch_kernel(cmd, stdin=None, stdout=None, stderr=None, env=None, | |
121 | independent=False, |
|
109 | independent=False, | |
122 |
cwd=None, |
|
110 | cwd=None, | |
123 | **kw |
|
111 | **kw | |
124 | ): |
|
112 | ): | |
125 | """ Launches a localhost kernel, binding to the specified ports. |
|
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 | cwd : path, optional |
|
129 | cwd : path, optional | |
142 | The working dir of the kernel process (default: cwd of this process). |
|
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 | Returns |
|
132 | Returns | |
149 | ------- |
|
133 | ------- | |
150 |
|
134 | |||
@@ -166,14 +150,22 b' def launch_kernel(cmd, stdin=None, stdout=None, stderr=None, env=None,' | |||||
166 | # stderr are all invalid. |
|
150 | # stderr are all invalid. | |
167 | redirect_out = sys.executable.endswith('pythonw.exe') |
|
151 | redirect_out = sys.executable.endswith('pythonw.exe') | |
168 | if redirect_out: |
|
152 | if redirect_out: | |
169 | _stdout = PIPE if stdout is None else stdout |
|
153 | blackhole = open(os.devnull, 'w') | |
170 |
_std |
|
154 | _stdout = blackhole if stdout is None else stdout | |
|
155 | _stderr = blackhole if stderr is None else stderr | |||
171 | else: |
|
156 | else: | |
172 | _stdout, _stderr = stdout, stderr |
|
157 | _stdout, _stderr = stdout, stderr | |
173 |
|
158 | |||
174 | env = env if (env is not None) else os.environ.copy() |
|
159 | env = env if (env is not None) else os.environ.copy() | |
175 |
|
160 | |||
176 | encoding = getdefaultencoding(prefer_stream=False) |
|
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 | # Spawn a kernel. |
|
170 | # Spawn a kernel. | |
179 | if sys.platform == 'win32': |
|
171 | if sys.platform == 'win32': | |
@@ -181,73 +173,49 b' def launch_kernel(cmd, stdin=None, stdout=None, stderr=None, env=None,' | |||||
181 | cmd = [ cast_bytes_py2(c, encoding) for c in cmd ] |
|
173 | cmd = [ cast_bytes_py2(c, encoding) for c in cmd ] | |
182 | if cwd: |
|
174 | if cwd: | |
183 | cwd = cast_bytes_py2(cwd, sys.getfilesystemencoding() or 'ascii') |
|
175 | cwd = cast_bytes_py2(cwd, sys.getfilesystemencoding() or 'ascii') | |
|
176 | kwargs['cwd'] = cwd | |||
184 |
|
177 | |||
185 | from IPython.kernel.zmq.parentpoller import ParentPollerWindows |
|
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 | interrupt_event = ParentPollerWindows.create_interrupt_event() |
|
181 | interrupt_event = ParentPollerWindows.create_interrupt_event() | |
188 | # Store this in an environment variable for third party kernels, but at |
|
182 | env["JPY_INTERRUPT_EVENT"] = str(interrupt_event) | |
189 | # present, our own kernel expects this as a command line argument. |
|
183 | # deprecated old env name: | |
190 |
env["IPY_INTERRUPT_EVENT"] = |
|
184 | env["IPY_INTERRUPT_EVENT"] = env["JPY_INTERRUPT_EVENT"] | |
191 | if ipython_kernel: |
|
185 | ||
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. |
|
|||
207 | if independent: |
|
|||
208 | proc = Popen(cmd, |
|
|||
209 | creationflags=512, # CREATE_NEW_PROCESS_GROUP |
|
|||
210 | stdin=_stdin, stdout=_stdout, stderr=_stderr, env=env) |
|
|||
211 | else: |
|
|||
212 | if ipython_kernel: |
|
|||
213 |
|
|
186 | try: | |
214 |
|
|
187 | from _winapi import DuplicateHandle, GetCurrentProcess, \ | |
215 |
|
|
188 | DUPLICATE_SAME_ACCESS, CREATE_NEW_PROCESS_GROUP | |
216 |
|
|
189 | except: | |
217 |
|
|
190 | from _subprocess import DuplicateHandle, GetCurrentProcess, \ | |
218 |
|
|
191 | DUPLICATE_SAME_ACCESS, CREATE_NEW_PROCESS_GROUP | |
|
192 | # Launch the kernel process | |||
|
193 | if independent: | |||
|
194 | kwargs['creationflags'] = CREATE_NEW_PROCESS_GROUP | |||
|
195 | else: | |||
219 |
|
|
196 | pid = GetCurrentProcess() | |
220 |
|
|
197 | handle = DuplicateHandle(pid, pid, pid, 0, | |
221 |
|
|
198 | True, # Inheritable by new processes. | |
222 |
|
|
199 | DUPLICATE_SAME_ACCESS) | |
223 | cmd +=[ '--parent=%i' % handle ] |
|
200 | env['JPY_PARENT_PID'] = str(handle) | |
224 |
|
|
201 | ||
225 |
|
202 | proc = Popen(cmd, **kwargs) | ||
226 | proc = Popen(cmd, |
|
|||
227 | stdin=_stdin, stdout=_stdout, stderr=_stderr, cwd=cwd, env=env) |
|
|||
228 |
|
203 | |||
229 | # Attach the interrupt event to the Popen objet so it can be used later. |
|
204 | # Attach the interrupt event to the Popen objet so it can be used later. | |
230 | proc.win32_interrupt_event = interrupt_event |
|
205 | proc.win32_interrupt_event = interrupt_event | |
231 |
|
206 | |||
232 | else: |
|
207 | else: | |
233 | if independent: |
|
208 | if independent: | |
234 |
|
|
209 | kwargs['preexec_fn'] = lambda: os.setsid() | |
235 | stdin=_stdin, stdout=_stdout, stderr=_stderr, cwd=cwd, env=env) |
|
|||
236 | else: |
|
210 | else: | |
237 | if ipython_kernel: |
|
211 | env['JPY_PARENT_PID'] = str(os.getpid()) | |
238 | cmd += ['--parent=1'] |
|
212 | ||
239 |
|
|
213 | proc = Popen(cmd, **kwargs) | |
240 | stdin=_stdin, stdout=_stdout, stderr=_stderr, cwd=cwd, env=env) |
|
|||
241 |
|
214 | |||
242 | # Clean up pipes created to work around Popen bug. |
|
215 | # Clean up pipes created to work around Popen bug. | |
243 | if redirect_in: |
|
216 | if redirect_in: | |
244 | if stdin is None: |
|
217 | if stdin is None: | |
245 | proc.stdin.close() |
|
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 | return proc |
|
220 | return proc | |
253 |
|
221 |
@@ -237,7 +237,6 b' class KernelManager(ConnectionFileMixin):' | |||||
237 | env.update(self.kernel_spec.env or {}) |
|
237 | env.update(self.kernel_spec.env or {}) | |
238 | # launch the kernel subprocess |
|
238 | # launch the kernel subprocess | |
239 | self.kernel = self._launch_kernel(kernel_cmd, env=env, |
|
239 | self.kernel = self._launch_kernel(kernel_cmd, env=env, | |
240 | ipython_kernel=self.ipython_kernel, |
|
|||
241 | **kw) |
|
240 | **kw) | |
242 | self.start_restarter() |
|
241 | self.start_restarter() | |
243 | self._connect_control_socket() |
|
242 | self._connect_control_socket() |
@@ -53,11 +53,8 b' kernel_aliases.update({' | |||||
53 | 'stdin' : 'IPKernelApp.stdin_port', |
|
53 | 'stdin' : 'IPKernelApp.stdin_port', | |
54 | 'control' : 'IPKernelApp.control_port', |
|
54 | 'control' : 'IPKernelApp.control_port', | |
55 | 'f' : 'IPKernelApp.connection_file', |
|
55 | 'f' : 'IPKernelApp.connection_file', | |
56 | 'parent': 'IPKernelApp.parent_handle', |
|
|||
57 | 'transport': 'IPKernelApp.transport', |
|
56 | 'transport': 'IPKernelApp.transport', | |
58 | }) |
|
57 | }) | |
59 | if sys.platform.startswith('win'): |
|
|||
60 | kernel_aliases['interrupt'] = 'IPKernelApp.interrupt' |
|
|||
61 |
|
58 | |||
62 | kernel_flags = dict(base_flags) |
|
59 | kernel_flags = dict(base_flags) | |
63 | kernel_flags.update({ |
|
60 | kernel_flags.update({ | |
@@ -133,11 +130,11 b' class IPKernelApp(BaseIPythonApplication, InteractiveShellApp,' | |||||
133 | config=True, help="The importstring for the DisplayHook factory") |
|
130 | config=True, help="The importstring for the DisplayHook factory") | |
134 |
|
131 | |||
135 | # polling |
|
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 | help="""kill this process if its parent dies. On Windows, the argument |
|
134 | help="""kill this process if its parent dies. On Windows, the argument | |
138 | specifies the HANDLE of the parent process, otherwise it is simply boolean. |
|
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 | help="""ONLY USED ON WINDOWS |
|
138 | help="""ONLY USED ON WINDOWS | |
142 | Interrupt this process when the parent is signaled. |
|
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