Show More
@@ -23,6 +23,7 b' from iostream import OutStream' | |||||
23 | from parentpoller import ParentPollerUnix, ParentPollerWindows |
|
23 | from parentpoller import ParentPollerUnix, ParentPollerWindows | |
24 | from session import Session |
|
24 | from session import Session | |
25 |
|
25 | |||
|
26 | ||||
26 | def bind_port(socket, ip, port): |
|
27 | def bind_port(socket, ip, port): | |
27 | """ Binds the specified ZMQ socket. If the port is zero, a random port is |
|
28 | """ Binds the specified ZMQ socket. If the port is zero, a random port is | |
28 | chosen. Returns the port that was bound. |
|
29 | chosen. Returns the port that was bound. | |
@@ -51,6 +52,10 b' def make_argument_parser():' | |||||
51 | help='set the REQ channel port [default: random]') |
|
52 | help='set the REQ channel port [default: random]') | |
52 | parser.add_argument('--hb', type=int, metavar='PORT', default=0, |
|
53 | parser.add_argument('--hb', type=int, metavar='PORT', default=0, | |
53 | help='set the heartbeat port [default: random]') |
|
54 | help='set the heartbeat port [default: random]') | |
|
55 | parser.add_argument('--no-stdout', action='store_true', | |||
|
56 | help='redirect stdout to the null device') | |||
|
57 | parser.add_argument('--no-stderr', action='store_true', | |||
|
58 | help='redirect stderr to the null device') | |||
54 |
|
59 | |||
55 | if sys.platform == 'win32': |
|
60 | if sys.platform == 'win32': | |
56 | parser.add_argument('--interrupt', type=int, metavar='HANDLE', |
|
61 | parser.add_argument('--interrupt', type=int, metavar='HANDLE', | |
@@ -71,13 +76,13 b' def make_kernel(namespace, kernel_factory,' | |||||
71 | """ Creates a kernel, redirects stdout/stderr, and installs a display hook |
|
76 | """ Creates a kernel, redirects stdout/stderr, and installs a display hook | |
72 | and exception handler. |
|
77 | and exception handler. | |
73 | """ |
|
78 | """ | |
74 | # If running under pythonw.exe, the interpreter will crash if more than 4KB |
|
79 | # Re-direct stdout/stderr, if necessary. | |
75 | # of data is written to stdout or stderr. This is a bug that has been with |
|
80 | if namespace.no_stdout or namespace.no_stderr: | |
76 | # Python for a very long time; see http://bugs.python.org/issue706263. |
|
|||
77 | if sys.executable.endswith('pythonw.exe'): |
|
|||
78 | blackhole = file(os.devnull, 'w') |
|
81 | blackhole = file(os.devnull, 'w') | |
79 | sys.stdout = sys.stderr = blackhole |
|
82 | if namespace.no_stdout: | |
80 |
sys.__stdout__ = |
|
83 | sys.stdout = sys.__stdout__ = blackhole | |
|
84 | if namespace.no_stderr: | |||
|
85 | sys.stderr = sys.__stderr__ = blackhole | |||
81 |
|
86 | |||
82 | # Install minimal exception handling |
|
87 | # Install minimal exception handling | |
83 | sys.excepthook = FormattedTB(mode='Verbose', color_scheme='NoColor', |
|
88 | sys.excepthook = FormattedTB(mode='Verbose', color_scheme='NoColor', | |
@@ -155,6 +160,7 b' def make_default_main(kernel_factory):' | |||||
155 |
|
160 | |||
156 |
|
161 | |||
157 | def base_launch_kernel(code, xrep_port=0, pub_port=0, req_port=0, hb_port=0, |
|
162 | def base_launch_kernel(code, xrep_port=0, pub_port=0, req_port=0, hb_port=0, | |
|
163 | stdin=None, stdout=None, stderr=None, | |||
158 | executable=None, independent=False, extra_arguments=[]): |
|
164 | executable=None, independent=False, extra_arguments=[]): | |
159 | """ Launches a localhost kernel, binding to the specified ports. |
|
165 | """ Launches a localhost kernel, binding to the specified ports. | |
160 |
|
166 | |||
@@ -175,6 +181,9 b' def base_launch_kernel(code, xrep_port=0, pub_port=0, req_port=0, hb_port=0,' | |||||
175 | hb_port : int, optional |
|
181 | hb_port : int, optional | |
176 | The port to use for the hearbeat REP channel. |
|
182 | The port to use for the hearbeat REP channel. | |
177 |
|
183 | |||
|
184 | stdin, stdout, stderr : optional (default None) | |||
|
185 | Standards streams, as defined in subprocess.Popen. | |||
|
186 | ||||
178 | executable : str, optional (default sys.executable) |
|
187 | executable : str, optional (default sys.executable) | |
179 | The Python executable to use for the kernel process. |
|
188 | The Python executable to use for the kernel process. | |
180 |
|
189 | |||
@@ -228,15 +237,35 b' def base_launch_kernel(code, xrep_port=0, pub_port=0, req_port=0, hb_port=0,' | |||||
228 | interrupt_event = ParentPollerWindows.create_interrupt_event() |
|
237 | interrupt_event = ParentPollerWindows.create_interrupt_event() | |
229 | arguments += [ '--interrupt', str(int(interrupt_event)) ] |
|
238 | arguments += [ '--interrupt', str(int(interrupt_event)) ] | |
230 |
|
239 | |||
231 |
# If |
|
240 | # If this process in running on pythonw, stdin, stdout, and stderr are | |
232 |
# fail unless they are suitably redirected. We don't |
|
241 | # invalid. Popen will fail unless they are suitably redirected. We don't | |
233 | # pipes, but they must exist. |
|
242 | # read from the pipes, but they must exist. | |
234 |
|
|
243 | if sys.executable.endswith('pythonw.exe'): | |
235 |
|
244 | redirect = True | ||
|
245 | _stdin = PIPE if stdin is None else stdin | |||
|
246 | _stdout = PIPE if stdout is None else stdout | |||
|
247 | _stderr = PIPE if stderr is None else stderr | |||
|
248 | else: | |||
|
249 | redirect = False | |||
|
250 | _stdin, _stdout, _stderr = stdin, stdout, stderr | |||
|
251 | ||||
|
252 | # If the kernel is running on pythonw and stdout/stderr are not been | |||
|
253 | # re-directed, it will crash when more than 4KB of data is written to | |||
|
254 | # stdout or stderr. This is a bug that has been with Python for a very | |||
|
255 | # long time; see http://bugs.python.org/issue706263. | |||
|
256 | # A cleaner solution to this problem would be to pass os.devnull to | |||
|
257 | # Popen directly. Unfortunately, that does not work. | |||
|
258 | if executable.endswith('pythonw.exe'): | |||
|
259 | if stdout is None: | |||
|
260 | arguments.append('--no-stdout') | |||
|
261 | if stderr is None: | |||
|
262 | arguments.append('--no-stderr') | |||
|
263 | ||||
|
264 | # Launch the kernel process. | |||
236 | if independent: |
|
265 | if independent: | |
237 | proc = Popen(arguments, |
|
266 | proc = Popen(arguments, | |
238 | creationflags=512, # CREATE_NEW_PROCESS_GROUP |
|
267 | creationflags=512, # CREATE_NEW_PROCESS_GROUP | |
239 |
stdout= |
|
268 | stdin=_stdin, stdout=_stdout, stderr=_stderr) | |
240 | else: |
|
269 | else: | |
241 | from _subprocess import DuplicateHandle, GetCurrentProcess, \ |
|
270 | from _subprocess import DuplicateHandle, GetCurrentProcess, \ | |
242 | DUPLICATE_SAME_ACCESS |
|
271 | DUPLICATE_SAME_ACCESS | |
@@ -245,21 +274,26 b' def base_launch_kernel(code, xrep_port=0, pub_port=0, req_port=0, hb_port=0,' | |||||
245 | True, # Inheritable by new processes. |
|
274 | True, # Inheritable by new processes. | |
246 | DUPLICATE_SAME_ACCESS) |
|
275 | DUPLICATE_SAME_ACCESS) | |
247 | proc = Popen(arguments + ['--parent', str(int(handle))], |
|
276 | proc = Popen(arguments + ['--parent', str(int(handle))], | |
248 |
stdout= |
|
277 | stdin=_stdin, stdout=_stdout, stderr=_stderr) | |
249 |
|
278 | |||
250 | # Attach the interrupt event to the Popen objet so it can be used later. |
|
279 | # Attach the interrupt event to the Popen objet so it can be used later. | |
251 | proc.win32_interrupt_event = interrupt_event |
|
280 | proc.win32_interrupt_event = interrupt_event | |
252 |
|
281 | |||
253 | # Clean up pipes created to work around Popen bug. |
|
282 | # Clean up pipes created to work around Popen bug. | |
254 |
if redirect |
|
283 | if redirect: | |
255 | proc.stdout.close() |
|
284 | if stdin is None: | |
256 |
proc.std |
|
285 | proc.stdin.close() | |
257 |
|
|
286 | if stdout is None: | |
|
287 | proc.stdout.close() | |||
|
288 | if stderr is None: | |||
|
289 | proc.stderr.close() | |||
258 |
|
290 | |||
259 | else: |
|
291 | else: | |
260 | if independent: |
|
292 | if independent: | |
261 |
proc = Popen(arguments, preexec_fn=lambda: os.setsid() |
|
293 | proc = Popen(arguments, preexec_fn=lambda: os.setsid(), | |
|
294 | stdin=stdin, stdout=stdout, stderr=stderr) | |||
262 | else: |
|
295 | else: | |
263 |
proc = Popen(arguments + ['--parent'] |
|
296 | proc = Popen(arguments + ['--parent'], | |
|
297 | stdin=stdin, stdout=stdout, stderr=stderr) | |||
264 |
|
298 | |||
265 | return proc, xrep_port, pub_port, req_port, hb_port |
|
299 | return proc, xrep_port, pub_port, req_port, hb_port |
@@ -568,6 +568,7 b' class GTKKernel(Kernel):' | |||||
568 | #----------------------------------------------------------------------------- |
|
568 | #----------------------------------------------------------------------------- | |
569 |
|
569 | |||
570 | def launch_kernel(ip=None, xrep_port=0, pub_port=0, req_port=0, hb_port=0, |
|
570 | def launch_kernel(ip=None, xrep_port=0, pub_port=0, req_port=0, hb_port=0, | |
|
571 | stdin=None, stdout=None, stderr=None, | |||
571 | executable=None, independent=False, pylab=False, colors=None): |
|
572 | executable=None, independent=False, pylab=False, colors=None): | |
572 | """Launches a localhost kernel, binding to the specified ports. |
|
573 | """Launches a localhost kernel, binding to the specified ports. | |
573 |
|
574 | |||
@@ -588,6 +589,9 b' def launch_kernel(ip=None, xrep_port=0, pub_port=0, req_port=0, hb_port=0,' | |||||
588 | hb_port : int, optional |
|
589 | hb_port : int, optional | |
589 | The port to use for the hearbeat REP channel. |
|
590 | The port to use for the hearbeat REP channel. | |
590 |
|
591 | |||
|
592 | stdin, stdout, stderr : optional (default None) | |||
|
593 | Standards streams, as defined in subprocess.Popen. | |||
|
594 | ||||
591 | executable : str, optional (default sys.executable) |
|
595 | executable : str, optional (default sys.executable) | |
592 | The Python executable to use for the kernel process. |
|
596 | The Python executable to use for the kernel process. | |
593 |
|
597 | |||
@@ -625,6 +629,7 b' def launch_kernel(ip=None, xrep_port=0, pub_port=0, req_port=0, hb_port=0,' | |||||
625 | extra_arguments.append(colors) |
|
629 | extra_arguments.append(colors) | |
626 | return base_launch_kernel('from IPython.zmq.ipkernel import main; main()', |
|
630 | return base_launch_kernel('from IPython.zmq.ipkernel import main; main()', | |
627 | xrep_port, pub_port, req_port, hb_port, |
|
631 | xrep_port, pub_port, req_port, hb_port, | |
|
632 | stdin, stdout, stderr, | |||
628 | executable, independent, extra_arguments) |
|
633 | executable, independent, extra_arguments) | |
629 |
|
634 | |||
630 |
|
635 |
@@ -590,7 +590,8 b' class HBSocketChannel(ZmqSocketChannel):' | |||||
590 | # list, poll is working correctly even if it |
|
590 | # list, poll is working correctly even if it | |
591 | # returns quickly. Note: poll timeout is in |
|
591 | # returns quickly. Note: poll timeout is in | |
592 | # milliseconds. |
|
592 | # milliseconds. | |
593 |
|
|
593 | if until_dead > 0.0: | |
|
594 | self.poller.poll(1000 * until_dead) | |||
594 |
|
595 | |||
595 | since_last_heartbeat = time.time()-request_time |
|
596 | since_last_heartbeat = time.time()-request_time | |
596 | if since_last_heartbeat > self.time_to_dead: |
|
597 | if since_last_heartbeat > self.time_to_dead: | |
@@ -852,8 +853,15 b' class KernelManager(HasTraits):' | |||||
852 | except OSError, e: |
|
853 | except OSError, e: | |
853 | # In Windows, we will get an Access Denied error if the process |
|
854 | # In Windows, we will get an Access Denied error if the process | |
854 | # has already terminated. Ignore it. |
|
855 | # has already terminated. Ignore it. | |
855 |
if |
|
856 | if sys.platform == 'win32': | |
856 |
|
|
857 | if e.winerror != 5: | |
|
858 | raise | |||
|
859 | # On Unix, we may get an ESRCH error if the process has already | |||
|
860 | # terminated. Ignore it. | |||
|
861 | else: | |||
|
862 | from errno import ESRCH | |||
|
863 | if e.errno != ESRCH: | |||
|
864 | raise | |||
857 | self.kernel = None |
|
865 | self.kernel = None | |
858 | else: |
|
866 | else: | |
859 | raise RuntimeError("Cannot kill kernel. No kernel is running!") |
|
867 | raise RuntimeError("Cannot kill kernel. No kernel is running!") |
@@ -248,6 +248,7 b' class Kernel(HasTraits):' | |||||
248 | #----------------------------------------------------------------------------- |
|
248 | #----------------------------------------------------------------------------- | |
249 |
|
249 | |||
250 | def launch_kernel(ip=None, xrep_port=0, pub_port=0, req_port=0, hb_port=0, |
|
250 | def launch_kernel(ip=None, xrep_port=0, pub_port=0, req_port=0, hb_port=0, | |
|
251 | stdin=None, stdout=None, stderr=None, | |||
251 | executable=None, independent=False): |
|
252 | executable=None, independent=False): | |
252 | """ Launches a localhost kernel, binding to the specified ports. |
|
253 | """ Launches a localhost kernel, binding to the specified ports. | |
253 |
|
254 | |||
@@ -268,6 +269,9 b' def launch_kernel(ip=None, xrep_port=0, pub_port=0, req_port=0, hb_port=0,' | |||||
268 | hb_port : int, optional |
|
269 | hb_port : int, optional | |
269 | The port to use for the hearbeat REP channel. |
|
270 | The port to use for the hearbeat REP channel. | |
270 |
|
271 | |||
|
272 | stdin, stdout, stderr : optional (default None) | |||
|
273 | Standards streams, as defined in subprocess.Popen. | |||
|
274 | ||||
271 | executable : str, optional (default sys.executable) |
|
275 | executable : str, optional (default sys.executable) | |
272 | The Python executable to use for the kernel process. |
|
276 | The Python executable to use for the kernel process. | |
273 |
|
277 | |||
@@ -291,8 +295,8 b' def launch_kernel(ip=None, xrep_port=0, pub_port=0, req_port=0, hb_port=0,' | |||||
291 |
|
295 | |||
292 | return base_launch_kernel('from IPython.zmq.pykernel import main; main()', |
|
296 | return base_launch_kernel('from IPython.zmq.pykernel import main; main()', | |
293 | xrep_port, pub_port, req_port, hb_port, |
|
297 | xrep_port, pub_port, req_port, hb_port, | |
294 |
|
|
298 | stdin, stdout, stderr, | |
295 |
ex |
|
299 | executable, independent, extra_arguments) | |
296 |
|
300 | |||
297 | main = make_default_main(Kernel) |
|
301 | main = make_default_main(Kernel) | |
298 |
|
302 |
General Comments 0
You need to be logged in to leave comments.
Login now