##// END OF EJS Templates
Merge pull request #1737 from minrk/histcfg...
Thomas Kluyver -
r6836:e63effa3 merge
parent child Browse files
Show More
@@ -1,410 +1,412 b''
1 1 #!/usr/bin/env python
2 2 # encoding: utf-8
3 3 """
4 4 The :class:`~IPython.core.application.Application` object for the command
5 5 line :command:`ipython` program.
6 6
7 7 Authors
8 8 -------
9 9
10 10 * Brian Granger
11 11 * Fernando Perez
12 12 * Min Ragan-Kelley
13 13 """
14 14
15 15 #-----------------------------------------------------------------------------
16 16 # Copyright (C) 2008-2011 The IPython Development Team
17 17 #
18 18 # Distributed under the terms of the BSD License. The full license is in
19 19 # the file COPYING, distributed as part of this software.
20 20 #-----------------------------------------------------------------------------
21 21
22 22 #-----------------------------------------------------------------------------
23 23 # Imports
24 24 #-----------------------------------------------------------------------------
25 25
26 26 from __future__ import absolute_import
27 27
28 28 import logging
29 29 import os
30 30 import sys
31 31
32 32 from IPython.config.loader import (
33 33 Config, PyFileConfigLoader, ConfigFileNotFound
34 34 )
35 35 from IPython.config.application import boolean_flag, catch_config_error
36 36 from IPython.core import release
37 37 from IPython.core import usage
38 38 from IPython.core.completer import IPCompleter
39 39 from IPython.core.crashhandler import CrashHandler
40 40 from IPython.core.formatters import PlainTextFormatter
41 from IPython.core.history import HistoryManager
41 42 from IPython.core.prompts import PromptManager
42 43 from IPython.core.application import (
43 44 ProfileDir, BaseIPythonApplication, base_flags, base_aliases
44 45 )
45 46 from IPython.core.shellapp import (
46 47 InteractiveShellApp, shell_flags, shell_aliases
47 48 )
48 49 from IPython.frontend.terminal.interactiveshell import TerminalInteractiveShell
49 50 from IPython.lib import inputhook
50 51 from IPython.utils import warn
51 52 from IPython.utils.path import get_ipython_dir, check_for_old_config
52 53 from IPython.utils.traitlets import (
53 54 Bool, List, Dict, CaselessStrEnum
54 55 )
55 56
56 57 #-----------------------------------------------------------------------------
57 58 # Globals, utilities and helpers
58 59 #-----------------------------------------------------------------------------
59 60
60 61 #: The default config file name for this application.
61 62 default_config_file_name = u'ipython_config.py'
62 63
63 64 _examples = """
64 65 ipython --pylab # start in pylab mode
65 66 ipython --pylab=qt # start in pylab mode with the qt4 backend
66 67 ipython --log-level=DEBUG # set logging to DEBUG
67 68 ipython --profile=foo # start with profile foo
68 69
69 70 ipython qtconsole # start the qtconsole GUI application
70 71 ipython help qtconsole # show the help for the qtconsole subcmd
71 72
72 73 ipython console # start the terminal-based console application
73 74 ipython help console # show the help for the console subcmd
74 75
75 76 ipython notebook # start the IPython notebook
76 77 ipython help notebook # show the help for the notebook subcmd
77 78
78 79 ipython profile create foo # create profile foo w/ default config files
79 80 ipython help profile # show the help for the profile subcmd
80 81 """
81 82
82 83 #-----------------------------------------------------------------------------
83 84 # Crash handler for this application
84 85 #-----------------------------------------------------------------------------
85 86
86 87 class IPAppCrashHandler(CrashHandler):
87 88 """sys.excepthook for IPython itself, leaves a detailed report on disk."""
88 89
89 90 def __init__(self, app):
90 91 contact_name = release.authors['Fernando'][0]
91 92 contact_email = release.author_email
92 93 bug_tracker = 'https://github.com/ipython/ipython/issues'
93 94 super(IPAppCrashHandler,self).__init__(
94 95 app, contact_name, contact_email, bug_tracker
95 96 )
96 97
97 98 def make_report(self,traceback):
98 99 """Return a string containing a crash report."""
99 100
100 101 sec_sep = self.section_sep
101 102 # Start with parent report
102 103 report = [super(IPAppCrashHandler, self).make_report(traceback)]
103 104 # Add interactive-specific info we may have
104 105 rpt_add = report.append
105 106 try:
106 107 rpt_add(sec_sep+"History of session input:")
107 108 for line in self.app.shell.user_ns['_ih']:
108 109 rpt_add(line)
109 110 rpt_add('\n*** Last line of input (may not be in above history):\n')
110 111 rpt_add(self.app.shell._last_input_line+'\n')
111 112 except:
112 113 pass
113 114
114 115 return ''.join(report)
115 116
116 117 #-----------------------------------------------------------------------------
117 118 # Aliases and Flags
118 119 #-----------------------------------------------------------------------------
119 120 flags = dict(base_flags)
120 121 flags.update(shell_flags)
121 122 frontend_flags = {}
122 123 addflag = lambda *args: frontend_flags.update(boolean_flag(*args))
123 124 addflag('autoedit-syntax', 'TerminalInteractiveShell.autoedit_syntax',
124 125 'Turn on auto editing of files with syntax errors.',
125 126 'Turn off auto editing of files with syntax errors.'
126 127 )
127 128 addflag('banner', 'TerminalIPythonApp.display_banner',
128 129 "Display a banner upon starting IPython.",
129 130 "Don't display a banner upon starting IPython."
130 131 )
131 132 addflag('confirm-exit', 'TerminalInteractiveShell.confirm_exit',
132 133 """Set to confirm when you try to exit IPython with an EOF (Control-D
133 134 in Unix, Control-Z/Enter in Windows). By typing 'exit' or 'quit',
134 135 you can force a direct exit without any confirmation.""",
135 136 "Don't prompt the user when exiting."
136 137 )
137 138 addflag('term-title', 'TerminalInteractiveShell.term_title',
138 139 "Enable auto setting the terminal title.",
139 140 "Disable auto setting the terminal title."
140 141 )
141 142 classic_config = Config()
142 143 classic_config.InteractiveShell.cache_size = 0
143 144 classic_config.PlainTextFormatter.pprint = False
144 145 classic_config.PromptManager.in_template = '>>> '
145 146 classic_config.PromptManager.in2_template = '... '
146 147 classic_config.PromptManager.out_template = ''
147 148 classic_config.InteractiveShell.separate_in = ''
148 149 classic_config.InteractiveShell.separate_out = ''
149 150 classic_config.InteractiveShell.separate_out2 = ''
150 151 classic_config.InteractiveShell.colors = 'NoColor'
151 152 classic_config.InteractiveShell.xmode = 'Plain'
152 153
153 154 frontend_flags['classic']=(
154 155 classic_config,
155 156 "Gives IPython a similar feel to the classic Python prompt."
156 157 )
157 158 # # log doesn't make so much sense this way anymore
158 159 # paa('--log','-l',
159 160 # action='store_true', dest='InteractiveShell.logstart',
160 161 # help="Start logging to the default log file (./ipython_log.py).")
161 162 #
162 163 # # quick is harder to implement
163 164 frontend_flags['quick']=(
164 165 {'TerminalIPythonApp' : {'quick' : True}},
165 166 "Enable quick startup with no config files."
166 167 )
167 168
168 169 frontend_flags['i'] = (
169 170 {'TerminalIPythonApp' : {'force_interact' : True}},
170 171 """If running code from the command line, become interactive afterwards.
171 172 Note: can also be given simply as '-i.'"""
172 173 )
173 174 frontend_flags['pylab'] = (
174 175 {'TerminalIPythonApp' : {'pylab' : 'auto'}},
175 176 """Pre-load matplotlib and numpy for interactive use with
176 177 the default matplotlib backend."""
177 178 )
178 179 flags.update(frontend_flags)
179 180
180 181 aliases = dict(base_aliases)
181 182 aliases.update(shell_aliases)
182 183
183 184 # it's possible we don't want short aliases for *all* of these:
184 185 aliases.update(dict(
185 186 gui='TerminalIPythonApp.gui',
186 187 pylab='TerminalIPythonApp.pylab',
187 188 ))
188 189
189 190 #-----------------------------------------------------------------------------
190 191 # Main classes and functions
191 192 #-----------------------------------------------------------------------------
192 193
193 194 class TerminalIPythonApp(BaseIPythonApplication, InteractiveShellApp):
194 195 name = u'ipython'
195 196 description = usage.cl_usage
196 197 default_config_file_name = default_config_file_name
197 198 crash_handler_class = IPAppCrashHandler
198 199 examples = _examples
199 200
200 201 flags = Dict(flags)
201 202 aliases = Dict(aliases)
202 203 classes = List()
203 204 def _classes_default(self):
204 205 """This has to be in a method, for TerminalIPythonApp to be available."""
205 206 return [
206 207 InteractiveShellApp, # ShellApp comes before TerminalApp, because
207 208 self.__class__, # it will also affect subclasses (e.g. QtConsole)
208 209 TerminalInteractiveShell,
209 210 PromptManager,
211 HistoryManager,
210 212 ProfileDir,
211 213 PlainTextFormatter,
212 214 IPCompleter,
213 215 ]
214 216
215 217 subcommands = Dict(dict(
216 218 qtconsole=('IPython.frontend.qt.console.qtconsoleapp.IPythonQtConsoleApp',
217 219 """Launch the IPython Qt Console."""
218 220 ),
219 221 notebook=('IPython.frontend.html.notebook.notebookapp.NotebookApp',
220 222 """Launch the IPython HTML Notebook Server."""
221 223 ),
222 224 profile = ("IPython.core.profileapp.ProfileApp",
223 225 "Create and manage IPython profiles."
224 226 ),
225 227 kernel = ("IPython.zmq.ipkernel.IPKernelApp",
226 228 "Start a kernel without an attached frontend."
227 229 ),
228 230 console=('IPython.frontend.terminal.console.app.ZMQTerminalIPythonApp',
229 231 """Launch the IPython terminal-based Console."""
230 232 ),
231 233 ))
232 234
233 235 # *do* autocreate requested profile, but don't create the config file.
234 236 auto_create=Bool(True)
235 237 # configurables
236 238 ignore_old_config=Bool(False, config=True,
237 239 help="Suppress warning messages about legacy config files"
238 240 )
239 241 quick = Bool(False, config=True,
240 242 help="""Start IPython quickly by skipping the loading of config files."""
241 243 )
242 244 def _quick_changed(self, name, old, new):
243 245 if new:
244 246 self.load_config_file = lambda *a, **kw: None
245 247 self.ignore_old_config=True
246 248
247 249 gui = CaselessStrEnum(('qt', 'wx', 'gtk', 'glut', 'pyglet'), config=True,
248 250 help="Enable GUI event loop integration ('qt', 'wx', 'gtk', 'glut', 'pyglet')."
249 251 )
250 252 pylab = CaselessStrEnum(['tk', 'qt', 'wx', 'gtk', 'osx', 'auto'],
251 253 config=True,
252 254 help="""Pre-load matplotlib and numpy for interactive use,
253 255 selecting a particular matplotlib backend and loop integration.
254 256 """
255 257 )
256 258 display_banner = Bool(True, config=True,
257 259 help="Whether to display a banner upon starting IPython."
258 260 )
259 261
260 262 # if there is code of files to run from the cmd line, don't interact
261 263 # unless the --i flag (App.force_interact) is true.
262 264 force_interact = Bool(False, config=True,
263 265 help="""If a command or file is given via the command-line,
264 266 e.g. 'ipython foo.py"""
265 267 )
266 268 def _force_interact_changed(self, name, old, new):
267 269 if new:
268 270 self.interact = True
269 271
270 272 def _file_to_run_changed(self, name, old, new):
271 273 if new:
272 274 self.something_to_run = True
273 275 if new and not self.force_interact:
274 276 self.interact = False
275 277 _code_to_run_changed = _file_to_run_changed
276 278 _module_to_run_changed = _file_to_run_changed
277 279
278 280 # internal, not-configurable
279 281 interact=Bool(True)
280 282 something_to_run=Bool(False)
281 283
282 284 def parse_command_line(self, argv=None):
283 285 """override to allow old '-pylab' flag with deprecation warning"""
284 286
285 287 argv = sys.argv[1:] if argv is None else argv
286 288
287 289 if '-pylab' in argv:
288 290 # deprecated `-pylab` given,
289 291 # warn and transform into current syntax
290 292 argv = argv[:] # copy, don't clobber
291 293 idx = argv.index('-pylab')
292 294 warn.warn("`-pylab` flag has been deprecated.\n"
293 295 " Use `--pylab` instead, or `--pylab=foo` to specify a backend.")
294 296 sub = '--pylab'
295 297 if len(argv) > idx+1:
296 298 # check for gui arg, as in '-pylab qt'
297 299 gui = argv[idx+1]
298 300 if gui in ('wx', 'qt', 'qt4', 'gtk', 'auto'):
299 301 sub = '--pylab='+gui
300 302 argv.pop(idx+1)
301 303 argv[idx] = sub
302 304
303 305 return super(TerminalIPythonApp, self).parse_command_line(argv)
304 306
305 307 @catch_config_error
306 308 def initialize(self, argv=None):
307 309 """Do actions after construct, but before starting the app."""
308 310 super(TerminalIPythonApp, self).initialize(argv)
309 311 if self.subapp is not None:
310 312 # don't bother initializing further, starting subapp
311 313 return
312 314 if not self.ignore_old_config:
313 315 check_for_old_config(self.ipython_dir)
314 316 # print self.extra_args
315 317 if self.extra_args and not self.something_to_run:
316 318 self.file_to_run = self.extra_args[0]
317 319 self.init_path()
318 320 # create the shell
319 321 self.init_shell()
320 322 # and draw the banner
321 323 self.init_banner()
322 324 # Now a variety of things that happen after the banner is printed.
323 325 self.init_gui_pylab()
324 326 self.init_extensions()
325 327 self.init_code()
326 328
327 329 def init_shell(self):
328 330 """initialize the InteractiveShell instance"""
329 331 # Create an InteractiveShell instance.
330 332 # shell.display_banner should always be False for the terminal
331 333 # based app, because we call shell.show_banner() by hand below
332 334 # so the banner shows *before* all extension loading stuff.
333 335 self.shell = TerminalInteractiveShell.instance(config=self.config,
334 336 display_banner=False, profile_dir=self.profile_dir,
335 337 ipython_dir=self.ipython_dir)
336 338 self.shell.configurables.append(self)
337 339
338 340 def init_banner(self):
339 341 """optionally display the banner"""
340 342 if self.display_banner and self.interact:
341 343 self.shell.show_banner()
342 344 # Make sure there is a space below the banner.
343 345 if self.log_level <= logging.INFO: print
344 346
345 347
346 348 def init_gui_pylab(self):
347 349 """Enable GUI event loop integration, taking pylab into account."""
348 350 gui = self.gui
349 351
350 352 # Using `pylab` will also require gui activation, though which toolkit
351 353 # to use may be chosen automatically based on mpl configuration.
352 354 if self.pylab:
353 355 activate = self.shell.enable_pylab
354 356 if self.pylab == 'auto':
355 357 gui = None
356 358 else:
357 359 gui = self.pylab
358 360 else:
359 361 # Enable only GUI integration, no pylab
360 362 activate = inputhook.enable_gui
361 363
362 364 if gui or self.pylab:
363 365 try:
364 366 self.log.info("Enabling GUI event loop integration, "
365 367 "toolkit=%s, pylab=%s" % (gui, self.pylab) )
366 368 if self.pylab:
367 369 activate(gui, import_all=self.pylab_import_all)
368 370 else:
369 371 activate(gui)
370 372 except:
371 373 self.log.warn("Error in enabling GUI event loop integration:")
372 374 self.shell.showtraceback()
373 375
374 376 def start(self):
375 377 if self.subapp is not None:
376 378 return self.subapp.start()
377 379 # perform any prexec steps:
378 380 if self.interact:
379 381 self.log.debug("Starting IPython's mainloop...")
380 382 self.shell.mainloop()
381 383 else:
382 384 self.log.debug("IPython not interactive...")
383 385
384 386
385 387 def load_default_config(ipython_dir=None):
386 388 """Load the default config file from the default ipython_dir.
387 389
388 390 This is useful for embedded shells.
389 391 """
390 392 if ipython_dir is None:
391 393 ipython_dir = get_ipython_dir()
392 394 profile_dir = os.path.join(ipython_dir, 'profile_default')
393 395 cl = PyFileConfigLoader(default_config_file_name, profile_dir)
394 396 try:
395 397 config = cl.load_config()
396 398 except ConfigFileNotFound:
397 399 # no config found
398 400 config = Config()
399 401 return config
400 402
401 403
402 404 def launch_new_instance():
403 405 """Create and run a full blown IPython instance"""
404 406 app = TerminalIPythonApp.instance()
405 407 app.initialize()
406 408 app.start()
407 409
408 410
409 411 if __name__ == '__main__':
410 412 launch_new_instance()
General Comments 0
You need to be logged in to leave comments. Login now