##// END OF EJS Templates
Merge branch 'minrk-keepkernel' into trunk...
Fernando Perez -
r3169:dc30beec merge
parent child Browse files
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 _CompletionRequest = namedtuple('_CompletionRequest', ['id', 'pos'])
101 _CompletionRequest = namedtuple('_CompletionRequest', ['id', 'pos'])
102 _ExecutionRequest = namedtuple('_ExecutionRequest', ['id', 'kind'])
102 _ExecutionRequest = namedtuple('_ExecutionRequest', ['id', 'kind'])
103 _input_splitter_class = InputSplitter
103 _input_splitter_class = InputSplitter
104 _local_kernel = False
104
105
105 #---------------------------------------------------------------------------
106 #---------------------------------------------------------------------------
106 # 'object' interface
107 # 'object' interface
@@ -141,6 +142,9 b' class FrontendWidget(HistoryConsoleWidget, BaseFrontendMixin):'
141 # Connect signal handlers.
142 # Connect signal handlers.
142 document = self._control.document()
143 document = self._control.document()
143 document.contentsChange.connect(self._document_contents_change)
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 # 'ConsoleWidget' public interface
150 # 'ConsoleWidget' public interface
@@ -366,14 +370,32 b' class FrontendWidget(HistoryConsoleWidget, BaseFrontendMixin):'
366 """ Handle shutdown signal, only if from other console.
370 """ Handle shutdown signal, only if from other console.
367 """
371 """
368 if not self._hidden and not self._is_from_this_session(msg):
372 if not self._hidden and not self._is_from_this_session(msg):
369 if not msg['content']['restart']:
373 if self._local_kernel:
370 sys.exit(0)
374 if not msg['content']['restart']:
371 else:
375 sys.exit(0)
372 # we just got notified of a restart!
376 else:
373 time.sleep(0.25) # wait 1/4 sec to reset
377 # we just got notified of a restart!
374 # lest the request for a new prompt
378 time.sleep(0.25) # wait 1/4 sec to reset
375 # goes to the old kernel
379 # lest the request for a new prompt
376 self.reset()
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 def _started_channels(self):
400 def _started_channels(self):
379 """ Called when the KernelManager channels have started listening or
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 from IPython.frontend.qt.kernelmanager import QtKernelManager
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 # Classes
25 # Classes
@@ -31,18 +31,24 b' class MainWindow(QtGui.QMainWindow):'
31 # 'object' interface
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 """ Create a MainWindow for the specified FrontendWidget.
35 """ Create a MainWindow for the specified FrontendWidget.
36
36
37 The app is passed as an argument to allow for different
37 The app is passed as an argument to allow for different
38 closing behavior depending on whether we are the Kernel's parent.
38 closing behavior depending on whether we are the Kernel's parent.
39
39
40 If existing is True, then this Window does not own the Kernel.
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 super(MainWindow, self).__init__()
44 super(MainWindow, self).__init__()
43 self._app = app
45 self._app = app
44 self._frontend = frontend
46 self._frontend = frontend
45 self._existing = existing
47 self._existing = existing
48 if existing:
49 self._may_close = may_close
50 else:
51 self._may_close = True
46 self._frontend.exit_requested.connect(self.close)
52 self._frontend.exit_requested.connect(self.close)
47 self.setCentralWidget(frontend)
53 self.setCentralWidget(frontend)
48
54
@@ -56,21 +62,47 b' class MainWindow(QtGui.QMainWindow):'
56 kernel_manager = self._frontend.kernel_manager
62 kernel_manager = self._frontend.kernel_manager
57 if kernel_manager and kernel_manager.channels_running:
63 if kernel_manager and kernel_manager.channels_running:
58 title = self.window().windowTitle()
64 title = self.window().windowTitle()
59 reply = QtGui.QMessageBox.question(self, title,
65 cancel = QtGui.QMessageBox.Cancel
60 "Close just this console, or shutdown the kernel and close "+
66 okay = QtGui.QMessageBox.Ok
61 "all windows attached to it?",
67 if self._may_close:
62 'Cancel', 'Close Console', 'Close All')
68 msg = "You are closing this Console window."
63 if reply == 2: # close All
69 info = "Would you like to quit the Kernel and all attached Consoles as well?"
64 kernel_manager.shutdown_kernel()
70 justthis = QtGui.QPushButton("&No, just this Console", self)
65 #kernel_manager.stop_channels()
71 justthis.setShortcut('N')
66 event.accept()
72 closeall = QtGui.QPushButton("&Yes, quit everything", self)
67 elif reply == 1: # close Console
73 closeall.setShortcut('Y')
68 if not self._existing:
74 box = QtGui.QMessageBox(QtGui.QMessageBox.Question, title, msg)
69 # I have the kernel: don't quit, just close the window
75 box.setInformativeText(info)
70 self._app.setQuitOnLastWindowClosed(False)
76 box.addButton(cancel)
71 event.accept()
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 else:
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 # Main entry point
108 # Main entry point
@@ -85,7 +117,11 b' def main():'
85 kgroup.add_argument('-e', '--existing', action='store_true',
117 kgroup.add_argument('-e', '--existing', action='store_true',
86 help='connect to an existing kernel')
118 help='connect to an existing kernel')
87 kgroup.add_argument('--ip', type=str, default=LOCALHOST,
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 kgroup.add_argument('--xreq', type=int, metavar='PORT', default=0,
125 kgroup.add_argument('--xreq', type=int, metavar='PORT', default=0,
90 help='set the XREQ channel port [default random]')
126 help='set the XREQ channel port [default random]')
91 kgroup.add_argument('--sub', type=int, metavar='PORT', default=0,
127 kgroup.add_argument('--sub', type=int, metavar='PORT', default=0,
@@ -124,29 +160,34 b' def main():'
124 sub_address=(args.ip, args.sub),
160 sub_address=(args.ip, args.sub),
125 rep_address=(args.ip, args.rep),
161 rep_address=(args.ip, args.rep),
126 hb_address=(args.ip, args.hb))
162 hb_address=(args.ip, args.hb))
127 if args.ip == LOCALHOST and not args.existing:
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 if args.pure:
168 if args.pure:
129 kernel_manager.start_kernel(ipython=False)
169 kwargs['ipython']=False
130 elif args.pylab:
170 elif args.pylab:
131 kernel_manager.start_kernel(pylab=args.pylab)
171 kwargs['pylab']=args.pylab
132 else:
172
133 kernel_manager.start_kernel()
173 kernel_manager.start_kernel(**kwargs)
134 kernel_manager.start_channels()
174 kernel_manager.start_channels()
135
175
176 local_kernel = (not args.existing) or args.ip in LOCAL_IPS
136 # Create the widget.
177 # Create the widget.
137 app = QtGui.QApplication([])
178 app = QtGui.QApplication([])
138 if args.pure:
179 if args.pure:
139 kind = 'rich' if args.rich else 'plain'
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 elif args.rich or args.pylab:
182 elif args.rich or args.pylab:
142 widget = RichIPythonWidget(paging=args.paging)
183 widget = RichIPythonWidget(paging=args.paging, local_kernel=local_kernel)
143 else:
184 else:
144 widget = IPythonWidget(paging=args.paging)
185 widget = IPythonWidget(paging=args.paging, local_kernel=local_kernel)
145 widget.gui_completion = args.gui_completion
186 widget.gui_completion = args.gui_completion
146 widget.kernel_manager = kernel_manager
187 widget.kernel_manager = kernel_manager
147
188
148 # Create the main window.
189 # Create the main window.
149 window = MainWindow(app, widget, args.existing)
190 window = MainWindow(app, widget, args.existing, may_close=local_kernel)
150 window.setWindowTitle('Python' if args.pure else 'IPython')
191 window.setWindowTitle('Python' if args.pure else 'IPython')
151 window.show()
192 window.show()
152
193
@@ -16,6 +16,7 b' import zmq'
16 from IPython.core.ultratb import FormattedTB
16 from IPython.core.ultratb import FormattedTB
17 from IPython.external.argparse import ArgumentParser
17 from IPython.external.argparse import ArgumentParser
18 from IPython.utils import io
18 from IPython.utils import io
19 from IPython.utils.localinterfaces import LOCALHOST
19 from displayhook import DisplayHook
20 from displayhook import DisplayHook
20 from heartbeat import Heartbeat
21 from heartbeat import Heartbeat
21 from iostream import OutStream
22 from iostream import OutStream
@@ -40,7 +41,7 b' def make_argument_parser():'
40 kernel entry points.
41 kernel entry points.
41 """
42 """
42 parser = ArgumentParser()
43 parser = ArgumentParser()
43 parser.add_argument('--ip', type=str, default='127.0.0.1',
44 parser.add_argument('--ip', type=str, default=LOCALHOST,
44 help='set the kernel\'s IP address [default: local]')
45 help='set the kernel\'s IP address [default: local]')
45 parser.add_argument('--xrep', type=int, metavar='PORT', default=0,
46 parser.add_argument('--xrep', type=int, metavar='PORT', default=0,
46 help='set the XREP channel port [default: random]')
47 help='set the XREP channel port [default: random]')
@@ -17,6 +17,7 b' import uuid'
17 import zmq
17 import zmq
18 import session
18 import session
19 import completer
19 import completer
20 from IPython.utils.localinterfaces import LOCALHOST
20
21
21 #-----------------------------------------------------------------------------
22 #-----------------------------------------------------------------------------
22 # Classes and functions
23 # Classes and functions
@@ -168,7 +169,7 b' class InteractiveClient(object):'
168 def main():
169 def main():
169 # Defaults
170 # Defaults
170 #ip = '192.168.2.109'
171 #ip = '192.168.2.109'
171 ip = '127.0.0.1'
172 ip = LOCALHOST
172 #ip = '99.146.222.252'
173 #ip = '99.146.222.252'
173 port_base = 5575
174 port_base = 5575
174 connection = ('tcp://%s' % ip) + ':%i'
175 connection = ('tcp://%s' % ip) + ':%i'
@@ -17,6 +17,8 b' from threading import Thread'
17
17
18 import zmq
18 import zmq
19
19
20 from IPython.utils.localinterfaces import LOCALHOST
21
20 #-----------------------------------------------------------------------------
22 #-----------------------------------------------------------------------------
21 # Code
23 # Code
22 #-----------------------------------------------------------------------------
24 #-----------------------------------------------------------------------------
@@ -25,7 +27,7 b' import zmq'
25 class Heartbeat(Thread):
27 class Heartbeat(Thread):
26 "A simple ping-pong style heartbeat that runs in a thread."
28 "A simple ping-pong style heartbeat that runs in a thread."
27
29
28 def __init__(self, context, addr=('127.0.0.1', 0)):
30 def __init__(self, context, addr=(LOCALHOST, 0)):
29 Thread.__init__(self)
31 Thread.__init__(self)
30 self.context = context
32 self.context = context
31 self.addr = addr
33 self.addr = addr
@@ -534,12 +534,15 b' class GTKKernel(Kernel):'
534 # Kernel main and launch functions
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 independent=False, pylab=False):
538 independent=False, pylab=False):
539 """Launches a localhost kernel, binding to the specified ports.
539 """Launches a localhost kernel, binding to the specified ports.
540
540
541 Parameters
541 Parameters
542 ----------
542 ----------
543 ip : str, optional
544 The ip address the kernel will bind to.
545
543 xrep_port : int, optional
546 xrep_port : int, optional
544 The port to use for XREP channel.
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 extra_arguments.append('--pylab')
577 extra_arguments.append('--pylab')
575 if isinstance(pylab, basestring):
578 if isinstance(pylab, basestring):
576 extra_arguments.append(pylab)
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 return base_launch_kernel('from IPython.zmq.ipkernel import main; main()',
584 return base_launch_kernel('from IPython.zmq.ipkernel import main; main()',
578 xrep_port, pub_port, req_port, hb_port,
585 xrep_port, pub_port, req_port, hb_port,
579 independent, extra_arguments)
586 independent, extra_arguments)
@@ -31,6 +31,7 b' from zmq.eventloop import ioloop'
31
31
32 # Local imports.
32 # Local imports.
33 from IPython.utils import io
33 from IPython.utils import io
34 from IPython.utils.localinterfaces import LOCALHOST, LOCAL_IPS
34 from IPython.utils.traitlets import HasTraits, Any, Instance, Type, TCPAddress
35 from IPython.utils.traitlets import HasTraits, Any, Instance, Type, TCPAddress
35 from session import Session
36 from session import Session
36
37
@@ -38,8 +39,6 b' from session import Session'
38 # Constants and exceptions
39 # Constants and exceptions
39 #-----------------------------------------------------------------------------
40 #-----------------------------------------------------------------------------
40
41
41 LOCALHOST = '127.0.0.1'
42
43 class InvalidPortNumber(Exception):
42 class InvalidPortNumber(Exception):
44 pass
43 pass
45
44
@@ -724,24 +723,26 b' class KernelManager(HasTraits):'
724 """
723 """
725 xreq, sub, rep, hb = self.xreq_address, self.sub_address, \
724 xreq, sub, rep, hb = self.xreq_address, self.sub_address, \
726 self.rep_address, self.hb_address
725 self.rep_address, self.hb_address
727 if xreq[0] != LOCALHOST or sub[0] != LOCALHOST or \
726 if xreq[0] not in LOCAL_IPS or sub[0] not in LOCAL_IPS or \
728 rep[0] != LOCALHOST or hb[0] != LOCALHOST:
727 rep[0] not in LOCAL_IPS or hb[0] not in LOCAL_IPS:
729 raise RuntimeError("Can only launch a kernel on localhost."
728 raise RuntimeError("Can only launch a kernel on a local interface. "
730 "Make sure that the '*_address' attributes are "
729 "Make sure that the '*_address' attributes are "
731 "configured properly.")
730 "configured properly. "
732
731 "Currently valid addresses are: %s"%LOCAL_IPS
732 )
733
733 self._launch_args = kw.copy()
734 self._launch_args = kw.copy()
734 if kw.pop('ipython', True):
735 if kw.pop('ipython', True):
735 from ipkernel import launch_kernel
736 from ipkernel import launch_kernel
736 else:
737 else:
737 from pykernel import launch_kernel
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 xrep_port=xreq[1], pub_port=sub[1],
740 xrep_port=xreq[1], pub_port=sub[1],
740 req_port=rep[1], hb_port=hb[1], **kw)
741 req_port=rep[1], hb_port=hb[1], **kw)
741 self.xreq_address = (LOCALHOST, xrep)
742 self.xreq_address = (xreq[0], xrep)
742 self.sub_address = (LOCALHOST, pub)
743 self.sub_address = (sub[0], pub)
743 self.rep_address = (LOCALHOST, req)
744 self.rep_address = (rep[0], req)
744 self.hb_address = (LOCALHOST, hb)
745 self.hb_address = (hb[0], _hb)
745
746
746 def shutdown_kernel(self, restart=False):
747 def shutdown_kernel(self, restart=False):
747 """ Attempts to the stop the kernel process cleanly. If the kernel
748 """ Attempts to the stop the kernel process cleanly. If the kernel
@@ -256,12 +256,15 b' class Kernel(HasTraits):'
256 # Kernel main and launch functions
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 independent=False):
260 independent=False):
261 """ Launches a localhost kernel, binding to the specified ports.
261 """ Launches a localhost kernel, binding to the specified ports.
262
262
263 Parameters
263 Parameters
264 ----------
264 ----------
265 ip : str, optional
266 The ip address the kernel will bind to.
267
265 xrep_port : int, optional
268 xrep_port : int, optional
266 The port to use for XREP channel.
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 (kernel_process, xrep_port, pub_port, req_port)
289 (kernel_process, xrep_port, pub_port, req_port)
287 where kernel_process is a Popen object and the ports are integers.
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 return base_launch_kernel('from IPython.zmq.pykernel import main; main()',
298 return base_launch_kernel('from IPython.zmq.pykernel import main; main()',
290 xrep_port, pub_port, req_port, hb_port,
299 xrep_port, pub_port, req_port, hb_port,
291 independent)
300 independent, extra_arguments=extra_arguments)
292
301
293 main = make_default_main(Kernel)
302 main = make_default_main(Kernel)
294
303
General Comments 0
You need to be logged in to leave comments. Login now