##// END OF EJS Templates
Ported the IPython Sphinx directive to 0.11....
Fernando Perez -
Show More
This diff has been collapsed as it changes many lines, (641 lines changed) Show them Hide them
@@ -0,0 +1,641 b''
1 # -*- coding: utf-8 -*-
2 """Sphinx directive to support embedded IPython code.
3
4 This directive allows pasting of entire interactive IPython sessions, prompts
5 and all, and their code will actually get re-executed at doc build time, with
6 all prompts renumbered sequentially.
7
8 To enable this directive, simply list it in your Sphinx ``conf.py`` file
9 (making sure the directory where you placed it is visible to sphinx, as is
10 needed for all Sphinx directives).
11
12 By default this directive assumes that your prompts are unchanged IPython ones,
13 but this can be customized. For example, the following code in your Sphinx
14 config file will configure this directive for the following input/output
15 prompts ``Yade [1]:`` and ``-> [1]:``::
16
17 import ipython_directive as id
18 id.rgxin =re.compile(r'(?:In |Yade )\[(\d+)\]:\s?(.*)\s*')
19 id.rgxout=re.compile(r'(?:Out| -> )\[(\d+)\]:\s?(.*)\s*')
20 id.fmtin ='Yade [%d]:'
21 id.fmtout=' -> [%d]:'
22
23 from IPython import Config
24 id.CONFIG = Config(
25 prompt_in1="Yade [\#]:",
26 prompt_in2=" .\D..",
27 prompt_out=" -> [\#]:"
28 )
29 id.reconfig_shell()
30
31 import ipython_console_highlighting as ich
32 ich.IPythonConsoleLexer.input_prompt=
33 re.compile("(Yade \[[0-9]+\]: )|( \.\.\.+:)")
34 ich.IPythonConsoleLexer.output_prompt=
35 re.compile("(( -> )|(Out)\[[0-9]+\]: )|( \.\.\.+:)")
36 ich.IPythonConsoleLexer.continue_prompt=re.compile(" \.\.\.+:")
37
38
39 ToDo
40 ----
41
42 - Turn the ad-hoc test() function into a real test suite.
43 - Break up ipython-specific functionality from matplotlib stuff into better
44 separated code.
45 - Make sure %bookmarks used internally are removed on exit.
46
47
48 Authors
49 -------
50
51 - John D Hunter: orignal author.
52 - Fernando Perez: refactoring, documentation, cleanups, port to 0.11.
53 - VΓ‘clavΕ milauer <eudoxos-AT-arcig.cz>: Prompt generalizations.
54 """
55
56 #-----------------------------------------------------------------------------
57 # Imports
58 #-----------------------------------------------------------------------------
59
60 # Stdlib
61 import cStringIO
62 import imp
63 import os
64 import re
65 import shutil
66 import sys
67 import warnings
68
69 # To keep compatibility with various python versions
70 try:
71 from hashlib import md5
72 except ImportError:
73 from md5 import md5
74
75 # Third-party
76 import matplotlib
77 import sphinx
78 from docutils.parsers.rst import directives
79
80 matplotlib.use('Agg')
81
82 # Our own
83 from IPython import Config, IPythonApp
84 from IPython.utils.genutils import Term, Tee
85
86 #-----------------------------------------------------------------------------
87 # Globals
88 #-----------------------------------------------------------------------------
89
90 sphinx_version = sphinx.__version__.split(".")
91 # The split is necessary for sphinx beta versions where the string is
92 # '6b1'
93 sphinx_version = tuple([int(re.split('[a-z]', x)[0])
94 for x in sphinx_version[:2]])
95
96 COMMENT, INPUT, OUTPUT = range(3)
97 CONFIG = Config()
98 rgxin = re.compile('In \[(\d+)\]:\s?(.*)\s*')
99 rgxout = re.compile('Out\[(\d+)\]:\s?(.*)\s*')
100 fmtin = 'In [%d]:'
101 fmtout = 'Out[%d]:'
102
103 #-----------------------------------------------------------------------------
104 # Functions and class declarations
105 #-----------------------------------------------------------------------------
106 def block_parser(part):
107 """
108 part is a string of ipython text, comprised of at most one
109 input, one ouput, comments, and blank lines. The block parser
110 parses the text into a list of::
111
112 blocks = [ (TOKEN0, data0), (TOKEN1, data1), ...]
113
114 where TOKEN is one of [COMMENT | INPUT | OUTPUT ] and
115 data is, depending on the type of token::
116
117 COMMENT : the comment string
118
119 INPUT: the (DECORATOR, INPUT_LINE, REST) where
120 DECORATOR: the input decorator (or None)
121 INPUT_LINE: the input as string (possibly multi-line)
122 REST : any stdout generated by the input line (not OUTPUT)
123
124
125 OUTPUT: the output string, possibly multi-line
126 """
127
128 block = []
129 lines = part.split('\n')
130 N = len(lines)
131 i = 0
132 decorator = None
133 while 1:
134
135 if i==N:
136 # nothing left to parse -- the last line
137 break
138
139 line = lines[i]
140 i += 1
141 line_stripped = line.strip()
142 if line_stripped.startswith('#'):
143 block.append((COMMENT, line))
144 continue
145
146 if line_stripped.startswith('@'):
147 # we're assuming at most one decorator -- may need to
148 # rethink
149 decorator = line_stripped
150 continue
151
152 # does this look like an input line?
153 matchin = rgxin.match(line)
154 if matchin:
155 lineno, inputline = int(matchin.group(1)), matchin.group(2)
156
157 # the ....: continuation string
158 continuation = ' %s:'%''.join(['.']*(len(str(lineno))+2))
159 Nc = len(continuation)
160 # input lines can continue on for more than one line, if
161 # we have a '\' line continuation char or a function call
162 # echo line 'print'. The input line can only be
163 # terminated by the end of the block or an output line, so
164 # we parse out the rest of the input line if it is
165 # multiline as well as any echo text
166
167 rest = []
168 while i<N:
169
170 # look ahead; if the next line is blank, or a comment, or
171 # an output line, we're done
172
173 nextline = lines[i]
174 matchout = rgxout.match(nextline)
175 #print "nextline=%s, continuation=%s, starts=%s"%(nextline, continuation, nextline.startswith(continuation))
176 if matchout or nextline.startswith('#'):
177 break
178 elif nextline.startswith(continuation):
179 inputline += '\n' + nextline[Nc:]
180 else:
181 rest.append(nextline)
182 i+= 1
183
184 block.append((INPUT, (decorator, inputline, '\n'.join(rest))))
185 continue
186
187 # if it looks like an output line grab all the text to the end
188 # of the block
189 matchout = rgxout.match(line)
190 if matchout:
191 lineno, output = int(matchout.group(1)), matchout.group(2)
192 if i<N-1:
193 output = '\n'.join([output] + lines[i:])
194
195 block.append((OUTPUT, output))
196 break
197
198 return block
199
200
201 class EmbeddedSphinxShell(object):
202 """An embedded IPython instance to run inside Sphinx"""
203
204 def __init__(self):
205
206 self.cout = cStringIO.StringIO()
207 Term.cout = self.cout
208 Term.cerr = self.cout
209
210 # For debugging, so we can see normal output, use this:
211 #Term.cout = genutils.Tee(self.cout, channel='stdout') # dbg
212 #Term.cerr = genutils.Tee(self.cout, channel='stderr') # dbg
213
214 # Create config object for IPython
215 config = Config()
216 config.Global.display_banner = False
217 config.Global.exec_lines = ['import numpy as np',
218 'from pylab import *'
219 ]
220 config.InteractiveShell.autocall = False
221 config.InteractiveShell.autoindent = False
222 config.InteractiveShell.colors = 'NoColor'
223
224 # Merge global config which can be used to override.
225 config._merge(CONFIG)
226
227 # Create and initialize ipython, but don't start its mainloop
228 IP = IPythonApp(override_config=config)
229 IP.initialize()
230
231 # Store a few parts of IPython we'll need.
232 self.IP = IP.shell
233 self.user_ns = self.IP.user_ns
234 self.user_global_ns = self.IP.user_global_ns
235
236 self.input = ''
237 self.output = ''
238
239 self.is_verbatim = False
240 self.is_doctest = False
241 self.is_suppress = False
242
243 # on the first call to the savefig decorator, we'll import
244 # pyplot as plt so we can make a call to the plt.gcf().savefig
245 self._pyplot_imported = False
246
247 # we need bookmark the current dir first so we can save
248 # relative to it
249 self.process_input_line('bookmark ipy_basedir')
250 self.cout.seek(0)
251 self.cout.truncate(0)
252
253 def process_input_line(self, line):
254 """process the input, capturing stdout"""
255 #print "input='%s'"%self.input
256 stdout = sys.stdout
257 try:
258 sys.stdout = self.cout
259 self.IP.push_line(line)
260 finally:
261 sys.stdout = stdout
262
263 # Callbacks for each type of token
264 def process_input(self, data, input_prompt, lineno):
265 """Process data block for INPUT token."""
266 decorator, input, rest = data
267 image_file = None
268 #print 'INPUT:', data # dbg
269 is_verbatim = decorator=='@verbatim' or self.is_verbatim
270 is_doctest = decorator=='@doctest' or self.is_doctest
271 is_suppress = decorator=='@suppress' or self.is_suppress
272 is_savefig = decorator is not None and \
273 decorator.startswith('@savefig')
274
275 input_lines = input.split('\n')
276
277 continuation = ' %s:'%''.join(['.']*(len(str(lineno))+2))
278 Nc = len(continuation)
279
280 if is_savefig:
281 saveargs = decorator.split(' ')
282 filename = saveargs[1]
283 outfile = os.path.join('_static/%s'%filename)
284 # build out an image directive like
285 # .. image:: somefile.png
286 # :width 4in
287 #
288 # from an input like
289 # savefig somefile.png width=4in
290 imagerows = ['.. image:: %s'%outfile]
291
292 for kwarg in saveargs[2:]:
293 arg, val = kwarg.split('=')
294 arg = arg.strip()
295 val = val.strip()
296 imagerows.append(' :%s: %s'%(arg, val))
297
298 image_file = outfile
299 image_directive = '\n'.join(imagerows)
300
301 # TODO: can we get "rest" from ipython
302 #self.process_input_line('\n'.join(input_lines))
303
304 ret = []
305 is_semicolon = False
306
307 for i, line in enumerate(input_lines):
308 if line.endswith(';'):
309 is_semicolon = True
310
311 if i==0:
312 # process the first input line
313 if is_verbatim:
314 self.process_input_line('')
315 else:
316 # only submit the line in non-verbatim mode
317 self.process_input_line(line)
318 formatted_line = '%s %s'%(input_prompt, line)
319 else:
320 # process a continuation line
321 if not is_verbatim:
322 self.process_input_line(line)
323
324 formatted_line = '%s %s'%(continuation, line)
325
326 if not is_suppress:
327 ret.append(formatted_line)
328
329 if not is_suppress:
330 if len(rest.strip()):
331 if is_verbatim:
332 # the "rest" is the standard output of the
333 # input, which needs to be added in
334 # verbatim mode
335 ret.append(rest)
336
337 self.cout.seek(0)
338 output = self.cout.read()
339 if not is_suppress and not is_semicolon:
340 ret.append(output)
341
342 self.cout.truncate(0)
343 return ret, input_lines, output, is_doctest, image_file
344 #print 'OUTPUT', output # dbg
345
346 def process_output(self, data, output_prompt,
347 input_lines, output, is_doctest, image_file):
348 """Process data block for OUTPUT token."""
349 if is_doctest:
350 submitted = data.strip()
351 found = output
352 if found is not None:
353 found = found.strip()
354
355 # XXX - fperez: in 0.11, 'output' never comes with the prompt
356 # in it, just the actual output text. So I think all this code
357 # can be nuked...
358 ## ind = found.find(output_prompt)
359 ## if ind<0:
360 ## e='output prompt="%s" does not match out line=%s' % \
361 ## (output_prompt, found)
362 ## raise RuntimeError(e)
363 ## found = found[len(output_prompt):].strip()
364
365 if found!=submitted:
366 e = ('doctest failure for input_lines="%s" with '
367 'found_output="%s" and submitted output="%s"' %
368 (input_lines, found, submitted) )
369 raise RuntimeError(e)
370 #print 'doctest PASSED for input_lines="%s" with found_output="%s" and submitted output="%s"'%(input_lines, found, submitted)
371
372 def process_comment(self, data):
373 """Process data block for COMMENT token."""
374 if not self.is_suppress:
375 return [data]
376
377 def process_block(self, block):
378 """
379 process block from the block_parser and return a list of processed lines
380 """
381
382 ret = []
383 output = None
384 input_lines = None
385
386 m = rgxin.match(str(self.IP.outputcache.prompt1).strip())
387 lineno = int(m.group(1))
388
389 input_prompt = fmtin%lineno
390 output_prompt = fmtout%lineno
391 image_file = None
392 image_directive = None
393 # XXX - This needs a second refactor. There's too much state being
394 # held globally, which makes for a very awkward interface and large,
395 # hard to test functions. I've already broken this up at least into
396 # three separate processors to isolate the logic better, but this only
397 # serves to highlight the coupling. Next we need to clean it up...
398 for token, data in block:
399 if token==COMMENT:
400 out_data = self.process_comment(data)
401 elif token==INPUT:
402 out_data, input_lines, output, is_doctest, image_file= \
403 self.process_input(data, input_prompt, lineno)
404 elif token==OUTPUT:
405 out_data = \
406 self.process_output(data, output_prompt,
407 input_lines, output, is_doctest,
408 image_file)
409 if out_data:
410 ret.extend(out_data)
411
412 if image_file is not None:
413 self.ensure_pyplot()
414 command = 'plt.gcf().savefig("%s")'%image_file
415 print 'SAVEFIG', command # dbg
416 self.process_input_line('bookmark ipy_thisdir')
417 self.process_input_line('cd -b ipy_basedir')
418 self.process_input_line(command)
419 self.process_input_line('cd -b ipy_thisdir')
420 self.cout.seek(0)
421 self.cout.truncate(0)
422 return ret, image_directive
423
424 def ensure_pyplot(self):
425 if self._pyplot_imported:
426 return
427 self.process_input_line('import matplotlib.pyplot as plt')
428
429 # A global instance used below. XXX: not sure why this can't be created inside
430 # ipython_directive itself.
431 shell = EmbeddedSphinxShell()
432
433 def reconfig_shell():
434 """Called after setting module-level variables to re-instantiate
435 with the set values (since shell is instantiated first at import-time
436 when module variables have default values)"""
437 global shell
438 shell = EmbeddedSphinxShell()
439
440
441 def ipython_directive(name, arguments, options, content, lineno,
442 content_offset, block_text, state, state_machine,
443 ):
444
445 debug = ipython_directive.DEBUG
446 shell.is_suppress = options.has_key('suppress')
447 shell.is_doctest = options.has_key('doctest')
448 shell.is_verbatim = options.has_key('verbatim')
449
450 #print 'ipy', shell.is_suppress, options
451 parts = '\n'.join(content).split('\n\n')
452 lines = ['.. sourcecode:: ipython', '']
453
454 figures = []
455 for part in parts:
456 block = block_parser(part)
457
458 if len(block):
459 rows, figure = shell.process_block(block)
460 for row in rows:
461 lines.extend([' %s'%line for line in row.split('\n')])
462
463 if figure is not None:
464 figures.append(figure)
465
466 for figure in figures:
467 lines.append('')
468 lines.extend(figure.split('\n'))
469 lines.append('')
470
471 #print lines
472 if len(lines)>2:
473 if debug:
474 print '\n'.join(lines)
475 else:
476 #print 'INSERTING %d lines'%len(lines)
477 state_machine.insert_input(
478 lines, state_machine.input_lines.source(0))
479
480 return []
481
482 ipython_directive.DEBUG = False
483 ipython_directive.DEBUG = True # dbg
484
485 # Enable as a proper Sphinx directive
486 def setup(app):
487 setup.app = app
488 options = {'suppress': directives.flag,
489 'doctest': directives.flag,
490 'verbatim': directives.flag,
491 }
492
493 app.add_directive('ipython', ipython_directive, True, (0, 2, 0), **options)
494
495
496 # Simple smoke test, needs to be converted to a proper automatic test.
497 def test():
498
499 examples = [
500 r"""
501 In [9]: pwd
502 Out[9]: '/home/jdhunter/py4science/book'
503
504 In [10]: cd bookdata/
505 /home/jdhunter/py4science/book/bookdata
506
507 In [2]: from pylab import *
508
509 In [2]: ion()
510
511 In [3]: im = imread('stinkbug.png')
512
513 @savefig mystinkbug.png width=4in
514 In [4]: imshow(im)
515 Out[4]: <matplotlib.image.AxesImage object at 0x39ea850>
516
517 """,
518 r"""
519
520 In [1]: x = 'hello world'
521
522 # string methods can be
523 # used to alter the string
524 @doctest
525 In [2]: x.upper()
526 Out[2]: 'HELLO WORLD'
527
528 @verbatim
529 In [3]: x.st<TAB>
530 x.startswith x.strip
531 """,
532 r"""
533
534 In [130]: url = 'http://ichart.finance.yahoo.com/table.csv?s=CROX\
535 .....: &d=9&e=22&f=2009&g=d&a=1&br=8&c=2006&ignore=.csv'
536
537 In [131]: print url.split('&')
538 ['http://ichart.finance.yahoo.com/table.csv?s=CROX', 'd=9', 'e=22', 'f=2009', 'g=d', 'a=1', 'b=8', 'c=2006', 'ignore=.csv']
539
540 In [60]: import urllib
541
542 """,
543 r"""\
544
545 In [133]: import numpy.random
546
547 @suppress
548 In [134]: numpy.random.seed(2358)
549
550 @doctest
551 In [135]: np.random.rand(10,2)
552 Out[135]:
553 array([[ 0.64524308, 0.59943846],
554 [ 0.47102322, 0.8715456 ],
555 [ 0.29370834, 0.74776844],
556 [ 0.99539577, 0.1313423 ],
557 [ 0.16250302, 0.21103583],
558 [ 0.81626524, 0.1312433 ],
559 [ 0.67338089, 0.72302393],
560 [ 0.7566368 , 0.07033696],
561 [ 0.22591016, 0.77731835],
562 [ 0.0072729 , 0.34273127]])
563
564 """,
565
566 r"""
567 In [106]: print x
568 jdh
569
570 In [109]: for i in range(10):
571 .....: print i
572 .....:
573 .....:
574 0
575 1
576 2
577 3
578 4
579 5
580 6
581 7
582 8
583 9
584 """,
585
586 r"""
587
588 In [144]: from pylab import *
589
590 In [145]: ion()
591
592 # use a semicolon to suppress the output
593 @savefig test_hist.png width=4in
594 In [151]: hist(np.random.randn(10000), 100);
595
596
597 @savefig test_plot.png width=4in
598 In [151]: plot(np.random.randn(10000), 'o');
599 """,
600
601 r"""
602 # use a semicolon to suppress the output
603 In [151]: plt.clf()
604
605 @savefig plot_simple.png width=4in
606 In [151]: plot([1,2,3])
607
608 @savefig hist_simple.png width=4in
609 In [151]: hist(np.random.randn(10000), 100);
610
611 """,
612 r"""
613 # update the current fig
614 In [151]: ylabel('number')
615
616 In [152]: title('normal distribution')
617
618
619 @savefig hist_with_text.png
620 In [153]: grid(True)
621
622 """,
623 ]
624
625 #ipython_directive.DEBUG = True # dbg
626 #options = dict(suppress=True) # dbg
627 options = dict()
628 for example in examples:
629 content = example.split('\n')
630 ipython_directive('debug', arguments=None, options=options,
631 content=content, lineno=0,
632 content_offset=None, block_text=None,
633 state=None, state_machine=None,
634 )
635
636 # Run test suite as a script
637 if __name__=='__main__':
638 if not os.path.isdir('_static'):
639 os.mkdir('_static')
640 test()
641 print 'All OK? Check figures in _static/'
@@ -1,63 +1,67 b''
1 #!/usr/bin/env python
1 #!/usr/bin/env python
2 # encoding: utf-8
2 # encoding: utf-8
3 """
3 """
4 IPython.
4 IPython.
5
5
6 IPython is a set of tools for interactive and exploratory computing in Python.
6 IPython is a set of tools for interactive and exploratory computing in Python.
7 """
7 """
8
8
9 #-----------------------------------------------------------------------------
9 #-----------------------------------------------------------------------------
10 # Copyright (C) 2008-2009 The IPython Development Team
10 # Copyright (C) 2008-2009 The IPython Development Team
11 #
11 #
12 # Distributed under the terms of the BSD License. The full license is in
12 # Distributed under the terms of the BSD License. The full license is in
13 # the file COPYING, distributed as part of this software.
13 # the file COPYING, distributed as part of this software.
14 #-----------------------------------------------------------------------------
14 #-----------------------------------------------------------------------------
15
15
16 #-----------------------------------------------------------------------------
16 #-----------------------------------------------------------------------------
17 # Imports
17 # Imports
18 #-----------------------------------------------------------------------------
18 #-----------------------------------------------------------------------------
19 from __future__ import absolute_import
19
20
20 import os
21 import os
21 import sys
22 import sys
22 from IPython.core import release
23
23
24 #-----------------------------------------------------------------------------
24 #-----------------------------------------------------------------------------
25 # Setup everything
25 # Setup everything
26 #-----------------------------------------------------------------------------
26 #-----------------------------------------------------------------------------
27
27
28 if sys.version[0:3] < '2.5':
28 if sys.version[0:3] < '2.5':
29 raise ImportError('Python Version 2.5 or above is required for IPython.')
29 raise ImportError('Python Version 2.5 or above is required for IPython.')
30
30
31
31
32 # Make it easy to import extensions - they are always directly on pythonpath.
32 # Make it easy to import extensions - they are always directly on pythonpath.
33 # Therefore, non-IPython modules can be added to extensions directory
33 # Therefore, non-IPython modules can be added to extensions directory
34 sys.path.append(os.path.join(os.path.dirname(__file__), "extensions"))
34 sys.path.append(os.path.join(os.path.dirname(__file__), "extensions"))
35
35
36 #-----------------------------------------------------------------------------
36 #-----------------------------------------------------------------------------
37 # Setup the top level names
37 # Setup the top level names
38 #-----------------------------------------------------------------------------
38 #-----------------------------------------------------------------------------
39
39
40 # In some cases, these are causing circular imports.
40 # In some cases, these are causing circular imports.
41 from IPython.core.iplib import InteractiveShell
41 from .config.loader import Config
42 from IPython.core.embed import embed
42 from .core import release
43 from IPython.core.error import TryNext
43 from .core.application import Application
44 from IPython.testing import test
44 from .core.ipapp import IPythonApp
45 from .core.embed import embed
46 from .core.error import TryNext
47 from .core.iplib import InteractiveShell
48 from .testing import test
45
49
46 from IPython.lib import (
50 from .lib import (
47 enable_wx, disable_wx,
51 enable_wx, disable_wx,
48 enable_gtk, disable_gtk,
52 enable_gtk, disable_gtk,
49 enable_qt4, disable_qt4,
53 enable_qt4, disable_qt4,
50 enable_tk, disable_tk,
54 enable_tk, disable_tk,
51 set_inputhook, clear_inputhook,
55 set_inputhook, clear_inputhook,
52 current_gui, spin,
56 current_gui, spin,
53 appstart_qt4, appstart_wx,
57 appstart_qt4, appstart_wx,
54 appstart_gtk, appstart_tk
58 appstart_gtk, appstart_tk
55 )
59 )
56
60
57 # Release data
61 # Release data
58 __author__ = ''
62 __author__ = ''
59 for author, email in release.authors.values():
63 for author, email in release.authors.values():
60 __author__ += author + ' <' + email + '>\n'
64 __author__ += author + ' <' + email + '>\n'
61 __license__ = release.license
65 __license__ = release.license
62 __version__ = release.version
66 __version__ = release.version
63 __revision__ = release.revision
67 __revision__ = release.revision
@@ -1,417 +1,490 b''
1 #!/usr/bin/env python
1 #!/usr/bin/env python
2 # encoding: utf-8
2 # encoding: utf-8
3 """
3 """
4 An application for IPython.
4 An application for IPython.
5
5
6 All top-level applications should use the classes in this module for
6 All top-level applications should use the classes in this module for
7 handling configuration and creating componenets.
7 handling configuration and creating componenets.
8
8
9 The job of an :class:`Application` is to create the master configuration
9 The job of an :class:`Application` is to create the master configuration
10 object and then create the components, passing the config to them.
10 object and then create the components, passing the config to them.
11
11
12 Authors:
12 Authors:
13
13
14 * Brian Granger
14 * Brian Granger
15 * Fernando Perez
15 * Fernando Perez
16
16
17 Notes
17 Notes
18 -----
18 -----
19 """
19 """
20
20
21 #-----------------------------------------------------------------------------
21 #-----------------------------------------------------------------------------
22 # Copyright (C) 2008-2009 The IPython Development Team
22 # Copyright (C) 2008-2009 The IPython Development Team
23 #
23 #
24 # Distributed under the terms of the BSD License. The full license is in
24 # Distributed under the terms of the BSD License. The full license is in
25 # the file COPYING, distributed as part of this software.
25 # the file COPYING, distributed as part of this software.
26 #-----------------------------------------------------------------------------
26 #-----------------------------------------------------------------------------
27
27
28 #-----------------------------------------------------------------------------
28 #-----------------------------------------------------------------------------
29 # Imports
29 # Imports
30 #-----------------------------------------------------------------------------
30 #-----------------------------------------------------------------------------
31
31
32 import logging
32 import logging
33 import os
33 import os
34 import sys
34 import sys
35
35
36 from IPython.core import release, crashhandler
36 from IPython.core import release, crashhandler
37 from IPython.utils.genutils import get_ipython_dir, get_ipython_package_dir
37 from IPython.utils.genutils import get_ipython_dir, get_ipython_package_dir
38 from IPython.config.loader import (
38 from IPython.config.loader import (
39 PyFileConfigLoader,
39 PyFileConfigLoader,
40 ArgParseConfigLoader,
40 ArgParseConfigLoader,
41 Config,
41 Config,
42 )
42 )
43
43
44 #-----------------------------------------------------------------------------
44 #-----------------------------------------------------------------------------
45 # Classes and functions
45 # Classes and functions
46 #-----------------------------------------------------------------------------
46 #-----------------------------------------------------------------------------
47
47
48 class ApplicationError(Exception):
48 class ApplicationError(Exception):
49 pass
49 pass
50
50
51
51
52 app_cl_args = (
52 app_cl_args = (
53 (('--ipython-dir', ), dict(
53 (('--ipython-dir', ), dict(
54 dest='Global.ipython_dir',type=unicode,
54 dest='Global.ipython_dir',type=unicode,
55 help=
55 help=
56 """Set to override default location of the IPython directory
56 """Set to override default location of the IPython directory
57 IPYTHON_DIR, stored as Global.ipython_dir. This can also be specified
57 IPYTHON_DIR, stored as Global.ipython_dir. This can also be specified
58 through the environment variable IPYTHON_DIR.""",
58 through the environment variable IPYTHON_DIR.""",
59 metavar='Global.ipython_dir') ),
59 metavar='Global.ipython_dir') ),
60 (('-p', '--profile',), dict(
60 (('-p', '--profile',), dict(
61 dest='Global.profile',type=unicode,
61 dest='Global.profile',type=unicode,
62 help=
62 help=
63 """The string name of the ipython profile to be used. Assume that your
63 """The string name of the ipython profile to be used. Assume that your
64 config file is ipython_config-<name>.py (looks in current dir first,
64 config file is ipython_config-<name>.py (looks in current dir first,
65 then in IPYTHON_DIR). This is a quick way to keep and load multiple
65 then in IPYTHON_DIR). This is a quick way to keep and load multiple
66 config files for different tasks, especially if include your basic one
66 config files for different tasks, especially if include your basic one
67 in your more specialized ones. You can keep a basic
67 in your more specialized ones. You can keep a basic
68 IPYTHON_DIR/ipython_config.py file and then have other 'profiles' which
68 IPYTHON_DIR/ipython_config.py file and then have other 'profiles' which
69 include this one and load extra things for particular tasks.""",
69 include this one and load extra things for particular tasks.""",
70 metavar='Global.profile') ),
70 metavar='Global.profile') ),
71 (('--log-level',), dict(
71 (('--log-level',), dict(
72 dest="Global.log_level",type=int,
72 dest="Global.log_level",type=int,
73 help='Set the log level (0,10,20,30,40,50). Default is 30.',
73 help='Set the log level (0,10,20,30,40,50). Default is 30.',
74 metavar='Global.log_level')),
74 metavar='Global.log_level')),
75 (('--config-file',), dict(
75 (('--config-file',), dict(
76 dest='Global.config_file',type=unicode,
76 dest='Global.config_file',type=unicode,
77 help=
77 help=
78 """Set the config file name to override default. Normally IPython
78 """Set the config file name to override default. Normally IPython
79 loads ipython_config.py (from current directory) or
79 loads ipython_config.py (from current directory) or
80 IPYTHON_DIR/ipython_config.py. If the loading of your config file
80 IPYTHON_DIR/ipython_config.py. If the loading of your config file
81 fails, IPython starts with a bare bones configuration (no modules
81 fails, IPython starts with a bare bones configuration (no modules
82 loaded at all).""",
82 loaded at all).""",
83 metavar='Global.config_file')),
83 metavar='Global.config_file')),
84 )
84 )
85
85
86 class Application(object):
86 class Application(object):
87 """Load a config, construct components and set them running."""
87 """Load a config, construct components and set them running.
88
89 The configuration of an application can be done via four different Config
90 objects, which are loaded and ultimately merged into a single one used from
91 that point on by the app. These are:
92
93 1. default_config: internal defaults, implemented in code.
94 2. file_config: read from the filesystem.
95 3. command_line_config: read from the system's command line flags.
96 4. constructor_config: passed parametrically to the constructor.
97
98 During initialization, 3 is actually read before 2, since at the
99 command-line one may override the location of the file to be read. But the
100 above is the order in which the merge is made.
101
102 There is a final config object can be created and passed to the
103 constructor: override_config. If it exists, this completely overrides the
104 configs 2-4 above (the default is still used to ensure that all needed
105 fields at least are created). This makes it easier to create
106 parametrically (e.g. in testing or sphinx plugins) objects with a known
107 configuration, that are unaffected by whatever arguments may be present in
108 sys.argv or files in the user's various directories.
109 """
88
110
89 name = u'ipython'
111 name = u'ipython'
90 description = 'IPython: an enhanced interactive Python shell.'
112 description = 'IPython: an enhanced interactive Python shell.'
91 #: usage message printed by argparse. If None, auto-generate
113 #: usage message printed by argparse. If None, auto-generate
92 usage = None
114 usage = None
93 config_file_name = u'ipython_config.py'
115 config_file_name = u'ipython_config.py'
94 # Track the default and actual separately because some messages are
116 #: Track the default and actual separately because some messages are
95 # only printed if we aren't using the default.
117 #: only printed if we aren't using the default.
96 default_config_file_name = config_file_name
118 default_config_file_name = config_file_name
97 default_log_level = logging.WARN
119 default_log_level = logging.WARN
98 # Set by --profile option
120 #: Set by --profile option
99 profile_name = None
121 profile_name = None
100 #: User's ipython directory, typically ~/.ipython/
122 #: User's ipython directory, typically ~/.ipython/
101 ipython_dir = None
123 ipython_dir = None
124 #: internal defaults, implemented in code.
125 default_config = None
126 #: read from the filesystem
127 file_config = None
128 #: read from the system's command line flags
129 command_line_config = None
130 #: passed parametrically to the constructor.
131 constructor_config = None
132 #: final override, if given supercedes file/command/constructor configs
133 override_config = None
102 #: A reference to the argv to be used (typically ends up being sys.argv[1:])
134 #: A reference to the argv to be used (typically ends up being sys.argv[1:])
103 argv = None
135 argv = None
104 #: Default command line arguments. Subclasses should create a new tuple
136 #: Default command line arguments. Subclasses should create a new tuple
105 #: that *includes* these.
137 #: that *includes* these.
106 cl_arguments = app_cl_args
138 cl_arguments = app_cl_args
107
139
140 #: extra arguments computed by the command-line loader
141 extra_args = None
142
108 # Private attributes
143 # Private attributes
109 _exiting = False
144 _exiting = False
110 _initialized = False
145 _initialized = False
111
146
112 # Class choices for things that will be instantiated at runtime.
147 # Class choices for things that will be instantiated at runtime.
113 _CrashHandler = crashhandler.CrashHandler
148 _CrashHandler = crashhandler.CrashHandler
114
149
115 def __init__(self, argv=None):
150 def __init__(self, argv=None, constructor_config=None, override_config=None):
116 self.argv = sys.argv[1:] if argv is None else argv
151 self.argv = sys.argv[1:] if argv is None else argv
152 self.constructor_config = constructor_config
153 self.override_config = override_config
117 self.init_logger()
154 self.init_logger()
118
155
119 def init_logger(self):
156 def init_logger(self):
120 self.log = logging.getLogger(self.__class__.__name__)
157 self.log = logging.getLogger(self.__class__.__name__)
121 # This is used as the default until the command line arguments are read.
158 # This is used as the default until the command line arguments are read.
122 self.log.setLevel(self.default_log_level)
159 self.log.setLevel(self.default_log_level)
123 self._log_handler = logging.StreamHandler()
160 self._log_handler = logging.StreamHandler()
124 self._log_formatter = logging.Formatter("[%(name)s] %(message)s")
161 self._log_formatter = logging.Formatter("[%(name)s] %(message)s")
125 self._log_handler.setFormatter(self._log_formatter)
162 self._log_handler.setFormatter(self._log_formatter)
126 self.log.addHandler(self._log_handler)
163 self.log.addHandler(self._log_handler)
127
164
128 def _set_log_level(self, level):
165 def _set_log_level(self, level):
129 self.log.setLevel(level)
166 self.log.setLevel(level)
130
167
131 def _get_log_level(self):
168 def _get_log_level(self):
132 return self.log.level
169 return self.log.level
133
170
134 log_level = property(_get_log_level, _set_log_level)
171 log_level = property(_get_log_level, _set_log_level)
135
172
136 def initialize(self):
173 def initialize(self):
137 """Start the application."""
174 """Initialize the application.
175
176 Loads all configuration information and sets all application state, but
177 does not start any relevant processing (typically some kind of event
178 loop).
179
180 Once this method has been called, the application is flagged as
181 initialized and the method becomes a no-op."""
138
182
139 if self._initialized:
183 if self._initialized:
140 return
184 return
141
185
142 # The first part is protected with an 'attempt' wrapper, that will log
186 # The first part is protected with an 'attempt' wrapper, that will log
143 # failures with the basic system traceback machinery. Once our crash
187 # failures with the basic system traceback machinery. Once our crash
144 # handler is in place, we can let any subsequent exception propagate,
188 # handler is in place, we can let any subsequent exception propagate,
145 # as our handler will log it with much better detail than the default.
189 # as our handler will log it with much better detail than the default.
146 self.attempt(self.create_crash_handler)
190 self.attempt(self.create_crash_handler)
191
192 # Configuration phase
193 # Default config (internally hardwired in application code)
147 self.create_default_config()
194 self.create_default_config()
148 self.log_default_config()
195 self.log_default_config()
149 self.set_default_config_log_level()
196 self.set_default_config_log_level()
197
198 if self.override_config is None:
199 # Command-line config
150 self.pre_load_command_line_config()
200 self.pre_load_command_line_config()
151 self.load_command_line_config()
201 self.load_command_line_config()
152 self.set_command_line_config_log_level()
202 self.set_command_line_config_log_level()
153 self.post_load_command_line_config()
203 self.post_load_command_line_config()
154 self.log_command_line_config()
204 self.log_command_line_config()
205
206 # Find resources needed for filesystem access, using information from
207 # the above two
155 self.find_ipython_dir()
208 self.find_ipython_dir()
156 self.find_resources()
209 self.find_resources()
157 self.find_config_file_name()
210 self.find_config_file_name()
158 self.find_config_file_paths()
211 self.find_config_file_paths()
212
213 if self.override_config is None:
214 # File-based config
159 self.pre_load_file_config()
215 self.pre_load_file_config()
160 self.load_file_config()
216 self.load_file_config()
161 self.set_file_config_log_level()
217 self.set_file_config_log_level()
162 self.post_load_file_config()
218 self.post_load_file_config()
163 self.log_file_config()
219 self.log_file_config()
220
221 # Merge all config objects into a single one the app can then use
164 self.merge_configs()
222 self.merge_configs()
165 self.log_master_config()
223 self.log_master_config()
224
225 # Construction phase
166 self.pre_construct()
226 self.pre_construct()
167 self.construct()
227 self.construct()
168 self.post_construct()
228 self.post_construct()
229
230 # Done, flag as such and
169 self._initialized = True
231 self._initialized = True
170
232
171 def start(self):
233 def start(self):
234 """Start the application."""
172 self.initialize()
235 self.initialize()
173 self.start_app()
236 self.start_app()
174
237
175 #-------------------------------------------------------------------------
238 #-------------------------------------------------------------------------
176 # Various stages of Application creation
239 # Various stages of Application creation
177 #-------------------------------------------------------------------------
240 #-------------------------------------------------------------------------
178
241
179 def create_crash_handler(self):
242 def create_crash_handler(self):
180 """Create a crash handler, typically setting sys.excepthook to it."""
243 """Create a crash handler, typically setting sys.excepthook to it."""
181 self.crash_handler = self._CrashHandler(self, self.name)
244 self.crash_handler = self._CrashHandler(self, self.name)
182 sys.excepthook = self.crash_handler
245 sys.excepthook = self.crash_handler
183
246
184 def create_default_config(self):
247 def create_default_config(self):
185 """Create defaults that can't be set elsewhere.
248 """Create defaults that can't be set elsewhere.
186
249
187 For the most part, we try to set default in the class attributes
250 For the most part, we try to set default in the class attributes
188 of Components. But, defaults the top-level Application (which is
251 of Components. But, defaults the top-level Application (which is
189 not a HasTraitlets or Component) are not set in this way. Instead
252 not a HasTraitlets or Component) are not set in this way. Instead
190 we set them here. The Global section is for variables like this that
253 we set them here. The Global section is for variables like this that
191 don't belong to a particular component.
254 don't belong to a particular component.
192 """
255 """
193 c = Config()
256 c = Config()
194 c.Global.ipython_dir = get_ipython_dir()
257 c.Global.ipython_dir = get_ipython_dir()
195 c.Global.log_level = self.log_level
258 c.Global.log_level = self.log_level
196 self.default_config = c
259 self.default_config = c
197
260
198 def log_default_config(self):
261 def log_default_config(self):
199 self.log.debug('Default config loaded:')
262 self.log.debug('Default config loaded:')
200 self.log.debug(repr(self.default_config))
263 self.log.debug(repr(self.default_config))
201
264
202 def set_default_config_log_level(self):
265 def set_default_config_log_level(self):
203 try:
266 try:
204 self.log_level = self.default_config.Global.log_level
267 self.log_level = self.default_config.Global.log_level
205 except AttributeError:
268 except AttributeError:
206 # Fallback to the default_log_level class attribute
269 # Fallback to the default_log_level class attribute
207 pass
270 pass
208
271
209 def create_command_line_config(self):
272 def create_command_line_config(self):
210 """Create and return a command line config loader."""
273 """Create and return a command line config loader."""
211 return ArgParseConfigLoader(self.argv, self.cl_arguments,
274 return ArgParseConfigLoader(self.argv, self.cl_arguments,
212 description=self.description,
275 description=self.description,
213 version=release.version,
276 version=release.version,
214 usage=self.usage,
277 usage=self.usage,
215 )
278 )
216
279
217 def pre_load_command_line_config(self):
280 def pre_load_command_line_config(self):
218 """Do actions just before loading the command line config."""
281 """Do actions just before loading the command line config."""
219 pass
282 pass
220
283
221 def load_command_line_config(self):
284 def load_command_line_config(self):
222 """Load the command line config."""
285 """Load the command line config."""
223 loader = self.create_command_line_config()
286 loader = self.create_command_line_config()
224 self.command_line_config = loader.load_config()
287 self.command_line_config = loader.load_config()
225 self.extra_args = loader.get_extra_args()
288 self.extra_args = loader.get_extra_args()
226
289
227 def set_command_line_config_log_level(self):
290 def set_command_line_config_log_level(self):
228 try:
291 try:
229 self.log_level = self.command_line_config.Global.log_level
292 self.log_level = self.command_line_config.Global.log_level
230 except AttributeError:
293 except AttributeError:
231 pass
294 pass
232
295
233 def post_load_command_line_config(self):
296 def post_load_command_line_config(self):
234 """Do actions just after loading the command line config."""
297 """Do actions just after loading the command line config."""
235 pass
298 pass
236
299
237 def log_command_line_config(self):
300 def log_command_line_config(self):
238 self.log.debug("Command line config loaded:")
301 self.log.debug("Command line config loaded:")
239 self.log.debug(repr(self.command_line_config))
302 self.log.debug(repr(self.command_line_config))
240
303
241 def find_ipython_dir(self):
304 def find_ipython_dir(self):
242 """Set the IPython directory.
305 """Set the IPython directory.
243
306
244 This sets ``self.ipython_dir``, but the actual value that is passed to
307 This sets ``self.ipython_dir``, but the actual value that is passed to
245 the application is kept in either ``self.default_config`` or
308 the application is kept in either ``self.default_config`` or
246 ``self.command_line_config``. This also adds ``self.ipython_dir`` to
309 ``self.command_line_config``. This also adds ``self.ipython_dir`` to
247 ``sys.path`` so config files there can be referenced by other config
310 ``sys.path`` so config files there can be referenced by other config
248 files.
311 files.
249 """
312 """
250
313
251 try:
314 try:
252 self.ipython_dir = self.command_line_config.Global.ipython_dir
315 self.ipython_dir = self.command_line_config.Global.ipython_dir
253 except AttributeError:
316 except AttributeError:
254 self.ipython_dir = self.default_config.Global.ipython_dir
317 self.ipython_dir = self.default_config.Global.ipython_dir
255 sys.path.append(os.path.abspath(self.ipython_dir))
318 sys.path.append(os.path.abspath(self.ipython_dir))
256 if not os.path.isdir(self.ipython_dir):
319 if not os.path.isdir(self.ipython_dir):
257 os.makedirs(self.ipython_dir, mode=0777)
320 os.makedirs(self.ipython_dir, mode=0777)
258 self.log.debug("IPYTHON_DIR set to: %s" % self.ipython_dir)
321 self.log.debug("IPYTHON_DIR set to: %s" % self.ipython_dir)
259
322
260 def find_resources(self):
323 def find_resources(self):
261 """Find other resources that need to be in place.
324 """Find other resources that need to be in place.
262
325
263 Things like cluster directories need to be in place to find the
326 Things like cluster directories need to be in place to find the
264 config file. These happen right after the IPython directory has
327 config file. These happen right after the IPython directory has
265 been set.
328 been set.
266 """
329 """
267 pass
330 pass
268
331
269 def find_config_file_name(self):
332 def find_config_file_name(self):
270 """Find the config file name for this application.
333 """Find the config file name for this application.
271
334
272 This must set ``self.config_file_name`` to the filename of the
335 This must set ``self.config_file_name`` to the filename of the
273 config file to use (just the filename). The search paths for the
336 config file to use (just the filename). The search paths for the
274 config file are set in :meth:`find_config_file_paths` and then passed
337 config file are set in :meth:`find_config_file_paths` and then passed
275 to the config file loader where they are resolved to an absolute path.
338 to the config file loader where they are resolved to an absolute path.
276
339
277 If a profile has been set at the command line, this will resolve it.
340 If a profile has been set at the command line, this will resolve it.
278 """
341 """
279
342
280 try:
343 try:
281 self.config_file_name = self.command_line_config.Global.config_file
344 self.config_file_name = self.command_line_config.Global.config_file
282 except AttributeError:
345 except AttributeError:
283 pass
346 pass
284
347
285 try:
348 try:
286 self.profile_name = self.command_line_config.Global.profile
349 self.profile_name = self.command_line_config.Global.profile
287 except AttributeError:
350 except AttributeError:
288 pass
351 pass
289 else:
352 else:
290 name_parts = self.config_file_name.split('.')
353 name_parts = self.config_file_name.split('.')
291 name_parts.insert(1, u'_' + self.profile_name + u'.')
354 name_parts.insert(1, u'_' + self.profile_name + u'.')
292 self.config_file_name = ''.join(name_parts)
355 self.config_file_name = ''.join(name_parts)
293
356
294 def find_config_file_paths(self):
357 def find_config_file_paths(self):
295 """Set the search paths for resolving the config file.
358 """Set the search paths for resolving the config file.
296
359
297 This must set ``self.config_file_paths`` to a sequence of search
360 This must set ``self.config_file_paths`` to a sequence of search
298 paths to pass to the config file loader.
361 paths to pass to the config file loader.
299 """
362 """
300 # Include our own profiles directory last, so that users can still find
363 # Include our own profiles directory last, so that users can still find
301 # our shipped copies of builtin profiles even if they don't have them
364 # our shipped copies of builtin profiles even if they don't have them
302 # in their local ipython directory.
365 # in their local ipython directory.
303 prof_dir = os.path.join(get_ipython_package_dir(), 'config', 'profile')
366 prof_dir = os.path.join(get_ipython_package_dir(), 'config', 'profile')
304 self.config_file_paths = (os.getcwd(), self.ipython_dir, prof_dir)
367 self.config_file_paths = (os.getcwd(), self.ipython_dir, prof_dir)
305
368
306 def pre_load_file_config(self):
369 def pre_load_file_config(self):
307 """Do actions before the config file is loaded."""
370 """Do actions before the config file is loaded."""
308 pass
371 pass
309
372
310 def load_file_config(self):
373 def load_file_config(self):
311 """Load the config file.
374 """Load the config file.
312
375
313 This tries to load the config file from disk. If successful, the
376 This tries to load the config file from disk. If successful, the
314 ``CONFIG_FILE`` config variable is set to the resolved config file
377 ``CONFIG_FILE`` config variable is set to the resolved config file
315 location. If not successful, an empty config is used.
378 location. If not successful, an empty config is used.
316 """
379 """
317 self.log.debug("Attempting to load config file: %s" %
380 self.log.debug("Attempting to load config file: %s" %
318 self.config_file_name)
381 self.config_file_name)
319 loader = PyFileConfigLoader(self.config_file_name,
382 loader = PyFileConfigLoader(self.config_file_name,
320 path=self.config_file_paths)
383 path=self.config_file_paths)
321 try:
384 try:
322 self.file_config = loader.load_config()
385 self.file_config = loader.load_config()
323 self.file_config.Global.config_file = loader.full_filename
386 self.file_config.Global.config_file = loader.full_filename
324 except IOError:
387 except IOError:
325 # Only warn if the default config file was NOT being used.
388 # Only warn if the default config file was NOT being used.
326 if not self.config_file_name==self.default_config_file_name:
389 if not self.config_file_name==self.default_config_file_name:
327 self.log.warn("Config file not found, skipping: %s" %
390 self.log.warn("Config file not found, skipping: %s" %
328 self.config_file_name, exc_info=True)
391 self.config_file_name, exc_info=True)
329 self.file_config = Config()
392 self.file_config = Config()
330 except:
393 except:
331 self.log.warn("Error loading config file: %s" %
394 self.log.warn("Error loading config file: %s" %
332 self.config_file_name, exc_info=True)
395 self.config_file_name, exc_info=True)
333 self.file_config = Config()
396 self.file_config = Config()
334
397
335 def set_file_config_log_level(self):
398 def set_file_config_log_level(self):
336 # We need to keeep self.log_level updated. But we only use the value
399 # We need to keeep self.log_level updated. But we only use the value
337 # of the file_config if a value was not specified at the command
400 # of the file_config if a value was not specified at the command
338 # line, because the command line overrides everything.
401 # line, because the command line overrides everything.
339 if not hasattr(self.command_line_config.Global, 'log_level'):
402 if not hasattr(self.command_line_config.Global, 'log_level'):
340 try:
403 try:
341 self.log_level = self.file_config.Global.log_level
404 self.log_level = self.file_config.Global.log_level
342 except AttributeError:
405 except AttributeError:
343 pass # Use existing value
406 pass # Use existing value
344
407
345 def post_load_file_config(self):
408 def post_load_file_config(self):
346 """Do actions after the config file is loaded."""
409 """Do actions after the config file is loaded."""
347 pass
410 pass
348
411
349 def log_file_config(self):
412 def log_file_config(self):
350 if hasattr(self.file_config.Global, 'config_file'):
413 if hasattr(self.file_config.Global, 'config_file'):
351 self.log.debug("Config file loaded: %s" %
414 self.log.debug("Config file loaded: %s" %
352 self.file_config.Global.config_file)
415 self.file_config.Global.config_file)
353 self.log.debug(repr(self.file_config))
416 self.log.debug(repr(self.file_config))
354
417
355 def merge_configs(self):
418 def merge_configs(self):
356 """Merge the default, command line and file config objects."""
419 """Merge the default, command line and file config objects."""
357 config = Config()
420 config = Config()
358 config._merge(self.default_config)
421 config._merge(self.default_config)
422 if self.override_config is None:
359 config._merge(self.file_config)
423 config._merge(self.file_config)
360 config._merge(self.command_line_config)
424 config._merge(self.command_line_config)
425 if self.constructor_config is not None:
426 config._merge(self.constructor_config)
427 else:
428 config._merge(self.override_config)
429 # XXX fperez - propose to Brian we rename master_config to simply
430 # config, I think this is going to be heavily used in examples and
431 # application code and the name is shorter/easier to find/remember.
432 # For now, just alias it...
361 self.master_config = config
433 self.master_config = config
434 self.config = config
362
435
363 def log_master_config(self):
436 def log_master_config(self):
364 self.log.debug("Master config created:")
437 self.log.debug("Master config created:")
365 self.log.debug(repr(self.master_config))
438 self.log.debug(repr(self.master_config))
366
439
367 def pre_construct(self):
440 def pre_construct(self):
368 """Do actions after the config has been built, but before construct."""
441 """Do actions after the config has been built, but before construct."""
369 pass
442 pass
370
443
371 def construct(self):
444 def construct(self):
372 """Construct the main components that make up this app."""
445 """Construct the main components that make up this app."""
373 self.log.debug("Constructing components for application")
446 self.log.debug("Constructing components for application")
374
447
375 def post_construct(self):
448 def post_construct(self):
376 """Do actions after construct, but before starting the app."""
449 """Do actions after construct, but before starting the app."""
377 pass
450 pass
378
451
379 def start_app(self):
452 def start_app(self):
380 """Actually start the app."""
453 """Actually start the app."""
381 self.log.debug("Starting application")
454 self.log.debug("Starting application")
382
455
383 #-------------------------------------------------------------------------
456 #-------------------------------------------------------------------------
384 # Utility methods
457 # Utility methods
385 #-------------------------------------------------------------------------
458 #-------------------------------------------------------------------------
386
459
387 def abort(self):
460 def abort(self):
388 """Abort the starting of the application."""
461 """Abort the starting of the application."""
389 if self._exiting:
462 if self._exiting:
390 pass
463 pass
391 else:
464 else:
392 self.log.critical("Aborting application: %s" % self.name, exc_info=True)
465 self.log.critical("Aborting application: %s" % self.name, exc_info=True)
393 self._exiting = True
466 self._exiting = True
394 sys.exit(1)
467 sys.exit(1)
395
468
396 def exit(self, exit_status=0):
469 def exit(self, exit_status=0):
397 if self._exiting:
470 if self._exiting:
398 pass
471 pass
399 else:
472 else:
400 self.log.debug("Exiting application: %s" % self.name)
473 self.log.debug("Exiting application: %s" % self.name)
401 self._exiting = True
474 self._exiting = True
402 sys.exit(exit_status)
475 sys.exit(exit_status)
403
476
404 def attempt(self, func, action='abort'):
477 def attempt(self, func, action='abort'):
405 try:
478 try:
406 func()
479 func()
407 except SystemExit:
480 except SystemExit:
408 raise
481 raise
409 except:
482 except:
410 if action == 'abort':
483 if action == 'abort':
411 self.log.critical("Aborting application: %s" % self.name,
484 self.log.critical("Aborting application: %s" % self.name,
412 exc_info=True)
485 exc_info=True)
413 self.abort()
486 self.abort()
414 raise
487 raise
415 elif action == 'exit':
488 elif action == 'exit':
416 self.exit(0)
489 self.exit(0)
417
490
@@ -1,643 +1,655 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 """
12 """
13
13
14 #-----------------------------------------------------------------------------
14 #-----------------------------------------------------------------------------
15 # Copyright (C) 2008-2010 The IPython Development Team
15 # Copyright (C) 2008-2010 The IPython Development Team
16 #
16 #
17 # Distributed under the terms of the BSD License. The full license is in
17 # Distributed under the terms of the BSD License. The full license is in
18 # the file COPYING, distributed as part of this software.
18 # the file COPYING, distributed as part of this software.
19 #-----------------------------------------------------------------------------
19 #-----------------------------------------------------------------------------
20
20
21 #-----------------------------------------------------------------------------
21 #-----------------------------------------------------------------------------
22 # Imports
22 # Imports
23 #-----------------------------------------------------------------------------
23 #-----------------------------------------------------------------------------
24 from __future__ import absolute_import
24 from __future__ import absolute_import
25
25
26 import logging
26 import logging
27 import os
27 import os
28 import sys
28 import sys
29
29
30 from IPython.core import crashhandler
30 from IPython.core import crashhandler
31 from IPython.core.application import Application
31 from IPython.core.application import Application
32 from IPython.core.iplib import InteractiveShell
32 from IPython.core.iplib import InteractiveShell
33 from IPython.config.loader import (
33 from IPython.config.loader import (
34 Config,
34 Config,
35 PyFileConfigLoader,
35 PyFileConfigLoader,
36 # NoConfigDefault,
36 # NoConfigDefault,
37 )
37 )
38 from IPython.lib import inputhook
38 from IPython.lib import inputhook
39 from IPython.utils.genutils import filefind, get_ipython_dir
39 from IPython.utils.genutils import filefind, get_ipython_dir
40 from . import usage
40 from . import usage
41
41
42 #-----------------------------------------------------------------------------
42 #-----------------------------------------------------------------------------
43 # Globals, utilities and helpers
43 # Globals, utilities and helpers
44 #-----------------------------------------------------------------------------
44 #-----------------------------------------------------------------------------
45
45
46 default_config_file_name = u'ipython_config.py'
46 default_config_file_name = u'ipython_config.py'
47
47
48 cl_args = (
48 cl_args = (
49 (('--autocall',), dict(
49 (('--autocall',), dict(
50 type=int, dest='InteractiveShell.autocall',
50 type=int, dest='InteractiveShell.autocall',
51 help=
51 help=
52 """Make IPython automatically call any callable object even if you
52 """Make IPython automatically call any callable object even if you
53 didn't type explicit parentheses. For example, 'str 43' becomes
53 didn't type explicit parentheses. For example, 'str 43' becomes
54 'str(43)' automatically. The value can be '0' to disable the feature,
54 'str(43)' automatically. The value can be '0' to disable the feature,
55 '1' for 'smart' autocall, where it is not applied if there are no more
55 '1' for 'smart' autocall, where it is not applied if there are no more
56 arguments on the line, and '2' for 'full' autocall, where all callable
56 arguments on the line, and '2' for 'full' autocall, where all callable
57 objects are automatically called (even if no arguments are present).
57 objects are automatically called (even if no arguments are present).
58 The default is '1'.""",
58 The default is '1'.""",
59 metavar='InteractiveShell.autocall')
59 metavar='InteractiveShell.autocall')
60 ),
60 ),
61 (('--autoindent',), dict(
61 (('--autoindent',), dict(
62 action='store_true', dest='InteractiveShell.autoindent',
62 action='store_true', dest='InteractiveShell.autoindent',
63 help='Turn on autoindenting.')
63 help='Turn on autoindenting.')
64 ),
64 ),
65 (('--no-autoindent',), dict(
65 (('--no-autoindent',), dict(
66 action='store_false', dest='InteractiveShell.autoindent',
66 action='store_false', dest='InteractiveShell.autoindent',
67 help='Turn off autoindenting.')
67 help='Turn off autoindenting.')
68 ),
68 ),
69 (('--automagic',), dict(
69 (('--automagic',), dict(
70 action='store_true', dest='InteractiveShell.automagic',
70 action='store_true', dest='InteractiveShell.automagic',
71 help='Turn on the auto calling of magic commands.'
71 help='Turn on the auto calling of magic commands.'
72 'Type %%magic at the IPython prompt for more information.')
72 'Type %%magic at the IPython prompt for more information.')
73 ),
73 ),
74 (('--no-automagic',), dict(
74 (('--no-automagic',), dict(
75 action='store_false', dest='InteractiveShell.automagic',
75 action='store_false', dest='InteractiveShell.automagic',
76 help='Turn off the auto calling of magic commands.')
76 help='Turn off the auto calling of magic commands.')
77 ),
77 ),
78 (('--autoedit-syntax',), dict(
78 (('--autoedit-syntax',), dict(
79 action='store_true', dest='InteractiveShell.autoedit_syntax',
79 action='store_true', dest='InteractiveShell.autoedit_syntax',
80 help='Turn on auto editing of files with syntax errors.')
80 help='Turn on auto editing of files with syntax errors.')
81 ),
81 ),
82 (('--no-autoedit-syntax',), dict(
82 (('--no-autoedit-syntax',), dict(
83 action='store_false', dest='InteractiveShell.autoedit_syntax',
83 action='store_false', dest='InteractiveShell.autoedit_syntax',
84 help='Turn off auto editing of files with syntax errors.')
84 help='Turn off auto editing of files with syntax errors.')
85 ),
85 ),
86 (('--banner',), dict(
86 (('--banner',), dict(
87 action='store_true', dest='Global.display_banner',
87 action='store_true', dest='Global.display_banner',
88 help='Display a banner upon starting IPython.')
88 help='Display a banner upon starting IPython.')
89 ),
89 ),
90 (('--no-banner',), dict(
90 (('--no-banner',), dict(
91 action='store_false', dest='Global.display_banner',
91 action='store_false', dest='Global.display_banner',
92 help="Don't display a banner upon starting IPython.")
92 help="Don't display a banner upon starting IPython.")
93 ),
93 ),
94 (('--cache-size',), dict(
94 (('--cache-size',), dict(
95 type=int, dest='InteractiveShell.cache_size',
95 type=int, dest='InteractiveShell.cache_size',
96 help=
96 help=
97 """Set the size of the output cache. The default is 1000, you can
97 """Set the size of the output cache. The default is 1000, you can
98 change it permanently in your config file. Setting it to 0 completely
98 change it permanently in your config file. Setting it to 0 completely
99 disables the caching system, and the minimum value accepted is 20 (if
99 disables the caching system, and the minimum value accepted is 20 (if
100 you provide a value less than 20, it is reset to 0 and a warning is
100 you provide a value less than 20, it is reset to 0 and a warning is
101 issued). This limit is defined because otherwise you'll spend more
101 issued). This limit is defined because otherwise you'll spend more
102 time re-flushing a too small cache than working.
102 time re-flushing a too small cache than working.
103 """,
103 """,
104 metavar='InteractiveShell.cache_size')
104 metavar='InteractiveShell.cache_size')
105 ),
105 ),
106 (('--classic',), dict(
106 (('--classic',), dict(
107 action='store_true', dest='Global.classic',
107 action='store_true', dest='Global.classic',
108 help="Gives IPython a similar feel to the classic Python prompt.")
108 help="Gives IPython a similar feel to the classic Python prompt.")
109 ),
109 ),
110 (('--colors',), dict(
110 (('--colors',), dict(
111 type=str, dest='InteractiveShell.colors',
111 type=str, dest='InteractiveShell.colors',
112 help="Set the color scheme (NoColor, Linux, and LightBG).",
112 help="Set the color scheme (NoColor, Linux, and LightBG).",
113 metavar='InteractiveShell.colors')
113 metavar='InteractiveShell.colors')
114 ),
114 ),
115 (('--color-info',), dict(
115 (('--color-info',), dict(
116 action='store_true', dest='InteractiveShell.color_info',
116 action='store_true', dest='InteractiveShell.color_info',
117 help=
117 help=
118 """IPython can display information about objects via a set of func-
118 """IPython can display information about objects via a set of func-
119 tions, and optionally can use colors for this, syntax highlighting
119 tions, and optionally can use colors for this, syntax highlighting
120 source code and various other elements. However, because this
120 source code and various other elements. However, because this
121 information is passed through a pager (like 'less') and many pagers get
121 information is passed through a pager (like 'less') and many pagers get
122 confused with color codes, this option is off by default. You can test
122 confused with color codes, this option is off by default. You can test
123 it and turn it on permanently in your ipython_config.py file if it
123 it and turn it on permanently in your ipython_config.py file if it
124 works for you. Test it and turn it on permanently if it works with
124 works for you. Test it and turn it on permanently if it works with
125 your system. The magic function %%color_info allows you to toggle this
125 your system. The magic function %%color_info allows you to toggle this
126 inter- actively for testing."""
126 inter- actively for testing."""
127 )
127 )
128 ),
128 ),
129 (('--no-color-info',), dict(
129 (('--no-color-info',), dict(
130 action='store_false', dest='InteractiveShell.color_info',
130 action='store_false', dest='InteractiveShell.color_info',
131 help="Disable using colors for info related things.")
131 help="Disable using colors for info related things.")
132 ),
132 ),
133 (('--confirm-exit',), dict(
133 (('--confirm-exit',), dict(
134 action='store_true', dest='InteractiveShell.confirm_exit',
134 action='store_true', dest='InteractiveShell.confirm_exit',
135 help=
135 help=
136 """Set to confirm when you try to exit IPython with an EOF (Control-D
136 """Set to confirm when you try to exit IPython with an EOF (Control-D
137 in Unix, Control-Z/Enter in Windows). By typing 'exit', 'quit' or
137 in Unix, Control-Z/Enter in Windows). By typing 'exit', 'quit' or
138 '%%Exit', you can force a direct exit without any confirmation.
138 '%%Exit', you can force a direct exit without any confirmation.
139 """
139 """
140 )
140 )
141 ),
141 ),
142 (('--no-confirm-exit',), dict(
142 (('--no-confirm-exit',), dict(
143 action='store_false', dest='InteractiveShell.confirm_exit',
143 action='store_false', dest='InteractiveShell.confirm_exit',
144 help="Don't prompt the user when exiting.")
144 help="Don't prompt the user when exiting.")
145 ),
145 ),
146 (('--deep-reload',), dict(
146 (('--deep-reload',), dict(
147 action='store_true', dest='InteractiveShell.deep_reload',
147 action='store_true', dest='InteractiveShell.deep_reload',
148 help=
148 help=
149 """Enable deep (recursive) reloading by default. IPython can use the
149 """Enable deep (recursive) reloading by default. IPython can use the
150 deep_reload module which reloads changes in modules recursively (it
150 deep_reload module which reloads changes in modules recursively (it
151 replaces the reload() function, so you don't need to change anything to
151 replaces the reload() function, so you don't need to change anything to
152 use it). deep_reload() forces a full reload of modules whose code may
152 use it). deep_reload() forces a full reload of modules whose code may
153 have changed, which the default reload() function does not. When
153 have changed, which the default reload() function does not. When
154 deep_reload is off, IPython will use the normal reload(), but
154 deep_reload is off, IPython will use the normal reload(), but
155 deep_reload will still be available as dreload(). This fea- ture is off
155 deep_reload will still be available as dreload(). This fea- ture is off
156 by default [which means that you have both normal reload() and
156 by default [which means that you have both normal reload() and
157 dreload()].""")
157 dreload()].""")
158 ),
158 ),
159 (('--no-deep-reload',), dict(
159 (('--no-deep-reload',), dict(
160 action='store_false', dest='InteractiveShell.deep_reload',
160 action='store_false', dest='InteractiveShell.deep_reload',
161 help="Disable deep (recursive) reloading by default.")
161 help="Disable deep (recursive) reloading by default.")
162 ),
162 ),
163 (('--editor',), dict(
163 (('--editor',), dict(
164 type=str, dest='InteractiveShell.editor',
164 type=str, dest='InteractiveShell.editor',
165 help="Set the editor used by IPython (default to $EDITOR/vi/notepad).",
165 help="Set the editor used by IPython (default to $EDITOR/vi/notepad).",
166 metavar='InteractiveShell.editor')
166 metavar='InteractiveShell.editor')
167 ),
167 ),
168 (('--log','-l'), dict(
168 (('--log','-l'), dict(
169 action='store_true', dest='InteractiveShell.logstart',
169 action='store_true', dest='InteractiveShell.logstart',
170 help="Start logging to the default log file (./ipython_log.py).")
170 help="Start logging to the default log file (./ipython_log.py).")
171 ),
171 ),
172 (('--logfile','-lf'), dict(
172 (('--logfile','-lf'), dict(
173 type=unicode, dest='InteractiveShell.logfile',
173 type=unicode, dest='InteractiveShell.logfile',
174 help="Start logging to logfile with this name.",
174 help="Start logging to logfile with this name.",
175 metavar='InteractiveShell.logfile')
175 metavar='InteractiveShell.logfile')
176 ),
176 ),
177 (('--log-append','-la'), dict(
177 (('--log-append','-la'), dict(
178 type=unicode, dest='InteractiveShell.logappend',
178 type=unicode, dest='InteractiveShell.logappend',
179 help="Start logging to the given file in append mode.",
179 help="Start logging to the given file in append mode.",
180 metavar='InteractiveShell.logfile')
180 metavar='InteractiveShell.logfile')
181 ),
181 ),
182 (('--pdb',), dict(
182 (('--pdb',), dict(
183 action='store_true', dest='InteractiveShell.pdb',
183 action='store_true', dest='InteractiveShell.pdb',
184 help="Enable auto calling the pdb debugger after every exception.")
184 help="Enable auto calling the pdb debugger after every exception.")
185 ),
185 ),
186 (('--no-pdb',), dict(
186 (('--no-pdb',), dict(
187 action='store_false', dest='InteractiveShell.pdb',
187 action='store_false', dest='InteractiveShell.pdb',
188 help="Disable auto calling the pdb debugger after every exception.")
188 help="Disable auto calling the pdb debugger after every exception.")
189 ),
189 ),
190 (('--pprint',), dict(
190 (('--pprint',), dict(
191 action='store_true', dest='InteractiveShell.pprint',
191 action='store_true', dest='InteractiveShell.pprint',
192 help="Enable auto pretty printing of results.")
192 help="Enable auto pretty printing of results.")
193 ),
193 ),
194 (('--no-pprint',), dict(
194 (('--no-pprint',), dict(
195 action='store_false', dest='InteractiveShell.pprint',
195 action='store_false', dest='InteractiveShell.pprint',
196 help="Disable auto auto pretty printing of results.")
196 help="Disable auto auto pretty printing of results.")
197 ),
197 ),
198 (('--prompt-in1','-pi1'), dict(
198 (('--prompt-in1','-pi1'), dict(
199 type=str, dest='InteractiveShell.prompt_in1',
199 type=str, dest='InteractiveShell.prompt_in1',
200 help=
200 help=
201 """Set the main input prompt ('In [\#]: '). Note that if you are using
201 """Set the main input prompt ('In [\#]: '). Note that if you are using
202 numbered prompts, the number is represented with a '\#' in the string.
202 numbered prompts, the number is represented with a '\#' in the string.
203 Don't forget to quote strings with spaces embedded in them. Most
203 Don't forget to quote strings with spaces embedded in them. Most
204 bash-like escapes can be used to customize IPython's prompts, as well
204 bash-like escapes can be used to customize IPython's prompts, as well
205 as a few additional ones which are IPython-spe- cific. All valid
205 as a few additional ones which are IPython-spe- cific. All valid
206 prompt escapes are described in detail in the Customization section of
206 prompt escapes are described in detail in the Customization section of
207 the IPython manual.""",
207 the IPython manual.""",
208 metavar='InteractiveShell.prompt_in1')
208 metavar='InteractiveShell.prompt_in1')
209 ),
209 ),
210 (('--prompt-in2','-pi2'), dict(
210 (('--prompt-in2','-pi2'), dict(
211 type=str, dest='InteractiveShell.prompt_in2',
211 type=str, dest='InteractiveShell.prompt_in2',
212 help=
212 help=
213 """Set the secondary input prompt (' .\D.: '). Similar to the previous
213 """Set the secondary input prompt (' .\D.: '). Similar to the previous
214 option, but used for the continuation prompts. The special sequence
214 option, but used for the continuation prompts. The special sequence
215 '\D' is similar to '\#', but with all digits replaced by dots (so you
215 '\D' is similar to '\#', but with all digits replaced by dots (so you
216 can have your continuation prompt aligned with your input prompt).
216 can have your continuation prompt aligned with your input prompt).
217 Default: ' .\D.: ' (note three spaces at the start for alignment with
217 Default: ' .\D.: ' (note three spaces at the start for alignment with
218 'In [\#]')""",
218 'In [\#]')""",
219 metavar='InteractiveShell.prompt_in2')
219 metavar='InteractiveShell.prompt_in2')
220 ),
220 ),
221 (('--prompt-out','-po'), dict(
221 (('--prompt-out','-po'), dict(
222 type=str, dest='InteractiveShell.prompt_out',
222 type=str, dest='InteractiveShell.prompt_out',
223 help="Set the output prompt ('Out[\#]:')",
223 help="Set the output prompt ('Out[\#]:')",
224 metavar='InteractiveShell.prompt_out')
224 metavar='InteractiveShell.prompt_out')
225 ),
225 ),
226 (('--quick',), dict(
226 (('--quick',), dict(
227 action='store_true', dest='Global.quick',
227 action='store_true', dest='Global.quick',
228 help="Enable quick startup with no config files.")
228 help="Enable quick startup with no config files.")
229 ),
229 ),
230 (('--readline',), dict(
230 (('--readline',), dict(
231 action='store_true', dest='InteractiveShell.readline_use',
231 action='store_true', dest='InteractiveShell.readline_use',
232 help="Enable readline for command line usage.")
232 help="Enable readline for command line usage.")
233 ),
233 ),
234 (('--no-readline',), dict(
234 (('--no-readline',), dict(
235 action='store_false', dest='InteractiveShell.readline_use',
235 action='store_false', dest='InteractiveShell.readline_use',
236 help="Disable readline for command line usage.")
236 help="Disable readline for command line usage.")
237 ),
237 ),
238 (('--screen-length','-sl'), dict(
238 (('--screen-length','-sl'), dict(
239 type=int, dest='InteractiveShell.screen_length',
239 type=int, dest='InteractiveShell.screen_length',
240 help=
240 help=
241 """Number of lines of your screen, used to control printing of very
241 """Number of lines of your screen, used to control printing of very
242 long strings. Strings longer than this number of lines will be sent
242 long strings. Strings longer than this number of lines will be sent
243 through a pager instead of directly printed. The default value for
243 through a pager instead of directly printed. The default value for
244 this is 0, which means IPython will auto-detect your screen size every
244 this is 0, which means IPython will auto-detect your screen size every
245 time it needs to print certain potentially long strings (this doesn't
245 time it needs to print certain potentially long strings (this doesn't
246 change the behavior of the 'print' keyword, it's only triggered
246 change the behavior of the 'print' keyword, it's only triggered
247 internally). If for some reason this isn't working well (it needs
247 internally). If for some reason this isn't working well (it needs
248 curses support), specify it yourself. Otherwise don't change the
248 curses support), specify it yourself. Otherwise don't change the
249 default.""",
249 default.""",
250 metavar='InteractiveShell.screen_length')
250 metavar='InteractiveShell.screen_length')
251 ),
251 ),
252 (('--separate-in','-si'), dict(
252 (('--separate-in','-si'), dict(
253 type=str, dest='InteractiveShell.separate_in',
253 type=str, dest='InteractiveShell.separate_in',
254 help="Separator before input prompts. Default '\\n'.",
254 help="Separator before input prompts. Default '\\n'.",
255 metavar='InteractiveShell.separate_in')
255 metavar='InteractiveShell.separate_in')
256 ),
256 ),
257 (('--separate-out','-so'), dict(
257 (('--separate-out','-so'), dict(
258 type=str, dest='InteractiveShell.separate_out',
258 type=str, dest='InteractiveShell.separate_out',
259 help="Separator before output prompts. Default 0 (nothing).",
259 help="Separator before output prompts. Default 0 (nothing).",
260 metavar='InteractiveShell.separate_out')
260 metavar='InteractiveShell.separate_out')
261 ),
261 ),
262 (('--separate-out2','-so2'), dict(
262 (('--separate-out2','-so2'), dict(
263 type=str, dest='InteractiveShell.separate_out2',
263 type=str, dest='InteractiveShell.separate_out2',
264 help="Separator after output prompts. Default 0 (nonight).",
264 help="Separator after output prompts. Default 0 (nonight).",
265 metavar='InteractiveShell.separate_out2')
265 metavar='InteractiveShell.separate_out2')
266 ),
266 ),
267 (('-no-sep',), dict(
267 (('-no-sep',), dict(
268 action='store_true', dest='Global.nosep',
268 action='store_true', dest='Global.nosep',
269 help="Eliminate all spacing between prompts.")
269 help="Eliminate all spacing between prompts.")
270 ),
270 ),
271 (('--term-title',), dict(
271 (('--term-title',), dict(
272 action='store_true', dest='InteractiveShell.term_title',
272 action='store_true', dest='InteractiveShell.term_title',
273 help="Enable auto setting the terminal title.")
273 help="Enable auto setting the terminal title.")
274 ),
274 ),
275 (('--no-term-title',), dict(
275 (('--no-term-title',), dict(
276 action='store_false', dest='InteractiveShell.term_title',
276 action='store_false', dest='InteractiveShell.term_title',
277 help="Disable auto setting the terminal title.")
277 help="Disable auto setting the terminal title.")
278 ),
278 ),
279 (('--xmode',), dict(
279 (('--xmode',), dict(
280 type=str, dest='InteractiveShell.xmode',
280 type=str, dest='InteractiveShell.xmode',
281 help=
281 help=
282 """Exception reporting mode ('Plain','Context','Verbose'). Plain:
282 """Exception reporting mode ('Plain','Context','Verbose'). Plain:
283 similar to python's normal traceback printing. Context: prints 5 lines
283 similar to python's normal traceback printing. Context: prints 5 lines
284 of context source code around each line in the traceback. Verbose:
284 of context source code around each line in the traceback. Verbose:
285 similar to Context, but additionally prints the variables currently
285 similar to Context, but additionally prints the variables currently
286 visible where the exception happened (shortening their strings if too
286 visible where the exception happened (shortening their strings if too
287 long). This can potentially be very slow, if you happen to have a huge
287 long). This can potentially be very slow, if you happen to have a huge
288 data structure whose string representation is complex to compute.
288 data structure whose string representation is complex to compute.
289 Your computer may appear to freeze for a while with cpu usage at 100%%.
289 Your computer may appear to freeze for a while with cpu usage at 100%%.
290 If this occurs, you can cancel the traceback with Ctrl-C (maybe hitting
290 If this occurs, you can cancel the traceback with Ctrl-C (maybe hitting
291 it more than once).
291 it more than once).
292 """,
292 """,
293 metavar='InteractiveShell.xmode')
293 metavar='InteractiveShell.xmode')
294 ),
294 ),
295 (('--ext',), dict(
295 (('--ext',), dict(
296 type=str, dest='Global.extra_extension',
296 type=str, dest='Global.extra_extension',
297 help="The dotted module name of an IPython extension to load.",
297 help="The dotted module name of an IPython extension to load.",
298 metavar='Global.extra_extension')
298 metavar='Global.extra_extension')
299 ),
299 ),
300 (('-c',), dict(
300 (('-c',), dict(
301 type=str, dest='Global.code_to_run',
301 type=str, dest='Global.code_to_run',
302 help="Execute the given command string.",
302 help="Execute the given command string.",
303 metavar='Global.code_to_run')
303 metavar='Global.code_to_run')
304 ),
304 ),
305 (('-i',), dict(
305 (('-i',), dict(
306 action='store_true', dest='Global.force_interact',
306 action='store_true', dest='Global.force_interact',
307 help=
307 help=
308 "If running code from the command line, become interactive afterwards."
308 "If running code from the command line, become interactive afterwards."
309 )
309 )
310 ),
310 ),
311
311
312 # Options to start with GUI control enabled from the beginning
312 # Options to start with GUI control enabled from the beginning
313 (('--gui',), dict(
313 (('--gui',), dict(
314 type=str, dest='Global.gui',
314 type=str, dest='Global.gui',
315 help="Enable GUI event loop integration ('qt', 'wx', 'gtk').",
315 help="Enable GUI event loop integration ('qt', 'wx', 'gtk').",
316 metavar='gui-mode')
316 metavar='gui-mode')
317 ),
317 ),
318
318
319 (('--pylab','-pylab'), dict(
319 (('--pylab','-pylab'), dict(
320 type=str, dest='Global.pylab',
320 type=str, dest='Global.pylab',
321 nargs='?', const='auto', metavar='gui-mode',
321 nargs='?', const='auto', metavar='gui-mode',
322 help="Pre-load matplotlib and numpy for interactive use. "+
322 help="Pre-load matplotlib and numpy for interactive use. "+
323 "If no value is given, the gui backend is matplotlib's, else use "+
323 "If no value is given, the gui backend is matplotlib's, else use "+
324 "one of: ['tk', 'qt', 'wx', 'gtk'].")
324 "one of: ['tk', 'qt', 'wx', 'gtk'].")
325 ),
325 ),
326
326
327 # Legacy GUI options. Leave them in for backwards compatibility, but the
327 # Legacy GUI options. Leave them in for backwards compatibility, but the
328 # 'thread' names are really a misnomer now.
328 # 'thread' names are really a misnomer now.
329 (('--wthread','-wthread'), dict(
329 (('--wthread','-wthread'), dict(
330 action='store_true', dest='Global.wthread',
330 action='store_true', dest='Global.wthread',
331 help="Enable wxPython event loop integration "+
331 help="Enable wxPython event loop integration "+
332 "(DEPRECATED, use --gui wx)")
332 "(DEPRECATED, use --gui wx)")
333 ),
333 ),
334 (('--q4thread','--qthread','-q4thread','-qthread'), dict(
334 (('--q4thread','--qthread','-q4thread','-qthread'), dict(
335 action='store_true', dest='Global.q4thread',
335 action='store_true', dest='Global.q4thread',
336 help="Enable Qt4 event loop integration. Qt3 is no longer supported. "+
336 help="Enable Qt4 event loop integration. Qt3 is no longer supported. "+
337 "(DEPRECATED, use --gui qt)")
337 "(DEPRECATED, use --gui qt)")
338 ),
338 ),
339 (('--gthread','-gthread'), dict(
339 (('--gthread','-gthread'), dict(
340 action='store_true', dest='Global.gthread',
340 action='store_true', dest='Global.gthread',
341 help="Enable GTK event loop integration. "+
341 help="Enable GTK event loop integration. "+
342 "(DEPRECATED, use --gui gtk)")
342 "(DEPRECATED, use --gui gtk)")
343 ),
343 ),
344 )
344 )
345
345
346 #-----------------------------------------------------------------------------
346 #-----------------------------------------------------------------------------
347 # Main classes and functions
347 # Main classes and functions
348 #-----------------------------------------------------------------------------
348 #-----------------------------------------------------------------------------
349
349
350 class IPythonApp(Application):
350 class IPythonApp(Application):
351 name = u'ipython'
351 name = u'ipython'
352 #: argparse formats better the 'usage' than the 'description' field
352 #: argparse formats better the 'usage' than the 'description' field
353 description = None
353 description = None
354 #: usage message printed by argparse. If None, auto-generate
354 #: usage message printed by argparse. If None, auto-generate
355 usage = usage.cl_usage
355 usage = usage.cl_usage
356
356
357 config_file_name = default_config_file_name
357 config_file_name = default_config_file_name
358
358
359 cl_arguments = Application.cl_arguments + cl_args
359 cl_arguments = Application.cl_arguments + cl_args
360
360
361 # Private and configuration attributes
361 # Private and configuration attributes
362 _CrashHandler = crashhandler.IPythonCrashHandler
362 _CrashHandler = crashhandler.IPythonCrashHandler
363
363
364 def __init__(self, argv=None, **shell_params):
364 def __init__(self, argv=None,
365 constructor_config=None, override_config=None,
366 **shell_params):
365 """Create a new IPythonApp.
367 """Create a new IPythonApp.
366
368
369 See the parent class for details on how configuration is handled.
370
367 Parameters
371 Parameters
368 ----------
372 ----------
369 argv : optional, list
373 argv : optional, list
370 If given, used as the command-line argv environment to read arguments
374 If given, used as the command-line argv environment to read arguments
371 from.
375 from.
372
376
377 constructor_config : optional, Config
378 If given, additional config that is merged last, after internal
379 defaults, command-line and file-based configs.
380
381 override_config : optional, Config
382 If given, config that overrides all others unconditionally (except
383 for internal defaults, which ensure that all parameters exist).
384
373 shell_params : optional, dict
385 shell_params : optional, dict
374 All other keywords are passed to the :class:`iplib.InteractiveShell`
386 All other keywords are passed to the :class:`iplib.InteractiveShell`
375 constructor.
387 constructor.
376 """
388 """
377 super(IPythonApp, self).__init__(argv)
389 super(IPythonApp, self).__init__(argv, constructor_config,
390 override_config)
378 self.shell_params = shell_params
391 self.shell_params = shell_params
379
392
380 def create_default_config(self):
393 def create_default_config(self):
381 super(IPythonApp, self).create_default_config()
394 super(IPythonApp, self).create_default_config()
382 # Eliminate multiple lookups
395 # Eliminate multiple lookups
383 Global = self.default_config.Global
396 Global = self.default_config.Global
384
397
385 # Set all default values
398 # Set all default values
386 Global.display_banner = True
399 Global.display_banner = True
387
400
388 # If the -c flag is given or a file is given to run at the cmd line
401 # If the -c flag is given or a file is given to run at the cmd line
389 # like "ipython foo.py", normally we exit without starting the main
402 # like "ipython foo.py", normally we exit without starting the main
390 # loop. The force_interact config variable allows a user to override
403 # loop. The force_interact config variable allows a user to override
391 # this and interact. It is also set by the -i cmd line flag, just
404 # this and interact. It is also set by the -i cmd line flag, just
392 # like Python.
405 # like Python.
393 Global.force_interact = False
406 Global.force_interact = False
394
407
395 # By default always interact by starting the IPython mainloop.
408 # By default always interact by starting the IPython mainloop.
396 Global.interact = True
409 Global.interact = True
397
410
398 # No GUI integration by default
411 # No GUI integration by default
399 Global.gui = False
412 Global.gui = False
400 # Pylab off by default
413 # Pylab off by default
401 Global.pylab = False
414 Global.pylab = False
402
415
403 # Deprecated versions of gui support that used threading, we support
416 # Deprecated versions of gui support that used threading, we support
404 # them just for bacwards compatibility as an alternate spelling for
417 # them just for bacwards compatibility as an alternate spelling for
405 # '--gui X'
418 # '--gui X'
406 Global.qthread = False
419 Global.qthread = False
407 Global.q4thread = False
420 Global.q4thread = False
408 Global.wthread = False
421 Global.wthread = False
409 Global.gthread = False
422 Global.gthread = False
410
423
411 def load_file_config(self):
424 def load_file_config(self):
412 if hasattr(self.command_line_config.Global, 'quick'):
425 if hasattr(self.command_line_config.Global, 'quick'):
413 if self.command_line_config.Global.quick:
426 if self.command_line_config.Global.quick:
414 self.file_config = Config()
427 self.file_config = Config()
415 return
428 return
416 super(IPythonApp, self).load_file_config()
429 super(IPythonApp, self).load_file_config()
417
430
418 def post_load_file_config(self):
431 def post_load_file_config(self):
419 if hasattr(self.command_line_config.Global, 'extra_extension'):
432 if hasattr(self.command_line_config.Global, 'extra_extension'):
420 if not hasattr(self.file_config.Global, 'extensions'):
433 if not hasattr(self.file_config.Global, 'extensions'):
421 self.file_config.Global.extensions = []
434 self.file_config.Global.extensions = []
422 self.file_config.Global.extensions.append(
435 self.file_config.Global.extensions.append(
423 self.command_line_config.Global.extra_extension)
436 self.command_line_config.Global.extra_extension)
424 del self.command_line_config.Global.extra_extension
437 del self.command_line_config.Global.extra_extension
425
438
426 def pre_construct(self):
439 def pre_construct(self):
427 config = self.master_config
440 config = self.master_config
428
441
429 if hasattr(config.Global, 'classic'):
442 if hasattr(config.Global, 'classic'):
430 if config.Global.classic:
443 if config.Global.classic:
431 config.InteractiveShell.cache_size = 0
444 config.InteractiveShell.cache_size = 0
432 config.InteractiveShell.pprint = 0
445 config.InteractiveShell.pprint = 0
433 config.InteractiveShell.prompt_in1 = '>>> '
446 config.InteractiveShell.prompt_in1 = '>>> '
434 config.InteractiveShell.prompt_in2 = '... '
447 config.InteractiveShell.prompt_in2 = '... '
435 config.InteractiveShell.prompt_out = ''
448 config.InteractiveShell.prompt_out = ''
436 config.InteractiveShell.separate_in = \
449 config.InteractiveShell.separate_in = \
437 config.InteractiveShell.separate_out = \
450 config.InteractiveShell.separate_out = \
438 config.InteractiveShell.separate_out2 = ''
451 config.InteractiveShell.separate_out2 = ''
439 config.InteractiveShell.colors = 'NoColor'
452 config.InteractiveShell.colors = 'NoColor'
440 config.InteractiveShell.xmode = 'Plain'
453 config.InteractiveShell.xmode = 'Plain'
441
454
442 if hasattr(config.Global, 'nosep'):
455 if hasattr(config.Global, 'nosep'):
443 if config.Global.nosep:
456 if config.Global.nosep:
444 config.InteractiveShell.separate_in = \
457 config.InteractiveShell.separate_in = \
445 config.InteractiveShell.separate_out = \
458 config.InteractiveShell.separate_out = \
446 config.InteractiveShell.separate_out2 = ''
459 config.InteractiveShell.separate_out2 = ''
447
460
448 # if there is code of files to run from the cmd line, don't interact
461 # if there is code of files to run from the cmd line, don't interact
449 # unless the -i flag (Global.force_interact) is true.
462 # unless the -i flag (Global.force_interact) is true.
450 code_to_run = config.Global.get('code_to_run','')
463 code_to_run = config.Global.get('code_to_run','')
451 file_to_run = False
464 file_to_run = False
452 if len(self.extra_args)>=1:
465 if self.extra_args and self.extra_args[0]:
453 if self.extra_args[0]:
454 file_to_run = True
466 file_to_run = True
455 if file_to_run or code_to_run:
467 if file_to_run or code_to_run:
456 if not config.Global.force_interact:
468 if not config.Global.force_interact:
457 config.Global.interact = False
469 config.Global.interact = False
458
470
459 def construct(self):
471 def construct(self):
460 # I am a little hesitant to put these into InteractiveShell itself.
472 # I am a little hesitant to put these into InteractiveShell itself.
461 # But that might be the place for them
473 # But that might be the place for them
462 sys.path.insert(0, '')
474 sys.path.insert(0, '')
463
475
464 # Create an InteractiveShell instance
476 # Create an InteractiveShell instance
465 self.shell = InteractiveShell(None, self.master_config,
477 self.shell = InteractiveShell(None, self.master_config,
466 **self.shell_params )
478 **self.shell_params )
467
479
468 def post_construct(self):
480 def post_construct(self):
469 """Do actions after construct, but before starting the app."""
481 """Do actions after construct, but before starting the app."""
470 config = self.master_config
482 config = self.master_config
471
483
472 # shell.display_banner should always be False for the terminal
484 # shell.display_banner should always be False for the terminal
473 # based app, because we call shell.show_banner() by hand below
485 # based app, because we call shell.show_banner() by hand below
474 # so the banner shows *before* all extension loading stuff.
486 # so the banner shows *before* all extension loading stuff.
475 self.shell.display_banner = False
487 self.shell.display_banner = False
476
488
477 if config.Global.display_banner and \
489 if config.Global.display_banner and \
478 config.Global.interact:
490 config.Global.interact:
479 self.shell.show_banner()
491 self.shell.show_banner()
480
492
481 # Make sure there is a space below the banner.
493 # Make sure there is a space below the banner.
482 if self.log_level <= logging.INFO: print
494 if self.log_level <= logging.INFO: print
483
495
484 # Now a variety of things that happen after the banner is printed.
496 # Now a variety of things that happen after the banner is printed.
485 self._enable_gui_pylab()
497 self._enable_gui_pylab()
486 self._load_extensions()
498 self._load_extensions()
487 self._run_exec_lines()
499 self._run_exec_lines()
488 self._run_exec_files()
500 self._run_exec_files()
489 self._run_cmd_line_code()
501 self._run_cmd_line_code()
490 self._configure_xmode()
502 self._configure_xmode()
491
503
492 def _enable_gui_pylab(self):
504 def _enable_gui_pylab(self):
493 """Enable GUI event loop integration, taking pylab into account."""
505 """Enable GUI event loop integration, taking pylab into account."""
494 Global = self.master_config.Global
506 Global = self.master_config.Global
495
507
496 # Select which gui to use
508 # Select which gui to use
497 if Global.gui:
509 if Global.gui:
498 gui = Global.gui
510 gui = Global.gui
499 # The following are deprecated, but there's likely to be a lot of use
511 # The following are deprecated, but there's likely to be a lot of use
500 # of this form out there, so we might as well support it for now. But
512 # of this form out there, so we might as well support it for now. But
501 # the --gui option above takes precedence.
513 # the --gui option above takes precedence.
502 elif Global.wthread:
514 elif Global.wthread:
503 gui = inputhook.GUI_WX
515 gui = inputhook.GUI_WX
504 elif Global.qthread:
516 elif Global.qthread:
505 gui = inputhook.GUI_QT
517 gui = inputhook.GUI_QT
506 elif Global.gthread:
518 elif Global.gthread:
507 gui = inputhook.GUI_GTK
519 gui = inputhook.GUI_GTK
508 else:
520 else:
509 gui = None
521 gui = None
510
522
511 # Using --pylab will also require gui activation, though which toolkit
523 # Using --pylab will also require gui activation, though which toolkit
512 # to use may be chosen automatically based on mpl configuration.
524 # to use may be chosen automatically based on mpl configuration.
513 if Global.pylab:
525 if Global.pylab:
514 activate = self.shell.enable_pylab
526 activate = self.shell.enable_pylab
515 if Global.pylab == 'auto':
527 if Global.pylab == 'auto':
516 gui = None
528 gui = None
517 else:
529 else:
518 gui = Global.pylab
530 gui = Global.pylab
519 else:
531 else:
520 # Enable only GUI integration, no pylab
532 # Enable only GUI integration, no pylab
521 activate = inputhook.enable_gui
533 activate = inputhook.enable_gui
522
534
523 if gui or Global.pylab:
535 if gui or Global.pylab:
524 try:
536 try:
525 self.log.info("Enabling GUI event loop integration, "
537 self.log.info("Enabling GUI event loop integration, "
526 "toolkit=%s, pylab=%s" % (gui, Global.pylab) )
538 "toolkit=%s, pylab=%s" % (gui, Global.pylab) )
527 activate(gui)
539 activate(gui)
528 except:
540 except:
529 self.log.warn("Error in enabling GUI event loop integration:")
541 self.log.warn("Error in enabling GUI event loop integration:")
530 self.shell.showtraceback()
542 self.shell.showtraceback()
531
543
532 def _load_extensions(self):
544 def _load_extensions(self):
533 """Load all IPython extensions in Global.extensions.
545 """Load all IPython extensions in Global.extensions.
534
546
535 This uses the :meth:`InteractiveShell.load_extensions` to load all
547 This uses the :meth:`InteractiveShell.load_extensions` to load all
536 the extensions listed in ``self.master_config.Global.extensions``.
548 the extensions listed in ``self.master_config.Global.extensions``.
537 """
549 """
538 try:
550 try:
539 if hasattr(self.master_config.Global, 'extensions'):
551 if hasattr(self.master_config.Global, 'extensions'):
540 self.log.debug("Loading IPython extensions...")
552 self.log.debug("Loading IPython extensions...")
541 extensions = self.master_config.Global.extensions
553 extensions = self.master_config.Global.extensions
542 for ext in extensions:
554 for ext in extensions:
543 try:
555 try:
544 self.log.info("Loading IPython extension: %s" % ext)
556 self.log.info("Loading IPython extension: %s" % ext)
545 self.shell.load_extension(ext)
557 self.shell.load_extension(ext)
546 except:
558 except:
547 self.log.warn("Error in loading extension: %s" % ext)
559 self.log.warn("Error in loading extension: %s" % ext)
548 self.shell.showtraceback()
560 self.shell.showtraceback()
549 except:
561 except:
550 self.log.warn("Unknown error in loading extensions:")
562 self.log.warn("Unknown error in loading extensions:")
551 self.shell.showtraceback()
563 self.shell.showtraceback()
552
564
553 def _run_exec_lines(self):
565 def _run_exec_lines(self):
554 """Run lines of code in Global.exec_lines in the user's namespace."""
566 """Run lines of code in Global.exec_lines in the user's namespace."""
555 try:
567 try:
556 if hasattr(self.master_config.Global, 'exec_lines'):
568 if hasattr(self.master_config.Global, 'exec_lines'):
557 self.log.debug("Running code from Global.exec_lines...")
569 self.log.debug("Running code from Global.exec_lines...")
558 exec_lines = self.master_config.Global.exec_lines
570 exec_lines = self.master_config.Global.exec_lines
559 for line in exec_lines:
571 for line in exec_lines:
560 try:
572 try:
561 self.log.info("Running code in user namespace: %s" % line)
573 self.log.info("Running code in user namespace: %s" % line)
562 self.shell.runlines(line)
574 self.shell.runlines(line)
563 except:
575 except:
564 self.log.warn("Error in executing line in user namespace: %s" % line)
576 self.log.warn("Error in executing line in user namespace: %s" % line)
565 self.shell.showtraceback()
577 self.shell.showtraceback()
566 except:
578 except:
567 self.log.warn("Unknown error in handling Global.exec_lines:")
579 self.log.warn("Unknown error in handling Global.exec_lines:")
568 self.shell.showtraceback()
580 self.shell.showtraceback()
569
581
570 def _exec_file(self, fname):
582 def _exec_file(self, fname):
571 full_filename = filefind(fname, [u'.', self.ipython_dir])
583 full_filename = filefind(fname, [u'.', self.ipython_dir])
572 if os.path.isfile(full_filename):
584 if os.path.isfile(full_filename):
573 if full_filename.endswith(u'.py'):
585 if full_filename.endswith(u'.py'):
574 self.log.info("Running file in user namespace: %s" % full_filename)
586 self.log.info("Running file in user namespace: %s" % full_filename)
575 self.shell.safe_execfile(full_filename, self.shell.user_ns)
587 self.shell.safe_execfile(full_filename, self.shell.user_ns)
576 elif full_filename.endswith('.ipy'):
588 elif full_filename.endswith('.ipy'):
577 self.log.info("Running file in user namespace: %s" % full_filename)
589 self.log.info("Running file in user namespace: %s" % full_filename)
578 self.shell.safe_execfile_ipy(full_filename)
590 self.shell.safe_execfile_ipy(full_filename)
579 else:
591 else:
580 self.log.warn("File does not have a .py or .ipy extension: <%s>" % full_filename)
592 self.log.warn("File does not have a .py or .ipy extension: <%s>" % full_filename)
581
593
582 def _run_exec_files(self):
594 def _run_exec_files(self):
583 try:
595 try:
584 if hasattr(self.master_config.Global, 'exec_files'):
596 if hasattr(self.master_config.Global, 'exec_files'):
585 self.log.debug("Running files in Global.exec_files...")
597 self.log.debug("Running files in Global.exec_files...")
586 exec_files = self.master_config.Global.exec_files
598 exec_files = self.master_config.Global.exec_files
587 for fname in exec_files:
599 for fname in exec_files:
588 self._exec_file(fname)
600 self._exec_file(fname)
589 except:
601 except:
590 self.log.warn("Unknown error in handling Global.exec_files:")
602 self.log.warn("Unknown error in handling Global.exec_files:")
591 self.shell.showtraceback()
603 self.shell.showtraceback()
592
604
593 def _run_cmd_line_code(self):
605 def _run_cmd_line_code(self):
594 if hasattr(self.master_config.Global, 'code_to_run'):
606 if hasattr(self.master_config.Global, 'code_to_run'):
595 line = self.master_config.Global.code_to_run
607 line = self.master_config.Global.code_to_run
596 try:
608 try:
597 self.log.info("Running code given at command line (-c): %s" % line)
609 self.log.info("Running code given at command line (-c): %s" % line)
598 self.shell.runlines(line)
610 self.shell.runlines(line)
599 except:
611 except:
600 self.log.warn("Error in executing line in user namespace: %s" % line)
612 self.log.warn("Error in executing line in user namespace: %s" % line)
601 self.shell.showtraceback()
613 self.shell.showtraceback()
602 return
614 return
603 # Like Python itself, ignore the second if the first of these is present
615 # Like Python itself, ignore the second if the first of these is present
604 try:
616 try:
605 fname = self.extra_args[0]
617 fname = self.extra_args[0]
606 except:
618 except:
607 pass
619 pass
608 else:
620 else:
609 try:
621 try:
610 self._exec_file(fname)
622 self._exec_file(fname)
611 except:
623 except:
612 self.log.warn("Error in executing file in user namespace: %s" % fname)
624 self.log.warn("Error in executing file in user namespace: %s" % fname)
613 self.shell.showtraceback()
625 self.shell.showtraceback()
614
626
615 def _configure_xmode(self):
627 def _configure_xmode(self):
616 # XXX - shouldn't this be read from the config? I'm still a little
628 # XXX - shouldn't this be read from the config? I'm still a little
617 # lost with all the details of handling the new config guys...
629 # lost with all the details of handling the new config guys...
618 self.shell.InteractiveTB.set_mode(mode=self.shell.xmode)
630 self.shell.InteractiveTB.set_mode(mode=self.shell.xmode)
619
631
620 def start_app(self):
632 def start_app(self):
621 if self.master_config.Global.interact:
633 if self.master_config.Global.interact:
622 self.log.debug("Starting IPython's mainloop...")
634 self.log.debug("Starting IPython's mainloop...")
623 self.shell.mainloop()
635 self.shell.mainloop()
624 else:
636 else:
625 self.log.debug("IPython not interactive, start_app is no-op...")
637 self.log.debug("IPython not interactive, start_app is no-op...")
626
638
627
639
628 def load_default_config(ipython_dir=None):
640 def load_default_config(ipython_dir=None):
629 """Load the default config file from the default ipython_dir.
641 """Load the default config file from the default ipython_dir.
630
642
631 This is useful for embedded shells.
643 This is useful for embedded shells.
632 """
644 """
633 if ipython_dir is None:
645 if ipython_dir is None:
634 ipython_dir = get_ipython_dir()
646 ipython_dir = get_ipython_dir()
635 cl = PyFileConfigLoader(default_config_file_name, ipython_dir)
647 cl = PyFileConfigLoader(default_config_file_name, ipython_dir)
636 config = cl.load_config()
648 config = cl.load_config()
637 return config
649 return config
638
650
639
651
640 def launch_new_instance():
652 def launch_new_instance():
641 """Create and run a full blown IPython instance"""
653 """Create and run a full blown IPython instance"""
642 app = IPythonApp()
654 app = IPythonApp()
643 app.start()
655 app.start()
General Comments 0
You need to be logged in to leave comments. Login now