Show More
@@ -0,0 +1,40 b'' | |||
|
1 | """Simple utility for building a list of local IPs using the socket module. | |
|
2 | This module defines two constants: | |
|
3 | ||
|
4 | LOCALHOST : The loopback interface, or the first interface that points to this | |
|
5 | machine. It will *almost* always be '127.0.0.1' | |
|
6 | ||
|
7 | LOCAL_IPS : A list of IP addresses, loopback first, that point to this machine. | |
|
8 | """ | |
|
9 | #----------------------------------------------------------------------------- | |
|
10 | # Copyright (C) 2010 The IPython Development Team | |
|
11 | # | |
|
12 | # Distributed under the terms of the BSD License. The full license is in | |
|
13 | # the file COPYING, distributed as part of this software. | |
|
14 | #----------------------------------------------------------------------------- | |
|
15 | ||
|
16 | #----------------------------------------------------------------------------- | |
|
17 | # Imports | |
|
18 | #----------------------------------------------------------------------------- | |
|
19 | ||
|
20 | import socket | |
|
21 | ||
|
22 | #----------------------------------------------------------------------------- | |
|
23 | # Code | |
|
24 | #----------------------------------------------------------------------------- | |
|
25 | ||
|
26 | LOCAL_IPS = [] | |
|
27 | try: | |
|
28 | LOCAL_IPS = socket.gethostbyname_ex('localhost')[2] | |
|
29 | except socket.gaierror: | |
|
30 | pass | |
|
31 | ||
|
32 | try: | |
|
33 | LOCAL_IPS.extend(socket.gethostbyname_ex(socket.gethostname())[2]) | |
|
34 | except socket.gaierror: | |
|
35 | pass | |
|
36 | ||
|
37 | # include all-interface aliases: 0.0.0.0 and '' | |
|
38 | LOCAL_IPS.extend(['0.0.0.0', '']) | |
|
39 | ||
|
40 | LOCALHOST = LOCAL_IPS[0] |
@@ -101,6 +101,7 b' class FrontendWidget(HistoryConsoleWidget, BaseFrontendMixin):' | |||
|
101 | 101 | _CompletionRequest = namedtuple('_CompletionRequest', ['id', 'pos']) |
|
102 | 102 | _ExecutionRequest = namedtuple('_ExecutionRequest', ['id', 'kind']) |
|
103 | 103 | _input_splitter_class = InputSplitter |
|
104 | _local_kernel = False | |
|
104 | 105 | |
|
105 | 106 | #--------------------------------------------------------------------------- |
|
106 | 107 | # 'object' interface |
@@ -141,6 +142,9 b' class FrontendWidget(HistoryConsoleWidget, BaseFrontendMixin):' | |||
|
141 | 142 | # Connect signal handlers. |
|
142 | 143 | document = self._control.document() |
|
143 | 144 | document.contentsChange.connect(self._document_contents_change) |
|
145 | ||
|
146 | # set flag for whether we are connected via localhost | |
|
147 | self._local_kernel = kw.get('local_kernel', FrontendWidget._local_kernel) | |
|
144 | 148 | |
|
145 | 149 | #--------------------------------------------------------------------------- |
|
146 | 150 | # 'ConsoleWidget' public interface |
@@ -366,14 +370,32 b' class FrontendWidget(HistoryConsoleWidget, BaseFrontendMixin):' | |||
|
366 | 370 | """ Handle shutdown signal, only if from other console. |
|
367 | 371 | """ |
|
368 | 372 | if not self._hidden and not self._is_from_this_session(msg): |
|
369 | if not msg['content']['restart']: | |
|
370 | sys.exit(0) | |
|
371 | else: | |
|
372 | # we just got notified of a restart! | |
|
373 | time.sleep(0.25) # wait 1/4 sec to reset | |
|
374 | # lest the request for a new prompt | |
|
375 |
|
|
|
376 | self.reset() | |
|
373 | if self._local_kernel: | |
|
374 | if not msg['content']['restart']: | |
|
375 | sys.exit(0) | |
|
376 | else: | |
|
377 | # we just got notified of a restart! | |
|
378 | time.sleep(0.25) # wait 1/4 sec to reset | |
|
379 | # lest the request for a new prompt | |
|
380 | # goes to the old kernel | |
|
381 | self.reset() | |
|
382 | else: # remote kernel, prompt on Kernel shutdown/reset | |
|
383 | title = self.window().windowTitle() | |
|
384 | if not msg['content']['restart']: | |
|
385 | reply = QtGui.QMessageBox.question(self, title, | |
|
386 | "Kernel has been shutdown permanently. Close the Console?", | |
|
387 | QtGui.QMessageBox.Yes,QtGui.QMessageBox.No) | |
|
388 | if reply == QtGui.QMessageBox.Yes: | |
|
389 | sys.exit(0) | |
|
390 | else: | |
|
391 | reply = QtGui.QMessageBox.question(self, title, | |
|
392 | "Kernel has been reset. Clear the Console?", | |
|
393 | QtGui.QMessageBox.Yes,QtGui.QMessageBox.No) | |
|
394 | if reply == QtGui.QMessageBox.Yes: | |
|
395 | time.sleep(0.25) # wait 1/4 sec to reset | |
|
396 | # lest the request for a new prompt | |
|
397 | # goes to the old kernel | |
|
398 | self.reset() | |
|
377 | 399 | |
|
378 | 400 | def _started_channels(self): |
|
379 | 401 | """ Called when the KernelManager channels have started listening or |
@@ -16,10 +16,10 b' from IPython.frontend.qt.console.rich_ipython_widget import RichIPythonWidget' | |||
|
16 | 16 | from IPython.frontend.qt.kernelmanager import QtKernelManager |
|
17 | 17 | |
|
18 | 18 | #----------------------------------------------------------------------------- |
|
19 | # Constants | |
|
19 | # Network Constants | |
|
20 | 20 | #----------------------------------------------------------------------------- |
|
21 | 21 | |
|
22 | LOCALHOST = '127.0.0.1' | |
|
22 | from IPython.utils.localinterfaces import LOCALHOST, LOCAL_IPS | |
|
23 | 23 | |
|
24 | 24 | #----------------------------------------------------------------------------- |
|
25 | 25 | # Classes |
@@ -31,18 +31,24 b' class MainWindow(QtGui.QMainWindow):' | |||
|
31 | 31 | # 'object' interface |
|
32 | 32 | #--------------------------------------------------------------------------- |
|
33 | 33 | |
|
34 | def __init__(self, app, frontend, existing=False): | |
|
34 | def __init__(self, app, frontend, existing=False, may_close=True): | |
|
35 | 35 | """ Create a MainWindow for the specified FrontendWidget. |
|
36 | 36 | |
|
37 | 37 | The app is passed as an argument to allow for different |
|
38 | 38 | closing behavior depending on whether we are the Kernel's parent. |
|
39 | 39 | |
|
40 |
If existing is True, then this |
|
|
40 | If existing is True, then this Console does not own the Kernel. | |
|
41 | ||
|
42 | If may_close is True, then this Console is permitted to close the kernel | |
|
41 | 43 | """ |
|
42 | 44 | super(MainWindow, self).__init__() |
|
43 | 45 | self._app = app |
|
44 | 46 | self._frontend = frontend |
|
45 | 47 | self._existing = existing |
|
48 | if existing: | |
|
49 | self._may_close = may_close | |
|
50 | else: | |
|
51 | self._may_close = True | |
|
46 | 52 | self._frontend.exit_requested.connect(self.close) |
|
47 | 53 | self.setCentralWidget(frontend) |
|
48 | 54 | |
@@ -56,21 +62,47 b' class MainWindow(QtGui.QMainWindow):' | |||
|
56 | 62 | kernel_manager = self._frontend.kernel_manager |
|
57 | 63 | if kernel_manager and kernel_manager.channels_running: |
|
58 | 64 | title = self.window().windowTitle() |
|
59 |
|
|
|
60 | "Close just this console, or shutdown the kernel and close "+ | |
|
61 | "all windows attached to it?", | |
|
62 | 'Cancel', 'Close Console', 'Close All') | |
|
63 | if reply == 2: # close All | |
|
64 | kernel_manager.shutdown_kernel() | |
|
65 | #kernel_manager.stop_channels() | |
|
66 | event.accept() | |
|
67 | elif reply == 1: # close Console | |
|
68 | if not self._existing: | |
|
69 | # I have the kernel: don't quit, just close the window | |
|
70 | self._app.setQuitOnLastWindowClosed(False) | |
|
71 | event.accept() | |
|
65 | cancel = QtGui.QMessageBox.Cancel | |
|
66 | okay = QtGui.QMessageBox.Ok | |
|
67 | if self._may_close: | |
|
68 | msg = "You are closing this Console window." | |
|
69 | info = "Would you like to quit the Kernel and all attached Consoles as well?" | |
|
70 | justthis = QtGui.QPushButton("&No, just this Console", self) | |
|
71 | justthis.setShortcut('N') | |
|
72 | closeall = QtGui.QPushButton("&Yes, quit everything", self) | |
|
73 | closeall.setShortcut('Y') | |
|
74 | box = QtGui.QMessageBox(QtGui.QMessageBox.Question, title, msg) | |
|
75 | box.setInformativeText(info) | |
|
76 | box.addButton(cancel) | |
|
77 | box.addButton(justthis, QtGui.QMessageBox.NoRole) | |
|
78 | box.addButton(closeall, QtGui.QMessageBox.YesRole) | |
|
79 | box.setDefaultButton(closeall) | |
|
80 | box.setEscapeButton(cancel) | |
|
81 | reply = box.exec_() | |
|
82 | if reply == 1: # close All | |
|
83 | kernel_manager.shutdown_kernel() | |
|
84 | #kernel_manager.stop_channels() | |
|
85 | event.accept() | |
|
86 | elif reply == 0: # close Console | |
|
87 | if not self._existing: | |
|
88 | # I have the kernel: don't quit, just close the window | |
|
89 | self._app.setQuitOnLastWindowClosed(False) | |
|
90 | self.deleteLater() | |
|
91 | event.accept() | |
|
92 | else: | |
|
93 | event.ignore() | |
|
72 | 94 | else: |
|
73 | event.ignore() | |
|
95 | reply = QtGui.QMessageBox.question(self, title, | |
|
96 | "Are you sure you want to close this Console?"+ | |
|
97 | "\nThe Kernel and other Consoles will remain active.", | |
|
98 | okay|cancel, | |
|
99 | defaultButton=okay | |
|
100 | ) | |
|
101 | if reply == okay: | |
|
102 | event.accept() | |
|
103 | else: | |
|
104 | event.ignore() | |
|
105 | ||
|
74 | 106 | |
|
75 | 107 | #----------------------------------------------------------------------------- |
|
76 | 108 | # Main entry point |
@@ -85,7 +117,11 b' def main():' | |||
|
85 | 117 | kgroup.add_argument('-e', '--existing', action='store_true', |
|
86 | 118 | help='connect to an existing kernel') |
|
87 | 119 | kgroup.add_argument('--ip', type=str, default=LOCALHOST, |
|
88 | help='set the kernel\'s IP address [default localhost]') | |
|
120 | help=\ | |
|
121 | "set the kernel\'s IP address [default localhost].\ | |
|
122 | If the IP address is something other than localhost, then \ | |
|
123 | Consoles on other machines will be able to connect\ | |
|
124 | to the Kernel, so be careful!") | |
|
89 | 125 | kgroup.add_argument('--xreq', type=int, metavar='PORT', default=0, |
|
90 | 126 | help='set the XREQ channel port [default random]') |
|
91 | 127 | kgroup.add_argument('--sub', type=int, metavar='PORT', default=0, |
@@ -124,29 +160,34 b' def main():' | |||
|
124 | 160 | sub_address=(args.ip, args.sub), |
|
125 | 161 | rep_address=(args.ip, args.rep), |
|
126 | 162 | hb_address=(args.ip, args.hb)) |
|
127 |
if |
|
|
163 | if not args.existing: | |
|
164 | # if not args.ip in LOCAL_IPS+ALL_ALIAS: | |
|
165 | # raise ValueError("Must bind a local ip, such as: %s"%LOCAL_IPS) | |
|
166 | ||
|
167 | kwargs = dict(ip=args.ip) | |
|
128 | 168 | if args.pure: |
|
129 |
k |
|
|
169 | kwargs['ipython']=False | |
|
130 | 170 | elif args.pylab: |
|
131 |
k |
|
|
132 |
|
|
|
133 |
|
|
|
171 | kwargs['pylab']=args.pylab | |
|
172 | ||
|
173 | kernel_manager.start_kernel(**kwargs) | |
|
134 | 174 | kernel_manager.start_channels() |
|
135 | 175 | |
|
176 | local_kernel = (not args.existing) or args.ip in LOCAL_IPS | |
|
136 | 177 | # Create the widget. |
|
137 | 178 | app = QtGui.QApplication([]) |
|
138 | 179 | if args.pure: |
|
139 | 180 | kind = 'rich' if args.rich else 'plain' |
|
140 | widget = FrontendWidget(kind=kind, paging=args.paging) | |
|
181 | widget = FrontendWidget(kind=kind, paging=args.paging, local_kernel=local_kernel) | |
|
141 | 182 | elif args.rich or args.pylab: |
|
142 | widget = RichIPythonWidget(paging=args.paging) | |
|
183 | widget = RichIPythonWidget(paging=args.paging, local_kernel=local_kernel) | |
|
143 | 184 | else: |
|
144 | widget = IPythonWidget(paging=args.paging) | |
|
185 | widget = IPythonWidget(paging=args.paging, local_kernel=local_kernel) | |
|
145 | 186 | widget.gui_completion = args.gui_completion |
|
146 | 187 | widget.kernel_manager = kernel_manager |
|
147 | 188 | |
|
148 | 189 | # Create the main window. |
|
149 | window = MainWindow(app, widget, args.existing) | |
|
190 | window = MainWindow(app, widget, args.existing, may_close=local_kernel) | |
|
150 | 191 | window.setWindowTitle('Python' if args.pure else 'IPython') |
|
151 | 192 | window.show() |
|
152 | 193 |
@@ -16,6 +16,7 b' import zmq' | |||
|
16 | 16 | from IPython.core.ultratb import FormattedTB |
|
17 | 17 | from IPython.external.argparse import ArgumentParser |
|
18 | 18 | from IPython.utils import io |
|
19 | from IPython.utils.localinterfaces import LOCALHOST | |
|
19 | 20 | from displayhook import DisplayHook |
|
20 | 21 | from heartbeat import Heartbeat |
|
21 | 22 | from iostream import OutStream |
@@ -40,7 +41,7 b' def make_argument_parser():' | |||
|
40 | 41 | kernel entry points. |
|
41 | 42 | """ |
|
42 | 43 | parser = ArgumentParser() |
|
43 |
parser.add_argument('--ip', type=str, default= |
|
|
44 | parser.add_argument('--ip', type=str, default=LOCALHOST, | |
|
44 | 45 | help='set the kernel\'s IP address [default: local]') |
|
45 | 46 | parser.add_argument('--xrep', type=int, metavar='PORT', default=0, |
|
46 | 47 | help='set the XREP channel port [default: random]') |
@@ -17,6 +17,7 b' import uuid' | |||
|
17 | 17 | import zmq |
|
18 | 18 | import session |
|
19 | 19 | import completer |
|
20 | from IPython.utils.localinterfaces import LOCALHOST | |
|
20 | 21 | |
|
21 | 22 | #----------------------------------------------------------------------------- |
|
22 | 23 | # Classes and functions |
@@ -168,7 +169,7 b' class InteractiveClient(object):' | |||
|
168 | 169 | def main(): |
|
169 | 170 | # Defaults |
|
170 | 171 | #ip = '192.168.2.109' |
|
171 | ip = '127.0.0.1' | |
|
172 | ip = LOCALHOST | |
|
172 | 173 | #ip = '99.146.222.252' |
|
173 | 174 | port_base = 5575 |
|
174 | 175 | connection = ('tcp://%s' % ip) + ':%i' |
@@ -17,6 +17,8 b' from threading import Thread' | |||
|
17 | 17 | |
|
18 | 18 | import zmq |
|
19 | 19 | |
|
20 | from IPython.utils.localinterfaces import LOCALHOST | |
|
21 | ||
|
20 | 22 | #----------------------------------------------------------------------------- |
|
21 | 23 | # Code |
|
22 | 24 | #----------------------------------------------------------------------------- |
@@ -25,7 +27,7 b' import zmq' | |||
|
25 | 27 | class Heartbeat(Thread): |
|
26 | 28 | "A simple ping-pong style heartbeat that runs in a thread." |
|
27 | 29 | |
|
28 |
def __init__(self, context, addr=( |
|
|
30 | def __init__(self, context, addr=(LOCALHOST, 0)): | |
|
29 | 31 | Thread.__init__(self) |
|
30 | 32 | self.context = context |
|
31 | 33 | self.addr = addr |
@@ -534,12 +534,15 b' class GTKKernel(Kernel):' | |||
|
534 | 534 | # Kernel main and launch functions |
|
535 | 535 | #----------------------------------------------------------------------------- |
|
536 | 536 | |
|
537 | def launch_kernel(xrep_port=0, pub_port=0, req_port=0, hb_port=0, | |
|
537 | def launch_kernel(ip=None, xrep_port=0, pub_port=0, req_port=0, hb_port=0, | |
|
538 | 538 | independent=False, pylab=False): |
|
539 | 539 | """Launches a localhost kernel, binding to the specified ports. |
|
540 | 540 | |
|
541 | 541 | Parameters |
|
542 | 542 | ---------- |
|
543 | ip : str, optional | |
|
544 | The ip address the kernel will bind to. | |
|
545 | ||
|
543 | 546 | xrep_port : int, optional |
|
544 | 547 | The port to use for XREP channel. |
|
545 | 548 | |
@@ -574,6 +577,10 b' def launch_kernel(xrep_port=0, pub_port=0, req_port=0, hb_port=0,' | |||
|
574 | 577 | extra_arguments.append('--pylab') |
|
575 | 578 | if isinstance(pylab, basestring): |
|
576 | 579 | extra_arguments.append(pylab) |
|
580 | if ip is not None: | |
|
581 | extra_arguments.append('--ip') | |
|
582 | if isinstance(ip, basestring): | |
|
583 | extra_arguments.append(ip) | |
|
577 | 584 | return base_launch_kernel('from IPython.zmq.ipkernel import main; main()', |
|
578 | 585 | xrep_port, pub_port, req_port, hb_port, |
|
579 | 586 | independent, extra_arguments) |
@@ -31,6 +31,7 b' from zmq.eventloop import ioloop' | |||
|
31 | 31 | |
|
32 | 32 | # Local imports. |
|
33 | 33 | from IPython.utils import io |
|
34 | from IPython.utils.localinterfaces import LOCALHOST, LOCAL_IPS | |
|
34 | 35 | from IPython.utils.traitlets import HasTraits, Any, Instance, Type, TCPAddress |
|
35 | 36 | from session import Session |
|
36 | 37 | |
@@ -38,8 +39,6 b' from session import Session' | |||
|
38 | 39 | # Constants and exceptions |
|
39 | 40 | #----------------------------------------------------------------------------- |
|
40 | 41 | |
|
41 | LOCALHOST = '127.0.0.1' | |
|
42 | ||
|
43 | 42 | class InvalidPortNumber(Exception): |
|
44 | 43 | pass |
|
45 | 44 | |
@@ -724,24 +723,26 b' class KernelManager(HasTraits):' | |||
|
724 | 723 | """ |
|
725 | 724 | xreq, sub, rep, hb = self.xreq_address, self.sub_address, \ |
|
726 | 725 | self.rep_address, self.hb_address |
|
727 |
if xreq[0] |
|
|
728 |
rep[0] |
|
|
729 |
raise RuntimeError("Can only launch a kernel on |
|
|
726 | if xreq[0] not in LOCAL_IPS or sub[0] not in LOCAL_IPS or \ | |
|
727 | rep[0] not in LOCAL_IPS or hb[0] not in LOCAL_IPS: | |
|
728 | raise RuntimeError("Can only launch a kernel on a local interface. " | |
|
730 | 729 | "Make sure that the '*_address' attributes are " |
|
731 |
"configured properly." |
|
|
732 | ||
|
730 | "configured properly. " | |
|
731 | "Currently valid addresses are: %s"%LOCAL_IPS | |
|
732 | ) | |
|
733 | ||
|
733 | 734 | self._launch_args = kw.copy() |
|
734 | 735 | if kw.pop('ipython', True): |
|
735 | 736 | from ipkernel import launch_kernel |
|
736 | 737 | else: |
|
737 | 738 | from pykernel import launch_kernel |
|
738 | self.kernel, xrep, pub, req, hb = launch_kernel( | |
|
739 | self.kernel, xrep, pub, req, _hb = launch_kernel( | |
|
739 | 740 | xrep_port=xreq[1], pub_port=sub[1], |
|
740 | 741 | req_port=rep[1], hb_port=hb[1], **kw) |
|
741 |
self.xreq_address = ( |
|
|
742 |
self.sub_address = ( |
|
|
743 |
self.rep_address = ( |
|
|
744 |
self.hb_address = ( |
|
|
742 | self.xreq_address = (xreq[0], xrep) | |
|
743 | self.sub_address = (sub[0], pub) | |
|
744 | self.rep_address = (rep[0], req) | |
|
745 | self.hb_address = (hb[0], _hb) | |
|
745 | 746 | |
|
746 | 747 | def shutdown_kernel(self, restart=False): |
|
747 | 748 | """ Attempts to the stop the kernel process cleanly. If the kernel |
@@ -256,12 +256,15 b' class Kernel(HasTraits):' | |||
|
256 | 256 | # Kernel main and launch functions |
|
257 | 257 | #----------------------------------------------------------------------------- |
|
258 | 258 | |
|
259 | def launch_kernel(xrep_port=0, pub_port=0, req_port=0, hb_port=0, | |
|
259 | def launch_kernel(ip=None, xrep_port=0, pub_port=0, req_port=0, hb_port=0, | |
|
260 | 260 | independent=False): |
|
261 | 261 | """ Launches a localhost kernel, binding to the specified ports. |
|
262 | 262 | |
|
263 | 263 | Parameters |
|
264 | 264 | ---------- |
|
265 | ip : str, optional | |
|
266 | The ip address the kernel will bind to. | |
|
267 | ||
|
265 | 268 | xrep_port : int, optional |
|
266 | 269 | The port to use for XREP channel. |
|
267 | 270 | |
@@ -286,9 +289,15 b' def launch_kernel(xrep_port=0, pub_port=0, req_port=0, hb_port=0,' | |||
|
286 | 289 | (kernel_process, xrep_port, pub_port, req_port) |
|
287 | 290 | where kernel_process is a Popen object and the ports are integers. |
|
288 | 291 | """ |
|
292 | extra_arguments = [] | |
|
293 | if ip is not None: | |
|
294 | extra_arguments.append('--ip') | |
|
295 | if isinstance(ip, basestring): | |
|
296 | extra_arguments.append(ip) | |
|
297 | ||
|
289 | 298 | return base_launch_kernel('from IPython.zmq.pykernel import main; main()', |
|
290 | 299 | xrep_port, pub_port, req_port, hb_port, |
|
291 | independent) | |
|
300 | independent, extra_arguments=extra_arguments) | |
|
292 | 301 | |
|
293 | 302 | main = make_default_main(Kernel) |
|
294 | 303 |
General Comments 0
You need to be logged in to leave comments.
Login now