##// END OF EJS Templates
Notebook app debugging....
Brian E. Granger -
Show More
@@ -1,186 +1,182 b''
1 """A kernel manager for multiple kernels."""
1 """A kernel manager for multiple kernels."""
2
2
3 #-----------------------------------------------------------------------------
3 #-----------------------------------------------------------------------------
4 # Imports
4 # Imports
5 #-----------------------------------------------------------------------------
5 #-----------------------------------------------------------------------------
6
6
7 import logging
7 import logging
8 import signal
8 import signal
9 import sys
9 import sys
10 import uuid
10 import uuid
11
11
12 import zmq
12 import zmq
13
13
14 from IPython.config.configurable import Configurable
14 from IPython.config.configurable import LoggingConfigurable
15 from IPython.zmq.ipkernel import launch_kernel
15 from IPython.zmq.ipkernel import launch_kernel
16 from IPython.utils.traitlets import Instance, Dict, Unicode
16 from IPython.utils.traitlets import Instance, Dict, Unicode
17
17
18 #-----------------------------------------------------------------------------
18 #-----------------------------------------------------------------------------
19 # Classes
19 # Classes
20 #-----------------------------------------------------------------------------
20 #-----------------------------------------------------------------------------
21
21
22 class DuplicateKernelError(Exception):
22 class DuplicateKernelError(Exception):
23 pass
23 pass
24
24
25
25
26 class KernelManager(Configurable):
26 class KernelManager(LoggingConfigurable):
27 """A class for managing multiple kernels."""
27 """A class for managing multiple kernels."""
28
28
29 context = Instance('zmq.Context')
29 context = Instance('zmq.Context')
30 def _context_default(self):
30 def _context_default(self):
31 return zmq.Context.instance()
31 return zmq.Context.instance()
32
32
33 logname = Unicode('')
34 def _logname_changed(self, name, old, new):
35 self.log = logging.getLogger(new)
36
37 _kernels = Dict()
33 _kernels = Dict()
38
34
39 @property
35 @property
40 def kernel_ids(self):
36 def kernel_ids(self):
41 """Return a list of the kernel ids of the active kernels."""
37 """Return a list of the kernel ids of the active kernels."""
42 return self._kernels.keys()
38 return self._kernels.keys()
43
39
44 def __len__(self):
40 def __len__(self):
45 """Return the number of running kernels."""
41 """Return the number of running kernels."""
46 return len(self.kernel_ids)
42 return len(self.kernel_ids)
47
43
48 def __contains__(self, kernel_id):
44 def __contains__(self, kernel_id):
49 if kernel_id in self.kernel_ids:
45 if kernel_id in self.kernel_ids:
50 return True
46 return True
51 else:
47 else:
52 return False
48 return False
53
49
54 def start_kernel(self, **kwargs):
50 def start_kernel(self, **kwargs):
55 """Start a new kernel."""
51 """Start a new kernel."""
56 kernel_id = str(uuid.uuid4())
52 kernel_id = str(uuid.uuid4())
57 (process, shell_port, iopub_port, stdin_port, hb_port) = launch_kernel(**kwargs)
53 (process, shell_port, iopub_port, stdin_port, hb_port) = launch_kernel(**kwargs)
58 # Store the information for contacting the kernel. This assumes the kernel is
54 # Store the information for contacting the kernel. This assumes the kernel is
59 # running on localhost.
55 # running on localhost.
60 d = dict(
56 d = dict(
61 process = process,
57 process = process,
62 stdin_port = stdin_port,
58 stdin_port = stdin_port,
63 iopub_port = iopub_port,
59 iopub_port = iopub_port,
64 shell_port = shell_port,
60 shell_port = shell_port,
65 hb_port = hb_port,
61 hb_port = hb_port,
66 ip = '127.0.0.1'
62 ip = '127.0.0.1'
67 )
63 )
68 self._kernels[kernel_id] = d
64 self._kernels[kernel_id] = d
69 return kernel_id
65 return kernel_id
70
66
71 def kill_kernel(self, kernel_id):
67 def kill_kernel(self, kernel_id):
72 """Kill a kernel by its kernel uuid.
68 """Kill a kernel by its kernel uuid.
73
69
74 Parameters
70 Parameters
75 ==========
71 ==========
76 kernel_id : uuid
72 kernel_id : uuid
77 The id of the kernel to kill.
73 The id of the kernel to kill.
78 """
74 """
79 kernel_process = self.get_kernel_process(kernel_id)
75 kernel_process = self.get_kernel_process(kernel_id)
80 if kernel_process is not None:
76 if kernel_process is not None:
81 # Attempt to kill the kernel.
77 # Attempt to kill the kernel.
82 try:
78 try:
83 kernel_process.kill()
79 kernel_process.kill()
84 except OSError, e:
80 except OSError, e:
85 # In Windows, we will get an Access Denied error if the process
81 # In Windows, we will get an Access Denied error if the process
86 # has already terminated. Ignore it.
82 # has already terminated. Ignore it.
87 if not (sys.platform == 'win32' and e.winerror == 5):
83 if not (sys.platform == 'win32' and e.winerror == 5):
88 raise
84 raise
89 del self._kernels[kernel_id]
85 del self._kernels[kernel_id]
90
86
91 def interrupt_kernel(self, kernel_id):
87 def interrupt_kernel(self, kernel_id):
92 """Interrupt (SIGINT) the kernel by its uuid.
88 """Interrupt (SIGINT) the kernel by its uuid.
93
89
94 Parameters
90 Parameters
95 ==========
91 ==========
96 kernel_id : uuid
92 kernel_id : uuid
97 The id of the kernel to interrupt.
93 The id of the kernel to interrupt.
98 """
94 """
99 kernel_process = self.get_kernel_process(kernel_id)
95 kernel_process = self.get_kernel_process(kernel_id)
100 if kernel_process is not None:
96 if kernel_process is not None:
101 if sys.platform == 'win32':
97 if sys.platform == 'win32':
102 from parentpoller import ParentPollerWindows as Poller
98 from parentpoller import ParentPollerWindows as Poller
103 Poller.send_interrupt(kernel_process.win32_interrupt_event)
99 Poller.send_interrupt(kernel_process.win32_interrupt_event)
104 else:
100 else:
105 kernel_process.send_signal(signal.SIGINT)
101 kernel_process.send_signal(signal.SIGINT)
106
102
107 def signal_kernel(self, kernel_id, signum):
103 def signal_kernel(self, kernel_id, signum):
108 """ Sends a signal to the kernel by its uuid.
104 """ Sends a signal to the kernel by its uuid.
109
105
110 Note that since only SIGTERM is supported on Windows, this function
106 Note that since only SIGTERM is supported on Windows, this function
111 is only useful on Unix systems.
107 is only useful on Unix systems.
112
108
113 Parameters
109 Parameters
114 ==========
110 ==========
115 kernel_id : uuid
111 kernel_id : uuid
116 The id of the kernel to signal.
112 The id of the kernel to signal.
117 """
113 """
118 kernel_process = self.get_kernel_process(kernel_id)
114 kernel_process = self.get_kernel_process(kernel_id)
119 if kernel_process is not None:
115 if kernel_process is not None:
120 kernel_process.send_signal(signum)
116 kernel_process.send_signal(signum)
121
117
122 def get_kernel_process(self, kernel_id):
118 def get_kernel_process(self, kernel_id):
123 """Get the process object for a kernel by its uuid.
119 """Get the process object for a kernel by its uuid.
124
120
125 Parameters
121 Parameters
126 ==========
122 ==========
127 kernel_id : uuid
123 kernel_id : uuid
128 The id of the kernel.
124 The id of the kernel.
129 """
125 """
130 d = self._kernels.get(kernel_id)
126 d = self._kernels.get(kernel_id)
131 if d is not None:
127 if d is not None:
132 return d['process']
128 return d['process']
133 else:
129 else:
134 raise KeyError("Kernel with id not found: %s" % kernel_id)
130 raise KeyError("Kernel with id not found: %s" % kernel_id)
135
131
136 def get_kernel_ports(self, kernel_id):
132 def get_kernel_ports(self, kernel_id):
137 """Return a dictionary of ports for a kernel.
133 """Return a dictionary of ports for a kernel.
138
134
139 Parameters
135 Parameters
140 ==========
136 ==========
141 kernel_id : uuid
137 kernel_id : uuid
142 The id of the kernel.
138 The id of the kernel.
143
139
144 Returns
140 Returns
145 =======
141 =======
146 port_dict : dict
142 port_dict : dict
147 A dict of key, value pairs where the keys are the names
143 A dict of key, value pairs where the keys are the names
148 (stdin_port,iopub_port,shell_port) and the values are the
144 (stdin_port,iopub_port,shell_port) and the values are the
149 integer port numbers for those channels.
145 integer port numbers for those channels.
150 """
146 """
151 d = self._kernels.get(kernel_id)
147 d = self._kernels.get(kernel_id)
152 if d is not None:
148 if d is not None:
153 dcopy = d.copy()
149 dcopy = d.copy()
154 dcopy.pop('process')
150 dcopy.pop('process')
155 dcopy.pop('ip')
151 dcopy.pop('ip')
156 return dcopy
152 return dcopy
157 else:
153 else:
158 raise KeyError("Kernel with id not found: %s" % kernel_id)
154 raise KeyError("Kernel with id not found: %s" % kernel_id)
159
155
160 def get_kernel_ip(self, kernel_id):
156 def get_kernel_ip(self, kernel_id):
161 """Return ip address for a kernel.
157 """Return ip address for a kernel.
162
158
163 Parameters
159 Parameters
164 ==========
160 ==========
165 kernel_id : uuid
161 kernel_id : uuid
166 The id of the kernel.
162 The id of the kernel.
167
163
168 Returns
164 Returns
169 =======
165 =======
170 ip : str
166 ip : str
171 The ip address of the kernel.
167 The ip address of the kernel.
172 """
168 """
173 d = self._kernels.get(kernel_id)
169 d = self._kernels.get(kernel_id)
174 if d is not None:
170 if d is not None:
175 return d['ip']
171 return d['ip']
176 else:
172 else:
177 raise KeyError("Kernel with id not found: %s" % kernel_id)
173 raise KeyError("Kernel with id not found: %s" % kernel_id)
178
174
179 def create_session_manager(self, kernel_id):
175 def create_session_manager(self, kernel_id):
180 """Create a new session manager for a kernel by its uuid."""
176 """Create a new session manager for a kernel by its uuid."""
181 from sessionmanager import SessionManager
177 from sessionmanager import SessionManager
182 return SessionManager(
178 return SessionManager(
183 kernel_id=kernel_id, kernel_manager=self,
179 kernel_id=kernel_id, kernel_manager=self,
184 config=self.config, context=self.context, logname=self.logname
180 config=self.config, context=self.context, log=self.log
185 )
181 )
186
182
@@ -1,220 +1,247 b''
1 """A tornado based IPython notebook server."""
1 """A tornado based IPython notebook server."""
2
2
3 #-----------------------------------------------------------------------------
3 #-----------------------------------------------------------------------------
4 # Imports
4 # Imports
5 #-----------------------------------------------------------------------------
5 #-----------------------------------------------------------------------------
6
6
7 import logging
7 import logging
8 import os
8 import os
9 import signal
10 import sys
9
11
10 import zmq
12 import zmq
11
13
12 # Install the pyzmq ioloop. This has to be done before anything else from
14 # Install the pyzmq ioloop. This has to be done before anything else from
13 # tornado is imported.
15 # tornado is imported.
14 from zmq.eventloop import ioloop
16 from zmq.eventloop import ioloop
15 import tornado.ioloop
17 import tornado.ioloop
16 tornado.ioloop = ioloop
18 tornado.ioloop = ioloop
17
19
18 from tornado import httpserver
20 from tornado import httpserver
19 from tornado import options
20 from tornado import web
21 from tornado import web
21
22
22 from kernelmanager import KernelManager
23 from kernelmanager import KernelManager
23 from sessionmanager import SessionManager
24 from sessionmanager import SessionManager
24 from handlers import (
25 from handlers import (
25 MainHandler, KernelHandler, KernelActionHandler, ZMQStreamHandler,
26 MainHandler, KernelHandler, KernelActionHandler, ZMQStreamHandler,
26 NotebookRootHandler, NotebookHandler
27 NotebookRootHandler, NotebookHandler
27 )
28 )
28 from routers import IOPubStreamRouter, ShellStreamRouter
29 from routers import IOPubStreamRouter, ShellStreamRouter
29
30
30 from IPython.core.application import BaseIPythonApplication
31 from IPython.core.application import BaseIPythonApplication
32 from IPython.core.profiledir import ProfileDir
33 from IPython.frontend.qt.console.rich_ipython_widget import RichIPythonWidget
31 from IPython.zmq.session import Session
34 from IPython.zmq.session import Session
35 from IPython.zmq.zmqshell import ZMQInteractiveShell
36 from IPython.zmq.ipkernel import (
37 flags as ipkernel_flags,
38 aliases as ipkernel_aliases,
39 IPKernelApp
40 )
41 from IPython.utils.traitlets import Dict, Unicode, Int, Any, List, Enum
32
42
33 #-----------------------------------------------------------------------------
43 #-----------------------------------------------------------------------------
34 # Module globals
44 # Module globals
35 #-----------------------------------------------------------------------------
45 #-----------------------------------------------------------------------------
36
46
37 _kernel_id_regex = r"(?P<kernel_id>\w+-\w+-\w+-\w+-\w+)"
47 _kernel_id_regex = r"(?P<kernel_id>\w+-\w+-\w+-\w+-\w+)"
38 _kernel_action_regex = r"(?P<action>restart|interrupt)"
48 _kernel_action_regex = r"(?P<action>restart|interrupt)"
39
49
50 LOCALHOST = '127.0.0.1'
51
40 #-----------------------------------------------------------------------------
52 #-----------------------------------------------------------------------------
41 # The Tornado web application
53 # The Tornado web application
42 #-----------------------------------------------------------------------------
54 #-----------------------------------------------------------------------------
43
55
44 class NotebookWebApplication(web.Application):
56 class NotebookWebApplication(web.Application):
45
57
46 def __init__(self, kernel_manager, log):
58 def __init__(self, kernel_manager, log, kernel_argv):
47 handlers = [
59 handlers = [
48 (r"/", MainHandler),
60 (r"/", MainHandler),
49 (r"/kernels", KernelHandler),
61 (r"/kernels", KernelHandler),
50 (r"/kernels/%s/%s" % (_kernel_id_regex, _kernel_action_regex), KernelActionHandler),
62 (r"/kernels/%s/%s" % (_kernel_id_regex, _kernel_action_regex), KernelActionHandler),
51 (r"/kernels/%s/iopub" % _kernel_id_regex, ZMQStreamHandler, dict(stream_name='iopub')),
63 (r"/kernels/%s/iopub" % _kernel_id_regex, ZMQStreamHandler, dict(stream_name='iopub')),
52 (r"/kernels/%s/shell" % _kernel_id_regex, ZMQStreamHandler, dict(stream_name='shell')),
64 (r"/kernels/%s/shell" % _kernel_id_regex, ZMQStreamHandler, dict(stream_name='shell')),
53 (r"/notebooks", NotebookRootHandler),
65 (r"/notebooks", NotebookRootHandler),
54 (r"/notebooks/([^/]+)", NotebookHandler)
66 (r"/notebooks/([^/]+)", NotebookHandler)
55 ]
67 ]
56 settings = dict(
68 settings = dict(
57 template_path=os.path.join(os.path.dirname(__file__), "templates"),
69 template_path=os.path.join(os.path.dirname(__file__), "templates"),
58 static_path=os.path.join(os.path.dirname(__file__), "static"),
70 static_path=os.path.join(os.path.dirname(__file__), "static"),
59 )
71 )
60 web.Application.__init__(self, handlers, **settings)
72 web.Application.__init__(self, handlers, **settings)
61
73
62 self.kernel_manager = kernel_manager
74 self.kernel_manager = kernel_manager
63 self.log = log
75 self.log = log
76 self.kernel_argv = kernel_argv
64 self._routers = {}
77 self._routers = {}
78 self._session_dict = {}
65
79
66 #-------------------------------------------------------------------------
80 #-------------------------------------------------------------------------
67 # Methods for managing kernels and sessions
81 # Methods for managing kernels and sessions
68 #-------------------------------------------------------------------------
82 #-------------------------------------------------------------------------
69
83
70 @property
84 @property
71 def kernel_ids(self):
85 def kernel_ids(self):
72 return self.kernel_manager.kernel_ids
86 return self.kernel_manager.kernel_ids
73
87
74 def start_kernel(self):
88 def start_kernel(self):
75 # TODO: pass command line options to the kernel in start_kernel()
89 kwargs = dict()
76 kernel_id = self.kernel_manager.start_kernel()
90 kwargs['extra_arguments'] = self.kernel_argv
91 kernel_id = self.kernel_manager.start_kernel(**kwargs)
77 self.log.info("Kernel started: %s" % kernel_id)
92 self.log.info("Kernel started: %s" % kernel_id)
93 self.log.debug("Kernel args: %r" % kwargs)
78 self.start_session_manager(kernel_id)
94 self.start_session_manager(kernel_id)
79 return kernel_id
95 return kernel_id
80
96
81 def start_session_manager(self, kernel_id):
97 def start_session_manager(self, kernel_id):
82 sm = self.kernel_manager.create_session_manager(kernel_id)
98 sm = self.kernel_manager.create_session_manager(kernel_id)
83 self._session_dict[kernel_id] = sm
99 self._session_dict[kernel_id] = sm
84 iopub_stream = sm.get_iopub_stream()
100 iopub_stream = sm.get_iopub_stream()
85 shell_stream = sm.get_shell_stream()
101 shell_stream = sm.get_shell_stream()
86 iopub_router = IOPubStreamRouter(iopub_stream)
102 iopub_router = IOPubStreamRouter(iopub_stream)
87 shell_router = ShellStreamRouter(shell_stream)
103 shell_router = ShellStreamRouter(shell_stream)
88 self._routers[(kernel_id, 'iopub')] = iopub_router
104 self._routers[(kernel_id, 'iopub')] = iopub_router
89 self._routers[(kernel_id, 'shell')] = shell_router
105 self._routers[(kernel_id, 'shell')] = shell_router
90 self.log.debug("Session manager started for kernel: %s" % kernel_id)
91
106
92 def kill_kernel(self, kernel_id):
107 def kill_kernel(self, kernel_id):
93 sm = self._session_dict.pop(kernel_id)
108 sm = self._session_dict.pop(kernel_id)
94 sm.stop()
109 sm.stop()
95 self.kernel_manager.kill_kernel(kernel_id)
110 self.kernel_manager.kill_kernel(kernel_id)
96 self.log.info("Kernel killed: %s" % kernel_id)
111 self.log.info("Kernel killed: %s" % kernel_id)
97
112
98 def interrupt_kernel(self, kernel_id):
113 def interrupt_kernel(self, kernel_id):
99 self.kernel_manager.interrupt_kernel(kernel_id)
114 self.kernel_manager.interrupt_kernel(kernel_id)
100 self.log.debug("Kernel interrupted: %s" % kernel_id)
115 self.log.debug("Kernel interrupted: %s" % kernel_id)
101
116
102 def restart_kernel(self, kernel_id):
117 def restart_kernel(self, kernel_id):
103 # Create the new kernel first so we can move the clients over.
118 # Create the new kernel first so we can move the clients over.
104 new_kernel_id = self.start_kernel()
119 new_kernel_id = self.start_kernel()
105
120
106 # Copy the clients over to the new routers.
121 # Copy the clients over to the new routers.
107 old_iopub_router = self.get_router(kernel_id, 'iopub')
122 old_iopub_router = self.get_router(kernel_id, 'iopub')
108 old_shell_router = self.get_router(kernel_id, 'shell')
123 old_shell_router = self.get_router(kernel_id, 'shell')
109 new_iopub_router = self.get_router(new_kernel_id, 'iopub')
124 new_iopub_router = self.get_router(new_kernel_id, 'iopub')
110 new_shell_router = self.get_router(new_kernel_id, 'shell')
125 new_shell_router = self.get_router(new_kernel_id, 'shell')
111 new_iopub_router.copy_clients(old_iopub_router)
126 new_iopub_router.copy_clients(old_iopub_router)
112 new_shell_router.copy_clients(old_shell_router)
127 new_shell_router.copy_clients(old_shell_router)
113
128
114 # Now shutdown the old session and the kernel.
129 # Now shutdown the old session and the kernel.
115 # TODO: This causes a hard crash in ZMQStream.close, which sets
130 # TODO: This causes a hard crash in ZMQStream.close, which sets
116 # self.socket to None to hastily. We will need to fix this in PyZMQ
131 # self.socket to None to hastily. We will need to fix this in PyZMQ
117 # itself. For now, we just leave the old kernel running :(
132 # itself. For now, we just leave the old kernel running :(
118 # self.kill_kernel(kernel_id)
133 # self.kill_kernel(kernel_id)
119
134
120 self.log.debug("Kernel restarted: %s -> %s" % (kernel_id, new_kernel_id))
135 self.log.debug("Kernel restarted: %s -> %s" % (kernel_id, new_kernel_id))
121 return new_kernel_id
136 return new_kernel_id
122
137
123 def get_router(self, kernel_id, stream_name):
138 def get_router(self, kernel_id, stream_name):
124 router = self._routers[(kernel_id, stream_name)]
139 router = self._routers[(kernel_id, stream_name)]
125 return router
140 return router
126
141
127 #-----------------------------------------------------------------------------
142 #-----------------------------------------------------------------------------
128 # Aliases and Flags
143 # Aliases and Flags
129 #-----------------------------------------------------------------------------
144 #-----------------------------------------------------------------------------
130
145
131 flags = dict(ipkernel_flags)
146 flags = dict(ipkernel_flags)
132
147
133 # the flags that are specific to the frontend
148 # the flags that are specific to the frontend
134 # these must be scrubbed before being passed to the kernel,
149 # these must be scrubbed before being passed to the kernel,
135 # or it will raise an error on unrecognized flags
150 # or it will raise an error on unrecognized flags
136 notebook_flags = []
151 notebook_flags = []
137
152
138 aliases = dict(ipkernel_aliases)
153 aliases = dict(ipkernel_aliases)
139
154
140 aliases.update(dict(
155 aliases.update(dict(
141 ip = 'IPythonNotebookApp.ip',
156 ip = 'IPythonNotebookApp.ip',
142 port = 'IPythonNotebookApp.port'
157 port = 'IPythonNotebookApp.port',
143 colors = 'ZMQInteractiveShell.colors',
158 colors = 'ZMQInteractiveShell.colors',
144 editor = 'IPythonWidget.editor',
159 editor = 'RichIPythonWidget.editor',
145 ))
160 ))
146
161
147 #-----------------------------------------------------------------------------
162 #-----------------------------------------------------------------------------
148 # IPythonNotebookApp
163 # IPythonNotebookApp
149 #-----------------------------------------------------------------------------
164 #-----------------------------------------------------------------------------
150
165
151 class IPythonNotebookApp(BaseIPythonApplication):
166 class IPythonNotebookApp(BaseIPythonApplication):
152 name = 'ipython-notebook'
167 name = 'ipython-notebook'
153 default_config_file_name='ipython_notebook_config.py'
168 default_config_file_name='ipython_notebook_config.py'
154
169
155 description = """
170 description = """
156 The IPython HTML Notebook.
171 The IPython HTML Notebook.
157
172
158 This launches a Tornado based HTML Notebook Server that serves up an
173 This launches a Tornado based HTML Notebook Server that serves up an
159 HTML5/Javascript Notebook client.
174 HTML5/Javascript Notebook client.
160 """
175 """
161
176
162 classes = [IPKernelApp, ZMQInteractiveShell, ProfileDir, Session,
177 classes = [IPKernelApp, ZMQInteractiveShell, ProfileDir, Session,
163 KernelManager, SessionManager]
178 KernelManager, SessionManager, RichIPythonWidget]
164 flags = Dict(flags)
179 flags = Dict(flags)
165 aliases = Dict(aliases)
180 aliases = Dict(aliases)
166
181
167 kernel_argv = List(Unicode)
182 kernel_argv = List(Unicode)
168
183
184 log_level = Enum((0,10,20,30,40,50,'DEBUG','INFO','WARN','ERROR','CRITICAL'),
185 default_value=logging.INFO,
186 config=True,
187 help="Set the log level by value or name.")
188
169 # connection info:
189 # connection info:
170 ip = Unicode(LOCALHOST, config=True,
190 ip = Unicode(LOCALHOST, config=True,
171 help="The IP address the notebook server will listen on."
191 help="The IP address the notebook server will listen on."
172 )
192 )
173
193
174 port = Int(8888, config=True,
194 port = Int(8888, config=True,
175 help="The port the notebook server will listen on."
195 help="The port the notebook server will listen on."
176 )
196 )
177
197
178 # the factory for creating a widget
198 # the factory for creating a widget
179 widget_factory = Any(RichIPythonWidget)
199 widget_factory = Any(RichIPythonWidget)
180
200
181 def parse_command_line(self, argv=None):
201 def parse_command_line(self, argv=None):
182 super(IPythonNotebookApp, self).parse_command_line(argv)
202 super(IPythonNotebookApp, self).parse_command_line(argv)
183 if argv is None:
203 if argv is None:
184 argv = sys.argv[1:]
204 argv = sys.argv[1:]
185
205
186 self.kernel_argv = list(argv) # copy
206 self.kernel_argv = list(argv) # copy
187 # kernel should inherit default config file from frontend
207 # kernel should inherit default config file from frontend
188 self.kernel_argv.append("KernelApp.parent_appname='%s'"%self.name)
208 self.kernel_argv.append("--KernelApp.parent_appname='%s'"%self.name)
189 # scrub frontend-specific flags
209 # scrub frontend-specific flags
190 for a in argv:
210 for a in argv:
191 if a.startswith('--') and a[2:] in qt_flags:
211 if a.startswith('-') and a.lstrip('-') in notebook_flags:
192 self.kernel_argv.remove(a)
212 self.kernel_argv.remove(a)
193
213
194 def init_kernel_manager(self):
214 def init_kernel_manager(self):
195 # Don't let Qt or ZMQ swallow KeyboardInterupts.
215 # Don't let Qt or ZMQ swallow KeyboardInterupts.
196 signal.signal(signal.SIGINT, signal.SIG_DFL)
216 signal.signal(signal.SIGINT, signal.SIG_DFL)
197
217
198 # Create a KernelManager and start a kernel.
218 # Create a KernelManager and start a kernel.
199 self.kernel_manager = KernelManager(config=self.config, log=self.log)
219 self.kernel_manager = KernelManager(config=self.config, log=self.log)
200
220
221 def init_logging(self):
222 super(IPythonNotebookApp, self).init_logging()
223 # This prevents double log messages because tornado use a root logger that
224 # self.log is a child of. The logging module dipatches log messages to a log
225 # and all of its ancenstors until propagate is set to False.
226 self.log.propagate = False
227
201 def initialize(self, argv=None):
228 def initialize(self, argv=None):
202 super(IPythonNotebookApp, self).initialize(argv)
229 super(IPythonNotebookApp, self).initialize(argv)
203 self.init_kernel_mananger()
230 self.init_kernel_manager()
204 self.web_app = NotebookWebApplication()
231 self.web_app = NotebookWebApplication(self.kernel_manager, self.log, self.kernel_argv)
205 self.http_server = httpserver.HTTPServer(self.web_app)
232 self.http_server = httpserver.HTTPServer(self.web_app)
206 self.http_server.listen(self.port)
233 self.http_server.listen(self.port)
207
234
208 def start(self):
235 def start(self):
209 self.log.info("The IPython Notebook is running at: http://%s:%i" % (self.ip, self.port))
236 self.log.info("The IPython Notebook is running at: http://%s:%i" % (self.ip, self.port))
210 ioloop.IOLoop.instance().start()
237 ioloop.IOLoop.instance().start()
211
238
212 #-----------------------------------------------------------------------------
239 #-----------------------------------------------------------------------------
213 # Main entry point
240 # Main entry point
214 #-----------------------------------------------------------------------------
241 #-----------------------------------------------------------------------------
215
242
216 def launch_new_instance():
243 def launch_new_instance():
217 app = IPythonNotebookApp()
244 app = IPythonNotebookApp()
218 app.initialize()
245 app.initialize()
219 app.start()
246 app.start()
220
247
@@ -1,83 +1,83 b''
1 """A manager for session and channels for a single kernel."""
1 """A manager for session and channels for a single kernel."""
2
2
3 #-----------------------------------------------------------------------------
3 #-----------------------------------------------------------------------------
4 # Imports
4 # Imports
5 #-----------------------------------------------------------------------------
5 #-----------------------------------------------------------------------------
6
6
7 import zmq
7 import zmq
8 from zmq.eventloop.zmqstream import ZMQStream
8 from zmq.eventloop.zmqstream import ZMQStream
9
9
10 from IPython.utils.traitlets import Instance, Dict, CBytes, Bool
10 from IPython.utils.traitlets import Instance, Dict, CBytes, Bool
11 from IPython.zmq.session import SessionFactory
11 from IPython.zmq.session import SessionFactory
12
12
13
13
14 class SessionManagerRunningError(Exception):
14 class SessionManagerRunningError(Exception):
15 pass
15 pass
16
16
17 #-----------------------------------------------------------------------------
17 #-----------------------------------------------------------------------------
18 # Classes
18 # Classes
19 #-----------------------------------------------------------------------------
19 #-----------------------------------------------------------------------------
20
20
21
21
22 class SessionManager(SessionFactory):
22 class SessionManager(SessionFactory):
23 """Manages a session for a kernel.
23 """Manages a session for a kernel.
24
24
25 The object manages a variety of things for a connection session to
25 The object manages a variety of things for a connection session to
26 a running kernel:
26 a running kernel:
27
27
28 * The set of channels or connected ZMQ streams to the kernel.
28 * The set of channels or connected ZMQ streams to the kernel.
29 * An IPython.zmq.session.Session object that manages send/recv logic
29 * An IPython.zmq.session.Session object that manages send/recv logic
30 for those channels.
30 for those channels.
31 """
31 """
32
32
33 kernel_manager = Instance('IPython.frontend.html.notebook.kernelmanager.KernelManager')
33 kernel_manager = Instance('IPython.frontend.html.notebook.kernelmanager.KernelManager')
34 kernel_id = CBytes(b'')
34 kernel_id = CBytes(b'')
35 _session_streams = Dict()
35 _session_streams = Dict()
36 _running = Bool(False)
36 _running = Bool(False)
37
37
38 def __init__(self, **kwargs):
38 def __init__(self, **kwargs):
39 kernel_id = kwargs.pop('kernel_id')
39 kernel_id = kwargs.pop('kernel_id')
40 super(SessionManager, self).__init__(**kwargs)
40 super(SessionManager, self).__init__(**kwargs)
41 self.kernel_id = kernel_id
41 self.kernel_id = kernel_id
42 self.start()
42 self.start()
43
43
44 def __del__(self):
44 def __del__(self):
45 self.stop()
45 self.stop()
46
46
47 def start(self):
47 def start(self):
48 if not self._running:
48 if not self._running:
49 ports = self.kernel_manager.get_kernel_ports(self.kernel_id)
49 ports = self.kernel_manager.get_kernel_ports(self.kernel_id)
50 iopub_stream = self.create_connected_stream(ports['iopub_port'], zmq.SUB)
50 iopub_stream = self.create_connected_stream(ports['iopub_port'], zmq.SUB)
51 iopub_stream.socket.setsockopt(zmq.SUBSCRIBE, b'')
51 iopub_stream.socket.setsockopt(zmq.SUBSCRIBE, b'')
52 shell_stream = self.create_connected_stream(ports['shell_port'], zmq.XREQ)
52 shell_stream = self.create_connected_stream(ports['shell_port'], zmq.XREQ)
53 self._session_streams = dict(
53 self._session_streams = dict(
54 iopub_stream = iopub_stream,
54 iopub_stream = iopub_stream,
55 shell_stream = shell_stream
55 shell_stream = shell_stream
56 )
56 )
57 self._running = True
57 self._running = True
58 else:
58 else:
59 raise SessionManagerRunningError(
59 raise SessionManagerRunningError(
60 'Session manager is already running, call stop() before start()'
60 'Session manager is already running, call stop() before start()'
61 )
61 )
62
62
63 def stop(self):
63 def stop(self):
64 if self._running:
64 if self._running:
65 for name, stream in self._session_streams.items():
65 for name, stream in self._session_streams.items():
66 stream.close()
66 stream.close()
67 self._session_streams = {}
67 self._session_streams = {}
68 self._running = False
68 self._running = False
69
69
70 def create_connected_stream(self, port, socket_type):
70 def create_connected_stream(self, port, socket_type):
71 sock = self.context.socket(socket_type)
71 sock = self.context.socket(socket_type)
72 addr = "tcp://%s:%i" % (self.kernel_manager.get_kernel_ip(self.kernel_id), port)
72 addr = "tcp://%s:%i" % (self.kernel_manager.get_kernel_ip(self.kernel_id), port)
73 self.log.info("Connecting to: %s, %r" % (addr, socket_type))
73 self.log.info("Connecting to: %s" % addr)
74 sock.connect(addr)
74 sock.connect(addr)
75 return ZMQStream(sock)
75 return ZMQStream(sock)
76
76
77 def get_iopub_stream(self):
77 def get_iopub_stream(self):
78 return self._session_streams['iopub_stream']
78 return self._session_streams['iopub_stream']
79
79
80 def get_shell_stream(self):
80 def get_shell_stream(self):
81 return self._session_streams['shell_stream']
81 return self._session_streams['shell_stream']
82
82
83
83
@@ -1,377 +1,377 b''
1 #!/usr/bin/env python
1 #!/usr/bin/env python
2 # encoding: utf-8
2 # encoding: utf-8
3 """
3 """
4 The :class:`~IPython.core.application.Application` object for the command
4 The :class:`~IPython.core.application.Application` object for the command
5 line :command:`ipython` program.
5 line :command:`ipython` program.
6
6
7 Authors
7 Authors
8 -------
8 -------
9
9
10 * Brian Granger
10 * Brian Granger
11 * Fernando Perez
11 * Fernando Perez
12 * Min Ragan-Kelley
12 * Min Ragan-Kelley
13 """
13 """
14
14
15 #-----------------------------------------------------------------------------
15 #-----------------------------------------------------------------------------
16 # Copyright (C) 2008-2010 The IPython Development Team
16 # Copyright (C) 2008-2010 The IPython Development Team
17 #
17 #
18 # Distributed under the terms of the BSD License. The full license is in
18 # Distributed under the terms of the BSD License. The full license is in
19 # the file COPYING, distributed as part of this software.
19 # the file COPYING, distributed as part of this software.
20 #-----------------------------------------------------------------------------
20 #-----------------------------------------------------------------------------
21
21
22 #-----------------------------------------------------------------------------
22 #-----------------------------------------------------------------------------
23 # Imports
23 # Imports
24 #-----------------------------------------------------------------------------
24 #-----------------------------------------------------------------------------
25
25
26 from __future__ import absolute_import
26 from __future__ import absolute_import
27
27
28 import logging
28 import logging
29 import os
29 import os
30 import sys
30 import sys
31
31
32 from IPython.config.loader import (
32 from IPython.config.loader import (
33 Config, PyFileConfigLoader
33 Config, PyFileConfigLoader
34 )
34 )
35 from IPython.config.application import boolean_flag
35 from IPython.config.application import boolean_flag
36 from IPython.core import release
36 from IPython.core import release
37 from IPython.core import usage
37 from IPython.core import usage
38 from IPython.core.crashhandler import CrashHandler
38 from IPython.core.crashhandler import CrashHandler
39 from IPython.core.formatters import PlainTextFormatter
39 from IPython.core.formatters import PlainTextFormatter
40 from IPython.core.application import (
40 from IPython.core.application import (
41 ProfileDir, BaseIPythonApplication, base_flags, base_aliases
41 ProfileDir, BaseIPythonApplication, base_flags, base_aliases
42 )
42 )
43 from IPython.core.shellapp import (
43 from IPython.core.shellapp import (
44 InteractiveShellApp, shell_flags, shell_aliases
44 InteractiveShellApp, shell_flags, shell_aliases
45 )
45 )
46 from IPython.frontend.terminal.interactiveshell import TerminalInteractiveShell
46 from IPython.frontend.terminal.interactiveshell import TerminalInteractiveShell
47 from IPython.lib import inputhook
47 from IPython.lib import inputhook
48 from IPython.utils import warn
48 from IPython.utils import warn
49 from IPython.utils.path import get_ipython_dir, check_for_old_config
49 from IPython.utils.path import get_ipython_dir, check_for_old_config
50 from IPython.utils.traitlets import (
50 from IPython.utils.traitlets import (
51 Bool, Dict, CaselessStrEnum
51 Bool, Dict, CaselessStrEnum
52 )
52 )
53
53
54 #-----------------------------------------------------------------------------
54 #-----------------------------------------------------------------------------
55 # Globals, utilities and helpers
55 # Globals, utilities and helpers
56 #-----------------------------------------------------------------------------
56 #-----------------------------------------------------------------------------
57
57
58 #: The default config file name for this application.
58 #: The default config file name for this application.
59 default_config_file_name = u'ipython_config.py'
59 default_config_file_name = u'ipython_config.py'
60
60
61 _examples = """
61 _examples = """
62 ipython --pylab # start in pylab mode
62 ipython --pylab # start in pylab mode
63 ipython --pylab=qt # start in pylab mode with the qt4 backend
63 ipython --pylab=qt # start in pylab mode with the qt4 backend
64 ipython --log-level=DEBUG # set logging to DEBUG
64 ipython --log-level=DEBUG # set logging to DEBUG
65 ipython --profile=foo # start with profile foo
65 ipython --profile=foo # start with profile foo
66
66
67 ipython qtconsole # start the qtconsole GUI application
67 ipython qtconsole # start the qtconsole GUI application
68 ipython qtconsole -h # show the help string for the qtconsole subcmd
68 ipython qtconsole -h # show the help string for the qtconsole subcmd
69
69
70 ipython profile create foo # create profile foo w/ default config files
70 ipython profile create foo # create profile foo w/ default config files
71 ipython profile -h # show the help string for the profile subcmd
71 ipython profile -h # show the help string for the profile subcmd
72 """
72 """
73
73
74 #-----------------------------------------------------------------------------
74 #-----------------------------------------------------------------------------
75 # Crash handler for this application
75 # Crash handler for this application
76 #-----------------------------------------------------------------------------
76 #-----------------------------------------------------------------------------
77
77
78 class IPAppCrashHandler(CrashHandler):
78 class IPAppCrashHandler(CrashHandler):
79 """sys.excepthook for IPython itself, leaves a detailed report on disk."""
79 """sys.excepthook for IPython itself, leaves a detailed report on disk."""
80
80
81 def __init__(self, app):
81 def __init__(self, app):
82 contact_name = release.authors['Fernando'][0]
82 contact_name = release.authors['Fernando'][0]
83 contact_email = release.authors['Fernando'][1]
83 contact_email = release.authors['Fernando'][1]
84 bug_tracker = 'http://github.com/ipython/ipython/issues'
84 bug_tracker = 'http://github.com/ipython/ipython/issues'
85 super(IPAppCrashHandler,self).__init__(
85 super(IPAppCrashHandler,self).__init__(
86 app, contact_name, contact_email, bug_tracker
86 app, contact_name, contact_email, bug_tracker
87 )
87 )
88
88
89 def make_report(self,traceback):
89 def make_report(self,traceback):
90 """Return a string containing a crash report."""
90 """Return a string containing a crash report."""
91
91
92 sec_sep = self.section_sep
92 sec_sep = self.section_sep
93 # Start with parent report
93 # Start with parent report
94 report = [super(IPAppCrashHandler, self).make_report(traceback)]
94 report = [super(IPAppCrashHandler, self).make_report(traceback)]
95 # Add interactive-specific info we may have
95 # Add interactive-specific info we may have
96 rpt_add = report.append
96 rpt_add = report.append
97 try:
97 try:
98 rpt_add(sec_sep+"History of session input:")
98 rpt_add(sec_sep+"History of session input:")
99 for line in self.app.shell.user_ns['_ih']:
99 for line in self.app.shell.user_ns['_ih']:
100 rpt_add(line)
100 rpt_add(line)
101 rpt_add('\n*** Last line of input (may not be in above history):\n')
101 rpt_add('\n*** Last line of input (may not be in above history):\n')
102 rpt_add(self.app.shell._last_input_line+'\n')
102 rpt_add(self.app.shell._last_input_line+'\n')
103 except:
103 except:
104 pass
104 pass
105
105
106 return ''.join(report)
106 return ''.join(report)
107
107
108 #-----------------------------------------------------------------------------
108 #-----------------------------------------------------------------------------
109 # Aliases and Flags
109 # Aliases and Flags
110 #-----------------------------------------------------------------------------
110 #-----------------------------------------------------------------------------
111 flags = dict(base_flags)
111 flags = dict(base_flags)
112 flags.update(shell_flags)
112 flags.update(shell_flags)
113 addflag = lambda *args: flags.update(boolean_flag(*args))
113 addflag = lambda *args: flags.update(boolean_flag(*args))
114 addflag('autoedit-syntax', 'TerminalInteractiveShell.autoedit_syntax',
114 addflag('autoedit-syntax', 'TerminalInteractiveShell.autoedit_syntax',
115 'Turn on auto editing of files with syntax errors.',
115 'Turn on auto editing of files with syntax errors.',
116 'Turn off auto editing of files with syntax errors.'
116 'Turn off auto editing of files with syntax errors.'
117 )
117 )
118 addflag('banner', 'TerminalIPythonApp.display_banner',
118 addflag('banner', 'TerminalIPythonApp.display_banner',
119 "Display a banner upon starting IPython.",
119 "Display a banner upon starting IPython.",
120 "Don't display a banner upon starting IPython."
120 "Don't display a banner upon starting IPython."
121 )
121 )
122 addflag('confirm-exit', 'TerminalInteractiveShell.confirm_exit',
122 addflag('confirm-exit', 'TerminalInteractiveShell.confirm_exit',
123 """Set to confirm when you try to exit IPython with an EOF (Control-D
123 """Set to confirm when you try to exit IPython with an EOF (Control-D
124 in Unix, Control-Z/Enter in Windows). By typing 'exit' or 'quit',
124 in Unix, Control-Z/Enter in Windows). By typing 'exit' or 'quit',
125 you can force a direct exit without any confirmation.""",
125 you can force a direct exit without any confirmation.""",
126 "Don't prompt the user when exiting."
126 "Don't prompt the user when exiting."
127 )
127 )
128 addflag('term-title', 'TerminalInteractiveShell.term_title',
128 addflag('term-title', 'TerminalInteractiveShell.term_title',
129 "Enable auto setting the terminal title.",
129 "Enable auto setting the terminal title.",
130 "Disable auto setting the terminal title."
130 "Disable auto setting the terminal title."
131 )
131 )
132 classic_config = Config()
132 classic_config = Config()
133 classic_config.InteractiveShell.cache_size = 0
133 classic_config.InteractiveShell.cache_size = 0
134 classic_config.PlainTextFormatter.pprint = False
134 classic_config.PlainTextFormatter.pprint = False
135 classic_config.InteractiveShell.prompt_in1 = '>>> '
135 classic_config.InteractiveShell.prompt_in1 = '>>> '
136 classic_config.InteractiveShell.prompt_in2 = '... '
136 classic_config.InteractiveShell.prompt_in2 = '... '
137 classic_config.InteractiveShell.prompt_out = ''
137 classic_config.InteractiveShell.prompt_out = ''
138 classic_config.InteractiveShell.separate_in = ''
138 classic_config.InteractiveShell.separate_in = ''
139 classic_config.InteractiveShell.separate_out = ''
139 classic_config.InteractiveShell.separate_out = ''
140 classic_config.InteractiveShell.separate_out2 = ''
140 classic_config.InteractiveShell.separate_out2 = ''
141 classic_config.InteractiveShell.colors = 'NoColor'
141 classic_config.InteractiveShell.colors = 'NoColor'
142 classic_config.InteractiveShell.xmode = 'Plain'
142 classic_config.InteractiveShell.xmode = 'Plain'
143
143
144 flags['classic']=(
144 flags['classic']=(
145 classic_config,
145 classic_config,
146 "Gives IPython a similar feel to the classic Python prompt."
146 "Gives IPython a similar feel to the classic Python prompt."
147 )
147 )
148 # # log doesn't make so much sense this way anymore
148 # # log doesn't make so much sense this way anymore
149 # paa('--log','-l',
149 # paa('--log','-l',
150 # action='store_true', dest='InteractiveShell.logstart',
150 # action='store_true', dest='InteractiveShell.logstart',
151 # help="Start logging to the default log file (./ipython_log.py).")
151 # help="Start logging to the default log file (./ipython_log.py).")
152 #
152 #
153 # # quick is harder to implement
153 # # quick is harder to implement
154 flags['quick']=(
154 flags['quick']=(
155 {'TerminalIPythonApp' : {'quick' : True}},
155 {'TerminalIPythonApp' : {'quick' : True}},
156 "Enable quick startup with no config files."
156 "Enable quick startup with no config files."
157 )
157 )
158
158
159 flags['i'] = (
159 flags['i'] = (
160 {'TerminalIPythonApp' : {'force_interact' : True}},
160 {'TerminalIPythonApp' : {'force_interact' : True}},
161 """If running code from the command line, become interactive afterwards.
161 """If running code from the command line, become interactive afterwards.
162 Note: can also be given simply as '-i.'"""
162 Note: can also be given simply as '-i.'"""
163 )
163 )
164 flags['pylab'] = (
164 flags['pylab'] = (
165 {'TerminalIPythonApp' : {'pylab' : 'auto'}},
165 {'TerminalIPythonApp' : {'pylab' : 'auto'}},
166 """Pre-load matplotlib and numpy for interactive use with
166 """Pre-load matplotlib and numpy for interactive use with
167 the default matplotlib backend."""
167 the default matplotlib backend."""
168 )
168 )
169
169
170 aliases = dict(base_aliases)
170 aliases = dict(base_aliases)
171 aliases.update(shell_aliases)
171 aliases.update(shell_aliases)
172
172
173 # it's possible we don't want short aliases for *all* of these:
173 # it's possible we don't want short aliases for *all* of these:
174 aliases.update(dict(
174 aliases.update(dict(
175 gui='TerminalIPythonApp.gui',
175 gui='TerminalIPythonApp.gui',
176 pylab='TerminalIPythonApp.pylab',
176 pylab='TerminalIPythonApp.pylab',
177 ))
177 ))
178
178
179 #-----------------------------------------------------------------------------
179 #-----------------------------------------------------------------------------
180 # Main classes and functions
180 # Main classes and functions
181 #-----------------------------------------------------------------------------
181 #-----------------------------------------------------------------------------
182
182
183 class TerminalIPythonApp(BaseIPythonApplication, InteractiveShellApp):
183 class TerminalIPythonApp(BaseIPythonApplication, InteractiveShellApp):
184 name = u'ipython'
184 name = u'ipython'
185 description = usage.cl_usage
185 description = usage.cl_usage
186 default_config_file_name = default_config_file_name
186 default_config_file_name = default_config_file_name
187 crash_handler_class = IPAppCrashHandler
187 crash_handler_class = IPAppCrashHandler
188 examples = _examples
188 examples = _examples
189
189
190 flags = Dict(flags)
190 flags = Dict(flags)
191 aliases = Dict(aliases)
191 aliases = Dict(aliases)
192 classes = [InteractiveShellApp, TerminalInteractiveShell, ProfileDir,
192 classes = [InteractiveShellApp, TerminalInteractiveShell, ProfileDir,
193 PlainTextFormatter]
193 PlainTextFormatter]
194 subcommands = Dict(dict(
194 subcommands = Dict(dict(
195 qtconsole=('IPython.frontend.qt.console.qtconsoleapp.IPythonQtConsoleApp',
195 qtconsole=('IPython.frontend.qt.console.qtconsoleapp.IPythonQtConsoleApp',
196 """Launch the IPython Qt Console."""
196 """Launch the IPython Qt Console."""
197 ),
197 ),
198 hotebook=('IPython.frontend.html.notebook.notebookapp.IPythonNotebookApp',
198 notebook=('IPython.frontend.html.notebook.notebookapp.IPythonNotebookApp',
199 """Launch the IPython HTML Notebook Server"""
199 """Launch the IPython HTML Notebook Server"""
200 ),
200 ),
201 profile = ("IPython.core.profileapp.ProfileApp",
201 profile = ("IPython.core.profileapp.ProfileApp",
202 "Create and manage IPython profiles.")
202 "Create and manage IPython profiles.")
203 ))
203 ))
204
204
205 # *do* autocreate requested profile, but don't create the config file.
205 # *do* autocreate requested profile, but don't create the config file.
206 auto_create=Bool(True)
206 auto_create=Bool(True)
207 # configurables
207 # configurables
208 ignore_old_config=Bool(False, config=True,
208 ignore_old_config=Bool(False, config=True,
209 help="Suppress warning messages about legacy config files"
209 help="Suppress warning messages about legacy config files"
210 )
210 )
211 quick = Bool(False, config=True,
211 quick = Bool(False, config=True,
212 help="""Start IPython quickly by skipping the loading of config files."""
212 help="""Start IPython quickly by skipping the loading of config files."""
213 )
213 )
214 def _quick_changed(self, name, old, new):
214 def _quick_changed(self, name, old, new):
215 if new:
215 if new:
216 self.load_config_file = lambda *a, **kw: None
216 self.load_config_file = lambda *a, **kw: None
217 self.ignore_old_config=True
217 self.ignore_old_config=True
218
218
219 gui = CaselessStrEnum(('qt','wx','gtk'), config=True,
219 gui = CaselessStrEnum(('qt','wx','gtk'), config=True,
220 help="Enable GUI event loop integration ('qt', 'wx', 'gtk')."
220 help="Enable GUI event loop integration ('qt', 'wx', 'gtk')."
221 )
221 )
222 pylab = CaselessStrEnum(['tk', 'qt', 'wx', 'gtk', 'osx', 'auto'],
222 pylab = CaselessStrEnum(['tk', 'qt', 'wx', 'gtk', 'osx', 'auto'],
223 config=True,
223 config=True,
224 help="""Pre-load matplotlib and numpy for interactive use,
224 help="""Pre-load matplotlib and numpy for interactive use,
225 selecting a particular matplotlib backend and loop integration.
225 selecting a particular matplotlib backend and loop integration.
226 """
226 """
227 )
227 )
228 display_banner = Bool(True, config=True,
228 display_banner = Bool(True, config=True,
229 help="Whether to display a banner upon starting IPython."
229 help="Whether to display a banner upon starting IPython."
230 )
230 )
231
231
232 # if there is code of files to run from the cmd line, don't interact
232 # if there is code of files to run from the cmd line, don't interact
233 # unless the --i flag (App.force_interact) is true.
233 # unless the --i flag (App.force_interact) is true.
234 force_interact = Bool(False, config=True,
234 force_interact = Bool(False, config=True,
235 help="""If a command or file is given via the command-line,
235 help="""If a command or file is given via the command-line,
236 e.g. 'ipython foo.py"""
236 e.g. 'ipython foo.py"""
237 )
237 )
238 def _force_interact_changed(self, name, old, new):
238 def _force_interact_changed(self, name, old, new):
239 if new:
239 if new:
240 self.interact = True
240 self.interact = True
241
241
242 def _file_to_run_changed(self, name, old, new):
242 def _file_to_run_changed(self, name, old, new):
243 if new and not self.force_interact:
243 if new and not self.force_interact:
244 self.interact = False
244 self.interact = False
245 _code_to_run_changed = _file_to_run_changed
245 _code_to_run_changed = _file_to_run_changed
246
246
247 # internal, not-configurable
247 # internal, not-configurable
248 interact=Bool(True)
248 interact=Bool(True)
249
249
250
250
251 def parse_command_line(self, argv=None):
251 def parse_command_line(self, argv=None):
252 """override to allow old '-pylab' flag with deprecation warning"""
252 """override to allow old '-pylab' flag with deprecation warning"""
253
253
254 argv = sys.argv[1:] if argv is None else argv
254 argv = sys.argv[1:] if argv is None else argv
255
255
256 if '-pylab' in argv:
256 if '-pylab' in argv:
257 # deprecated `-pylab` given,
257 # deprecated `-pylab` given,
258 # warn and transform into current syntax
258 # warn and transform into current syntax
259 argv = argv[:] # copy, don't clobber
259 argv = argv[:] # copy, don't clobber
260 idx = argv.index('-pylab')
260 idx = argv.index('-pylab')
261 warn.warn("`-pylab` flag has been deprecated.\n"
261 warn.warn("`-pylab` flag has been deprecated.\n"
262 " Use `--pylab` instead, or `--pylab=foo` to specify a backend.")
262 " Use `--pylab` instead, or `--pylab=foo` to specify a backend.")
263 sub = '--pylab'
263 sub = '--pylab'
264 if len(argv) > idx+1:
264 if len(argv) > idx+1:
265 # check for gui arg, as in '-pylab qt'
265 # check for gui arg, as in '-pylab qt'
266 gui = argv[idx+1]
266 gui = argv[idx+1]
267 if gui in ('wx', 'qt', 'qt4', 'gtk', 'auto'):
267 if gui in ('wx', 'qt', 'qt4', 'gtk', 'auto'):
268 sub = '--pylab='+gui
268 sub = '--pylab='+gui
269 argv.pop(idx+1)
269 argv.pop(idx+1)
270 argv[idx] = sub
270 argv[idx] = sub
271
271
272 return super(TerminalIPythonApp, self).parse_command_line(argv)
272 return super(TerminalIPythonApp, self).parse_command_line(argv)
273
273
274 def initialize(self, argv=None):
274 def initialize(self, argv=None):
275 """Do actions after construct, but before starting the app."""
275 """Do actions after construct, but before starting the app."""
276 super(TerminalIPythonApp, self).initialize(argv)
276 super(TerminalIPythonApp, self).initialize(argv)
277 if self.subapp is not None:
277 if self.subapp is not None:
278 # don't bother initializing further, starting subapp
278 # don't bother initializing further, starting subapp
279 return
279 return
280 if not self.ignore_old_config:
280 if not self.ignore_old_config:
281 check_for_old_config(self.ipython_dir)
281 check_for_old_config(self.ipython_dir)
282 # print self.extra_args
282 # print self.extra_args
283 if self.extra_args:
283 if self.extra_args:
284 self.file_to_run = self.extra_args[0]
284 self.file_to_run = self.extra_args[0]
285 # create the shell
285 # create the shell
286 self.init_shell()
286 self.init_shell()
287 # and draw the banner
287 # and draw the banner
288 self.init_banner()
288 self.init_banner()
289 # Now a variety of things that happen after the banner is printed.
289 # Now a variety of things that happen after the banner is printed.
290 self.init_gui_pylab()
290 self.init_gui_pylab()
291 self.init_extensions()
291 self.init_extensions()
292 self.init_code()
292 self.init_code()
293
293
294 def init_shell(self):
294 def init_shell(self):
295 """initialize the InteractiveShell instance"""
295 """initialize the InteractiveShell instance"""
296 # I am a little hesitant to put these into InteractiveShell itself.
296 # I am a little hesitant to put these into InteractiveShell itself.
297 # But that might be the place for them
297 # But that might be the place for them
298 sys.path.insert(0, '')
298 sys.path.insert(0, '')
299
299
300 # Create an InteractiveShell instance.
300 # Create an InteractiveShell instance.
301 # shell.display_banner should always be False for the terminal
301 # shell.display_banner should always be False for the terminal
302 # based app, because we call shell.show_banner() by hand below
302 # based app, because we call shell.show_banner() by hand below
303 # so the banner shows *before* all extension loading stuff.
303 # so the banner shows *before* all extension loading stuff.
304 self.shell = TerminalInteractiveShell.instance(config=self.config,
304 self.shell = TerminalInteractiveShell.instance(config=self.config,
305 display_banner=False, profile_dir=self.profile_dir,
305 display_banner=False, profile_dir=self.profile_dir,
306 ipython_dir=self.ipython_dir)
306 ipython_dir=self.ipython_dir)
307
307
308 def init_banner(self):
308 def init_banner(self):
309 """optionally display the banner"""
309 """optionally display the banner"""
310 if self.display_banner and self.interact:
310 if self.display_banner and self.interact:
311 self.shell.show_banner()
311 self.shell.show_banner()
312 # Make sure there is a space below the banner.
312 # Make sure there is a space below the banner.
313 if self.log_level <= logging.INFO: print
313 if self.log_level <= logging.INFO: print
314
314
315
315
316 def init_gui_pylab(self):
316 def init_gui_pylab(self):
317 """Enable GUI event loop integration, taking pylab into account."""
317 """Enable GUI event loop integration, taking pylab into account."""
318 gui = self.gui
318 gui = self.gui
319
319
320 # Using `pylab` will also require gui activation, though which toolkit
320 # Using `pylab` will also require gui activation, though which toolkit
321 # to use may be chosen automatically based on mpl configuration.
321 # to use may be chosen automatically based on mpl configuration.
322 if self.pylab:
322 if self.pylab:
323 activate = self.shell.enable_pylab
323 activate = self.shell.enable_pylab
324 if self.pylab == 'auto':
324 if self.pylab == 'auto':
325 gui = None
325 gui = None
326 else:
326 else:
327 gui = self.pylab
327 gui = self.pylab
328 else:
328 else:
329 # Enable only GUI integration, no pylab
329 # Enable only GUI integration, no pylab
330 activate = inputhook.enable_gui
330 activate = inputhook.enable_gui
331
331
332 if gui or self.pylab:
332 if gui or self.pylab:
333 try:
333 try:
334 self.log.info("Enabling GUI event loop integration, "
334 self.log.info("Enabling GUI event loop integration, "
335 "toolkit=%s, pylab=%s" % (gui, self.pylab) )
335 "toolkit=%s, pylab=%s" % (gui, self.pylab) )
336 activate(gui)
336 activate(gui)
337 except:
337 except:
338 self.log.warn("Error in enabling GUI event loop integration:")
338 self.log.warn("Error in enabling GUI event loop integration:")
339 self.shell.showtraceback()
339 self.shell.showtraceback()
340
340
341 def start(self):
341 def start(self):
342 if self.subapp is not None:
342 if self.subapp is not None:
343 return self.subapp.start()
343 return self.subapp.start()
344 # perform any prexec steps:
344 # perform any prexec steps:
345 if self.interact:
345 if self.interact:
346 self.log.debug("Starting IPython's mainloop...")
346 self.log.debug("Starting IPython's mainloop...")
347 self.shell.mainloop()
347 self.shell.mainloop()
348 else:
348 else:
349 self.log.debug("IPython not interactive...")
349 self.log.debug("IPython not interactive...")
350
350
351
351
352 def load_default_config(ipython_dir=None):
352 def load_default_config(ipython_dir=None):
353 """Load the default config file from the default ipython_dir.
353 """Load the default config file from the default ipython_dir.
354
354
355 This is useful for embedded shells.
355 This is useful for embedded shells.
356 """
356 """
357 if ipython_dir is None:
357 if ipython_dir is None:
358 ipython_dir = get_ipython_dir()
358 ipython_dir = get_ipython_dir()
359 profile_dir = os.path.join(ipython_dir, 'profile_default')
359 profile_dir = os.path.join(ipython_dir, 'profile_default')
360 cl = PyFileConfigLoader(default_config_file_name, profile_dir)
360 cl = PyFileConfigLoader(default_config_file_name, profile_dir)
361 try:
361 try:
362 config = cl.load_config()
362 config = cl.load_config()
363 except IOError:
363 except IOError:
364 # no config found
364 # no config found
365 config = Config()
365 config = Config()
366 return config
366 return config
367
367
368
368
369 def launch_new_instance():
369 def launch_new_instance():
370 """Create and run a full blown IPython instance"""
370 """Create and run a full blown IPython instance"""
371 app = TerminalIPythonApp.instance()
371 app = TerminalIPythonApp.instance()
372 app.initialize()
372 app.initialize()
373 app.start()
373 app.start()
374
374
375
375
376 if __name__ == '__main__':
376 if __name__ == '__main__':
377 launch_new_instance()
377 launch_new_instance()
General Comments 0
You need to be logged in to leave comments. Login now