##// END OF EJS Templates
prevent remote frontends from closing the kernel
MinRK -
Show More
@@ -1,160 +1,178 b''
1 1 """ A minimal application using the Qt console-style IPython frontend.
2 2 """
3 3
4 4 #-----------------------------------------------------------------------------
5 5 # Imports
6 6 #-----------------------------------------------------------------------------
7 7
8 8 # Systemm library imports
9 9 from PyQt4 import QtGui
10 10
11 11 # Local imports
12 12 from IPython.external.argparse import ArgumentParser
13 13 from IPython.frontend.qt.console.frontend_widget import FrontendWidget
14 14 from IPython.frontend.qt.console.ipython_widget import IPythonWidget
15 15 from IPython.frontend.qt.console.rich_ipython_widget import RichIPythonWidget
16 16 from IPython.frontend.qt.kernelmanager import QtKernelManager
17 17
18 18 #-----------------------------------------------------------------------------
19 19 # Constants
20 20 #-----------------------------------------------------------------------------
21 21
22 22 LOCALHOST = '127.0.0.1'
23 23
24 24 #-----------------------------------------------------------------------------
25 25 # Classes
26 26 #-----------------------------------------------------------------------------
27 27
28 28 class MainWindow(QtGui.QMainWindow):
29 29
30 30 #---------------------------------------------------------------------------
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 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 44 super(MainWindow, self).__init__()
43 45 self._app = app
44 46 self._frontend = frontend
45 47 self._existing = existing
48 if not 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
49 55 #---------------------------------------------------------------------------
50 56 # QWidget interface
51 57 #---------------------------------------------------------------------------
52 58
53 59 def closeEvent(self, event):
54 60 """ Reimplemented to prompt the user and close the kernel cleanly.
55 61 """
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 reply = QtGui.QMessageBox.question(self, title,
60 "You are closing this Console window."+
61 "\nWould you like to quit the Kernel and all attached Consoles as well?",
62 'Cancel', 'No, just this Console', 'Yes, quit everything')
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 self.deleteLater()
72 event.accept()
65 if self._may_close:
66 reply = QtGui.QMessageBox.question(self, title,
67 "You are closing this Console window."+
68 "\nWould you like to quit the Kernel and all attached Consoles as well?",
69 'Cancel', 'No, just this Console', 'Yes, quit everything')
70 if reply == 2: # close All
71 kernel_manager.shutdown_kernel()
72 #kernel_manager.stop_channels()
73 event.accept()
74 elif reply == 1: # close Console
75 if not self._existing:
76 # I have the kernel: don't quit, just close the window
77 self._app.setQuitOnLastWindowClosed(False)
78 self.deleteLater()
79 event.accept()
80 else:
81 event.ignore()
73 82 else:
74 event.ignore()
83 reply = QtGui.QMessageBox.question(self, title,
84 "Are you sure you want to close this Console?\n"+
85 "The Kernel and other Consoles will remain active.",
86 QtGui.QMessageBox.Yes, QtGui.QMessageBox.No
87 )
88 if reply == QtGui.QMessageBox.Yes:
89 event.accept()
90 else:
91 event.ignore()
92
75 93
76 94 #-----------------------------------------------------------------------------
77 95 # Main entry point
78 96 #-----------------------------------------------------------------------------
79 97
80 98 def main():
81 99 """ Entry point for application.
82 100 """
83 101 # Parse command line arguments.
84 102 parser = ArgumentParser()
85 103 kgroup = parser.add_argument_group('kernel options')
86 104 kgroup.add_argument('-e', '--existing', action='store_true',
87 105 help='connect to an existing kernel')
88 106 kgroup.add_argument('--ip', type=str, default=LOCALHOST,
89 107 help='set the kernel\'s IP address [default localhost]')
90 108 kgroup.add_argument('--xreq', type=int, metavar='PORT', default=0,
91 109 help='set the XREQ channel port [default random]')
92 110 kgroup.add_argument('--sub', type=int, metavar='PORT', default=0,
93 111 help='set the SUB channel port [default random]')
94 112 kgroup.add_argument('--rep', type=int, metavar='PORT', default=0,
95 113 help='set the REP channel port [default random]')
96 114 kgroup.add_argument('--hb', type=int, metavar='PORT', default=0,
97 115 help='set the heartbeat port [default: random]')
98 116
99 117 egroup = kgroup.add_mutually_exclusive_group()
100 118 egroup.add_argument('--pure', action='store_true', help = \
101 119 'use a pure Python kernel instead of an IPython kernel')
102 120 egroup.add_argument('--pylab', type=str, metavar='GUI', nargs='?',
103 121 const='auto', help = \
104 122 "Pre-load matplotlib and numpy for interactive use. If GUI is not \
105 123 given, the GUI backend is matplotlib's, otherwise use one of: \
106 124 ['tk', 'gtk', 'qt', 'wx', 'inline'].")
107 125
108 126 wgroup = parser.add_argument_group('widget options')
109 127 wgroup.add_argument('--paging', type=str, default='inside',
110 128 choices = ['inside', 'hsplit', 'vsplit', 'none'],
111 129 help='set the paging style [default inside]')
112 130 wgroup.add_argument('--rich', action='store_true',
113 131 help='enable rich text support')
114 132 wgroup.add_argument('--gui-completion', action='store_true',
115 133 help='use a GUI widget for tab completion')
116 134
117 135 args = parser.parse_args()
118 136
119 137 # Don't let Qt or ZMQ swallow KeyboardInterupts.
120 138 import signal
121 139 signal.signal(signal.SIGINT, signal.SIG_DFL)
122 140
123 141 # Create a KernelManager and start a kernel.
124 142 kernel_manager = QtKernelManager(xreq_address=(args.ip, args.xreq),
125 143 sub_address=(args.ip, args.sub),
126 144 rep_address=(args.ip, args.rep),
127 145 hb_address=(args.ip, args.hb))
128 if args.ip == LOCALHOST and not args.existing:
146 if not args.existing:
129 147 if args.pure:
130 148 kernel_manager.start_kernel(ipython=False)
131 149 elif args.pylab:
132 150 kernel_manager.start_kernel(pylab=args.pylab)
133 151 else:
134 152 kernel_manager.start_kernel()
135 153 kernel_manager.start_channels()
136 154
137 local_kernel = (args.ip == LOCALHOST)
155 local_kernel = (not args.existing) or args.ip == LOCALHOST
138 156 # Create the widget.
139 157 app = QtGui.QApplication([])
140 158 if args.pure:
141 159 kind = 'rich' if args.rich else 'plain'
142 160 widget = FrontendWidget(kind=kind, paging=args.paging, local_kernel=local_kernel)
143 161 elif args.rich or args.pylab:
144 162 widget = RichIPythonWidget(paging=args.paging, local_kernel=local_kernel)
145 163 else:
146 164 widget = IPythonWidget(paging=args.paging, local_kernel=local_kernel)
147 165 widget.gui_completion = args.gui_completion
148 166 widget.kernel_manager = kernel_manager
149 167
150 168 # Create the main window.
151 window = MainWindow(app, widget, args.existing)
169 window = MainWindow(app, widget, args.existing, may_close=local_kernel)
152 170 window.setWindowTitle('Python' if args.pure else 'IPython')
153 171 window.show()
154 172
155 173 # Start the application main loop.
156 174 app.exec_()
157 175
158 176
159 177 if __name__ == '__main__':
160 178 main()
General Comments 0
You need to be logged in to leave comments. Login now