##// END OF EJS Templates
Merge pull request #660 from minrk/i658...
Min RK -
r4464:d932a915 merge
parent child Browse files
Show More
@@ -1,426 +1,427 b''
1 1 # encoding: utf-8
2 2 """
3 3 A base class for a configurable application.
4 4
5 5 Authors:
6 6
7 7 * Brian Granger
8 8 * Min RK
9 9 """
10 10
11 11 #-----------------------------------------------------------------------------
12 12 # Copyright (C) 2008-2011 The IPython Development Team
13 13 #
14 14 # Distributed under the terms of the BSD License. The full license is in
15 15 # the file COPYING, distributed as part of this software.
16 16 #-----------------------------------------------------------------------------
17 17
18 18 #-----------------------------------------------------------------------------
19 19 # Imports
20 20 #-----------------------------------------------------------------------------
21 21
22 22 import logging
23 23 import os
24 24 import re
25 25 import sys
26 26 from copy import deepcopy
27 27
28 28 from IPython.config.configurable import SingletonConfigurable
29 29 from IPython.config.loader import (
30 30 KeyValueConfigLoader, PyFileConfigLoader, Config, ArgumentError
31 31 )
32 32
33 33 from IPython.utils.traitlets import (
34 34 Unicode, List, Int, Enum, Dict, Instance, TraitError
35 35 )
36 36 from IPython.utils.importstring import import_item
37 37 from IPython.utils.text import indent, wrap_paragraphs, dedent
38 38
39 39 #-----------------------------------------------------------------------------
40 40 # function for re-wrapping a helpstring
41 41 #-----------------------------------------------------------------------------
42 42
43 43 #-----------------------------------------------------------------------------
44 44 # Descriptions for the various sections
45 45 #-----------------------------------------------------------------------------
46 46
47 47 # merge flags&aliases into options
48 48 option_description = """
49 49 IPython command-line arguments are passed as '--<flag>', or '--<name>=<value>'.
50 50
51 51 Arguments that take values are actually convenience aliases to full
52 52 Configurables, whose aliases are listed on the help line. For more information
53 53 on full configurables, see '--help-all'.
54 54 """.strip() # trim newlines of front and back
55 55
56 56 keyvalue_description = """
57 57 Parameters are set from command-line arguments of the form:
58 58 `--Class.trait=value`.
59 59 This line is evaluated in Python, so simple expressions are allowed, e.g.::
60 60 `--C.a='range(3)'` For setting C.a=[0,1,2].
61 61 """.strip() # trim newlines of front and back
62 62
63 63 subcommand_description = """
64 64 Subcommands are launched as `{app} cmd [args]`. For information on using
65 65 subcommand 'cmd', do: `{app} cmd -h`.
66 66 """.strip().format(app=os.path.basename(sys.argv[0]))
67 67 # get running program name
68 68
69 69 #-----------------------------------------------------------------------------
70 70 # Application class
71 71 #-----------------------------------------------------------------------------
72 72
73 73
74 74 class ApplicationError(Exception):
75 75 pass
76 76
77 77
78 78 class Application(SingletonConfigurable):
79 79 """A singleton application with full configuration support."""
80 80
81 81 # The name of the application, will usually match the name of the command
82 82 # line application
83 83 name = Unicode(u'application')
84 84
85 85 # The description of the application that is printed at the beginning
86 86 # of the help.
87 87 description = Unicode(u'This is an application.')
88 88 # default section descriptions
89 89 option_description = Unicode(option_description)
90 90 keyvalue_description = Unicode(keyvalue_description)
91 91 subcommand_description = Unicode(subcommand_description)
92 92
93 93 # The usage and example string that goes at the end of the help string.
94 94 examples = Unicode()
95 95
96 96 # A sequence of Configurable subclasses whose config=True attributes will
97 97 # be exposed at the command line.
98 98 classes = List([])
99 99
100 100 # The version string of this application.
101 101 version = Unicode(u'0.0')
102 102
103 103 # The log level for the application
104 104 log_level = Enum((0,10,20,30,40,50,'DEBUG','INFO','WARN','ERROR','CRITICAL'),
105 105 default_value=logging.WARN,
106 106 config=True,
107 107 help="Set the log level by value or name.")
108 108 def _log_level_changed(self, name, old, new):
109 109 """Adjust the log level when log_level is set."""
110 110 if isinstance(new, basestring):
111 111 new = getattr(logging, new)
112 112 self.log_level = new
113 113 self.log.setLevel(new)
114 114
115 115 # the alias map for configurables
116 116 aliases = Dict({'log-level' : 'Application.log_level'})
117 117
118 118 # flags for loading Configurables or store_const style flags
119 119 # flags are loaded from this dict by '--key' flags
120 120 # this must be a dict of two-tuples, the first element being the Config/dict
121 121 # and the second being the help string for the flag
122 122 flags = Dict()
123 123 def _flags_changed(self, name, old, new):
124 124 """ensure flags dict is valid"""
125 125 for key,value in new.iteritems():
126 126 assert len(value) == 2, "Bad flag: %r:%s"%(key,value)
127 127 assert isinstance(value[0], (dict, Config)), "Bad flag: %r:%s"%(key,value)
128 128 assert isinstance(value[1], basestring), "Bad flag: %r:%s"%(key,value)
129 129
130 130
131 131 # subcommands for launching other applications
132 132 # if this is not empty, this will be a parent Application
133 133 # this must be a dict of two-tuples,
134 134 # the first element being the application class/import string
135 135 # and the second being the help string for the subcommand
136 136 subcommands = Dict()
137 137 # parse_command_line will initialize a subapp, if requested
138 138 subapp = Instance('IPython.config.application.Application', allow_none=True)
139 139
140 140 # extra command-line arguments that don't set config values
141 141 extra_args = List(Unicode)
142 142
143 143
144 144 def __init__(self, **kwargs):
145 145 SingletonConfigurable.__init__(self, **kwargs)
146 # Add my class to self.classes so my attributes appear in command line
147 # options.
148 self.classes.insert(0, self.__class__)
146 # Ensure my class is in self.classes, so my attributes appear in command line
147 # options and config files.
148 if self.__class__ not in self.classes:
149 self.classes.insert(0, self.__class__)
149 150
150 151 self.init_logging()
151 152
152 153 def _config_changed(self, name, old, new):
153 154 SingletonConfigurable._config_changed(self, name, old, new)
154 155 self.log.debug('Config changed:')
155 156 self.log.debug(repr(new))
156 157
157 158 def init_logging(self):
158 159 """Start logging for this application.
159 160
160 161 The default is to log to stdout using a StreaHandler. The log level
161 162 starts at loggin.WARN, but this can be adjusted by setting the
162 163 ``log_level`` attribute.
163 164 """
164 165 self.log = logging.getLogger(self.__class__.__name__)
165 166 self.log.setLevel(self.log_level)
166 167 if sys.executable.endswith('pythonw.exe'):
167 168 # this should really go to a file, but file-logging is only
168 169 # hooked up in parallel applications
169 170 self._log_handler = logging.StreamHandler(open(os.devnull, 'w'))
170 171 else:
171 172 self._log_handler = logging.StreamHandler()
172 173 self._log_formatter = logging.Formatter("[%(name)s] %(message)s")
173 174 self._log_handler.setFormatter(self._log_formatter)
174 175 self.log.addHandler(self._log_handler)
175 176
176 177 def initialize(self, argv=None):
177 178 """Do the basic steps to configure me.
178 179
179 180 Override in subclasses.
180 181 """
181 182 self.parse_command_line(argv)
182 183
183 184
184 185 def start(self):
185 186 """Start the app mainloop.
186 187
187 188 Override in subclasses.
188 189 """
189 190 if self.subapp is not None:
190 191 return self.subapp.start()
191 192
192 193 def print_alias_help(self):
193 194 """Print the alias part of the help."""
194 195 if not self.aliases:
195 196 return
196 197
197 198 lines = []
198 199 classdict = {}
199 200 for cls in self.classes:
200 201 # include all parents (up to, but excluding Configurable) in available names
201 202 for c in cls.mro()[:-3]:
202 203 classdict[c.__name__] = c
203 204
204 205 for alias, longname in self.aliases.iteritems():
205 206 classname, traitname = longname.split('.',1)
206 207 cls = classdict[classname]
207 208
208 209 trait = cls.class_traits(config=True)[traitname]
209 210 help = cls.class_get_trait_help(trait).splitlines()
210 211 # reformat first line
211 212 help[0] = help[0].replace(longname, alias) + ' (%s)'%longname
212 213 lines.extend(help)
213 214 # lines.append('')
214 215 print os.linesep.join(lines)
215 216
216 217 def print_flag_help(self):
217 218 """Print the flag part of the help."""
218 219 if not self.flags:
219 220 return
220 221
221 222 lines = []
222 223 for m, (cfg,help) in self.flags.iteritems():
223 224 lines.append('--'+m)
224 225 lines.append(indent(dedent(help.strip())))
225 226 # lines.append('')
226 227 print os.linesep.join(lines)
227 228
228 229 def print_options(self):
229 230 if not self.flags and not self.aliases:
230 231 return
231 232 lines = ['Options']
232 233 lines.append('-'*len(lines[0]))
233 234 lines.append('')
234 235 for p in wrap_paragraphs(self.option_description):
235 236 lines.append(p)
236 237 lines.append('')
237 238 print os.linesep.join(lines)
238 239 self.print_flag_help()
239 240 self.print_alias_help()
240 241 print
241 242
242 243 def print_subcommands(self):
243 244 """Print the subcommand part of the help."""
244 245 if not self.subcommands:
245 246 return
246 247
247 248 lines = ["Subcommands"]
248 249 lines.append('-'*len(lines[0]))
249 250 lines.append('')
250 251 for p in wrap_paragraphs(self.subcommand_description):
251 252 lines.append(p)
252 253 lines.append('')
253 254 for subc, (cls, help) in self.subcommands.iteritems():
254 255 lines.append(subc)
255 256 if help:
256 257 lines.append(indent(dedent(help.strip())))
257 258 lines.append('')
258 259 print os.linesep.join(lines)
259 260
260 261 def print_help(self, classes=False):
261 262 """Print the help for each Configurable class in self.classes.
262 263
263 264 If classes=False (the default), only flags and aliases are printed.
264 265 """
265 266 self.print_subcommands()
266 267 self.print_options()
267 268
268 269 if classes:
269 270 if self.classes:
270 271 print "Class parameters"
271 272 print "----------------"
272 273 print
273 274 for p in wrap_paragraphs(self.keyvalue_description):
274 275 print p
275 276 print
276 277
277 278 for cls in self.classes:
278 279 cls.class_print_help()
279 280 print
280 281 else:
281 282 print "To see all available configurables, use `--help-all`"
282 283 print
283 284
284 285 def print_description(self):
285 286 """Print the application description."""
286 287 for p in wrap_paragraphs(self.description):
287 288 print p
288 289 print
289 290
290 291 def print_examples(self):
291 292 """Print usage and examples.
292 293
293 294 This usage string goes at the end of the command line help string
294 295 and should contain examples of the application's usage.
295 296 """
296 297 if self.examples:
297 298 print "Examples"
298 299 print "--------"
299 300 print
300 301 print indent(dedent(self.examples.strip()))
301 302 print
302 303
303 304 def print_version(self):
304 305 """Print the version string."""
305 306 print self.version
306 307
307 308 def update_config(self, config):
308 309 """Fire the traits events when the config is updated."""
309 310 # Save a copy of the current config.
310 311 newconfig = deepcopy(self.config)
311 312 # Merge the new config into the current one.
312 313 newconfig._merge(config)
313 314 # Save the combined config as self.config, which triggers the traits
314 315 # events.
315 316 self.config = newconfig
316 317
317 318 def initialize_subcommand(self, subc, argv=None):
318 319 """Initialize a subcommand with argv."""
319 320 subapp,help = self.subcommands.get(subc)
320 321
321 322 if isinstance(subapp, basestring):
322 323 subapp = import_item(subapp)
323 324
324 325 # clear existing instances
325 326 self.__class__.clear_instance()
326 327 # instantiate
327 328 self.subapp = subapp.instance()
328 329 # and initialize subapp
329 330 self.subapp.initialize(argv)
330 331
331 332 def parse_command_line(self, argv=None):
332 333 """Parse the command line arguments."""
333 334 argv = sys.argv[1:] if argv is None else argv
334 335
335 336 if self.subcommands and len(argv) > 0:
336 337 # we have subcommands, and one may have been specified
337 338 subc, subargv = argv[0], argv[1:]
338 339 if re.match(r'^\w(\-?\w)*$', subc) and subc in self.subcommands:
339 340 # it's a subcommand, and *not* a flag or class parameter
340 341 return self.initialize_subcommand(subc, subargv)
341 342
342 343 if '-h' in argv or '--help' in argv or '--help-all' in argv:
343 344 self.print_description()
344 345 self.print_help('--help-all' in argv)
345 346 self.print_examples()
346 347 self.exit(0)
347 348
348 349 if '--version' in argv:
349 350 self.print_version()
350 351 self.exit(0)
351 352
352 353 loader = KeyValueConfigLoader(argv=argv, aliases=self.aliases,
353 354 flags=self.flags)
354 355 try:
355 356 config = loader.load_config()
356 357 self.update_config(config)
357 358 except (TraitError, ArgumentError) as e:
358 359 self.print_description()
359 360 self.print_help()
360 361 self.print_examples()
361 362 self.log.fatal(str(e))
362 363 self.exit(1)
363 364 # store unparsed args in extra_args
364 365 self.extra_args = loader.extra_args
365 366
366 367 def load_config_file(self, filename, path=None):
367 368 """Load a .py based config file by filename and path."""
368 369 loader = PyFileConfigLoader(filename, path=path)
369 370 try:
370 371 config = loader.load_config()
371 372 except Exception:
372 373 self.log.error("Exception while loading config file %s [path=%s]"%
373 374 (filename, path), exc_info=True)
374 375 else:
375 376 self.update_config(config)
376 377
377 378 def generate_config_file(self):
378 379 """generate default config file from Configurables"""
379 380 lines = ["# Configuration file for %s."%self.name]
380 381 lines.append('')
381 382 lines.append('c = get_config()')
382 383 lines.append('')
383 384 for cls in self.classes:
384 385 lines.append(cls.class_config_section())
385 386 return '\n'.join(lines)
386 387
387 388 def exit(self, exit_status=0):
388 389 self.log.debug("Exiting application: %s" % self.name)
389 390 sys.exit(exit_status)
390 391
391 392 #-----------------------------------------------------------------------------
392 393 # utility functions, for convenience
393 394 #-----------------------------------------------------------------------------
394 395
395 396 def boolean_flag(name, configurable, set_help='', unset_help=''):
396 397 """Helper for building basic --trait, --no-trait flags.
397 398
398 399 Parameters
399 400 ----------
400 401
401 402 name : str
402 403 The name of the flag.
403 404 configurable : str
404 405 The 'Class.trait' string of the trait to be set/unset with the flag
405 406 set_help : unicode
406 407 help string for --name flag
407 408 unset_help : unicode
408 409 help string for --no-name flag
409 410
410 411 Returns
411 412 -------
412 413
413 414 cfg : dict
414 415 A dict with two keys: 'name', and 'no-name', for setting and unsetting
415 416 the trait, respectively.
416 417 """
417 418 # default helpstrings
418 419 set_help = set_help or "set %s=True"%configurable
419 420 unset_help = unset_help or "set %s=False"%configurable
420 421
421 422 cls,trait = configurable.split('.')
422 423
423 424 setter = {cls : {trait : True}}
424 425 unsetter = {cls : {trait : False}}
425 426 return {name : (setter, set_help), 'no-'+name : (unsetter, unset_help)}
426 427
@@ -1,374 +1,383 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 48 from IPython.utils import warn
49 49 from IPython.utils.path import get_ipython_dir, check_for_old_config
50 50 from IPython.utils.traitlets import (
51 Bool, Dict, CaselessStrEnum
51 Bool, List, Dict, CaselessStrEnum
52 52 )
53 53
54 54 #-----------------------------------------------------------------------------
55 55 # Globals, utilities and helpers
56 56 #-----------------------------------------------------------------------------
57 57
58 58 #: The default config file name for this application.
59 59 default_config_file_name = u'ipython_config.py'
60 60
61 61 _examples = """
62 62 ipython --pylab # start in pylab mode
63 63 ipython --pylab=qt # start in pylab mode with the qt4 backend
64 64 ipython --log-level=DEBUG # set logging to DEBUG
65 65 ipython --profile=foo # start with profile foo
66 66
67 67 ipython qtconsole # start the qtconsole GUI application
68 68 ipython qtconsole -h # show the help string for the qtconsole subcmd
69 69
70 70 ipython profile create foo # create profile foo w/ default config files
71 71 ipython profile -h # show the help string for the profile subcmd
72 72 """
73 73
74 74 #-----------------------------------------------------------------------------
75 75 # Crash handler for this application
76 76 #-----------------------------------------------------------------------------
77 77
78 78 class IPAppCrashHandler(CrashHandler):
79 79 """sys.excepthook for IPython itself, leaves a detailed report on disk."""
80 80
81 81 def __init__(self, app):
82 82 contact_name = release.authors['Fernando'][0]
83 83 contact_email = release.authors['Fernando'][1]
84 84 bug_tracker = 'http://github.com/ipython/ipython/issues'
85 85 super(IPAppCrashHandler,self).__init__(
86 86 app, contact_name, contact_email, bug_tracker
87 87 )
88 88
89 89 def make_report(self,traceback):
90 90 """Return a string containing a crash report."""
91 91
92 92 sec_sep = self.section_sep
93 93 # Start with parent report
94 94 report = [super(IPAppCrashHandler, self).make_report(traceback)]
95 95 # Add interactive-specific info we may have
96 96 rpt_add = report.append
97 97 try:
98 98 rpt_add(sec_sep+"History of session input:")
99 99 for line in self.app.shell.user_ns['_ih']:
100 100 rpt_add(line)
101 101 rpt_add('\n*** Last line of input (may not be in above history):\n')
102 102 rpt_add(self.app.shell._last_input_line+'\n')
103 103 except:
104 104 pass
105 105
106 106 return ''.join(report)
107 107
108 108 #-----------------------------------------------------------------------------
109 109 # Aliases and Flags
110 110 #-----------------------------------------------------------------------------
111 111 flags = dict(base_flags)
112 112 flags.update(shell_flags)
113 113 addflag = lambda *args: flags.update(boolean_flag(*args))
114 114 addflag('autoedit-syntax', 'TerminalInteractiveShell.autoedit_syntax',
115 115 'Turn on auto editing of files with syntax errors.',
116 116 'Turn off auto editing of files with syntax errors.'
117 117 )
118 118 addflag('banner', 'TerminalIPythonApp.display_banner',
119 119 "Display a banner upon starting IPython.",
120 120 "Don't display a banner upon starting IPython."
121 121 )
122 122 addflag('confirm-exit', 'TerminalInteractiveShell.confirm_exit',
123 123 """Set to confirm when you try to exit IPython with an EOF (Control-D
124 124 in Unix, Control-Z/Enter in Windows). By typing 'exit' or 'quit',
125 125 you can force a direct exit without any confirmation.""",
126 126 "Don't prompt the user when exiting."
127 127 )
128 128 addflag('term-title', 'TerminalInteractiveShell.term_title',
129 129 "Enable auto setting the terminal title.",
130 130 "Disable auto setting the terminal title."
131 131 )
132 132 classic_config = Config()
133 133 classic_config.InteractiveShell.cache_size = 0
134 134 classic_config.PlainTextFormatter.pprint = False
135 135 classic_config.InteractiveShell.prompt_in1 = '>>> '
136 136 classic_config.InteractiveShell.prompt_in2 = '... '
137 137 classic_config.InteractiveShell.prompt_out = ''
138 138 classic_config.InteractiveShell.separate_in = ''
139 139 classic_config.InteractiveShell.separate_out = ''
140 140 classic_config.InteractiveShell.separate_out2 = ''
141 141 classic_config.InteractiveShell.colors = 'NoColor'
142 142 classic_config.InteractiveShell.xmode = 'Plain'
143 143
144 144 flags['classic']=(
145 145 classic_config,
146 146 "Gives IPython a similar feel to the classic Python prompt."
147 147 )
148 148 # # log doesn't make so much sense this way anymore
149 149 # paa('--log','-l',
150 150 # action='store_true', dest='InteractiveShell.logstart',
151 151 # help="Start logging to the default log file (./ipython_log.py).")
152 152 #
153 153 # # quick is harder to implement
154 154 flags['quick']=(
155 155 {'TerminalIPythonApp' : {'quick' : True}},
156 156 "Enable quick startup with no config files."
157 157 )
158 158
159 159 flags['i'] = (
160 160 {'TerminalIPythonApp' : {'force_interact' : True}},
161 161 """If running code from the command line, become interactive afterwards.
162 162 Note: can also be given simply as '-i.'"""
163 163 )
164 164 flags['pylab'] = (
165 165 {'TerminalIPythonApp' : {'pylab' : 'auto'}},
166 166 """Pre-load matplotlib and numpy for interactive use with
167 167 the default matplotlib backend."""
168 168 )
169 169
170 170 aliases = dict(base_aliases)
171 171 aliases.update(shell_aliases)
172 172
173 173 # it's possible we don't want short aliases for *all* of these:
174 174 aliases.update(dict(
175 175 gui='TerminalIPythonApp.gui',
176 176 pylab='TerminalIPythonApp.pylab',
177 177 ))
178 178
179 179 #-----------------------------------------------------------------------------
180 180 # Main classes and functions
181 181 #-----------------------------------------------------------------------------
182 182
183 183 class TerminalIPythonApp(BaseIPythonApplication, InteractiveShellApp):
184 184 name = u'ipython'
185 185 description = usage.cl_usage
186 186 default_config_file_name = default_config_file_name
187 187 crash_handler_class = IPAppCrashHandler
188 188 examples = _examples
189 189
190 190 flags = Dict(flags)
191 191 aliases = Dict(aliases)
192 classes = [InteractiveShellApp, TerminalInteractiveShell, ProfileDir,
193 PlainTextFormatter]
192 classes = List()
193 def _classes_default(self):
194 """This has to be in a method, for TerminalIPythonApp to be available."""
195 return [
196 InteractiveShellApp, # ShellApp comes before TerminalApp, because
197 self.__class__, # it will also affect subclasses (e.g. QtConsole)
198 TerminalInteractiveShell,
199 ProfileDir,
200 PlainTextFormatter,
201 ]
202
194 203 subcommands = Dict(dict(
195 204 qtconsole=('IPython.frontend.qt.console.qtconsoleapp.IPythonQtConsoleApp',
196 205 """Launch the IPython Qt Console."""
197 206 ),
198 207 profile = ("IPython.core.profileapp.ProfileApp",
199 208 "Create and manage IPython profiles.")
200 209 ))
201 210
202 211 # *do* autocreate requested profile, but don't create the config file.
203 212 auto_create=Bool(True)
204 213 # configurables
205 214 ignore_old_config=Bool(False, config=True,
206 215 help="Suppress warning messages about legacy config files"
207 216 )
208 217 quick = Bool(False, config=True,
209 218 help="""Start IPython quickly by skipping the loading of config files."""
210 219 )
211 220 def _quick_changed(self, name, old, new):
212 221 if new:
213 222 self.load_config_file = lambda *a, **kw: None
214 223 self.ignore_old_config=True
215 224
216 225 gui = CaselessStrEnum(('qt','wx','gtk'), config=True,
217 226 help="Enable GUI event loop integration ('qt', 'wx', 'gtk')."
218 227 )
219 228 pylab = CaselessStrEnum(['tk', 'qt', 'wx', 'gtk', 'osx', 'auto'],
220 229 config=True,
221 230 help="""Pre-load matplotlib and numpy for interactive use,
222 231 selecting a particular matplotlib backend and loop integration.
223 232 """
224 233 )
225 234 display_banner = Bool(True, config=True,
226 235 help="Whether to display a banner upon starting IPython."
227 236 )
228 237
229 238 # if there is code of files to run from the cmd line, don't interact
230 239 # unless the --i flag (App.force_interact) is true.
231 240 force_interact = Bool(False, config=True,
232 241 help="""If a command or file is given via the command-line,
233 242 e.g. 'ipython foo.py"""
234 243 )
235 244 def _force_interact_changed(self, name, old, new):
236 245 if new:
237 246 self.interact = True
238 247
239 248 def _file_to_run_changed(self, name, old, new):
240 249 if new and not self.force_interact:
241 250 self.interact = False
242 251 _code_to_run_changed = _file_to_run_changed
243 252
244 253 # internal, not-configurable
245 254 interact=Bool(True)
246 255
247 256
248 257 def parse_command_line(self, argv=None):
249 258 """override to allow old '-pylab' flag with deprecation warning"""
250 259
251 260 argv = sys.argv[1:] if argv is None else argv
252 261
253 262 if '-pylab' in argv:
254 263 # deprecated `-pylab` given,
255 264 # warn and transform into current syntax
256 265 argv = argv[:] # copy, don't clobber
257 266 idx = argv.index('-pylab')
258 267 warn.warn("`-pylab` flag has been deprecated.\n"
259 268 " Use `--pylab` instead, or `--pylab=foo` to specify a backend.")
260 269 sub = '--pylab'
261 270 if len(argv) > idx+1:
262 271 # check for gui arg, as in '-pylab qt'
263 272 gui = argv[idx+1]
264 273 if gui in ('wx', 'qt', 'qt4', 'gtk', 'auto'):
265 274 sub = '--pylab='+gui
266 275 argv.pop(idx+1)
267 276 argv[idx] = sub
268 277
269 278 return super(TerminalIPythonApp, self).parse_command_line(argv)
270 279
271 280 def initialize(self, argv=None):
272 281 """Do actions after construct, but before starting the app."""
273 282 super(TerminalIPythonApp, self).initialize(argv)
274 283 if self.subapp is not None:
275 284 # don't bother initializing further, starting subapp
276 285 return
277 286 if not self.ignore_old_config:
278 287 check_for_old_config(self.ipython_dir)
279 288 # print self.extra_args
280 289 if self.extra_args:
281 290 self.file_to_run = self.extra_args[0]
282 291 # create the shell
283 292 self.init_shell()
284 293 # and draw the banner
285 294 self.init_banner()
286 295 # Now a variety of things that happen after the banner is printed.
287 296 self.init_gui_pylab()
288 297 self.init_extensions()
289 298 self.init_code()
290 299
291 300 def init_shell(self):
292 301 """initialize the InteractiveShell instance"""
293 302 # I am a little hesitant to put these into InteractiveShell itself.
294 303 # But that might be the place for them
295 304 sys.path.insert(0, '')
296 305
297 306 # Create an InteractiveShell instance.
298 307 # shell.display_banner should always be False for the terminal
299 308 # based app, because we call shell.show_banner() by hand below
300 309 # so the banner shows *before* all extension loading stuff.
301 310 self.shell = TerminalInteractiveShell.instance(config=self.config,
302 311 display_banner=False, profile_dir=self.profile_dir,
303 312 ipython_dir=self.ipython_dir)
304 313
305 314 def init_banner(self):
306 315 """optionally display the banner"""
307 316 if self.display_banner and self.interact:
308 317 self.shell.show_banner()
309 318 # Make sure there is a space below the banner.
310 319 if self.log_level <= logging.INFO: print
311 320
312 321
313 322 def init_gui_pylab(self):
314 323 """Enable GUI event loop integration, taking pylab into account."""
315 324 gui = self.gui
316 325
317 326 # Using `pylab` will also require gui activation, though which toolkit
318 327 # to use may be chosen automatically based on mpl configuration.
319 328 if self.pylab:
320 329 activate = self.shell.enable_pylab
321 330 if self.pylab == 'auto':
322 331 gui = None
323 332 else:
324 333 gui = self.pylab
325 334 else:
326 335 # Enable only GUI integration, no pylab
327 336 activate = inputhook.enable_gui
328 337
329 338 if gui or self.pylab:
330 339 try:
331 340 self.log.info("Enabling GUI event loop integration, "
332 341 "toolkit=%s, pylab=%s" % (gui, self.pylab) )
333 342 activate(gui)
334 343 except:
335 344 self.log.warn("Error in enabling GUI event loop integration:")
336 345 self.shell.showtraceback()
337 346
338 347 def start(self):
339 348 if self.subapp is not None:
340 349 return self.subapp.start()
341 350 # perform any prexec steps:
342 351 if self.interact:
343 352 self.log.debug("Starting IPython's mainloop...")
344 353 self.shell.mainloop()
345 354 else:
346 355 self.log.debug("IPython not interactive...")
347 356
348 357
349 358 def load_default_config(ipython_dir=None):
350 359 """Load the default config file from the default ipython_dir.
351 360
352 361 This is useful for embedded shells.
353 362 """
354 363 if ipython_dir is None:
355 364 ipython_dir = get_ipython_dir()
356 365 profile_dir = os.path.join(ipython_dir, 'profile_default')
357 366 cl = PyFileConfigLoader(default_config_file_name, profile_dir)
358 367 try:
359 368 config = cl.load_config()
360 369 except IOError:
361 370 # no config found
362 371 config = Config()
363 372 return config
364 373
365 374
366 375 def launch_new_instance():
367 376 """Create and run a full blown IPython instance"""
368 377 app = TerminalIPythonApp.instance()
369 378 app.initialize()
370 379 app.start()
371 380
372 381
373 382 if __name__ == '__main__':
374 383 launch_new_instance()
General Comments 0
You need to be logged in to leave comments. Login now