##// END OF EJS Templates
support `-pylab` flag with deprecation warning...
MinRK -
Show More
@@ -1,357 +1,384 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-2010 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
34 34 )
35 35 from IPython.config.application import boolean_flag
36 36 from IPython.core import release
37 37 from IPython.core import usage
38 38 from IPython.core.crashhandler import CrashHandler
39 39 from IPython.core.formatters import PlainTextFormatter
40 40 from IPython.core.application import (
41 41 ProfileDir, BaseIPythonApplication, base_flags, base_aliases
42 42 )
43 43 from IPython.core.shellapp import (
44 44 InteractiveShellApp, shell_flags, shell_aliases
45 45 )
46 46 from IPython.frontend.terminal.interactiveshell import TerminalInteractiveShell
47 47 from IPython.lib import inputhook
48 from IPython.utils import warn
48 49 from IPython.utils.path import get_ipython_dir, check_for_old_config
49 50 from IPython.utils.traitlets import (
50 51 Bool, Dict, CaselessStrEnum
51 52 )
52 53
53 54 #-----------------------------------------------------------------------------
54 55 # Globals, utilities and helpers
55 56 #-----------------------------------------------------------------------------
56 57
57 58 #: The default config file name for this application.
58 59 default_config_file_name = u'ipython_config.py'
59 60
60 61
61 62 #-----------------------------------------------------------------------------
62 63 # Crash handler for this application
63 64 #-----------------------------------------------------------------------------
64 65
65 66 _message_template = """\
66 67 Oops, $self.app_name crashed. We do our best to make it stable, but...
67 68
68 69 A crash report was automatically generated with the following information:
69 70 - A verbatim copy of the crash traceback.
70 71 - A copy of your input history during this session.
71 72 - Data on your current $self.app_name configuration.
72 73
73 74 It was left in the file named:
74 75 \t'$self.crash_report_fname'
75 76 If you can email this file to the developers, the information in it will help
76 77 them in understanding and correcting the problem.
77 78
78 79 You can mail it to: $self.contact_name at $self.contact_email
79 80 with the subject '$self.app_name Crash Report'.
80 81
81 82 If you want to do it now, the following command will work (under Unix):
82 83 mail -s '$self.app_name Crash Report' $self.contact_email < $self.crash_report_fname
83 84
84 85 To ensure accurate tracking of this issue, please file a report about it at:
85 86 $self.bug_tracker
86 87 """
87 88
88 89 class IPAppCrashHandler(CrashHandler):
89 90 """sys.excepthook for IPython itself, leaves a detailed report on disk."""
90 91
91 92 message_template = _message_template
92 93
93 94 def __init__(self, app):
94 95 contact_name = release.authors['Fernando'][0]
95 96 contact_email = release.authors['Fernando'][1]
96 97 bug_tracker = 'http://github.com/ipython/ipython/issues'
97 98 super(IPAppCrashHandler,self).__init__(
98 99 app, contact_name, contact_email, bug_tracker
99 100 )
100 101
101 102 def make_report(self,traceback):
102 103 """Return a string containing a crash report."""
103 104
104 105 sec_sep = self.section_sep
105 106 # Start with parent report
106 107 report = [super(IPAppCrashHandler, self).make_report(traceback)]
107 108 # Add interactive-specific info we may have
108 109 rpt_add = report.append
109 110 try:
110 111 rpt_add(sec_sep+"History of session input:")
111 112 for line in self.app.shell.user_ns['_ih']:
112 113 rpt_add(line)
113 114 rpt_add('\n*** Last line of input (may not be in above history):\n')
114 115 rpt_add(self.app.shell._last_input_line+'\n')
115 116 except:
116 117 pass
117 118
118 119 return ''.join(report)
119 120
120 121 #-----------------------------------------------------------------------------
121 122 # Aliases and Flags
122 123 #-----------------------------------------------------------------------------
123 124 flags = dict(base_flags)
124 125 flags.update(shell_flags)
125 126 addflag = lambda *args: flags.update(boolean_flag(*args))
126 127 addflag('autoedit-syntax', 'TerminalInteractiveShell.autoedit_syntax',
127 128 'Turn on auto editing of files with syntax errors.',
128 129 'Turn off auto editing of files with syntax errors.'
129 130 )
130 131 addflag('banner', 'TerminalIPythonApp.display_banner',
131 132 "Display a banner upon starting IPython.",
132 133 "Don't display a banner upon starting IPython."
133 134 )
134 135 addflag('confirm-exit', 'TerminalInteractiveShell.confirm_exit',
135 136 """Set to confirm when you try to exit IPython with an EOF (Control-D
136 137 in Unix, Control-Z/Enter in Windows). By typing 'exit' or 'quit',
137 138 you can force a direct exit without any confirmation.""",
138 139 "Don't prompt the user when exiting."
139 140 )
140 141 addflag('term-title', 'TerminalInteractiveShell.term_title',
141 142 "Enable auto setting the terminal title.",
142 143 "Disable auto setting the terminal title."
143 144 )
144 145 classic_config = Config()
145 146 classic_config.InteractiveShell.cache_size = 0
146 147 classic_config.PlainTextFormatter.pprint = False
147 148 classic_config.InteractiveShell.prompt_in1 = '>>> '
148 149 classic_config.InteractiveShell.prompt_in2 = '... '
149 150 classic_config.InteractiveShell.prompt_out = ''
150 151 classic_config.InteractiveShell.separate_in = ''
151 152 classic_config.InteractiveShell.separate_out = ''
152 153 classic_config.InteractiveShell.separate_out2 = ''
153 154 classic_config.InteractiveShell.colors = 'NoColor'
154 155 classic_config.InteractiveShell.xmode = 'Plain'
155 156
156 157 flags['classic']=(
157 158 classic_config,
158 159 "Gives IPython a similar feel to the classic Python prompt."
159 160 )
160 161 # # log doesn't make so much sense this way anymore
161 162 # paa('--log','-l',
162 163 # action='store_true', dest='InteractiveShell.logstart',
163 164 # help="Start logging to the default log file (./ipython_log.py).")
164 165 #
165 166 # # quick is harder to implement
166 167 flags['quick']=(
167 168 {'TerminalIPythonApp' : {'quick' : True}},
168 169 "Enable quick startup with no config files."
169 170 )
170 171
171 172 flags['i'] = (
172 173 {'TerminalIPythonApp' : {'force_interact' : True}},
173 174 "If running code from the command line, become interactive afterwards."
174 175 )
175 176 flags['pylab'] = (
176 177 {'TerminalIPythonApp' : {'pylab' : 'auto'}},
177 178 """Pre-load matplotlib and numpy for interactive use with
178 179 the default matplotlib backend."""
179 180 )
180 181
181 182 aliases = dict(base_aliases)
182 183 aliases.update(shell_aliases)
183 184
184 185 # it's possible we don't want short aliases for *all* of these:
185 186 aliases.update(dict(
186 187 gui='TerminalIPythonApp.gui',
187 188 pylab='TerminalIPythonApp.pylab',
188 189 ))
189 190
190 191 #-----------------------------------------------------------------------------
191 192 # Main classes and functions
192 193 #-----------------------------------------------------------------------------
193 194
194 195 class TerminalIPythonApp(BaseIPythonApplication, InteractiveShellApp):
195 196 name = u'ipython'
196 197 description = usage.cl_usage
197 198 default_config_file_name = default_config_file_name
198 199 crash_handler_class = IPAppCrashHandler
199 200
200 201 flags = Dict(flags)
201 202 aliases = Dict(aliases)
202 203 classes = [InteractiveShellApp, TerminalInteractiveShell, ProfileDir, PlainTextFormatter]
203 204 subcommands = Dict(dict(
204 205 qtconsole=('IPython.frontend.qt.console.qtconsoleapp.IPythonQtConsoleApp',
205 206 """Launch the IPython Qt Console."""
206 207 ),
207 208 profile = ("IPython.core.profileapp.ProfileApp",
208 209 "Create and manage IPython profiles.")
209 210 ))
210 211
211 212 # *do* autocreate requested profile, but don't create the config file.
212 213 auto_create=Bool(True)
213 214 # configurables
214 215 ignore_old_config=Bool(False, config=True,
215 216 help="Suppress warning messages about legacy config files"
216 217 )
217 218 quick = Bool(False, config=True,
218 219 help="""Start IPython quickly by skipping the loading of config files."""
219 220 )
220 221 def _quick_changed(self, name, old, new):
221 222 if new:
222 223 self.load_config_file = lambda *a, **kw: None
223 224 self.ignore_old_config=True
224 225
225 226 gui = CaselessStrEnum(('qt','wx','gtk'), config=True,
226 227 help="Enable GUI event loop integration ('qt', 'wx', 'gtk')."
227 228 )
228 229 pylab = CaselessStrEnum(['tk', 'qt', 'wx', 'gtk', 'osx', 'auto'],
229 230 config=True,
230 231 help="""Pre-load matplotlib and numpy for interactive use,
231 232 selecting a particular matplotlib backend and loop integration.
232 233 """
233 234 )
234 235 display_banner = Bool(True, config=True,
235 236 help="Whether to display a banner upon starting IPython."
236 237 )
237 238
238 239 # if there is code of files to run from the cmd line, don't interact
239 240 # unless the --i flag (App.force_interact) is true.
240 241 force_interact = Bool(False, config=True,
241 242 help="""If a command or file is given via the command-line,
242 243 e.g. 'ipython foo.py"""
243 244 )
244 245 def _force_interact_changed(self, name, old, new):
245 246 if new:
246 247 self.interact = True
247 248
248 249 def _file_to_run_changed(self, name, old, new):
249 250 if new and not self.force_interact:
250 251 self.interact = False
251 252 _code_to_run_changed = _file_to_run_changed
252 253
253 254 # internal, not-configurable
254 255 interact=Bool(True)
255 256
256 257
258 def parse_command_line(self, argv=None):
259 """override to allow old '-pylab' flag with deprecation warning"""
260 argv = sys.argv[1:] if argv is None else argv
261
262 try:
263 idx = argv.index('-pylab')
264 except ValueError:
265 # `-pylab` not given, proceed as normal
266 pass
267 else:
268 # deprecated `-pylab` given,
269 # warn and transform into current syntax
270 argv = list(argv) # copy, don't clobber
271 warn.warn("`-pylab` flag has been deprecated.\n"
272 " Use `--pylab` instead, or `pylab=foo` to specify a backend.")
273 sub = '--pylab'
274 if len(argv) > idx+1:
275 # check for gui arg, as in '-pylab qt'
276 gui = argv[idx+1]
277 if gui in ('wx', 'qt', 'qt4', 'gtk', 'auto'):
278 sub = 'pylab='+gui
279 argv.pop(idx+1)
280 argv[idx] = sub
281
282 return super(TerminalIPythonApp, self).parse_command_line(argv)
283
257 284 def initialize(self, argv=None):
258 285 """Do actions after construct, but before starting the app."""
259 286 super(TerminalIPythonApp, self).initialize(argv)
260 287 if self.subapp is not None:
261 288 # don't bother initializing further, starting subapp
262 289 return
263 290 if not self.ignore_old_config:
264 291 check_for_old_config(self.ipython_dir)
265 292 # print self.extra_args
266 293 if self.extra_args:
267 294 self.file_to_run = self.extra_args[0]
268 295 # create the shell
269 296 self.init_shell()
270 297 # and draw the banner
271 298 self.init_banner()
272 299 # Now a variety of things that happen after the banner is printed.
273 300 self.init_gui_pylab()
274 301 self.init_extensions()
275 302 self.init_code()
276 303
277 304 def init_shell(self):
278 305 """initialize the InteractiveShell instance"""
279 306 # I am a little hesitant to put these into InteractiveShell itself.
280 307 # But that might be the place for them
281 308 sys.path.insert(0, '')
282 309
283 310 # Create an InteractiveShell instance.
284 311 # shell.display_banner should always be False for the terminal
285 312 # based app, because we call shell.show_banner() by hand below
286 313 # so the banner shows *before* all extension loading stuff.
287 314 self.shell = TerminalInteractiveShell.instance(config=self.config,
288 315 display_banner=False, profile_dir=self.profile_dir,
289 316 ipython_dir=self.ipython_dir)
290 317
291 318 def init_banner(self):
292 319 """optionally display the banner"""
293 320 if self.display_banner and self.interact:
294 321 self.shell.show_banner()
295 322 # Make sure there is a space below the banner.
296 323 if self.log_level <= logging.INFO: print
297 324
298 325
299 326 def init_gui_pylab(self):
300 327 """Enable GUI event loop integration, taking pylab into account."""
301 328 gui = self.gui
302 329
303 330 # Using `pylab` will also require gui activation, though which toolkit
304 331 # to use may be chosen automatically based on mpl configuration.
305 332 if self.pylab:
306 333 activate = self.shell.enable_pylab
307 334 if self.pylab == 'auto':
308 335 gui = None
309 336 else:
310 337 gui = self.pylab
311 338 else:
312 339 # Enable only GUI integration, no pylab
313 340 activate = inputhook.enable_gui
314 341
315 342 if gui or self.pylab:
316 343 try:
317 344 self.log.info("Enabling GUI event loop integration, "
318 345 "toolkit=%s, pylab=%s" % (gui, self.pylab) )
319 346 activate(gui)
320 347 except:
321 348 self.log.warn("Error in enabling GUI event loop integration:")
322 349 self.shell.showtraceback()
323 350
324 351 def start(self):
325 352 if self.subapp is not None:
326 353 return self.subapp.start()
327 354 # perform any prexec steps:
328 355 if self.interact:
329 356 self.log.debug("Starting IPython's mainloop...")
330 357 self.shell.mainloop()
331 358 else:
332 359 self.log.debug("IPython not interactive...")
333 360
334 361
335 362 def load_default_config(ipython_dir=None):
336 363 """Load the default config file from the default ipython_dir.
337 364
338 365 This is useful for embedded shells.
339 366 """
340 367 if ipython_dir is None:
341 368 ipython_dir = get_ipython_dir()
342 369 profile_dir = os.path.join(ipython_dir, 'profile_default')
343 370 cl = PyFileConfigLoader(default_config_file_name, profile_dir)
344 371 config = cl.load_config()
345 372 return config
346 373
347 374
348 375 def launch_new_instance():
349 376 """Create and run a full blown IPython instance"""
350 377 app = TerminalIPythonApp.instance()
351 378 app.initialize()
352 379 app.start()
353 380
354 381
355 382 if __name__ == '__main__':
356 383 launch_new_instance()
357 384
General Comments 0
You need to be logged in to leave comments. Login now