##// END OF EJS Templates
More work addressing review comments for Fernando's branch....
Brian Granger -
Show More
@@ -1,2558 +1,2558 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """
2 """
3 Main IPython Component
3 Main IPython Component
4 """
4 """
5
5
6 #-----------------------------------------------------------------------------
6 #-----------------------------------------------------------------------------
7 # Copyright (C) 2001 Janko Hauser <jhauser@zscout.de>
7 # Copyright (C) 2001 Janko Hauser <jhauser@zscout.de>
8 # Copyright (C) 2001-2007 Fernando Perez. <fperez@colorado.edu>
8 # Copyright (C) 2001-2007 Fernando Perez. <fperez@colorado.edu>
9 # Copyright (C) 2008-2009 The IPython Development Team
9 # Copyright (C) 2008-2009 The IPython Development Team
10 #
10 #
11 # Distributed under the terms of the BSD License. The full license is in
11 # Distributed under the terms of the BSD License. The full license is in
12 # the file COPYING, distributed as part of this software.
12 # the file COPYING, distributed as part of this software.
13 #-----------------------------------------------------------------------------
13 #-----------------------------------------------------------------------------
14
14
15 #-----------------------------------------------------------------------------
15 #-----------------------------------------------------------------------------
16 # Imports
16 # Imports
17 #-----------------------------------------------------------------------------
17 #-----------------------------------------------------------------------------
18
18
19 from __future__ import with_statement
19 from __future__ import with_statement
20 from __future__ import absolute_import
20 from __future__ import absolute_import
21
21
22 import __builtin__
22 import __builtin__
23 import bdb
23 import bdb
24 import codeop
24 import codeop
25 import exceptions
25 import exceptions
26 import new
26 import new
27 import os
27 import os
28 import re
28 import re
29 import string
29 import string
30 import sys
30 import sys
31 import tempfile
31 import tempfile
32 from contextlib import nested
32 from contextlib import nested
33
33
34 from IPython.core import debugger, oinspect
34 from IPython.core import debugger, oinspect
35 from IPython.core import history as ipcorehist
35 from IPython.core import history as ipcorehist
36 from IPython.core import prefilter
36 from IPython.core import prefilter
37 from IPython.core import shadowns
37 from IPython.core import shadowns
38 from IPython.core import ultratb
38 from IPython.core import ultratb
39 from IPython.core.alias import AliasManager
39 from IPython.core.alias import AliasManager
40 from IPython.core.builtin_trap import BuiltinTrap
40 from IPython.core.builtin_trap import BuiltinTrap
41 from IPython.core.component import Component
41 from IPython.core.component import Component
42 from IPython.core.display_trap import DisplayTrap
42 from IPython.core.display_trap import DisplayTrap
43 from IPython.core.error import TryNext, UsageError
43 from IPython.core.error import TryNext, UsageError
44 from IPython.core.fakemodule import FakeModule, init_fakemod_dict
44 from IPython.core.fakemodule import FakeModule, init_fakemod_dict
45 from IPython.core.logger import Logger
45 from IPython.core.logger import Logger
46 from IPython.core.magic import Magic
46 from IPython.core.magic import Magic
47 from IPython.core.prefilter import PrefilterManager
47 from IPython.core.prefilter import PrefilterManager
48 from IPython.core.prompts import CachedOutput
48 from IPython.core.prompts import CachedOutput
49 from IPython.core.usage import interactive_usage, default_banner
49 from IPython.core.usage import interactive_usage, default_banner
50 import IPython.core.hooks
50 import IPython.core.hooks
51 from IPython.external.Itpl import ItplNS
51 from IPython.external.Itpl import ItplNS
52 from IPython.lib.inputhook import enable_gui
52 from IPython.lib.inputhook import enable_gui
53 from IPython.lib.backgroundjobs import BackgroundJobManager
53 from IPython.lib.backgroundjobs import BackgroundJobManager
54 from IPython.lib.pylabtools import pylab_activate
54 from IPython.lib.pylabtools import pylab_activate
55 from IPython.utils import PyColorize
55 from IPython.utils import PyColorize
56 from IPython.utils import pickleshare
56 from IPython.utils import pickleshare
57 from IPython.utils.doctestreload import doctest_reload
57 from IPython.utils.doctestreload import doctest_reload
58 from IPython.utils.ipstruct import Struct
58 from IPython.utils.ipstruct import Struct
59 from IPython.utils.io import Term, ask_yes_no
59 from IPython.utils.io import Term, ask_yes_no
60 from IPython.utils.path import get_home_dir, get_ipython_dir, HomeDirError
60 from IPython.utils.path import get_home_dir, get_ipython_dir, HomeDirError
61 from IPython.utils.process import (
61 from IPython.utils.process import (
62 abbrev_cwd,
62 abbrev_cwd,
63 getoutput,
63 getoutput,
64 getoutputerror
64 getoutputerror
65 )
65 )
66 # import IPython.utils.rlineimpl as readline
66 # import IPython.utils.rlineimpl as readline
67 from IPython.utils.strdispatch import StrDispatch
67 from IPython.utils.strdispatch import StrDispatch
68 from IPython.utils.syspathcontext import prepended_to_syspath
68 from IPython.utils.syspathcontext import prepended_to_syspath
69 from IPython.utils.terminal import toggle_set_term_title, set_term_title
69 from IPython.utils.terminal import toggle_set_term_title, set_term_title
70 from IPython.utils.warn import warn, error, fatal
70 from IPython.utils.warn import warn, error, fatal
71 from IPython.utils.traitlets import (
71 from IPython.utils.traitlets import (
72 Int, Str, CBool, CaselessStrEnum, Enum, List, Unicode
72 Int, Str, CBool, CaselessStrEnum, Enum, List, Unicode
73 )
73 )
74
74
75 # from IPython.utils import growl
75 # from IPython.utils import growl
76 # growl.start("IPython")
76 # growl.start("IPython")
77
77
78 #-----------------------------------------------------------------------------
78 #-----------------------------------------------------------------------------
79 # Globals
79 # Globals
80 #-----------------------------------------------------------------------------
80 #-----------------------------------------------------------------------------
81
81
82 # store the builtin raw_input globally, and use this always, in case user code
82 # store the builtin raw_input globally, and use this always, in case user code
83 # overwrites it (like wx.py.PyShell does)
83 # overwrites it (like wx.py.PyShell does)
84 raw_input_original = raw_input
84 raw_input_original = raw_input
85
85
86 # compiled regexps for autoindent management
86 # compiled regexps for autoindent management
87 dedent_re = re.compile(r'^\s+raise|^\s+return|^\s+pass')
87 dedent_re = re.compile(r'^\s+raise|^\s+return|^\s+pass')
88
88
89 #-----------------------------------------------------------------------------
89 #-----------------------------------------------------------------------------
90 # Utilities
90 # Utilities
91 #-----------------------------------------------------------------------------
91 #-----------------------------------------------------------------------------
92
92
93 ini_spaces_re = re.compile(r'^(\s+)')
93 ini_spaces_re = re.compile(r'^(\s+)')
94
94
95
95
96 def num_ini_spaces(strng):
96 def num_ini_spaces(strng):
97 """Return the number of initial spaces in a string"""
97 """Return the number of initial spaces in a string"""
98
98
99 ini_spaces = ini_spaces_re.match(strng)
99 ini_spaces = ini_spaces_re.match(strng)
100 if ini_spaces:
100 if ini_spaces:
101 return ini_spaces.end()
101 return ini_spaces.end()
102 else:
102 else:
103 return 0
103 return 0
104
104
105
105
106 def softspace(file, newvalue):
106 def softspace(file, newvalue):
107 """Copied from code.py, to remove the dependency"""
107 """Copied from code.py, to remove the dependency"""
108
108
109 oldvalue = 0
109 oldvalue = 0
110 try:
110 try:
111 oldvalue = file.softspace
111 oldvalue = file.softspace
112 except AttributeError:
112 except AttributeError:
113 pass
113 pass
114 try:
114 try:
115 file.softspace = newvalue
115 file.softspace = newvalue
116 except (AttributeError, TypeError):
116 except (AttributeError, TypeError):
117 # "attribute-less object" or "read-only attributes"
117 # "attribute-less object" or "read-only attributes"
118 pass
118 pass
119 return oldvalue
119 return oldvalue
120
120
121
121
122 def no_op(*a, **kw): pass
122 def no_op(*a, **kw): pass
123
123
124 class SpaceInInput(exceptions.Exception): pass
124 class SpaceInInput(exceptions.Exception): pass
125
125
126 class Bunch: pass
126 class Bunch: pass
127
127
128 class InputList(list):
128 class InputList(list):
129 """Class to store user input.
129 """Class to store user input.
130
130
131 It's basically a list, but slices return a string instead of a list, thus
131 It's basically a list, but slices return a string instead of a list, thus
132 allowing things like (assuming 'In' is an instance):
132 allowing things like (assuming 'In' is an instance):
133
133
134 exec In[4:7]
134 exec In[4:7]
135
135
136 or
136 or
137
137
138 exec In[5:9] + In[14] + In[21:25]"""
138 exec In[5:9] + In[14] + In[21:25]"""
139
139
140 def __getslice__(self,i,j):
140 def __getslice__(self,i,j):
141 return ''.join(list.__getslice__(self,i,j))
141 return ''.join(list.__getslice__(self,i,j))
142
142
143
143
144 class SyntaxTB(ultratb.ListTB):
144 class SyntaxTB(ultratb.ListTB):
145 """Extension which holds some state: the last exception value"""
145 """Extension which holds some state: the last exception value"""
146
146
147 def __init__(self,color_scheme = 'NoColor'):
147 def __init__(self,color_scheme = 'NoColor'):
148 ultratb.ListTB.__init__(self,color_scheme)
148 ultratb.ListTB.__init__(self,color_scheme)
149 self.last_syntax_error = None
149 self.last_syntax_error = None
150
150
151 def __call__(self, etype, value, elist):
151 def __call__(self, etype, value, elist):
152 self.last_syntax_error = value
152 self.last_syntax_error = value
153 ultratb.ListTB.__call__(self,etype,value,elist)
153 ultratb.ListTB.__call__(self,etype,value,elist)
154
154
155 def clear_err_state(self):
155 def clear_err_state(self):
156 """Return the current error state and clear it"""
156 """Return the current error state and clear it"""
157 e = self.last_syntax_error
157 e = self.last_syntax_error
158 self.last_syntax_error = None
158 self.last_syntax_error = None
159 return e
159 return e
160
160
161
161
162 def get_default_editor():
162 def get_default_editor():
163 try:
163 try:
164 ed = os.environ['EDITOR']
164 ed = os.environ['EDITOR']
165 except KeyError:
165 except KeyError:
166 if os.name == 'posix':
166 if os.name == 'posix':
167 ed = 'vi' # the only one guaranteed to be there!
167 ed = 'vi' # the only one guaranteed to be there!
168 else:
168 else:
169 ed = 'notepad' # same in Windows!
169 ed = 'notepad' # same in Windows!
170 return ed
170 return ed
171
171
172
172
173 def get_default_colors():
173 def get_default_colors():
174 if sys.platform=='darwin':
174 if sys.platform=='darwin':
175 return "LightBG"
175 return "LightBG"
176 elif os.name=='nt':
176 elif os.name=='nt':
177 return 'Linux'
177 return 'Linux'
178 else:
178 else:
179 return 'Linux'
179 return 'Linux'
180
180
181
181
182 class SeparateStr(Str):
182 class SeparateStr(Str):
183 """A Str subclass to validate separate_in, separate_out, etc.
183 """A Str subclass to validate separate_in, separate_out, etc.
184
184
185 This is a Str based traitlet that converts '0'->'' and '\\n'->'\n'.
185 This is a Str based traitlet that converts '0'->'' and '\\n'->'\n'.
186 """
186 """
187
187
188 def validate(self, obj, value):
188 def validate(self, obj, value):
189 if value == '0': value = ''
189 if value == '0': value = ''
190 value = value.replace('\\n','\n')
190 value = value.replace('\\n','\n')
191 return super(SeparateStr, self).validate(obj, value)
191 return super(SeparateStr, self).validate(obj, value)
192
192
193
193
194 def make_user_namespaces(user_ns=None, user_global_ns=None):
195 """Return a valid local and global user interactive namespaces.
196
197 This builds a dict with the minimal information needed to operate as a
198 valid IPython user namespace, which you can pass to the various
199 embedding classes in ipython. The default implementation returns the
200 same dict for both the locals and the globals to allow functions to
201 refer to variables in the namespace. Customized implementations can
202 return different dicts. The locals dictionary can actually be anything
203 following the basic mapping protocol of a dict, but the globals dict
204 must be a true dict, not even a subclass. It is recommended that any
205 custom object for the locals namespace synchronize with the globals
206 dict somehow.
207
208 Raises TypeError if the provided globals namespace is not a true dict.
209
210 Parameters
211 ----------
212 user_ns : dict-like, optional
213 The current user namespace. The items in this namespace should
214 be included in the output. If None, an appropriate blank
215 namespace should be created.
216 user_global_ns : dict, optional
217 The current user global namespace. The items in this namespace
218 should be included in the output. If None, an appropriate
219 blank namespace should be created.
220
221 Returns
222 -------
223 A pair of dictionary-like object to be used as the local namespace
224 of the interpreter and a dict to be used as the global namespace.
225 """
226
227
228 # We must ensure that __builtin__ (without the final 's') is always
229 # available and pointing to the __builtin__ *module*. For more details:
230 # http://mail.python.org/pipermail/python-dev/2001-April/014068.html
231
232 if user_ns is None:
233 # Set __name__ to __main__ to better match the behavior of the
234 # normal interpreter.
235 user_ns = {'__name__' :'__main__',
236 '__builtin__' : __builtin__,
237 '__builtins__' : __builtin__,
238 }
239 else:
240 user_ns.setdefault('__name__','__main__')
241 user_ns.setdefault('__builtin__',__builtin__)
242 user_ns.setdefault('__builtins__',__builtin__)
243
244 if user_global_ns is None:
245 user_global_ns = user_ns
246 if type(user_global_ns) is not dict:
247 raise TypeError("user_global_ns must be a true dict; got %r"
248 % type(user_global_ns))
249
250 return user_ns, user_global_ns
251
252 #-----------------------------------------------------------------------------
194 #-----------------------------------------------------------------------------
253 # Main IPython class
195 # Main IPython class
254 #-----------------------------------------------------------------------------
196 #-----------------------------------------------------------------------------
255
197
256
198
257 class InteractiveShell(Component, Magic):
199 class InteractiveShell(Component, Magic):
258 """An enhanced, interactive shell for Python."""
200 """An enhanced, interactive shell for Python."""
259
201
260 autocall = Enum((0,1,2), default_value=1, config=True)
202 autocall = Enum((0,1,2), default_value=1, config=True)
261 autoedit_syntax = CBool(False, config=True)
203 autoedit_syntax = CBool(False, config=True)
262 autoindent = CBool(True, config=True)
204 autoindent = CBool(True, config=True)
263 automagic = CBool(True, config=True)
205 automagic = CBool(True, config=True)
264 banner = Str('')
206 banner = Str('')
265 banner1 = Str(default_banner, config=True)
207 banner1 = Str(default_banner, config=True)
266 banner2 = Str('', config=True)
208 banner2 = Str('', config=True)
267 cache_size = Int(1000, config=True)
209 cache_size = Int(1000, config=True)
268 color_info = CBool(True, config=True)
210 color_info = CBool(True, config=True)
269 colors = CaselessStrEnum(('NoColor','LightBG','Linux'),
211 colors = CaselessStrEnum(('NoColor','LightBG','Linux'),
270 default_value=get_default_colors(), config=True)
212 default_value=get_default_colors(), config=True)
271 confirm_exit = CBool(True, config=True)
213 confirm_exit = CBool(True, config=True)
272 debug = CBool(False, config=True)
214 debug = CBool(False, config=True)
273 deep_reload = CBool(False, config=True)
215 deep_reload = CBool(False, config=True)
274 # This display_banner only controls whether or not self.show_banner()
216 # This display_banner only controls whether or not self.show_banner()
275 # is called when mainloop/interact are called. The default is False
217 # is called when mainloop/interact are called. The default is False
276 # because for the terminal based application, the banner behavior
218 # because for the terminal based application, the banner behavior
277 # is controlled by Global.display_banner, which IPythonApp looks at
219 # is controlled by Global.display_banner, which IPythonApp looks at
278 # to determine if *it* should call show_banner() by hand or not.
220 # to determine if *it* should call show_banner() by hand or not.
279 display_banner = CBool(False) # This isn't configurable!
221 display_banner = CBool(False) # This isn't configurable!
280 embedded = CBool(False)
222 embedded = CBool(False)
281 embedded_active = CBool(False)
223 embedded_active = CBool(False)
282 editor = Str(get_default_editor(), config=True)
224 editor = Str(get_default_editor(), config=True)
283 filename = Str("<ipython console>")
225 filename = Str("<ipython console>")
284 ipython_dir= Unicode('', config=True) # Set to get_ipython_dir() in __init__
226 ipython_dir= Unicode('', config=True) # Set to get_ipython_dir() in __init__
285 logstart = CBool(False, config=True)
227 logstart = CBool(False, config=True)
286 logfile = Str('', config=True)
228 logfile = Str('', config=True)
287 logappend = Str('', config=True)
229 logappend = Str('', config=True)
288 object_info_string_level = Enum((0,1,2), default_value=0,
230 object_info_string_level = Enum((0,1,2), default_value=0,
289 config=True)
231 config=True)
290 pager = Str('less', config=True)
232 pager = Str('less', config=True)
291 pdb = CBool(False, config=True)
233 pdb = CBool(False, config=True)
292 pprint = CBool(True, config=True)
234 pprint = CBool(True, config=True)
293 profile = Str('', config=True)
235 profile = Str('', config=True)
294 prompt_in1 = Str('In [\\#]: ', config=True)
236 prompt_in1 = Str('In [\\#]: ', config=True)
295 prompt_in2 = Str(' .\\D.: ', config=True)
237 prompt_in2 = Str(' .\\D.: ', config=True)
296 prompt_out = Str('Out[\\#]: ', config=True)
238 prompt_out = Str('Out[\\#]: ', config=True)
297 prompts_pad_left = CBool(True, config=True)
239 prompts_pad_left = CBool(True, config=True)
298 quiet = CBool(False, config=True)
240 quiet = CBool(False, config=True)
299
241
300 readline_use = CBool(True, config=True)
242 readline_use = CBool(True, config=True)
301 readline_merge_completions = CBool(True, config=True)
243 readline_merge_completions = CBool(True, config=True)
302 readline_omit__names = Enum((0,1,2), default_value=0, config=True)
244 readline_omit__names = Enum((0,1,2), default_value=0, config=True)
303 readline_remove_delims = Str('-/~', config=True)
245 readline_remove_delims = Str('-/~', config=True)
304 readline_parse_and_bind = List([
246 readline_parse_and_bind = List([
305 'tab: complete',
247 'tab: complete',
306 '"\C-l": possible-completions',
248 '"\C-l": possible-completions',
307 'set show-all-if-ambiguous on',
249 'set show-all-if-ambiguous on',
308 '"\C-o": tab-insert',
250 '"\C-o": tab-insert',
309 '"\M-i": " "',
251 '"\M-i": " "',
310 '"\M-o": "\d\d\d\d"',
252 '"\M-o": "\d\d\d\d"',
311 '"\M-I": "\d\d\d\d"',
253 '"\M-I": "\d\d\d\d"',
312 '"\C-r": reverse-search-history',
254 '"\C-r": reverse-search-history',
313 '"\C-s": forward-search-history',
255 '"\C-s": forward-search-history',
314 '"\C-p": history-search-backward',
256 '"\C-p": history-search-backward',
315 '"\C-n": history-search-forward',
257 '"\C-n": history-search-forward',
316 '"\e[A": history-search-backward',
258 '"\e[A": history-search-backward',
317 '"\e[B": history-search-forward',
259 '"\e[B": history-search-forward',
318 '"\C-k": kill-line',
260 '"\C-k": kill-line',
319 '"\C-u": unix-line-discard',
261 '"\C-u": unix-line-discard',
320 ], allow_none=False, config=True)
262 ], allow_none=False, config=True)
321
263
322 screen_length = Int(0, config=True)
264 screen_length = Int(0, config=True)
323
265
324 # Use custom TraitletTypes that convert '0'->'' and '\\n'->'\n'
266 # Use custom TraitletTypes that convert '0'->'' and '\\n'->'\n'
325 separate_in = SeparateStr('\n', config=True)
267 separate_in = SeparateStr('\n', config=True)
326 separate_out = SeparateStr('', config=True)
268 separate_out = SeparateStr('', config=True)
327 separate_out2 = SeparateStr('', config=True)
269 separate_out2 = SeparateStr('', config=True)
328
270
329 system_header = Str('IPython system call: ', config=True)
271 system_header = Str('IPython system call: ', config=True)
330 system_verbose = CBool(False, config=True)
272 system_verbose = CBool(False, config=True)
331 term_title = CBool(False, config=True)
273 term_title = CBool(False, config=True)
332 wildcards_case_sensitive = CBool(True, config=True)
274 wildcards_case_sensitive = CBool(True, config=True)
333 xmode = CaselessStrEnum(('Context','Plain', 'Verbose'),
275 xmode = CaselessStrEnum(('Context','Plain', 'Verbose'),
334 default_value='Context', config=True)
276 default_value='Context', config=True)
335
277
336 autoexec = List(allow_none=False)
278 autoexec = List(allow_none=False)
337
279
338 # class attribute to indicate whether the class supports threads or not.
280 # class attribute to indicate whether the class supports threads or not.
339 # Subclasses with thread support should override this as needed.
281 # Subclasses with thread support should override this as needed.
340 isthreaded = False
282 isthreaded = False
341
283
342 def __init__(self, parent=None, config=None, ipython_dir=None, usage=None,
284 def __init__(self, parent=None, config=None, ipython_dir=None, usage=None,
343 user_ns=None, user_global_ns=None,
285 user_ns=None, user_global_ns=None,
344 banner1=None, banner2=None, display_banner=None,
286 banner1=None, banner2=None, display_banner=None,
345 custom_exceptions=((),None)):
287 custom_exceptions=((),None)):
346
288
347 # This is where traitlets with a config_key argument are updated
289 # This is where traitlets with a config_key argument are updated
348 # from the values on config.
290 # from the values on config.
349 super(InteractiveShell, self).__init__(parent, config=config)
291 super(InteractiveShell, self).__init__(parent, config=config)
350
292
351 # These are relatively independent and stateless
293 # These are relatively independent and stateless
352 self.init_ipython_dir(ipython_dir)
294 self.init_ipython_dir(ipython_dir)
353 self.init_instance_attrs()
295 self.init_instance_attrs()
354 self.init_term_title()
296 self.init_term_title()
355 self.init_usage(usage)
297 self.init_usage(usage)
356 self.init_banner(banner1, banner2, display_banner)
298 self.init_banner(banner1, banner2, display_banner)
357
299
358 # Create namespaces (user_ns, user_global_ns, etc.)
300 # Create namespaces (user_ns, user_global_ns, etc.)
359 self.init_create_namespaces(user_ns, user_global_ns)
301 self.init_create_namespaces(user_ns, user_global_ns)
360 # This has to be done after init_create_namespaces because it uses
302 # This has to be done after init_create_namespaces because it uses
361 # something in self.user_ns, but before init_sys_modules, which
303 # something in self.user_ns, but before init_sys_modules, which
362 # is the first thing to modify sys.
304 # is the first thing to modify sys.
363 self.save_sys_module_state()
305 self.save_sys_module_state()
364 self.init_sys_modules()
306 self.init_sys_modules()
365
307
366 self.init_history()
308 self.init_history()
367 self.init_encoding()
309 self.init_encoding()
368 self.init_prefilter()
310 self.init_prefilter()
369
311
370 Magic.__init__(self, self)
312 Magic.__init__(self, self)
371
313
372 self.init_syntax_highlighting()
314 self.init_syntax_highlighting()
373 self.init_hooks()
315 self.init_hooks()
374 self.init_pushd_popd_magic()
316 self.init_pushd_popd_magic()
375 self.init_traceback_handlers(custom_exceptions)
317 self.init_traceback_handlers(custom_exceptions)
376 self.init_user_ns()
318 self.init_user_ns()
377 self.init_logger()
319 self.init_logger()
378 self.init_alias()
320 self.init_alias()
379 self.init_builtins()
321 self.init_builtins()
380
322
381 # pre_config_initialization
323 # pre_config_initialization
382 self.init_shadow_hist()
324 self.init_shadow_hist()
383
325
384 # The next section should contain averything that was in ipmaker.
326 # The next section should contain averything that was in ipmaker.
385 self.init_logstart()
327 self.init_logstart()
386
328
387 # The following was in post_config_initialization
329 # The following was in post_config_initialization
388 self.init_inspector()
330 self.init_inspector()
389 self.init_readline()
331 self.init_readline()
390 self.init_prompts()
332 self.init_prompts()
391 self.init_displayhook()
333 self.init_displayhook()
392 self.init_reload_doctest()
334 self.init_reload_doctest()
393 self.init_magics()
335 self.init_magics()
394 self.init_pdb()
336 self.init_pdb()
395 self.hooks.late_startup_hook()
337 self.hooks.late_startup_hook()
396
338
397 def get_ipython(self):
339 def get_ipython(self):
398 """Return the currently running IPython instance."""
340 """Return the currently running IPython instance."""
399 return self
341 return self
400
342
401 #-------------------------------------------------------------------------
343 #-------------------------------------------------------------------------
402 # Traitlet changed handlers
344 # Traitlet changed handlers
403 #-------------------------------------------------------------------------
345 #-------------------------------------------------------------------------
404
346
405 def _banner1_changed(self):
347 def _banner1_changed(self):
406 self.compute_banner()
348 self.compute_banner()
407
349
408 def _banner2_changed(self):
350 def _banner2_changed(self):
409 self.compute_banner()
351 self.compute_banner()
410
352
411 def _ipython_dir_changed(self, name, new):
353 def _ipython_dir_changed(self, name, new):
412 if not os.path.isdir(new):
354 if not os.path.isdir(new):
413 os.makedirs(new, mode = 0777)
355 os.makedirs(new, mode = 0777)
414 if not os.path.isdir(self.ipython_extension_dir):
356 if not os.path.isdir(self.ipython_extension_dir):
415 os.makedirs(self.ipython_extension_dir, mode = 0777)
357 os.makedirs(self.ipython_extension_dir, mode = 0777)
416
358
417 @property
359 @property
418 def ipython_extension_dir(self):
360 def ipython_extension_dir(self):
419 return os.path.join(self.ipython_dir, 'extensions')
361 return os.path.join(self.ipython_dir, 'extensions')
420
362
421 @property
363 @property
422 def usable_screen_length(self):
364 def usable_screen_length(self):
423 if self.screen_length == 0:
365 if self.screen_length == 0:
424 return 0
366 return 0
425 else:
367 else:
426 num_lines_bot = self.separate_in.count('\n')+1
368 num_lines_bot = self.separate_in.count('\n')+1
427 return self.screen_length - num_lines_bot
369 return self.screen_length - num_lines_bot
428
370
429 def _term_title_changed(self, name, new_value):
371 def _term_title_changed(self, name, new_value):
430 self.init_term_title()
372 self.init_term_title()
431
373
432 def set_autoindent(self,value=None):
374 def set_autoindent(self,value=None):
433 """Set the autoindent flag, checking for readline support.
375 """Set the autoindent flag, checking for readline support.
434
376
435 If called with no arguments, it acts as a toggle."""
377 If called with no arguments, it acts as a toggle."""
436
378
437 if not self.has_readline:
379 if not self.has_readline:
438 if os.name == 'posix':
380 if os.name == 'posix':
439 warn("The auto-indent feature requires the readline library")
381 warn("The auto-indent feature requires the readline library")
440 self.autoindent = 0
382 self.autoindent = 0
441 return
383 return
442 if value is None:
384 if value is None:
443 self.autoindent = not self.autoindent
385 self.autoindent = not self.autoindent
444 else:
386 else:
445 self.autoindent = value
387 self.autoindent = value
446
388
447 #-------------------------------------------------------------------------
389 #-------------------------------------------------------------------------
448 # init_* methods called by __init__
390 # init_* methods called by __init__
449 #-------------------------------------------------------------------------
391 #-------------------------------------------------------------------------
450
392
451 def init_ipython_dir(self, ipython_dir):
393 def init_ipython_dir(self, ipython_dir):
452 if ipython_dir is not None:
394 if ipython_dir is not None:
453 self.ipython_dir = ipython_dir
395 self.ipython_dir = ipython_dir
454 self.config.Global.ipython_dir = self.ipython_dir
396 self.config.Global.ipython_dir = self.ipython_dir
455 return
397 return
456
398
457 if hasattr(self.config.Global, 'ipython_dir'):
399 if hasattr(self.config.Global, 'ipython_dir'):
458 self.ipython_dir = self.config.Global.ipython_dir
400 self.ipython_dir = self.config.Global.ipython_dir
459 else:
401 else:
460 self.ipython_dir = get_ipython_dir()
402 self.ipython_dir = get_ipython_dir()
461
403
462 # All children can just read this
404 # All children can just read this
463 self.config.Global.ipython_dir = self.ipython_dir
405 self.config.Global.ipython_dir = self.ipython_dir
464
406
465 def init_instance_attrs(self):
407 def init_instance_attrs(self):
466 self.jobs = BackgroundJobManager()
408 self.jobs = BackgroundJobManager()
467 self.more = False
409 self.more = False
468
410
469 # command compiler
411 # command compiler
470 self.compile = codeop.CommandCompiler()
412 self.compile = codeop.CommandCompiler()
471
413
472 # User input buffer
414 # User input buffer
473 self.buffer = []
415 self.buffer = []
474
416
475 # Make an empty namespace, which extension writers can rely on both
417 # Make an empty namespace, which extension writers can rely on both
476 # existing and NEVER being used by ipython itself. This gives them a
418 # existing and NEVER being used by ipython itself. This gives them a
477 # convenient location for storing additional information and state
419 # convenient location for storing additional information and state
478 # their extensions may require, without fear of collisions with other
420 # their extensions may require, without fear of collisions with other
479 # ipython names that may develop later.
421 # ipython names that may develop later.
480 self.meta = Struct()
422 self.meta = Struct()
481
423
482 # Object variable to store code object waiting execution. This is
424 # Object variable to store code object waiting execution. This is
483 # used mainly by the multithreaded shells, but it can come in handy in
425 # used mainly by the multithreaded shells, but it can come in handy in
484 # other situations. No need to use a Queue here, since it's a single
426 # other situations. No need to use a Queue here, since it's a single
485 # item which gets cleared once run.
427 # item which gets cleared once run.
486 self.code_to_run = None
428 self.code_to_run = None
487
429
488 # Flag to mark unconditional exit
430 # Flag to mark unconditional exit
489 self.exit_now = False
431 self.exit_now = False
490
432
491 # Temporary files used for various purposes. Deleted at exit.
433 # Temporary files used for various purposes. Deleted at exit.
492 self.tempfiles = []
434 self.tempfiles = []
493
435
494 # Keep track of readline usage (later set by init_readline)
436 # Keep track of readline usage (later set by init_readline)
495 self.has_readline = False
437 self.has_readline = False
496
438
497 # keep track of where we started running (mainly for crash post-mortem)
439 # keep track of where we started running (mainly for crash post-mortem)
498 # This is not being used anywhere currently.
440 # This is not being used anywhere currently.
499 self.starting_dir = os.getcwd()
441 self.starting_dir = os.getcwd()
500
442
501 # Indentation management
443 # Indentation management
502 self.indent_current_nsp = 0
444 self.indent_current_nsp = 0
503
445
504 def init_term_title(self):
446 def init_term_title(self):
505 # Enable or disable the terminal title.
447 # Enable or disable the terminal title.
506 if self.term_title:
448 if self.term_title:
507 toggle_set_term_title(True)
449 toggle_set_term_title(True)
508 set_term_title('IPython: ' + abbrev_cwd())
450 set_term_title('IPython: ' + abbrev_cwd())
509 else:
451 else:
510 toggle_set_term_title(False)
452 toggle_set_term_title(False)
511
453
512 def init_usage(self, usage=None):
454 def init_usage(self, usage=None):
513 if usage is None:
455 if usage is None:
514 self.usage = interactive_usage
456 self.usage = interactive_usage
515 else:
457 else:
516 self.usage = usage
458 self.usage = usage
517
459
518 def init_encoding(self):
460 def init_encoding(self):
519 # Get system encoding at startup time. Certain terminals (like Emacs
461 # Get system encoding at startup time. Certain terminals (like Emacs
520 # under Win32 have it set to None, and we need to have a known valid
462 # under Win32 have it set to None, and we need to have a known valid
521 # encoding to use in the raw_input() method
463 # encoding to use in the raw_input() method
522 try:
464 try:
523 self.stdin_encoding = sys.stdin.encoding or 'ascii'
465 self.stdin_encoding = sys.stdin.encoding or 'ascii'
524 except AttributeError:
466 except AttributeError:
525 self.stdin_encoding = 'ascii'
467 self.stdin_encoding = 'ascii'
526
468
527 def init_syntax_highlighting(self):
469 def init_syntax_highlighting(self):
528 # Python source parser/formatter for syntax highlighting
470 # Python source parser/formatter for syntax highlighting
529 pyformat = PyColorize.Parser().format
471 pyformat = PyColorize.Parser().format
530 self.pycolorize = lambda src: pyformat(src,'str',self.colors)
472 self.pycolorize = lambda src: pyformat(src,'str',self.colors)
531
473
532 def init_pushd_popd_magic(self):
474 def init_pushd_popd_magic(self):
533 # for pushd/popd management
475 # for pushd/popd management
534 try:
476 try:
535 self.home_dir = get_home_dir()
477 self.home_dir = get_home_dir()
536 except HomeDirError, msg:
478 except HomeDirError, msg:
537 fatal(msg)
479 fatal(msg)
538
480
539 self.dir_stack = []
481 self.dir_stack = []
540
482
541 def init_logger(self):
483 def init_logger(self):
542 self.logger = Logger(self, logfname='ipython_log.py', logmode='rotate')
484 self.logger = Logger(self, logfname='ipython_log.py', logmode='rotate')
543 # local shortcut, this is used a LOT
485 # local shortcut, this is used a LOT
544 self.log = self.logger.log
486 self.log = self.logger.log
545
487
546 def init_logstart(self):
488 def init_logstart(self):
547 if self.logappend:
489 if self.logappend:
548 self.magic_logstart(self.logappend + ' append')
490 self.magic_logstart(self.logappend + ' append')
549 elif self.logfile:
491 elif self.logfile:
550 self.magic_logstart(self.logfile)
492 self.magic_logstart(self.logfile)
551 elif self.logstart:
493 elif self.logstart:
552 self.magic_logstart()
494 self.magic_logstart()
553
495
554 def init_builtins(self):
496 def init_builtins(self):
555 self.builtin_trap = BuiltinTrap(self)
497 self.builtin_trap = BuiltinTrap(self)
556
498
557 def init_inspector(self):
499 def init_inspector(self):
558 # Object inspector
500 # Object inspector
559 self.inspector = oinspect.Inspector(oinspect.InspectColors,
501 self.inspector = oinspect.Inspector(oinspect.InspectColors,
560 PyColorize.ANSICodeColors,
502 PyColorize.ANSICodeColors,
561 'NoColor',
503 'NoColor',
562 self.object_info_string_level)
504 self.object_info_string_level)
563
505
564 def init_prompts(self):
506 def init_prompts(self):
565 # Initialize cache, set in/out prompts and printing system
507 # Initialize cache, set in/out prompts and printing system
566 self.outputcache = CachedOutput(self,
508 self.outputcache = CachedOutput(self,
567 self.cache_size,
509 self.cache_size,
568 self.pprint,
510 self.pprint,
569 input_sep = self.separate_in,
511 input_sep = self.separate_in,
570 output_sep = self.separate_out,
512 output_sep = self.separate_out,
571 output_sep2 = self.separate_out2,
513 output_sep2 = self.separate_out2,
572 ps1 = self.prompt_in1,
514 ps1 = self.prompt_in1,
573 ps2 = self.prompt_in2,
515 ps2 = self.prompt_in2,
574 ps_out = self.prompt_out,
516 ps_out = self.prompt_out,
575 pad_left = self.prompts_pad_left)
517 pad_left = self.prompts_pad_left)
576
518
577 # user may have over-ridden the default print hook:
519 # user may have over-ridden the default print hook:
578 try:
520 try:
579 self.outputcache.__class__.display = self.hooks.display
521 self.outputcache.__class__.display = self.hooks.display
580 except AttributeError:
522 except AttributeError:
581 pass
523 pass
582
524
583 def init_displayhook(self):
525 def init_displayhook(self):
584 self.display_trap = DisplayTrap(self, self.outputcache)
526 self.display_trap = DisplayTrap(self, self.outputcache)
585
527
586 def init_reload_doctest(self):
528 def init_reload_doctest(self):
587 # Do a proper resetting of doctest, including the necessary displayhook
529 # Do a proper resetting of doctest, including the necessary displayhook
588 # monkeypatching
530 # monkeypatching
589 try:
531 try:
590 doctest_reload()
532 doctest_reload()
591 except ImportError:
533 except ImportError:
592 warn("doctest module does not exist.")
534 warn("doctest module does not exist.")
593
535
594 #-------------------------------------------------------------------------
536 #-------------------------------------------------------------------------
595 # Things related to the banner
537 # Things related to the banner
596 #-------------------------------------------------------------------------
538 #-------------------------------------------------------------------------
597
539
598 def init_banner(self, banner1, banner2, display_banner):
540 def init_banner(self, banner1, banner2, display_banner):
599 if banner1 is not None:
541 if banner1 is not None:
600 self.banner1 = banner1
542 self.banner1 = banner1
601 if banner2 is not None:
543 if banner2 is not None:
602 self.banner2 = banner2
544 self.banner2 = banner2
603 if display_banner is not None:
545 if display_banner is not None:
604 self.display_banner = display_banner
546 self.display_banner = display_banner
605 self.compute_banner()
547 self.compute_banner()
606
548
607 def show_banner(self, banner=None):
549 def show_banner(self, banner=None):
608 if banner is None:
550 if banner is None:
609 banner = self.banner
551 banner = self.banner
610 self.write(banner)
552 self.write(banner)
611
553
612 def compute_banner(self):
554 def compute_banner(self):
613 self.banner = self.banner1 + '\n'
555 self.banner = self.banner1 + '\n'
614 if self.profile:
556 if self.profile:
615 self.banner += '\nIPython profile: %s\n' % self.profile
557 self.banner += '\nIPython profile: %s\n' % self.profile
616 if self.banner2:
558 if self.banner2:
617 self.banner += '\n' + self.banner2 + '\n'
559 self.banner += '\n' + self.banner2 + '\n'
618
560
619 #-------------------------------------------------------------------------
561 #-------------------------------------------------------------------------
620 # Things related to injections into the sys module
562 # Things related to injections into the sys module
621 #-------------------------------------------------------------------------
563 #-------------------------------------------------------------------------
622
564
623 def save_sys_module_state(self):
565 def save_sys_module_state(self):
624 """Save the state of hooks in the sys module.
566 """Save the state of hooks in the sys module.
625
567
626 This has to be called after self.user_ns is created.
568 This has to be called after self.user_ns is created.
627 """
569 """
628 self._orig_sys_module_state = {}
570 self._orig_sys_module_state = {}
629 self._orig_sys_module_state['stdin'] = sys.stdin
571 self._orig_sys_module_state['stdin'] = sys.stdin
630 self._orig_sys_module_state['stdout'] = sys.stdout
572 self._orig_sys_module_state['stdout'] = sys.stdout
631 self._orig_sys_module_state['stderr'] = sys.stderr
573 self._orig_sys_module_state['stderr'] = sys.stderr
632 self._orig_sys_module_state['excepthook'] = sys.excepthook
574 self._orig_sys_module_state['excepthook'] = sys.excepthook
633 try:
575 try:
634 self._orig_sys_modules_main_name = self.user_ns['__name__']
576 self._orig_sys_modules_main_name = self.user_ns['__name__']
635 except KeyError:
577 except KeyError:
636 pass
578 pass
637
579
638 def restore_sys_module_state(self):
580 def restore_sys_module_state(self):
639 """Restore the state of the sys module."""
581 """Restore the state of the sys module."""
640 try:
582 try:
641 for k, v in self._orig_sys_module_state.items():
583 for k, v in self._orig_sys_module_state.items():
642 setattr(sys, k, v)
584 setattr(sys, k, v)
643 except AttributeError:
585 except AttributeError:
644 pass
586 pass
645 try:
587 try:
646 delattr(sys, 'ipcompleter')
588 delattr(sys, 'ipcompleter')
647 except AttributeError:
589 except AttributeError:
648 pass
590 pass
649 # Reset what what done in self.init_sys_modules
591 # Reset what what done in self.init_sys_modules
650 try:
592 try:
651 sys.modules[self.user_ns['__name__']] = self._orig_sys_modules_main_name
593 sys.modules[self.user_ns['__name__']] = self._orig_sys_modules_main_name
652 except (AttributeError, KeyError):
594 except (AttributeError, KeyError):
653 pass
595 pass
654
596
655 #-------------------------------------------------------------------------
597 #-------------------------------------------------------------------------
656 # Things related to hooks
598 # Things related to hooks
657 #-------------------------------------------------------------------------
599 #-------------------------------------------------------------------------
658
600
659 def init_hooks(self):
601 def init_hooks(self):
660 # hooks holds pointers used for user-side customizations
602 # hooks holds pointers used for user-side customizations
661 self.hooks = Struct()
603 self.hooks = Struct()
662
604
663 self.strdispatchers = {}
605 self.strdispatchers = {}
664
606
665 # Set all default hooks, defined in the IPython.hooks module.
607 # Set all default hooks, defined in the IPython.hooks module.
666 hooks = IPython.core.hooks
608 hooks = IPython.core.hooks
667 for hook_name in hooks.__all__:
609 for hook_name in hooks.__all__:
668 # default hooks have priority 100, i.e. low; user hooks should have
610 # default hooks have priority 100, i.e. low; user hooks should have
669 # 0-100 priority
611 # 0-100 priority
670 self.set_hook(hook_name,getattr(hooks,hook_name), 100)
612 self.set_hook(hook_name,getattr(hooks,hook_name), 100)
671
613
672 def set_hook(self,name,hook, priority = 50, str_key = None, re_key = None):
614 def set_hook(self,name,hook, priority = 50, str_key = None, re_key = None):
673 """set_hook(name,hook) -> sets an internal IPython hook.
615 """set_hook(name,hook) -> sets an internal IPython hook.
674
616
675 IPython exposes some of its internal API as user-modifiable hooks. By
617 IPython exposes some of its internal API as user-modifiable hooks. By
676 adding your function to one of these hooks, you can modify IPython's
618 adding your function to one of these hooks, you can modify IPython's
677 behavior to call at runtime your own routines."""
619 behavior to call at runtime your own routines."""
678
620
679 # At some point in the future, this should validate the hook before it
621 # At some point in the future, this should validate the hook before it
680 # accepts it. Probably at least check that the hook takes the number
622 # accepts it. Probably at least check that the hook takes the number
681 # of args it's supposed to.
623 # of args it's supposed to.
682
624
683 f = new.instancemethod(hook,self,self.__class__)
625 f = new.instancemethod(hook,self,self.__class__)
684
626
685 # check if the hook is for strdispatcher first
627 # check if the hook is for strdispatcher first
686 if str_key is not None:
628 if str_key is not None:
687 sdp = self.strdispatchers.get(name, StrDispatch())
629 sdp = self.strdispatchers.get(name, StrDispatch())
688 sdp.add_s(str_key, f, priority )
630 sdp.add_s(str_key, f, priority )
689 self.strdispatchers[name] = sdp
631 self.strdispatchers[name] = sdp
690 return
632 return
691 if re_key is not None:
633 if re_key is not None:
692 sdp = self.strdispatchers.get(name, StrDispatch())
634 sdp = self.strdispatchers.get(name, StrDispatch())
693 sdp.add_re(re.compile(re_key), f, priority )
635 sdp.add_re(re.compile(re_key), f, priority )
694 self.strdispatchers[name] = sdp
636 self.strdispatchers[name] = sdp
695 return
637 return
696
638
697 dp = getattr(self.hooks, name, None)
639 dp = getattr(self.hooks, name, None)
698 if name not in IPython.core.hooks.__all__:
640 if name not in IPython.core.hooks.__all__:
699 print "Warning! Hook '%s' is not one of %s" % (name, IPython.core.hooks.__all__ )
641 print "Warning! Hook '%s' is not one of %s" % (name, IPython.core.hooks.__all__ )
700 if not dp:
642 if not dp:
701 dp = IPython.core.hooks.CommandChainDispatcher()
643 dp = IPython.core.hooks.CommandChainDispatcher()
702
644
703 try:
645 try:
704 dp.add(f,priority)
646 dp.add(f,priority)
705 except AttributeError:
647 except AttributeError:
706 # it was not commandchain, plain old func - replace
648 # it was not commandchain, plain old func - replace
707 dp = f
649 dp = f
708
650
709 setattr(self.hooks,name, dp)
651 setattr(self.hooks,name, dp)
710
652
711 #-------------------------------------------------------------------------
653 #-------------------------------------------------------------------------
712 # Things related to the "main" module
654 # Things related to the "main" module
713 #-------------------------------------------------------------------------
655 #-------------------------------------------------------------------------
714
656
715 def new_main_mod(self,ns=None):
657 def new_main_mod(self,ns=None):
716 """Return a new 'main' module object for user code execution.
658 """Return a new 'main' module object for user code execution.
717 """
659 """
718 main_mod = self._user_main_module
660 main_mod = self._user_main_module
719 init_fakemod_dict(main_mod,ns)
661 init_fakemod_dict(main_mod,ns)
720 return main_mod
662 return main_mod
721
663
722 def cache_main_mod(self,ns,fname):
664 def cache_main_mod(self,ns,fname):
723 """Cache a main module's namespace.
665 """Cache a main module's namespace.
724
666
725 When scripts are executed via %run, we must keep a reference to the
667 When scripts are executed via %run, we must keep a reference to the
726 namespace of their __main__ module (a FakeModule instance) around so
668 namespace of their __main__ module (a FakeModule instance) around so
727 that Python doesn't clear it, rendering objects defined therein
669 that Python doesn't clear it, rendering objects defined therein
728 useless.
670 useless.
729
671
730 This method keeps said reference in a private dict, keyed by the
672 This method keeps said reference in a private dict, keyed by the
731 absolute path of the module object (which corresponds to the script
673 absolute path of the module object (which corresponds to the script
732 path). This way, for multiple executions of the same script we only
674 path). This way, for multiple executions of the same script we only
733 keep one copy of the namespace (the last one), thus preventing memory
675 keep one copy of the namespace (the last one), thus preventing memory
734 leaks from old references while allowing the objects from the last
676 leaks from old references while allowing the objects from the last
735 execution to be accessible.
677 execution to be accessible.
736
678
737 Note: we can not allow the actual FakeModule instances to be deleted,
679 Note: we can not allow the actual FakeModule instances to be deleted,
738 because of how Python tears down modules (it hard-sets all their
680 because of how Python tears down modules (it hard-sets all their
739 references to None without regard for reference counts). This method
681 references to None without regard for reference counts). This method
740 must therefore make a *copy* of the given namespace, to allow the
682 must therefore make a *copy* of the given namespace, to allow the
741 original module's __dict__ to be cleared and reused.
683 original module's __dict__ to be cleared and reused.
742
684
743
685
744 Parameters
686 Parameters
745 ----------
687 ----------
746 ns : a namespace (a dict, typically)
688 ns : a namespace (a dict, typically)
747
689
748 fname : str
690 fname : str
749 Filename associated with the namespace.
691 Filename associated with the namespace.
750
692
751 Examples
693 Examples
752 --------
694 --------
753
695
754 In [10]: import IPython
696 In [10]: import IPython
755
697
756 In [11]: _ip.cache_main_mod(IPython.__dict__,IPython.__file__)
698 In [11]: _ip.cache_main_mod(IPython.__dict__,IPython.__file__)
757
699
758 In [12]: IPython.__file__ in _ip._main_ns_cache
700 In [12]: IPython.__file__ in _ip._main_ns_cache
759 Out[12]: True
701 Out[12]: True
760 """
702 """
761 self._main_ns_cache[os.path.abspath(fname)] = ns.copy()
703 self._main_ns_cache[os.path.abspath(fname)] = ns.copy()
762
704
763 def clear_main_mod_cache(self):
705 def clear_main_mod_cache(self):
764 """Clear the cache of main modules.
706 """Clear the cache of main modules.
765
707
766 Mainly for use by utilities like %reset.
708 Mainly for use by utilities like %reset.
767
709
768 Examples
710 Examples
769 --------
711 --------
770
712
771 In [15]: import IPython
713 In [15]: import IPython
772
714
773 In [16]: _ip.cache_main_mod(IPython.__dict__,IPython.__file__)
715 In [16]: _ip.cache_main_mod(IPython.__dict__,IPython.__file__)
774
716
775 In [17]: len(_ip._main_ns_cache) > 0
717 In [17]: len(_ip._main_ns_cache) > 0
776 Out[17]: True
718 Out[17]: True
777
719
778 In [18]: _ip.clear_main_mod_cache()
720 In [18]: _ip.clear_main_mod_cache()
779
721
780 In [19]: len(_ip._main_ns_cache) == 0
722 In [19]: len(_ip._main_ns_cache) == 0
781 Out[19]: True
723 Out[19]: True
782 """
724 """
783 self._main_ns_cache.clear()
725 self._main_ns_cache.clear()
784
726
785 #-------------------------------------------------------------------------
727 #-------------------------------------------------------------------------
786 # Things related to debugging
728 # Things related to debugging
787 #-------------------------------------------------------------------------
729 #-------------------------------------------------------------------------
788
730
789 def init_pdb(self):
731 def init_pdb(self):
790 # Set calling of pdb on exceptions
732 # Set calling of pdb on exceptions
791 # self.call_pdb is a property
733 # self.call_pdb is a property
792 self.call_pdb = self.pdb
734 self.call_pdb = self.pdb
793
735
794 def _get_call_pdb(self):
736 def _get_call_pdb(self):
795 return self._call_pdb
737 return self._call_pdb
796
738
797 def _set_call_pdb(self,val):
739 def _set_call_pdb(self,val):
798
740
799 if val not in (0,1,False,True):
741 if val not in (0,1,False,True):
800 raise ValueError,'new call_pdb value must be boolean'
742 raise ValueError,'new call_pdb value must be boolean'
801
743
802 # store value in instance
744 # store value in instance
803 self._call_pdb = val
745 self._call_pdb = val
804
746
805 # notify the actual exception handlers
747 # notify the actual exception handlers
806 self.InteractiveTB.call_pdb = val
748 self.InteractiveTB.call_pdb = val
807 if self.isthreaded:
749 if self.isthreaded:
808 try:
750 try:
809 self.sys_excepthook.call_pdb = val
751 self.sys_excepthook.call_pdb = val
810 except:
752 except:
811 warn('Failed to activate pdb for threaded exception handler')
753 warn('Failed to activate pdb for threaded exception handler')
812
754
813 call_pdb = property(_get_call_pdb,_set_call_pdb,None,
755 call_pdb = property(_get_call_pdb,_set_call_pdb,None,
814 'Control auto-activation of pdb at exceptions')
756 'Control auto-activation of pdb at exceptions')
815
757
816 def debugger(self,force=False):
758 def debugger(self,force=False):
817 """Call the pydb/pdb debugger.
759 """Call the pydb/pdb debugger.
818
760
819 Keywords:
761 Keywords:
820
762
821 - force(False): by default, this routine checks the instance call_pdb
763 - force(False): by default, this routine checks the instance call_pdb
822 flag and does not actually invoke the debugger if the flag is false.
764 flag and does not actually invoke the debugger if the flag is false.
823 The 'force' option forces the debugger to activate even if the flag
765 The 'force' option forces the debugger to activate even if the flag
824 is false.
766 is false.
825 """
767 """
826
768
827 if not (force or self.call_pdb):
769 if not (force or self.call_pdb):
828 return
770 return
829
771
830 if not hasattr(sys,'last_traceback'):
772 if not hasattr(sys,'last_traceback'):
831 error('No traceback has been produced, nothing to debug.')
773 error('No traceback has been produced, nothing to debug.')
832 return
774 return
833
775
834 # use pydb if available
776 # use pydb if available
835 if debugger.has_pydb:
777 if debugger.has_pydb:
836 from pydb import pm
778 from pydb import pm
837 else:
779 else:
838 # fallback to our internal debugger
780 # fallback to our internal debugger
839 pm = lambda : self.InteractiveTB.debugger(force=True)
781 pm = lambda : self.InteractiveTB.debugger(force=True)
840 self.history_saving_wrapper(pm)()
782 self.history_saving_wrapper(pm)()
841
783
842 #-------------------------------------------------------------------------
784 #-------------------------------------------------------------------------
843 # Things related to IPython's various namespaces
785 # Things related to IPython's various namespaces
844 #-------------------------------------------------------------------------
786 #-------------------------------------------------------------------------
845
787
846 def init_create_namespaces(self, user_ns=None, user_global_ns=None):
788 def init_create_namespaces(self, user_ns=None, user_global_ns=None):
847 # Create the namespace where the user will operate. user_ns is
789 # Create the namespace where the user will operate. user_ns is
848 # normally the only one used, and it is passed to the exec calls as
790 # normally the only one used, and it is passed to the exec calls as
849 # the locals argument. But we do carry a user_global_ns namespace
791 # the locals argument. But we do carry a user_global_ns namespace
850 # given as the exec 'globals' argument, This is useful in embedding
792 # given as the exec 'globals' argument, This is useful in embedding
851 # situations where the ipython shell opens in a context where the
793 # situations where the ipython shell opens in a context where the
852 # distinction between locals and globals is meaningful. For
794 # distinction between locals and globals is meaningful. For
853 # non-embedded contexts, it is just the same object as the user_ns dict.
795 # non-embedded contexts, it is just the same object as the user_ns dict.
854
796
855 # FIXME. For some strange reason, __builtins__ is showing up at user
797 # FIXME. For some strange reason, __builtins__ is showing up at user
856 # level as a dict instead of a module. This is a manual fix, but I
798 # level as a dict instead of a module. This is a manual fix, but I
857 # should really track down where the problem is coming from. Alex
799 # should really track down where the problem is coming from. Alex
858 # Schmolck reported this problem first.
800 # Schmolck reported this problem first.
859
801
860 # A useful post by Alex Martelli on this topic:
802 # A useful post by Alex Martelli on this topic:
861 # Re: inconsistent value from __builtins__
803 # Re: inconsistent value from __builtins__
862 # Von: Alex Martelli <aleaxit@yahoo.com>
804 # Von: Alex Martelli <aleaxit@yahoo.com>
863 # Datum: Freitag 01 Oktober 2004 04:45:34 nachmittags/abends
805 # Datum: Freitag 01 Oktober 2004 04:45:34 nachmittags/abends
864 # Gruppen: comp.lang.python
806 # Gruppen: comp.lang.python
865
807
866 # Michael Hohn <hohn@hooknose.lbl.gov> wrote:
808 # Michael Hohn <hohn@hooknose.lbl.gov> wrote:
867 # > >>> print type(builtin_check.get_global_binding('__builtins__'))
809 # > >>> print type(builtin_check.get_global_binding('__builtins__'))
868 # > <type 'dict'>
810 # > <type 'dict'>
869 # > >>> print type(__builtins__)
811 # > >>> print type(__builtins__)
870 # > <type 'module'>
812 # > <type 'module'>
871 # > Is this difference in return value intentional?
813 # > Is this difference in return value intentional?
872
814
873 # Well, it's documented that '__builtins__' can be either a dictionary
815 # Well, it's documented that '__builtins__' can be either a dictionary
874 # or a module, and it's been that way for a long time. Whether it's
816 # or a module, and it's been that way for a long time. Whether it's
875 # intentional (or sensible), I don't know. In any case, the idea is
817 # intentional (or sensible), I don't know. In any case, the idea is
876 # that if you need to access the built-in namespace directly, you
818 # that if you need to access the built-in namespace directly, you
877 # should start with "import __builtin__" (note, no 's') which will
819 # should start with "import __builtin__" (note, no 's') which will
878 # definitely give you a module. Yeah, it's somewhat confusing:-(.
820 # definitely give you a module. Yeah, it's somewhat confusing:-(.
879
821
880 # These routines return properly built dicts as needed by the rest of
822 # These routines return properly built dicts as needed by the rest of
881 # the code, and can also be used by extension writers to generate
823 # the code, and can also be used by extension writers to generate
882 # properly initialized namespaces.
824 # properly initialized namespaces.
883 user_ns, user_global_ns = make_user_namespaces(user_ns, user_global_ns)
825 user_ns, user_global_ns = self.make_user_namespaces(user_ns, user_global_ns)
884
826
885 # Assign namespaces
827 # Assign namespaces
886 # This is the namespace where all normal user variables live
828 # This is the namespace where all normal user variables live
887 self.user_ns = user_ns
829 self.user_ns = user_ns
888 self.user_global_ns = user_global_ns
830 self.user_global_ns = user_global_ns
889
831
890 # An auxiliary namespace that checks what parts of the user_ns were
832 # An auxiliary namespace that checks what parts of the user_ns were
891 # loaded at startup, so we can list later only variables defined in
833 # loaded at startup, so we can list later only variables defined in
892 # actual interactive use. Since it is always a subset of user_ns, it
834 # actual interactive use. Since it is always a subset of user_ns, it
893 # doesn't need to be separately tracked in the ns_table.
835 # doesn't need to be separately tracked in the ns_table.
894 self.user_config_ns = {}
836 self.user_config_ns = {}
895
837
896 # A namespace to keep track of internal data structures to prevent
838 # A namespace to keep track of internal data structures to prevent
897 # them from cluttering user-visible stuff. Will be updated later
839 # them from cluttering user-visible stuff. Will be updated later
898 self.internal_ns = {}
840 self.internal_ns = {}
899
841
900 # Now that FakeModule produces a real module, we've run into a nasty
842 # Now that FakeModule produces a real module, we've run into a nasty
901 # problem: after script execution (via %run), the module where the user
843 # problem: after script execution (via %run), the module where the user
902 # code ran is deleted. Now that this object is a true module (needed
844 # code ran is deleted. Now that this object is a true module (needed
903 # so docetst and other tools work correctly), the Python module
845 # so docetst and other tools work correctly), the Python module
904 # teardown mechanism runs over it, and sets to None every variable
846 # teardown mechanism runs over it, and sets to None every variable
905 # present in that module. Top-level references to objects from the
847 # present in that module. Top-level references to objects from the
906 # script survive, because the user_ns is updated with them. However,
848 # script survive, because the user_ns is updated with them. However,
907 # calling functions defined in the script that use other things from
849 # calling functions defined in the script that use other things from
908 # the script will fail, because the function's closure had references
850 # the script will fail, because the function's closure had references
909 # to the original objects, which are now all None. So we must protect
851 # to the original objects, which are now all None. So we must protect
910 # these modules from deletion by keeping a cache.
852 # these modules from deletion by keeping a cache.
911 #
853 #
912 # To avoid keeping stale modules around (we only need the one from the
854 # To avoid keeping stale modules around (we only need the one from the
913 # last run), we use a dict keyed with the full path to the script, so
855 # last run), we use a dict keyed with the full path to the script, so
914 # only the last version of the module is held in the cache. Note,
856 # only the last version of the module is held in the cache. Note,
915 # however, that we must cache the module *namespace contents* (their
857 # however, that we must cache the module *namespace contents* (their
916 # __dict__). Because if we try to cache the actual modules, old ones
858 # __dict__). Because if we try to cache the actual modules, old ones
917 # (uncached) could be destroyed while still holding references (such as
859 # (uncached) could be destroyed while still holding references (such as
918 # those held by GUI objects that tend to be long-lived)>
860 # those held by GUI objects that tend to be long-lived)>
919 #
861 #
920 # The %reset command will flush this cache. See the cache_main_mod()
862 # The %reset command will flush this cache. See the cache_main_mod()
921 # and clear_main_mod_cache() methods for details on use.
863 # and clear_main_mod_cache() methods for details on use.
922
864
923 # This is the cache used for 'main' namespaces
865 # This is the cache used for 'main' namespaces
924 self._main_ns_cache = {}
866 self._main_ns_cache = {}
925 # And this is the single instance of FakeModule whose __dict__ we keep
867 # And this is the single instance of FakeModule whose __dict__ we keep
926 # copying and clearing for reuse on each %run
868 # copying and clearing for reuse on each %run
927 self._user_main_module = FakeModule()
869 self._user_main_module = FakeModule()
928
870
929 # A table holding all the namespaces IPython deals with, so that
871 # A table holding all the namespaces IPython deals with, so that
930 # introspection facilities can search easily.
872 # introspection facilities can search easily.
931 self.ns_table = {'user':user_ns,
873 self.ns_table = {'user':user_ns,
932 'user_global':user_global_ns,
874 'user_global':user_global_ns,
933 'internal':self.internal_ns,
875 'internal':self.internal_ns,
934 'builtin':__builtin__.__dict__
876 'builtin':__builtin__.__dict__
935 }
877 }
936
878
937 # Similarly, track all namespaces where references can be held and that
879 # Similarly, track all namespaces where references can be held and that
938 # we can safely clear (so it can NOT include builtin). This one can be
880 # we can safely clear (so it can NOT include builtin). This one can be
939 # a simple list.
881 # a simple list.
940 self.ns_refs_table = [ user_ns, user_global_ns, self.user_config_ns,
882 self.ns_refs_table = [ user_ns, user_global_ns, self.user_config_ns,
941 self.internal_ns, self._main_ns_cache ]
883 self.internal_ns, self._main_ns_cache ]
942
884
885 def make_user_namespaces(self, user_ns=None, user_global_ns=None):
886 """Return a valid local and global user interactive namespaces.
887
888 This builds a dict with the minimal information needed to operate as a
889 valid IPython user namespace, which you can pass to the various
890 embedding classes in ipython. The default implementation returns the
891 same dict for both the locals and the globals to allow functions to
892 refer to variables in the namespace. Customized implementations can
893 return different dicts. The locals dictionary can actually be anything
894 following the basic mapping protocol of a dict, but the globals dict
895 must be a true dict, not even a subclass. It is recommended that any
896 custom object for the locals namespace synchronize with the globals
897 dict somehow.
898
899 Raises TypeError if the provided globals namespace is not a true dict.
900
901 Parameters
902 ----------
903 user_ns : dict-like, optional
904 The current user namespace. The items in this namespace should
905 be included in the output. If None, an appropriate blank
906 namespace should be created.
907 user_global_ns : dict, optional
908 The current user global namespace. The items in this namespace
909 should be included in the output. If None, an appropriate
910 blank namespace should be created.
911
912 Returns
913 -------
914 A pair of dictionary-like object to be used as the local namespace
915 of the interpreter and a dict to be used as the global namespace.
916 """
917
918
919 # We must ensure that __builtin__ (without the final 's') is always
920 # available and pointing to the __builtin__ *module*. For more details:
921 # http://mail.python.org/pipermail/python-dev/2001-April/014068.html
922
923 if user_ns is None:
924 # Set __name__ to __main__ to better match the behavior of the
925 # normal interpreter.
926 user_ns = {'__name__' :'__main__',
927 '__builtin__' : __builtin__,
928 '__builtins__' : __builtin__,
929 }
930 else:
931 user_ns.setdefault('__name__','__main__')
932 user_ns.setdefault('__builtin__',__builtin__)
933 user_ns.setdefault('__builtins__',__builtin__)
934
935 if user_global_ns is None:
936 user_global_ns = user_ns
937 if type(user_global_ns) is not dict:
938 raise TypeError("user_global_ns must be a true dict; got %r"
939 % type(user_global_ns))
940
941 return user_ns, user_global_ns
942
943 def init_sys_modules(self):
943 def init_sys_modules(self):
944 # We need to insert into sys.modules something that looks like a
944 # We need to insert into sys.modules something that looks like a
945 # module but which accesses the IPython namespace, for shelve and
945 # module but which accesses the IPython namespace, for shelve and
946 # pickle to work interactively. Normally they rely on getting
946 # pickle to work interactively. Normally they rely on getting
947 # everything out of __main__, but for embedding purposes each IPython
947 # everything out of __main__, but for embedding purposes each IPython
948 # instance has its own private namespace, so we can't go shoving
948 # instance has its own private namespace, so we can't go shoving
949 # everything into __main__.
949 # everything into __main__.
950
950
951 # note, however, that we should only do this for non-embedded
951 # note, however, that we should only do this for non-embedded
952 # ipythons, which really mimic the __main__.__dict__ with their own
952 # ipythons, which really mimic the __main__.__dict__ with their own
953 # namespace. Embedded instances, on the other hand, should not do
953 # namespace. Embedded instances, on the other hand, should not do
954 # this because they need to manage the user local/global namespaces
954 # this because they need to manage the user local/global namespaces
955 # only, but they live within a 'normal' __main__ (meaning, they
955 # only, but they live within a 'normal' __main__ (meaning, they
956 # shouldn't overtake the execution environment of the script they're
956 # shouldn't overtake the execution environment of the script they're
957 # embedded in).
957 # embedded in).
958
958
959 # This is overridden in the InteractiveShellEmbed subclass to a no-op.
959 # This is overridden in the InteractiveShellEmbed subclass to a no-op.
960
960
961 try:
961 try:
962 main_name = self.user_ns['__name__']
962 main_name = self.user_ns['__name__']
963 except KeyError:
963 except KeyError:
964 raise KeyError('user_ns dictionary MUST have a "__name__" key')
964 raise KeyError('user_ns dictionary MUST have a "__name__" key')
965 else:
965 else:
966 sys.modules[main_name] = FakeModule(self.user_ns)
966 sys.modules[main_name] = FakeModule(self.user_ns)
967
967
968 def init_user_ns(self):
968 def init_user_ns(self):
969 """Initialize all user-visible namespaces to their minimum defaults.
969 """Initialize all user-visible namespaces to their minimum defaults.
970
970
971 Certain history lists are also initialized here, as they effectively
971 Certain history lists are also initialized here, as they effectively
972 act as user namespaces.
972 act as user namespaces.
973
973
974 Notes
974 Notes
975 -----
975 -----
976 All data structures here are only filled in, they are NOT reset by this
976 All data structures here are only filled in, they are NOT reset by this
977 method. If they were not empty before, data will simply be added to
977 method. If they were not empty before, data will simply be added to
978 therm.
978 therm.
979 """
979 """
980 # This function works in two parts: first we put a few things in
980 # This function works in two parts: first we put a few things in
981 # user_ns, and we sync that contents into user_config_ns so that these
981 # user_ns, and we sync that contents into user_config_ns so that these
982 # initial variables aren't shown by %who. After the sync, we add the
982 # initial variables aren't shown by %who. After the sync, we add the
983 # rest of what we *do* want the user to see with %who even on a new
983 # rest of what we *do* want the user to see with %who even on a new
984 # session (probably nothing, so theye really only see their own stuff)
984 # session (probably nothing, so theye really only see their own stuff)
985
985
986 # The user dict must *always* have a __builtin__ reference to the
986 # The user dict must *always* have a __builtin__ reference to the
987 # Python standard __builtin__ namespace, which must be imported.
987 # Python standard __builtin__ namespace, which must be imported.
988 # This is so that certain operations in prompt evaluation can be
988 # This is so that certain operations in prompt evaluation can be
989 # reliably executed with builtins. Note that we can NOT use
989 # reliably executed with builtins. Note that we can NOT use
990 # __builtins__ (note the 's'), because that can either be a dict or a
990 # __builtins__ (note the 's'), because that can either be a dict or a
991 # module, and can even mutate at runtime, depending on the context
991 # module, and can even mutate at runtime, depending on the context
992 # (Python makes no guarantees on it). In contrast, __builtin__ is
992 # (Python makes no guarantees on it). In contrast, __builtin__ is
993 # always a module object, though it must be explicitly imported.
993 # always a module object, though it must be explicitly imported.
994
994
995 # For more details:
995 # For more details:
996 # http://mail.python.org/pipermail/python-dev/2001-April/014068.html
996 # http://mail.python.org/pipermail/python-dev/2001-April/014068.html
997 ns = dict(__builtin__ = __builtin__)
997 ns = dict(__builtin__ = __builtin__)
998
998
999 # Put 'help' in the user namespace
999 # Put 'help' in the user namespace
1000 try:
1000 try:
1001 from site import _Helper
1001 from site import _Helper
1002 ns['help'] = _Helper()
1002 ns['help'] = _Helper()
1003 except ImportError:
1003 except ImportError:
1004 warn('help() not available - check site.py')
1004 warn('help() not available - check site.py')
1005
1005
1006 # make global variables for user access to the histories
1006 # make global variables for user access to the histories
1007 ns['_ih'] = self.input_hist
1007 ns['_ih'] = self.input_hist
1008 ns['_oh'] = self.output_hist
1008 ns['_oh'] = self.output_hist
1009 ns['_dh'] = self.dir_hist
1009 ns['_dh'] = self.dir_hist
1010
1010
1011 ns['_sh'] = shadowns
1011 ns['_sh'] = shadowns
1012
1012
1013 # user aliases to input and output histories. These shouldn't show up
1013 # user aliases to input and output histories. These shouldn't show up
1014 # in %who, as they can have very large reprs.
1014 # in %who, as they can have very large reprs.
1015 ns['In'] = self.input_hist
1015 ns['In'] = self.input_hist
1016 ns['Out'] = self.output_hist
1016 ns['Out'] = self.output_hist
1017
1017
1018 # Store myself as the public api!!!
1018 # Store myself as the public api!!!
1019 ns['get_ipython'] = self.get_ipython
1019 ns['get_ipython'] = self.get_ipython
1020
1020
1021 # Sync what we've added so far to user_config_ns so these aren't seen
1021 # Sync what we've added so far to user_config_ns so these aren't seen
1022 # by %who
1022 # by %who
1023 self.user_config_ns.update(ns)
1023 self.user_config_ns.update(ns)
1024
1024
1025 # Anything put into ns now would show up in %who. Think twice before
1025 # Anything put into ns now would show up in %who. Think twice before
1026 # putting anything here, as we really want %who to show the user their
1026 # putting anything here, as we really want %who to show the user their
1027 # stuff, not our variables.
1027 # stuff, not our variables.
1028
1028
1029 # Finally, update the real user's namespace
1029 # Finally, update the real user's namespace
1030 self.user_ns.update(ns)
1030 self.user_ns.update(ns)
1031
1031
1032
1032
1033 def reset(self):
1033 def reset(self):
1034 """Clear all internal namespaces.
1034 """Clear all internal namespaces.
1035
1035
1036 Note that this is much more aggressive than %reset, since it clears
1036 Note that this is much more aggressive than %reset, since it clears
1037 fully all namespaces, as well as all input/output lists.
1037 fully all namespaces, as well as all input/output lists.
1038 """
1038 """
1039 for ns in self.ns_refs_table:
1039 for ns in self.ns_refs_table:
1040 ns.clear()
1040 ns.clear()
1041
1041
1042 self.alias_manager.clear_aliases()
1042 self.alias_manager.clear_aliases()
1043
1043
1044 # Clear input and output histories
1044 # Clear input and output histories
1045 self.input_hist[:] = []
1045 self.input_hist[:] = []
1046 self.input_hist_raw[:] = []
1046 self.input_hist_raw[:] = []
1047 self.output_hist.clear()
1047 self.output_hist.clear()
1048
1048
1049 # Restore the user namespaces to minimal usability
1049 # Restore the user namespaces to minimal usability
1050 self.init_user_ns()
1050 self.init_user_ns()
1051
1051
1052 # Restore the default and user aliases
1052 # Restore the default and user aliases
1053 self.alias_manager.init_aliases()
1053 self.alias_manager.init_aliases()
1054
1054
1055 def push(self, variables, interactive=True):
1055 def push(self, variables, interactive=True):
1056 """Inject a group of variables into the IPython user namespace.
1056 """Inject a group of variables into the IPython user namespace.
1057
1057
1058 Parameters
1058 Parameters
1059 ----------
1059 ----------
1060 variables : dict, str or list/tuple of str
1060 variables : dict, str or list/tuple of str
1061 The variables to inject into the user's namespace. If a dict,
1061 The variables to inject into the user's namespace. If a dict,
1062 a simple update is done. If a str, the string is assumed to
1062 a simple update is done. If a str, the string is assumed to
1063 have variable names separated by spaces. A list/tuple of str
1063 have variable names separated by spaces. A list/tuple of str
1064 can also be used to give the variable names. If just the variable
1064 can also be used to give the variable names. If just the variable
1065 names are give (list/tuple/str) then the variable values looked
1065 names are give (list/tuple/str) then the variable values looked
1066 up in the callers frame.
1066 up in the callers frame.
1067 interactive : bool
1067 interactive : bool
1068 If True (default), the variables will be listed with the ``who``
1068 If True (default), the variables will be listed with the ``who``
1069 magic.
1069 magic.
1070 """
1070 """
1071 vdict = None
1071 vdict = None
1072
1072
1073 # We need a dict of name/value pairs to do namespace updates.
1073 # We need a dict of name/value pairs to do namespace updates.
1074 if isinstance(variables, dict):
1074 if isinstance(variables, dict):
1075 vdict = variables
1075 vdict = variables
1076 elif isinstance(variables, (basestring, list, tuple)):
1076 elif isinstance(variables, (basestring, list, tuple)):
1077 if isinstance(variables, basestring):
1077 if isinstance(variables, basestring):
1078 vlist = variables.split()
1078 vlist = variables.split()
1079 else:
1079 else:
1080 vlist = variables
1080 vlist = variables
1081 vdict = {}
1081 vdict = {}
1082 cf = sys._getframe(1)
1082 cf = sys._getframe(1)
1083 for name in vlist:
1083 for name in vlist:
1084 try:
1084 try:
1085 vdict[name] = eval(name, cf.f_globals, cf.f_locals)
1085 vdict[name] = eval(name, cf.f_globals, cf.f_locals)
1086 except:
1086 except:
1087 print ('Could not get variable %s from %s' %
1087 print ('Could not get variable %s from %s' %
1088 (name,cf.f_code.co_name))
1088 (name,cf.f_code.co_name))
1089 else:
1089 else:
1090 raise ValueError('variables must be a dict/str/list/tuple')
1090 raise ValueError('variables must be a dict/str/list/tuple')
1091
1091
1092 # Propagate variables to user namespace
1092 # Propagate variables to user namespace
1093 self.user_ns.update(vdict)
1093 self.user_ns.update(vdict)
1094
1094
1095 # And configure interactive visibility
1095 # And configure interactive visibility
1096 config_ns = self.user_config_ns
1096 config_ns = self.user_config_ns
1097 if interactive:
1097 if interactive:
1098 for name, val in vdict.iteritems():
1098 for name, val in vdict.iteritems():
1099 config_ns.pop(name, None)
1099 config_ns.pop(name, None)
1100 else:
1100 else:
1101 for name,val in vdict.iteritems():
1101 for name,val in vdict.iteritems():
1102 config_ns[name] = val
1102 config_ns[name] = val
1103
1103
1104 #-------------------------------------------------------------------------
1104 #-------------------------------------------------------------------------
1105 # Things related to history management
1105 # Things related to history management
1106 #-------------------------------------------------------------------------
1106 #-------------------------------------------------------------------------
1107
1107
1108 def init_history(self):
1108 def init_history(self):
1109 # List of input with multi-line handling.
1109 # List of input with multi-line handling.
1110 self.input_hist = InputList()
1110 self.input_hist = InputList()
1111 # This one will hold the 'raw' input history, without any
1111 # This one will hold the 'raw' input history, without any
1112 # pre-processing. This will allow users to retrieve the input just as
1112 # pre-processing. This will allow users to retrieve the input just as
1113 # it was exactly typed in by the user, with %hist -r.
1113 # it was exactly typed in by the user, with %hist -r.
1114 self.input_hist_raw = InputList()
1114 self.input_hist_raw = InputList()
1115
1115
1116 # list of visited directories
1116 # list of visited directories
1117 try:
1117 try:
1118 self.dir_hist = [os.getcwd()]
1118 self.dir_hist = [os.getcwd()]
1119 except OSError:
1119 except OSError:
1120 self.dir_hist = []
1120 self.dir_hist = []
1121
1121
1122 # dict of output history
1122 # dict of output history
1123 self.output_hist = {}
1123 self.output_hist = {}
1124
1124
1125 # Now the history file
1125 # Now the history file
1126 if self.profile:
1126 if self.profile:
1127 histfname = 'history-%s' % self.profile
1127 histfname = 'history-%s' % self.profile
1128 else:
1128 else:
1129 histfname = 'history'
1129 histfname = 'history'
1130 self.histfile = os.path.join(self.ipython_dir, histfname)
1130 self.histfile = os.path.join(self.ipython_dir, histfname)
1131
1131
1132 # Fill the history zero entry, user counter starts at 1
1132 # Fill the history zero entry, user counter starts at 1
1133 self.input_hist.append('\n')
1133 self.input_hist.append('\n')
1134 self.input_hist_raw.append('\n')
1134 self.input_hist_raw.append('\n')
1135
1135
1136 def init_shadow_hist(self):
1136 def init_shadow_hist(self):
1137 try:
1137 try:
1138 self.db = pickleshare.PickleShareDB(self.ipython_dir + "/db")
1138 self.db = pickleshare.PickleShareDB(self.ipython_dir + "/db")
1139 except exceptions.UnicodeDecodeError:
1139 except exceptions.UnicodeDecodeError:
1140 print "Your ipython_dir can't be decoded to unicode!"
1140 print "Your ipython_dir can't be decoded to unicode!"
1141 print "Please set HOME environment variable to something that"
1141 print "Please set HOME environment variable to something that"
1142 print r"only has ASCII characters, e.g. c:\home"
1142 print r"only has ASCII characters, e.g. c:\home"
1143 print "Now it is", self.ipython_dir
1143 print "Now it is", self.ipython_dir
1144 sys.exit()
1144 sys.exit()
1145 self.shadowhist = ipcorehist.ShadowHist(self.db)
1145 self.shadowhist = ipcorehist.ShadowHist(self.db)
1146
1146
1147 def savehist(self):
1147 def savehist(self):
1148 """Save input history to a file (via readline library)."""
1148 """Save input history to a file (via readline library)."""
1149
1149
1150 try:
1150 try:
1151 self.readline.write_history_file(self.histfile)
1151 self.readline.write_history_file(self.histfile)
1152 except:
1152 except:
1153 print 'Unable to save IPython command history to file: ' + \
1153 print 'Unable to save IPython command history to file: ' + \
1154 `self.histfile`
1154 `self.histfile`
1155
1155
1156 def reloadhist(self):
1156 def reloadhist(self):
1157 """Reload the input history from disk file."""
1157 """Reload the input history from disk file."""
1158
1158
1159 try:
1159 try:
1160 self.readline.clear_history()
1160 self.readline.clear_history()
1161 self.readline.read_history_file(self.shell.histfile)
1161 self.readline.read_history_file(self.shell.histfile)
1162 except AttributeError:
1162 except AttributeError:
1163 pass
1163 pass
1164
1164
1165 def history_saving_wrapper(self, func):
1165 def history_saving_wrapper(self, func):
1166 """ Wrap func for readline history saving
1166 """ Wrap func for readline history saving
1167
1167
1168 Convert func into callable that saves & restores
1168 Convert func into callable that saves & restores
1169 history around the call """
1169 history around the call """
1170
1170
1171 if self.has_readline:
1171 if self.has_readline:
1172 from IPython.utils import rlineimpl as readline
1172 from IPython.utils import rlineimpl as readline
1173 else:
1173 else:
1174 return func
1174 return func
1175
1175
1176 def wrapper():
1176 def wrapper():
1177 self.savehist()
1177 self.savehist()
1178 try:
1178 try:
1179 func()
1179 func()
1180 finally:
1180 finally:
1181 readline.read_history_file(self.histfile)
1181 readline.read_history_file(self.histfile)
1182 return wrapper
1182 return wrapper
1183
1183
1184 #-------------------------------------------------------------------------
1184 #-------------------------------------------------------------------------
1185 # Things related to exception handling and tracebacks (not debugging)
1185 # Things related to exception handling and tracebacks (not debugging)
1186 #-------------------------------------------------------------------------
1186 #-------------------------------------------------------------------------
1187
1187
1188 def init_traceback_handlers(self, custom_exceptions):
1188 def init_traceback_handlers(self, custom_exceptions):
1189 # Syntax error handler.
1189 # Syntax error handler.
1190 self.SyntaxTB = SyntaxTB(color_scheme='NoColor')
1190 self.SyntaxTB = SyntaxTB(color_scheme='NoColor')
1191
1191
1192 # The interactive one is initialized with an offset, meaning we always
1192 # The interactive one is initialized with an offset, meaning we always
1193 # want to remove the topmost item in the traceback, which is our own
1193 # want to remove the topmost item in the traceback, which is our own
1194 # internal code. Valid modes: ['Plain','Context','Verbose']
1194 # internal code. Valid modes: ['Plain','Context','Verbose']
1195 self.InteractiveTB = ultratb.AutoFormattedTB(mode = 'Plain',
1195 self.InteractiveTB = ultratb.AutoFormattedTB(mode = 'Plain',
1196 color_scheme='NoColor',
1196 color_scheme='NoColor',
1197 tb_offset = 1)
1197 tb_offset = 1)
1198
1198
1199 # The instance will store a pointer to the system-wide exception hook,
1199 # The instance will store a pointer to the system-wide exception hook,
1200 # so that runtime code (such as magics) can access it. This is because
1200 # so that runtime code (such as magics) can access it. This is because
1201 # during the read-eval loop, it may get temporarily overwritten.
1201 # during the read-eval loop, it may get temporarily overwritten.
1202 self.sys_excepthook = sys.excepthook
1202 self.sys_excepthook = sys.excepthook
1203
1203
1204 # and add any custom exception handlers the user may have specified
1204 # and add any custom exception handlers the user may have specified
1205 self.set_custom_exc(*custom_exceptions)
1205 self.set_custom_exc(*custom_exceptions)
1206
1206
1207 # Set the exception mode
1207 # Set the exception mode
1208 self.InteractiveTB.set_mode(mode=self.xmode)
1208 self.InteractiveTB.set_mode(mode=self.xmode)
1209
1209
1210 def set_custom_exc(self,exc_tuple,handler):
1210 def set_custom_exc(self,exc_tuple,handler):
1211 """set_custom_exc(exc_tuple,handler)
1211 """set_custom_exc(exc_tuple,handler)
1212
1212
1213 Set a custom exception handler, which will be called if any of the
1213 Set a custom exception handler, which will be called if any of the
1214 exceptions in exc_tuple occur in the mainloop (specifically, in the
1214 exceptions in exc_tuple occur in the mainloop (specifically, in the
1215 runcode() method.
1215 runcode() method.
1216
1216
1217 Inputs:
1217 Inputs:
1218
1218
1219 - exc_tuple: a *tuple* of valid exceptions to call the defined
1219 - exc_tuple: a *tuple* of valid exceptions to call the defined
1220 handler for. It is very important that you use a tuple, and NOT A
1220 handler for. It is very important that you use a tuple, and NOT A
1221 LIST here, because of the way Python's except statement works. If
1221 LIST here, because of the way Python's except statement works. If
1222 you only want to trap a single exception, use a singleton tuple:
1222 you only want to trap a single exception, use a singleton tuple:
1223
1223
1224 exc_tuple == (MyCustomException,)
1224 exc_tuple == (MyCustomException,)
1225
1225
1226 - handler: this must be defined as a function with the following
1226 - handler: this must be defined as a function with the following
1227 basic interface: def my_handler(self,etype,value,tb).
1227 basic interface: def my_handler(self,etype,value,tb).
1228
1228
1229 This will be made into an instance method (via new.instancemethod)
1229 This will be made into an instance method (via new.instancemethod)
1230 of IPython itself, and it will be called if any of the exceptions
1230 of IPython itself, and it will be called if any of the exceptions
1231 listed in the exc_tuple are caught. If the handler is None, an
1231 listed in the exc_tuple are caught. If the handler is None, an
1232 internal basic one is used, which just prints basic info.
1232 internal basic one is used, which just prints basic info.
1233
1233
1234 WARNING: by putting in your own exception handler into IPython's main
1234 WARNING: by putting in your own exception handler into IPython's main
1235 execution loop, you run a very good chance of nasty crashes. This
1235 execution loop, you run a very good chance of nasty crashes. This
1236 facility should only be used if you really know what you are doing."""
1236 facility should only be used if you really know what you are doing."""
1237
1237
1238 assert type(exc_tuple)==type(()) , \
1238 assert type(exc_tuple)==type(()) , \
1239 "The custom exceptions must be given AS A TUPLE."
1239 "The custom exceptions must be given AS A TUPLE."
1240
1240
1241 def dummy_handler(self,etype,value,tb):
1241 def dummy_handler(self,etype,value,tb):
1242 print '*** Simple custom exception handler ***'
1242 print '*** Simple custom exception handler ***'
1243 print 'Exception type :',etype
1243 print 'Exception type :',etype
1244 print 'Exception value:',value
1244 print 'Exception value:',value
1245 print 'Traceback :',tb
1245 print 'Traceback :',tb
1246 print 'Source code :','\n'.join(self.buffer)
1246 print 'Source code :','\n'.join(self.buffer)
1247
1247
1248 if handler is None: handler = dummy_handler
1248 if handler is None: handler = dummy_handler
1249
1249
1250 self.CustomTB = new.instancemethod(handler,self,self.__class__)
1250 self.CustomTB = new.instancemethod(handler,self,self.__class__)
1251 self.custom_exceptions = exc_tuple
1251 self.custom_exceptions = exc_tuple
1252
1252
1253 def excepthook(self, etype, value, tb):
1253 def excepthook(self, etype, value, tb):
1254 """One more defense for GUI apps that call sys.excepthook.
1254 """One more defense for GUI apps that call sys.excepthook.
1255
1255
1256 GUI frameworks like wxPython trap exceptions and call
1256 GUI frameworks like wxPython trap exceptions and call
1257 sys.excepthook themselves. I guess this is a feature that
1257 sys.excepthook themselves. I guess this is a feature that
1258 enables them to keep running after exceptions that would
1258 enables them to keep running after exceptions that would
1259 otherwise kill their mainloop. This is a bother for IPython
1259 otherwise kill their mainloop. This is a bother for IPython
1260 which excepts to catch all of the program exceptions with a try:
1260 which excepts to catch all of the program exceptions with a try:
1261 except: statement.
1261 except: statement.
1262
1262
1263 Normally, IPython sets sys.excepthook to a CrashHandler instance, so if
1263 Normally, IPython sets sys.excepthook to a CrashHandler instance, so if
1264 any app directly invokes sys.excepthook, it will look to the user like
1264 any app directly invokes sys.excepthook, it will look to the user like
1265 IPython crashed. In order to work around this, we can disable the
1265 IPython crashed. In order to work around this, we can disable the
1266 CrashHandler and replace it with this excepthook instead, which prints a
1266 CrashHandler and replace it with this excepthook instead, which prints a
1267 regular traceback using our InteractiveTB. In this fashion, apps which
1267 regular traceback using our InteractiveTB. In this fashion, apps which
1268 call sys.excepthook will generate a regular-looking exception from
1268 call sys.excepthook will generate a regular-looking exception from
1269 IPython, and the CrashHandler will only be triggered by real IPython
1269 IPython, and the CrashHandler will only be triggered by real IPython
1270 crashes.
1270 crashes.
1271
1271
1272 This hook should be used sparingly, only in places which are not likely
1272 This hook should be used sparingly, only in places which are not likely
1273 to be true IPython errors.
1273 to be true IPython errors.
1274 """
1274 """
1275 self.showtraceback((etype,value,tb),tb_offset=0)
1275 self.showtraceback((etype,value,tb),tb_offset=0)
1276
1276
1277 def showtraceback(self,exc_tuple = None,filename=None,tb_offset=None,
1277 def showtraceback(self,exc_tuple = None,filename=None,tb_offset=None,
1278 exception_only=False):
1278 exception_only=False):
1279 """Display the exception that just occurred.
1279 """Display the exception that just occurred.
1280
1280
1281 If nothing is known about the exception, this is the method which
1281 If nothing is known about the exception, this is the method which
1282 should be used throughout the code for presenting user tracebacks,
1282 should be used throughout the code for presenting user tracebacks,
1283 rather than directly invoking the InteractiveTB object.
1283 rather than directly invoking the InteractiveTB object.
1284
1284
1285 A specific showsyntaxerror() also exists, but this method can take
1285 A specific showsyntaxerror() also exists, but this method can take
1286 care of calling it if needed, so unless you are explicitly catching a
1286 care of calling it if needed, so unless you are explicitly catching a
1287 SyntaxError exception, don't try to analyze the stack manually and
1287 SyntaxError exception, don't try to analyze the stack manually and
1288 simply call this method."""
1288 simply call this method."""
1289
1289
1290 try:
1290 try:
1291 if exc_tuple is None:
1291 if exc_tuple is None:
1292 etype, value, tb = sys.exc_info()
1292 etype, value, tb = sys.exc_info()
1293 else:
1293 else:
1294 etype, value, tb = exc_tuple
1294 etype, value, tb = exc_tuple
1295
1295
1296 if etype is None:
1296 if etype is None:
1297 if hasattr(sys, 'last_type'):
1297 if hasattr(sys, 'last_type'):
1298 etype, value, tb = sys.last_type, sys.last_value, \
1298 etype, value, tb = sys.last_type, sys.last_value, \
1299 sys.last_traceback
1299 sys.last_traceback
1300 else:
1300 else:
1301 self.write('No traceback available to show.\n')
1301 self.write('No traceback available to show.\n')
1302 return
1302 return
1303
1303
1304 if etype is SyntaxError:
1304 if etype is SyntaxError:
1305 # Though this won't be called by syntax errors in the input
1305 # Though this won't be called by syntax errors in the input
1306 # line, there may be SyntaxError cases whith imported code.
1306 # line, there may be SyntaxError cases whith imported code.
1307 self.showsyntaxerror(filename)
1307 self.showsyntaxerror(filename)
1308 elif etype is UsageError:
1308 elif etype is UsageError:
1309 print "UsageError:", value
1309 print "UsageError:", value
1310 else:
1310 else:
1311 # WARNING: these variables are somewhat deprecated and not
1311 # WARNING: these variables are somewhat deprecated and not
1312 # necessarily safe to use in a threaded environment, but tools
1312 # necessarily safe to use in a threaded environment, but tools
1313 # like pdb depend on their existence, so let's set them. If we
1313 # like pdb depend on their existence, so let's set them. If we
1314 # find problems in the field, we'll need to revisit their use.
1314 # find problems in the field, we'll need to revisit their use.
1315 sys.last_type = etype
1315 sys.last_type = etype
1316 sys.last_value = value
1316 sys.last_value = value
1317 sys.last_traceback = tb
1317 sys.last_traceback = tb
1318
1318
1319 if etype in self.custom_exceptions:
1319 if etype in self.custom_exceptions:
1320 self.CustomTB(etype,value,tb)
1320 self.CustomTB(etype,value,tb)
1321 else:
1321 else:
1322 if exception_only:
1322 if exception_only:
1323 m = ('An exception has occurred, use %tb to see the '
1323 m = ('An exception has occurred, use %tb to see the '
1324 'full traceback.')
1324 'full traceback.')
1325 print m
1325 print m
1326 self.InteractiveTB.show_exception_only(etype, value)
1326 self.InteractiveTB.show_exception_only(etype, value)
1327 else:
1327 else:
1328 self.InteractiveTB(etype,value,tb,tb_offset=tb_offset)
1328 self.InteractiveTB(etype,value,tb,tb_offset=tb_offset)
1329 if self.InteractiveTB.call_pdb:
1329 if self.InteractiveTB.call_pdb:
1330 # pdb mucks up readline, fix it back
1330 # pdb mucks up readline, fix it back
1331 self.set_completer()
1331 self.set_completer()
1332
1332
1333 except KeyboardInterrupt:
1333 except KeyboardInterrupt:
1334 self.write("\nKeyboardInterrupt\n")
1334 self.write("\nKeyboardInterrupt\n")
1335
1335
1336
1336
1337 def showsyntaxerror(self, filename=None):
1337 def showsyntaxerror(self, filename=None):
1338 """Display the syntax error that just occurred.
1338 """Display the syntax error that just occurred.
1339
1339
1340 This doesn't display a stack trace because there isn't one.
1340 This doesn't display a stack trace because there isn't one.
1341
1341
1342 If a filename is given, it is stuffed in the exception instead
1342 If a filename is given, it is stuffed in the exception instead
1343 of what was there before (because Python's parser always uses
1343 of what was there before (because Python's parser always uses
1344 "<string>" when reading from a string).
1344 "<string>" when reading from a string).
1345 """
1345 """
1346 etype, value, last_traceback = sys.exc_info()
1346 etype, value, last_traceback = sys.exc_info()
1347
1347
1348 # See note about these variables in showtraceback() above
1348 # See note about these variables in showtraceback() above
1349 sys.last_type = etype
1349 sys.last_type = etype
1350 sys.last_value = value
1350 sys.last_value = value
1351 sys.last_traceback = last_traceback
1351 sys.last_traceback = last_traceback
1352
1352
1353 if filename and etype is SyntaxError:
1353 if filename and etype is SyntaxError:
1354 # Work hard to stuff the correct filename in the exception
1354 # Work hard to stuff the correct filename in the exception
1355 try:
1355 try:
1356 msg, (dummy_filename, lineno, offset, line) = value
1356 msg, (dummy_filename, lineno, offset, line) = value
1357 except:
1357 except:
1358 # Not the format we expect; leave it alone
1358 # Not the format we expect; leave it alone
1359 pass
1359 pass
1360 else:
1360 else:
1361 # Stuff in the right filename
1361 # Stuff in the right filename
1362 try:
1362 try:
1363 # Assume SyntaxError is a class exception
1363 # Assume SyntaxError is a class exception
1364 value = SyntaxError(msg, (filename, lineno, offset, line))
1364 value = SyntaxError(msg, (filename, lineno, offset, line))
1365 except:
1365 except:
1366 # If that failed, assume SyntaxError is a string
1366 # If that failed, assume SyntaxError is a string
1367 value = msg, (filename, lineno, offset, line)
1367 value = msg, (filename, lineno, offset, line)
1368 self.SyntaxTB(etype,value,[])
1368 self.SyntaxTB(etype,value,[])
1369
1369
1370 def edit_syntax_error(self):
1370 def edit_syntax_error(self):
1371 """The bottom half of the syntax error handler called in the main loop.
1371 """The bottom half of the syntax error handler called in the main loop.
1372
1372
1373 Loop until syntax error is fixed or user cancels.
1373 Loop until syntax error is fixed or user cancels.
1374 """
1374 """
1375
1375
1376 while self.SyntaxTB.last_syntax_error:
1376 while self.SyntaxTB.last_syntax_error:
1377 # copy and clear last_syntax_error
1377 # copy and clear last_syntax_error
1378 err = self.SyntaxTB.clear_err_state()
1378 err = self.SyntaxTB.clear_err_state()
1379 if not self._should_recompile(err):
1379 if not self._should_recompile(err):
1380 return
1380 return
1381 try:
1381 try:
1382 # may set last_syntax_error again if a SyntaxError is raised
1382 # may set last_syntax_error again if a SyntaxError is raised
1383 self.safe_execfile(err.filename,self.user_ns)
1383 self.safe_execfile(err.filename,self.user_ns)
1384 except:
1384 except:
1385 self.showtraceback()
1385 self.showtraceback()
1386 else:
1386 else:
1387 try:
1387 try:
1388 f = file(err.filename)
1388 f = file(err.filename)
1389 try:
1389 try:
1390 # This should be inside a display_trap block and I
1390 # This should be inside a display_trap block and I
1391 # think it is.
1391 # think it is.
1392 sys.displayhook(f.read())
1392 sys.displayhook(f.read())
1393 finally:
1393 finally:
1394 f.close()
1394 f.close()
1395 except:
1395 except:
1396 self.showtraceback()
1396 self.showtraceback()
1397
1397
1398 def _should_recompile(self,e):
1398 def _should_recompile(self,e):
1399 """Utility routine for edit_syntax_error"""
1399 """Utility routine for edit_syntax_error"""
1400
1400
1401 if e.filename in ('<ipython console>','<input>','<string>',
1401 if e.filename in ('<ipython console>','<input>','<string>',
1402 '<console>','<BackgroundJob compilation>',
1402 '<console>','<BackgroundJob compilation>',
1403 None):
1403 None):
1404
1404
1405 return False
1405 return False
1406 try:
1406 try:
1407 if (self.autoedit_syntax and
1407 if (self.autoedit_syntax and
1408 not self.ask_yes_no('Return to editor to correct syntax error? '
1408 not self.ask_yes_no('Return to editor to correct syntax error? '
1409 '[Y/n] ','y')):
1409 '[Y/n] ','y')):
1410 return False
1410 return False
1411 except EOFError:
1411 except EOFError:
1412 return False
1412 return False
1413
1413
1414 def int0(x):
1414 def int0(x):
1415 try:
1415 try:
1416 return int(x)
1416 return int(x)
1417 except TypeError:
1417 except TypeError:
1418 return 0
1418 return 0
1419 # always pass integer line and offset values to editor hook
1419 # always pass integer line and offset values to editor hook
1420 try:
1420 try:
1421 self.hooks.fix_error_editor(e.filename,
1421 self.hooks.fix_error_editor(e.filename,
1422 int0(e.lineno),int0(e.offset),e.msg)
1422 int0(e.lineno),int0(e.offset),e.msg)
1423 except TryNext:
1423 except TryNext:
1424 warn('Could not open editor')
1424 warn('Could not open editor')
1425 return False
1425 return False
1426 return True
1426 return True
1427
1427
1428 #-------------------------------------------------------------------------
1428 #-------------------------------------------------------------------------
1429 # Things related to tab completion
1429 # Things related to tab completion
1430 #-------------------------------------------------------------------------
1430 #-------------------------------------------------------------------------
1431
1431
1432 def complete(self, text):
1432 def complete(self, text):
1433 """Return a sorted list of all possible completions on text.
1433 """Return a sorted list of all possible completions on text.
1434
1434
1435 Inputs:
1435 Inputs:
1436
1436
1437 - text: a string of text to be completed on.
1437 - text: a string of text to be completed on.
1438
1438
1439 This is a wrapper around the completion mechanism, similar to what
1439 This is a wrapper around the completion mechanism, similar to what
1440 readline does at the command line when the TAB key is hit. By
1440 readline does at the command line when the TAB key is hit. By
1441 exposing it as a method, it can be used by other non-readline
1441 exposing it as a method, it can be used by other non-readline
1442 environments (such as GUIs) for text completion.
1442 environments (such as GUIs) for text completion.
1443
1443
1444 Simple usage example:
1444 Simple usage example:
1445
1445
1446 In [7]: x = 'hello'
1446 In [7]: x = 'hello'
1447
1447
1448 In [8]: x
1448 In [8]: x
1449 Out[8]: 'hello'
1449 Out[8]: 'hello'
1450
1450
1451 In [9]: print x
1451 In [9]: print x
1452 hello
1452 hello
1453
1453
1454 In [10]: _ip.complete('x.l')
1454 In [10]: _ip.complete('x.l')
1455 Out[10]: ['x.ljust', 'x.lower', 'x.lstrip']
1455 Out[10]: ['x.ljust', 'x.lower', 'x.lstrip']
1456 """
1456 """
1457
1457
1458 # Inject names into __builtin__ so we can complete on the added names.
1458 # Inject names into __builtin__ so we can complete on the added names.
1459 with self.builtin_trap:
1459 with self.builtin_trap:
1460 complete = self.Completer.complete
1460 complete = self.Completer.complete
1461 state = 0
1461 state = 0
1462 # use a dict so we get unique keys, since ipyhton's multiple
1462 # use a dict so we get unique keys, since ipyhton's multiple
1463 # completers can return duplicates. When we make 2.4 a requirement,
1463 # completers can return duplicates. When we make 2.4 a requirement,
1464 # start using sets instead, which are faster.
1464 # start using sets instead, which are faster.
1465 comps = {}
1465 comps = {}
1466 while True:
1466 while True:
1467 newcomp = complete(text,state,line_buffer=text)
1467 newcomp = complete(text,state,line_buffer=text)
1468 if newcomp is None:
1468 if newcomp is None:
1469 break
1469 break
1470 comps[newcomp] = 1
1470 comps[newcomp] = 1
1471 state += 1
1471 state += 1
1472 outcomps = comps.keys()
1472 outcomps = comps.keys()
1473 outcomps.sort()
1473 outcomps.sort()
1474 #print "T:",text,"OC:",outcomps # dbg
1474 #print "T:",text,"OC:",outcomps # dbg
1475 #print "vars:",self.user_ns.keys()
1475 #print "vars:",self.user_ns.keys()
1476 return outcomps
1476 return outcomps
1477
1477
1478 def set_custom_completer(self,completer,pos=0):
1478 def set_custom_completer(self,completer,pos=0):
1479 """Adds a new custom completer function.
1479 """Adds a new custom completer function.
1480
1480
1481 The position argument (defaults to 0) is the index in the completers
1481 The position argument (defaults to 0) is the index in the completers
1482 list where you want the completer to be inserted."""
1482 list where you want the completer to be inserted."""
1483
1483
1484 newcomp = new.instancemethod(completer,self.Completer,
1484 newcomp = new.instancemethod(completer,self.Completer,
1485 self.Completer.__class__)
1485 self.Completer.__class__)
1486 self.Completer.matchers.insert(pos,newcomp)
1486 self.Completer.matchers.insert(pos,newcomp)
1487
1487
1488 def set_completer(self):
1488 def set_completer(self):
1489 """Reset readline's completer to be our own."""
1489 """Reset readline's completer to be our own."""
1490 self.readline.set_completer(self.Completer.complete)
1490 self.readline.set_completer(self.Completer.complete)
1491
1491
1492 def set_completer_frame(self, frame=None):
1492 def set_completer_frame(self, frame=None):
1493 """Set the frame of the completer."""
1493 """Set the frame of the completer."""
1494 if frame:
1494 if frame:
1495 self.Completer.namespace = frame.f_locals
1495 self.Completer.namespace = frame.f_locals
1496 self.Completer.global_namespace = frame.f_globals
1496 self.Completer.global_namespace = frame.f_globals
1497 else:
1497 else:
1498 self.Completer.namespace = self.user_ns
1498 self.Completer.namespace = self.user_ns
1499 self.Completer.global_namespace = self.user_global_ns
1499 self.Completer.global_namespace = self.user_global_ns
1500
1500
1501 #-------------------------------------------------------------------------
1501 #-------------------------------------------------------------------------
1502 # Things related to readline
1502 # Things related to readline
1503 #-------------------------------------------------------------------------
1503 #-------------------------------------------------------------------------
1504
1504
1505 def init_readline(self):
1505 def init_readline(self):
1506 """Command history completion/saving/reloading."""
1506 """Command history completion/saving/reloading."""
1507
1507
1508 if self.readline_use:
1508 if self.readline_use:
1509 import IPython.utils.rlineimpl as readline
1509 import IPython.utils.rlineimpl as readline
1510
1510
1511 self.rl_next_input = None
1511 self.rl_next_input = None
1512 self.rl_do_indent = False
1512 self.rl_do_indent = False
1513
1513
1514 if not self.readline_use or not readline.have_readline:
1514 if not self.readline_use or not readline.have_readline:
1515 self.has_readline = False
1515 self.has_readline = False
1516 self.readline = None
1516 self.readline = None
1517 # Set a number of methods that depend on readline to be no-op
1517 # Set a number of methods that depend on readline to be no-op
1518 self.savehist = no_op
1518 self.savehist = no_op
1519 self.reloadhist = no_op
1519 self.reloadhist = no_op
1520 self.set_completer = no_op
1520 self.set_completer = no_op
1521 self.set_custom_completer = no_op
1521 self.set_custom_completer = no_op
1522 self.set_completer_frame = no_op
1522 self.set_completer_frame = no_op
1523 warn('Readline services not available or not loaded.')
1523 warn('Readline services not available or not loaded.')
1524 else:
1524 else:
1525 self.has_readline = True
1525 self.has_readline = True
1526 self.readline = readline
1526 self.readline = readline
1527 sys.modules['readline'] = readline
1527 sys.modules['readline'] = readline
1528 import atexit
1528 import atexit
1529 from IPython.core.completer import IPCompleter
1529 from IPython.core.completer import IPCompleter
1530 self.Completer = IPCompleter(self,
1530 self.Completer = IPCompleter(self,
1531 self.user_ns,
1531 self.user_ns,
1532 self.user_global_ns,
1532 self.user_global_ns,
1533 self.readline_omit__names,
1533 self.readline_omit__names,
1534 self.alias_manager.alias_table)
1534 self.alias_manager.alias_table)
1535 sdisp = self.strdispatchers.get('complete_command', StrDispatch())
1535 sdisp = self.strdispatchers.get('complete_command', StrDispatch())
1536 self.strdispatchers['complete_command'] = sdisp
1536 self.strdispatchers['complete_command'] = sdisp
1537 self.Completer.custom_completers = sdisp
1537 self.Completer.custom_completers = sdisp
1538 # Platform-specific configuration
1538 # Platform-specific configuration
1539 if os.name == 'nt':
1539 if os.name == 'nt':
1540 self.readline_startup_hook = readline.set_pre_input_hook
1540 self.readline_startup_hook = readline.set_pre_input_hook
1541 else:
1541 else:
1542 self.readline_startup_hook = readline.set_startup_hook
1542 self.readline_startup_hook = readline.set_startup_hook
1543
1543
1544 # Load user's initrc file (readline config)
1544 # Load user's initrc file (readline config)
1545 # Or if libedit is used, load editrc.
1545 # Or if libedit is used, load editrc.
1546 inputrc_name = os.environ.get('INPUTRC')
1546 inputrc_name = os.environ.get('INPUTRC')
1547 if inputrc_name is None:
1547 if inputrc_name is None:
1548 home_dir = get_home_dir()
1548 home_dir = get_home_dir()
1549 if home_dir is not None:
1549 if home_dir is not None:
1550 inputrc_name = '.inputrc'
1550 inputrc_name = '.inputrc'
1551 if readline.uses_libedit:
1551 if readline.uses_libedit:
1552 inputrc_name = '.editrc'
1552 inputrc_name = '.editrc'
1553 inputrc_name = os.path.join(home_dir, inputrc_name)
1553 inputrc_name = os.path.join(home_dir, inputrc_name)
1554 if os.path.isfile(inputrc_name):
1554 if os.path.isfile(inputrc_name):
1555 try:
1555 try:
1556 readline.read_init_file(inputrc_name)
1556 readline.read_init_file(inputrc_name)
1557 except:
1557 except:
1558 warn('Problems reading readline initialization file <%s>'
1558 warn('Problems reading readline initialization file <%s>'
1559 % inputrc_name)
1559 % inputrc_name)
1560
1560
1561 # save this in sys so embedded copies can restore it properly
1561 # save this in sys so embedded copies can restore it properly
1562 sys.ipcompleter = self.Completer.complete
1562 sys.ipcompleter = self.Completer.complete
1563 self.set_completer()
1563 self.set_completer()
1564
1564
1565 # Configure readline according to user's prefs
1565 # Configure readline according to user's prefs
1566 # This is only done if GNU readline is being used. If libedit
1566 # This is only done if GNU readline is being used. If libedit
1567 # is being used (as on Leopard) the readline config is
1567 # is being used (as on Leopard) the readline config is
1568 # not run as the syntax for libedit is different.
1568 # not run as the syntax for libedit is different.
1569 if not readline.uses_libedit:
1569 if not readline.uses_libedit:
1570 for rlcommand in self.readline_parse_and_bind:
1570 for rlcommand in self.readline_parse_and_bind:
1571 #print "loading rl:",rlcommand # dbg
1571 #print "loading rl:",rlcommand # dbg
1572 readline.parse_and_bind(rlcommand)
1572 readline.parse_and_bind(rlcommand)
1573
1573
1574 # Remove some chars from the delimiters list. If we encounter
1574 # Remove some chars from the delimiters list. If we encounter
1575 # unicode chars, discard them.
1575 # unicode chars, discard them.
1576 delims = readline.get_completer_delims().encode("ascii", "ignore")
1576 delims = readline.get_completer_delims().encode("ascii", "ignore")
1577 delims = delims.translate(string._idmap,
1577 delims = delims.translate(string._idmap,
1578 self.readline_remove_delims)
1578 self.readline_remove_delims)
1579 readline.set_completer_delims(delims)
1579 readline.set_completer_delims(delims)
1580 # otherwise we end up with a monster history after a while:
1580 # otherwise we end up with a monster history after a while:
1581 readline.set_history_length(1000)
1581 readline.set_history_length(1000)
1582 try:
1582 try:
1583 #print '*** Reading readline history' # dbg
1583 #print '*** Reading readline history' # dbg
1584 readline.read_history_file(self.histfile)
1584 readline.read_history_file(self.histfile)
1585 except IOError:
1585 except IOError:
1586 pass # It doesn't exist yet.
1586 pass # It doesn't exist yet.
1587
1587
1588 atexit.register(self.atexit_operations)
1588 atexit.register(self.atexit_operations)
1589 del atexit
1589 del atexit
1590
1590
1591 # Configure auto-indent for all platforms
1591 # Configure auto-indent for all platforms
1592 self.set_autoindent(self.autoindent)
1592 self.set_autoindent(self.autoindent)
1593
1593
1594 def set_next_input(self, s):
1594 def set_next_input(self, s):
1595 """ Sets the 'default' input string for the next command line.
1595 """ Sets the 'default' input string for the next command line.
1596
1596
1597 Requires readline.
1597 Requires readline.
1598
1598
1599 Example:
1599 Example:
1600
1600
1601 [D:\ipython]|1> _ip.set_next_input("Hello Word")
1601 [D:\ipython]|1> _ip.set_next_input("Hello Word")
1602 [D:\ipython]|2> Hello Word_ # cursor is here
1602 [D:\ipython]|2> Hello Word_ # cursor is here
1603 """
1603 """
1604
1604
1605 self.rl_next_input = s
1605 self.rl_next_input = s
1606
1606
1607 def pre_readline(self):
1607 def pre_readline(self):
1608 """readline hook to be used at the start of each line.
1608 """readline hook to be used at the start of each line.
1609
1609
1610 Currently it handles auto-indent only."""
1610 Currently it handles auto-indent only."""
1611
1611
1612 #debugx('self.indent_current_nsp','pre_readline:')
1612 #debugx('self.indent_current_nsp','pre_readline:')
1613
1613
1614 if self.rl_do_indent:
1614 if self.rl_do_indent:
1615 self.readline.insert_text(self._indent_current_str())
1615 self.readline.insert_text(self._indent_current_str())
1616 if self.rl_next_input is not None:
1616 if self.rl_next_input is not None:
1617 self.readline.insert_text(self.rl_next_input)
1617 self.readline.insert_text(self.rl_next_input)
1618 self.rl_next_input = None
1618 self.rl_next_input = None
1619
1619
1620 def _indent_current_str(self):
1620 def _indent_current_str(self):
1621 """return the current level of indentation as a string"""
1621 """return the current level of indentation as a string"""
1622 return self.indent_current_nsp * ' '
1622 return self.indent_current_nsp * ' '
1623
1623
1624 #-------------------------------------------------------------------------
1624 #-------------------------------------------------------------------------
1625 # Things related to magics
1625 # Things related to magics
1626 #-------------------------------------------------------------------------
1626 #-------------------------------------------------------------------------
1627
1627
1628 def init_magics(self):
1628 def init_magics(self):
1629 # Set user colors (don't do it in the constructor above so that it
1629 # Set user colors (don't do it in the constructor above so that it
1630 # doesn't crash if colors option is invalid)
1630 # doesn't crash if colors option is invalid)
1631 self.magic_colors(self.colors)
1631 self.magic_colors(self.colors)
1632 # History was moved to a separate module
1632 # History was moved to a separate module
1633 from . import history
1633 from . import history
1634 history.init_ipython(self)
1634 history.init_ipython(self)
1635
1635
1636 def magic(self,arg_s):
1636 def magic(self,arg_s):
1637 """Call a magic function by name.
1637 """Call a magic function by name.
1638
1638
1639 Input: a string containing the name of the magic function to call and any
1639 Input: a string containing the name of the magic function to call and any
1640 additional arguments to be passed to the magic.
1640 additional arguments to be passed to the magic.
1641
1641
1642 magic('name -opt foo bar') is equivalent to typing at the ipython
1642 magic('name -opt foo bar') is equivalent to typing at the ipython
1643 prompt:
1643 prompt:
1644
1644
1645 In[1]: %name -opt foo bar
1645 In[1]: %name -opt foo bar
1646
1646
1647 To call a magic without arguments, simply use magic('name').
1647 To call a magic without arguments, simply use magic('name').
1648
1648
1649 This provides a proper Python function to call IPython's magics in any
1649 This provides a proper Python function to call IPython's magics in any
1650 valid Python code you can type at the interpreter, including loops and
1650 valid Python code you can type at the interpreter, including loops and
1651 compound statements.
1651 compound statements.
1652 """
1652 """
1653 args = arg_s.split(' ',1)
1653 args = arg_s.split(' ',1)
1654 magic_name = args[0]
1654 magic_name = args[0]
1655 magic_name = magic_name.lstrip(prefilter.ESC_MAGIC)
1655 magic_name = magic_name.lstrip(prefilter.ESC_MAGIC)
1656
1656
1657 try:
1657 try:
1658 magic_args = args[1]
1658 magic_args = args[1]
1659 except IndexError:
1659 except IndexError:
1660 magic_args = ''
1660 magic_args = ''
1661 fn = getattr(self,'magic_'+magic_name,None)
1661 fn = getattr(self,'magic_'+magic_name,None)
1662 if fn is None:
1662 if fn is None:
1663 error("Magic function `%s` not found." % magic_name)
1663 error("Magic function `%s` not found." % magic_name)
1664 else:
1664 else:
1665 magic_args = self.var_expand(magic_args,1)
1665 magic_args = self.var_expand(magic_args,1)
1666 with nested(self.builtin_trap,):
1666 with nested(self.builtin_trap,):
1667 result = fn(magic_args)
1667 result = fn(magic_args)
1668 return result
1668 return result
1669
1669
1670 def define_magic(self, magicname, func):
1670 def define_magic(self, magicname, func):
1671 """Expose own function as magic function for ipython
1671 """Expose own function as magic function for ipython
1672
1672
1673 def foo_impl(self,parameter_s=''):
1673 def foo_impl(self,parameter_s=''):
1674 'My very own magic!. (Use docstrings, IPython reads them).'
1674 'My very own magic!. (Use docstrings, IPython reads them).'
1675 print 'Magic function. Passed parameter is between < >:'
1675 print 'Magic function. Passed parameter is between < >:'
1676 print '<%s>' % parameter_s
1676 print '<%s>' % parameter_s
1677 print 'The self object is:',self
1677 print 'The self object is:',self
1678
1678
1679 self.define_magic('foo',foo_impl)
1679 self.define_magic('foo',foo_impl)
1680 """
1680 """
1681
1681
1682 import new
1682 import new
1683 im = new.instancemethod(func,self, self.__class__)
1683 im = new.instancemethod(func,self, self.__class__)
1684 old = getattr(self, "magic_" + magicname, None)
1684 old = getattr(self, "magic_" + magicname, None)
1685 setattr(self, "magic_" + magicname, im)
1685 setattr(self, "magic_" + magicname, im)
1686 return old
1686 return old
1687
1687
1688 #-------------------------------------------------------------------------
1688 #-------------------------------------------------------------------------
1689 # Things related to macros
1689 # Things related to macros
1690 #-------------------------------------------------------------------------
1690 #-------------------------------------------------------------------------
1691
1691
1692 def define_macro(self, name, themacro):
1692 def define_macro(self, name, themacro):
1693 """Define a new macro
1693 """Define a new macro
1694
1694
1695 Parameters
1695 Parameters
1696 ----------
1696 ----------
1697 name : str
1697 name : str
1698 The name of the macro.
1698 The name of the macro.
1699 themacro : str or Macro
1699 themacro : str or Macro
1700 The action to do upon invoking the macro. If a string, a new
1700 The action to do upon invoking the macro. If a string, a new
1701 Macro object is created by passing the string to it.
1701 Macro object is created by passing the string to it.
1702 """
1702 """
1703
1703
1704 from IPython.core import macro
1704 from IPython.core import macro
1705
1705
1706 if isinstance(themacro, basestring):
1706 if isinstance(themacro, basestring):
1707 themacro = macro.Macro(themacro)
1707 themacro = macro.Macro(themacro)
1708 if not isinstance(themacro, macro.Macro):
1708 if not isinstance(themacro, macro.Macro):
1709 raise ValueError('A macro must be a string or a Macro instance.')
1709 raise ValueError('A macro must be a string or a Macro instance.')
1710 self.user_ns[name] = themacro
1710 self.user_ns[name] = themacro
1711
1711
1712 #-------------------------------------------------------------------------
1712 #-------------------------------------------------------------------------
1713 # Things related to the running of system commands
1713 # Things related to the running of system commands
1714 #-------------------------------------------------------------------------
1714 #-------------------------------------------------------------------------
1715
1715
1716 def system(self, cmd):
1716 def system(self, cmd):
1717 """Make a system call, using IPython."""
1717 """Make a system call, using IPython."""
1718 return self.hooks.shell_hook(self.var_expand(cmd, depth=2))
1718 return self.hooks.shell_hook(self.var_expand(cmd, depth=2))
1719
1719
1720 #-------------------------------------------------------------------------
1720 #-------------------------------------------------------------------------
1721 # Things related to aliases
1721 # Things related to aliases
1722 #-------------------------------------------------------------------------
1722 #-------------------------------------------------------------------------
1723
1723
1724 def init_alias(self):
1724 def init_alias(self):
1725 self.alias_manager = AliasManager(self, config=self.config)
1725 self.alias_manager = AliasManager(self, config=self.config)
1726 self.ns_table['alias'] = self.alias_manager.alias_table,
1726 self.ns_table['alias'] = self.alias_manager.alias_table,
1727
1727
1728 #-------------------------------------------------------------------------
1728 #-------------------------------------------------------------------------
1729 # Things related to the running of code
1729 # Things related to the running of code
1730 #-------------------------------------------------------------------------
1730 #-------------------------------------------------------------------------
1731
1731
1732 def ex(self, cmd):
1732 def ex(self, cmd):
1733 """Execute a normal python statement in user namespace."""
1733 """Execute a normal python statement in user namespace."""
1734 with nested(self.builtin_trap,):
1734 with nested(self.builtin_trap,):
1735 exec cmd in self.user_global_ns, self.user_ns
1735 exec cmd in self.user_global_ns, self.user_ns
1736
1736
1737 def ev(self, expr):
1737 def ev(self, expr):
1738 """Evaluate python expression expr in user namespace.
1738 """Evaluate python expression expr in user namespace.
1739
1739
1740 Returns the result of evaluation
1740 Returns the result of evaluation
1741 """
1741 """
1742 with nested(self.builtin_trap,):
1742 with nested(self.builtin_trap,):
1743 return eval(expr, self.user_global_ns, self.user_ns)
1743 return eval(expr, self.user_global_ns, self.user_ns)
1744
1744
1745 def mainloop(self, display_banner=None):
1745 def mainloop(self, display_banner=None):
1746 """Start the mainloop.
1746 """Start the mainloop.
1747
1747
1748 If an optional banner argument is given, it will override the
1748 If an optional banner argument is given, it will override the
1749 internally created default banner.
1749 internally created default banner.
1750 """
1750 """
1751
1751
1752 with nested(self.builtin_trap, self.display_trap):
1752 with nested(self.builtin_trap, self.display_trap):
1753
1753
1754 # if you run stuff with -c <cmd>, raw hist is not updated
1754 # if you run stuff with -c <cmd>, raw hist is not updated
1755 # ensure that it's in sync
1755 # ensure that it's in sync
1756 if len(self.input_hist) != len (self.input_hist_raw):
1756 if len(self.input_hist) != len (self.input_hist_raw):
1757 self.input_hist_raw = InputList(self.input_hist)
1757 self.input_hist_raw = InputList(self.input_hist)
1758
1758
1759 while 1:
1759 while 1:
1760 try:
1760 try:
1761 self.interact(display_banner=display_banner)
1761 self.interact(display_banner=display_banner)
1762 #self.interact_with_readline()
1762 #self.interact_with_readline()
1763 # XXX for testing of a readline-decoupled repl loop, call
1763 # XXX for testing of a readline-decoupled repl loop, call
1764 # interact_with_readline above
1764 # interact_with_readline above
1765 break
1765 break
1766 except KeyboardInterrupt:
1766 except KeyboardInterrupt:
1767 # this should not be necessary, but KeyboardInterrupt
1767 # this should not be necessary, but KeyboardInterrupt
1768 # handling seems rather unpredictable...
1768 # handling seems rather unpredictable...
1769 self.write("\nKeyboardInterrupt in interact()\n")
1769 self.write("\nKeyboardInterrupt in interact()\n")
1770
1770
1771 def interact_prompt(self):
1771 def interact_prompt(self):
1772 """ Print the prompt (in read-eval-print loop)
1772 """ Print the prompt (in read-eval-print loop)
1773
1773
1774 Provided for those who want to implement their own read-eval-print loop (e.g. GUIs), not
1774 Provided for those who want to implement their own read-eval-print loop (e.g. GUIs), not
1775 used in standard IPython flow.
1775 used in standard IPython flow.
1776 """
1776 """
1777 if self.more:
1777 if self.more:
1778 try:
1778 try:
1779 prompt = self.hooks.generate_prompt(True)
1779 prompt = self.hooks.generate_prompt(True)
1780 except:
1780 except:
1781 self.showtraceback()
1781 self.showtraceback()
1782 if self.autoindent:
1782 if self.autoindent:
1783 self.rl_do_indent = True
1783 self.rl_do_indent = True
1784
1784
1785 else:
1785 else:
1786 try:
1786 try:
1787 prompt = self.hooks.generate_prompt(False)
1787 prompt = self.hooks.generate_prompt(False)
1788 except:
1788 except:
1789 self.showtraceback()
1789 self.showtraceback()
1790 self.write(prompt)
1790 self.write(prompt)
1791
1791
1792 def interact_handle_input(self,line):
1792 def interact_handle_input(self,line):
1793 """ Handle the input line (in read-eval-print loop)
1793 """ Handle the input line (in read-eval-print loop)
1794
1794
1795 Provided for those who want to implement their own read-eval-print loop (e.g. GUIs), not
1795 Provided for those who want to implement their own read-eval-print loop (e.g. GUIs), not
1796 used in standard IPython flow.
1796 used in standard IPython flow.
1797 """
1797 """
1798 if line.lstrip() == line:
1798 if line.lstrip() == line:
1799 self.shadowhist.add(line.strip())
1799 self.shadowhist.add(line.strip())
1800 lineout = self.prefilter_manager.prefilter_lines(line,self.more)
1800 lineout = self.prefilter_manager.prefilter_lines(line,self.more)
1801
1801
1802 if line.strip():
1802 if line.strip():
1803 if self.more:
1803 if self.more:
1804 self.input_hist_raw[-1] += '%s\n' % line
1804 self.input_hist_raw[-1] += '%s\n' % line
1805 else:
1805 else:
1806 self.input_hist_raw.append('%s\n' % line)
1806 self.input_hist_raw.append('%s\n' % line)
1807
1807
1808
1808
1809 self.more = self.push_line(lineout)
1809 self.more = self.push_line(lineout)
1810 if (self.SyntaxTB.last_syntax_error and
1810 if (self.SyntaxTB.last_syntax_error and
1811 self.autoedit_syntax):
1811 self.autoedit_syntax):
1812 self.edit_syntax_error()
1812 self.edit_syntax_error()
1813
1813
1814 def interact_with_readline(self):
1814 def interact_with_readline(self):
1815 """ Demo of using interact_handle_input, interact_prompt
1815 """ Demo of using interact_handle_input, interact_prompt
1816
1816
1817 This is the main read-eval-print loop. If you need to implement your own (e.g. for GUI),
1817 This is the main read-eval-print loop. If you need to implement your own (e.g. for GUI),
1818 it should work like this.
1818 it should work like this.
1819 """
1819 """
1820 self.readline_startup_hook(self.pre_readline)
1820 self.readline_startup_hook(self.pre_readline)
1821 while not self.exit_now:
1821 while not self.exit_now:
1822 self.interact_prompt()
1822 self.interact_prompt()
1823 if self.more:
1823 if self.more:
1824 self.rl_do_indent = True
1824 self.rl_do_indent = True
1825 else:
1825 else:
1826 self.rl_do_indent = False
1826 self.rl_do_indent = False
1827 line = raw_input_original().decode(self.stdin_encoding)
1827 line = raw_input_original().decode(self.stdin_encoding)
1828 self.interact_handle_input(line)
1828 self.interact_handle_input(line)
1829
1829
1830 def interact(self, display_banner=None):
1830 def interact(self, display_banner=None):
1831 """Closely emulate the interactive Python console."""
1831 """Closely emulate the interactive Python console."""
1832
1832
1833 # batch run -> do not interact
1833 # batch run -> do not interact
1834 if self.exit_now:
1834 if self.exit_now:
1835 return
1835 return
1836
1836
1837 if display_banner is None:
1837 if display_banner is None:
1838 display_banner = self.display_banner
1838 display_banner = self.display_banner
1839 if display_banner:
1839 if display_banner:
1840 self.show_banner()
1840 self.show_banner()
1841
1841
1842 more = 0
1842 more = 0
1843
1843
1844 # Mark activity in the builtins
1844 # Mark activity in the builtins
1845 __builtin__.__dict__['__IPYTHON__active'] += 1
1845 __builtin__.__dict__['__IPYTHON__active'] += 1
1846
1846
1847 if self.has_readline:
1847 if self.has_readline:
1848 self.readline_startup_hook(self.pre_readline)
1848 self.readline_startup_hook(self.pre_readline)
1849 # exit_now is set by a call to %Exit or %Quit, through the
1849 # exit_now is set by a call to %Exit or %Quit, through the
1850 # ask_exit callback.
1850 # ask_exit callback.
1851
1851
1852 while not self.exit_now:
1852 while not self.exit_now:
1853 self.hooks.pre_prompt_hook()
1853 self.hooks.pre_prompt_hook()
1854 if more:
1854 if more:
1855 try:
1855 try:
1856 prompt = self.hooks.generate_prompt(True)
1856 prompt = self.hooks.generate_prompt(True)
1857 except:
1857 except:
1858 self.showtraceback()
1858 self.showtraceback()
1859 if self.autoindent:
1859 if self.autoindent:
1860 self.rl_do_indent = True
1860 self.rl_do_indent = True
1861
1861
1862 else:
1862 else:
1863 try:
1863 try:
1864 prompt = self.hooks.generate_prompt(False)
1864 prompt = self.hooks.generate_prompt(False)
1865 except:
1865 except:
1866 self.showtraceback()
1866 self.showtraceback()
1867 try:
1867 try:
1868 line = self.raw_input(prompt, more)
1868 line = self.raw_input(prompt, more)
1869 if self.exit_now:
1869 if self.exit_now:
1870 # quick exit on sys.std[in|out] close
1870 # quick exit on sys.std[in|out] close
1871 break
1871 break
1872 if self.autoindent:
1872 if self.autoindent:
1873 self.rl_do_indent = False
1873 self.rl_do_indent = False
1874
1874
1875 except KeyboardInterrupt:
1875 except KeyboardInterrupt:
1876 #double-guard against keyboardinterrupts during kbdint handling
1876 #double-guard against keyboardinterrupts during kbdint handling
1877 try:
1877 try:
1878 self.write('\nKeyboardInterrupt\n')
1878 self.write('\nKeyboardInterrupt\n')
1879 self.resetbuffer()
1879 self.resetbuffer()
1880 # keep cache in sync with the prompt counter:
1880 # keep cache in sync with the prompt counter:
1881 self.outputcache.prompt_count -= 1
1881 self.outputcache.prompt_count -= 1
1882
1882
1883 if self.autoindent:
1883 if self.autoindent:
1884 self.indent_current_nsp = 0
1884 self.indent_current_nsp = 0
1885 more = 0
1885 more = 0
1886 except KeyboardInterrupt:
1886 except KeyboardInterrupt:
1887 pass
1887 pass
1888 except EOFError:
1888 except EOFError:
1889 if self.autoindent:
1889 if self.autoindent:
1890 self.rl_do_indent = False
1890 self.rl_do_indent = False
1891 if self.has_readline:
1891 if self.has_readline:
1892 self.readline_startup_hook(None)
1892 self.readline_startup_hook(None)
1893 self.write('\n')
1893 self.write('\n')
1894 self.exit()
1894 self.exit()
1895 except bdb.BdbQuit:
1895 except bdb.BdbQuit:
1896 warn('The Python debugger has exited with a BdbQuit exception.\n'
1896 warn('The Python debugger has exited with a BdbQuit exception.\n'
1897 'Because of how pdb handles the stack, it is impossible\n'
1897 'Because of how pdb handles the stack, it is impossible\n'
1898 'for IPython to properly format this particular exception.\n'
1898 'for IPython to properly format this particular exception.\n'
1899 'IPython will resume normal operation.')
1899 'IPython will resume normal operation.')
1900 except:
1900 except:
1901 # exceptions here are VERY RARE, but they can be triggered
1901 # exceptions here are VERY RARE, but they can be triggered
1902 # asynchronously by signal handlers, for example.
1902 # asynchronously by signal handlers, for example.
1903 self.showtraceback()
1903 self.showtraceback()
1904 else:
1904 else:
1905 more = self.push_line(line)
1905 more = self.push_line(line)
1906 if (self.SyntaxTB.last_syntax_error and
1906 if (self.SyntaxTB.last_syntax_error and
1907 self.autoedit_syntax):
1907 self.autoedit_syntax):
1908 self.edit_syntax_error()
1908 self.edit_syntax_error()
1909
1909
1910 # We are off again...
1910 # We are off again...
1911 __builtin__.__dict__['__IPYTHON__active'] -= 1
1911 __builtin__.__dict__['__IPYTHON__active'] -= 1
1912
1912
1913 # Turn off the exit flag, so the mainloop can be restarted if desired
1913 # Turn off the exit flag, so the mainloop can be restarted if desired
1914 self.exit_now = False
1914 self.exit_now = False
1915
1915
1916 def safe_execfile(self, fname, *where, **kw):
1916 def safe_execfile(self, fname, *where, **kw):
1917 """A safe version of the builtin execfile().
1917 """A safe version of the builtin execfile().
1918
1918
1919 This version will never throw an exception, but instead print
1919 This version will never throw an exception, but instead print
1920 helpful error messages to the screen. This only works on pure
1920 helpful error messages to the screen. This only works on pure
1921 Python files with the .py extension.
1921 Python files with the .py extension.
1922
1922
1923 Parameters
1923 Parameters
1924 ----------
1924 ----------
1925 fname : string
1925 fname : string
1926 The name of the file to be executed.
1926 The name of the file to be executed.
1927 where : tuple
1927 where : tuple
1928 One or two namespaces, passed to execfile() as (globals,locals).
1928 One or two namespaces, passed to execfile() as (globals,locals).
1929 If only one is given, it is passed as both.
1929 If only one is given, it is passed as both.
1930 exit_ignore : bool (False)
1930 exit_ignore : bool (False)
1931 If True, then silence SystemExit for non-zero status (it is always
1931 If True, then silence SystemExit for non-zero status (it is always
1932 silenced for zero status, as it is so common).
1932 silenced for zero status, as it is so common).
1933 """
1933 """
1934 kw.setdefault('exit_ignore', False)
1934 kw.setdefault('exit_ignore', False)
1935
1935
1936 fname = os.path.abspath(os.path.expanduser(fname))
1936 fname = os.path.abspath(os.path.expanduser(fname))
1937
1937
1938 # Make sure we have a .py file
1938 # Make sure we have a .py file
1939 if not fname.endswith('.py'):
1939 if not fname.endswith('.py'):
1940 warn('File must end with .py to be run using execfile: <%s>' % fname)
1940 warn('File must end with .py to be run using execfile: <%s>' % fname)
1941
1941
1942 # Make sure we can open the file
1942 # Make sure we can open the file
1943 try:
1943 try:
1944 with open(fname) as thefile:
1944 with open(fname) as thefile:
1945 pass
1945 pass
1946 except:
1946 except:
1947 warn('Could not open file <%s> for safe execution.' % fname)
1947 warn('Could not open file <%s> for safe execution.' % fname)
1948 return
1948 return
1949
1949
1950 # Find things also in current directory. This is needed to mimic the
1950 # Find things also in current directory. This is needed to mimic the
1951 # behavior of running a script from the system command line, where
1951 # behavior of running a script from the system command line, where
1952 # Python inserts the script's directory into sys.path
1952 # Python inserts the script's directory into sys.path
1953 dname = os.path.dirname(fname)
1953 dname = os.path.dirname(fname)
1954
1954
1955 with prepended_to_syspath(dname):
1955 with prepended_to_syspath(dname):
1956 try:
1956 try:
1957 execfile(fname,*where)
1957 execfile(fname,*where)
1958 except SystemExit, status:
1958 except SystemExit, status:
1959 # If the call was made with 0 or None exit status (sys.exit(0)
1959 # If the call was made with 0 or None exit status (sys.exit(0)
1960 # or sys.exit() ), don't bother showing a traceback, as both of
1960 # or sys.exit() ), don't bother showing a traceback, as both of
1961 # these are considered normal by the OS:
1961 # these are considered normal by the OS:
1962 # > python -c'import sys;sys.exit(0)'; echo $?
1962 # > python -c'import sys;sys.exit(0)'; echo $?
1963 # 0
1963 # 0
1964 # > python -c'import sys;sys.exit()'; echo $?
1964 # > python -c'import sys;sys.exit()'; echo $?
1965 # 0
1965 # 0
1966 # For other exit status, we show the exception unless
1966 # For other exit status, we show the exception unless
1967 # explicitly silenced, but only in short form.
1967 # explicitly silenced, but only in short form.
1968 if status.code not in (0, None) and not kw['exit_ignore']:
1968 if status.code not in (0, None) and not kw['exit_ignore']:
1969 self.showtraceback(exception_only=True)
1969 self.showtraceback(exception_only=True)
1970 except:
1970 except:
1971 self.showtraceback()
1971 self.showtraceback()
1972
1972
1973 def safe_execfile_ipy(self, fname):
1973 def safe_execfile_ipy(self, fname):
1974 """Like safe_execfile, but for .ipy files with IPython syntax.
1974 """Like safe_execfile, but for .ipy files with IPython syntax.
1975
1975
1976 Parameters
1976 Parameters
1977 ----------
1977 ----------
1978 fname : str
1978 fname : str
1979 The name of the file to execute. The filename must have a
1979 The name of the file to execute. The filename must have a
1980 .ipy extension.
1980 .ipy extension.
1981 """
1981 """
1982 fname = os.path.abspath(os.path.expanduser(fname))
1982 fname = os.path.abspath(os.path.expanduser(fname))
1983
1983
1984 # Make sure we have a .py file
1984 # Make sure we have a .py file
1985 if not fname.endswith('.ipy'):
1985 if not fname.endswith('.ipy'):
1986 warn('File must end with .py to be run using execfile: <%s>' % fname)
1986 warn('File must end with .py to be run using execfile: <%s>' % fname)
1987
1987
1988 # Make sure we can open the file
1988 # Make sure we can open the file
1989 try:
1989 try:
1990 with open(fname) as thefile:
1990 with open(fname) as thefile:
1991 pass
1991 pass
1992 except:
1992 except:
1993 warn('Could not open file <%s> for safe execution.' % fname)
1993 warn('Could not open file <%s> for safe execution.' % fname)
1994 return
1994 return
1995
1995
1996 # Find things also in current directory. This is needed to mimic the
1996 # Find things also in current directory. This is needed to mimic the
1997 # behavior of running a script from the system command line, where
1997 # behavior of running a script from the system command line, where
1998 # Python inserts the script's directory into sys.path
1998 # Python inserts the script's directory into sys.path
1999 dname = os.path.dirname(fname)
1999 dname = os.path.dirname(fname)
2000
2000
2001 with prepended_to_syspath(dname):
2001 with prepended_to_syspath(dname):
2002 try:
2002 try:
2003 with open(fname) as thefile:
2003 with open(fname) as thefile:
2004 script = thefile.read()
2004 script = thefile.read()
2005 # self.runlines currently captures all exceptions
2005 # self.runlines currently captures all exceptions
2006 # raise in user code. It would be nice if there were
2006 # raise in user code. It would be nice if there were
2007 # versions of runlines, execfile that did raise, so
2007 # versions of runlines, execfile that did raise, so
2008 # we could catch the errors.
2008 # we could catch the errors.
2009 self.runlines(script, clean=True)
2009 self.runlines(script, clean=True)
2010 except:
2010 except:
2011 self.showtraceback()
2011 self.showtraceback()
2012 warn('Unknown failure executing file: <%s>' % fname)
2012 warn('Unknown failure executing file: <%s>' % fname)
2013
2013
2014 def _is_secondary_block_start(self, s):
2014 def _is_secondary_block_start(self, s):
2015 if not s.endswith(':'):
2015 if not s.endswith(':'):
2016 return False
2016 return False
2017 if (s.startswith('elif') or
2017 if (s.startswith('elif') or
2018 s.startswith('else') or
2018 s.startswith('else') or
2019 s.startswith('except') or
2019 s.startswith('except') or
2020 s.startswith('finally')):
2020 s.startswith('finally')):
2021 return True
2021 return True
2022
2022
2023 def cleanup_ipy_script(self, script):
2023 def cleanup_ipy_script(self, script):
2024 """Make a script safe for self.runlines()
2024 """Make a script safe for self.runlines()
2025
2025
2026 Currently, IPython is lines based, with blocks being detected by
2026 Currently, IPython is lines based, with blocks being detected by
2027 empty lines. This is a problem for block based scripts that may
2027 empty lines. This is a problem for block based scripts that may
2028 not have empty lines after blocks. This script adds those empty
2028 not have empty lines after blocks. This script adds those empty
2029 lines to make scripts safe for running in the current line based
2029 lines to make scripts safe for running in the current line based
2030 IPython.
2030 IPython.
2031 """
2031 """
2032 res = []
2032 res = []
2033 lines = script.splitlines()
2033 lines = script.splitlines()
2034 level = 0
2034 level = 0
2035
2035
2036 for l in lines:
2036 for l in lines:
2037 lstripped = l.lstrip()
2037 lstripped = l.lstrip()
2038 stripped = l.strip()
2038 stripped = l.strip()
2039 if not stripped:
2039 if not stripped:
2040 continue
2040 continue
2041 newlevel = len(l) - len(lstripped)
2041 newlevel = len(l) - len(lstripped)
2042 if level > 0 and newlevel == 0 and \
2042 if level > 0 and newlevel == 0 and \
2043 not self._is_secondary_block_start(stripped):
2043 not self._is_secondary_block_start(stripped):
2044 # add empty line
2044 # add empty line
2045 res.append('')
2045 res.append('')
2046 res.append(l)
2046 res.append(l)
2047 level = newlevel
2047 level = newlevel
2048
2048
2049 return '\n'.join(res) + '\n'
2049 return '\n'.join(res) + '\n'
2050
2050
2051 def runlines(self, lines, clean=False):
2051 def runlines(self, lines, clean=False):
2052 """Run a string of one or more lines of source.
2052 """Run a string of one or more lines of source.
2053
2053
2054 This method is capable of running a string containing multiple source
2054 This method is capable of running a string containing multiple source
2055 lines, as if they had been entered at the IPython prompt. Since it
2055 lines, as if they had been entered at the IPython prompt. Since it
2056 exposes IPython's processing machinery, the given strings can contain
2056 exposes IPython's processing machinery, the given strings can contain
2057 magic calls (%magic), special shell access (!cmd), etc.
2057 magic calls (%magic), special shell access (!cmd), etc.
2058 """
2058 """
2059
2059
2060 if isinstance(lines, (list, tuple)):
2060 if isinstance(lines, (list, tuple)):
2061 lines = '\n'.join(lines)
2061 lines = '\n'.join(lines)
2062
2062
2063 if clean:
2063 if clean:
2064 lines = self.cleanup_ipy_script(lines)
2064 lines = self.cleanup_ipy_script(lines)
2065
2065
2066 # We must start with a clean buffer, in case this is run from an
2066 # We must start with a clean buffer, in case this is run from an
2067 # interactive IPython session (via a magic, for example).
2067 # interactive IPython session (via a magic, for example).
2068 self.resetbuffer()
2068 self.resetbuffer()
2069 lines = lines.splitlines()
2069 lines = lines.splitlines()
2070 more = 0
2070 more = 0
2071
2071
2072 with nested(self.builtin_trap, self.display_trap):
2072 with nested(self.builtin_trap, self.display_trap):
2073 for line in lines:
2073 for line in lines:
2074 # skip blank lines so we don't mess up the prompt counter, but do
2074 # skip blank lines so we don't mess up the prompt counter, but do
2075 # NOT skip even a blank line if we are in a code block (more is
2075 # NOT skip even a blank line if we are in a code block (more is
2076 # true)
2076 # true)
2077
2077
2078 if line or more:
2078 if line or more:
2079 # push to raw history, so hist line numbers stay in sync
2079 # push to raw history, so hist line numbers stay in sync
2080 self.input_hist_raw.append("# " + line + "\n")
2080 self.input_hist_raw.append("# " + line + "\n")
2081 prefiltered = self.prefilter_manager.prefilter_lines(line,more)
2081 prefiltered = self.prefilter_manager.prefilter_lines(line,more)
2082 more = self.push_line(prefiltered)
2082 more = self.push_line(prefiltered)
2083 # IPython's runsource returns None if there was an error
2083 # IPython's runsource returns None if there was an error
2084 # compiling the code. This allows us to stop processing right
2084 # compiling the code. This allows us to stop processing right
2085 # away, so the user gets the error message at the right place.
2085 # away, so the user gets the error message at the right place.
2086 if more is None:
2086 if more is None:
2087 break
2087 break
2088 else:
2088 else:
2089 self.input_hist_raw.append("\n")
2089 self.input_hist_raw.append("\n")
2090 # final newline in case the input didn't have it, so that the code
2090 # final newline in case the input didn't have it, so that the code
2091 # actually does get executed
2091 # actually does get executed
2092 if more:
2092 if more:
2093 self.push_line('\n')
2093 self.push_line('\n')
2094
2094
2095 def runsource(self, source, filename='<input>', symbol='single'):
2095 def runsource(self, source, filename='<input>', symbol='single'):
2096 """Compile and run some source in the interpreter.
2096 """Compile and run some source in the interpreter.
2097
2097
2098 Arguments are as for compile_command().
2098 Arguments are as for compile_command().
2099
2099
2100 One several things can happen:
2100 One several things can happen:
2101
2101
2102 1) The input is incorrect; compile_command() raised an
2102 1) The input is incorrect; compile_command() raised an
2103 exception (SyntaxError or OverflowError). A syntax traceback
2103 exception (SyntaxError or OverflowError). A syntax traceback
2104 will be printed by calling the showsyntaxerror() method.
2104 will be printed by calling the showsyntaxerror() method.
2105
2105
2106 2) The input is incomplete, and more input is required;
2106 2) The input is incomplete, and more input is required;
2107 compile_command() returned None. Nothing happens.
2107 compile_command() returned None. Nothing happens.
2108
2108
2109 3) The input is complete; compile_command() returned a code
2109 3) The input is complete; compile_command() returned a code
2110 object. The code is executed by calling self.runcode() (which
2110 object. The code is executed by calling self.runcode() (which
2111 also handles run-time exceptions, except for SystemExit).
2111 also handles run-time exceptions, except for SystemExit).
2112
2112
2113 The return value is:
2113 The return value is:
2114
2114
2115 - True in case 2
2115 - True in case 2
2116
2116
2117 - False in the other cases, unless an exception is raised, where
2117 - False in the other cases, unless an exception is raised, where
2118 None is returned instead. This can be used by external callers to
2118 None is returned instead. This can be used by external callers to
2119 know whether to continue feeding input or not.
2119 know whether to continue feeding input or not.
2120
2120
2121 The return value can be used to decide whether to use sys.ps1 or
2121 The return value can be used to decide whether to use sys.ps1 or
2122 sys.ps2 to prompt the next line."""
2122 sys.ps2 to prompt the next line."""
2123
2123
2124 # if the source code has leading blanks, add 'if 1:\n' to it
2124 # if the source code has leading blanks, add 'if 1:\n' to it
2125 # this allows execution of indented pasted code. It is tempting
2125 # this allows execution of indented pasted code. It is tempting
2126 # to add '\n' at the end of source to run commands like ' a=1'
2126 # to add '\n' at the end of source to run commands like ' a=1'
2127 # directly, but this fails for more complicated scenarios
2127 # directly, but this fails for more complicated scenarios
2128 source=source.encode(self.stdin_encoding)
2128 source=source.encode(self.stdin_encoding)
2129 if source[:1] in [' ', '\t']:
2129 if source[:1] in [' ', '\t']:
2130 source = 'if 1:\n%s' % source
2130 source = 'if 1:\n%s' % source
2131
2131
2132 try:
2132 try:
2133 code = self.compile(source,filename,symbol)
2133 code = self.compile(source,filename,symbol)
2134 except (OverflowError, SyntaxError, ValueError, TypeError, MemoryError):
2134 except (OverflowError, SyntaxError, ValueError, TypeError, MemoryError):
2135 # Case 1
2135 # Case 1
2136 self.showsyntaxerror(filename)
2136 self.showsyntaxerror(filename)
2137 return None
2137 return None
2138
2138
2139 if code is None:
2139 if code is None:
2140 # Case 2
2140 # Case 2
2141 return True
2141 return True
2142
2142
2143 # Case 3
2143 # Case 3
2144 # We store the code object so that threaded shells and
2144 # We store the code object so that threaded shells and
2145 # custom exception handlers can access all this info if needed.
2145 # custom exception handlers can access all this info if needed.
2146 # The source corresponding to this can be obtained from the
2146 # The source corresponding to this can be obtained from the
2147 # buffer attribute as '\n'.join(self.buffer).
2147 # buffer attribute as '\n'.join(self.buffer).
2148 self.code_to_run = code
2148 self.code_to_run = code
2149 # now actually execute the code object
2149 # now actually execute the code object
2150 if self.runcode(code) == 0:
2150 if self.runcode(code) == 0:
2151 return False
2151 return False
2152 else:
2152 else:
2153 return None
2153 return None
2154
2154
2155 def runcode(self,code_obj):
2155 def runcode(self,code_obj):
2156 """Execute a code object.
2156 """Execute a code object.
2157
2157
2158 When an exception occurs, self.showtraceback() is called to display a
2158 When an exception occurs, self.showtraceback() is called to display a
2159 traceback.
2159 traceback.
2160
2160
2161 Return value: a flag indicating whether the code to be run completed
2161 Return value: a flag indicating whether the code to be run completed
2162 successfully:
2162 successfully:
2163
2163
2164 - 0: successful execution.
2164 - 0: successful execution.
2165 - 1: an error occurred.
2165 - 1: an error occurred.
2166 """
2166 """
2167
2167
2168 # Set our own excepthook in case the user code tries to call it
2168 # Set our own excepthook in case the user code tries to call it
2169 # directly, so that the IPython crash handler doesn't get triggered
2169 # directly, so that the IPython crash handler doesn't get triggered
2170 old_excepthook,sys.excepthook = sys.excepthook, self.excepthook
2170 old_excepthook,sys.excepthook = sys.excepthook, self.excepthook
2171
2171
2172 # we save the original sys.excepthook in the instance, in case config
2172 # we save the original sys.excepthook in the instance, in case config
2173 # code (such as magics) needs access to it.
2173 # code (such as magics) needs access to it.
2174 self.sys_excepthook = old_excepthook
2174 self.sys_excepthook = old_excepthook
2175 outflag = 1 # happens in more places, so it's easier as default
2175 outflag = 1 # happens in more places, so it's easier as default
2176 try:
2176 try:
2177 try:
2177 try:
2178 self.hooks.pre_runcode_hook()
2178 self.hooks.pre_runcode_hook()
2179 exec code_obj in self.user_global_ns, self.user_ns
2179 exec code_obj in self.user_global_ns, self.user_ns
2180 finally:
2180 finally:
2181 # Reset our crash handler in place
2181 # Reset our crash handler in place
2182 sys.excepthook = old_excepthook
2182 sys.excepthook = old_excepthook
2183 except SystemExit:
2183 except SystemExit:
2184 self.resetbuffer()
2184 self.resetbuffer()
2185 self.showtraceback(exception_only=True)
2185 self.showtraceback(exception_only=True)
2186 warn("To exit: use any of 'exit', 'quit', %Exit or Ctrl-D.", level=1)
2186 warn("To exit: use any of 'exit', 'quit', %Exit or Ctrl-D.", level=1)
2187 except self.custom_exceptions:
2187 except self.custom_exceptions:
2188 etype,value,tb = sys.exc_info()
2188 etype,value,tb = sys.exc_info()
2189 self.CustomTB(etype,value,tb)
2189 self.CustomTB(etype,value,tb)
2190 except:
2190 except:
2191 self.showtraceback()
2191 self.showtraceback()
2192 else:
2192 else:
2193 outflag = 0
2193 outflag = 0
2194 if softspace(sys.stdout, 0):
2194 if softspace(sys.stdout, 0):
2195 print
2195 print
2196 # Flush out code object which has been run (and source)
2196 # Flush out code object which has been run (and source)
2197 self.code_to_run = None
2197 self.code_to_run = None
2198 return outflag
2198 return outflag
2199
2199
2200 def push_line(self, line):
2200 def push_line(self, line):
2201 """Push a line to the interpreter.
2201 """Push a line to the interpreter.
2202
2202
2203 The line should not have a trailing newline; it may have
2203 The line should not have a trailing newline; it may have
2204 internal newlines. The line is appended to a buffer and the
2204 internal newlines. The line is appended to a buffer and the
2205 interpreter's runsource() method is called with the
2205 interpreter's runsource() method is called with the
2206 concatenated contents of the buffer as source. If this
2206 concatenated contents of the buffer as source. If this
2207 indicates that the command was executed or invalid, the buffer
2207 indicates that the command was executed or invalid, the buffer
2208 is reset; otherwise, the command is incomplete, and the buffer
2208 is reset; otherwise, the command is incomplete, and the buffer
2209 is left as it was after the line was appended. The return
2209 is left as it was after the line was appended. The return
2210 value is 1 if more input is required, 0 if the line was dealt
2210 value is 1 if more input is required, 0 if the line was dealt
2211 with in some way (this is the same as runsource()).
2211 with in some way (this is the same as runsource()).
2212 """
2212 """
2213
2213
2214 # autoindent management should be done here, and not in the
2214 # autoindent management should be done here, and not in the
2215 # interactive loop, since that one is only seen by keyboard input. We
2215 # interactive loop, since that one is only seen by keyboard input. We
2216 # need this done correctly even for code run via runlines (which uses
2216 # need this done correctly even for code run via runlines (which uses
2217 # push).
2217 # push).
2218
2218
2219 #print 'push line: <%s>' % line # dbg
2219 #print 'push line: <%s>' % line # dbg
2220 for subline in line.splitlines():
2220 for subline in line.splitlines():
2221 self._autoindent_update(subline)
2221 self._autoindent_update(subline)
2222 self.buffer.append(line)
2222 self.buffer.append(line)
2223 more = self.runsource('\n'.join(self.buffer), self.filename)
2223 more = self.runsource('\n'.join(self.buffer), self.filename)
2224 if not more:
2224 if not more:
2225 self.resetbuffer()
2225 self.resetbuffer()
2226 return more
2226 return more
2227
2227
2228 def _autoindent_update(self,line):
2228 def _autoindent_update(self,line):
2229 """Keep track of the indent level."""
2229 """Keep track of the indent level."""
2230
2230
2231 #debugx('line')
2231 #debugx('line')
2232 #debugx('self.indent_current_nsp')
2232 #debugx('self.indent_current_nsp')
2233 if self.autoindent:
2233 if self.autoindent:
2234 if line:
2234 if line:
2235 inisp = num_ini_spaces(line)
2235 inisp = num_ini_spaces(line)
2236 if inisp < self.indent_current_nsp:
2236 if inisp < self.indent_current_nsp:
2237 self.indent_current_nsp = inisp
2237 self.indent_current_nsp = inisp
2238
2238
2239 if line[-1] == ':':
2239 if line[-1] == ':':
2240 self.indent_current_nsp += 4
2240 self.indent_current_nsp += 4
2241 elif dedent_re.match(line):
2241 elif dedent_re.match(line):
2242 self.indent_current_nsp -= 4
2242 self.indent_current_nsp -= 4
2243 else:
2243 else:
2244 self.indent_current_nsp = 0
2244 self.indent_current_nsp = 0
2245
2245
2246 def resetbuffer(self):
2246 def resetbuffer(self):
2247 """Reset the input buffer."""
2247 """Reset the input buffer."""
2248 self.buffer[:] = []
2248 self.buffer[:] = []
2249
2249
2250 def raw_input(self,prompt='',continue_prompt=False):
2250 def raw_input(self,prompt='',continue_prompt=False):
2251 """Write a prompt and read a line.
2251 """Write a prompt and read a line.
2252
2252
2253 The returned line does not include the trailing newline.
2253 The returned line does not include the trailing newline.
2254 When the user enters the EOF key sequence, EOFError is raised.
2254 When the user enters the EOF key sequence, EOFError is raised.
2255
2255
2256 Optional inputs:
2256 Optional inputs:
2257
2257
2258 - prompt(''): a string to be printed to prompt the user.
2258 - prompt(''): a string to be printed to prompt the user.
2259
2259
2260 - continue_prompt(False): whether this line is the first one or a
2260 - continue_prompt(False): whether this line is the first one or a
2261 continuation in a sequence of inputs.
2261 continuation in a sequence of inputs.
2262 """
2262 """
2263 # growl.notify("raw_input: ", "prompt = %r\ncontinue_prompt = %s" % (prompt, continue_prompt))
2263 # growl.notify("raw_input: ", "prompt = %r\ncontinue_prompt = %s" % (prompt, continue_prompt))
2264
2264
2265 # Code run by the user may have modified the readline completer state.
2265 # Code run by the user may have modified the readline completer state.
2266 # We must ensure that our completer is back in place.
2266 # We must ensure that our completer is back in place.
2267
2267
2268 if self.has_readline:
2268 if self.has_readline:
2269 self.set_completer()
2269 self.set_completer()
2270
2270
2271 try:
2271 try:
2272 line = raw_input_original(prompt).decode(self.stdin_encoding)
2272 line = raw_input_original(prompt).decode(self.stdin_encoding)
2273 except ValueError:
2273 except ValueError:
2274 warn("\n********\nYou or a %run:ed script called sys.stdin.close()"
2274 warn("\n********\nYou or a %run:ed script called sys.stdin.close()"
2275 " or sys.stdout.close()!\nExiting IPython!")
2275 " or sys.stdout.close()!\nExiting IPython!")
2276 self.ask_exit()
2276 self.ask_exit()
2277 return ""
2277 return ""
2278
2278
2279 # Try to be reasonably smart about not re-indenting pasted input more
2279 # Try to be reasonably smart about not re-indenting pasted input more
2280 # than necessary. We do this by trimming out the auto-indent initial
2280 # than necessary. We do this by trimming out the auto-indent initial
2281 # spaces, if the user's actual input started itself with whitespace.
2281 # spaces, if the user's actual input started itself with whitespace.
2282 #debugx('self.buffer[-1]')
2282 #debugx('self.buffer[-1]')
2283
2283
2284 if self.autoindent:
2284 if self.autoindent:
2285 if num_ini_spaces(line) > self.indent_current_nsp:
2285 if num_ini_spaces(line) > self.indent_current_nsp:
2286 line = line[self.indent_current_nsp:]
2286 line = line[self.indent_current_nsp:]
2287 self.indent_current_nsp = 0
2287 self.indent_current_nsp = 0
2288
2288
2289 # store the unfiltered input before the user has any chance to modify
2289 # store the unfiltered input before the user has any chance to modify
2290 # it.
2290 # it.
2291 if line.strip():
2291 if line.strip():
2292 if continue_prompt:
2292 if continue_prompt:
2293 self.input_hist_raw[-1] += '%s\n' % line
2293 self.input_hist_raw[-1] += '%s\n' % line
2294 if self.has_readline and self.readline_use:
2294 if self.has_readline and self.readline_use:
2295 try:
2295 try:
2296 histlen = self.readline.get_current_history_length()
2296 histlen = self.readline.get_current_history_length()
2297 if histlen > 1:
2297 if histlen > 1:
2298 newhist = self.input_hist_raw[-1].rstrip()
2298 newhist = self.input_hist_raw[-1].rstrip()
2299 self.readline.remove_history_item(histlen-1)
2299 self.readline.remove_history_item(histlen-1)
2300 self.readline.replace_history_item(histlen-2,
2300 self.readline.replace_history_item(histlen-2,
2301 newhist.encode(self.stdin_encoding))
2301 newhist.encode(self.stdin_encoding))
2302 except AttributeError:
2302 except AttributeError:
2303 pass # re{move,place}_history_item are new in 2.4.
2303 pass # re{move,place}_history_item are new in 2.4.
2304 else:
2304 else:
2305 self.input_hist_raw.append('%s\n' % line)
2305 self.input_hist_raw.append('%s\n' % line)
2306 # only entries starting at first column go to shadow history
2306 # only entries starting at first column go to shadow history
2307 if line.lstrip() == line:
2307 if line.lstrip() == line:
2308 self.shadowhist.add(line.strip())
2308 self.shadowhist.add(line.strip())
2309 elif not continue_prompt:
2309 elif not continue_prompt:
2310 self.input_hist_raw.append('\n')
2310 self.input_hist_raw.append('\n')
2311 try:
2311 try:
2312 lineout = self.prefilter_manager.prefilter_lines(line,continue_prompt)
2312 lineout = self.prefilter_manager.prefilter_lines(line,continue_prompt)
2313 except:
2313 except:
2314 # blanket except, in case a user-defined prefilter crashes, so it
2314 # blanket except, in case a user-defined prefilter crashes, so it
2315 # can't take all of ipython with it.
2315 # can't take all of ipython with it.
2316 self.showtraceback()
2316 self.showtraceback()
2317 return ''
2317 return ''
2318 else:
2318 else:
2319 return lineout
2319 return lineout
2320
2320
2321 #-------------------------------------------------------------------------
2321 #-------------------------------------------------------------------------
2322 # Working with components
2322 # Working with components
2323 #-------------------------------------------------------------------------
2323 #-------------------------------------------------------------------------
2324
2324
2325 def get_component(self, name=None, klass=None):
2325 def get_component(self, name=None, klass=None):
2326 """Fetch a component by name and klass in my tree."""
2326 """Fetch a component by name and klass in my tree."""
2327 c = Component.get_instances(root=self, name=name, klass=klass)
2327 c = Component.get_instances(root=self, name=name, klass=klass)
2328 if len(c) == 0:
2328 if len(c) == 0:
2329 return None
2329 return None
2330 if len(c) == 1:
2330 if len(c) == 1:
2331 return c[0]
2331 return c[0]
2332 else:
2332 else:
2333 return c
2333 return c
2334
2334
2335 #-------------------------------------------------------------------------
2335 #-------------------------------------------------------------------------
2336 # IPython extensions
2336 # IPython extensions
2337 #-------------------------------------------------------------------------
2337 #-------------------------------------------------------------------------
2338
2338
2339 def load_extension(self, module_str):
2339 def load_extension(self, module_str):
2340 """Load an IPython extension by its module name.
2340 """Load an IPython extension by its module name.
2341
2341
2342 An IPython extension is an importable Python module that has
2342 An IPython extension is an importable Python module that has
2343 a function with the signature::
2343 a function with the signature::
2344
2344
2345 def load_ipython_extension(ipython):
2345 def load_ipython_extension(ipython):
2346 # Do things with ipython
2346 # Do things with ipython
2347
2347
2348 This function is called after your extension is imported and the
2348 This function is called after your extension is imported and the
2349 currently active :class:`InteractiveShell` instance is passed as
2349 currently active :class:`InteractiveShell` instance is passed as
2350 the only argument. You can do anything you want with IPython at
2350 the only argument. You can do anything you want with IPython at
2351 that point, including defining new magic and aliases, adding new
2351 that point, including defining new magic and aliases, adding new
2352 components, etc.
2352 components, etc.
2353
2353
2354 The :func:`load_ipython_extension` will be called again is you
2354 The :func:`load_ipython_extension` will be called again is you
2355 load or reload the extension again. It is up to the extension
2355 load or reload the extension again. It is up to the extension
2356 author to add code to manage that.
2356 author to add code to manage that.
2357
2357
2358 You can put your extension modules anywhere you want, as long as
2358 You can put your extension modules anywhere you want, as long as
2359 they can be imported by Python's standard import mechanism. However,
2359 they can be imported by Python's standard import mechanism. However,
2360 to make it easy to write extensions, you can also put your extensions
2360 to make it easy to write extensions, you can also put your extensions
2361 in ``os.path.join(self.ipython_dir, 'extensions')``. This directory
2361 in ``os.path.join(self.ipython_dir, 'extensions')``. This directory
2362 is added to ``sys.path`` automatically.
2362 is added to ``sys.path`` automatically.
2363 """
2363 """
2364 from IPython.utils.syspathcontext import prepended_to_syspath
2364 from IPython.utils.syspathcontext import prepended_to_syspath
2365
2365
2366 if module_str not in sys.modules:
2366 if module_str not in sys.modules:
2367 with prepended_to_syspath(self.ipython_extension_dir):
2367 with prepended_to_syspath(self.ipython_extension_dir):
2368 __import__(module_str)
2368 __import__(module_str)
2369 mod = sys.modules[module_str]
2369 mod = sys.modules[module_str]
2370 return self._call_load_ipython_extension(mod)
2370 return self._call_load_ipython_extension(mod)
2371
2371
2372 def unload_extension(self, module_str):
2372 def unload_extension(self, module_str):
2373 """Unload an IPython extension by its module name.
2373 """Unload an IPython extension by its module name.
2374
2374
2375 This function looks up the extension's name in ``sys.modules`` and
2375 This function looks up the extension's name in ``sys.modules`` and
2376 simply calls ``mod.unload_ipython_extension(self)``.
2376 simply calls ``mod.unload_ipython_extension(self)``.
2377 """
2377 """
2378 if module_str in sys.modules:
2378 if module_str in sys.modules:
2379 mod = sys.modules[module_str]
2379 mod = sys.modules[module_str]
2380 self._call_unload_ipython_extension(mod)
2380 self._call_unload_ipython_extension(mod)
2381
2381
2382 def reload_extension(self, module_str):
2382 def reload_extension(self, module_str):
2383 """Reload an IPython extension by calling reload.
2383 """Reload an IPython extension by calling reload.
2384
2384
2385 If the module has not been loaded before,
2385 If the module has not been loaded before,
2386 :meth:`InteractiveShell.load_extension` is called. Otherwise
2386 :meth:`InteractiveShell.load_extension` is called. Otherwise
2387 :func:`reload` is called and then the :func:`load_ipython_extension`
2387 :func:`reload` is called and then the :func:`load_ipython_extension`
2388 function of the module, if it exists is called.
2388 function of the module, if it exists is called.
2389 """
2389 """
2390 from IPython.utils.syspathcontext import prepended_to_syspath
2390 from IPython.utils.syspathcontext import prepended_to_syspath
2391
2391
2392 with prepended_to_syspath(self.ipython_extension_dir):
2392 with prepended_to_syspath(self.ipython_extension_dir):
2393 if module_str in sys.modules:
2393 if module_str in sys.modules:
2394 mod = sys.modules[module_str]
2394 mod = sys.modules[module_str]
2395 reload(mod)
2395 reload(mod)
2396 self._call_load_ipython_extension(mod)
2396 self._call_load_ipython_extension(mod)
2397 else:
2397 else:
2398 self.load_extension(module_str)
2398 self.load_extension(module_str)
2399
2399
2400 def _call_load_ipython_extension(self, mod):
2400 def _call_load_ipython_extension(self, mod):
2401 if hasattr(mod, 'load_ipython_extension'):
2401 if hasattr(mod, 'load_ipython_extension'):
2402 return mod.load_ipython_extension(self)
2402 return mod.load_ipython_extension(self)
2403
2403
2404 def _call_unload_ipython_extension(self, mod):
2404 def _call_unload_ipython_extension(self, mod):
2405 if hasattr(mod, 'unload_ipython_extension'):
2405 if hasattr(mod, 'unload_ipython_extension'):
2406 return mod.unload_ipython_extension(self)
2406 return mod.unload_ipython_extension(self)
2407
2407
2408 #-------------------------------------------------------------------------
2408 #-------------------------------------------------------------------------
2409 # Things related to the prefilter
2409 # Things related to the prefilter
2410 #-------------------------------------------------------------------------
2410 #-------------------------------------------------------------------------
2411
2411
2412 def init_prefilter(self):
2412 def init_prefilter(self):
2413 self.prefilter_manager = PrefilterManager(self, config=self.config)
2413 self.prefilter_manager = PrefilterManager(self, config=self.config)
2414 # Ultimately this will be refactored in the new interpreter code, but
2414 # Ultimately this will be refactored in the new interpreter code, but
2415 # for now, we should expose the main prefilter method (there's legacy
2415 # for now, we should expose the main prefilter method (there's legacy
2416 # code out there that may rely on this).
2416 # code out there that may rely on this).
2417 self.prefilter = self.prefilter_manager.prefilter_lines
2417 self.prefilter = self.prefilter_manager.prefilter_lines
2418
2418
2419 #-------------------------------------------------------------------------
2419 #-------------------------------------------------------------------------
2420 # Utilities
2420 # Utilities
2421 #-------------------------------------------------------------------------
2421 #-------------------------------------------------------------------------
2422
2422
2423 def getoutput(self, cmd):
2423 def getoutput(self, cmd):
2424 return getoutput(self.var_expand(cmd,depth=2),
2424 return getoutput(self.var_expand(cmd,depth=2),
2425 header=self.system_header,
2425 header=self.system_header,
2426 verbose=self.system_verbose)
2426 verbose=self.system_verbose)
2427
2427
2428 def getoutputerror(self, cmd):
2428 def getoutputerror(self, cmd):
2429 return getoutputerror(self.var_expand(cmd,depth=2),
2429 return getoutputerror(self.var_expand(cmd,depth=2),
2430 header=self.system_header,
2430 header=self.system_header,
2431 verbose=self.system_verbose)
2431 verbose=self.system_verbose)
2432
2432
2433 def var_expand(self,cmd,depth=0):
2433 def var_expand(self,cmd,depth=0):
2434 """Expand python variables in a string.
2434 """Expand python variables in a string.
2435
2435
2436 The depth argument indicates how many frames above the caller should
2436 The depth argument indicates how many frames above the caller should
2437 be walked to look for the local namespace where to expand variables.
2437 be walked to look for the local namespace where to expand variables.
2438
2438
2439 The global namespace for expansion is always the user's interactive
2439 The global namespace for expansion is always the user's interactive
2440 namespace.
2440 namespace.
2441 """
2441 """
2442
2442
2443 return str(ItplNS(cmd,
2443 return str(ItplNS(cmd,
2444 self.user_ns, # globals
2444 self.user_ns, # globals
2445 # Skip our own frame in searching for locals:
2445 # Skip our own frame in searching for locals:
2446 sys._getframe(depth+1).f_locals # locals
2446 sys._getframe(depth+1).f_locals # locals
2447 ))
2447 ))
2448
2448
2449 def mktempfile(self,data=None):
2449 def mktempfile(self,data=None):
2450 """Make a new tempfile and return its filename.
2450 """Make a new tempfile and return its filename.
2451
2451
2452 This makes a call to tempfile.mktemp, but it registers the created
2452 This makes a call to tempfile.mktemp, but it registers the created
2453 filename internally so ipython cleans it up at exit time.
2453 filename internally so ipython cleans it up at exit time.
2454
2454
2455 Optional inputs:
2455 Optional inputs:
2456
2456
2457 - data(None): if data is given, it gets written out to the temp file
2457 - data(None): if data is given, it gets written out to the temp file
2458 immediately, and the file is closed again."""
2458 immediately, and the file is closed again."""
2459
2459
2460 filename = tempfile.mktemp('.py','ipython_edit_')
2460 filename = tempfile.mktemp('.py','ipython_edit_')
2461 self.tempfiles.append(filename)
2461 self.tempfiles.append(filename)
2462
2462
2463 if data:
2463 if data:
2464 tmp_file = open(filename,'w')
2464 tmp_file = open(filename,'w')
2465 tmp_file.write(data)
2465 tmp_file.write(data)
2466 tmp_file.close()
2466 tmp_file.close()
2467 return filename
2467 return filename
2468
2468
2469 def write(self,data):
2469 def write(self,data):
2470 """Write a string to the default output"""
2470 """Write a string to the default output"""
2471 Term.cout.write(data)
2471 Term.cout.write(data)
2472
2472
2473 def write_err(self,data):
2473 def write_err(self,data):
2474 """Write a string to the default error output"""
2474 """Write a string to the default error output"""
2475 Term.cerr.write(data)
2475 Term.cerr.write(data)
2476
2476
2477 def ask_yes_no(self,prompt,default=True):
2477 def ask_yes_no(self,prompt,default=True):
2478 if self.quiet:
2478 if self.quiet:
2479 return True
2479 return True
2480 return ask_yes_no(prompt,default)
2480 return ask_yes_no(prompt,default)
2481
2481
2482 #-------------------------------------------------------------------------
2482 #-------------------------------------------------------------------------
2483 # Things related to GUI support and pylab
2483 # Things related to GUI support and pylab
2484 #-------------------------------------------------------------------------
2484 #-------------------------------------------------------------------------
2485
2485
2486 def enable_pylab(self, gui=None):
2486 def enable_pylab(self, gui=None):
2487 """Activate pylab support at runtime.
2487 """Activate pylab support at runtime.
2488
2488
2489 This turns on support for matplotlib, preloads into the interactive
2489 This turns on support for matplotlib, preloads into the interactive
2490 namespace all of numpy and pylab, and configures IPython to correcdtly
2490 namespace all of numpy and pylab, and configures IPython to correcdtly
2491 interact with the GUI event loop. The GUI backend to be used can be
2491 interact with the GUI event loop. The GUI backend to be used can be
2492 optionally selected with the optional :param:`gui` argument.
2492 optionally selected with the optional :param:`gui` argument.
2493
2493
2494 Parameters
2494 Parameters
2495 ----------
2495 ----------
2496 gui : optional, string
2496 gui : optional, string
2497
2497
2498 If given, dictates the choice of matplotlib GUI backend to use
2498 If given, dictates the choice of matplotlib GUI backend to use
2499 (should be one of IPython's supported backends, 'tk', 'qt', 'wx' or
2499 (should be one of IPython's supported backends, 'tk', 'qt', 'wx' or
2500 'gtk'), otherwise we use the default chosen by matplotlib (as
2500 'gtk'), otherwise we use the default chosen by matplotlib (as
2501 dictated by the matplotlib build-time options plus the user's
2501 dictated by the matplotlib build-time options plus the user's
2502 matplotlibrc configuration file).
2502 matplotlibrc configuration file).
2503 """
2503 """
2504 # We want to prevent the loading of pylab to pollute the user's
2504 # We want to prevent the loading of pylab to pollute the user's
2505 # namespace as shown by the %who* magics, so we execute the activation
2505 # namespace as shown by the %who* magics, so we execute the activation
2506 # code in an empty namespace, and we update *both* user_ns and
2506 # code in an empty namespace, and we update *both* user_ns and
2507 # user_config_ns with this information.
2507 # user_config_ns with this information.
2508 ns = {}
2508 ns = {}
2509 gui = pylab_activate(ns, gui)
2509 gui = pylab_activate(ns, gui)
2510 self.user_ns.update(ns)
2510 self.user_ns.update(ns)
2511 self.user_config_ns.update(ns)
2511 self.user_config_ns.update(ns)
2512 # Now we must activate the gui pylab wants to use, and fix %run to take
2512 # Now we must activate the gui pylab wants to use, and fix %run to take
2513 # plot updates into account
2513 # plot updates into account
2514 enable_gui(gui)
2514 enable_gui(gui)
2515 self.magic_run = self._pylab_magic_run
2515 self.magic_run = self._pylab_magic_run
2516
2516
2517 #-------------------------------------------------------------------------
2517 #-------------------------------------------------------------------------
2518 # Things related to IPython exiting
2518 # Things related to IPython exiting
2519 #-------------------------------------------------------------------------
2519 #-------------------------------------------------------------------------
2520
2520
2521 def ask_exit(self):
2521 def ask_exit(self):
2522 """ Ask the shell to exit. Can be overiden and used as a callback. """
2522 """ Ask the shell to exit. Can be overiden and used as a callback. """
2523 self.exit_now = True
2523 self.exit_now = True
2524
2524
2525 def exit(self):
2525 def exit(self):
2526 """Handle interactive exit.
2526 """Handle interactive exit.
2527
2527
2528 This method calls the ask_exit callback."""
2528 This method calls the ask_exit callback."""
2529 if self.confirm_exit:
2529 if self.confirm_exit:
2530 if self.ask_yes_no('Do you really want to exit ([y]/n)?','y'):
2530 if self.ask_yes_no('Do you really want to exit ([y]/n)?','y'):
2531 self.ask_exit()
2531 self.ask_exit()
2532 else:
2532 else:
2533 self.ask_exit()
2533 self.ask_exit()
2534
2534
2535 def atexit_operations(self):
2535 def atexit_operations(self):
2536 """This will be executed at the time of exit.
2536 """This will be executed at the time of exit.
2537
2537
2538 Saving of persistent data should be performed here.
2538 Saving of persistent data should be performed here.
2539 """
2539 """
2540 self.savehist()
2540 self.savehist()
2541
2541
2542 # Cleanup all tempfiles left around
2542 # Cleanup all tempfiles left around
2543 for tfile in self.tempfiles:
2543 for tfile in self.tempfiles:
2544 try:
2544 try:
2545 os.unlink(tfile)
2545 os.unlink(tfile)
2546 except OSError:
2546 except OSError:
2547 pass
2547 pass
2548
2548
2549 # Clear all user namespaces to release all references cleanly.
2549 # Clear all user namespaces to release all references cleanly.
2550 self.reset()
2550 self.reset()
2551
2551
2552 # Run user hooks
2552 # Run user hooks
2553 self.hooks.shutdown_hook()
2553 self.hooks.shutdown_hook()
2554
2554
2555 def cleanup(self):
2555 def cleanup(self):
2556 self.restore_sys_module_state()
2556 self.restore_sys_module_state()
2557
2557
2558
2558
@@ -1,167 +1,166 b''
1 """Use pretty.py for configurable pretty-printing.
1 """Use pretty.py for configurable pretty-printing.
2
2
3 To enable this extension in your configuration
3 To enable this extension in your configuration
4 file, add the following to :file:`ipython_config.py`::
4 file, add the following to :file:`ipython_config.py`::
5
5
6 c.Global.extensions = ['IPython.extensions.pretty']
6 c.Global.extensions = ['IPython.extensions.pretty']
7 def dict_pprinter(obj, p, cycle):
7 def dict_pprinter(obj, p, cycle):
8 return p.text("<dict>")
8 return p.text("<dict>")
9 c.PrettyResultDisplay.verbose = True
9 c.PrettyResultDisplay.verbose = True
10 c.PrettyResultDisplay.defaults_for_type = [
10 c.PrettyResultDisplay.defaults_for_type = [
11 (dict, dict_pprinter)
11 (dict, dict_pprinter)
12 ]
12 ]
13 c.PrettyResultDisplay.defaults_for_type_by_name = [
13 c.PrettyResultDisplay.defaults_for_type_by_name = [
14 ('numpy', 'dtype', 'IPython.extensions.pretty.dtype_pprinter')
14 ('numpy', 'dtype', 'IPython.extensions.pretty.dtype_pprinter')
15 ]
15 ]
16
16
17 This extension can also be loaded by using the ``%load_ext`` magic::
17 This extension can also be loaded by using the ``%load_ext`` magic::
18
18
19 %load_ext IPython.extensions.pretty
19 %load_ext IPython.extensions.pretty
20
20
21 If this extension is enabled, you can always add additional pretty printers
21 If this extension is enabled, you can always add additional pretty printers
22 by doing::
22 by doing::
23
23
24 ip = get_ipython()
24 ip = get_ipython()
25 prd = ip.get_component('pretty_result_display')
25 prd = ip.get_component('pretty_result_display')
26 import numpy
26 import numpy
27 from IPython.extensions.pretty import dtype_pprinter
27 from IPython.extensions.pretty import dtype_pprinter
28 prd.for_type(numpy.dtype, dtype_pprinter)
28 prd.for_type(numpy.dtype, dtype_pprinter)
29
29
30 # If you don't want to have numpy imported until it needs to be:
30 # If you don't want to have numpy imported until it needs to be:
31 prd.for_type_by_name('numpy', 'dtype', dtype_pprinter)
31 prd.for_type_by_name('numpy', 'dtype', dtype_pprinter)
32 """
32 """
33
33
34 #-----------------------------------------------------------------------------
34 #-----------------------------------------------------------------------------
35 # Imports
35 # Imports
36 #-----------------------------------------------------------------------------
36 #-----------------------------------------------------------------------------
37
37
38 from IPython.core.error import TryNext
38 from IPython.core.error import TryNext
39 from IPython.external import pretty
39 from IPython.external import pretty
40 from IPython.core.component import Component
40 from IPython.core.component import Component
41 from IPython.utils.traitlets import Bool, List
41 from IPython.utils.traitlets import Bool, List
42 from IPython.utils.io import Term
42 from IPython.utils.io import Term
43 from IPython.utils.autoattr import auto_attr
43 from IPython.utils.autoattr import auto_attr
44 from IPython.utils.importstring import import_item
44 from IPython.utils.importstring import import_item
45
45
46 #-----------------------------------------------------------------------------
46 #-----------------------------------------------------------------------------
47 # Code
47 # Code
48 #-----------------------------------------------------------------------------
48 #-----------------------------------------------------------------------------
49
49
50
50
51 _loaded = False
51 _loaded = False
52
52
53
53
54 class PrettyResultDisplay(Component):
54 class PrettyResultDisplay(Component):
55 """A component for pretty printing on steroids."""
55 """A component for pretty printing on steroids."""
56
56
57 verbose = Bool(False, config=True)
57 verbose = Bool(False, config=True)
58
58
59 # A list of (type, func_name), like
59 # A list of (type, func_name), like
60 # [(dict, 'my_dict_printer')]
60 # [(dict, 'my_dict_printer')]
61 # The final argument can also be a callable
61 # The final argument can also be a callable
62 defaults_for_type = List(default_value=[], config=True)
62 defaults_for_type = List(default_value=[], config=True)
63
63
64 # A list of (module_name, type_name, func_name), like
64 # A list of (module_name, type_name, func_name), like
65 # [('numpy', 'dtype', 'IPython.extensions.pretty.dtype_pprinter')]
65 # [('numpy', 'dtype', 'IPython.extensions.pretty.dtype_pprinter')]
66 # The final argument can also be a callable
66 # The final argument can also be a callable
67 defaults_for_type_by_name = List(default_value=[], config=True)
67 defaults_for_type_by_name = List(default_value=[], config=True)
68
68
69 def __init__(self, parent, name=None, config=None):
69 def __init__(self, parent, name=None, config=None):
70 super(PrettyResultDisplay, self).__init__(parent, name=name, config=config)
70 super(PrettyResultDisplay, self).__init__(parent, name=name, config=config)
71 self._setup_defaults()
71 self._setup_defaults()
72
72
73 def _setup_defaults(self):
73 def _setup_defaults(self):
74 """Initialize the default pretty printers."""
74 """Initialize the default pretty printers."""
75 for typ, func_name in self.defaults_for_type:
75 for typ, func_name in self.defaults_for_type:
76 func = self._resolve_func_name(func_name)
76 func = self._resolve_func_name(func_name)
77 self.for_type(typ, func)
77 self.for_type(typ, func)
78 for type_module, type_name, func_name in self.defaults_for_type_by_name:
78 for type_module, type_name, func_name in self.defaults_for_type_by_name:
79 func = self._resolve_func_name(func_name)
79 func = self._resolve_func_name(func_name)
80 self.for_type_by_name(type_module, type_name, func)
80 self.for_type_by_name(type_module, type_name, func)
81
81
82 def _resolve_func_name(self, func_name):
82 def _resolve_func_name(self, func_name):
83 if callable(func_name):
83 if callable(func_name):
84 return func_name
84 return func_name
85 elif isinstance(func_name, basestring):
85 elif isinstance(func_name, basestring):
86 return import_item(func_name)
86 return import_item(func_name)
87 else:
87 else:
88 raise TypeError('func_name must be a str or callable, got: %r' % func_name)
88 raise TypeError('func_name must be a str or callable, got: %r' % func_name)
89
89
90 # Access other components like this rather than by a regular attribute.
90 # Access other components like this rather than by a regular attribute.
91 # This won't lookup the InteractiveShell object until it is used and
91 # This won't lookup the InteractiveShell object until it is used and
92 # then it is cached. This is both efficient and couples this class
92 # then it is cached. This is both efficient and couples this class
93 # more loosely to InteractiveShell.
93 # more loosely to InteractiveShell.
94 @auto_attr
94 @auto_attr
95 def shell(self):
95 def shell(self):
96 return Component.get_instances(
96 return Component.get_instances(
97 root=self.root,
97 root=self.root,
98 klass='IPython.core.iplib.InteractiveShell')[0]
98 klass='IPython.core.iplib.InteractiveShell')[0]
99
99
100 def __call__(self, otherself, arg):
100 def __call__(self, otherself, arg):
101 """Uber-pretty-printing display hook.
101 """Uber-pretty-printing display hook.
102
102
103 Called for displaying the result to the user.
103 Called for displaying the result to the user.
104 """
104 """
105
105
106 if self.shell.pprint:
106 if self.shell.pprint:
107 out = pretty.pretty(arg, verbose=self.verbose)
107 out = pretty.pretty(arg, verbose=self.verbose)
108 if '\n' in out:
108 if '\n' in out:
109 # So that multi-line strings line up with the left column of
109 # So that multi-line strings line up with the left column of
110 # the screen, instead of having the output prompt mess up
110 # the screen, instead of having the output prompt mess up
111 # their first line.
111 # their first line.
112 Term.cout.write('\n')
112 Term.cout.write('\n')
113 print >>Term.cout, out
113 print >>Term.cout, out
114 else:
114 else:
115 raise TryNext
115 raise TryNext
116
116
117 def for_type(self, typ, func):
117 def for_type(self, typ, func):
118 """Add a pretty printer for a type."""
118 """Add a pretty printer for a type."""
119 return pretty.for_type(typ, func)
119 return pretty.for_type(typ, func)
120
120
121 def for_type_by_name(self, type_module, type_name, func):
121 def for_type_by_name(self, type_module, type_name, func):
122 """Add a pretty printer for a type by its name and module name."""
122 """Add a pretty printer for a type by its name and module name."""
123 return pretty.for_type_by_name(type_module, type_name, func)
123 return pretty.for_type_by_name(type_module, type_name, func)
124
124
125
125
126 #-----------------------------------------------------------------------------
126 #-----------------------------------------------------------------------------
127 # Initialization code for the extension
127 # Initialization code for the extension
128 #-----------------------------------------------------------------------------
128 #-----------------------------------------------------------------------------
129
129
130
130
131 def load_ipython_extension(ip=None):
131 def load_ipython_extension(ip):
132 """Load the extension in IPython as a hook."""
132 """Load the extension in IPython as a hook."""
133 if ip is None: ip = get_ipython()
134 global _loaded
133 global _loaded
135 if not _loaded:
134 if not _loaded:
136 prd = PrettyResultDisplay(ip, name='pretty_result_display')
135 prd = PrettyResultDisplay(ip, name='pretty_result_display')
137 ip.set_hook('result_display', prd, priority=99)
136 ip.set_hook('result_display', prd, priority=99)
138 _loaded = True
137 _loaded = True
139 return prd
138 return prd
140
139
141 def unload_ipython_extension(ip):
140 def unload_ipython_extension(ip):
142 """Unload the extension."""
141 """Unload the extension."""
143 # The hook system does not have a way to remove a hook so this is a pass
142 # The hook system does not have a way to remove a hook so this is a pass
144 pass
143 pass
145
144
146
145
147 #-----------------------------------------------------------------------------
146 #-----------------------------------------------------------------------------
148 # Example pretty printers
147 # Example pretty printers
149 #-----------------------------------------------------------------------------
148 #-----------------------------------------------------------------------------
150
149
151
150
152 def dtype_pprinter(obj, p, cycle):
151 def dtype_pprinter(obj, p, cycle):
153 """ A pretty-printer for numpy dtype objects.
152 """ A pretty-printer for numpy dtype objects.
154 """
153 """
155 if cycle:
154 if cycle:
156 return p.text('dtype(...)')
155 return p.text('dtype(...)')
157 if hasattr(obj, 'fields'):
156 if hasattr(obj, 'fields'):
158 if obj.fields is None:
157 if obj.fields is None:
159 p.text(repr(obj))
158 p.text(repr(obj))
160 else:
159 else:
161 p.begin_group(7, 'dtype([')
160 p.begin_group(7, 'dtype([')
162 for i, field in enumerate(obj.descr):
161 for i, field in enumerate(obj.descr):
163 if i > 0:
162 if i > 0:
164 p.text(',')
163 p.text(',')
165 p.breakable()
164 p.breakable()
166 p.pretty(field)
165 p.pretty(field)
167 p.end_group(7, '])')
166 p.end_group(7, '])')
@@ -1,372 +1,373 b''
1 """
1 """
2 Base front end class for all line-oriented frontends, rather than
2 Base front end class for all line-oriented frontends, rather than
3 block-oriented.
3 block-oriented.
4
4
5 Currently this focuses on synchronous frontends.
5 Currently this focuses on synchronous frontends.
6 """
6 """
7 __docformat__ = "restructuredtext en"
7 __docformat__ = "restructuredtext en"
8
8
9 #-------------------------------------------------------------------------------
9 #-------------------------------------------------------------------------------
10 # Copyright (C) 2008 The IPython Development Team
10 # Copyright (C) 2008 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 import re
19 import re
20
20
21 import sys
21 import sys
22 import codeop
22 import codeop
23
23
24 from frontendbase import FrontEndBase
24 from frontendbase import FrontEndBase
25 from IPython.kernel.core.interpreter import Interpreter
25 from IPython.kernel.core.interpreter import Interpreter
26
26
27 def common_prefix(strings):
27 def common_prefix(strings):
28 """ Given a list of strings, return the common prefix between all
28 """ Given a list of strings, return the common prefix between all
29 these strings.
29 these strings.
30 """
30 """
31 ref = strings[0]
31 ref = strings[0]
32 prefix = ''
32 prefix = ''
33 for size in range(len(ref)):
33 for size in range(len(ref)):
34 test_prefix = ref[:size+1]
34 test_prefix = ref[:size+1]
35 for string in strings[1:]:
35 for string in strings[1:]:
36 if not string.startswith(test_prefix):
36 if not string.startswith(test_prefix):
37 return prefix
37 return prefix
38 prefix = test_prefix
38 prefix = test_prefix
39
39
40 return prefix
40 return prefix
41
41
42 #-------------------------------------------------------------------------------
42 #-----------------------------------------------------------------------------
43 # Base class for the line-oriented front ends
43 # Base class for the line-oriented front ends
44 #-------------------------------------------------------------------------------
44 #-----------------------------------------------------------------------------
45
45 class LineFrontEndBase(FrontEndBase):
46 class LineFrontEndBase(FrontEndBase):
46 """ Concrete implementation of the FrontEndBase class. This is meant
47 """ Concrete implementation of the FrontEndBase class. This is meant
47 to be the base class behind all the frontend that are line-oriented,
48 to be the base class behind all the frontend that are line-oriented,
48 rather than block-oriented.
49 rather than block-oriented.
49 """
50 """
50
51
51 # We need to keep the prompt number, to be able to increment
52 # We need to keep the prompt number, to be able to increment
52 # it when there is an exception.
53 # it when there is an exception.
53 prompt_number = 1
54 prompt_number = 1
54
55
55 # We keep a reference to the last result: it helps testing and
56 # We keep a reference to the last result: it helps testing and
56 # programatic control of the frontend.
57 # programatic control of the frontend.
57 last_result = dict(number=0)
58 last_result = dict(number=0)
58
59
59 # The last prompt displayed. Useful for continuation prompts.
60 # The last prompt displayed. Useful for continuation prompts.
60 last_prompt = ''
61 last_prompt = ''
61
62
62 # The input buffer being edited
63 # The input buffer being edited
63 input_buffer = ''
64 input_buffer = ''
64
65
65 # Set to true for debug output
66 # Set to true for debug output
66 debug = False
67 debug = False
67
68
68 # A banner to print at startup
69 # A banner to print at startup
69 banner = None
70 banner = None
70
71
71 #--------------------------------------------------------------------------
72 #--------------------------------------------------------------------------
72 # FrontEndBase interface
73 # FrontEndBase interface
73 #--------------------------------------------------------------------------
74 #--------------------------------------------------------------------------
74
75
75 def __init__(self, shell=None, history=None, banner=None, *args, **kwargs):
76 def __init__(self, shell=None, history=None, banner=None, *args, **kwargs):
76 if shell is None:
77 if shell is None:
77 shell = Interpreter()
78 shell = Interpreter()
78 FrontEndBase.__init__(self, shell=shell, history=history)
79 FrontEndBase.__init__(self, shell=shell, history=history)
79
80
80 if banner is not None:
81 if banner is not None:
81 self.banner = banner
82 self.banner = banner
82
83
83 def start(self):
84 def start(self):
84 """ Put the frontend in a state where it is ready for user
85 """ Put the frontend in a state where it is ready for user
85 interaction.
86 interaction.
86 """
87 """
87 if self.banner is not None:
88 if self.banner is not None:
88 self.write(self.banner, refresh=False)
89 self.write(self.banner, refresh=False)
89
90
90 self.new_prompt(self.input_prompt_template.substitute(number=1))
91 self.new_prompt(self.input_prompt_template.substitute(number=1))
91
92
92
93
93 def complete(self, line):
94 def complete(self, line):
94 """Complete line in engine's user_ns
95 """Complete line in engine's user_ns
95
96
96 Parameters
97 Parameters
97 ----------
98 ----------
98 line : string
99 line : string
99
100
100 Returns
101 Returns
101 -------
102 -------
102 The replacement for the line and the list of possible completions.
103 The replacement for the line and the list of possible completions.
103 """
104 """
104 completions = self.shell.complete(line)
105 completions = self.shell.complete(line)
105 complete_sep = re.compile('[\s\{\}\[\]\(\)\=]')
106 complete_sep = re.compile('[\s\{\}\[\]\(\)\=]')
106 if completions:
107 if completions:
107 prefix = common_prefix(completions)
108 prefix = common_prefix(completions)
108 residual = complete_sep.split(line)[:-1]
109 residual = complete_sep.split(line)[:-1]
109 line = line[:-len(residual)] + prefix
110 line = line[:-len(residual)] + prefix
110 return line, completions
111 return line, completions
111
112
112
113
113 def render_result(self, result):
114 def render_result(self, result):
114 """ Frontend-specific rendering of the result of a calculation
115 """ Frontend-specific rendering of the result of a calculation
115 that has been sent to an engine.
116 that has been sent to an engine.
116 """
117 """
117 if 'stdout' in result and result['stdout']:
118 if 'stdout' in result and result['stdout']:
118 self.write('\n' + result['stdout'])
119 self.write('\n' + result['stdout'])
119 if 'display' in result and result['display']:
120 if 'display' in result and result['display']:
120 self.write("%s%s\n" % (
121 self.write("%s%s\n" % (
121 self.output_prompt_template.substitute(
122 self.output_prompt_template.substitute(
122 number=result['number']),
123 number=result['number']),
123 result['display']['pprint']
124 result['display']['pprint']
124 ) )
125 ) )
125
126
126
127
127 def render_error(self, failure):
128 def render_error(self, failure):
128 """ Frontend-specific rendering of error.
129 """ Frontend-specific rendering of error.
129 """
130 """
130 self.write('\n\n'+str(failure)+'\n\n')
131 self.write('\n\n'+str(failure)+'\n\n')
131 return failure
132 return failure
132
133
133
134
134 def is_complete(self, string):
135 def is_complete(self, string):
135 """ Check if a string forms a complete, executable set of
136 """ Check if a string forms a complete, executable set of
136 commands.
137 commands.
137
138
138 For the line-oriented frontend, multi-line code is not executed
139 For the line-oriented frontend, multi-line code is not executed
139 as soon as it is complete: the users has to enter two line
140 as soon as it is complete: the users has to enter two line
140 returns.
141 returns.
141 """
142 """
142 if string in ('', '\n'):
143 if string in ('', '\n'):
143 # Prefiltering, eg through ipython0, may return an empty
144 # Prefiltering, eg through ipython0, may return an empty
144 # string although some operations have been accomplished. We
145 # string although some operations have been accomplished. We
145 # thus want to consider an empty string as a complete
146 # thus want to consider an empty string as a complete
146 # statement.
147 # statement.
147 return True
148 return True
148 elif ( len(self.input_buffer.split('\n'))>2
149 elif ( len(self.input_buffer.split('\n'))>2
149 and not re.findall(r"\n[\t ]*\n[\t ]*$", string)):
150 and not re.findall(r"\n[\t ]*\n[\t ]*$", string)):
150 return False
151 return False
151 else:
152 else:
152 self.capture_output()
153 self.capture_output()
153 try:
154 try:
154 # Add line returns here, to make sure that the statement is
155 # Add line returns here, to make sure that the statement is
155 # complete (except if '\' was used).
156 # complete (except if '\' was used).
156 # This should probably be done in a different place (like
157 # This should probably be done in a different place (like
157 # maybe 'prefilter_input' method? For now, this works.
158 # maybe 'prefilter_input' method? For now, this works.
158 clean_string = string.rstrip('\n')
159 clean_string = string.rstrip('\n')
159 if not clean_string.endswith('\\'): clean_string +='\n\n'
160 if not clean_string.endswith('\\'): clean_string +='\n\n'
160 is_complete = codeop.compile_command(clean_string,
161 is_complete = codeop.compile_command(clean_string,
161 "<string>", "exec")
162 "<string>", "exec")
162 self.release_output()
163 self.release_output()
163 except Exception, e:
164 except Exception, e:
164 # XXX: Hack: return True so that the
165 # XXX: Hack: return True so that the
165 # code gets executed and the error captured.
166 # code gets executed and the error captured.
166 is_complete = True
167 is_complete = True
167 return is_complete
168 return is_complete
168
169
169
170
170 def write(self, string, refresh=True):
171 def write(self, string, refresh=True):
171 """ Write some characters to the display.
172 """ Write some characters to the display.
172
173
173 Subclass should overide this method.
174 Subclass should overide this method.
174
175
175 The refresh keyword argument is used in frontends with an
176 The refresh keyword argument is used in frontends with an
176 event loop, to choose whether the write should trigget an UI
177 event loop, to choose whether the write should trigget an UI
177 refresh, and thus be syncrhonous, or not.
178 refresh, and thus be syncrhonous, or not.
178 """
179 """
179 print >>sys.__stderr__, string
180 print >>sys.__stderr__, string
180
181
181
182
182 def execute(self, python_string, raw_string=None):
183 def execute(self, python_string, raw_string=None):
183 """ Stores the raw_string in the history, and sends the
184 """ Stores the raw_string in the history, and sends the
184 python string to the interpreter.
185 python string to the interpreter.
185 """
186 """
186 if raw_string is None:
187 if raw_string is None:
187 raw_string = python_string
188 raw_string = python_string
188 # Create a false result, in case there is an exception
189 # Create a false result, in case there is an exception
189 self.last_result = dict(number=self.prompt_number)
190 self.last_result = dict(number=self.prompt_number)
190
191
191 try:
192 try:
192 try:
193 try:
193 self.history.input_cache[-1] = raw_string.rstrip()
194 self.history.input_cache[-1] = raw_string.rstrip()
194 result = self.shell.execute(python_string)
195 result = self.shell.execute(python_string)
195 self.last_result = result
196 self.last_result = result
196 self.render_result(result)
197 self.render_result(result)
197 except:
198 except:
198 self.show_traceback()
199 self.show_traceback()
199 finally:
200 finally:
200 self.after_execute()
201 self.after_execute()
201
202
202
203
203 #--------------------------------------------------------------------------
204 #--------------------------------------------------------------------------
204 # LineFrontEndBase interface
205 # LineFrontEndBase interface
205 #--------------------------------------------------------------------------
206 #--------------------------------------------------------------------------
206
207
207 def prefilter_input(self, string):
208 def prefilter_input(self, string):
208 """ Prefilter the input to turn it in valid python.
209 """ Prefilter the input to turn it in valid python.
209 """
210 """
210 string = string.replace('\r\n', '\n')
211 string = string.replace('\r\n', '\n')
211 string = string.replace('\t', 4*' ')
212 string = string.replace('\t', 4*' ')
212 # Clean the trailing whitespace
213 # Clean the trailing whitespace
213 string = '\n'.join(l.rstrip() for l in string.split('\n'))
214 string = '\n'.join(l.rstrip() for l in string.split('\n'))
214 return string
215 return string
215
216
216
217
217 def after_execute(self):
218 def after_execute(self):
218 """ All the operations required after an execution to put the
219 """ All the operations required after an execution to put the
219 terminal back in a shape where it is usable.
220 terminal back in a shape where it is usable.
220 """
221 """
221 self.prompt_number += 1
222 self.prompt_number += 1
222 self.new_prompt(self.input_prompt_template.substitute(
223 self.new_prompt(self.input_prompt_template.substitute(
223 number=(self.last_result['number'] + 1)))
224 number=(self.last_result['number'] + 1)))
224 # Start a new empty history entry
225 # Start a new empty history entry
225 self._add_history(None, '')
226 self._add_history(None, '')
226 self.history_cursor = len(self.history.input_cache) - 1
227 self.history_cursor = len(self.history.input_cache) - 1
227
228
228
229
229 def complete_current_input(self):
230 def complete_current_input(self):
230 """ Do code completion on current line.
231 """ Do code completion on current line.
231 """
232 """
232 if self.debug:
233 if self.debug:
233 print >>sys.__stdout__, "complete_current_input",
234 print >>sys.__stdout__, "complete_current_input",
234 line = self.input_buffer
235 line = self.input_buffer
235 new_line, completions = self.complete(line)
236 new_line, completions = self.complete(line)
236 if len(completions)>1:
237 if len(completions)>1:
237 self.write_completion(completions, new_line=new_line)
238 self.write_completion(completions, new_line=new_line)
238 elif not line == new_line:
239 elif not line == new_line:
239 self.input_buffer = new_line
240 self.input_buffer = new_line
240 if self.debug:
241 if self.debug:
241 print >>sys.__stdout__, 'line', line
242 print >>sys.__stdout__, 'line', line
242 print >>sys.__stdout__, 'new_line', new_line
243 print >>sys.__stdout__, 'new_line', new_line
243 print >>sys.__stdout__, completions
244 print >>sys.__stdout__, completions
244
245
245
246
246 def get_line_width(self):
247 def get_line_width(self):
247 """ Return the width of the line in characters.
248 """ Return the width of the line in characters.
248 """
249 """
249 return 80
250 return 80
250
251
251
252
252 def write_completion(self, possibilities, new_line=None):
253 def write_completion(self, possibilities, new_line=None):
253 """ Write the list of possible completions.
254 """ Write the list of possible completions.
254
255
255 new_line is the completed input line that should be displayed
256 new_line is the completed input line that should be displayed
256 after the completion are writen. If None, the input_buffer
257 after the completion are writen. If None, the input_buffer
257 before the completion is used.
258 before the completion is used.
258 """
259 """
259 if new_line is None:
260 if new_line is None:
260 new_line = self.input_buffer
261 new_line = self.input_buffer
261
262
262 self.write('\n')
263 self.write('\n')
263 max_len = len(max(possibilities, key=len)) + 1
264 max_len = len(max(possibilities, key=len)) + 1
264
265
265 # Now we check how much symbol we can put on a line...
266 # Now we check how much symbol we can put on a line...
266 chars_per_line = self.get_line_width()
267 chars_per_line = self.get_line_width()
267 symbols_per_line = max(1, chars_per_line/max_len)
268 symbols_per_line = max(1, chars_per_line/max_len)
268
269
269 pos = 1
270 pos = 1
270 completion_string = []
271 completion_string = []
271 for symbol in possibilities:
272 for symbol in possibilities:
272 if pos < symbols_per_line:
273 if pos < symbols_per_line:
273 completion_string.append(symbol.ljust(max_len))
274 completion_string.append(symbol.ljust(max_len))
274 pos += 1
275 pos += 1
275 else:
276 else:
276 completion_string.append(symbol.rstrip() + '\n')
277 completion_string.append(symbol.rstrip() + '\n')
277 pos = 1
278 pos = 1
278 self.write(''.join(completion_string))
279 self.write(''.join(completion_string))
279 self.new_prompt(self.input_prompt_template.substitute(
280 self.new_prompt(self.input_prompt_template.substitute(
280 number=self.last_result['number'] + 1))
281 number=self.last_result['number'] + 1))
281 self.input_buffer = new_line
282 self.input_buffer = new_line
282
283
283
284
284 def new_prompt(self, prompt):
285 def new_prompt(self, prompt):
285 """ Prints a prompt and starts a new editing buffer.
286 """ Prints a prompt and starts a new editing buffer.
286
287
287 Subclasses should use this method to make sure that the
288 Subclasses should use this method to make sure that the
288 terminal is put in a state favorable for a new line
289 terminal is put in a state favorable for a new line
289 input.
290 input.
290 """
291 """
291 self.input_buffer = ''
292 self.input_buffer = ''
292 self.write(prompt)
293 self.write(prompt)
293
294
294
295
295 def continuation_prompt(self):
296 def continuation_prompt(self):
296 """Returns the current continuation prompt.
297 """Returns the current continuation prompt.
297 """
298 """
298 return ("."*(len(self.last_prompt)-2) + ': ')
299 return ("."*(len(self.last_prompt)-2) + ': ')
299
300
300
301
301 def execute_command(self, command, hidden=False):
302 def execute_command(self, command, hidden=False):
302 """ Execute a command, not only in the model, but also in the
303 """ Execute a command, not only in the model, but also in the
303 view, if any.
304 view, if any.
304 """
305 """
305 return self.shell.execute(command)
306 return self.shell.execute(command)
306
307
307 #--------------------------------------------------------------------------
308 #--------------------------------------------------------------------------
308 # Private API
309 # Private API
309 #--------------------------------------------------------------------------
310 #--------------------------------------------------------------------------
310
311
311 def _on_enter(self, new_line_pos=0):
312 def _on_enter(self, new_line_pos=0):
312 """ Called when the return key is pressed in a line editing
313 """ Called when the return key is pressed in a line editing
313 buffer.
314 buffer.
314
315
315 Parameters
316 Parameters
316 ----------
317 ----------
317 new_line_pos : integer, optional
318 new_line_pos : integer, optional
318 Position of the new line to add, starting from the
319 Position of the new line to add, starting from the
319 end (0 adds a new line after the last line, -1 before
320 end (0 adds a new line after the last line, -1 before
320 the last line...)
321 the last line...)
321
322
322 Returns
323 Returns
323 -------
324 -------
324 True if execution is triggered
325 True if execution is triggered
325 """
326 """
326 current_buffer = self.input_buffer
327 current_buffer = self.input_buffer
327 # XXX: This string replace is ugly, but there should be no way it
328 # XXX: This string replace is ugly, but there should be no way it
328 # fails.
329 # fails.
329 prompt_less_buffer = re.sub('^' + self.continuation_prompt(),
330 prompt_less_buffer = re.sub('^' + self.continuation_prompt(),
330 '', current_buffer).replace('\n' + self.continuation_prompt(),
331 '', current_buffer).replace('\n' + self.continuation_prompt(),
331 '\n')
332 '\n')
332 cleaned_buffer = self.prefilter_input(prompt_less_buffer)
333 cleaned_buffer = self.prefilter_input(prompt_less_buffer)
333 if self.is_complete(cleaned_buffer):
334 if self.is_complete(cleaned_buffer):
334 self.execute(cleaned_buffer, raw_string=current_buffer)
335 self.execute(cleaned_buffer, raw_string=current_buffer)
335 return True
336 return True
336 else:
337 else:
337 # Start a new line.
338 # Start a new line.
338 new_line_pos = -new_line_pos
339 new_line_pos = -new_line_pos
339 lines = current_buffer.split('\n')[:-1]
340 lines = current_buffer.split('\n')[:-1]
340 prompt_less_lines = prompt_less_buffer.split('\n')
341 prompt_less_lines = prompt_less_buffer.split('\n')
341 # Create the new line, with the continuation prompt, and the
342 # Create the new line, with the continuation prompt, and the
342 # same amount of indent than the line above it.
343 # same amount of indent than the line above it.
343 new_line = self.continuation_prompt() + \
344 new_line = self.continuation_prompt() + \
344 self._get_indent_string('\n'.join(
345 self._get_indent_string('\n'.join(
345 prompt_less_lines[:new_line_pos-1]))
346 prompt_less_lines[:new_line_pos-1]))
346 if len(lines) == 1:
347 if len(lines) == 1:
347 # We are starting a first continuation line. Indent it.
348 # We are starting a first continuation line. Indent it.
348 new_line += '\t'
349 new_line += '\t'
349 elif current_buffer[:-1].split('\n')[-1].rstrip().endswith(':'):
350 elif current_buffer[:-1].split('\n')[-1].rstrip().endswith(':'):
350 # The last line ends with ":", autoindent the new line.
351 # The last line ends with ":", autoindent the new line.
351 new_line += '\t'
352 new_line += '\t'
352
353
353 if new_line_pos == 0:
354 if new_line_pos == 0:
354 lines.append(new_line)
355 lines.append(new_line)
355 else:
356 else:
356 lines.insert(new_line_pos, new_line)
357 lines.insert(new_line_pos, new_line)
357 self.input_buffer = '\n'.join(lines)
358 self.input_buffer = '\n'.join(lines)
358
359
359
360
360 def _get_indent_string(self, string):
361 def _get_indent_string(self, string):
361 """ Return the string of whitespace that prefixes a line. Used to
362 """ Return the string of whitespace that prefixes a line. Used to
362 add the right amount of indendation when creating a new line.
363 add the right amount of indendation when creating a new line.
363 """
364 """
364 string = string.replace('\t', ' '*4)
365 string = string.replace('\t', ' '*4)
365 string = string.split('\n')[-1]
366 string = string.split('\n')[-1]
366 indent_chars = len(string) - len(string.lstrip())
367 indent_chars = len(string) - len(string.lstrip())
367 indent_string = '\t'*(indent_chars // 4) + \
368 indent_string = '\t'*(indent_chars // 4) + \
368 ' '*(indent_chars % 4)
369 ' '*(indent_chars % 4)
369
370
370 return indent_string
371 return indent_string
371
372
372
373
@@ -1,264 +1,256 b''
1 """
1 """
2 Frontend class that uses IPython0 to prefilter the inputs.
2 Frontend class that uses IPython0 to prefilter the inputs.
3
3
4 Using the IPython0 mechanism gives us access to the magics.
4 Using the IPython0 mechanism gives us access to the magics.
5
5
6 This is a transitory class, used here to do the transition between
6 This is a transitory class, used here to do the transition between
7 ipython0 and ipython1. This class is meant to be short-lived as more
7 ipython0 and ipython1. This class is meant to be short-lived as more
8 functionnality is abstracted out of ipython0 in reusable functions and
8 functionnality is abstracted out of ipython0 in reusable functions and
9 is added on the interpreter. This class can be a used to guide this
9 is added on the interpreter. This class can be a used to guide this
10 refactoring.
10 refactoring.
11 """
11 """
12
12
13 #-------------------------------------------------------------------------------
13 #-------------------------------------------------------------------------------
14 # Copyright (C) 2008 The IPython Development Team
14 # Copyright (C) 2008 The IPython Development Team
15 #
15 #
16 # Distributed under the terms of the BSD License. The full license is in
16 # Distributed under the terms of the BSD License. The full license is in
17 # the file COPYING, distributed as part of this software.
17 # the file COPYING, distributed as part of this software.
18 #-------------------------------------------------------------------------------
18 #-------------------------------------------------------------------------------
19
19
20 #-------------------------------------------------------------------------------
20 #-------------------------------------------------------------------------------
21 # Imports
21 # Imports
22 #-------------------------------------------------------------------------------
22 #-------------------------------------------------------------------------------
23 import sys
23 import sys
24 import pydoc
24 import pydoc
25 import os
25 import os
26 import re
26 import re
27 import __builtin__
27 import __builtin__
28
28
29 from IPython.core.ipapp import IPythonApp
29 from IPython.core.iplib import InteractiveShell
30 from IPython.kernel.core.redirector_output_trap import RedirectorOutputTrap
30 from IPython.kernel.core.redirector_output_trap import RedirectorOutputTrap
31
31
32 from IPython.kernel.core.sync_traceback_trap import SyncTracebackTrap
32 from IPython.kernel.core.sync_traceback_trap import SyncTracebackTrap
33
33
34 from IPython.utils.io import Term
34 from IPython.utils.io import Term
35
35
36 from linefrontendbase import LineFrontEndBase, common_prefix
36 from linefrontendbase import LineFrontEndBase, common_prefix
37
37
38 #-----------------------------------------------------------------------------
38 #-----------------------------------------------------------------------------
39 # Utility functions
39 # Utility functions
40 #-----------------------------------------------------------------------------
40 #-----------------------------------------------------------------------------
41
41
42 def mk_system_call(system_call_function, command):
42 def mk_system_call(system_call_function, command):
43 """ given a os.system replacement, and a leading string command,
43 """ given a os.system replacement, and a leading string command,
44 returns a function that will execute the command with the given
44 returns a function that will execute the command with the given
45 argument string.
45 argument string.
46 """
46 """
47 def my_system_call(args):
47 def my_system_call(args):
48 system_call_function("%s %s" % (command, args))
48 system_call_function("%s %s" % (command, args))
49
49
50 my_system_call.__doc__ = "Calls %s" % command
50 my_system_call.__doc__ = "Calls %s" % command
51 return my_system_call
51 return my_system_call
52
52
53 #-------------------------------------------------------------------------------
53 #-----------------------------------------------------------------------------
54 # Frontend class using ipython0 to do the prefiltering.
54 # Frontend class using ipython0 to do the prefiltering.
55 #-------------------------------------------------------------------------------
55 #-----------------------------------------------------------------------------
56
56 class PrefilterFrontEnd(LineFrontEndBase):
57 class PrefilterFrontEnd(LineFrontEndBase):
57 """ Class that uses ipython0 to do prefilter the input, do the
58 """ Class that uses ipython0 to do prefilter the input, do the
58 completion and the magics.
59 completion and the magics.
59
60
60 The core trick is to use an ipython0 instance to prefilter the
61 The core trick is to use an ipython0 instance to prefilter the
61 input, and share the namespace between the interpreter instance used
62 input, and share the namespace between the interpreter instance used
62 to execute the statements and the ipython0 used for code
63 to execute the statements and the ipython0 used for code
63 completion...
64 completion...
64 """
65 """
65
66
66 debug = False
67 debug = False
67
68
68 def __init__(self, ipython0=None, argv=None, *args, **kwargs):
69 def __init__(self, ipython0=None, *args, **kwargs):
69 """ Parameters
70 """ Parameters
70 ----------
71 ----------
71
72
72 ipython0: an optional ipython0 instance to use for command
73 ipython0: an optional ipython0 instance to use for command
73 prefiltering and completion.
74 prefiltering and completion.
74
75 argv : list, optional
76 Used as the instance's argv value. If not given, [] is used.
77 """
75 """
78 if argv is None:
79 argv = ['--no-banner']
80
81 LineFrontEndBase.__init__(self, *args, **kwargs)
76 LineFrontEndBase.__init__(self, *args, **kwargs)
82 self.shell.output_trap = RedirectorOutputTrap(
77 self.shell.output_trap = RedirectorOutputTrap(
83 out_callback=self.write,
78 out_callback=self.write,
84 err_callback=self.write,
79 err_callback=self.write,
85 )
80 )
86 self.shell.traceback_trap = SyncTracebackTrap(
81 self.shell.traceback_trap = SyncTracebackTrap(
87 formatters=self.shell.traceback_trap.formatters,
82 formatters=self.shell.traceback_trap.formatters,
88 )
83 )
89
84
90 # Start the ipython0 instance:
85 # Start the ipython0 instance:
91 self.save_output_hooks()
86 self.save_output_hooks()
92 if ipython0 is None:
87 if ipython0 is None:
93 # Instanciate an IPython0 interpreter to be able to use the
88 # Instanciate an IPython0 InteractiveShell to be able to use the
94 # prefiltering.
89 # prefiltering.
95 # Suppress all key input, to avoid waiting
90 # Suppress all key input, to avoid waiting
96 def my_rawinput(x=None):
91 def my_rawinput(x=None):
97 return '\n'
92 return '\n'
98 old_rawinput = __builtin__.raw_input
93 old_rawinput = __builtin__.raw_input
99 __builtin__.raw_input = my_rawinput
94 __builtin__.raw_input = my_rawinput
100 ipython0 = IPythonApp(argv=argv,
95 ipython0 = InteractiveShell(
101 user_ns=self.shell.user_ns,
96 parent=None, user_ns=self.shell.user_ns,
102 user_global_ns=self.shell.user_global_ns)
97 user_global_ns=self.shell.user_global_ns
103 ipython0.initialize()
98 )
104 __builtin__.raw_input = old_rawinput
99 __builtin__.raw_input = old_rawinput
105 # XXX This will need to be updated as we refactor things, but for now,
100 self.ipython0 = ipython0
106 # the .shell attribute of the ipythonapp instance conforms to the old
107 # api.
108 self.ipython0 = ipython0.shell
109 # Set the pager:
101 # Set the pager:
110 self.ipython0.set_hook('show_in_pager',
102 self.ipython0.set_hook('show_in_pager',
111 lambda s, string: self.write("\n" + string))
103 lambda s, string: self.write("\n" + string))
112 self.ipython0.write = self.write
104 self.ipython0.write = self.write
113 self._ip = _ip = self.ipython0
105 self._ip = _ip = self.ipython0
114 # Make sure the raw system call doesn't get called, as we don't
106 # Make sure the raw system call doesn't get called, as we don't
115 # have a stdin accessible.
107 # have a stdin accessible.
116 self._ip.system = self.system_call
108 self._ip.system = self.system_call
117 # XXX: Muck around with magics so that they work better
109 # XXX: Muck around with magics so that they work better
118 # in our environment
110 # in our environment
119 if not sys.platform.startswith('win'):
111 if not sys.platform.startswith('win'):
120 self.ipython0.magic_ls = mk_system_call(self.system_call,
112 self.ipython0.magic_ls = mk_system_call(self.system_call,
121 'ls -CF')
113 'ls -CF')
122 # And now clean up the mess created by ipython0
114 # And now clean up the mess created by ipython0
123 self.release_output()
115 self.release_output()
124
116
125
117
126 if not 'banner' in kwargs and self.banner is None:
118 if not 'banner' in kwargs and self.banner is None:
127 self.banner = self.ipython0.banner
119 self.banner = self.ipython0.banner
128
120
129 # FIXME: __init__ and start should be two different steps
121 # FIXME: __init__ and start should be two different steps
130 self.start()
122 self.start()
131
123
132 #--------------------------------------------------------------------------
124 #--------------------------------------------------------------------------
133 # FrontEndBase interface
125 # FrontEndBase interface
134 #--------------------------------------------------------------------------
126 #--------------------------------------------------------------------------
135
127
136 def show_traceback(self):
128 def show_traceback(self):
137 """ Use ipython0 to capture the last traceback and display it.
129 """ Use ipython0 to capture the last traceback and display it.
138 """
130 """
139 # Don't do the capture; the except_hook has already done some
131 # Don't do the capture; the except_hook has already done some
140 # modifications to the IO streams, if we store them, we'll be
132 # modifications to the IO streams, if we store them, we'll be
141 # storing the wrong ones.
133 # storing the wrong ones.
142 #self.capture_output()
134 #self.capture_output()
143 self.ipython0.showtraceback(tb_offset=-1)
135 self.ipython0.showtraceback(tb_offset=-1)
144 self.release_output()
136 self.release_output()
145
137
146
138
147 def execute(self, python_string, raw_string=None):
139 def execute(self, python_string, raw_string=None):
148 if self.debug:
140 if self.debug:
149 print 'Executing Python code:', repr(python_string)
141 print 'Executing Python code:', repr(python_string)
150 self.capture_output()
142 self.capture_output()
151 LineFrontEndBase.execute(self, python_string,
143 LineFrontEndBase.execute(self, python_string,
152 raw_string=raw_string)
144 raw_string=raw_string)
153 self.release_output()
145 self.release_output()
154
146
155
147
156 def save_output_hooks(self):
148 def save_output_hooks(self):
157 """ Store all the output hooks we can think of, to be able to
149 """ Store all the output hooks we can think of, to be able to
158 restore them.
150 restore them.
159
151
160 We need to do this early, as starting the ipython0 instance will
152 We need to do this early, as starting the ipython0 instance will
161 screw ouput hooks.
153 screw ouput hooks.
162 """
154 """
163 self.__old_cout_write = Term.cout.write
155 self.__old_cout_write = Term.cout.write
164 self.__old_cerr_write = Term.cerr.write
156 self.__old_cerr_write = Term.cerr.write
165 self.__old_stdout = sys.stdout
157 self.__old_stdout = sys.stdout
166 self.__old_stderr= sys.stderr
158 self.__old_stderr= sys.stderr
167 self.__old_help_output = pydoc.help.output
159 self.__old_help_output = pydoc.help.output
168 self.__old_display_hook = sys.displayhook
160 self.__old_display_hook = sys.displayhook
169
161
170
162
171 def capture_output(self):
163 def capture_output(self):
172 """ Capture all the output mechanisms we can think of.
164 """ Capture all the output mechanisms we can think of.
173 """
165 """
174 self.save_output_hooks()
166 self.save_output_hooks()
175 Term.cout.write = self.write
167 Term.cout.write = self.write
176 Term.cerr.write = self.write
168 Term.cerr.write = self.write
177 sys.stdout = Term.cout
169 sys.stdout = Term.cout
178 sys.stderr = Term.cerr
170 sys.stderr = Term.cerr
179 pydoc.help.output = self.shell.output_trap.out
171 pydoc.help.output = self.shell.output_trap.out
180
172
181
173
182 def release_output(self):
174 def release_output(self):
183 """ Release all the different captures we have made.
175 """ Release all the different captures we have made.
184 """
176 """
185 Term.cout.write = self.__old_cout_write
177 Term.cout.write = self.__old_cout_write
186 Term.cerr.write = self.__old_cerr_write
178 Term.cerr.write = self.__old_cerr_write
187 sys.stdout = self.__old_stdout
179 sys.stdout = self.__old_stdout
188 sys.stderr = self.__old_stderr
180 sys.stderr = self.__old_stderr
189 pydoc.help.output = self.__old_help_output
181 pydoc.help.output = self.__old_help_output
190 sys.displayhook = self.__old_display_hook
182 sys.displayhook = self.__old_display_hook
191
183
192
184
193 def complete(self, line):
185 def complete(self, line):
194 # FIXME: This should be factored out in the linefrontendbase
186 # FIXME: This should be factored out in the linefrontendbase
195 # method.
187 # method.
196 word = self._get_completion_text(line)
188 word = self._get_completion_text(line)
197 completions = self.ipython0.complete(word)
189 completions = self.ipython0.complete(word)
198 # FIXME: The proper sort should be done in the complete method.
190 # FIXME: The proper sort should be done in the complete method.
199 key = lambda x: x.replace('_', '')
191 key = lambda x: x.replace('_', '')
200 completions.sort(key=key)
192 completions.sort(key=key)
201 if completions:
193 if completions:
202 prefix = common_prefix(completions)
194 prefix = common_prefix(completions)
203 line = line[:-len(word)] + prefix
195 line = line[:-len(word)] + prefix
204 return line, completions
196 return line, completions
205
197
206 #--------------------------------------------------------------------------
198 #--------------------------------------------------------------------------
207 # LineFrontEndBase interface
199 # LineFrontEndBase interface
208 #--------------------------------------------------------------------------
200 #--------------------------------------------------------------------------
209
201
210 def prefilter_input(self, input_string):
202 def prefilter_input(self, input_string):
211 """ Using IPython0 to prefilter the commands to turn them
203 """ Using IPython0 to prefilter the commands to turn them
212 in executable statements that are valid Python strings.
204 in executable statements that are valid Python strings.
213 """
205 """
214 input_string = LineFrontEndBase.prefilter_input(self, input_string)
206 input_string = LineFrontEndBase.prefilter_input(self, input_string)
215 filtered_lines = []
207 filtered_lines = []
216 # The IPython0 prefilters sometime produce output. We need to
208 # The IPython0 prefilters sometime produce output. We need to
217 # capture it.
209 # capture it.
218 self.capture_output()
210 self.capture_output()
219 self.last_result = dict(number=self.prompt_number)
211 self.last_result = dict(number=self.prompt_number)
220
212
221 try:
213 try:
222 try:
214 try:
223 for line in input_string.split('\n'):
215 for line in input_string.split('\n'):
224 pf = self.ipython0.prefilter_manager.prefilter_lines
216 pf = self.ipython0.prefilter_manager.prefilter_lines
225 filtered_lines.append(pf(line, False).rstrip())
217 filtered_lines.append(pf(line, False).rstrip())
226 except:
218 except:
227 # XXX: probably not the right thing to do.
219 # XXX: probably not the right thing to do.
228 self.ipython0.showsyntaxerror()
220 self.ipython0.showsyntaxerror()
229 self.after_execute()
221 self.after_execute()
230 finally:
222 finally:
231 self.release_output()
223 self.release_output()
232
224
233 # Clean up the trailing whitespace, to avoid indentation errors
225 # Clean up the trailing whitespace, to avoid indentation errors
234 filtered_string = '\n'.join(filtered_lines)
226 filtered_string = '\n'.join(filtered_lines)
235 return filtered_string
227 return filtered_string
236
228
237 #--------------------------------------------------------------------------
229 #--------------------------------------------------------------------------
238 # PrefilterFrontEnd interface
230 # PrefilterFrontEnd interface
239 #--------------------------------------------------------------------------
231 #--------------------------------------------------------------------------
240
232
241 def system_call(self, command_string):
233 def system_call(self, command_string):
242 """ Allows for frontend to define their own system call, to be
234 """ Allows for frontend to define their own system call, to be
243 able capture output and redirect input.
235 able capture output and redirect input.
244 """
236 """
245 return os.system(command_string)
237 return os.system(command_string)
246
238
247 def do_exit(self):
239 def do_exit(self):
248 """ Exit the shell, cleanup and save the history.
240 """ Exit the shell, cleanup and save the history.
249 """
241 """
250 self.ipython0.atexit_operations()
242 self.ipython0.atexit_operations()
251
243
252 def _get_completion_text(self, line):
244 def _get_completion_text(self, line):
253 """ Returns the text to be completed by breaking the line at specified
245 """ Returns the text to be completed by breaking the line at specified
254 delimiters.
246 delimiters.
255 """
247 """
256 # Break at: spaces, '=', all parentheses (except if balanced).
248 # Break at: spaces, '=', all parentheses (except if balanced).
257 # FIXME2: In the future, we need to make the implementation similar to
249 # FIXME2: In the future, we need to make the implementation similar to
258 # that in the 'pyreadline' module (modes/basemode.py) where we break at
250 # that in the 'pyreadline' module (modes/basemode.py) where we break at
259 # each delimiter and try to complete the residual line, until we get a
251 # each delimiter and try to complete the residual line, until we get a
260 # successful list of completions.
252 # successful list of completions.
261 expression = '\s|=|,|:|\((?!.*\))|\[(?!.*\])|\{(?!.*\})'
253 expression = '\s|=|,|:|\((?!.*\))|\[(?!.*\])|\{(?!.*\})'
262 complete_sep = re.compile(expression)
254 complete_sep = re.compile(expression)
263 text = complete_sep.split(line)[-1]
255 text = complete_sep.split(line)[-1]
264 return text
256 return text
@@ -1,112 +1,109 b''
1 # encoding: utf-8
1 # encoding: utf-8
2
3 """This file contains unittests for the asyncfrontendbase module."""
2 """This file contains unittests for the asyncfrontendbase module."""
4
5 __docformat__ = "restructuredtext en"
6
3
7 # Tell nose to skip this module
4 # Tell nose to skip this module
8 __test__ = {}
5 __test__ = {}
9
6
10 #---------------------------------------------------------------------------
7 #---------------------------------------------------------------------------
11 # Copyright (C) 2008 The IPython Development Team
8 # Copyright (C) 2008-2009 The IPython Development Team
12 #
9 #
13 # Distributed under the terms of the BSD License. The full license is in
10 # Distributed under the terms of the BSD License. The full license is in
14 # the file COPYING, distributed as part of this software.
11 # the file COPYING, distributed as part of this software.
15 #---------------------------------------------------------------------------
12 #---------------------------------------------------------------------------
16
13
17 #---------------------------------------------------------------------------
14 #---------------------------------------------------------------------------
18 # Imports
15 # Imports
19 #---------------------------------------------------------------------------
16 #---------------------------------------------------------------------------
20
17
21 from twisted.trial import unittest
18 from twisted.trial import unittest
22
19
23 from IPython.frontend.asyncfrontendbase import AsyncFrontEndBase
20 from IPython.frontend.asyncfrontendbase import AsyncFrontEndBase
24 from IPython.frontend import frontendbase
21 from IPython.frontend import frontendbase
25 from IPython.kernel.engineservice import EngineService
22 from IPython.kernel.engineservice import EngineService
26 from IPython.testing.parametric import Parametric, parametric
23 from IPython.testing.parametric import Parametric, parametric
27
24
28 #-----------------------------------------------------------------------------
25 #-----------------------------------------------------------------------------
29 # Classes and functions
26 # Classes and functions
30 #-----------------------------------------------------------------------------
27 #-----------------------------------------------------------------------------
31
28
32 class FrontEndCallbackChecker(AsyncFrontEndBase):
29 class FrontEndCallbackChecker(AsyncFrontEndBase):
33 """FrontEndBase subclass for checking callbacks"""
30 """FrontEndBase subclass for checking callbacks"""
34 def __init__(self, engine=None, history=None):
31 def __init__(self, engine=None, history=None):
35 super(FrontEndCallbackChecker, self).__init__(engine=engine,
32 super(FrontEndCallbackChecker, self).__init__(engine=engine,
36 history=history)
33 history=history)
37 self.updateCalled = False
34 self.updateCalled = False
38 self.renderResultCalled = False
35 self.renderResultCalled = False
39 self.renderErrorCalled = False
36 self.renderErrorCalled = False
40
37
41 def update_cell_prompt(self, result, blockID=None):
38 def update_cell_prompt(self, result, blockID=None):
42 self.updateCalled = True
39 self.updateCalled = True
43 return result
40 return result
44
41
45 def render_result(self, result):
42 def render_result(self, result):
46 self.renderResultCalled = True
43 self.renderResultCalled = True
47 return result
44 return result
48
45
49 def render_error(self, failure):
46 def render_error(self, failure):
50 self.renderErrorCalled = True
47 self.renderErrorCalled = True
51 return failure
48 return failure
52
49
53
50
54 class TestAsyncFrontendBase(unittest.TestCase):
51 class TestAsyncFrontendBase(unittest.TestCase):
55 def setUp(self):
52 def setUp(self):
56 """Setup the EngineService and FrontEndBase"""
53 """Setup the EngineService and FrontEndBase"""
57
54
58 self.fb = FrontEndCallbackChecker(engine=EngineService())
55 self.fb = FrontEndCallbackChecker(engine=EngineService())
59
56
60 def test_implements_IFrontEnd(self):
57 def test_implements_IFrontEnd(self):
61 self.assert_(frontendbase.IFrontEnd.implementedBy(
58 self.assert_(frontendbase.IFrontEnd.implementedBy(
62 AsyncFrontEndBase))
59 AsyncFrontEndBase))
63
60
64 def test_is_complete_returns_False_for_incomplete_block(self):
61 def test_is_complete_returns_False_for_incomplete_block(self):
65 block = """def test(a):"""
62 block = """def test(a):"""
66 self.assert_(self.fb.is_complete(block) == False)
63 self.assert_(self.fb.is_complete(block) == False)
67
64
68 def test_is_complete_returns_True_for_complete_block(self):
65 def test_is_complete_returns_True_for_complete_block(self):
69 block = """def test(a): pass"""
66 block = """def test(a): pass"""
70 self.assert_(self.fb.is_complete(block))
67 self.assert_(self.fb.is_complete(block))
71 block = """a=3"""
68 block = """a=3"""
72 self.assert_(self.fb.is_complete(block))
69 self.assert_(self.fb.is_complete(block))
73
70
74 def test_blockID_added_to_result(self):
71 def test_blockID_added_to_result(self):
75 block = """3+3"""
72 block = """3+3"""
76 d = self.fb.execute(block, blockID='TEST_ID')
73 d = self.fb.execute(block, blockID='TEST_ID')
77 d.addCallback(lambda r: self.assert_(r['blockID']=='TEST_ID'))
74 d.addCallback(lambda r: self.assert_(r['blockID']=='TEST_ID'))
78 return d
75 return d
79
76
80 def test_blockID_added_to_failure(self):
77 def test_blockID_added_to_failure(self):
81 block = "raise Exception()"
78 block = "raise Exception()"
82 d = self.fb.execute(block,blockID='TEST_ID')
79 d = self.fb.execute(block,blockID='TEST_ID')
83 d.addErrback(lambda f: self.assert_(f.blockID=='TEST_ID'))
80 d.addErrback(lambda f: self.assert_(f.blockID=='TEST_ID'))
84 return d
81 return d
85
82
86 def test_callbacks_added_to_execute(self):
83 def test_callbacks_added_to_execute(self):
87 d = self.fb.execute("10+10")
84 d = self.fb.execute("10+10")
88 d.addCallback(lambda r: self.assert_(self.fb.updateCalled and self.fb.renderResultCalled))
85 d.addCallback(lambda r: self.assert_(self.fb.updateCalled and self.fb.renderResultCalled))
89 return d
86 return d
90
87
91 def test_error_callback_added_to_execute(self):
88 def test_error_callback_added_to_execute(self):
92 """Test that render_error called on execution error."""
89 """Test that render_error called on execution error."""
93
90
94 d = self.fb.execute("raise Exception()")
91 d = self.fb.execute("raise Exception()")
95 d.addErrback(lambda f: self.assert_(self.fb.renderErrorCalled))
92 d.addErrback(lambda f: self.assert_(self.fb.renderErrorCalled))
96 return d
93 return d
97
94
98 def test_history_returns_expected_block(self):
95 def test_history_returns_expected_block(self):
99 """Make sure history browsing doesn't fail."""
96 """Make sure history browsing doesn't fail."""
100
97
101 blocks = ["a=1","a=2","a=3"]
98 blocks = ["a=1","a=2","a=3"]
102 d = self.fb.execute(blocks[0])
99 d = self.fb.execute(blocks[0])
103 d.addCallback(lambda _: self.fb.execute(blocks[1]))
100 d.addCallback(lambda _: self.fb.execute(blocks[1]))
104 d.addCallback(lambda _: self.fb.execute(blocks[2]))
101 d.addCallback(lambda _: self.fb.execute(blocks[2]))
105 d.addCallback(lambda _: self.assert_(self.fb.get_history_previous("")==blocks[-2]))
102 d.addCallback(lambda _: self.assert_(self.fb.get_history_previous("")==blocks[-2]))
106 d.addCallback(lambda _: self.assert_(self.fb.get_history_previous("")==blocks[-3]))
103 d.addCallback(lambda _: self.assert_(self.fb.get_history_previous("")==blocks[-3]))
107 d.addCallback(lambda _: self.assert_(self.fb.get_history_next()==blocks[-2]))
104 d.addCallback(lambda _: self.assert_(self.fb.get_history_next()==blocks[-2]))
108 return d
105 return d
109
106
110 def test_history_returns_none_at_startup(self):
107 def test_history_returns_none_at_startup(self):
111 self.assert_(self.fb.get_history_previous("")==None)
108 self.assert_(self.fb.get_history_previous("")==None)
112 self.assert_(self.fb.get_history_next()==None)
109 self.assert_(self.fb.get_history_next()==None)
@@ -1,269 +1,268 b''
1 # encoding: utf-8
1 # encoding: utf-8
2 """
2 """
3 Test process execution and IO redirection.
3 Test process execution and IO redirection.
4 """
4 """
5
5
6 __docformat__ = "restructuredtext en"
6 __docformat__ = "restructuredtext en"
7
7
8 #-------------------------------------------------------------------------------
8 #-------------------------------------------------------------------------------
9 # Copyright (C) 2008 The IPython Development Team
9 # Copyright (C) 2008 The IPython Development Team
10 #
10 #
11 # Distributed under the terms of the BSD License. The full license is
11 # Distributed under the terms of the BSD License. The full license is
12 # in the file COPYING, distributed as part of this software.
12 # in the file COPYING, distributed as part of this software.
13 #-------------------------------------------------------------------------------
13 #-------------------------------------------------------------------------------
14
14
15 from copy import copy, deepcopy
15 from copy import copy, deepcopy
16 from cStringIO import StringIO
16 from cStringIO import StringIO
17 import string
17 import string
18 import sys
18 import sys
19
19
20 from nose.tools import assert_equal
20 from nose.tools import assert_equal
21
21
22 from IPython.frontend.prefilterfrontend import PrefilterFrontEnd
22 from IPython.frontend.prefilterfrontend import PrefilterFrontEnd
23 from IPython.testing.globalipapp import get_ipython
23 from IPython.testing.globalipapp import get_ipython
24 from IPython.testing.tools import default_argv
25
24
26 #-----------------------------------------------------------------------------
25 #-----------------------------------------------------------------------------
27 # Support utilities
26 # Support utilities
28 #-----------------------------------------------------------------------------
27 #-----------------------------------------------------------------------------
29
28
30 class TestPrefilterFrontEnd(PrefilterFrontEnd):
29 class TestPrefilterFrontEnd(PrefilterFrontEnd):
31
30
32 input_prompt_template = string.Template('')
31 input_prompt_template = string.Template('')
33 output_prompt_template = string.Template('')
32 output_prompt_template = string.Template('')
34 banner = ''
33 banner = ''
35
34
36 def __init__(self):
35 def __init__(self):
37 self.out = StringIO()
36 self.out = StringIO()
38 PrefilterFrontEnd.__init__(self,argv=default_argv())
37 PrefilterFrontEnd.__init__(self)
39 # Some more code for isolation (yeah, crazy)
38 # Some more code for isolation (yeah, crazy)
40 self._on_enter()
39 self._on_enter()
41 self.out.flush()
40 self.out.flush()
42 self.out.reset()
41 self.out.reset()
43 self.out.truncate()
42 self.out.truncate()
44
43
45 def write(self, string, *args, **kwargs):
44 def write(self, string, *args, **kwargs):
46 self.out.write(string)
45 self.out.write(string)
47
46
48 def _on_enter(self):
47 def _on_enter(self):
49 self.input_buffer += '\n'
48 self.input_buffer += '\n'
50 PrefilterFrontEnd._on_enter(self)
49 PrefilterFrontEnd._on_enter(self)
51
50
52
51
53 def isolate_ipython0(func):
52 def isolate_ipython0(func):
54 """ Decorator to isolate execution that involves an iptyhon0.
53 """ Decorator to isolate execution that involves an iptyhon0.
55
54
56 Notes
55 Notes
57 -----
56 -----
58
57
59 Apply only to functions with no arguments. Nose skips functions
58 Apply only to functions with no arguments. Nose skips functions
60 with arguments.
59 with arguments.
61 """
60 """
62 def my_func():
61 def my_func():
63 ip0 = get_ipython()
62 ip0 = get_ipython()
64 if ip0 is None:
63 if ip0 is None:
65 return func()
64 return func()
66 # We have a real ipython running...
65 # We have a real ipython running...
67 user_ns = ip0.user_ns
66 user_ns = ip0.user_ns
68 user_global_ns = ip0.user_global_ns
67 user_global_ns = ip0.user_global_ns
69
68
70 # Previously the isolation was attempted with a deep copy of the user
69 # Previously the isolation was attempted with a deep copy of the user
71 # dicts, but we found cases where this didn't work correctly. I'm not
70 # dicts, but we found cases where this didn't work correctly. I'm not
72 # quite sure why, but basically it did damage the user namespace, such
71 # quite sure why, but basically it did damage the user namespace, such
73 # that later tests stopped working correctly. Instead we use a simpler
72 # that later tests stopped working correctly. Instead we use a simpler
74 # approach, just computing the list of added keys to the namespace and
73 # approach, just computing the list of added keys to the namespace and
75 # eliminating those afterwards. Existing keys that may have been
74 # eliminating those afterwards. Existing keys that may have been
76 # modified remain modified. So far this has proven to be robust.
75 # modified remain modified. So far this has proven to be robust.
77
76
78 # Compute set of old local/global keys
77 # Compute set of old local/global keys
79 old_locals = set(user_ns.keys())
78 old_locals = set(user_ns.keys())
80 old_globals = set(user_global_ns.keys())
79 old_globals = set(user_global_ns.keys())
81 try:
80 try:
82 out = func()
81 out = func()
83 finally:
82 finally:
84 # Find new keys, and if any, remove them
83 # Find new keys, and if any, remove them
85 new_locals = set(user_ns.keys()) - old_locals
84 new_locals = set(user_ns.keys()) - old_locals
86 new_globals = set(user_global_ns.keys()) - old_globals
85 new_globals = set(user_global_ns.keys()) - old_globals
87 for k in new_locals:
86 for k in new_locals:
88 del user_ns[k]
87 del user_ns[k]
89 for k in new_globals:
88 for k in new_globals:
90 del user_global_ns[k]
89 del user_global_ns[k]
91 return out
90 return out
92
91
93 my_func.__name__ = func.__name__
92 my_func.__name__ = func.__name__
94 return my_func
93 return my_func
95
94
96 #-----------------------------------------------------------------------------
95 #-----------------------------------------------------------------------------
97 # Tests
96 # Tests
98 #-----------------------------------------------------------------------------
97 #-----------------------------------------------------------------------------
99
98
100 @isolate_ipython0
99 @isolate_ipython0
101 def test_execution():
100 def test_execution():
102 """ Test execution of a command.
101 """ Test execution of a command.
103 """
102 """
104 f = TestPrefilterFrontEnd()
103 f = TestPrefilterFrontEnd()
105 f.input_buffer = 'print(1)'
104 f.input_buffer = 'print(1)'
106 f._on_enter()
105 f._on_enter()
107 out_value = f.out.getvalue()
106 out_value = f.out.getvalue()
108 assert_equal(out_value, '1\n')
107 assert_equal(out_value, '1\n')
109
108
110
109
111 @isolate_ipython0
110 @isolate_ipython0
112 def test_multiline():
111 def test_multiline():
113 """ Test execution of a multiline command.
112 """ Test execution of a multiline command.
114 """
113 """
115 f = TestPrefilterFrontEnd()
114 f = TestPrefilterFrontEnd()
116 f.input_buffer = 'if True:'
115 f.input_buffer = 'if True:'
117 f._on_enter()
116 f._on_enter()
118 f.input_buffer += 'print 1'
117 f.input_buffer += 'print 1'
119 f._on_enter()
118 f._on_enter()
120 out_value = f.out.getvalue()
119 out_value = f.out.getvalue()
121 yield assert_equal, out_value, ''
120 yield assert_equal, out_value, ''
122 f._on_enter()
121 f._on_enter()
123 out_value = f.out.getvalue()
122 out_value = f.out.getvalue()
124 yield assert_equal, out_value, '1\n'
123 yield assert_equal, out_value, '1\n'
125 f = TestPrefilterFrontEnd()
124 f = TestPrefilterFrontEnd()
126 f.input_buffer='(1 +'
125 f.input_buffer='(1 +'
127 f._on_enter()
126 f._on_enter()
128 f.input_buffer += '0)'
127 f.input_buffer += '0)'
129 f._on_enter()
128 f._on_enter()
130 out_value = f.out.getvalue()
129 out_value = f.out.getvalue()
131 yield assert_equal, out_value, ''
130 yield assert_equal, out_value, ''
132 f._on_enter()
131 f._on_enter()
133 out_value = f.out.getvalue()
132 out_value = f.out.getvalue()
134 yield assert_equal, out_value, '1\n'
133 yield assert_equal, out_value, '1\n'
135
134
136
135
137 @isolate_ipython0
136 @isolate_ipython0
138 def test_capture():
137 def test_capture():
139 """ Test the capture of output in different channels.
138 """ Test the capture of output in different channels.
140 """
139 """
141 # Test on the OS-level stdout, stderr.
140 # Test on the OS-level stdout, stderr.
142 f = TestPrefilterFrontEnd()
141 f = TestPrefilterFrontEnd()
143 f.input_buffer = \
142 f.input_buffer = \
144 'import os; out=os.fdopen(1, "w"); out.write("1") ; out.flush()'
143 'import os; out=os.fdopen(1, "w"); out.write("1") ; out.flush()'
145 f._on_enter()
144 f._on_enter()
146 out_value = f.out.getvalue()
145 out_value = f.out.getvalue()
147 yield assert_equal, out_value, '1'
146 yield assert_equal, out_value, '1'
148 f = TestPrefilterFrontEnd()
147 f = TestPrefilterFrontEnd()
149 f.input_buffer = \
148 f.input_buffer = \
150 'import os; out=os.fdopen(2, "w"); out.write("1") ; out.flush()'
149 'import os; out=os.fdopen(2, "w"); out.write("1") ; out.flush()'
151 f._on_enter()
150 f._on_enter()
152 out_value = f.out.getvalue()
151 out_value = f.out.getvalue()
153 yield assert_equal, out_value, '1'
152 yield assert_equal, out_value, '1'
154
153
155
154
156 @isolate_ipython0
155 @isolate_ipython0
157 def test_magic():
156 def test_magic():
158 """ Test the magic expansion and history.
157 """ Test the magic expansion and history.
159
158
160 This test is fairly fragile and will break when magics change.
159 This test is fairly fragile and will break when magics change.
161 """
160 """
162 f = TestPrefilterFrontEnd()
161 f = TestPrefilterFrontEnd()
163 # Before checking the interactive namespace, make sure it's clear (it can
162 # Before checking the interactive namespace, make sure it's clear (it can
164 # otherwise pick up things stored in the user's local db)
163 # otherwise pick up things stored in the user's local db)
165 f.input_buffer += '%reset -f'
164 f.input_buffer += '%reset -f'
166 f._on_enter()
165 f._on_enter()
167 f.complete_current_input()
166 f.complete_current_input()
168 # Now, run the %who magic and check output
167 # Now, run the %who magic and check output
169 f.input_buffer += '%who'
168 f.input_buffer += '%who'
170 f._on_enter()
169 f._on_enter()
171 out_value = f.out.getvalue()
170 out_value = f.out.getvalue()
172 assert_equal(out_value, 'Interactive namespace is empty.\n')
171 assert_equal(out_value, 'Interactive namespace is empty.\n')
173
172
174
173
175 @isolate_ipython0
174 @isolate_ipython0
176 def test_help():
175 def test_help():
177 """ Test object inspection.
176 """ Test object inspection.
178 """
177 """
179 f = TestPrefilterFrontEnd()
178 f = TestPrefilterFrontEnd()
180 f.input_buffer += "def f():"
179 f.input_buffer += "def f():"
181 f._on_enter()
180 f._on_enter()
182 f.input_buffer += "'foobar'"
181 f.input_buffer += "'foobar'"
183 f._on_enter()
182 f._on_enter()
184 f.input_buffer += "pass"
183 f.input_buffer += "pass"
185 f._on_enter()
184 f._on_enter()
186 f._on_enter()
185 f._on_enter()
187 f.input_buffer += "f?"
186 f.input_buffer += "f?"
188 f._on_enter()
187 f._on_enter()
189 assert 'traceback' not in f.last_result
188 assert 'traceback' not in f.last_result
190 ## XXX: ipython doctest magic breaks this. I have no clue why
189 ## XXX: ipython doctest magic breaks this. I have no clue why
191 #out_value = f.out.getvalue()
190 #out_value = f.out.getvalue()
192 #assert out_value.split()[-1] == 'foobar'
191 #assert out_value.split()[-1] == 'foobar'
193
192
194
193
195 @isolate_ipython0
194 @isolate_ipython0
196 def test_completion_simple():
195 def test_completion_simple():
197 """ Test command-line completion on trivial examples.
196 """ Test command-line completion on trivial examples.
198 """
197 """
199 f = TestPrefilterFrontEnd()
198 f = TestPrefilterFrontEnd()
200 f.input_buffer = 'zzza = 1'
199 f.input_buffer = 'zzza = 1'
201 f._on_enter()
200 f._on_enter()
202 f.input_buffer = 'zzzb = 2'
201 f.input_buffer = 'zzzb = 2'
203 f._on_enter()
202 f._on_enter()
204 f.input_buffer = 'zz'
203 f.input_buffer = 'zz'
205 f.complete_current_input()
204 f.complete_current_input()
206 out_value = f.out.getvalue()
205 out_value = f.out.getvalue()
207 yield assert_equal, out_value, '\nzzza zzzb '
206 yield assert_equal, out_value, '\nzzza zzzb '
208 yield assert_equal, f.input_buffer, 'zzz'
207 yield assert_equal, f.input_buffer, 'zzz'
209
208
210
209
211 @isolate_ipython0
210 @isolate_ipython0
212 def test_completion_parenthesis():
211 def test_completion_parenthesis():
213 """ Test command-line completion when a parenthesis is open.
212 """ Test command-line completion when a parenthesis is open.
214 """
213 """
215 f = TestPrefilterFrontEnd()
214 f = TestPrefilterFrontEnd()
216 f.input_buffer = 'zzza = 1'
215 f.input_buffer = 'zzza = 1'
217 f._on_enter()
216 f._on_enter()
218 f.input_buffer = 'zzzb = 2'
217 f.input_buffer = 'zzzb = 2'
219 f._on_enter()
218 f._on_enter()
220 f.input_buffer = 'map(zz'
219 f.input_buffer = 'map(zz'
221 f.complete_current_input()
220 f.complete_current_input()
222 out_value = f.out.getvalue()
221 out_value = f.out.getvalue()
223 yield assert_equal, out_value, '\nzzza zzzb '
222 yield assert_equal, out_value, '\nzzza zzzb '
224 yield assert_equal, f.input_buffer, 'map(zzz'
223 yield assert_equal, f.input_buffer, 'map(zzz'
225
224
226
225
227 @isolate_ipython0
226 @isolate_ipython0
228 def test_completion_indexing():
227 def test_completion_indexing():
229 """ Test command-line completion when indexing on objects.
228 """ Test command-line completion when indexing on objects.
230 """
229 """
231 f = TestPrefilterFrontEnd()
230 f = TestPrefilterFrontEnd()
232 f.input_buffer = 'a = [0]'
231 f.input_buffer = 'a = [0]'
233 f._on_enter()
232 f._on_enter()
234 f.input_buffer = 'a[0].'
233 f.input_buffer = 'a[0].'
235 f.complete_current_input()
234 f.complete_current_input()
236
235
237 if sys.version_info[:2] >= (2,6):
236 if sys.version_info[:2] >= (2,6):
238 # In Python 2.6, ints picked up a few non __ methods, so now there are
237 # In Python 2.6, ints picked up a few non __ methods, so now there are
239 # no completions.
238 # no completions.
240 assert_equal(f.input_buffer, 'a[0].')
239 assert_equal(f.input_buffer, 'a[0].')
241 else:
240 else:
242 # Right answer for 2.4/2.5
241 # Right answer for 2.4/2.5
243 assert_equal(f.input_buffer, 'a[0].__')
242 assert_equal(f.input_buffer, 'a[0].__')
244
243
245
244
246 @isolate_ipython0
245 @isolate_ipython0
247 def test_completion_equal():
246 def test_completion_equal():
248 """ Test command-line completion when the delimiter is "=", not " ".
247 """ Test command-line completion when the delimiter is "=", not " ".
249 """
248 """
250 f = TestPrefilterFrontEnd()
249 f = TestPrefilterFrontEnd()
251 f.input_buffer = 'a=1.'
250 f.input_buffer = 'a=1.'
252 f.complete_current_input()
251 f.complete_current_input()
253 if sys.version_info[:2] >= (2,6):
252 if sys.version_info[:2] >= (2,6):
254 # In Python 2.6, ints picked up a few non __ methods, so now there are
253 # In Python 2.6, ints picked up a few non __ methods, so now there are
255 # no completions.
254 # no completions.
256 assert_equal(f.input_buffer, 'a=1.')
255 assert_equal(f.input_buffer, 'a=1.')
257 else:
256 else:
258 # Right answer for 2.4/2.5
257 # Right answer for 2.4/2.5
259 assert_equal(f.input_buffer, 'a=1.__')
258 assert_equal(f.input_buffer, 'a=1.__')
260
259
261
260
262 if __name__ == '__main__':
261 if __name__ == '__main__':
263 test_magic()
262 test_magic()
264 test_help()
263 test_help()
265 test_execution()
264 test_execution()
266 test_multiline()
265 test_multiline()
267 test_capture()
266 test_capture()
268 test_completion_simple()
267 test_completion_simple()
269 test_completion_complex()
268 test_completion_complex()
@@ -1,624 +1,625 b''
1 # encoding: utf-8
1 # encoding: utf-8
2 """
2 """
3 A Wx widget to act as a console and input commands.
3 A Wx widget to act as a console and input commands.
4
4
5 This widget deals with prompts and provides an edit buffer
5 This widget deals with prompts and provides an edit buffer
6 restricted to after the last prompt.
6 restricted to after the last prompt.
7 """
7 """
8
8
9 __docformat__ = "restructuredtext en"
9 __docformat__ = "restructuredtext en"
10
10
11 #-------------------------------------------------------------------------------
11 #-------------------------------------------------------------------------------
12 # Copyright (C) 2008 The IPython Development Team
12 # Copyright (C) 2008 The IPython Development Team
13 #
13 #
14 # Distributed under the terms of the BSD License. The full license is
14 # Distributed under the terms of the BSD License. The full license is
15 # in the file COPYING, distributed as part of this software.
15 # in the file COPYING, distributed as part of this software.
16 #-------------------------------------------------------------------------------
16 #-------------------------------------------------------------------------------
17
17
18 #-------------------------------------------------------------------------------
18 #-------------------------------------------------------------------------------
19 # Imports
19 # Imports
20 #-------------------------------------------------------------------------------
20 #-------------------------------------------------------------------------------
21
21
22 import wx
22 import wx
23 import wx.stc as stc
23 import wx.stc as stc
24
24
25 from wx.py import editwindow
25 from wx.py import editwindow
26 import time
26 import time
27 import sys
27 import sys
28 import string
28 import string
29
29
30 LINESEP = '\n'
30 LINESEP = '\n'
31 if sys.platform == 'win32':
31 if sys.platform == 'win32':
32 LINESEP = '\n\r'
32 LINESEP = '\n\r'
33
33
34 import re
34 import re
35
35
36 # FIXME: Need to provide an API for non user-generated display on the
36 # FIXME: Need to provide an API for non user-generated display on the
37 # screen: this should not be editable by the user.
37 # screen: this should not be editable by the user.
38 #-------------------------------------------------------------------------------
38 #-------------------------------------------------------------------------------
39 # Constants
39 # Constants
40 #-------------------------------------------------------------------------------
40 #-------------------------------------------------------------------------------
41 _COMPLETE_BUFFER_MARKER = 31
41 _COMPLETE_BUFFER_MARKER = 31
42 _ERROR_MARKER = 30
42 _ERROR_MARKER = 30
43 _INPUT_MARKER = 29
43 _INPUT_MARKER = 29
44
44
45 _DEFAULT_SIZE = 10
45 _DEFAULT_SIZE = 10
46 if sys.platform == 'darwin':
46 if sys.platform == 'darwin':
47 _DEFAULT_SIZE = 12
47 _DEFAULT_SIZE = 12
48
48
49 _DEFAULT_STYLE = {
49 _DEFAULT_STYLE = {
50 #background definition
50 #background definition
51 'default' : 'size:%d' % _DEFAULT_SIZE,
51 'default' : 'size:%d' % _DEFAULT_SIZE,
52 'bracegood' : 'fore:#00AA00,back:#000000,bold',
52 'bracegood' : 'fore:#00AA00,back:#000000,bold',
53 'bracebad' : 'fore:#FF0000,back:#000000,bold',
53 'bracebad' : 'fore:#FF0000,back:#000000,bold',
54
54
55 # Edge column: a number of None
55 # Edge column: a number of None
56 'edge_column' : -1,
56 'edge_column' : -1,
57
57
58 # properties for the various Python lexer styles
58 # properties for the various Python lexer styles
59 'comment' : 'fore:#007F00',
59 'comment' : 'fore:#007F00',
60 'number' : 'fore:#007F7F',
60 'number' : 'fore:#007F7F',
61 'string' : 'fore:#7F007F,italic',
61 'string' : 'fore:#7F007F,italic',
62 'char' : 'fore:#7F007F,italic',
62 'char' : 'fore:#7F007F,italic',
63 'keyword' : 'fore:#00007F,bold',
63 'keyword' : 'fore:#00007F,bold',
64 'triple' : 'fore:#7F0000',
64 'triple' : 'fore:#7F0000',
65 'tripledouble' : 'fore:#7F0000',
65 'tripledouble' : 'fore:#7F0000',
66 'class' : 'fore:#0000FF,bold,underline',
66 'class' : 'fore:#0000FF,bold,underline',
67 'def' : 'fore:#007F7F,bold',
67 'def' : 'fore:#007F7F,bold',
68 'operator' : 'bold',
68 'operator' : 'bold',
69
69
70 # Default colors
70 # Default colors
71 'trace' : '#FAFAF1', # Nice green
71 'trace' : '#FAFAF1', # Nice green
72 'stdout' : '#FDFFD3', # Nice yellow
72 'stdout' : '#FDFFD3', # Nice yellow
73 'stderr' : '#FFF1F1', # Nice red
73 'stderr' : '#FFF1F1', # Nice red
74
74
75 # Default scintilla settings
75 # Default scintilla settings
76 'antialiasing' : True,
76 'antialiasing' : True,
77 'carret_color' : 'BLACK',
77 'carret_color' : 'BLACK',
78 'background_color' :'WHITE',
78 'background_color' :'WHITE',
79
79
80 #prompt definition
80 #prompt definition
81 'prompt_in1' : \
81 'prompt_in1' : \
82 '\n\x01\x1b[0;34m\x02In [\x01\x1b[1;34m\x02$number\x01\x1b[0;34m\x02]: \x01\x1b[0m\x02',
82 '\n\x01\x1b[0;34m\x02In [\x01\x1b[1;34m\x02$number\x01\x1b[0;34m\x02]: \x01\x1b[0m\x02',
83
83
84 'prompt_out': \
84 'prompt_out': \
85 '\x01\x1b[0;31m\x02Out[\x01\x1b[1;31m\x02$number\x01\x1b[0;31m\x02]: \x01\x1b[0m\x02',
85 '\x01\x1b[0;31m\x02Out[\x01\x1b[1;31m\x02$number\x01\x1b[0;31m\x02]: \x01\x1b[0m\x02',
86 }
86 }
87
87
88 # new style numbers
88 # new style numbers
89 _STDOUT_STYLE = 15
89 _STDOUT_STYLE = 15
90 _STDERR_STYLE = 16
90 _STDERR_STYLE = 16
91 _TRACE_STYLE = 17
91 _TRACE_STYLE = 17
92
92
93
93
94 # system colors
94 # system colors
95 #SYS_COLOUR_BACKGROUND = wx.SystemSettings.GetColour(wx.SYS_COLOUR_BACKGROUND)
95 #SYS_COLOUR_BACKGROUND = wx.SystemSettings.GetColour(wx.SYS_COLOUR_BACKGROUND)
96
96
97 # Translation table from ANSI escape sequences to color.
97 # Translation table from ANSI escape sequences to color.
98 ANSI_STYLES = {'0;30': [0, 'BLACK'], '0;31': [1, 'RED'],
98 ANSI_STYLES = {'0;30': [0, 'BLACK'], '0;31': [1, 'RED'],
99 '0;32': [2, 'GREEN'], '0;33': [3, 'BROWN'],
99 '0;32': [2, 'GREEN'], '0;33': [3, 'BROWN'],
100 '0;34': [4, 'BLUE'], '0;35': [5, 'PURPLE'],
100 '0;34': [4, 'BLUE'], '0;35': [5, 'PURPLE'],
101 '0;36': [6, 'CYAN'], '0;37': [7, 'LIGHT GREY'],
101 '0;36': [6, 'CYAN'], '0;37': [7, 'LIGHT GREY'],
102 '1;30': [8, 'DARK GREY'], '1;31': [9, 'RED'],
102 '1;30': [8, 'DARK GREY'], '1;31': [9, 'RED'],
103 '1;32': [10, 'SEA GREEN'], '1;33': [11, 'YELLOW'],
103 '1;32': [10, 'SEA GREEN'], '1;33': [11, 'YELLOW'],
104 '1;34': [12, 'LIGHT BLUE'], '1;35':
104 '1;34': [12, 'LIGHT BLUE'], '1;35':
105 [13, 'MEDIUM VIOLET RED'],
105 [13, 'MEDIUM VIOLET RED'],
106 '1;36': [14, 'LIGHT STEEL BLUE'], '1;37': [15, 'YELLOW']}
106 '1;36': [14, 'LIGHT STEEL BLUE'], '1;37': [15, 'YELLOW']}
107
107
108 # XXX: Maybe one day we should factor this code with coloransi. Right now
108 # XXX: Maybe one day we should factor this code with coloransi. Right now
109 # coloransi is hard to reuse and makes our code more complex.
109 # coloransi is hard to reuse and makes our code more complex.
110
110
111 #we define platform specific fonts
111 #we define platform specific fonts
112 if wx.Platform == '__WXMSW__':
112 if wx.Platform == '__WXMSW__':
113 FACES = { 'times': 'Times New Roman',
113 FACES = { 'times': 'Times New Roman',
114 'mono' : 'Courier New',
114 'mono' : 'Courier New',
115 'helv' : 'Arial',
115 'helv' : 'Arial',
116 'other': 'Comic Sans MS',
116 'other': 'Comic Sans MS',
117 'size' : 10,
117 'size' : 10,
118 'size2': 8,
118 'size2': 8,
119 }
119 }
120 elif wx.Platform == '__WXMAC__':
120 elif wx.Platform == '__WXMAC__':
121 FACES = { 'times': 'Times New Roman',
121 FACES = { 'times': 'Times New Roman',
122 'mono' : 'Monaco',
122 'mono' : 'Monaco',
123 'helv' : 'Arial',
123 'helv' : 'Arial',
124 'other': 'Comic Sans MS',
124 'other': 'Comic Sans MS',
125 'size' : 10,
125 'size' : 10,
126 'size2': 8,
126 'size2': 8,
127 }
127 }
128 else:
128 else:
129 FACES = { 'times': 'Times',
129 FACES = { 'times': 'Times',
130 'mono' : 'Courier',
130 'mono' : 'Courier',
131 'helv' : 'Helvetica',
131 'helv' : 'Helvetica',
132 'other': 'new century schoolbook',
132 'other': 'new century schoolbook',
133 'size' : 10,
133 'size' : 10,
134 'size2': 8,
134 'size2': 8,
135 }
135 }
136
136
137
137
138 #-------------------------------------------------------------------------------
138 #-----------------------------------------------------------------------------
139 # The console widget class
139 # The console widget class
140 #-------------------------------------------------------------------------------
140 #-----------------------------------------------------------------------------
141
141 class ConsoleWidget(editwindow.EditWindow):
142 class ConsoleWidget(editwindow.EditWindow):
142 """ Specialized styled text control view for console-like workflow.
143 """ Specialized styled text control view for console-like workflow.
143
144
144 This widget is mainly interested in dealing with the prompt and
145 This widget is mainly interested in dealing with the prompt and
145 keeping the cursor inside the editing line.
146 keeping the cursor inside the editing line.
146 """
147 """
147
148
148 # This is where the title captured from the ANSI escape sequences are
149 # This is where the title captured from the ANSI escape sequences are
149 # stored.
150 # stored.
150 title = 'Console'
151 title = 'Console'
151
152
152 # Last prompt printed
153 # Last prompt printed
153 last_prompt = ''
154 last_prompt = ''
154
155
155 # The buffer being edited.
156 # The buffer being edited.
156 def _set_input_buffer(self, string):
157 def _set_input_buffer(self, string):
157 self.SetSelection(self.current_prompt_pos, self.GetLength())
158 self.SetSelection(self.current_prompt_pos, self.GetLength())
158 self.ReplaceSelection(string)
159 self.ReplaceSelection(string)
159 self.GotoPos(self.GetLength())
160 self.GotoPos(self.GetLength())
160
161
161 def _get_input_buffer(self):
162 def _get_input_buffer(self):
162 """ Returns the text in current edit buffer.
163 """ Returns the text in current edit buffer.
163 """
164 """
164 input_buffer = self.GetTextRange(self.current_prompt_pos,
165 input_buffer = self.GetTextRange(self.current_prompt_pos,
165 self.GetLength())
166 self.GetLength())
166 input_buffer = input_buffer.replace(LINESEP, '\n')
167 input_buffer = input_buffer.replace(LINESEP, '\n')
167 return input_buffer
168 return input_buffer
168
169
169 input_buffer = property(_get_input_buffer, _set_input_buffer)
170 input_buffer = property(_get_input_buffer, _set_input_buffer)
170
171
171 style = _DEFAULT_STYLE.copy()
172 style = _DEFAULT_STYLE.copy()
172
173
173 # Translation table from ANSI escape sequences to color. Override
174 # Translation table from ANSI escape sequences to color. Override
174 # this to specify your colors.
175 # this to specify your colors.
175 ANSI_STYLES = ANSI_STYLES.copy()
176 ANSI_STYLES = ANSI_STYLES.copy()
176
177
177 # Font faces
178 # Font faces
178 faces = FACES.copy()
179 faces = FACES.copy()
179
180
180 # Store the last time a refresh was done
181 # Store the last time a refresh was done
181 _last_refresh_time = 0
182 _last_refresh_time = 0
182
183
183 #--------------------------------------------------------------------------
184 #--------------------------------------------------------------------------
184 # Public API
185 # Public API
185 #--------------------------------------------------------------------------
186 #--------------------------------------------------------------------------
186
187
187 def __init__(self, parent, id=wx.ID_ANY, pos=wx.DefaultPosition,
188 def __init__(self, parent, id=wx.ID_ANY, pos=wx.DefaultPosition,
188 size=wx.DefaultSize, style=wx.WANTS_CHARS, ):
189 size=wx.DefaultSize, style=wx.WANTS_CHARS, ):
189 editwindow.EditWindow.__init__(self, parent, id, pos, size, style)
190 editwindow.EditWindow.__init__(self, parent, id, pos, size, style)
190 self.configure_scintilla()
191 self.configure_scintilla()
191 # Track if 'enter' key as ever been processed
192 # Track if 'enter' key as ever been processed
192 # This variable will only be reallowed until key goes up
193 # This variable will only be reallowed until key goes up
193 self.enter_catched = False
194 self.enter_catched = False
194 self.current_prompt_pos = 0
195 self.current_prompt_pos = 0
195
196
196 self.Bind(wx.EVT_KEY_DOWN, self._on_key_down)
197 self.Bind(wx.EVT_KEY_DOWN, self._on_key_down)
197 self.Bind(wx.EVT_KEY_UP, self._on_key_up)
198 self.Bind(wx.EVT_KEY_UP, self._on_key_up)
198
199
199
200
200 def write(self, text, refresh=True):
201 def write(self, text, refresh=True):
201 """ Write given text to buffer, while translating the ansi escape
202 """ Write given text to buffer, while translating the ansi escape
202 sequences.
203 sequences.
203 """
204 """
204 # XXX: do not put print statements to sys.stdout/sys.stderr in
205 # XXX: do not put print statements to sys.stdout/sys.stderr in
205 # this method, the print statements will call this method, as
206 # this method, the print statements will call this method, as
206 # you will end up with an infinit loop
207 # you will end up with an infinit loop
207 title = self.title_pat.split(text)
208 title = self.title_pat.split(text)
208 if len(title)>1:
209 if len(title)>1:
209 self.title = title[-2]
210 self.title = title[-2]
210
211
211 text = self.title_pat.sub('', text)
212 text = self.title_pat.sub('', text)
212 segments = self.color_pat.split(text)
213 segments = self.color_pat.split(text)
213 segment = segments.pop(0)
214 segment = segments.pop(0)
214 self.GotoPos(self.GetLength())
215 self.GotoPos(self.GetLength())
215 self.StartStyling(self.GetLength(), 0xFF)
216 self.StartStyling(self.GetLength(), 0xFF)
216 try:
217 try:
217 self.AppendText(segment)
218 self.AppendText(segment)
218 except UnicodeDecodeError:
219 except UnicodeDecodeError:
219 # XXX: Do I really want to skip the exception?
220 # XXX: Do I really want to skip the exception?
220 pass
221 pass
221
222
222 if segments:
223 if segments:
223 for ansi_tag, text in zip(segments[::2], segments[1::2]):
224 for ansi_tag, text in zip(segments[::2], segments[1::2]):
224 self.StartStyling(self.GetLength(), 0xFF)
225 self.StartStyling(self.GetLength(), 0xFF)
225 try:
226 try:
226 self.AppendText(text)
227 self.AppendText(text)
227 except UnicodeDecodeError:
228 except UnicodeDecodeError:
228 # XXX: Do I really want to skip the exception?
229 # XXX: Do I really want to skip the exception?
229 pass
230 pass
230
231
231 if ansi_tag not in self.ANSI_STYLES:
232 if ansi_tag not in self.ANSI_STYLES:
232 style = 0
233 style = 0
233 else:
234 else:
234 style = self.ANSI_STYLES[ansi_tag][0]
235 style = self.ANSI_STYLES[ansi_tag][0]
235
236
236 self.SetStyling(len(text), style)
237 self.SetStyling(len(text), style)
237
238
238 self.GotoPos(self.GetLength())
239 self.GotoPos(self.GetLength())
239 if refresh:
240 if refresh:
240 current_time = time.time()
241 current_time = time.time()
241 if current_time - self._last_refresh_time > 0.03:
242 if current_time - self._last_refresh_time > 0.03:
242 if sys.platform == 'win32':
243 if sys.platform == 'win32':
243 wx.SafeYield()
244 wx.SafeYield()
244 else:
245 else:
245 wx.Yield()
246 wx.Yield()
246 # self.ProcessEvent(wx.PaintEvent())
247 # self.ProcessEvent(wx.PaintEvent())
247 self._last_refresh_time = current_time
248 self._last_refresh_time = current_time
248
249
249
250
250 def new_prompt(self, prompt):
251 def new_prompt(self, prompt):
251 """ Prints a prompt at start of line, and move the start of the
252 """ Prints a prompt at start of line, and move the start of the
252 current block there.
253 current block there.
253
254
254 The prompt can be given with ascii escape sequences.
255 The prompt can be given with ascii escape sequences.
255 """
256 """
256 self.write(prompt, refresh=False)
257 self.write(prompt, refresh=False)
257 # now we update our cursor giving end of prompt
258 # now we update our cursor giving end of prompt
258 self.current_prompt_pos = self.GetLength()
259 self.current_prompt_pos = self.GetLength()
259 self.current_prompt_line = self.GetCurrentLine()
260 self.current_prompt_line = self.GetCurrentLine()
260 self.EnsureCaretVisible()
261 self.EnsureCaretVisible()
261 self.last_prompt = prompt
262 self.last_prompt = prompt
262
263
263
264
264 def continuation_prompt(self):
265 def continuation_prompt(self):
265 """ Returns the current continuation prompt.
266 """ Returns the current continuation prompt.
266 We need to implement this method here to deal with the
267 We need to implement this method here to deal with the
267 ascii escape sequences cleaning up.
268 ascii escape sequences cleaning up.
268 """
269 """
269 # ASCII-less prompt
270 # ASCII-less prompt
270 ascii_less = ''.join(self.color_pat.split(self.last_prompt)[2::2])
271 ascii_less = ''.join(self.color_pat.split(self.last_prompt)[2::2])
271 return "."*(len(ascii_less)-2) + ': '
272 return "."*(len(ascii_less)-2) + ': '
272
273
273
274
274 def scroll_to_bottom(self):
275 def scroll_to_bottom(self):
275 maxrange = self.GetScrollRange(wx.VERTICAL)
276 maxrange = self.GetScrollRange(wx.VERTICAL)
276 self.ScrollLines(maxrange)
277 self.ScrollLines(maxrange)
277
278
278
279
279 def pop_completion(self, possibilities, offset=0):
280 def pop_completion(self, possibilities, offset=0):
280 """ Pops up an autocompletion menu. Offset is the offset
281 """ Pops up an autocompletion menu. Offset is the offset
281 in characters of the position at which the menu should
282 in characters of the position at which the menu should
282 appear, relativ to the cursor.
283 appear, relativ to the cursor.
283 """
284 """
284 self.AutoCompSetIgnoreCase(False)
285 self.AutoCompSetIgnoreCase(False)
285 self.AutoCompSetAutoHide(False)
286 self.AutoCompSetAutoHide(False)
286 self.AutoCompSetMaxHeight(len(possibilities))
287 self.AutoCompSetMaxHeight(len(possibilities))
287 self.AutoCompShow(offset, " ".join(possibilities))
288 self.AutoCompShow(offset, " ".join(possibilities))
288
289
289
290
290 def get_line_width(self):
291 def get_line_width(self):
291 """ Return the width of the line in characters.
292 """ Return the width of the line in characters.
292 """
293 """
293 return self.GetSize()[0]/self.GetCharWidth()
294 return self.GetSize()[0]/self.GetCharWidth()
294
295
295
296
296 def configure_scintilla(self):
297 def configure_scintilla(self):
297 """ Set up all the styling option of the embedded scintilla
298 """ Set up all the styling option of the embedded scintilla
298 widget.
299 widget.
299 """
300 """
300 p = self.style.copy()
301 p = self.style.copy()
301
302
302 # Marker for complete buffer.
303 # Marker for complete buffer.
303 self.MarkerDefine(_COMPLETE_BUFFER_MARKER, stc.STC_MARK_BACKGROUND,
304 self.MarkerDefine(_COMPLETE_BUFFER_MARKER, stc.STC_MARK_BACKGROUND,
304 background=p['trace'])
305 background=p['trace'])
305
306
306 # Marker for current input buffer.
307 # Marker for current input buffer.
307 self.MarkerDefine(_INPUT_MARKER, stc.STC_MARK_BACKGROUND,
308 self.MarkerDefine(_INPUT_MARKER, stc.STC_MARK_BACKGROUND,
308 background=p['stdout'])
309 background=p['stdout'])
309 # Marker for tracebacks.
310 # Marker for tracebacks.
310 self.MarkerDefine(_ERROR_MARKER, stc.STC_MARK_BACKGROUND,
311 self.MarkerDefine(_ERROR_MARKER, stc.STC_MARK_BACKGROUND,
311 background=p['stderr'])
312 background=p['stderr'])
312
313
313 self.SetEOLMode(stc.STC_EOL_LF)
314 self.SetEOLMode(stc.STC_EOL_LF)
314
315
315 # Ctrl"+" or Ctrl "-" can be used to zoomin/zoomout the text inside
316 # Ctrl"+" or Ctrl "-" can be used to zoomin/zoomout the text inside
316 # the widget
317 # the widget
317 self.CmdKeyAssign(ord('+'), stc.STC_SCMOD_CTRL, stc.STC_CMD_ZOOMIN)
318 self.CmdKeyAssign(ord('+'), stc.STC_SCMOD_CTRL, stc.STC_CMD_ZOOMIN)
318 self.CmdKeyAssign(ord('-'), stc.STC_SCMOD_CTRL, stc.STC_CMD_ZOOMOUT)
319 self.CmdKeyAssign(ord('-'), stc.STC_SCMOD_CTRL, stc.STC_CMD_ZOOMOUT)
319 # Also allow Ctrl Shift "=" for poor non US keyboard users.
320 # Also allow Ctrl Shift "=" for poor non US keyboard users.
320 self.CmdKeyAssign(ord('='), stc.STC_SCMOD_CTRL|stc.STC_SCMOD_SHIFT,
321 self.CmdKeyAssign(ord('='), stc.STC_SCMOD_CTRL|stc.STC_SCMOD_SHIFT,
321 stc.STC_CMD_ZOOMIN)
322 stc.STC_CMD_ZOOMIN)
322
323
323 # Keys: we need to clear some of the keys the that don't play
324 # Keys: we need to clear some of the keys the that don't play
324 # well with a console.
325 # well with a console.
325 self.CmdKeyClear(ord('D'), stc.STC_SCMOD_CTRL)
326 self.CmdKeyClear(ord('D'), stc.STC_SCMOD_CTRL)
326 self.CmdKeyClear(ord('L'), stc.STC_SCMOD_CTRL)
327 self.CmdKeyClear(ord('L'), stc.STC_SCMOD_CTRL)
327 self.CmdKeyClear(ord('T'), stc.STC_SCMOD_CTRL)
328 self.CmdKeyClear(ord('T'), stc.STC_SCMOD_CTRL)
328 self.CmdKeyClear(ord('A'), stc.STC_SCMOD_CTRL)
329 self.CmdKeyClear(ord('A'), stc.STC_SCMOD_CTRL)
329
330
330 self.SetEOLMode(stc.STC_EOL_CRLF)
331 self.SetEOLMode(stc.STC_EOL_CRLF)
331 self.SetWrapMode(stc.STC_WRAP_CHAR)
332 self.SetWrapMode(stc.STC_WRAP_CHAR)
332 self.SetWrapMode(stc.STC_WRAP_WORD)
333 self.SetWrapMode(stc.STC_WRAP_WORD)
333 self.SetBufferedDraw(True)
334 self.SetBufferedDraw(True)
334
335
335 self.SetUseAntiAliasing(p['antialiasing'])
336 self.SetUseAntiAliasing(p['antialiasing'])
336
337
337 self.SetLayoutCache(stc.STC_CACHE_PAGE)
338 self.SetLayoutCache(stc.STC_CACHE_PAGE)
338 self.SetUndoCollection(False)
339 self.SetUndoCollection(False)
339 self.SetUseTabs(True)
340 self.SetUseTabs(True)
340 self.SetIndent(4)
341 self.SetIndent(4)
341 self.SetTabWidth(4)
342 self.SetTabWidth(4)
342
343
343 # we don't want scintilla's autocompletion to choose
344 # we don't want scintilla's autocompletion to choose
344 # automaticaly out of a single choice list, as we pop it up
345 # automaticaly out of a single choice list, as we pop it up
345 # automaticaly
346 # automaticaly
346 self.AutoCompSetChooseSingle(False)
347 self.AutoCompSetChooseSingle(False)
347 self.AutoCompSetMaxHeight(10)
348 self.AutoCompSetMaxHeight(10)
348 # XXX: this doesn't seem to have an effect.
349 # XXX: this doesn't seem to have an effect.
349 self.AutoCompSetFillUps('\n')
350 self.AutoCompSetFillUps('\n')
350
351
351 self.SetMargins(3, 3) #text is moved away from border with 3px
352 self.SetMargins(3, 3) #text is moved away from border with 3px
352 # Suppressing Scintilla margins
353 # Suppressing Scintilla margins
353 self.SetMarginWidth(0, 0)
354 self.SetMarginWidth(0, 0)
354 self.SetMarginWidth(1, 0)
355 self.SetMarginWidth(1, 0)
355 self.SetMarginWidth(2, 0)
356 self.SetMarginWidth(2, 0)
356
357
357 # Xterm escape sequences
358 # Xterm escape sequences
358 self.color_pat = re.compile('\x01?\x1b\[(.*?)m\x02?')
359 self.color_pat = re.compile('\x01?\x1b\[(.*?)m\x02?')
359 self.title_pat = re.compile('\x1b]0;(.*?)\x07')
360 self.title_pat = re.compile('\x1b]0;(.*?)\x07')
360
361
361 # styles
362 # styles
362
363
363 self.SetCaretForeground(p['carret_color'])
364 self.SetCaretForeground(p['carret_color'])
364
365
365 background_color = p['background_color']
366 background_color = p['background_color']
366
367
367 if 'default' in p:
368 if 'default' in p:
368 if 'back' not in p['default']:
369 if 'back' not in p['default']:
369 p['default'] += ',back:%s' % background_color
370 p['default'] += ',back:%s' % background_color
370 if 'size' not in p['default']:
371 if 'size' not in p['default']:
371 p['default'] += ',size:%s' % self.faces['size']
372 p['default'] += ',size:%s' % self.faces['size']
372 if 'face' not in p['default']:
373 if 'face' not in p['default']:
373 p['default'] += ',face:%s' % self.faces['mono']
374 p['default'] += ',face:%s' % self.faces['mono']
374
375
375 self.StyleSetSpec(stc.STC_STYLE_DEFAULT, p['default'])
376 self.StyleSetSpec(stc.STC_STYLE_DEFAULT, p['default'])
376 else:
377 else:
377 self.StyleSetSpec(stc.STC_STYLE_DEFAULT,
378 self.StyleSetSpec(stc.STC_STYLE_DEFAULT,
378 "fore:%s,back:%s,size:%d,face:%s"
379 "fore:%s,back:%s,size:%d,face:%s"
379 % (self.ANSI_STYLES['0;30'][1],
380 % (self.ANSI_STYLES['0;30'][1],
380 background_color,
381 background_color,
381 self.faces['size'], self.faces['mono']))
382 self.faces['size'], self.faces['mono']))
382
383
383 self.StyleClearAll()
384 self.StyleClearAll()
384
385
385 # XXX: two lines below are usefull if not using the lexer
386 # XXX: two lines below are usefull if not using the lexer
386 #for style in self.ANSI_STYLES.values():
387 #for style in self.ANSI_STYLES.values():
387 # self.StyleSetSpec(style[0], "bold,fore:%s" % style[1])
388 # self.StyleSetSpec(style[0], "bold,fore:%s" % style[1])
388
389
389 # prompt definition
390 # prompt definition
390 self.prompt_in1 = p['prompt_in1']
391 self.prompt_in1 = p['prompt_in1']
391 self.prompt_out = p['prompt_out']
392 self.prompt_out = p['prompt_out']
392
393
393 self.output_prompt_template = string.Template(self.prompt_out)
394 self.output_prompt_template = string.Template(self.prompt_out)
394 self.input_prompt_template = string.Template(self.prompt_in1)
395 self.input_prompt_template = string.Template(self.prompt_in1)
395
396
396 self.StyleSetSpec(_STDOUT_STYLE, p['stdout'])
397 self.StyleSetSpec(_STDOUT_STYLE, p['stdout'])
397 self.StyleSetSpec(_STDERR_STYLE, p['stderr'])
398 self.StyleSetSpec(_STDERR_STYLE, p['stderr'])
398 self.StyleSetSpec(_TRACE_STYLE, p['trace'])
399 self.StyleSetSpec(_TRACE_STYLE, p['trace'])
399 self.StyleSetSpec(stc.STC_STYLE_BRACELIGHT, p['bracegood'])
400 self.StyleSetSpec(stc.STC_STYLE_BRACELIGHT, p['bracegood'])
400 self.StyleSetSpec(stc.STC_STYLE_BRACEBAD, p['bracebad'])
401 self.StyleSetSpec(stc.STC_STYLE_BRACEBAD, p['bracebad'])
401 self.StyleSetSpec(stc.STC_P_COMMENTLINE, p['comment'])
402 self.StyleSetSpec(stc.STC_P_COMMENTLINE, p['comment'])
402 self.StyleSetSpec(stc.STC_P_NUMBER, p['number'])
403 self.StyleSetSpec(stc.STC_P_NUMBER, p['number'])
403 self.StyleSetSpec(stc.STC_P_STRING, p['string'])
404 self.StyleSetSpec(stc.STC_P_STRING, p['string'])
404 self.StyleSetSpec(stc.STC_P_CHARACTER, p['char'])
405 self.StyleSetSpec(stc.STC_P_CHARACTER, p['char'])
405 self.StyleSetSpec(stc.STC_P_WORD, p['keyword'])
406 self.StyleSetSpec(stc.STC_P_WORD, p['keyword'])
406 self.StyleSetSpec(stc.STC_P_WORD2, p['keyword'])
407 self.StyleSetSpec(stc.STC_P_WORD2, p['keyword'])
407 self.StyleSetSpec(stc.STC_P_TRIPLE, p['triple'])
408 self.StyleSetSpec(stc.STC_P_TRIPLE, p['triple'])
408 self.StyleSetSpec(stc.STC_P_TRIPLEDOUBLE, p['tripledouble'])
409 self.StyleSetSpec(stc.STC_P_TRIPLEDOUBLE, p['tripledouble'])
409 self.StyleSetSpec(stc.STC_P_CLASSNAME, p['class'])
410 self.StyleSetSpec(stc.STC_P_CLASSNAME, p['class'])
410 self.StyleSetSpec(stc.STC_P_DEFNAME, p['def'])
411 self.StyleSetSpec(stc.STC_P_DEFNAME, p['def'])
411 self.StyleSetSpec(stc.STC_P_OPERATOR, p['operator'])
412 self.StyleSetSpec(stc.STC_P_OPERATOR, p['operator'])
412 self.StyleSetSpec(stc.STC_P_COMMENTBLOCK, p['comment'])
413 self.StyleSetSpec(stc.STC_P_COMMENTBLOCK, p['comment'])
413
414
414 edge_column = p['edge_column']
415 edge_column = p['edge_column']
415 if edge_column is not None and edge_column > 0:
416 if edge_column is not None and edge_column > 0:
416 #we add a vertical line to console widget
417 #we add a vertical line to console widget
417 self.SetEdgeMode(stc.STC_EDGE_LINE)
418 self.SetEdgeMode(stc.STC_EDGE_LINE)
418 self.SetEdgeColumn(edge_column)
419 self.SetEdgeColumn(edge_column)
419
420
420
421
421 #--------------------------------------------------------------------------
422 #--------------------------------------------------------------------------
422 # EditWindow API
423 # EditWindow API
423 #--------------------------------------------------------------------------
424 #--------------------------------------------------------------------------
424
425
425 def OnUpdateUI(self, event):
426 def OnUpdateUI(self, event):
426 """ Override the OnUpdateUI of the EditWindow class, to prevent
427 """ Override the OnUpdateUI of the EditWindow class, to prevent
427 syntax highlighting both for faster redraw, and for more
428 syntax highlighting both for faster redraw, and for more
428 consistent look and feel.
429 consistent look and feel.
429 """
430 """
430
431
431
432
432 #--------------------------------------------------------------------------
433 #--------------------------------------------------------------------------
433 # Private API
434 # Private API
434 #--------------------------------------------------------------------------
435 #--------------------------------------------------------------------------
435
436
436 def _on_key_down(self, event, skip=True):
437 def _on_key_down(self, event, skip=True):
437 """ Key press callback used for correcting behavior for
438 """ Key press callback used for correcting behavior for
438 console-like interfaces: the cursor is constraint to be after
439 console-like interfaces: the cursor is constraint to be after
439 the last prompt.
440 the last prompt.
440
441
441 Return True if event as been catched.
442 Return True if event as been catched.
442 """
443 """
443 catched = True
444 catched = True
444 # XXX: Would the right way to do this be to have a
445 # XXX: Would the right way to do this be to have a
445 # dictionary at the instance level associating keys with
446 # dictionary at the instance level associating keys with
446 # callbacks? How would we deal with inheritance? And Do the
447 # callbacks? How would we deal with inheritance? And Do the
447 # different callbacks share local variables?
448 # different callbacks share local variables?
448
449
449 # Intercept some specific keys.
450 # Intercept some specific keys.
450 key_code = event.GetKeyCode()
451 key_code = event.GetKeyCode()
451 if key_code == ord('L') and event.ControlDown() :
452 if key_code == ord('L') and event.ControlDown() :
452 self.scroll_to_bottom()
453 self.scroll_to_bottom()
453 elif key_code == ord('K') and event.ControlDown() :
454 elif key_code == ord('K') and event.ControlDown() :
454 self.input_buffer = ''
455 self.input_buffer = ''
455 elif key_code == ord('A') and event.ControlDown() :
456 elif key_code == ord('A') and event.ControlDown() :
456 self.GotoPos(self.GetLength())
457 self.GotoPos(self.GetLength())
457 self.SetSelectionStart(self.current_prompt_pos)
458 self.SetSelectionStart(self.current_prompt_pos)
458 self.SetSelectionEnd(self.GetCurrentPos())
459 self.SetSelectionEnd(self.GetCurrentPos())
459 catched = True
460 catched = True
460 elif key_code == ord('E') and event.ControlDown() :
461 elif key_code == ord('E') and event.ControlDown() :
461 self.GotoPos(self.GetLength())
462 self.GotoPos(self.GetLength())
462 catched = True
463 catched = True
463 elif key_code == wx.WXK_PAGEUP:
464 elif key_code == wx.WXK_PAGEUP:
464 self.ScrollPages(-1)
465 self.ScrollPages(-1)
465 elif key_code == wx.WXK_PAGEDOWN:
466 elif key_code == wx.WXK_PAGEDOWN:
466 self.ScrollPages(1)
467 self.ScrollPages(1)
467 elif key_code == wx.WXK_HOME:
468 elif key_code == wx.WXK_HOME:
468 self.GotoPos(self.GetLength())
469 self.GotoPos(self.GetLength())
469 elif key_code == wx.WXK_END:
470 elif key_code == wx.WXK_END:
470 self.GotoPos(self.GetLength())
471 self.GotoPos(self.GetLength())
471 elif key_code == wx.WXK_UP and event.ShiftDown():
472 elif key_code == wx.WXK_UP and event.ShiftDown():
472 self.ScrollLines(-1)
473 self.ScrollLines(-1)
473 elif key_code == wx.WXK_DOWN and event.ShiftDown():
474 elif key_code == wx.WXK_DOWN and event.ShiftDown():
474 self.ScrollLines(1)
475 self.ScrollLines(1)
475 else:
476 else:
476 catched = False
477 catched = False
477
478
478 if self.AutoCompActive():
479 if self.AutoCompActive():
479 event.Skip()
480 event.Skip()
480 else:
481 else:
481 if key_code in (13, wx.WXK_NUMPAD_ENTER):
482 if key_code in (13, wx.WXK_NUMPAD_ENTER):
482 # XXX: not catching modifiers, to be wx2.6-compatible
483 # XXX: not catching modifiers, to be wx2.6-compatible
483 catched = True
484 catched = True
484 if not self.enter_catched:
485 if not self.enter_catched:
485 self.CallTipCancel()
486 self.CallTipCancel()
486 if event.ShiftDown():
487 if event.ShiftDown():
487 # Try to force execution
488 # Try to force execution
488 self.GotoPos(self.GetLength())
489 self.GotoPos(self.GetLength())
489 self.write('\n' + self.continuation_prompt(),
490 self.write('\n' + self.continuation_prompt(),
490 refresh=False)
491 refresh=False)
491 self._on_enter()
492 self._on_enter()
492 else:
493 else:
493 self._on_enter()
494 self._on_enter()
494 self.enter_catched = True
495 self.enter_catched = True
495
496
496 elif key_code == wx.WXK_HOME:
497 elif key_code == wx.WXK_HOME:
497 if not event.ShiftDown():
498 if not event.ShiftDown():
498 self.GotoPos(self.current_prompt_pos)
499 self.GotoPos(self.current_prompt_pos)
499 catched = True
500 catched = True
500 else:
501 else:
501 # FIXME: This behavior is not ideal: if the selection
502 # FIXME: This behavior is not ideal: if the selection
502 # is already started, it will jump.
503 # is already started, it will jump.
503 self.SetSelectionStart(self.current_prompt_pos)
504 self.SetSelectionStart(self.current_prompt_pos)
504 self.SetSelectionEnd(self.GetCurrentPos())
505 self.SetSelectionEnd(self.GetCurrentPos())
505 catched = True
506 catched = True
506
507
507 elif key_code == wx.WXK_UP:
508 elif key_code == wx.WXK_UP:
508 if self.GetCurrentLine() > self.current_prompt_line:
509 if self.GetCurrentLine() > self.current_prompt_line:
509 if self.GetCurrentLine() == self.current_prompt_line + 1 \
510 if self.GetCurrentLine() == self.current_prompt_line + 1 \
510 and self.GetColumn(self.GetCurrentPos()) < \
511 and self.GetColumn(self.GetCurrentPos()) < \
511 self.GetColumn(self.current_prompt_pos):
512 self.GetColumn(self.current_prompt_pos):
512 self.GotoPos(self.current_prompt_pos)
513 self.GotoPos(self.current_prompt_pos)
513 else:
514 else:
514 event.Skip()
515 event.Skip()
515 catched = True
516 catched = True
516
517
517 elif key_code in (wx.WXK_LEFT, wx.WXK_BACK):
518 elif key_code in (wx.WXK_LEFT, wx.WXK_BACK):
518 if not self._keep_cursor_in_buffer(self.GetCurrentPos() - 1):
519 if not self._keep_cursor_in_buffer(self.GetCurrentPos() - 1):
519 event.Skip()
520 event.Skip()
520 catched = True
521 catched = True
521
522
522 elif key_code == wx.WXK_RIGHT:
523 elif key_code == wx.WXK_RIGHT:
523 if not self._keep_cursor_in_buffer(self.GetCurrentPos() + 1):
524 if not self._keep_cursor_in_buffer(self.GetCurrentPos() + 1):
524 event.Skip()
525 event.Skip()
525 catched = True
526 catched = True
526
527
527
528
528 elif key_code == wx.WXK_DELETE:
529 elif key_code == wx.WXK_DELETE:
529 if not self._keep_cursor_in_buffer(self.GetCurrentPos() - 1):
530 if not self._keep_cursor_in_buffer(self.GetCurrentPos() - 1):
530 event.Skip()
531 event.Skip()
531 catched = True
532 catched = True
532
533
533 if skip and not catched:
534 if skip and not catched:
534 # Put the cursor back in the edit region
535 # Put the cursor back in the edit region
535 if not self._keep_cursor_in_buffer():
536 if not self._keep_cursor_in_buffer():
536 if not (self.GetCurrentPos() == self.GetLength()
537 if not (self.GetCurrentPos() == self.GetLength()
537 and key_code == wx.WXK_DELETE):
538 and key_code == wx.WXK_DELETE):
538 event.Skip()
539 event.Skip()
539 catched = True
540 catched = True
540
541
541 return catched
542 return catched
542
543
543
544
544 def _on_key_up(self, event, skip=True):
545 def _on_key_up(self, event, skip=True):
545 """ If cursor is outside the editing region, put it back.
546 """ If cursor is outside the editing region, put it back.
546 """
547 """
547 if skip:
548 if skip:
548 event.Skip()
549 event.Skip()
549 self._keep_cursor_in_buffer()
550 self._keep_cursor_in_buffer()
550
551
551
552
552 # XXX: I need to avoid the problem of having an empty glass;
553 # XXX: I need to avoid the problem of having an empty glass;
553 def _keep_cursor_in_buffer(self, pos=None):
554 def _keep_cursor_in_buffer(self, pos=None):
554 """ Checks if the cursor is where it is allowed to be. If not,
555 """ Checks if the cursor is where it is allowed to be. If not,
555 put it back.
556 put it back.
556
557
557 Returns
558 Returns
558 -------
559 -------
559 cursor_moved: Boolean
560 cursor_moved: Boolean
560 whether or not the cursor was moved by this routine.
561 whether or not the cursor was moved by this routine.
561
562
562 Notes
563 Notes
563 ------
564 ------
564 WARNING: This does proper checks only for horizontal
565 WARNING: This does proper checks only for horizontal
565 movements.
566 movements.
566 """
567 """
567 if pos is None:
568 if pos is None:
568 current_pos = self.GetCurrentPos()
569 current_pos = self.GetCurrentPos()
569 else:
570 else:
570 current_pos = pos
571 current_pos = pos
571 if current_pos < self.current_prompt_pos:
572 if current_pos < self.current_prompt_pos:
572 self.GotoPos(self.current_prompt_pos)
573 self.GotoPos(self.current_prompt_pos)
573 return True
574 return True
574 line_num = self.LineFromPosition(current_pos)
575 line_num = self.LineFromPosition(current_pos)
575 if not current_pos > self.GetLength():
576 if not current_pos > self.GetLength():
576 line_pos = self.GetColumn(current_pos)
577 line_pos = self.GetColumn(current_pos)
577 else:
578 else:
578 line_pos = self.GetColumn(self.GetLength())
579 line_pos = self.GetColumn(self.GetLength())
579 line = self.GetLine(line_num)
580 line = self.GetLine(line_num)
580 # Jump the continuation prompt
581 # Jump the continuation prompt
581 continuation_prompt = self.continuation_prompt()
582 continuation_prompt = self.continuation_prompt()
582 if ( line.startswith(continuation_prompt)
583 if ( line.startswith(continuation_prompt)
583 and line_pos < len(continuation_prompt)):
584 and line_pos < len(continuation_prompt)):
584 if line_pos < 2:
585 if line_pos < 2:
585 # We are at the beginning of the line, trying to move
586 # We are at the beginning of the line, trying to move
586 # forward: jump forward.
587 # forward: jump forward.
587 self.GotoPos(current_pos + 1 +
588 self.GotoPos(current_pos + 1 +
588 len(continuation_prompt) - line_pos)
589 len(continuation_prompt) - line_pos)
589 else:
590 else:
590 # Jump back up
591 # Jump back up
591 self.GotoPos(self.GetLineEndPosition(line_num-1))
592 self.GotoPos(self.GetLineEndPosition(line_num-1))
592 return True
593 return True
593 elif ( current_pos > self.GetLineEndPosition(line_num)
594 elif ( current_pos > self.GetLineEndPosition(line_num)
594 and not current_pos == self.GetLength()):
595 and not current_pos == self.GetLength()):
595 # Jump to next line
596 # Jump to next line
596 self.GotoPos(current_pos + 1 +
597 self.GotoPos(current_pos + 1 +
597 len(continuation_prompt))
598 len(continuation_prompt))
598 return True
599 return True
599
600
600 # We re-allow enter event processing
601 # We re-allow enter event processing
601 self.enter_catched = False
602 self.enter_catched = False
602 return False
603 return False
603
604
604
605
605 if __name__ == '__main__':
606 if __name__ == '__main__':
606 # Some simple code to test the console widget.
607 # Some simple code to test the console widget.
607 class MainWindow(wx.Frame):
608 class MainWindow(wx.Frame):
608 def __init__(self, parent, id, title):
609 def __init__(self, parent, id, title):
609 wx.Frame.__init__(self, parent, id, title, size=(300, 250))
610 wx.Frame.__init__(self, parent, id, title, size=(300, 250))
610 self._sizer = wx.BoxSizer(wx.VERTICAL)
611 self._sizer = wx.BoxSizer(wx.VERTICAL)
611 self.console_widget = ConsoleWidget(self)
612 self.console_widget = ConsoleWidget(self)
612 self._sizer.Add(self.console_widget, 1, wx.EXPAND)
613 self._sizer.Add(self.console_widget, 1, wx.EXPAND)
613 self.SetSizer(self._sizer)
614 self.SetSizer(self._sizer)
614 self.SetAutoLayout(1)
615 self.SetAutoLayout(1)
615 self.Show(True)
616 self.Show(True)
616
617
617 app = wx.PySimpleApp()
618 app = wx.PySimpleApp()
618 w = MainWindow(None, wx.ID_ANY, 'ConsoleWidget')
619 w = MainWindow(None, wx.ID_ANY, 'ConsoleWidget')
619 w.SetSize((780, 460))
620 w.SetSize((780, 460))
620 w.Show()
621 w.Show()
621
622
622 app.MainLoop()
623 app.MainLoop()
623
624
624
625
@@ -1,118 +1,118 b''
1 """
1 """
2 Entry point for a simple application giving a graphical frontend to
2 Entry point for a simple application giving a graphical frontend to
3 ipython.
3 ipython.
4 """
4 """
5
5
6 try:
6 try:
7 import wx
7 import wx
8 except ImportError, e:
8 except ImportError, e:
9 e.args[0] = """%s
9 e.args[0] = """%s
10 ________________________________________________________________________________
10 ________________________________________________________________________________
11 You need wxPython to run this application.
11 You need wxPython to run this application.
12 """ % e.args[0]
12 """ % e.args[0]
13 raise e
13 raise e
14
14
15 from wx_frontend import WxController
15 from wx_frontend import WxController
16 import __builtin__
16 import __builtin__
17
17
18
18
19 class IPythonXController(WxController):
19 class IPythonXController(WxController):
20 """ Sub class of WxController that adds some application-specific
20 """ Sub class of WxController that adds some application-specific
21 bindings.
21 bindings.
22 """
22 """
23
23
24 debug = False
24 debug = False
25
25
26 def __init__(self, *args, **kwargs):
26 def __init__(self, *args, **kwargs):
27 WxController.__init__(self, *args, **kwargs)
27 WxController.__init__(self, *args, **kwargs)
28 self.ipython0.ask_exit = self.do_exit
28 self.ipython0.ask_exit = self.do_exit
29 # Scroll to top
29 # Scroll to top
30 maxrange = self.GetScrollRange(wx.VERTICAL)
30 maxrange = self.GetScrollRange(wx.VERTICAL)
31 self.ScrollLines(-maxrange)
31 self.ScrollLines(-maxrange)
32
32
33
33
34 def _on_key_down(self, event, skip=True):
34 def _on_key_down(self, event, skip=True):
35 # Intercept Ctrl-D to quit
35 # Intercept Ctrl-D to quit
36 if event.KeyCode == ord('D') and event.ControlDown() and \
36 if event.KeyCode == ord('D') and event.ControlDown() and \
37 self.input_buffer == '' and \
37 self.input_buffer == '' and \
38 self._input_state == 'readline':
38 self._input_state == 'readline':
39 wx.CallAfter(self.ask_exit)
39 wx.CallAfter(self.ask_exit)
40 else:
40 else:
41 WxController._on_key_down(self, event, skip=skip)
41 WxController._on_key_down(self, event, skip=skip)
42
42
43
43
44 def ask_exit(self):
44 def ask_exit(self):
45 """ Ask the user whether to exit.
45 """ Ask the user whether to exit.
46 """
46 """
47 self._input_state = 'subprocess'
47 self._input_state = 'subprocess'
48 self.write('\n', refresh=False)
48 self.write('\n', refresh=False)
49 self.capture_output()
49 self.capture_output()
50 self.ipython0.shell.exit()
50 self.ipython0.exit()
51 self.release_output()
51 self.release_output()
52 if not self.ipython0.exit_now:
52 if not self.ipython0.exit_now:
53 wx.CallAfter(self.new_prompt,
53 wx.CallAfter(self.new_prompt,
54 self.input_prompt_template.substitute(
54 self.input_prompt_template.substitute(
55 number=self.last_result['number'] + 1))
55 number=self.last_result['number'] + 1))
56 else:
56 else:
57 wx.CallAfter(wx.GetApp().Exit)
57 wx.CallAfter(wx.GetApp().Exit)
58 self.write('Exiting ...', refresh=False)
58 self.write('Exiting ...', refresh=False)
59
59
60
60
61 def do_exit(self):
61 def do_exit(self):
62 """ Exits the interpreter, kills the windows.
62 """ Exits the interpreter, kills the windows.
63 """
63 """
64 WxController.do_exit(self)
64 WxController.do_exit(self)
65 self.release_output()
65 self.release_output()
66 wx.CallAfter(wx.Exit)
66 wx.CallAfter(wx.Exit)
67
67
68
68
69
69
70 class IPythonX(wx.Frame):
70 class IPythonX(wx.Frame):
71 """ Main frame of the IPythonX app.
71 """ Main frame of the IPythonX app.
72 """
72 """
73
73
74 def __init__(self, parent, id, title, debug=False):
74 def __init__(self, parent, id, title, debug=False):
75 wx.Frame.__init__(self, parent, id, title, size=(300,250))
75 wx.Frame.__init__(self, parent, id, title, size=(300,250))
76 self._sizer = wx.BoxSizer(wx.VERTICAL)
76 self._sizer = wx.BoxSizer(wx.VERTICAL)
77 self.shell = IPythonXController(self, debug=debug)
77 self.shell = IPythonXController(self, debug=debug)
78 self._sizer.Add(self.shell, 1, wx.EXPAND)
78 self._sizer.Add(self.shell, 1, wx.EXPAND)
79 self.SetSizer(self._sizer)
79 self.SetSizer(self._sizer)
80 self.SetAutoLayout(1)
80 self.SetAutoLayout(1)
81 self.Show(True)
81 self.Show(True)
82 wx.EVT_CLOSE(self, self.on_close)
82 wx.EVT_CLOSE(self, self.on_close)
83
83
84
84
85 def on_close(self, event):
85 def on_close(self, event):
86 """ Called on closing the windows.
86 """ Called on closing the windows.
87
87
88 Stops the event loop, to close all the child windows.
88 Stops the event loop, to close all the child windows.
89 """
89 """
90 wx.CallAfter(wx.Exit)
90 wx.CallAfter(wx.Exit)
91
91
92
92
93 def main():
93 def main():
94 from optparse import OptionParser
94 from optparse import OptionParser
95 usage = """usage: %prog [options]
95 usage = """usage: %prog [options]
96
96
97 Simple graphical frontend to IPython, using WxWidgets."""
97 Simple graphical frontend to IPython, using WxWidgets."""
98 parser = OptionParser(usage=usage)
98 parser = OptionParser(usage=usage)
99 parser.add_option("-d", "--debug",
99 parser.add_option("-d", "--debug",
100 action="store_true", dest="debug", default=False,
100 action="store_true", dest="debug", default=False,
101 help="Enable debug message for the wx frontend.")
101 help="Enable debug message for the wx frontend.")
102
102
103 options, args = parser.parse_args()
103 options, args = parser.parse_args()
104
104
105 # Clear the options, to avoid having the ipython0 instance complain
105 # Clear the options, to avoid having the ipython0 instance complain
106 import sys
106 import sys
107 sys.argv = sys.argv[:1]
107 sys.argv = sys.argv[:1]
108
108
109 app = wx.PySimpleApp()
109 app = wx.PySimpleApp()
110 frame = IPythonX(None, wx.ID_ANY, 'IPythonX', debug=options.debug)
110 frame = IPythonX(None, wx.ID_ANY, 'IPythonX', debug=options.debug)
111 frame.shell.SetFocus()
111 frame.shell.SetFocus()
112 frame.shell.app = app
112 frame.shell.app = app
113 frame.SetSize((680, 460))
113 frame.SetSize((680, 460))
114
114
115 app.MainLoop()
115 app.MainLoop()
116
116
117 if __name__ == '__main__':
117 if __name__ == '__main__':
118 main()
118 main()
@@ -1,528 +1,518 b''
1 #!/usr/bin/python
1 #!/usr/bin/python
2 # -*- coding: iso-8859-15 -*-
2 # -*- coding: iso-8859-15 -*-
3 '''
3 '''
4 Provides IPython remote instance.
4 Provides IPython remote instance.
5
5
6 @author: Laurent Dufrechou
6 @author: Laurent Dufrechou
7 laurent.dufrechou _at_ gmail.com
7 laurent.dufrechou _at_ gmail.com
8 @license: BSD
8 @license: BSD
9
9
10 All rights reserved. This program and the accompanying materials are made
10 All rights reserved. This program and the accompanying materials are made
11 available under the terms of the BSD which accompanies this distribution, and
11 available under the terms of the BSD which accompanies this distribution, and
12 is available at U{http://www.opensource.org/licenses/bsd-license.php}
12 is available at U{http://www.opensource.org/licenses/bsd-license.php}
13 '''
13 '''
14
14
15 __version__ = 0.9
15 __version__ = 0.9
16 __author__ = "Laurent Dufrechou"
16 __author__ = "Laurent Dufrechou"
17 __email__ = "laurent.dufrechou _at_ gmail.com"
17 __email__ = "laurent.dufrechou _at_ gmail.com"
18 __license__ = "BSD"
18 __license__ = "BSD"
19
19
20 import re
20 import re
21 import sys
21 import sys
22 import os
22 import os
23 import locale
23 import locale
24 from thread_ex import ThreadEx
24 from thread_ex import ThreadEx
25
25
26 import IPython
26 from IPython.core import iplib
27 from IPython.core import iplib, ipapp
28 from IPython.utils.io import Term
27 from IPython.utils.io import Term
29
28
30 ##############################################################################
29 ##############################################################################
31 class _Helper(object):
30 class _Helper(object):
32 """Redefine the built-in 'help'.
31 """Redefine the built-in 'help'.
33 This is a wrapper around pydoc.help (with a twist).
32 This is a wrapper around pydoc.help (with a twist).
34 """
33 """
35
34
36 def __init__(self, pager):
35 def __init__(self, pager):
37 self._pager = pager
36 self._pager = pager
38
37
39 def __repr__(self):
38 def __repr__(self):
40 return "Type help() for interactive help, " \
39 return "Type help() for interactive help, " \
41 "or help(object) for help about object."
40 "or help(object) for help about object."
42
41
43 def __call__(self, *args, **kwds):
42 def __call__(self, *args, **kwds):
44 class DummyWriter(object):
43 class DummyWriter(object):
45 '''Dumy class to handle help output'''
44 '''Dumy class to handle help output'''
46 def __init__(self, pager):
45 def __init__(self, pager):
47 self._pager = pager
46 self._pager = pager
48
47
49 def write(self, data):
48 def write(self, data):
50 '''hook to fill self._pager'''
49 '''hook to fill self._pager'''
51 self._pager(data)
50 self._pager(data)
52
51
53 import pydoc
52 import pydoc
54 pydoc.help.output = DummyWriter(self._pager)
53 pydoc.help.output = DummyWriter(self._pager)
55 pydoc.help.interact = lambda :1
54 pydoc.help.interact = lambda :1
56
55
57 return pydoc.help(*args, **kwds)
56 return pydoc.help(*args, **kwds)
58
57
59
58
60 ##############################################################################
59 ##############################################################################
61 class _CodeExecutor(ThreadEx):
60 class _CodeExecutor(ThreadEx):
62 ''' Thread that execute ipython code '''
61 ''' Thread that execute ipython code '''
63 def __init__(self, instance):
62 def __init__(self, instance):
64 ThreadEx.__init__(self)
63 ThreadEx.__init__(self)
65 self.instance = instance
64 self.instance = instance
66
65
67 def run(self):
66 def run(self):
68 '''Thread main loop'''
67 '''Thread main loop'''
69 try:
68 try:
70 self.instance._doc_text = None
69 self.instance._doc_text = None
71 self.instance._help_text = None
70 self.instance._help_text = None
72 self.instance._execute()
71 self.instance._execute()
73 # used for uper class to generate event after execution
72 # used for uper class to generate event after execution
74 self.instance._after_execute()
73 self.instance._after_execute()
75
74
76 except KeyboardInterrupt:
75 except KeyboardInterrupt:
77 pass
76 pass
78
77
79
78
80 ##############################################################################
79 ##############################################################################
81 class NonBlockingIPShell(object):
80 class NonBlockingIPShell(object):
82 '''
81 '''
83 Create an IPython instance, running the commands in a separate,
82 Create an IPython instance, running the commands in a separate,
84 non-blocking thread.
83 non-blocking thread.
85 This allows embedding in any GUI without blockage.
84 This allows embedding in any GUI without blockage.
86
85
87 Note: The ThreadEx class supports asynchroneous function call
86 Note: The ThreadEx class supports asynchroneous function call
88 via raise_exc()
87 via raise_exc()
89 '''
88 '''
90
89
91 def __init__(self, argv=[], user_ns={}, user_global_ns=None,
90 def __init__(self, user_ns={}, user_global_ns=None,
92 cin=None, cout=None, cerr=None,
91 cin=None, cout=None, cerr=None,
93 ask_exit_handler=None):
92 ask_exit_handler=None):
94 '''
93 '''
95 @param argv: Command line options for IPython
96 @type argv: list
97 @param user_ns: User namespace.
94 @param user_ns: User namespace.
98 @type user_ns: dictionary
95 @type user_ns: dictionary
99 @param user_global_ns: User global namespace.
96 @param user_global_ns: User global namespace.
100 @type user_global_ns: dictionary.
97 @type user_global_ns: dictionary.
101 @param cin: Console standard input.
98 @param cin: Console standard input.
102 @type cin: IO stream
99 @type cin: IO stream
103 @param cout: Console standard output.
100 @param cout: Console standard output.
104 @type cout: IO stream
101 @type cout: IO stream
105 @param cerr: Console standard error.
102 @param cerr: Console standard error.
106 @type cerr: IO stream
103 @type cerr: IO stream
107 @param exit_handler: Replacement for builtin exit() function
104 @param exit_handler: Replacement for builtin exit() function
108 @type exit_handler: function
105 @type exit_handler: function
109 @param time_loop: Define the sleep time between two thread's loop
106 @param time_loop: Define the sleep time between two thread's loop
110 @type int
107 @type int
111 '''
108 '''
112 #ipython0 initialisation
109 #ipython0 initialisation
113 self._IP = None
110 self._IP = None
114 self.init_ipython0(argv, user_ns, user_global_ns,
111 self.init_ipython0(user_ns, user_global_ns,
115 cin, cout, cerr,
112 cin, cout, cerr,
116 ask_exit_handler)
113 ask_exit_handler)
117
114
118 #vars used by _execute
115 #vars used by _execute
119 self._iter_more = 0
116 self._iter_more = 0
120 self._history_level = 0
117 self._history_level = 0
121 self._complete_sep = re.compile('[\s\{\}\[\]\(\)\=]')
118 self._complete_sep = re.compile('[\s\{\}\[\]\(\)\=]')
122 self._prompt = str(self._IP.outputcache.prompt1).strip()
119 self._prompt = str(self._IP.outputcache.prompt1).strip()
123
120
124 #thread working vars
121 #thread working vars
125 self._line_to_execute = ''
122 self._line_to_execute = ''
126 self._threading = True
123 self._threading = True
127
124
128 #vars that will be checked by GUI loop to handle thread states...
125 #vars that will be checked by GUI loop to handle thread states...
129 #will be replaced later by PostEvent GUI funtions...
126 #will be replaced later by PostEvent GUI funtions...
130 self._doc_text = None
127 self._doc_text = None
131 self._help_text = None
128 self._help_text = None
132 self._add_button = None
129 self._add_button = None
133
130
134 def init_ipython0(self, argv=[], user_ns={}, user_global_ns=None,
131 def init_ipython0(self, user_ns={}, user_global_ns=None,
135 cin=None, cout=None, cerr=None,
132 cin=None, cout=None, cerr=None,
136 ask_exit_handler=None):
133 ask_exit_handler=None):
137 ''' Initialize an ipython0 instance '''
134 ''' Initialize an ipython0 instance '''
138
135
139 #first we redefine in/out/error functions of IPython
136 #first we redefine in/out/error functions of IPython
140 #BUG: we've got a limitation form ipython0 there
137 #BUG: we've got a limitation form ipython0 there
141 #only one instance can be instanciated else tehre will be
138 #only one instance can be instanciated else tehre will be
142 #cin/cout/cerr clash...
139 #cin/cout/cerr clash...
143 if cin:
140 if cin:
144 Term.cin = cin
141 Term.cin = cin
145 if cout:
142 if cout:
146 Term.cout = cout
143 Term.cout = cout
147 if cerr:
144 if cerr:
148 Term.cerr = cerr
145 Term.cerr = cerr
149
146
150 excepthook = sys.excepthook
147 excepthook = sys.excepthook
151
148
152 #Hack to save sys.displayhook, because ipython seems to overwrite it...
149 #Hack to save sys.displayhook, because ipython seems to overwrite it...
153 self.sys_displayhook_ori = sys.displayhook
150 self.sys_displayhook_ori = sys.displayhook
154
151 ipython0 = iplib.InteractiveShell(
155 ipython0 = ipapp.IPythonApp(argv,user_ns=user_ns,
152 parent=None, config=None,
156 user_global_ns=user_global_ns)
153 user_ns=user_ns,
157 ipython0.initialize()
154 user_global_ns=user_global_ns
158 self._IP = ipython0.shell
155 )
159
156 self._IP = ipython0
160 ## self._IP = IPython.shell.make_IPython(
161 ## argv,user_ns=user_ns,
162 ## user_global_ns=user_global_ns,
163 ## embedded=True,
164 ## shell_class=IPython.shell.InteractiveShell)
165
157
166 #we save ipython0 displayhook and we restore sys.displayhook
158 #we save ipython0 displayhook and we restore sys.displayhook
167 self.displayhook = sys.displayhook
159 self.displayhook = sys.displayhook
168 sys.displayhook = self.sys_displayhook_ori
160 sys.displayhook = self.sys_displayhook_ori
169
161
170 #we replace IPython default encoding by wx locale encoding
162 #we replace IPython default encoding by wx locale encoding
171 loc = locale.getpreferredencoding()
163 loc = locale.getpreferredencoding()
172 if loc:
164 if loc:
173 self._IP.stdin_encoding = loc
165 self._IP.stdin_encoding = loc
174 #we replace the ipython default pager by our pager
166 #we replace the ipython default pager by our pager
175 self._IP.set_hook('show_in_pager', self._pager)
167 self._IP.set_hook('show_in_pager', self._pager)
176
168
177 #we replace the ipython default shell command caller
169 #we replace the ipython default shell command caller
178 #by our shell handler
170 #by our shell handler
179 self._IP.set_hook('shell_hook', self._shell)
171 self._IP.set_hook('shell_hook', self._shell)
180
172
181 #we replace the ipython default input command caller by our method
173 #we replace the ipython default input command caller by our method
182 iplib.raw_input_original = self._raw_input_original
174 iplib.raw_input_original = self._raw_input_original
183 #we replace the ipython default exit command by our method
175 #we replace the ipython default exit command by our method
184 self._IP.exit = ask_exit_handler
176 self._IP.exit = ask_exit_handler
185 #we replace the help command
177 #we replace the help command
186 self._IP.user_ns['help'] = _Helper(self._pager_help)
178 self._IP.user_ns['help'] = _Helper(self._pager_help)
187
179
188 #we disable cpase magic... until we found a way to use it properly.
180 #we disable cpaste magic... until we found a way to use it properly.
189 from IPython.core import ipapi
190 ip = ipapi.get()
191 def bypass_magic(self, arg):
181 def bypass_magic(self, arg):
192 print '%this magic is currently disabled.'
182 print '%this magic is currently disabled.'
193 ip.define_magic('cpaste', bypass_magic)
183 ipython0.define_magic('cpaste', bypass_magic)
194
184
195 import __builtin__
185 import __builtin__
196 __builtin__.raw_input = self._raw_input
186 __builtin__.raw_input = self._raw_input
197
187
198 sys.excepthook = excepthook
188 sys.excepthook = excepthook
199
189
200 #----------------------- Thread management section ----------------------
190 #----------------------- Thread management section ----------------------
201 def do_execute(self, line):
191 def do_execute(self, line):
202 """
192 """
203 Tell the thread to process the 'line' command
193 Tell the thread to process the 'line' command
204 """
194 """
205
195
206 self._line_to_execute = line
196 self._line_to_execute = line
207
197
208 if self._threading:
198 if self._threading:
209 #we launch the ipython line execution in a thread to make it
199 #we launch the ipython line execution in a thread to make it
210 #interruptible with include it in self namespace to be able
200 #interruptible with include it in self namespace to be able
211 #to call ce.raise_exc(KeyboardInterrupt)
201 #to call ce.raise_exc(KeyboardInterrupt)
212 self.ce = _CodeExecutor(self)
202 self.ce = _CodeExecutor(self)
213 self.ce.start()
203 self.ce.start()
214 else:
204 else:
215 try:
205 try:
216 self._doc_text = None
206 self._doc_text = None
217 self._help_text = None
207 self._help_text = None
218 self._execute()
208 self._execute()
219 # used for uper class to generate event after execution
209 # used for uper class to generate event after execution
220 self._after_execute()
210 self._after_execute()
221
211
222 except KeyboardInterrupt:
212 except KeyboardInterrupt:
223 pass
213 pass
224
214
225 #----------------------- IPython management section ----------------------
215 #----------------------- IPython management section ----------------------
226 def get_threading(self):
216 def get_threading(self):
227 """
217 """
228 Returns threading status, is set to True, then each command sent to
218 Returns threading status, is set to True, then each command sent to
229 the interpreter will be executed in a separated thread allowing,
219 the interpreter will be executed in a separated thread allowing,
230 for example, breaking a long running commands.
220 for example, breaking a long running commands.
231 Disallowing it, permits better compatibilty with instance that is embedding
221 Disallowing it, permits better compatibilty with instance that is embedding
232 IPython instance.
222 IPython instance.
233
223
234 @return: Execution method
224 @return: Execution method
235 @rtype: bool
225 @rtype: bool
236 """
226 """
237 return self._threading
227 return self._threading
238
228
239 def set_threading(self, state):
229 def set_threading(self, state):
240 """
230 """
241 Sets threading state, if set to True, then each command sent to
231 Sets threading state, if set to True, then each command sent to
242 the interpreter will be executed in a separated thread allowing,
232 the interpreter will be executed in a separated thread allowing,
243 for example, breaking a long running commands.
233 for example, breaking a long running commands.
244 Disallowing it, permits better compatibilty with instance that is embedding
234 Disallowing it, permits better compatibilty with instance that is embedding
245 IPython instance.
235 IPython instance.
246
236
247 @param state: Sets threading state
237 @param state: Sets threading state
248 @type bool
238 @type bool
249 """
239 """
250 self._threading = state
240 self._threading = state
251
241
252 def get_doc_text(self):
242 def get_doc_text(self):
253 """
243 """
254 Returns the output of the processing that need to be paged (if any)
244 Returns the output of the processing that need to be paged (if any)
255
245
256 @return: The std output string.
246 @return: The std output string.
257 @rtype: string
247 @rtype: string
258 """
248 """
259 return self._doc_text
249 return self._doc_text
260
250
261 def get_help_text(self):
251 def get_help_text(self):
262 """
252 """
263 Returns the output of the processing that need to be paged via help pager(if any)
253 Returns the output of the processing that need to be paged via help pager(if any)
264
254
265 @return: The std output string.
255 @return: The std output string.
266 @rtype: string
256 @rtype: string
267 """
257 """
268 return self._help_text
258 return self._help_text
269
259
270 def get_banner(self):
260 def get_banner(self):
271 """
261 """
272 Returns the IPython banner for useful info on IPython instance
262 Returns the IPython banner for useful info on IPython instance
273
263
274 @return: The banner string.
264 @return: The banner string.
275 @rtype: string
265 @rtype: string
276 """
266 """
277 return self._IP.banner
267 return self._IP.banner
278
268
279 def get_prompt_count(self):
269 def get_prompt_count(self):
280 """
270 """
281 Returns the prompt number.
271 Returns the prompt number.
282 Each time a user execute a line in the IPython shell the prompt count is increased
272 Each time a user execute a line in the IPython shell the prompt count is increased
283
273
284 @return: The prompt number
274 @return: The prompt number
285 @rtype: int
275 @rtype: int
286 """
276 """
287 return self._IP.outputcache.prompt_count
277 return self._IP.outputcache.prompt_count
288
278
289 def get_prompt(self):
279 def get_prompt(self):
290 """
280 """
291 Returns current prompt inside IPython instance
281 Returns current prompt inside IPython instance
292 (Can be In [...]: ot ...:)
282 (Can be In [...]: ot ...:)
293
283
294 @return: The current prompt.
284 @return: The current prompt.
295 @rtype: string
285 @rtype: string
296 """
286 """
297 return self._prompt
287 return self._prompt
298
288
299 def get_indentation(self):
289 def get_indentation(self):
300 """
290 """
301 Returns the current indentation level
291 Returns the current indentation level
302 Usefull to put the caret at the good start position if we want to do autoindentation.
292 Usefull to put the caret at the good start position if we want to do autoindentation.
303
293
304 @return: The indentation level.
294 @return: The indentation level.
305 @rtype: int
295 @rtype: int
306 """
296 """
307 return self._IP.indent_current_nsp
297 return self._IP.indent_current_nsp
308
298
309 def update_namespace(self, ns_dict):
299 def update_namespace(self, ns_dict):
310 '''
300 '''
311 Add the current dictionary to the shell namespace.
301 Add the current dictionary to the shell namespace.
312
302
313 @param ns_dict: A dictionary of symbol-values.
303 @param ns_dict: A dictionary of symbol-values.
314 @type ns_dict: dictionary
304 @type ns_dict: dictionary
315 '''
305 '''
316 self._IP.user_ns.update(ns_dict)
306 self._IP.user_ns.update(ns_dict)
317
307
318 def complete(self, line):
308 def complete(self, line):
319 '''
309 '''
320 Returns an auto completed line and/or posibilities for completion.
310 Returns an auto completed line and/or posibilities for completion.
321
311
322 @param line: Given line so far.
312 @param line: Given line so far.
323 @type line: string
313 @type line: string
324
314
325 @return: Line completed as for as possible,
315 @return: Line completed as for as possible,
326 and possible further completions.
316 and possible further completions.
327 @rtype: tuple
317 @rtype: tuple
328 '''
318 '''
329 split_line = self._complete_sep.split(line)
319 split_line = self._complete_sep.split(line)
330 possibilities = self._IP.complete(split_line[-1])
320 possibilities = self._IP.complete(split_line[-1])
331 if possibilities:
321 if possibilities:
332
322
333 def _common_prefix(str1, str2):
323 def _common_prefix(str1, str2):
334 '''
324 '''
335 Reduction function. returns common prefix of two given strings.
325 Reduction function. returns common prefix of two given strings.
336
326
337 @param str1: First string.
327 @param str1: First string.
338 @type str1: string
328 @type str1: string
339 @param str2: Second string
329 @param str2: Second string
340 @type str2: string
330 @type str2: string
341
331
342 @return: Common prefix to both strings.
332 @return: Common prefix to both strings.
343 @rtype: string
333 @rtype: string
344 '''
334 '''
345 for i in range(len(str1)):
335 for i in range(len(str1)):
346 if not str2.startswith(str1[:i+1]):
336 if not str2.startswith(str1[:i+1]):
347 return str1[:i]
337 return str1[:i]
348 return str1
338 return str1
349 common_prefix = reduce(_common_prefix, possibilities)
339 common_prefix = reduce(_common_prefix, possibilities)
350 completed = line[:-len(split_line[-1])]+common_prefix
340 completed = line[:-len(split_line[-1])]+common_prefix
351 else:
341 else:
352 completed = line
342 completed = line
353 return completed, possibilities
343 return completed, possibilities
354
344
355 def history_back(self):
345 def history_back(self):
356 '''
346 '''
357 Provides one history command back.
347 Provides one history command back.
358
348
359 @return: The command string.
349 @return: The command string.
360 @rtype: string
350 @rtype: string
361 '''
351 '''
362 history = ''
352 history = ''
363 #the below while loop is used to suppress empty history lines
353 #the below while loop is used to suppress empty history lines
364 while((history == '' or history == '\n') and self._history_level >0):
354 while((history == '' or history == '\n') and self._history_level >0):
365 if self._history_level >= 1:
355 if self._history_level >= 1:
366 self._history_level -= 1
356 self._history_level -= 1
367 history = self._get_history()
357 history = self._get_history()
368 return history
358 return history
369
359
370 def history_forward(self):
360 def history_forward(self):
371 '''
361 '''
372 Provides one history command forward.
362 Provides one history command forward.
373
363
374 @return: The command string.
364 @return: The command string.
375 @rtype: string
365 @rtype: string
376 '''
366 '''
377 history = ''
367 history = ''
378 #the below while loop is used to suppress empty history lines
368 #the below while loop is used to suppress empty history lines
379 while((history == '' or history == '\n') \
369 while((history == '' or history == '\n') \
380 and self._history_level <= self._get_history_max_index()):
370 and self._history_level <= self._get_history_max_index()):
381 if self._history_level < self._get_history_max_index():
371 if self._history_level < self._get_history_max_index():
382 self._history_level += 1
372 self._history_level += 1
383 history = self._get_history()
373 history = self._get_history()
384 else:
374 else:
385 if self._history_level == self._get_history_max_index():
375 if self._history_level == self._get_history_max_index():
386 history = self._get_history()
376 history = self._get_history()
387 self._history_level += 1
377 self._history_level += 1
388 else:
378 else:
389 history = ''
379 history = ''
390 return history
380 return history
391
381
392 def init_history_index(self):
382 def init_history_index(self):
393 '''
383 '''
394 set history to last command entered
384 set history to last command entered
395 '''
385 '''
396 self._history_level = self._get_history_max_index()+1
386 self._history_level = self._get_history_max_index()+1
397
387
398 #----------------------- IPython PRIVATE management section --------------
388 #----------------------- IPython PRIVATE management section --------------
399 def _after_execute(self):
389 def _after_execute(self):
400 '''
390 '''
401 Can be redefined to generate post event after excution is done
391 Can be redefined to generate post event after excution is done
402 '''
392 '''
403 pass
393 pass
404
394
405 def _ask_exit(self):
395 def _ask_exit(self):
406 '''
396 '''
407 Can be redefined to generate post event to exit the Ipython shell
397 Can be redefined to generate post event to exit the Ipython shell
408 '''
398 '''
409 pass
399 pass
410
400
411 def _get_history_max_index(self):
401 def _get_history_max_index(self):
412 '''
402 '''
413 returns the max length of the history buffer
403 returns the max length of the history buffer
414
404
415 @return: history length
405 @return: history length
416 @rtype: int
406 @rtype: int
417 '''
407 '''
418 return len(self._IP.input_hist_raw)-1
408 return len(self._IP.input_hist_raw)-1
419
409
420 def _get_history(self):
410 def _get_history(self):
421 '''
411 '''
422 Get's the command string of the current history level.
412 Get's the command string of the current history level.
423
413
424 @return: Historic command stri
414 @return: Historic command stri
425 @rtype: string
415 @rtype: string
426 '''
416 '''
427 rv = self._IP.input_hist_raw[self._history_level].strip('\n')
417 rv = self._IP.input_hist_raw[self._history_level].strip('\n')
428 return rv
418 return rv
429
419
430 def _pager_help(self, text):
420 def _pager_help(self, text):
431 '''
421 '''
432 This function is used as a callback replacment to IPython help pager function
422 This function is used as a callback replacment to IPython help pager function
433
423
434 It puts the 'text' value inside the self._help_text string that can be retrived via
424 It puts the 'text' value inside the self._help_text string that can be retrived via
435 get_help_text function.
425 get_help_text function.
436 '''
426 '''
437 if self._help_text == None:
427 if self._help_text == None:
438 self._help_text = text
428 self._help_text = text
439 else:
429 else:
440 self._help_text += text
430 self._help_text += text
441
431
442 def _pager(self, IP, text):
432 def _pager(self, IP, text):
443 '''
433 '''
444 This function is used as a callback replacment to IPython pager function
434 This function is used as a callback replacment to IPython pager function
445
435
446 It puts the 'text' value inside the self._doc_text string that can be retrived via
436 It puts the 'text' value inside the self._doc_text string that can be retrived via
447 get_doc_text function.
437 get_doc_text function.
448 '''
438 '''
449 self._doc_text = text
439 self._doc_text = text
450
440
451 def _raw_input_original(self, prompt=''):
441 def _raw_input_original(self, prompt=''):
452 '''
442 '''
453 Custom raw_input() replacement. Get's current line from console buffer.
443 Custom raw_input() replacement. Get's current line from console buffer.
454
444
455 @param prompt: Prompt to print. Here for compatability as replacement.
445 @param prompt: Prompt to print. Here for compatability as replacement.
456 @type prompt: string
446 @type prompt: string
457
447
458 @return: The current command line text.
448 @return: The current command line text.
459 @rtype: string
449 @rtype: string
460 '''
450 '''
461 return self._line_to_execute
451 return self._line_to_execute
462
452
463 def _raw_input(self, prompt=''):
453 def _raw_input(self, prompt=''):
464 """ A replacement from python's raw_input.
454 """ A replacement from python's raw_input.
465 """
455 """
466 raise NotImplementedError
456 raise NotImplementedError
467
457
468 def _execute(self):
458 def _execute(self):
469 '''
459 '''
470 Executes the current line provided by the shell object.
460 Executes the current line provided by the shell object.
471 '''
461 '''
472
462
473 orig_stdout = sys.stdout
463 orig_stdout = sys.stdout
474 sys.stdout = Term.cout
464 sys.stdout = Term.cout
475 #self.sys_displayhook_ori = sys.displayhook
465 #self.sys_displayhook_ori = sys.displayhook
476 #sys.displayhook = self.displayhook
466 #sys.displayhook = self.displayhook
477
467
478 try:
468 try:
479 line = self._IP.raw_input(None, self._iter_more)
469 line = self._IP.raw_input(None, self._iter_more)
480 if self._IP.autoindent:
470 if self._IP.autoindent:
481 self._IP.readline_startup_hook(None)
471 self._IP.readline_startup_hook(None)
482
472
483 except KeyboardInterrupt:
473 except KeyboardInterrupt:
484 self._IP.write('\nKeyboardInterrupt\n')
474 self._IP.write('\nKeyboardInterrupt\n')
485 self._IP.resetbuffer()
475 self._IP.resetbuffer()
486 # keep cache in sync with the prompt counter:
476 # keep cache in sync with the prompt counter:
487 self._IP.outputcache.prompt_count -= 1
477 self._IP.outputcache.prompt_count -= 1
488
478
489 if self._IP.autoindent:
479 if self._IP.autoindent:
490 self._IP.indent_current_nsp = 0
480 self._IP.indent_current_nsp = 0
491 self._iter_more = 0
481 self._iter_more = 0
492 except:
482 except:
493 self._IP.showtraceback()
483 self._IP.showtraceback()
494 else:
484 else:
495 self._IP.write(str(self._IP.outputcache.prompt_out).strip())
485 self._IP.write(str(self._IP.outputcache.prompt_out).strip())
496 self._iter_more = self._IP.push_line(line)
486 self._iter_more = self._IP.push_line(line)
497 if (self._IP.SyntaxTB.last_syntax_error and \
487 if (self._IP.SyntaxTB.last_syntax_error and \
498 self._IP.autoedit_syntax):
488 self._IP.autoedit_syntax):
499 self._IP.edit_syntax_error()
489 self._IP.edit_syntax_error()
500 if self._iter_more:
490 if self._iter_more:
501 self._prompt = str(self._IP.outputcache.prompt2).strip()
491 self._prompt = str(self._IP.outputcache.prompt2).strip()
502 if self._IP.autoindent:
492 if self._IP.autoindent:
503 self._IP.readline_startup_hook(self._IP.pre_readline)
493 self._IP.readline_startup_hook(self._IP.pre_readline)
504 else:
494 else:
505 self._prompt = str(self._IP.outputcache.prompt1).strip()
495 self._prompt = str(self._IP.outputcache.prompt1).strip()
506 self._IP.indent_current_nsp = 0 #we set indentation to 0
496 self._IP.indent_current_nsp = 0 #we set indentation to 0
507
497
508 sys.stdout = orig_stdout
498 sys.stdout = orig_stdout
509 #sys.displayhook = self.sys_displayhook_ori
499 #sys.displayhook = self.sys_displayhook_ori
510
500
511 def _shell(self, ip, cmd):
501 def _shell(self, ip, cmd):
512 '''
502 '''
513 Replacement method to allow shell commands without them blocking.
503 Replacement method to allow shell commands without them blocking.
514
504
515 @param ip: Ipython instance, same as self._IP
505 @param ip: Ipython instance, same as self._IP
516 @type cmd: Ipython instance
506 @type cmd: Ipython instance
517 @param cmd: Shell command to execute.
507 @param cmd: Shell command to execute.
518 @type cmd: string
508 @type cmd: string
519 '''
509 '''
520 stdin, stdout = os.popen4(cmd)
510 stdin, stdout = os.popen4(cmd)
521 result = stdout.read().decode('cp437').\
511 result = stdout.read().decode('cp437').\
522 encode(locale.getpreferredencoding())
512 encode(locale.getpreferredencoding())
523 #we use print command because the shell command is called
513 #we use print command because the shell command is called
524 #inside IPython instance and thus is redirected to thread cout
514 #inside IPython instance and thus is redirected to thread cout
525 #"\x01\x1b[1;36m\x02" <-- add colour to the text...
515 #"\x01\x1b[1;36m\x02" <-- add colour to the text...
526 print "\x01\x1b[1;36m\x02"+result
516 print "\x01\x1b[1;36m\x02"+result
527 stdout.close()
517 stdout.close()
528 stdin.close()
518 stdin.close()
@@ -1,509 +1,510 b''
1 #!/usr/bin/python
1 #!/usr/bin/python
2 # -*- coding: iso-8859-15 -*-
2 # -*- coding: iso-8859-15 -*-
3 import wx
3 import wx
4 import wx.stc as stc
4 import wx.stc as stc
5 import keyword
5 import keyword
6
6
7 #-----------------------------------------
7 #-----------------------------------------
8 # History widget for IPython
8 # History widget for IPython
9 __version__ = 0.5
9 __version__ = 0.5
10 __author__ = "Laurent Dufrechou"
10 __author__ = "Laurent Dufrechou"
11 __email__ = "laurent.dufrechou _at_ gmail.com"
11 __email__ = "laurent.dufrechou _at_ gmail.com"
12 __license__ = "BSD"
12 __license__ = "BSD"
13 #-----------------------------------------
13 #-----------------------------------------
14
14 class IPythonHistoryPanel(wx.Panel):
15 class IPythonHistoryPanel(wx.Panel):
15
16
16 def __init__(self, parent,flt_empty=True,
17 def __init__(self, parent,flt_empty=True,
17 flt_doc=True,flt_cmd=True,flt_magic=True):
18 flt_doc=True,flt_cmd=True,flt_magic=True):
18
19
19 wx.Panel.__init__(self,parent,-1)
20 wx.Panel.__init__(self,parent,-1)
20 #text_ctrl = wx.TextCtrl(self, -1, style=wx.TE_MULTILINE)
21 #text_ctrl = wx.TextCtrl(self, -1, style=wx.TE_MULTILINE)
21 text_ctrl = PythonSTC(self, -1)
22 text_ctrl = PythonSTC(self, -1)
22
23
23
24
24 st_filt = wx.StaticText(self, -1, " Filter:")
25 st_filt = wx.StaticText(self, -1, " Filter:")
25
26
26 self.filter_empty = wx.CheckBox(self, -1, "Empty commands")
27 self.filter_empty = wx.CheckBox(self, -1, "Empty commands")
27 self.filter_doc = wx.CheckBox(self, -1, "?: Doc commands")
28 self.filter_doc = wx.CheckBox(self, -1, "?: Doc commands")
28 self.filter_cmd = wx.CheckBox(self, -1, "!: Sys commands")
29 self.filter_cmd = wx.CheckBox(self, -1, "!: Sys commands")
29 self.filter_magic = wx.CheckBox(self, -1, "%: Magic keys")
30 self.filter_magic = wx.CheckBox(self, -1, "%: Magic keys")
30
31
31 self.options={'filter_empty':{'value':'True',
32 self.options={'filter_empty':{'value':'True',
32 'checkbox':self.filter_empty, \
33 'checkbox':self.filter_empty, \
33 'True':True,'False':False,
34 'True':True,'False':False,
34 'setfunc':lambda x:None},
35 'setfunc':lambda x:None},
35 'filter_doc':{'value':'True',
36 'filter_doc':{'value':'True',
36 'checkbox':self.filter_doc, \
37 'checkbox':self.filter_doc, \
37 'True':True,'False':False,
38 'True':True,'False':False,
38 'setfunc':lambda x:None},
39 'setfunc':lambda x:None},
39 'filter_cmd':{'value':'True',
40 'filter_cmd':{'value':'True',
40 'checkbox':self.filter_cmd, \
41 'checkbox':self.filter_cmd, \
41 'True':True,'False':False,
42 'True':True,'False':False,
42 'setfunc':lambda x:None},
43 'setfunc':lambda x:None},
43 'filter_magic':{'value':'True',
44 'filter_magic':{'value':'True',
44 'checkbox':self.filter_magic, \
45 'checkbox':self.filter_magic, \
45 'True':True,'False':False,
46 'True':True,'False':False,
46 'setfunc':lambda x:None},
47 'setfunc':lambda x:None},
47 }
48 }
48 self.reloadOptions(self.options)
49 self.reloadOptions(self.options)
49
50
50 self.filter_empty.Bind(wx.EVT_CHECKBOX, self.evtCheckEmptyFilter)
51 self.filter_empty.Bind(wx.EVT_CHECKBOX, self.evtCheckEmptyFilter)
51 self.filter_doc.Bind(wx.EVT_CHECKBOX, self.evtCheckDocFilter)
52 self.filter_doc.Bind(wx.EVT_CHECKBOX, self.evtCheckDocFilter)
52 self.filter_cmd.Bind(wx.EVT_CHECKBOX, self.evtCheckCmdFilter)
53 self.filter_cmd.Bind(wx.EVT_CHECKBOX, self.evtCheckCmdFilter)
53 self.filter_magic.Bind(wx.EVT_CHECKBOX, self.evtCheckMagicFilter)
54 self.filter_magic.Bind(wx.EVT_CHECKBOX, self.evtCheckMagicFilter)
54
55
55 #self.filter_empty.SetValue(flt_empty)
56 #self.filter_empty.SetValue(flt_empty)
56 #self.filter_doc.SetValue(flt_doc)
57 #self.filter_doc.SetValue(flt_doc)
57 #self.filter_cmd.SetValue(flt_cmd)
58 #self.filter_cmd.SetValue(flt_cmd)
58 #self.filter_magic.SetValue(flt_magic)
59 #self.filter_magic.SetValue(flt_magic)
59
60
60 sizer = wx.BoxSizer(wx.VERTICAL)
61 sizer = wx.BoxSizer(wx.VERTICAL)
61
62
62 sizer.Add(text_ctrl, 1, wx.EXPAND)
63 sizer.Add(text_ctrl, 1, wx.EXPAND)
63 sizer.AddMany( [(5,5),
64 sizer.AddMany( [(5,5),
64 st_filt,
65 st_filt,
65 (10,10),
66 (10,10),
66 self.filter_empty,
67 self.filter_empty,
67 self.filter_doc,
68 self.filter_doc,
68 self.filter_cmd,
69 self.filter_cmd,
69 self.filter_magic,
70 self.filter_magic,
70 (10,10),
71 (10,10),
71 ])
72 ])
72 self.SetAutoLayout(True)
73 self.SetAutoLayout(True)
73 sizer.Fit(self)
74 sizer.Fit(self)
74 sizer.SetSizeHints(self)
75 sizer.SetSizeHints(self)
75 self.SetSizer(sizer)
76 self.SetSizer(sizer)
76 self.text_ctrl=text_ctrl
77 self.text_ctrl=text_ctrl
77 #text_ctrl.SetText(demoText + open('Main.py').read())
78 #text_ctrl.SetText(demoText + open('Main.py').read())
78 text_ctrl.EmptyUndoBuffer()
79 text_ctrl.EmptyUndoBuffer()
79 text_ctrl.Colourise(0, -1)
80 text_ctrl.Colourise(0, -1)
80
81
81 # line numbers in the margin
82 # line numbers in the margin
82 text_ctrl.SetMarginType(1, stc.STC_MARGIN_NUMBER)
83 text_ctrl.SetMarginType(1, stc.STC_MARGIN_NUMBER)
83 text_ctrl.SetMarginWidth(1, 15)
84 text_ctrl.SetMarginWidth(1, 15)
84
85
85
86
86 def write(self,history_line):
87 def write(self,history_line):
87 add = True
88 add = True
88 if self.filter_empty.GetValue() == True and history_line == '':
89 if self.filter_empty.GetValue() == True and history_line == '':
89 add = False
90 add = False
90 if len(history_line)>0:
91 if len(history_line)>0:
91 if self.filter_doc.GetValue() == True and history_line[-1:] == '?':
92 if self.filter_doc.GetValue() == True and history_line[-1:] == '?':
92 add = False
93 add = False
93 if self.filter_cmd.GetValue() == True and history_line[0] == '!':
94 if self.filter_cmd.GetValue() == True and history_line[0] == '!':
94 add = False
95 add = False
95 if self.filter_magic.GetValue() == True and history_line[0] == '%':
96 if self.filter_magic.GetValue() == True and history_line[0] == '%':
96 add = False
97 add = False
97 if add:
98 if add:
98 self.text_ctrl.AppendText(history_line+'\n')
99 self.text_ctrl.AppendText(history_line+'\n')
99
100
100 #------------------------ Option Section -----------------------------------
101 #------------------------ Option Section -----------------------------------
101 def processOptionCheckedEvt(self, event, name):
102 def processOptionCheckedEvt(self, event, name):
102 if event.IsChecked():
103 if event.IsChecked():
103 self.options[name]['value']='True'
104 self.options[name]['value']='True'
104 else:
105 else:
105 self.options[name]['value']='False'
106 self.options[name]['value']='False'
106 self.updateOptionTracker(name,
107 self.updateOptionTracker(name,
107 self.options[name]['value'])
108 self.options[name]['value'])
108
109
109 def evtCheckEmptyFilter(self, event):
110 def evtCheckEmptyFilter(self, event):
110 self.processOptionCheckedEvt(event, 'filter_empty')
111 self.processOptionCheckedEvt(event, 'filter_empty')
111
112
112 def evtCheckDocFilter(self, event):
113 def evtCheckDocFilter(self, event):
113 self.processOptionCheckedEvt(event, 'filter_doc')
114 self.processOptionCheckedEvt(event, 'filter_doc')
114
115
115 def evtCheckCmdFilter(self, event):
116 def evtCheckCmdFilter(self, event):
116 self.processOptionCheckedEvt(event, 'filter_cmd')
117 self.processOptionCheckedEvt(event, 'filter_cmd')
117
118
118 def evtCheckMagicFilter(self, event):
119 def evtCheckMagicFilter(self, event):
119 self.processOptionCheckedEvt(event, 'filter_magic')
120 self.processOptionCheckedEvt(event, 'filter_magic')
120
121
121 def getOptions(self):
122 def getOptions(self):
122 return self.options
123 return self.options
123
124
124 def reloadOptions(self,options):
125 def reloadOptions(self,options):
125 self.options = options
126 self.options = options
126 for key in self.options.keys():
127 for key in self.options.keys():
127 value = self.options[key]['value']
128 value = self.options[key]['value']
128 self.options[key]['checkbox'].SetValue(self.options[key][value])
129 self.options[key]['checkbox'].SetValue(self.options[key][value])
129 self.options[key]['setfunc'](value)
130 self.options[key]['setfunc'](value)
130
131
131 #------------------------ Hook Section -----------------------------------
132 #------------------------ Hook Section -----------------------------------
132 def updateOptionTracker(self,name,value):
133 def updateOptionTracker(self,name,value):
133 '''
134 '''
134 Default history tracker (does nothing)
135 Default history tracker (does nothing)
135 '''
136 '''
136 pass
137 pass
137
138
138 def setOptionTrackerHook(self,func):
139 def setOptionTrackerHook(self,func):
139 '''
140 '''
140 Define a new history tracker
141 Define a new history tracker
141 '''
142 '''
142 self.updateOptionTracker = func
143 self.updateOptionTracker = func
143
144
144
145
145 #----------------------------------------------------------------------
146 #----------------------------------------------------------------------
146 # Font definition for Styled Text Control
147 # Font definition for Styled Text Control
147
148
148 if wx.Platform == '__WXMSW__':
149 if wx.Platform == '__WXMSW__':
149 faces = { 'times': 'Times New Roman',
150 faces = { 'times': 'Times New Roman',
150 'mono' : 'Courier New',
151 'mono' : 'Courier New',
151 'helv' : 'Arial',
152 'helv' : 'Arial',
152 'other': 'Comic Sans MS',
153 'other': 'Comic Sans MS',
153 'size' : 8,
154 'size' : 8,
154 'size2': 6,
155 'size2': 6,
155 }
156 }
156 elif wx.Platform == '__WXMAC__':
157 elif wx.Platform == '__WXMAC__':
157 faces = { 'times': 'Times New Roman',
158 faces = { 'times': 'Times New Roman',
158 'mono' : 'Monaco',
159 'mono' : 'Monaco',
159 'helv' : 'Arial',
160 'helv' : 'Arial',
160 'other': 'Comic Sans MS',
161 'other': 'Comic Sans MS',
161 'size' : 8,
162 'size' : 8,
162 'size2': 6,
163 'size2': 6,
163 }
164 }
164 else:
165 else:
165 faces = { 'times': 'Times',
166 faces = { 'times': 'Times',
166 'mono' : 'Courier',
167 'mono' : 'Courier',
167 'helv' : 'Helvetica',
168 'helv' : 'Helvetica',
168 'other': 'new century schoolbook',
169 'other': 'new century schoolbook',
169 'size' : 8,
170 'size' : 8,
170 'size2': 6,
171 'size2': 6,
171 }
172 }
172
173
173
174
174 #----------------------------------------------------------------------
175 #----------------------------------------------------------------------
175
176
176 class PythonSTC(stc.StyledTextCtrl):
177 class PythonSTC(stc.StyledTextCtrl):
177
178
178 fold_symbols = 3
179 fold_symbols = 3
179
180
180 def __init__(self, parent, ID,
181 def __init__(self, parent, ID,
181 pos=wx.DefaultPosition, size=wx.DefaultSize,
182 pos=wx.DefaultPosition, size=wx.DefaultSize,
182 style=0):
183 style=0):
183 stc.StyledTextCtrl.__init__(self, parent, ID, pos, size, style)
184 stc.StyledTextCtrl.__init__(self, parent, ID, pos, size, style)
184 #self.CmdKeyAssign(ord('B'), stc.STC_SCMOD_CTRL, stc.STC_CMD_ZOOMIN)
185 #self.CmdKeyAssign(ord('B'), stc.STC_SCMOD_CTRL, stc.STC_CMD_ZOOMIN)
185 #self.CmdKeyAssign(ord('N'), stc.STC_SCMOD_CTRL, stc.STC_CMD_ZOOMOUT)
186 #self.CmdKeyAssign(ord('N'), stc.STC_SCMOD_CTRL, stc.STC_CMD_ZOOMOUT)
186
187
187 self.SetLexer(stc.STC_LEX_PYTHON)
188 self.SetLexer(stc.STC_LEX_PYTHON)
188 self.SetKeyWords(0, " ".join(keyword.kwlist))
189 self.SetKeyWords(0, " ".join(keyword.kwlist))
189
190
190 #self.SetProperty("fold", "1")
191 #self.SetProperty("fold", "1")
191 #self.SetProperty("tab.timmy.whinge.level", "1")
192 #self.SetProperty("tab.timmy.whinge.level", "1")
192 #self.SetMargins(0,0)
193 #self.SetMargins(0,0)
193
194
194 #self.SetViewWhiteSpace(False)
195 #self.SetViewWhiteSpace(False)
195 #self.SetBufferedDraw(False)
196 #self.SetBufferedDraw(False)
196 #self.SetViewEOL(True)
197 #self.SetViewEOL(True)
197 self.SetEOLMode(stc.STC_EOL_CRLF)
198 self.SetEOLMode(stc.STC_EOL_CRLF)
198 #self.SetUseAntiAliasing(True)
199 #self.SetUseAntiAliasing(True)
199
200
200 self.SetEdgeMode(stc.STC_EDGE_LINE)
201 self.SetEdgeMode(stc.STC_EDGE_LINE)
201 self.SetEdgeColumn(80)
202 self.SetEdgeColumn(80)
202 self.SetEdgeColour(wx.LIGHT_GREY)
203 self.SetEdgeColour(wx.LIGHT_GREY)
203 self.SetLayoutCache(stc.STC_CACHE_PAGE)
204 self.SetLayoutCache(stc.STC_CACHE_PAGE)
204
205
205 # Setup a margin to hold fold markers
206 # Setup a margin to hold fold markers
206 #self.SetFoldFlags(16)
207 #self.SetFoldFlags(16)
207 ### WHAT IS THIS VALUE? WHAT ARE THE OTHER FLAGS? DOES IT MATTER?
208 ### WHAT IS THIS VALUE? WHAT ARE THE OTHER FLAGS? DOES IT MATTER?
208 self.SetMarginType(2, stc.STC_MARGIN_SYMBOL)
209 self.SetMarginType(2, stc.STC_MARGIN_SYMBOL)
209 self.SetMarginMask(2, stc.STC_MASK_FOLDERS)
210 self.SetMarginMask(2, stc.STC_MASK_FOLDERS)
210 self.SetMarginSensitive(2, True)
211 self.SetMarginSensitive(2, True)
211 self.SetMarginWidth(2, 12)
212 self.SetMarginWidth(2, 12)
212
213
213 if self.fold_symbols == 0:
214 if self.fold_symbols == 0:
214 # Arrow pointing right for contracted folders,
215 # Arrow pointing right for contracted folders,
215 # arrow pointing down for expanded
216 # arrow pointing down for expanded
216 self.MarkerDefine(stc.STC_MARKNUM_FOLDEROPEN, \
217 self.MarkerDefine(stc.STC_MARKNUM_FOLDEROPEN, \
217 stc.STC_MARK_ARROWDOWN, "black", "black")
218 stc.STC_MARK_ARROWDOWN, "black", "black")
218 self.MarkerDefine(stc.STC_MARKNUM_FOLDER, \
219 self.MarkerDefine(stc.STC_MARKNUM_FOLDER, \
219 stc.STC_MARK_ARROW, "black", "black")
220 stc.STC_MARK_ARROW, "black", "black")
220 self.MarkerDefine(stc.STC_MARKNUM_FOLDERSUB, \
221 self.MarkerDefine(stc.STC_MARKNUM_FOLDERSUB, \
221 stc.STC_MARK_EMPTY, "black", "black")
222 stc.STC_MARK_EMPTY, "black", "black")
222 self.MarkerDefine(stc.STC_MARKNUM_FOLDERTAIL, \
223 self.MarkerDefine(stc.STC_MARKNUM_FOLDERTAIL, \
223 stc.STC_MARK_EMPTY, "black", "black")
224 stc.STC_MARK_EMPTY, "black", "black")
224 self.MarkerDefine(stc.STC_MARKNUM_FOLDEREND, \
225 self.MarkerDefine(stc.STC_MARKNUM_FOLDEREND, \
225 stc.STC_MARK_EMPTY, "white", "black")
226 stc.STC_MARK_EMPTY, "white", "black")
226 self.MarkerDefine(stc.STC_MARKNUM_FOLDEROPENMID, \
227 self.MarkerDefine(stc.STC_MARKNUM_FOLDEROPENMID, \
227 stc.STC_MARK_EMPTY, "white", "black")
228 stc.STC_MARK_EMPTY, "white", "black")
228 self.MarkerDefine(stc.STC_MARKNUM_FOLDERMIDTAIL, \
229 self.MarkerDefine(stc.STC_MARKNUM_FOLDERMIDTAIL, \
229 stc.STC_MARK_EMPTY, "white", "black")
230 stc.STC_MARK_EMPTY, "white", "black")
230
231
231 elif self.fold_symbols == 1:
232 elif self.fold_symbols == 1:
232 # Plus for contracted folders, minus for expanded
233 # Plus for contracted folders, minus for expanded
233 self.MarkerDefine(stc.STC_MARKNUM_FOLDEROPEN, \
234 self.MarkerDefine(stc.STC_MARKNUM_FOLDEROPEN, \
234 stc.STC_MARK_MINUS, "white", "black")
235 stc.STC_MARK_MINUS, "white", "black")
235 self.MarkerDefine(stc.STC_MARKNUM_FOLDER, \
236 self.MarkerDefine(stc.STC_MARKNUM_FOLDER, \
236 stc.STC_MARK_PLUS, "white", "black")
237 stc.STC_MARK_PLUS, "white", "black")
237 self.MarkerDefine(stc.STC_MARKNUM_FOLDERSUB, \
238 self.MarkerDefine(stc.STC_MARKNUM_FOLDERSUB, \
238 stc.STC_MARK_EMPTY, "white", "black")
239 stc.STC_MARK_EMPTY, "white", "black")
239 self.MarkerDefine(stc.STC_MARKNUM_FOLDERTAIL, \
240 self.MarkerDefine(stc.STC_MARKNUM_FOLDERTAIL, \
240 stc.STC_MARK_EMPTY, "white", "black")
241 stc.STC_MARK_EMPTY, "white", "black")
241 self.MarkerDefine(stc.STC_MARKNUM_FOLDEREND, \
242 self.MarkerDefine(stc.STC_MARKNUM_FOLDEREND, \
242 stc.STC_MARK_EMPTY, "white", "black")
243 stc.STC_MARK_EMPTY, "white", "black")
243 self.MarkerDefine(stc.STC_MARKNUM_FOLDEROPENMID, \
244 self.MarkerDefine(stc.STC_MARKNUM_FOLDEROPENMID, \
244 stc.STC_MARK_EMPTY, "white", "black")
245 stc.STC_MARK_EMPTY, "white", "black")
245 self.MarkerDefine(stc.STC_MARKNUM_FOLDERMIDTAIL, \
246 self.MarkerDefine(stc.STC_MARKNUM_FOLDERMIDTAIL, \
246 stc.STC_MARK_EMPTY, "white", "black")
247 stc.STC_MARK_EMPTY, "white", "black")
247
248
248 elif self.fold_symbols == 2:
249 elif self.fold_symbols == 2:
249 # Like a flattened tree control using circular headers and curved joins
250 # Like a flattened tree control using circular headers and curved joins
250 self.MarkerDefine(stc.STC_MARKNUM_FOLDEROPEN, \
251 self.MarkerDefine(stc.STC_MARKNUM_FOLDEROPEN, \
251 stc.STC_MARK_CIRCLEMINUS, "white", "#404040")
252 stc.STC_MARK_CIRCLEMINUS, "white", "#404040")
252 self.MarkerDefine(stc.STC_MARKNUM_FOLDER, \
253 self.MarkerDefine(stc.STC_MARKNUM_FOLDER, \
253 stc.STC_MARK_CIRCLEPLUS, "white", "#404040")
254 stc.STC_MARK_CIRCLEPLUS, "white", "#404040")
254 self.MarkerDefine(stc.STC_MARKNUM_FOLDERSUB, \
255 self.MarkerDefine(stc.STC_MARKNUM_FOLDERSUB, \
255 stc.STC_MARK_VLINE, "white", "#404040")
256 stc.STC_MARK_VLINE, "white", "#404040")
256 self.MarkerDefine(stc.STC_MARKNUM_FOLDERTAIL, \
257 self.MarkerDefine(stc.STC_MARKNUM_FOLDERTAIL, \
257 stc.STC_MARK_LCORNERCURVE, "white", "#404040")
258 stc.STC_MARK_LCORNERCURVE, "white", "#404040")
258 self.MarkerDefine(stc.STC_MARKNUM_FOLDEREND, \
259 self.MarkerDefine(stc.STC_MARKNUM_FOLDEREND, \
259 stc.STC_MARK_CIRCLEPLUSCONNECTED, "white", "#404040")
260 stc.STC_MARK_CIRCLEPLUSCONNECTED, "white", "#404040")
260 self.MarkerDefine(stc.STC_MARKNUM_FOLDEROPENMID, \
261 self.MarkerDefine(stc.STC_MARKNUM_FOLDEROPENMID, \
261 stc.STC_MARK_CIRCLEMINUSCONNECTED, "white", "#404040")
262 stc.STC_MARK_CIRCLEMINUSCONNECTED, "white", "#404040")
262 self.MarkerDefine(stc.STC_MARKNUM_FOLDERMIDTAIL, \
263 self.MarkerDefine(stc.STC_MARKNUM_FOLDERMIDTAIL, \
263 stc.STC_MARK_TCORNERCURVE, "white", "#404040")
264 stc.STC_MARK_TCORNERCURVE, "white", "#404040")
264
265
265 elif self.fold_symbols == 3:
266 elif self.fold_symbols == 3:
266 # Like a flattened tree control using square headers
267 # Like a flattened tree control using square headers
267 self.MarkerDefine(stc.STC_MARKNUM_FOLDEROPEN, \
268 self.MarkerDefine(stc.STC_MARKNUM_FOLDEROPEN, \
268 stc.STC_MARK_BOXMINUS, "white", "#808080")
269 stc.STC_MARK_BOXMINUS, "white", "#808080")
269 self.MarkerDefine(stc.STC_MARKNUM_FOLDER, \
270 self.MarkerDefine(stc.STC_MARKNUM_FOLDER, \
270 stc.STC_MARK_BOXPLUS, "white", "#808080")
271 stc.STC_MARK_BOXPLUS, "white", "#808080")
271 self.MarkerDefine(stc.STC_MARKNUM_FOLDERSUB, \
272 self.MarkerDefine(stc.STC_MARKNUM_FOLDERSUB, \
272 stc.STC_MARK_VLINE, "white", "#808080")
273 stc.STC_MARK_VLINE, "white", "#808080")
273 self.MarkerDefine(stc.STC_MARKNUM_FOLDERTAIL, \
274 self.MarkerDefine(stc.STC_MARKNUM_FOLDERTAIL, \
274 stc.STC_MARK_LCORNER, "white", "#808080")
275 stc.STC_MARK_LCORNER, "white", "#808080")
275 self.MarkerDefine(stc.STC_MARKNUM_FOLDEREND, \
276 self.MarkerDefine(stc.STC_MARKNUM_FOLDEREND, \
276 stc.STC_MARK_BOXPLUSCONNECTED, "white", "#808080")
277 stc.STC_MARK_BOXPLUSCONNECTED, "white", "#808080")
277 self.MarkerDefine(stc.STC_MARKNUM_FOLDEROPENMID, \
278 self.MarkerDefine(stc.STC_MARKNUM_FOLDEROPENMID, \
278 stc.STC_MARK_BOXMINUSCONNECTED, "white", "#808080")
279 stc.STC_MARK_BOXMINUSCONNECTED, "white", "#808080")
279 self.MarkerDefine(stc.STC_MARKNUM_FOLDERMIDTAIL, \
280 self.MarkerDefine(stc.STC_MARKNUM_FOLDERMIDTAIL, \
280 stc.STC_MARK_TCORNER, "white", "#808080")
281 stc.STC_MARK_TCORNER, "white", "#808080")
281
282
282
283
283 self.Bind(stc.EVT_STC_UPDATEUI, self.OnUpdateUI)
284 self.Bind(stc.EVT_STC_UPDATEUI, self.OnUpdateUI)
284 self.Bind(stc.EVT_STC_MARGINCLICK, self.OnMarginClick)
285 self.Bind(stc.EVT_STC_MARGINCLICK, self.OnMarginClick)
285 self.Bind(wx.EVT_KEY_DOWN, self.OnKeyPressed)
286 self.Bind(wx.EVT_KEY_DOWN, self.OnKeyPressed)
286
287
287 # Make some styles, The lexer defines what each style is used for, we
288 # Make some styles, The lexer defines what each style is used for, we
288 # just have to define what each style looks like. This set is adapted from
289 # just have to define what each style looks like. This set is adapted from
289 # Scintilla sample property files.
290 # Scintilla sample property files.
290
291
291 # Global default styles for all languages
292 # Global default styles for all languages
292 self.StyleSetSpec(stc.STC_STYLE_DEFAULT, "face:%(helv)s,size:%(size)d" % faces)
293 self.StyleSetSpec(stc.STC_STYLE_DEFAULT, "face:%(helv)s,size:%(size)d" % faces)
293 self.StyleClearAll() # Reset all to be like the default
294 self.StyleClearAll() # Reset all to be like the default
294
295
295 # Global default styles for all languages
296 # Global default styles for all languages
296 self.StyleSetSpec(stc.STC_STYLE_DEFAULT, "face:%(helv)s,size:%(size)d" % faces)
297 self.StyleSetSpec(stc.STC_STYLE_DEFAULT, "face:%(helv)s,size:%(size)d" % faces)
297 self.StyleSetSpec(stc.STC_STYLE_LINENUMBER, "back:#C0C0C0,face:%(helv)s,size:%(size2)d" % faces)
298 self.StyleSetSpec(stc.STC_STYLE_LINENUMBER, "back:#C0C0C0,face:%(helv)s,size:%(size2)d" % faces)
298 self.StyleSetSpec(stc.STC_STYLE_CONTROLCHAR, "face:%(other)s" % faces)
299 self.StyleSetSpec(stc.STC_STYLE_CONTROLCHAR, "face:%(other)s" % faces)
299 self.StyleSetSpec(stc.STC_STYLE_BRACELIGHT, "fore:#FFFFFF,back:#0000FF,bold")
300 self.StyleSetSpec(stc.STC_STYLE_BRACELIGHT, "fore:#FFFFFF,back:#0000FF,bold")
300 self.StyleSetSpec(stc.STC_STYLE_BRACEBAD, "fore:#000000,back:#FF0000,bold")
301 self.StyleSetSpec(stc.STC_STYLE_BRACEBAD, "fore:#000000,back:#FF0000,bold")
301
302
302 # Python styles
303 # Python styles
303 # Default
304 # Default
304 self.StyleSetSpec(stc.STC_P_DEFAULT, "fore:#000000,face:%(helv)s,size:%(size)d" % faces)
305 self.StyleSetSpec(stc.STC_P_DEFAULT, "fore:#000000,face:%(helv)s,size:%(size)d" % faces)
305 # Comments
306 # Comments
306 self.StyleSetSpec(stc.STC_P_COMMENTLINE, "fore:#007F00,face:%(other)s,size:%(size)d" % faces)
307 self.StyleSetSpec(stc.STC_P_COMMENTLINE, "fore:#007F00,face:%(other)s,size:%(size)d" % faces)
307 # Number
308 # Number
308 self.StyleSetSpec(stc.STC_P_NUMBER, "fore:#007F7F,size:%(size)d" % faces)
309 self.StyleSetSpec(stc.STC_P_NUMBER, "fore:#007F7F,size:%(size)d" % faces)
309 # String
310 # String
310 self.StyleSetSpec(stc.STC_P_STRING, "fore:#7F007F,face:%(helv)s,size:%(size)d" % faces)
311 self.StyleSetSpec(stc.STC_P_STRING, "fore:#7F007F,face:%(helv)s,size:%(size)d" % faces)
311 # Single quoted string
312 # Single quoted string
312 self.StyleSetSpec(stc.STC_P_CHARACTER, "fore:#7F007F,face:%(helv)s,size:%(size)d" % faces)
313 self.StyleSetSpec(stc.STC_P_CHARACTER, "fore:#7F007F,face:%(helv)s,size:%(size)d" % faces)
313 # Keyword
314 # Keyword
314 self.StyleSetSpec(stc.STC_P_WORD, "fore:#00007F,bold,size:%(size)d" % faces)
315 self.StyleSetSpec(stc.STC_P_WORD, "fore:#00007F,bold,size:%(size)d" % faces)
315 # Triple quotes
316 # Triple quotes
316 self.StyleSetSpec(stc.STC_P_TRIPLE, "fore:#7F0000,size:%(size)d" % faces)
317 self.StyleSetSpec(stc.STC_P_TRIPLE, "fore:#7F0000,size:%(size)d" % faces)
317 # Triple double quotes
318 # Triple double quotes
318 self.StyleSetSpec(stc.STC_P_TRIPLEDOUBLE, "fore:#7F0000,size:%(size)d" % faces)
319 self.StyleSetSpec(stc.STC_P_TRIPLEDOUBLE, "fore:#7F0000,size:%(size)d" % faces)
319 # Class name definition
320 # Class name definition
320 self.StyleSetSpec(stc.STC_P_CLASSNAME, "fore:#0000FF,bold,underline,size:%(size)d" % faces)
321 self.StyleSetSpec(stc.STC_P_CLASSNAME, "fore:#0000FF,bold,underline,size:%(size)d" % faces)
321 # Function or method name definition
322 # Function or method name definition
322 self.StyleSetSpec(stc.STC_P_DEFNAME, "fore:#007F7F,bold,size:%(size)d" % faces)
323 self.StyleSetSpec(stc.STC_P_DEFNAME, "fore:#007F7F,bold,size:%(size)d" % faces)
323 # Operators
324 # Operators
324 self.StyleSetSpec(stc.STC_P_OPERATOR, "bold,size:%(size)d" % faces)
325 self.StyleSetSpec(stc.STC_P_OPERATOR, "bold,size:%(size)d" % faces)
325 # Identifiers
326 # Identifiers
326 self.StyleSetSpec(stc.STC_P_IDENTIFIER, "fore:#000000,face:%(helv)s,size:%(size)d" % faces)
327 self.StyleSetSpec(stc.STC_P_IDENTIFIER, "fore:#000000,face:%(helv)s,size:%(size)d" % faces)
327 # Comment-blocks
328 # Comment-blocks
328 self.StyleSetSpec(stc.STC_P_COMMENTBLOCK, "fore:#7F7F7F,size:%(size)d" % faces)
329 self.StyleSetSpec(stc.STC_P_COMMENTBLOCK, "fore:#7F7F7F,size:%(size)d" % faces)
329 # End of line where string is not closed
330 # End of line where string is not closed
330 self.StyleSetSpec(stc.STC_P_STRINGEOL, "fore:#000000,face:%(mono)s,back:#E0C0E0,eol,size:%(size)d" % faces)
331 self.StyleSetSpec(stc.STC_P_STRINGEOL, "fore:#000000,face:%(mono)s,back:#E0C0E0,eol,size:%(size)d" % faces)
331
332
332 self.SetCaretForeground("BLUE")
333 self.SetCaretForeground("BLUE")
333
334
334
335
335 # register some images for use in the AutoComplete box.
336 # register some images for use in the AutoComplete box.
336 #self.RegisterImage(1, images.getSmilesBitmap())
337 #self.RegisterImage(1, images.getSmilesBitmap())
337 #self.RegisterImage(2,
338 #self.RegisterImage(2,
338 # wx.ArtProvider.GetBitmap(wx.ART_NEW, size=(16,16)))
339 # wx.ArtProvider.GetBitmap(wx.ART_NEW, size=(16,16)))
339 #self.RegisterImage(3,
340 #self.RegisterImage(3,
340 # wx.ArtProvider.GetBitmap(wx.ART_COPY, size=(16,16)))
341 # wx.ArtProvider.GetBitmap(wx.ART_COPY, size=(16,16)))
341
342
342
343
343 def OnKeyPressed(self, event):
344 def OnKeyPressed(self, event):
344 if self.CallTipActive():
345 if self.CallTipActive():
345 self.CallTipCancel()
346 self.CallTipCancel()
346 key = event.GetKeyCode()
347 key = event.GetKeyCode()
347
348
348 if key == 32 and event.ControlDown():
349 if key == 32 and event.ControlDown():
349 pos = self.GetCurrentPos()
350 pos = self.GetCurrentPos()
350
351
351 # Tips
352 # Tips
352 if event.ShiftDown():
353 if event.ShiftDown():
353 self.CallTipSetBackground("yellow")
354 self.CallTipSetBackground("yellow")
354 self.CallTipShow(pos, 'lots of of text: blah, blah, blah\n\n'
355 self.CallTipShow(pos, 'lots of of text: blah, blah, blah\n\n'
355 'show some suff, maybe parameters..\n\n'
356 'show some suff, maybe parameters..\n\n'
356 'fubar(param1, param2)')
357 'fubar(param1, param2)')
357 # Code completion
358 # Code completion
358 else:
359 else:
359 #lst = []
360 #lst = []
360 #for x in range(50000):
361 #for x in range(50000):
361 # lst.append('%05d' % x)
362 # lst.append('%05d' % x)
362 #st = " ".join(lst)
363 #st = " ".join(lst)
363 #print len(st)
364 #print len(st)
364 #self.AutoCompShow(0, st)
365 #self.AutoCompShow(0, st)
365
366
366 kw = keyword.kwlist[:]
367 kw = keyword.kwlist[:]
367
368
368 kw.sort() # Python sorts are case sensitive
369 kw.sort() # Python sorts are case sensitive
369 self.AutoCompSetIgnoreCase(False) # so this needs to match
370 self.AutoCompSetIgnoreCase(False) # so this needs to match
370
371
371 # Images are specified with a appended "?type"
372 # Images are specified with a appended "?type"
372 for i in range(len(kw)):
373 for i in range(len(kw)):
373 if kw[i] in keyword.kwlist:
374 if kw[i] in keyword.kwlist:
374 kw[i] = kw[i]# + "?1"
375 kw[i] = kw[i]# + "?1"
375
376
376 self.AutoCompShow(0, " ".join(kw))
377 self.AutoCompShow(0, " ".join(kw))
377 else:
378 else:
378 event.Skip()
379 event.Skip()
379
380
380
381
381 def OnUpdateUI(self, evt):
382 def OnUpdateUI(self, evt):
382 # check for matching braces
383 # check for matching braces
383 braceAtCaret = -1
384 braceAtCaret = -1
384 braceOpposite = -1
385 braceOpposite = -1
385 charBefore = None
386 charBefore = None
386 caretPos = self.GetCurrentPos()
387 caretPos = self.GetCurrentPos()
387
388
388 if caretPos > 0:
389 if caretPos > 0:
389 charBefore = self.GetCharAt(caretPos - 1)
390 charBefore = self.GetCharAt(caretPos - 1)
390 styleBefore = self.GetStyleAt(caretPos - 1)
391 styleBefore = self.GetStyleAt(caretPos - 1)
391
392
392 # check before
393 # check before
393 if charBefore and chr(charBefore) in "[]{}()" and styleBefore == stc.STC_P_OPERATOR:
394 if charBefore and chr(charBefore) in "[]{}()" and styleBefore == stc.STC_P_OPERATOR:
394 braceAtCaret = caretPos - 1
395 braceAtCaret = caretPos - 1
395
396
396 # check after
397 # check after
397 if braceAtCaret < 0:
398 if braceAtCaret < 0:
398 charAfter = self.GetCharAt(caretPos)
399 charAfter = self.GetCharAt(caretPos)
399 styleAfter = self.GetStyleAt(caretPos)
400 styleAfter = self.GetStyleAt(caretPos)
400
401
401 if charAfter and chr(charAfter) in "[]{}()" and styleAfter == stc.STC_P_OPERATOR:
402 if charAfter and chr(charAfter) in "[]{}()" and styleAfter == stc.STC_P_OPERATOR:
402 braceAtCaret = caretPos
403 braceAtCaret = caretPos
403
404
404 if braceAtCaret >= 0:
405 if braceAtCaret >= 0:
405 braceOpposite = self.BraceMatch(braceAtCaret)
406 braceOpposite = self.BraceMatch(braceAtCaret)
406
407
407 if braceAtCaret != -1 and braceOpposite == -1:
408 if braceAtCaret != -1 and braceOpposite == -1:
408 self.BraceBadLight(braceAtCaret)
409 self.BraceBadLight(braceAtCaret)
409 else:
410 else:
410 self.BraceHighlight(braceAtCaret, braceOpposite)
411 self.BraceHighlight(braceAtCaret, braceOpposite)
411 #pt = self.PointFromPosition(braceOpposite)
412 #pt = self.PointFromPosition(braceOpposite)
412 #self.Refresh(True, wxRect(pt.x, pt.y, 5,5))
413 #self.Refresh(True, wxRect(pt.x, pt.y, 5,5))
413 #print pt
414 #print pt
414 #self.Refresh(False)
415 #self.Refresh(False)
415
416
416
417
417 def OnMarginClick(self, evt):
418 def OnMarginClick(self, evt):
418 # fold and unfold as needed
419 # fold and unfold as needed
419 if evt.GetMargin() == 2:
420 if evt.GetMargin() == 2:
420 if evt.GetShift() and evt.GetControl():
421 if evt.GetShift() and evt.GetControl():
421 self.FoldAll()
422 self.FoldAll()
422 else:
423 else:
423 lineClicked = self.LineFromPosition(evt.GetPosition())
424 lineClicked = self.LineFromPosition(evt.GetPosition())
424
425
425 if self.GetFoldLevel(lineClicked) & stc.STC_FOLDLEVELHEADERFLAG:
426 if self.GetFoldLevel(lineClicked) & stc.STC_FOLDLEVELHEADERFLAG:
426 if evt.GetShift():
427 if evt.GetShift():
427 self.SetFoldExpanded(lineClicked, True)
428 self.SetFoldExpanded(lineClicked, True)
428 self.Expand(lineClicked, True, True, 1)
429 self.Expand(lineClicked, True, True, 1)
429 elif evt.GetControl():
430 elif evt.GetControl():
430 if self.GetFoldExpanded(lineClicked):
431 if self.GetFoldExpanded(lineClicked):
431 self.SetFoldExpanded(lineClicked, False)
432 self.SetFoldExpanded(lineClicked, False)
432 self.Expand(lineClicked, False, True, 0)
433 self.Expand(lineClicked, False, True, 0)
433 else:
434 else:
434 self.SetFoldExpanded(lineClicked, True)
435 self.SetFoldExpanded(lineClicked, True)
435 self.Expand(lineClicked, True, True, 100)
436 self.Expand(lineClicked, True, True, 100)
436 else:
437 else:
437 self.ToggleFold(lineClicked)
438 self.ToggleFold(lineClicked)
438
439
439
440
440 def FoldAll(self):
441 def FoldAll(self):
441 lineCount = self.GetLineCount()
442 lineCount = self.GetLineCount()
442 expanding = True
443 expanding = True
443
444
444 # find out if we are folding or unfolding
445 # find out if we are folding or unfolding
445 for lineNum in range(lineCount):
446 for lineNum in range(lineCount):
446 if self.GetFoldLevel(lineNum) & stc.STC_FOLDLEVELHEADERFLAG:
447 if self.GetFoldLevel(lineNum) & stc.STC_FOLDLEVELHEADERFLAG:
447 expanding = not self.GetFoldExpanded(lineNum)
448 expanding = not self.GetFoldExpanded(lineNum)
448 break
449 break
449
450
450 lineNum = 0
451 lineNum = 0
451
452
452 while lineNum < lineCount:
453 while lineNum < lineCount:
453 level = self.GetFoldLevel(lineNum)
454 level = self.GetFoldLevel(lineNum)
454 if level & stc.STC_FOLDLEVELHEADERFLAG and \
455 if level & stc.STC_FOLDLEVELHEADERFLAG and \
455 (level & stc.STC_FOLDLEVELNUMBERMASK) == stc.STC_FOLDLEVELBASE:
456 (level & stc.STC_FOLDLEVELNUMBERMASK) == stc.STC_FOLDLEVELBASE:
456
457
457 if expanding:
458 if expanding:
458 self.SetFoldExpanded(lineNum, True)
459 self.SetFoldExpanded(lineNum, True)
459 lineNum = self.Expand(lineNum, True)
460 lineNum = self.Expand(lineNum, True)
460 lineNum = lineNum - 1
461 lineNum = lineNum - 1
461 else:
462 else:
462 lastChild = self.GetLastChild(lineNum, -1)
463 lastChild = self.GetLastChild(lineNum, -1)
463 self.SetFoldExpanded(lineNum, False)
464 self.SetFoldExpanded(lineNum, False)
464
465
465 if lastChild > lineNum:
466 if lastChild > lineNum:
466 self.HideLines(lineNum+1, lastChild)
467 self.HideLines(lineNum+1, lastChild)
467
468
468 lineNum = lineNum + 1
469 lineNum = lineNum + 1
469
470
470
471
471
472
472 def Expand(self, line, doExpand, force=False, visLevels=0, level=-1):
473 def Expand(self, line, doExpand, force=False, visLevels=0, level=-1):
473 lastChild = self.GetLastChild(line, level)
474 lastChild = self.GetLastChild(line, level)
474 line = line + 1
475 line = line + 1
475
476
476 while line <= lastChild:
477 while line <= lastChild:
477 if force:
478 if force:
478 if visLevels > 0:
479 if visLevels > 0:
479 self.ShowLines(line, line)
480 self.ShowLines(line, line)
480 else:
481 else:
481 self.HideLines(line, line)
482 self.HideLines(line, line)
482 else:
483 else:
483 if doExpand:
484 if doExpand:
484 self.ShowLines(line, line)
485 self.ShowLines(line, line)
485
486
486 if level == -1:
487 if level == -1:
487 level = self.GetFoldLevel(line)
488 level = self.GetFoldLevel(line)
488
489
489 if level & stc.STC_FOLDLEVELHEADERFLAG:
490 if level & stc.STC_FOLDLEVELHEADERFLAG:
490 if force:
491 if force:
491 if visLevels > 1:
492 if visLevels > 1:
492 self.SetFoldExpanded(line, True)
493 self.SetFoldExpanded(line, True)
493 else:
494 else:
494 self.SetFoldExpanded(line, False)
495 self.SetFoldExpanded(line, False)
495
496
496 line = self.Expand(line, doExpand, force, visLevels-1)
497 line = self.Expand(line, doExpand, force, visLevels-1)
497
498
498 else:
499 else:
499 if doExpand and self.GetFoldExpanded(line):
500 if doExpand and self.GetFoldExpanded(line):
500 line = self.Expand(line, True, force, visLevels-1)
501 line = self.Expand(line, True, force, visLevels-1)
501 else:
502 else:
502 line = self.Expand(line, False, force, visLevels-1)
503 line = self.Expand(line, False, force, visLevels-1)
503 else:
504 else:
504 line = line + 1
505 line = line + 1
505
506
506 return line
507 return line
507
508
508
509
509 #----------------------------------------------------------------------
510 #----------------------------------------------------------------------
@@ -1,460 +1,463 b''
1 #!/usr/bin/env python
1 #!/usr/bin/env python
2 # encoding: utf-8
2 # encoding: utf-8
3 """
3 """
4 The ipcluster application.
4 The ipcluster application.
5 """
5 """
6
6
7 #-----------------------------------------------------------------------------
7 #-----------------------------------------------------------------------------
8 # Copyright (C) 2008-2009 The IPython Development Team
8 # Copyright (C) 2008-2009 The IPython Development Team
9 #
9 #
10 # Distributed under the terms of the BSD License. The full license is in
10 # Distributed under the terms of the BSD License. The full license is in
11 # the file COPYING, distributed as part of this software.
11 # the file COPYING, distributed as part of this software.
12 #-----------------------------------------------------------------------------
12 #-----------------------------------------------------------------------------
13
13
14 #-----------------------------------------------------------------------------
14 #-----------------------------------------------------------------------------
15 # Imports
15 # Imports
16 #-----------------------------------------------------------------------------
16 #-----------------------------------------------------------------------------
17
17
18 import logging
18 import logging
19 import os
19 import os
20 import signal
20 import signal
21
21
22 if os.name=='posix':
22 if os.name=='posix':
23 from twisted.scripts._twistd_unix import daemonize
23 from twisted.scripts._twistd_unix import daemonize
24
24
25 from IPython.core import release
25 from IPython.core import release
26 from IPython.external.argparse import ArgumentParser
26 from IPython.external.argparse import ArgumentParser
27 from IPython.config.loader import ArgParseConfigLoader, NoConfigDefault
27 from IPython.config.loader import ArgParseConfigLoader, NoConfigDefault
28 from IPython.utils.importstring import import_item
28 from IPython.utils.importstring import import_item
29
29
30 from IPython.kernel.clusterdir import (
30 from IPython.kernel.clusterdir import (
31 ApplicationWithClusterDir, ClusterDirError, PIDFileError
31 ApplicationWithClusterDir, ClusterDirError, PIDFileError
32 )
32 )
33
33
34 from twisted.internet import reactor, defer
34 from twisted.internet import reactor, defer
35 from twisted.python import log, failure
35 from twisted.python import log, failure
36
36
37
37
38 #-----------------------------------------------------------------------------
38 #-----------------------------------------------------------------------------
39 # The ipcluster application
39 # The ipcluster application
40 #-----------------------------------------------------------------------------
40 #-----------------------------------------------------------------------------
41
41
42
42
43 # Exit codes for ipcluster
43 # Exit codes for ipcluster
44
44
45 # This will be the exit code if the ipcluster appears to be running because
45 # This will be the exit code if the ipcluster appears to be running because
46 # a .pid file exists
46 # a .pid file exists
47 ALREADY_STARTED = 10
47 ALREADY_STARTED = 10
48
48
49 # This will be the exit code if ipcluster stop is run, but there is not .pid
49 # This will be the exit code if ipcluster stop is run, but there is not .pid
50 # file to be found.
50 # file to be found.
51 ALREADY_STOPPED = 11
51 ALREADY_STOPPED = 11
52
52
53
53
54 class IPClusterCLLoader(ArgParseConfigLoader):
54 class IPClusterCLLoader(ArgParseConfigLoader):
55
55
56 def _add_other_arguments(self):
56 def _add_other_arguments(self):
57 # This has all the common options that all subcommands use
57 # This has all the common options that all subcommands use
58 parent_parser1 = ArgumentParser(add_help=False,
58 parent_parser1 = ArgumentParser(add_help=False,
59 argument_default=NoConfigDefault)
59 argument_default=NoConfigDefault)
60 parent_parser1.add_argument('--ipython-dir',
60 parent_parser1.add_argument('--ipython-dir',
61 dest='Global.ipython_dir',type=unicode,
61 dest='Global.ipython_dir',type=unicode,
62 help='Set to override default location of Global.ipython_dir.',
62 help='Set to override default location of Global.ipython_dir.',
63 metavar='Global.ipython_dir')
63 metavar='Global.ipython_dir')
64 parent_parser1.add_argument('--log-level',
64 parent_parser1.add_argument('--log-level',
65 dest="Global.log_level",type=int,
65 dest="Global.log_level",type=int,
66 help='Set the log level (0,10,20,30,40,50). Default is 30.',
66 help='Set the log level (0,10,20,30,40,50). Default is 30.',
67 metavar='Global.log_level')
67 metavar='Global.log_level')
68
68
69 # This has all the common options that other subcommands use
69 # This has all the common options that other subcommands use
70 parent_parser2 = ArgumentParser(add_help=False,
70 parent_parser2 = ArgumentParser(add_help=False,
71 argument_default=NoConfigDefault)
71 argument_default=NoConfigDefault)
72 parent_parser2.add_argument('-p','--profile',
72 parent_parser2.add_argument('-p','--profile',
73 dest='Global.profile',type=unicode,
73 dest='Global.profile',type=unicode,
74 help='The string name of the profile to be used. This determines '
74 help='The string name of the profile to be used. This determines '
75 'the name of the cluster dir as: cluster_<profile>. The default profile '
75 'the name of the cluster dir as: cluster_<profile>. The default profile '
76 'is named "default". The cluster directory is resolve this way '
76 'is named "default". The cluster directory is resolve this way '
77 'if the --cluster-dir option is not used.',
77 'if the --cluster-dir option is not used.',
78 metavar='Global.profile')
78 metavar='Global.profile')
79 parent_parser2.add_argument('--cluster-dir',
79 parent_parser2.add_argument('--cluster-dir',
80 dest='Global.cluster_dir',type=unicode,
80 dest='Global.cluster_dir',type=unicode,
81 help='Set the cluster dir. This overrides the logic used by the '
81 help='Set the cluster dir. This overrides the logic used by the '
82 '--profile option.',
82 '--profile option.',
83 metavar='Global.cluster_dir'),
83 metavar='Global.cluster_dir'),
84 parent_parser2.add_argument('--work-dir',
84 parent_parser2.add_argument('--work-dir',
85 dest='Global.work_dir',type=unicode,
85 dest='Global.work_dir',type=unicode,
86 help='Set the working dir for the process.',
86 help='Set the working dir for the process.',
87 metavar='Global.work_dir')
87 metavar='Global.work_dir')
88 parent_parser2.add_argument('--log-to-file',
88 parent_parser2.add_argument('--log-to-file',
89 action='store_true', dest='Global.log_to_file',
89 action='store_true', dest='Global.log_to_file',
90 help='Log to a file in the log directory (default is stdout)'
90 help='Log to a file in the log directory (default is stdout)'
91 )
91 )
92
92
93 subparsers = self.parser.add_subparsers(
93 subparsers = self.parser.add_subparsers(
94 dest='Global.subcommand',
94 dest='Global.subcommand',
95 title='ipcluster subcommands',
95 title='ipcluster subcommands',
96 description='ipcluster has a variety of subcommands. '
96 description='ipcluster has a variety of subcommands. '
97 'The general way of running ipcluster is "ipcluster <cmd> '
97 'The general way of running ipcluster is "ipcluster <cmd> '
98 ' [options]""',
98 ' [options]""',
99 help='For more help, type "ipcluster <cmd> -h"')
99 help='For more help, type "ipcluster <cmd> -h"')
100
100
101 parser_list = subparsers.add_parser(
101 parser_list = subparsers.add_parser(
102 'list',
102 'list',
103 help='List all clusters in cwd and ipython_dir.',
103 help='List all clusters in cwd and ipython_dir.',
104 parents=[parent_parser1]
104 parents=[parent_parser1]
105 )
105 )
106
106
107 parser_create = subparsers.add_parser(
107 parser_create = subparsers.add_parser(
108 'create',
108 'create',
109 help='Create a new cluster directory.',
109 help='Create a new cluster directory.',
110 parents=[parent_parser1, parent_parser2]
110 parents=[parent_parser1, parent_parser2]
111 )
111 )
112 parser_create.add_argument(
112 parser_create.add_argument(
113 '--reset-config',
113 '--reset-config',
114 dest='Global.reset_config', action='store_true',
114 dest='Global.reset_config', action='store_true',
115 default=NoConfigDefault,
115 default=NoConfigDefault,
116 help='Recopy the default config files to the cluster directory. '
116 help='Recopy the default config files to the cluster directory. '
117 'You will loose any modifications you have made to these files.'
117 'You will loose any modifications you have made to these files.'
118 )
118 )
119
119
120 parser_start = subparsers.add_parser(
120 parser_start = subparsers.add_parser(
121 'start',
121 'start',
122 help='Start a cluster.',
122 help='Start a cluster.',
123 parents=[parent_parser1, parent_parser2]
123 parents=[parent_parser1, parent_parser2]
124 )
124 )
125 parser_start.add_argument(
125 parser_start.add_argument(
126 '-n', '--number',
126 '-n', '--number',
127 type=int, dest='Global.n',
127 type=int, dest='Global.n',
128 help='The number of engines to start.',
128 help='The number of engines to start.',
129 metavar='Global.n'
129 metavar='Global.n'
130 )
130 )
131 parser_start.add_argument('--clean-logs',
131 parser_start.add_argument('--clean-logs',
132 dest='Global.clean_logs', action='store_true',
132 dest='Global.clean_logs', action='store_true',
133 help='Delete old log flies before starting.',
133 help='Delete old log flies before starting.',
134 )
134 )
135 parser_start.add_argument('--no-clean-logs',
135 parser_start.add_argument('--no-clean-logs',
136 dest='Global.clean_logs', action='store_false',
136 dest='Global.clean_logs', action='store_false',
137 help="Don't delete old log flies before starting.",
137 help="Don't delete old log flies before starting.",
138 )
138 )
139 parser_start.add_argument('--daemon',
139 parser_start.add_argument('--daemon',
140 dest='Global.daemonize', action='store_true',
140 dest='Global.daemonize', action='store_true',
141 help='Daemonize the ipcluster program. This implies --log-to-file',
141 help='Daemonize the ipcluster program. This implies --log-to-file',
142 )
142 )
143 parser_start.add_argument('--no-daemon',
143 parser_start.add_argument('--no-daemon',
144 dest='Global.daemonize', action='store_false',
144 dest='Global.daemonize', action='store_false',
145 help="Dont't daemonize the ipcluster program.",
145 help="Dont't daemonize the ipcluster program.",
146 )
146 )
147
147
148 parser_start = subparsers.add_parser(
148 parser_start = subparsers.add_parser(
149 'stop',
149 'stop',
150 help='Stop a cluster.',
150 help='Stop a cluster.',
151 parents=[parent_parser1, parent_parser2]
151 parents=[parent_parser1, parent_parser2]
152 )
152 )
153 parser_start.add_argument('--signal',
153 parser_start.add_argument('--signal',
154 dest='Global.signal', type=int,
154 dest='Global.signal', type=int,
155 help="The signal number to use in stopping the cluster (default=2).",
155 help="The signal number to use in stopping the cluster (default=2).",
156 metavar="Global.signal",
156 metavar="Global.signal",
157 )
157 )
158
158
159
159
160 default_config_file_name = u'ipcluster_config.py'
160 default_config_file_name = u'ipcluster_config.py'
161
161
162
162
163 _description = """Start an IPython cluster for parallel computing.\n\n
163 _description = """Start an IPython cluster for parallel computing.\n\n
164
164
165 An IPython cluster consists of 1 controller and 1 or more engines.
165 An IPython cluster consists of 1 controller and 1 or more engines.
166 This command automates the startup of these processes using a wide
166 This command automates the startup of these processes using a wide
167 range of startup methods (SSH, local processes, PBS, mpiexec,
167 range of startup methods (SSH, local processes, PBS, mpiexec,
168 Windows HPC Server 2008). To start a cluster with 4 engines on your
168 Windows HPC Server 2008). To start a cluster with 4 engines on your
169 local host simply do "ipcluster start -n 4". For more complex usage
169 local host simply do "ipcluster start -n 4". For more complex usage
170 you will typically do "ipcluster create -p mycluster", then edit
170 you will typically do "ipcluster create -p mycluster", then edit
171 configuration files, followed by "ipcluster start -p mycluster -n 4".
171 configuration files, followed by "ipcluster start -p mycluster -n 4".
172 """
172 """
173
173
174
174
175 class IPClusterApp(ApplicationWithClusterDir):
175 class IPClusterApp(ApplicationWithClusterDir):
176
176
177 name = u'ipcluster'
177 name = u'ipcluster'
178 description = _description
178 description = _description
179 config_file_name = default_config_file_name
179 config_file_name = default_config_file_name
180 default_log_level = logging.INFO
180 default_log_level = logging.INFO
181 auto_create_cluster_dir = False
181 auto_create_cluster_dir = False
182
182
183 def create_default_config(self):
183 def create_default_config(self):
184 super(IPClusterApp, self).create_default_config()
184 super(IPClusterApp, self).create_default_config()
185 self.default_config.Global.controller_launcher = \
185 self.default_config.Global.controller_launcher = \
186 'IPython.kernel.launcher.LocalControllerLauncher'
186 'IPython.kernel.launcher.LocalControllerLauncher'
187 self.default_config.Global.engine_launcher = \
187 self.default_config.Global.engine_launcher = \
188 'IPython.kernel.launcher.LocalEngineSetLauncher'
188 'IPython.kernel.launcher.LocalEngineSetLauncher'
189 self.default_config.Global.n = 2
189 self.default_config.Global.n = 2
190 self.default_config.Global.reset_config = False
190 self.default_config.Global.reset_config = False
191 self.default_config.Global.clean_logs = True
191 self.default_config.Global.clean_logs = True
192 self.default_config.Global.signal = 2
192 self.default_config.Global.signal = 2
193 self.default_config.Global.daemonize = False
193 self.default_config.Global.daemonize = False
194
194
195 def create_command_line_config(self):
195 def create_command_line_config(self):
196 """Create and return a command line config loader."""
196 """Create and return a command line config loader."""
197 return IPClusterCLLoader(
197 return IPClusterCLLoader(
198 description=self.description,
198 description=self.description,
199 version=release.version
199 version=release.version
200 )
200 )
201
201
202 def find_resources(self):
202 def find_resources(self):
203 subcommand = self.command_line_config.Global.subcommand
203 subcommand = self.command_line_config.Global.subcommand
204 if subcommand=='list':
204 if subcommand=='list':
205 self.list_cluster_dirs()
205 self.list_cluster_dirs()
206 # Exit immediately because there is nothing left to do.
206 # Exit immediately because there is nothing left to do.
207 self.exit()
207 self.exit()
208 elif subcommand=='create':
208 elif subcommand=='create':
209 self.auto_create_cluster_dir = True
209 self.auto_create_cluster_dir = True
210 super(IPClusterApp, self).find_resources()
210 super(IPClusterApp, self).find_resources()
211 elif subcommand=='start' or subcommand=='stop':
211 elif subcommand=='start' or subcommand=='stop':
212 self.auto_create_cluster_dir = True
212 self.auto_create_cluster_dir = True
213 try:
213 try:
214 super(IPClusterApp, self).find_resources()
214 super(IPClusterApp, self).find_resources()
215 except ClusterDirError:
215 except ClusterDirError:
216 raise ClusterDirError(
216 raise ClusterDirError(
217 "Could not find a cluster directory. A cluster dir must "
217 "Could not find a cluster directory. A cluster dir must "
218 "be created before running 'ipcluster start'. Do "
218 "be created before running 'ipcluster start'. Do "
219 "'ipcluster create -h' or 'ipcluster list -h' for more "
219 "'ipcluster create -h' or 'ipcluster list -h' for more "
220 "information about creating and listing cluster dirs."
220 "information about creating and listing cluster dirs."
221 )
221 )
222
222
223 def list_cluster_dirs(self):
223 def list_cluster_dirs(self):
224 # Find the search paths
224 # Find the search paths
225 cluster_dir_paths = os.environ.get('IPCLUSTER_DIR_PATH','')
225 cluster_dir_paths = os.environ.get('IPCLUSTER_DIR_PATH','')
226 if cluster_dir_paths:
226 if cluster_dir_paths:
227 cluster_dir_paths = cluster_dir_paths.split(':')
227 cluster_dir_paths = cluster_dir_paths.split(':')
228 else:
228 else:
229 cluster_dir_paths = []
229 cluster_dir_paths = []
230 try:
230 try:
231 ipython_dir = self.command_line_config.Global.ipython_dir
231 ipython_dir = self.command_line_config.Global.ipython_dir
232 except AttributeError:
232 except AttributeError:
233 ipython_dir = self.default_config.Global.ipython_dir
233 ipython_dir = self.default_config.Global.ipython_dir
234 paths = [os.getcwd(), ipython_dir] + \
234 paths = [os.getcwd(), ipython_dir] + \
235 cluster_dir_paths
235 cluster_dir_paths
236 paths = list(set(paths))
236 paths = list(set(paths))
237
237
238 self.log.info('Searching for cluster dirs in paths: %r' % paths)
238 self.log.info('Searching for cluster dirs in paths: %r' % paths)
239 for path in paths:
239 for path in paths:
240 files = os.listdir(path)
240 files = os.listdir(path)
241 for f in files:
241 for f in files:
242 full_path = os.path.join(path, f)
242 full_path = os.path.join(path, f)
243 if os.path.isdir(full_path) and f.startswith('cluster_'):
243 if os.path.isdir(full_path) and f.startswith('cluster_'):
244 profile = full_path.split('_')[-1]
244 profile = full_path.split('_')[-1]
245 start_cmd = 'ipcluster start -p %s -n 4' % profile
245 start_cmd = 'ipcluster start -p %s -n 4' % profile
246 print start_cmd + " ==> " + full_path
246 print start_cmd + " ==> " + full_path
247
247
248 def pre_construct(self):
248 def pre_construct(self):
249 # IPClusterApp.pre_construct() is where we cd to the working directory.
249 # IPClusterApp.pre_construct() is where we cd to the working directory.
250 super(IPClusterApp, self).pre_construct()
250 super(IPClusterApp, self).pre_construct()
251 config = self.master_config
251 config = self.master_config
252 try:
252 try:
253 daemon = config.Global.daemonize
253 daemon = config.Global.daemonize
254 if daemon:
254 if daemon:
255 config.Global.log_to_file = True
255 config.Global.log_to_file = True
256 except AttributeError:
256 except AttributeError:
257 pass
257 pass
258
258
259 def construct(self):
259 def construct(self):
260 config = self.master_config
260 config = self.master_config
261 subcmd = config.Global.subcommand
261 subcmd = config.Global.subcommand
262 reset = config.Global.reset_config
262 reset = config.Global.reset_config
263 if subcmd == 'list':
263 if subcmd == 'list':
264 return
264 return
265 if subcmd == 'create':
265 if subcmd == 'create':
266 self.log.info('Copying default config files to cluster directory '
266 self.log.info('Copying default config files to cluster directory '
267 '[overwrite=%r]' % (reset,))
267 '[overwrite=%r]' % (reset,))
268 self.cluster_dir_obj.copy_all_config_files(overwrite=reset)
268 self.cluster_dir_obj.copy_all_config_files(overwrite=reset)
269 if subcmd =='start':
269 if subcmd =='start':
270 self.cluster_dir_obj.copy_all_config_files(overwrite=False)
270 self.cluster_dir_obj.copy_all_config_files(overwrite=False)
271 self.start_logging()
271 self.start_logging()
272 reactor.callWhenRunning(self.start_launchers)
272 reactor.callWhenRunning(self.start_launchers)
273
273
274 def start_launchers(self):
274 def start_launchers(self):
275 config = self.master_config
275 config = self.master_config
276
276
277 # Create the launchers. In both bases, we set the work_dir of
277 # Create the launchers. In both bases, we set the work_dir of
278 # the launcher to the cluster_dir. This is where the launcher's
278 # the launcher to the cluster_dir. This is where the launcher's
279 # subprocesses will be launched. It is not where the controller
279 # subprocesses will be launched. It is not where the controller
280 # and engine will be launched.
280 # and engine will be launched.
281 el_class = import_item(config.Global.engine_launcher)
281 el_class = import_item(config.Global.engine_launcher)
282 self.engine_launcher = el_class(
282 self.engine_launcher = el_class(
283 work_dir=self.cluster_dir, config=config
283 work_dir=self.cluster_dir, config=config
284 )
284 )
285 cl_class = import_item(config.Global.controller_launcher)
285 cl_class = import_item(config.Global.controller_launcher)
286 self.controller_launcher = cl_class(
286 self.controller_launcher = cl_class(
287 work_dir=self.cluster_dir, config=config
287 work_dir=self.cluster_dir, config=config
288 )
288 )
289
289
290 # Setup signals
290 # Setup signals
291 signal.signal(signal.SIGINT, self.sigint_handler)
291 signal.signal(signal.SIGINT, self.sigint_handler)
292
292
293 # Setup the observing of stopping. If the controller dies, shut
293 # Setup the observing of stopping. If the controller dies, shut
294 # everything down as that will be completely fatal for the engines.
294 # everything down as that will be completely fatal for the engines.
295 d1 = self.controller_launcher.observe_stop()
295 d1 = self.controller_launcher.observe_stop()
296 d1.addCallback(self.stop_launchers)
296 d1.addCallback(self.stop_launchers)
297 # But, we don't monitor the stopping of engines. An engine dying
297 # But, we don't monitor the stopping of engines. An engine dying
298 # is just fine and in principle a user could start a new engine.
298 # is just fine and in principle a user could start a new engine.
299 # Also, if we did monitor engine stopping, it is difficult to
299 # Also, if we did monitor engine stopping, it is difficult to
300 # know what to do when only some engines die. Currently, the
300 # know what to do when only some engines die. Currently, the
301 # observing of engine stopping is inconsistent. Some launchers
301 # observing of engine stopping is inconsistent. Some launchers
302 # might trigger on a single engine stopping, other wait until
302 # might trigger on a single engine stopping, other wait until
303 # all stop. TODO: think more about how to handle this.
303 # all stop. TODO: think more about how to handle this.
304
304
305 # Start the controller and engines
305 # Start the controller and engines
306 self._stopping = False # Make sure stop_launchers is not called 2x.
306 self._stopping = False # Make sure stop_launchers is not called 2x.
307 d = self.start_controller()
307 d = self.start_controller()
308 d.addCallback(self.start_engines)
308 d.addCallback(self.start_engines)
309 d.addCallback(self.startup_message)
309 d.addCallback(self.startup_message)
310 # If the controller or engines fail to start, stop everything
310 # If the controller or engines fail to start, stop everything
311 d.addErrback(self.stop_launchers)
311 d.addErrback(self.stop_launchers)
312 return d
312 return d
313
313
314 def startup_message(self, r=None):
314 def startup_message(self, r=None):
315 log.msg("IPython cluster: started")
315 log.msg("IPython cluster: started")
316 return r
316 return r
317
317
318 def start_controller(self, r=None):
318 def start_controller(self, r=None):
319 # log.msg("In start_controller")
319 # log.msg("In start_controller")
320 config = self.master_config
320 config = self.master_config
321 d = self.controller_launcher.start(
321 d = self.controller_launcher.start(
322 cluster_dir=config.Global.cluster_dir
322 cluster_dir=config.Global.cluster_dir
323 )
323 )
324 return d
324 return d
325
325
326 def start_engines(self, r=None):
326 def start_engines(self, r=None):
327 # log.msg("In start_engines")
327 # log.msg("In start_engines")
328 config = self.master_config
328 config = self.master_config
329 d = self.engine_launcher.start(
329 d = self.engine_launcher.start(
330 config.Global.n,
330 config.Global.n,
331 cluster_dir=config.Global.cluster_dir
331 cluster_dir=config.Global.cluster_dir
332 )
332 )
333 return d
333 return d
334
334
335 def stop_controller(self, r=None):
335 def stop_controller(self, r=None):
336 # log.msg("In stop_controller")
336 # log.msg("In stop_controller")
337 if self.controller_launcher.running:
337 if self.controller_launcher.running:
338 d = self.controller_launcher.stop()
338 d = self.controller_launcher.stop()
339 d.addErrback(self.log_err)
339 d.addErrback(self.log_err)
340 return d
340 return d
341 else:
341 else:
342 return defer.succeed(None)
342 return defer.succeed(None)
343
343
344 def stop_engines(self, r=None):
344 def stop_engines(self, r=None):
345 # log.msg("In stop_engines")
345 # log.msg("In stop_engines")
346 if self.engine_launcher.running:
346 if self.engine_launcher.running:
347 d = self.engine_launcher.stop()
347 d = self.engine_launcher.stop()
348 d.addErrback(self.log_err)
348 d.addErrback(self.log_err)
349 return d
349 return d
350 else:
350 else:
351 return defer.succeed(None)
351 return defer.succeed(None)
352
352
353 def log_err(self, f):
353 def log_err(self, f):
354 log.msg(f.getTraceback())
354 log.msg(f.getTraceback())
355 return None
355 return None
356
356
357 def stop_launchers(self, r=None):
357 def stop_launchers(self, r=None):
358 if not self._stopping:
358 if not self._stopping:
359 self._stopping = True
359 self._stopping = True
360 if isinstance(r, failure.Failure):
360 if isinstance(r, failure.Failure):
361 log.msg('Unexpected error in ipcluster:')
361 log.msg('Unexpected error in ipcluster:')
362 log.msg(r.getTraceback())
362 log.msg(r.getTraceback())
363 log.msg("IPython cluster: stopping")
363 log.msg("IPython cluster: stopping")
364 self.stop_engines()
364 # These return deferreds. We are not doing anything with them
365 self.stop_controller()
365 # but we are holding refs to them as a reminder that they
366 # do return deferreds.
367 d1 = self.stop_engines()
368 d2 = self.stop_controller()
366 # Wait a few seconds to let things shut down.
369 # Wait a few seconds to let things shut down.
367 reactor.callLater(4.0, reactor.stop)
370 reactor.callLater(4.0, reactor.stop)
368
371
369 def sigint_handler(self, signum, frame):
372 def sigint_handler(self, signum, frame):
370 self.stop_launchers()
373 self.stop_launchers()
371
374
372 def start_logging(self):
375 def start_logging(self):
373 # Remove old log files of the controller and engine
376 # Remove old log files of the controller and engine
374 if self.master_config.Global.clean_logs:
377 if self.master_config.Global.clean_logs:
375 log_dir = self.master_config.Global.log_dir
378 log_dir = self.master_config.Global.log_dir
376 for f in os.listdir(log_dir):
379 for f in os.listdir(log_dir):
377 if f.startswith('ipengine' + '-'):
380 if f.startswith('ipengine' + '-'):
378 if f.endswith('.log') or f.endswith('.out') or f.endswith('.err'):
381 if f.endswith('.log') or f.endswith('.out') or f.endswith('.err'):
379 os.remove(os.path.join(log_dir, f))
382 os.remove(os.path.join(log_dir, f))
380 if f.startswith('ipcontroller' + '-'):
383 if f.startswith('ipcontroller' + '-'):
381 if f.endswith('.log') or f.endswith('.out') or f.endswith('.err'):
384 if f.endswith('.log') or f.endswith('.out') or f.endswith('.err'):
382 os.remove(os.path.join(log_dir, f))
385 os.remove(os.path.join(log_dir, f))
383 # This will remote old log files for ipcluster itself
386 # This will remote old log files for ipcluster itself
384 super(IPClusterApp, self).start_logging()
387 super(IPClusterApp, self).start_logging()
385
388
386 def start_app(self):
389 def start_app(self):
387 """Start the application, depending on what subcommand is used."""
390 """Start the application, depending on what subcommand is used."""
388 subcmd = self.master_config.Global.subcommand
391 subcmd = self.master_config.Global.subcommand
389 if subcmd=='create' or subcmd=='list':
392 if subcmd=='create' or subcmd=='list':
390 return
393 return
391 elif subcmd=='start':
394 elif subcmd=='start':
392 self.start_app_start()
395 self.start_app_start()
393 elif subcmd=='stop':
396 elif subcmd=='stop':
394 self.start_app_stop()
397 self.start_app_stop()
395
398
396 def start_app_start(self):
399 def start_app_start(self):
397 """Start the app for the start subcommand."""
400 """Start the app for the start subcommand."""
398 config = self.master_config
401 config = self.master_config
399 # First see if the cluster is already running
402 # First see if the cluster is already running
400 try:
403 try:
401 pid = self.get_pid_from_file()
404 pid = self.get_pid_from_file()
402 except PIDFileError:
405 except PIDFileError:
403 pass
406 pass
404 else:
407 else:
405 self.log.critical(
408 self.log.critical(
406 'Cluster is already running with [pid=%s]. '
409 'Cluster is already running with [pid=%s]. '
407 'use "ipcluster stop" to stop the cluster.' % pid
410 'use "ipcluster stop" to stop the cluster.' % pid
408 )
411 )
409 # Here I exit with a unusual exit status that other processes
412 # Here I exit with a unusual exit status that other processes
410 # can watch for to learn how I existed.
413 # can watch for to learn how I existed.
411 self.exit(ALREADY_STARTED)
414 self.exit(ALREADY_STARTED)
412
415
413 # Now log and daemonize
416 # Now log and daemonize
414 self.log.info(
417 self.log.info(
415 'Starting ipcluster with [daemon=%r]' % config.Global.daemonize
418 'Starting ipcluster with [daemon=%r]' % config.Global.daemonize
416 )
419 )
417 # TODO: Get daemonize working on Windows or as a Windows Server.
420 # TODO: Get daemonize working on Windows or as a Windows Server.
418 if config.Global.daemonize:
421 if config.Global.daemonize:
419 if os.name=='posix':
422 if os.name=='posix':
420 daemonize()
423 daemonize()
421
424
422 # Now write the new pid file AFTER our new forked pid is active.
425 # Now write the new pid file AFTER our new forked pid is active.
423 self.write_pid_file()
426 self.write_pid_file()
424 reactor.addSystemEventTrigger('during','shutdown', self.remove_pid_file)
427 reactor.addSystemEventTrigger('during','shutdown', self.remove_pid_file)
425 reactor.run()
428 reactor.run()
426
429
427 def start_app_stop(self):
430 def start_app_stop(self):
428 """Start the app for the stop subcommand."""
431 """Start the app for the stop subcommand."""
429 config = self.master_config
432 config = self.master_config
430 try:
433 try:
431 pid = self.get_pid_from_file()
434 pid = self.get_pid_from_file()
432 except PIDFileError:
435 except PIDFileError:
433 self.log.critical(
436 self.log.critical(
434 'Problem reading pid file, cluster is probably not running.'
437 'Problem reading pid file, cluster is probably not running.'
435 )
438 )
436 # Here I exit with a unusual exit status that other processes
439 # Here I exit with a unusual exit status that other processes
437 # can watch for to learn how I existed.
440 # can watch for to learn how I existed.
438 self.exit(ALREADY_STOPPED)
441 self.exit(ALREADY_STOPPED)
439 else:
442 else:
440 if os.name=='posix':
443 if os.name=='posix':
441 sig = config.Global.signal
444 sig = config.Global.signal
442 self.log.info(
445 self.log.info(
443 "Stopping cluster [pid=%r] with [signal=%r]" % (pid, sig)
446 "Stopping cluster [pid=%r] with [signal=%r]" % (pid, sig)
444 )
447 )
445 os.kill(pid, sig)
448 os.kill(pid, sig)
446 elif os.name=='nt':
449 elif os.name=='nt':
447 # As of right now, we don't support daemonize on Windows, so
450 # As of right now, we don't support daemonize on Windows, so
448 # stop will not do anything. Minimally, it should clean up the
451 # stop will not do anything. Minimally, it should clean up the
449 # old .pid files.
452 # old .pid files.
450 self.remove_pid_file()
453 self.remove_pid_file()
451
454
452 def launch_new_instance():
455 def launch_new_instance():
453 """Create and run the IPython cluster."""
456 """Create and run the IPython cluster."""
454 app = IPClusterApp()
457 app = IPClusterApp()
455 app.start()
458 app.start()
456
459
457
460
458 if __name__ == '__main__':
461 if __name__ == '__main__':
459 launch_new_instance()
462 launch_new_instance()
460
463
@@ -1,182 +1,185 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """
2 """
3 A module to change reload() so that it acts recursively.
3 A module to change reload() so that it acts recursively.
4 To enable it type:
4 To enable it type::
5 >>> import __builtin__, deepreload
6 >>> __builtin__.reload = deepreload.reload
7
5
8 You can then disable it with:
6 import __builtin__, deepreload
9 >>> __builtin__.reload = deepreload.original_reload
7 __builtin__.reload = deepreload.reload
8
9 You can then disable it with::
10
11 __builtin__.reload = deepreload.original_reload
10
12
11 Alternatively, you can add a dreload builtin alongside normal reload with:
13 Alternatively, you can add a dreload builtin alongside normal reload with::
12 >>> __builtin__.dreload = deepreload.reload
14
15 __builtin__.dreload = deepreload.reload
13
16
14 This code is almost entirely based on knee.py from the standard library.
17 This code is almost entirely based on knee.py from the standard library.
15 """
18 """
16
19
17 #*****************************************************************************
20 #*****************************************************************************
18 # Copyright (C) 2001 Nathaniel Gray <n8gray@caltech.edu>
21 # Copyright (C) 2001 Nathaniel Gray <n8gray@caltech.edu>
19 #
22 #
20 # Distributed under the terms of the BSD License. The full license is in
23 # Distributed under the terms of the BSD License. The full license is in
21 # the file COPYING, distributed as part of this software.
24 # the file COPYING, distributed as part of this software.
22 #*****************************************************************************
25 #*****************************************************************************
23
26
24 import __builtin__
27 import __builtin__
25 import imp
28 import imp
26 import sys
29 import sys
27
30
28 # Replacement for __import__()
31 # Replacement for __import__()
29 def deep_import_hook(name, globals=None, locals=None, fromlist=None, level=-1):
32 def deep_import_hook(name, globals=None, locals=None, fromlist=None, level=-1):
30 # For now level is ignored, it's just there to prevent crash
33 # For now level is ignored, it's just there to prevent crash
31 # with from __future__ import absolute_import
34 # with from __future__ import absolute_import
32 parent = determine_parent(globals)
35 parent = determine_parent(globals)
33 q, tail = find_head_package(parent, name)
36 q, tail = find_head_package(parent, name)
34 m = load_tail(q, tail)
37 m = load_tail(q, tail)
35 if not fromlist:
38 if not fromlist:
36 return q
39 return q
37 if hasattr(m, "__path__"):
40 if hasattr(m, "__path__"):
38 ensure_fromlist(m, fromlist)
41 ensure_fromlist(m, fromlist)
39 return m
42 return m
40
43
41 def determine_parent(globals):
44 def determine_parent(globals):
42 if not globals or not globals.has_key("__name__"):
45 if not globals or not globals.has_key("__name__"):
43 return None
46 return None
44 pname = globals['__name__']
47 pname = globals['__name__']
45 if globals.has_key("__path__"):
48 if globals.has_key("__path__"):
46 parent = sys.modules[pname]
49 parent = sys.modules[pname]
47 assert globals is parent.__dict__
50 assert globals is parent.__dict__
48 return parent
51 return parent
49 if '.' in pname:
52 if '.' in pname:
50 i = pname.rfind('.')
53 i = pname.rfind('.')
51 pname = pname[:i]
54 pname = pname[:i]
52 parent = sys.modules[pname]
55 parent = sys.modules[pname]
53 assert parent.__name__ == pname
56 assert parent.__name__ == pname
54 return parent
57 return parent
55 return None
58 return None
56
59
57 def find_head_package(parent, name):
60 def find_head_package(parent, name):
58 # Import the first
61 # Import the first
59 if '.' in name:
62 if '.' in name:
60 # 'some.nested.package' -> head = 'some', tail = 'nested.package'
63 # 'some.nested.package' -> head = 'some', tail = 'nested.package'
61 i = name.find('.')
64 i = name.find('.')
62 head = name[:i]
65 head = name[:i]
63 tail = name[i+1:]
66 tail = name[i+1:]
64 else:
67 else:
65 # 'packagename' -> head = 'packagename', tail = ''
68 # 'packagename' -> head = 'packagename', tail = ''
66 head = name
69 head = name
67 tail = ""
70 tail = ""
68 if parent:
71 if parent:
69 # If this is a subpackage then qname = parent's name + head
72 # If this is a subpackage then qname = parent's name + head
70 qname = "%s.%s" % (parent.__name__, head)
73 qname = "%s.%s" % (parent.__name__, head)
71 else:
74 else:
72 qname = head
75 qname = head
73 q = import_module(head, qname, parent)
76 q = import_module(head, qname, parent)
74 if q: return q, tail
77 if q: return q, tail
75 if parent:
78 if parent:
76 qname = head
79 qname = head
77 parent = None
80 parent = None
78 q = import_module(head, qname, parent)
81 q = import_module(head, qname, parent)
79 if q: return q, tail
82 if q: return q, tail
80 raise ImportError, "No module named " + qname
83 raise ImportError, "No module named " + qname
81
84
82 def load_tail(q, tail):
85 def load_tail(q, tail):
83 m = q
86 m = q
84 while tail:
87 while tail:
85 i = tail.find('.')
88 i = tail.find('.')
86 if i < 0: i = len(tail)
89 if i < 0: i = len(tail)
87 head, tail = tail[:i], tail[i+1:]
90 head, tail = tail[:i], tail[i+1:]
88
91
89 # fperez: fix dotted.name reloading failures by changing:
92 # fperez: fix dotted.name reloading failures by changing:
90 #mname = "%s.%s" % (m.__name__, head)
93 #mname = "%s.%s" % (m.__name__, head)
91 # to:
94 # to:
92 mname = m.__name__
95 mname = m.__name__
93 # This needs more testing!!! (I don't understand this module too well)
96 # This needs more testing!!! (I don't understand this module too well)
94
97
95 #print '** head,tail=|%s|->|%s|, mname=|%s|' % (head,tail,mname) # dbg
98 #print '** head,tail=|%s|->|%s|, mname=|%s|' % (head,tail,mname) # dbg
96 m = import_module(head, mname, m)
99 m = import_module(head, mname, m)
97 if not m:
100 if not m:
98 raise ImportError, "No module named " + mname
101 raise ImportError, "No module named " + mname
99 return m
102 return m
100
103
101 def ensure_fromlist(m, fromlist, recursive=0):
104 def ensure_fromlist(m, fromlist, recursive=0):
102 for sub in fromlist:
105 for sub in fromlist:
103 if sub == "*":
106 if sub == "*":
104 if not recursive:
107 if not recursive:
105 try:
108 try:
106 all = m.__all__
109 all = m.__all__
107 except AttributeError:
110 except AttributeError:
108 pass
111 pass
109 else:
112 else:
110 ensure_fromlist(m, all, 1)
113 ensure_fromlist(m, all, 1)
111 continue
114 continue
112 if sub != "*" and not hasattr(m, sub):
115 if sub != "*" and not hasattr(m, sub):
113 subname = "%s.%s" % (m.__name__, sub)
116 subname = "%s.%s" % (m.__name__, sub)
114 submod = import_module(sub, subname, m)
117 submod = import_module(sub, subname, m)
115 if not submod:
118 if not submod:
116 raise ImportError, "No module named " + subname
119 raise ImportError, "No module named " + subname
117
120
118 # Need to keep track of what we've already reloaded to prevent cyclic evil
121 # Need to keep track of what we've already reloaded to prevent cyclic evil
119 found_now = {}
122 found_now = {}
120
123
121 def import_module(partname, fqname, parent):
124 def import_module(partname, fqname, parent):
122 global found_now
125 global found_now
123 if found_now.has_key(fqname):
126 if found_now.has_key(fqname):
124 try:
127 try:
125 return sys.modules[fqname]
128 return sys.modules[fqname]
126 except KeyError:
129 except KeyError:
127 pass
130 pass
128
131
129 print 'Reloading', fqname #, sys.excepthook is sys.__excepthook__, \
132 print 'Reloading', fqname #, sys.excepthook is sys.__excepthook__, \
130 #sys.displayhook is sys.__displayhook__
133 #sys.displayhook is sys.__displayhook__
131
134
132 found_now[fqname] = 1
135 found_now[fqname] = 1
133 try:
136 try:
134 fp, pathname, stuff = imp.find_module(partname,
137 fp, pathname, stuff = imp.find_module(partname,
135 parent and parent.__path__)
138 parent and parent.__path__)
136 except ImportError:
139 except ImportError:
137 return None
140 return None
138
141
139 try:
142 try:
140 m = imp.load_module(fqname, fp, pathname, stuff)
143 m = imp.load_module(fqname, fp, pathname, stuff)
141 finally:
144 finally:
142 if fp: fp.close()
145 if fp: fp.close()
143
146
144 if parent:
147 if parent:
145 setattr(parent, partname, m)
148 setattr(parent, partname, m)
146
149
147 return m
150 return m
148
151
149 def deep_reload_hook(module):
152 def deep_reload_hook(module):
150 name = module.__name__
153 name = module.__name__
151 if '.' not in name:
154 if '.' not in name:
152 return import_module(name, name, None)
155 return import_module(name, name, None)
153 i = name.rfind('.')
156 i = name.rfind('.')
154 pname = name[:i]
157 pname = name[:i]
155 parent = sys.modules[pname]
158 parent = sys.modules[pname]
156 return import_module(name[i+1:], name, parent)
159 return import_module(name[i+1:], name, parent)
157
160
158 # Save the original hooks
161 # Save the original hooks
159 original_reload = __builtin__.reload
162 original_reload = __builtin__.reload
160
163
161 # Replacement for reload()
164 # Replacement for reload()
162 def reload(module, exclude=['sys', '__builtin__', '__main__']):
165 def reload(module, exclude=['sys', '__builtin__', '__main__']):
163 """Recursively reload all modules used in the given module. Optionally
166 """Recursively reload all modules used in the given module. Optionally
164 takes a list of modules to exclude from reloading. The default exclude
167 takes a list of modules to exclude from reloading. The default exclude
165 list contains sys, __main__, and __builtin__, to prevent, e.g., resetting
168 list contains sys, __main__, and __builtin__, to prevent, e.g., resetting
166 display, exception, and io hooks.
169 display, exception, and io hooks.
167 """
170 """
168 global found_now
171 global found_now
169 for i in exclude:
172 for i in exclude:
170 found_now[i] = 1
173 found_now[i] = 1
171 original_import = __builtin__.__import__
174 original_import = __builtin__.__import__
172 __builtin__.__import__ = deep_import_hook
175 __builtin__.__import__ = deep_import_hook
173 try:
176 try:
174 ret = deep_reload_hook(module)
177 ret = deep_reload_hook(module)
175 finally:
178 finally:
176 __builtin__.__import__ = original_import
179 __builtin__.__import__ = original_import
177 found_now = {}
180 found_now = {}
178 return ret
181 return ret
179
182
180 # Uncomment the following to automatically activate deep reloading whenever
183 # Uncomment the following to automatically activate deep reloading whenever
181 # this module is imported
184 # this module is imported
182 #__builtin__.reload = reload
185 #__builtin__.reload = reload
@@ -1,172 +1,174 b''
1 """Global IPython app to support test running.
1 """Global IPython app to support test running.
2
2
3 We must start our own ipython object and heavily muck with it so that all the
3 We must start our own ipython object and heavily muck with it so that all the
4 modifications IPython makes to system behavior don't send the doctest machinery
4 modifications IPython makes to system behavior don't send the doctest machinery
5 into a fit. This code should be considered a gross hack, but it gets the job
5 into a fit. This code should be considered a gross hack, but it gets the job
6 done.
6 done.
7 """
7 """
8
8
9 from __future__ import absolute_import
9 from __future__ import absolute_import
10
10
11 #-----------------------------------------------------------------------------
11 #-----------------------------------------------------------------------------
12 # Copyright (C) 2009 The IPython Development Team
12 # Copyright (C) 2009 The IPython Development Team
13 #
13 #
14 # Distributed under the terms of the BSD License. The full license is in
14 # Distributed under the terms of the BSD License. The full license is in
15 # the file COPYING, distributed as part of this software.
15 # the file COPYING, distributed as part of this software.
16 #-----------------------------------------------------------------------------
16 #-----------------------------------------------------------------------------
17
17
18 #-----------------------------------------------------------------------------
18 #-----------------------------------------------------------------------------
19 # Imports
19 # Imports
20 #-----------------------------------------------------------------------------
20 #-----------------------------------------------------------------------------
21
21
22 import __builtin__
22 import __builtin__
23 import commands
23 import commands
24 import os
24 import os
25 import sys
25 import sys
26
26
27 from . import tools
27 from . import tools
28
28
29 #-----------------------------------------------------------------------------
29 #-----------------------------------------------------------------------------
30 # Functions
30 # Functions
31 #-----------------------------------------------------------------------------
31 #-----------------------------------------------------------------------------
32
32
33 # Hack to modify the %run command so we can sync the user's namespace with the
33 # Hack to modify the %run command so we can sync the user's namespace with the
34 # test globals. Once we move over to a clean magic system, this will be done
34 # test globals. Once we move over to a clean magic system, this will be done
35 # with much less ugliness.
35 # with much less ugliness.
36
36
37 class py_file_finder(object):
37 class py_file_finder(object):
38 def __init__(self,test_filename):
38 def __init__(self,test_filename):
39 self.test_filename = test_filename
39 self.test_filename = test_filename
40
40
41 def __call__(self,name):
41 def __call__(self,name):
42 from IPython.utils.path import get_py_filename
42 from IPython.utils.path import get_py_filename
43 try:
43 try:
44 return get_py_filename(name)
44 return get_py_filename(name)
45 except IOError:
45 except IOError:
46 test_dir = os.path.dirname(self.test_filename)
46 test_dir = os.path.dirname(self.test_filename)
47 new_path = os.path.join(test_dir,name)
47 new_path = os.path.join(test_dir,name)
48 return get_py_filename(new_path)
48 return get_py_filename(new_path)
49
49
50
50
51 def _run_ns_sync(self,arg_s,runner=None):
51 def _run_ns_sync(self,arg_s,runner=None):
52 """Modified version of %run that syncs testing namespaces.
52 """Modified version of %run that syncs testing namespaces.
53
53
54 This is strictly needed for running doctests that call %run.
54 This is strictly needed for running doctests that call %run.
55 """
55 """
56 #print >> sys.stderr, 'in run_ns_sync', arg_s # dbg
56 #print >> sys.stderr, 'in run_ns_sync', arg_s # dbg
57
57
58 _ip = get_ipython()
58 _ip = get_ipython()
59 finder = py_file_finder(arg_s)
59 finder = py_file_finder(arg_s)
60 out = _ip.magic_run_ori(arg_s,runner,finder)
60 out = _ip.magic_run_ori(arg_s,runner,finder)
61 return out
61 return out
62
62
63
63
64 class ipnsdict(dict):
64 class ipnsdict(dict):
65 """A special subclass of dict for use as an IPython namespace in doctests.
65 """A special subclass of dict for use as an IPython namespace in doctests.
66
66
67 This subclass adds a simple checkpointing capability so that when testing
67 This subclass adds a simple checkpointing capability so that when testing
68 machinery clears it (we use it as the test execution context), it doesn't
68 machinery clears it (we use it as the test execution context), it doesn't
69 get completely destroyed.
69 get completely destroyed.
70 """
70 """
71
71
72 def __init__(self,*a):
72 def __init__(self,*a):
73 dict.__init__(self,*a)
73 dict.__init__(self,*a)
74 self._savedict = {}
74 self._savedict = {}
75
75
76 def clear(self):
76 def clear(self):
77 dict.clear(self)
77 dict.clear(self)
78 self.update(self._savedict)
78 self.update(self._savedict)
79
79
80 def _checkpoint(self):
80 def _checkpoint(self):
81 self._savedict.clear()
81 self._savedict.clear()
82 self._savedict.update(self)
82 self._savedict.update(self)
83
83
84 def update(self,other):
84 def update(self,other):
85 self._checkpoint()
85 self._checkpoint()
86 dict.update(self,other)
86 dict.update(self,other)
87
87
88 # If '_' is in the namespace, python won't set it when executing code,
88 # If '_' is in the namespace, python won't set it when executing code,
89 # and we have examples that test it. So we ensure that the namespace
89 # and we have examples that test it. So we ensure that the namespace
90 # is always 'clean' of it before it's used for test code execution.
90 # is always 'clean' of it before it's used for test code execution.
91 self.pop('_',None)
91 self.pop('_',None)
92
92
93 # The builtins namespace must *always* be the real __builtin__ module,
93 # The builtins namespace must *always* be the real __builtin__ module,
94 # else weird stuff happens. The main ipython code does have provisions
94 # else weird stuff happens. The main ipython code does have provisions
95 # to ensure this after %run, but since in this class we do some
95 # to ensure this after %run, but since in this class we do some
96 # aggressive low-level cleaning of the execution namespace, we need to
96 # aggressive low-level cleaning of the execution namespace, we need to
97 # correct for that ourselves, to ensure consitency with the 'real'
97 # correct for that ourselves, to ensure consitency with the 'real'
98 # ipython.
98 # ipython.
99 self['__builtins__'] = __builtin__
99 self['__builtins__'] = __builtin__
100
100
101
101
102 def get_ipython():
102 def get_ipython():
103 # This will get replaced by the real thing once we start IPython below
103 # This will get replaced by the real thing once we start IPython below
104 return start_ipython()
104 return start_ipython()
105
105
106
106 def start_ipython():
107 def start_ipython():
107 """Start a global IPython shell, which we need for IPython-specific syntax.
108 """Start a global IPython shell, which we need for IPython-specific syntax.
108 """
109 """
109 global get_ipython
110 global get_ipython
110
111
111 # This function should only ever run once!
112 # This function should only ever run once!
112 if hasattr(start_ipython,'already_called'):
113 if hasattr(start_ipython, 'already_called'):
113 return
114 return
114 start_ipython.already_called = True
115 start_ipython.already_called = True
115
116
116 # Ok, first time we're called, go ahead
117 # Ok, first time we're called, go ahead
117 from IPython.core import ipapp, iplib
118 from IPython.core import iplib
118
119
119 def xsys(cmd):
120 def xsys(cmd):
120 """Execute a command and print its output.
121 """Execute a command and print its output.
121
122
122 This is just a convenience function to replace the IPython system call
123 This is just a convenience function to replace the IPython system call
123 with one that is more doctest-friendly.
124 with one that is more doctest-friendly.
124 """
125 """
125 cmd = _ip.var_expand(cmd,depth=1)
126 cmd = _ip.var_expand(cmd,depth=1)
126 sys.stdout.write(commands.getoutput(cmd))
127 sys.stdout.write(commands.getoutput(cmd))
127 sys.stdout.flush()
128 sys.stdout.flush()
128
129
129 # Store certain global objects that IPython modifies
130 # Store certain global objects that IPython modifies
130 _displayhook = sys.displayhook
131 _displayhook = sys.displayhook
131 _excepthook = sys.excepthook
132 _excepthook = sys.excepthook
132 _main = sys.modules.get('__main__')
133 _main = sys.modules.get('__main__')
133
134
134 # Create custom argv and namespaces for our IPython to be test-friendly
135 # Create custom argv and namespaces for our IPython to be test-friendly
135 argv = tools.default_argv()
136 config = tools.default_config()
136 user_ns, global_ns = iplib.make_user_namespaces(ipnsdict(), {})
137
137
138 # Create and initialize our test-friendly IPython instance.
138 # Create and initialize our test-friendly IPython instance.
139 ip = ipapp.IPythonApp(argv, user_ns=user_ns, user_global_ns=global_ns)
139 shell = iplib.InteractiveShell(
140 ip.initialize()
140 parent=None, config=config,
141 user_ns=ipnsdict(), user_global_ns={}
142 )
141
143
142 # A few more tweaks needed for playing nicely with doctests...
144 # A few more tweaks needed for playing nicely with doctests...
143
145
144 # These traps are normally only active for interactive use, set them
146 # These traps are normally only active for interactive use, set them
145 # permanently since we'll be mocking interactive sessions.
147 # permanently since we'll be mocking interactive sessions.
146 ip.shell.builtin_trap.set()
148 shell.builtin_trap.set()
147
149
148 # Set error printing to stdout so nose can doctest exceptions
150 # Set error printing to stdout so nose can doctest exceptions
149 ip.shell.InteractiveTB.out_stream = 'stdout'
151 shell.InteractiveTB.out_stream = 'stdout'
150
152
151 # Modify the IPython system call with one that uses getoutput, so that we
153 # Modify the IPython system call with one that uses getoutput, so that we
152 # can capture subcommands and print them to Python's stdout, otherwise the
154 # can capture subcommands and print them to Python's stdout, otherwise the
153 # doctest machinery would miss them.
155 # doctest machinery would miss them.
154 ip.shell.system = xsys
156 shell.system = xsys
155
157
156 # IPython is ready, now clean up some global state...
158 # IPython is ready, now clean up some global state...
157
159
158 # Deactivate the various python system hooks added by ipython for
160 # Deactivate the various python system hooks added by ipython for
159 # interactive convenience so we don't confuse the doctest system
161 # interactive convenience so we don't confuse the doctest system
160 sys.modules['__main__'] = _main
162 sys.modules['__main__'] = _main
161 sys.displayhook = _displayhook
163 sys.displayhook = _displayhook
162 sys.excepthook = _excepthook
164 sys.excepthook = _excepthook
163
165
164 # So that ipython magics and aliases can be doctested (they work by making
166 # So that ipython magics and aliases can be doctested (they work by making
165 # a call into a global _ip object). Also make the top-level get_ipython
167 # a call into a global _ip object). Also make the top-level get_ipython
166 # now return this without recursively calling here again.
168 # now return this without recursively calling here again.
167 _ip = ip.shell
169 _ip = shell
168 get_ipython = _ip.get_ipython
170 get_ipython = _ip.get_ipython
169 __builtin__._ip = _ip
171 __builtin__._ip = _ip
170 __builtin__.get_ipython = get_ipython
172 __builtin__.get_ipython = get_ipython
171
173
172 return _ip
174 return _ip
@@ -1,488 +1,488 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """IPython Test Suite Runner.
2 """IPython Test Suite Runner.
3
3
4 This module provides a main entry point to a user script to test IPython
4 This module provides a main entry point to a user script to test IPython
5 itself from the command line. There are two ways of running this script:
5 itself from the command line. There are two ways of running this script:
6
6
7 1. With the syntax `iptest all`. This runs our entire test suite by
7 1. With the syntax `iptest all`. This runs our entire test suite by
8 calling this script (with different arguments) or trial recursively. This
8 calling this script (with different arguments) or trial recursively. This
9 causes modules and package to be tested in different processes, using nose
9 causes modules and package to be tested in different processes, using nose
10 or trial where appropriate.
10 or trial where appropriate.
11 2. With the regular nose syntax, like `iptest -vvs IPython`. In this form
11 2. With the regular nose syntax, like `iptest -vvs IPython`. In this form
12 the script simply calls nose, but with special command line flags and
12 the script simply calls nose, but with special command line flags and
13 plugins loaded.
13 plugins loaded.
14
14
15 For now, this script requires that both nose and twisted are installed. This
15 For now, this script requires that both nose and twisted are installed. This
16 will change in the future.
16 will change in the future.
17 """
17 """
18
18
19 #-----------------------------------------------------------------------------
19 #-----------------------------------------------------------------------------
20 # Copyright (C) 2009 The IPython Development Team
20 # Copyright (C) 2009 The IPython Development Team
21 #
21 #
22 # Distributed under the terms of the BSD License. The full license is in
22 # Distributed under the terms of the BSD License. The full license is in
23 # the file COPYING, distributed as part of this software.
23 # the file COPYING, distributed as part of this software.
24 #-----------------------------------------------------------------------------
24 #-----------------------------------------------------------------------------
25
25
26 #-----------------------------------------------------------------------------
26 #-----------------------------------------------------------------------------
27 # Imports
27 # Imports
28 #-----------------------------------------------------------------------------
28 #-----------------------------------------------------------------------------
29
29
30 # Stdlib
30 # Stdlib
31 import os
31 import os
32 import os.path as path
32 import os.path as path
33 import signal
33 import signal
34 import sys
34 import sys
35 import subprocess
35 import subprocess
36 import tempfile
36 import tempfile
37 import time
37 import time
38 import warnings
38 import warnings
39
39
40
40
41 # Ugly, but necessary hack to ensure the test suite finds our version of
41 # Ugly, but necessary hack to ensure the test suite finds our version of
42 # IPython and not a possibly different one that may exist system-wide.
42 # IPython and not a possibly different one that may exist system-wide.
43 # Note that this must be done here, so the imports that come next work
43 # Note that this must be done here, so the imports that come next work
44 # correctly even if IPython isn't installed yet.
44 # correctly even if IPython isn't installed yet.
45 p = os.path
45 p = os.path
46 ippath = p.abspath(p.join(p.dirname(__file__),'..','..'))
46 ippath = p.abspath(p.join(p.dirname(__file__),'..','..'))
47 sys.path.insert(0, ippath)
47 sys.path.insert(0, ippath)
48
48
49 # Note: monkeypatch!
49 # Note: monkeypatch!
50 # We need to monkeypatch a small problem in nose itself first, before importing
50 # We need to monkeypatch a small problem in nose itself first, before importing
51 # it for actual use. This should get into nose upstream, but its release cycle
51 # it for actual use. This should get into nose upstream, but its release cycle
52 # is slow and we need it for our parametric tests to work correctly.
52 # is slow and we need it for our parametric tests to work correctly.
53 from IPython.testing import nosepatch
53 from IPython.testing import nosepatch
54 # Now, proceed to import nose itself
54 # Now, proceed to import nose itself
55 import nose.plugins.builtin
55 import nose.plugins.builtin
56 from nose.core import TestProgram
56 from nose.core import TestProgram
57
57
58 # Our own imports
58 # Our own imports
59 from IPython.utils.path import get_ipython_module_path
59 from IPython.utils.path import get_ipython_module_path
60 from IPython.utils.process import find_cmd, pycmd2argv
60 from IPython.utils.process import find_cmd, pycmd2argv
61 from IPython.utils.sysinfo import sys_info
61 from IPython.utils.sysinfo import sys_info
62
62
63 from IPython.testing import globalipapp
63 from IPython.testing import globalipapp
64 from IPython.testing.plugin.ipdoctest import IPythonDoctest
64 from IPython.testing.plugin.ipdoctest import IPythonDoctest
65
65
66 pjoin = path.join
66 pjoin = path.join
67
67
68
68
69 #-----------------------------------------------------------------------------
69 #-----------------------------------------------------------------------------
70 # Globals
70 # Globals
71 #-----------------------------------------------------------------------------
71 #-----------------------------------------------------------------------------
72
72
73 # By default, we assume IPython has been installed. But if the test suite is
73 # By default, we assume IPython has been installed. But if the test suite is
74 # being run from a source tree that has NOT been installed yet, this flag can
74 # being run from a source tree that has NOT been installed yet, this flag can
75 # be set to False by the entry point scripts, to let us know that we must call
75 # be set to False by the entry point scripts, to let us know that we must call
76 # the source tree versions of the scripts which manipulate sys.path instead of
76 # the source tree versions of the scripts which manipulate sys.path instead of
77 # assuming that things exist system-wide.
77 # assuming that things exist system-wide.
78 INSTALLED = True
78 INSTALLED = True
79
79
80 #-----------------------------------------------------------------------------
80 #-----------------------------------------------------------------------------
81 # Warnings control
81 # Warnings control
82 #-----------------------------------------------------------------------------
82 #-----------------------------------------------------------------------------
83 # Twisted generates annoying warnings with Python 2.6, as will do other code
83 # Twisted generates annoying warnings with Python 2.6, as will do other code
84 # that imports 'sets' as of today
84 # that imports 'sets' as of today
85 warnings.filterwarnings('ignore', 'the sets module is deprecated',
85 warnings.filterwarnings('ignore', 'the sets module is deprecated',
86 DeprecationWarning )
86 DeprecationWarning )
87
87
88 # This one also comes from Twisted
88 # This one also comes from Twisted
89 warnings.filterwarnings('ignore', 'the sha module is deprecated',
89 warnings.filterwarnings('ignore', 'the sha module is deprecated',
90 DeprecationWarning)
90 DeprecationWarning)
91
91
92 # Wx on Fedora11 spits these out
92 # Wx on Fedora11 spits these out
93 warnings.filterwarnings('ignore', 'wxPython/wxWidgets release number mismatch',
93 warnings.filterwarnings('ignore', 'wxPython/wxWidgets release number mismatch',
94 UserWarning)
94 UserWarning)
95
95
96 #-----------------------------------------------------------------------------
96 #-----------------------------------------------------------------------------
97 # Logic for skipping doctests
97 # Logic for skipping doctests
98 #-----------------------------------------------------------------------------
98 #-----------------------------------------------------------------------------
99
99
100 def test_for(mod):
100 def test_for(mod):
101 """Test to see if mod is importable."""
101 """Test to see if mod is importable."""
102 try:
102 try:
103 __import__(mod)
103 __import__(mod)
104 except (ImportError, RuntimeError):
104 except (ImportError, RuntimeError):
105 # GTK reports Runtime error if it can't be initialized even if it's
105 # GTK reports Runtime error if it can't be initialized even if it's
106 # importable.
106 # importable.
107 return False
107 return False
108 else:
108 else:
109 return True
109 return True
110
110
111 # Global dict where we can store information on what we have and what we don't
111 # Global dict where we can store information on what we have and what we don't
112 # have available at test run time
112 # have available at test run time
113 have = {}
113 have = {}
114
114
115 have['curses'] = test_for('_curses')
115 have['curses'] = test_for('_curses')
116 have['wx'] = test_for('wx')
116 have['wx'] = test_for('wx')
117 have['wx.aui'] = test_for('wx.aui')
117 have['wx.aui'] = test_for('wx.aui')
118 have['zope.interface'] = test_for('zope.interface')
118 have['zope.interface'] = test_for('zope.interface')
119 have['twisted'] = test_for('twisted')
119 have['twisted'] = test_for('twisted')
120 have['foolscap'] = test_for('foolscap')
120 have['foolscap'] = test_for('foolscap')
121 have['objc'] = test_for('objc')
121 have['objc'] = test_for('objc')
122 have['pexpect'] = test_for('pexpect')
122 have['pexpect'] = test_for('pexpect')
123 have['gtk'] = test_for('gtk')
123 have['gtk'] = test_for('gtk')
124 have['gobject'] = test_for('gobject')
124 have['gobject'] = test_for('gobject')
125
125
126 #-----------------------------------------------------------------------------
126 #-----------------------------------------------------------------------------
127 # Functions and classes
127 # Functions and classes
128 #-----------------------------------------------------------------------------
128 #-----------------------------------------------------------------------------
129
129
130 def report():
130 def report():
131 """Return a string with a summary report of test-related variables."""
131 """Return a string with a summary report of test-related variables."""
132
132
133 out = [ sys_info() ]
133 out = [ sys_info() ]
134
134
135 out.append('\nRunning from an installed IPython: %s\n' % INSTALLED)
135 out.append('\nRunning from an installed IPython: %s\n' % INSTALLED)
136
136
137 avail = []
137 avail = []
138 not_avail = []
138 not_avail = []
139
139
140 for k, is_avail in have.items():
140 for k, is_avail in have.items():
141 if is_avail:
141 if is_avail:
142 avail.append(k)
142 avail.append(k)
143 else:
143 else:
144 not_avail.append(k)
144 not_avail.append(k)
145
145
146 if avail:
146 if avail:
147 out.append('\nTools and libraries available at test time:\n')
147 out.append('\nTools and libraries available at test time:\n')
148 avail.sort()
148 avail.sort()
149 out.append(' ' + ' '.join(avail)+'\n')
149 out.append(' ' + ' '.join(avail)+'\n')
150
150
151 if not_avail:
151 if not_avail:
152 out.append('\nTools and libraries NOT available at test time:\n')
152 out.append('\nTools and libraries NOT available at test time:\n')
153 not_avail.sort()
153 not_avail.sort()
154 out.append(' ' + ' '.join(not_avail)+'\n')
154 out.append(' ' + ' '.join(not_avail)+'\n')
155
155
156 return ''.join(out)
156 return ''.join(out)
157
157
158
158
159 def make_exclude():
159 def make_exclude():
160 """Make patterns of modules and packages to exclude from testing.
160 """Make patterns of modules and packages to exclude from testing.
161
161
162 For the IPythonDoctest plugin, we need to exclude certain patterns that
162 For the IPythonDoctest plugin, we need to exclude certain patterns that
163 cause testing problems. We should strive to minimize the number of
163 cause testing problems. We should strive to minimize the number of
164 skipped modules, since this means untested code. As the testing
164 skipped modules, since this means untested code. As the testing
165 machinery solidifies, this list should eventually become empty.
165 machinery solidifies, this list should eventually become empty.
166 These modules and packages will NOT get scanned by nose at all for tests.
166 These modules and packages will NOT get scanned by nose at all for tests.
167 """
167 """
168 # Simple utility to make IPython paths more readably, we need a lot of
168 # Simple utility to make IPython paths more readably, we need a lot of
169 # these below
169 # these below
170 ipjoin = lambda *paths: pjoin('IPython', *paths)
170 ipjoin = lambda *paths: pjoin('IPython', *paths)
171
171
172 exclusions = [ipjoin('external'),
172 exclusions = [ipjoin('external'),
173 ipjoin('frontend', 'process', 'winprocess.py'),
173 ipjoin('frontend', 'process', 'winprocess.py'),
174 # Deprecated old Shell and iplib modules, skip to avoid
174 # Deprecated old Shell and iplib modules, skip to avoid
175 # warnings
175 # warnings
176 ipjoin('Shell'),
176 ipjoin('Shell'),
177 ipjoin('iplib'),
177 ipjoin('iplib'),
178 pjoin('IPython_doctest_plugin'),
178 pjoin('IPython_doctest_plugin'),
179 ipjoin('quarantine'),
179 ipjoin('quarantine'),
180 ipjoin('deathrow'),
180 ipjoin('deathrow'),
181 ipjoin('testing', 'attic'),
181 ipjoin('testing', 'attic'),
182 # This guy is probably attic material
182 # This guy is probably attic material
183 ipjoin('testing', 'mkdoctests'),
183 ipjoin('testing', 'mkdoctests'),
184 # Testing inputhook will need a lot of thought, to figure out
184 # Testing inputhook will need a lot of thought, to figure out
185 # how to have tests that don't lock up with the gui event
185 # how to have tests that don't lock up with the gui event
186 # loops in the picture
186 # loops in the picture
187 ipjoin('lib', 'inputhook'),
187 ipjoin('lib', 'inputhook'),
188 # Config files aren't really importable stand-alone
188 # Config files aren't really importable stand-alone
189 ipjoin('config', 'default'),
189 ipjoin('config', 'default'),
190 ipjoin('config', 'profile'),
190 ipjoin('config', 'profile'),
191 ]
191 ]
192
192
193 if not have['wx']:
193 if not have['wx']:
194 exclusions.append(ipjoin('gui'))
194 exclusions.append(ipjoin('gui'))
195 exclusions.append(ipjoin('frontend', 'wx'))
195 exclusions.append(ipjoin('frontend', 'wx'))
196 exclusions.append(ipjoin('lib', 'inputhookwx'))
196 exclusions.append(ipjoin('lib', 'inputhookwx'))
197
197
198 if not have['gtk'] or not have['gobject']:
198 if not have['gtk'] or not have['gobject']:
199 exclusions.append(ipjoin('lib', 'inputhookgtk'))
199 exclusions.append(ipjoin('lib', 'inputhookgtk'))
200
200
201 if not have['wx.aui']:
201 if not have['wx.aui']:
202 exclusions.append(ipjoin('gui', 'wx', 'wxIPython'))
202 exclusions.append(ipjoin('gui', 'wx', 'wxIPython'))
203
203
204 if not have['objc']:
204 if not have['objc']:
205 exclusions.append(ipjoin('frontend', 'cocoa'))
205 exclusions.append(ipjoin('frontend', 'cocoa'))
206
206
207 # These have to be skipped on win32 because the use echo, rm, cd, etc.
207 # These have to be skipped on win32 because the use echo, rm, cd, etc.
208 # See ticket https://bugs.launchpad.net/bugs/366982
208 # See ticket https://bugs.launchpad.net/bugs/366982
209 if sys.platform == 'win32':
209 if sys.platform == 'win32':
210 exclusions.append(ipjoin('testing', 'plugin', 'test_exampleip'))
210 exclusions.append(ipjoin('testing', 'plugin', 'test_exampleip'))
211 exclusions.append(ipjoin('testing', 'plugin', 'dtexample'))
211 exclusions.append(ipjoin('testing', 'plugin', 'dtexample'))
212
212
213 if not have['pexpect']:
213 if not have['pexpect']:
214 exclusions.extend([ipjoin('scripts', 'irunner'),
214 exclusions.extend([ipjoin('scripts', 'irunner'),
215 ipjoin('lib', 'irunner')])
215 ipjoin('lib', 'irunner')])
216
216
217 # This is scary. We still have things in frontend and testing that
217 # This is scary. We still have things in frontend and testing that
218 # are being tested by nose that use twisted. We need to rethink
218 # are being tested by nose that use twisted. We need to rethink
219 # how we are isolating dependencies in testing.
219 # how we are isolating dependencies in testing.
220 if not (have['twisted'] and have['zope.interface'] and have['foolscap']):
220 if not (have['twisted'] and have['zope.interface'] and have['foolscap']):
221 exclusions.extend(
221 exclusions.extend(
222 [ipjoin('frontend', 'asyncfrontendbase'),
222 [ipjoin('frontend', 'asyncfrontendbase'),
223 ipjoin('frontend', 'prefilterfrontend'),
223 ipjoin('frontend', 'prefilterfrontend'),
224 ipjoin('frontend', 'frontendbase'),
224 ipjoin('frontend', 'frontendbase'),
225 ipjoin('frontend', 'linefrontendbase'),
225 ipjoin('frontend', 'linefrontendbase'),
226 ipjoin('frontend', 'tests', 'test_linefrontend'),
226 ipjoin('frontend', 'tests', 'test_linefrontend'),
227 ipjoin('frontend', 'tests', 'test_frontendbase'),
227 ipjoin('frontend', 'tests', 'test_frontendbase'),
228 ipjoin('frontend', 'tests', 'test_prefilterfrontend'),
228 ipjoin('frontend', 'tests', 'test_prefilterfrontend'),
229 ipjoin('frontend', 'tests', 'test_asyncfrontendbase'),
229 ipjoin('frontend', 'tests', 'test_asyncfrontendbase'),
230 ipjoin('testing', 'parametric'),
230 ipjoin('testing', 'parametric'),
231 ipjoin('testing', 'util'),
231 ipjoin('testing', 'util'),
232 ipjoin('testing', 'tests', 'test_decorators_trial'),
232 ipjoin('testing', 'tests', 'test_decorators_trial'),
233 ] )
233 ] )
234
234
235 # This is needed for the reg-exp to match on win32 in the ipdoctest plugin.
235 # This is needed for the reg-exp to match on win32 in the ipdoctest plugin.
236 if sys.platform == 'win32':
236 if sys.platform == 'win32':
237 exclusions = [s.replace('\\','\\\\') for s in exclusions]
237 exclusions = [s.replace('\\','\\\\') for s in exclusions]
238
238
239 return exclusions
239 return exclusions
240
240
241
241
242 class IPTester(object):
242 class IPTester(object):
243 """Call that calls iptest or trial in a subprocess.
243 """Call that calls iptest or trial in a subprocess.
244 """
244 """
245 #: string, name of test runner that will be called
245 #: string, name of test runner that will be called
246 runner = None
246 runner = None
247 #: list, parameters for test runner
247 #: list, parameters for test runner
248 params = None
248 params = None
249 #: list, arguments of system call to be made to call test runner
249 #: list, arguments of system call to be made to call test runner
250 call_args = None
250 call_args = None
251 #: list, process ids of subprocesses we start (for cleanup)
251 #: list, process ids of subprocesses we start (for cleanup)
252 pids = None
252 pids = None
253
253
254 def __init__(self, runner='iptest', params=None):
254 def __init__(self, runner='iptest', params=None):
255 """Create new test runner."""
255 """Create new test runner."""
256 p = os.path
256 p = os.path
257 if runner == 'iptest':
257 if runner == 'iptest':
258 if INSTALLED:
258 if INSTALLED:
259 iptest_app = get_ipython_module_path('IPython.testing.iptest')
259 iptest_app = get_ipython_module_path('IPython.testing.iptest')
260 self.runner = pycmd2argv(iptest_app) + sys.argv[1:]
260 self.runner = pycmd2argv(iptest_app) + sys.argv[1:]
261 else:
261 else:
262 # Find our own 'iptest' script OS-level entry point. Don't
262 # Find our own 'iptest' script OS-level entry point. Don't
263 # look system-wide, so we are sure we pick up *this one*. And
263 # look system-wide, so we are sure we pick up *this one*. And
264 # pass through to subprocess call our own sys.argv
264 # pass through to subprocess call our own sys.argv
265 ippath = p.abspath(p.join(p.dirname(__file__),'..','..'))
265 ippath = p.abspath(p.join(p.dirname(__file__),'..','..'))
266 script = p.join(ippath, 'iptest.py')
266 script = p.join(ippath, 'iptest.py')
267 self.runner = pycmd2argv(script) + sys.argv[1:]
267 self.runner = pycmd2argv(script) + sys.argv[1:]
268
268
269 else:
269 else:
270 # For trial, it needs to be installed system-wide
270 # For trial, it needs to be installed system-wide
271 self.runner = pycmd2argv(p.abspath(find_cmd('trial')))
271 self.runner = pycmd2argv(p.abspath(find_cmd('trial')))
272 if params is None:
272 if params is None:
273 params = []
273 params = []
274 if isinstance(params, str):
274 if isinstance(params, str):
275 params = [params]
275 params = [params]
276 self.params = params
276 self.params = params
277
277
278 # Assemble call
278 # Assemble call
279 self.call_args = self.runner+self.params
279 self.call_args = self.runner+self.params
280
280
281 # Store pids of anything we start to clean up on deletion, if possible
281 # Store pids of anything we start to clean up on deletion, if possible
282 # (on posix only, since win32 has no os.kill)
282 # (on posix only, since win32 has no os.kill)
283 self.pids = []
283 self.pids = []
284
284
285 if sys.platform == 'win32':
285 if sys.platform == 'win32':
286 def _run_cmd(self):
286 def _run_cmd(self):
287 # On Windows, use os.system instead of subprocess.call, because I
287 # On Windows, use os.system instead of subprocess.call, because I
288 # was having problems with subprocess and I just don't know enough
288 # was having problems with subprocess and I just don't know enough
289 # about win32 to debug this reliably. Os.system may be the 'old
289 # about win32 to debug this reliably. Os.system may be the 'old
290 # fashioned' way to do it, but it works just fine. If someone
290 # fashioned' way to do it, but it works just fine. If someone
291 # later can clean this up that's fine, as long as the tests run
291 # later can clean this up that's fine, as long as the tests run
292 # reliably in win32.
292 # reliably in win32.
293 return os.system(' '.join(self.call_args))
293 return os.system(' '.join(self.call_args))
294 else:
294 else:
295 def _run_cmd(self):
295 def _run_cmd(self):
296 #print >> sys.stderr, '*** CMD:', ' '.join(self.call_args) # dbg
296 #print >> sys.stderr, '*** CMD:', ' '.join(self.call_args) # dbg
297 subp = subprocess.Popen(self.call_args)
297 subp = subprocess.Popen(self.call_args)
298 self.pids.append(subp.pid)
298 self.pids.append(subp.pid)
299 # If this fails, the pid will be left in self.pids and cleaned up
299 # If this fails, the pid will be left in self.pids and cleaned up
300 # later, but if the wait call succeeds, then we can clear the
300 # later, but if the wait call succeeds, then we can clear the
301 # stored pid.
301 # stored pid.
302 retcode = subp.wait()
302 retcode = subp.wait()
303 self.pids.pop()
303 self.pids.pop()
304 return retcode
304 return retcode
305
305
306 def run(self):
306 def run(self):
307 """Run the stored commands"""
307 """Run the stored commands"""
308 try:
308 try:
309 return self._run_cmd()
309 return self._run_cmd()
310 except:
310 except:
311 import traceback
311 import traceback
312 traceback.print_exc()
312 traceback.print_exc()
313 return 1 # signal failure
313 return 1 # signal failure
314
314
315 def __del__(self):
315 def __del__(self):
316 """Cleanup on exit by killing any leftover processes."""
316 """Cleanup on exit by killing any leftover processes."""
317
317
318 if not hasattr(os, 'kill'):
318 if not hasattr(os, 'kill'):
319 return
319 return
320
320
321 for pid in self.pids:
321 for pid in self.pids:
322 try:
322 try:
323 print 'Cleaning stale PID:', pid
323 print 'Cleaning stale PID:', pid
324 os.kill(pid, signal.SIGKILL)
324 os.kill(pid, signal.SIGKILL)
325 except OSError:
325 except OSError:
326 # This is just a best effort, if we fail or the process was
326 # This is just a best effort, if we fail or the process was
327 # really gone, ignore it.
327 # really gone, ignore it.
328 pass
328 pass
329
329
330
330
331 def make_runners():
331 def make_runners():
332 """Define the top-level packages that need to be tested.
332 """Define the top-level packages that need to be tested.
333 """
333 """
334
334
335 # Packages to be tested via nose, that only depend on the stdlib
335 # Packages to be tested via nose, that only depend on the stdlib
336 nose_pkg_names = ['config', 'core', 'extensions', 'frontend', 'lib',
336 nose_pkg_names = ['config', 'core', 'extensions', 'frontend', 'lib',
337 'scripts', 'testing', 'utils' ]
337 'scripts', 'testing', 'utils' ]
338 # The machinery in kernel needs twisted for real testing
338 # The machinery in kernel needs twisted for real testing
339 trial_pkg_names = []
339 trial_pkg_names = []
340
340
341 if have['wx']:
341 if have['wx']:
342 nose_pkg_names.append('gui')
342 nose_pkg_names.append('gui')
343
343
344 # And add twisted ones if conditions are met
344 # And add twisted ones if conditions are met
345 if have['zope.interface'] and have['twisted'] and have['foolscap']:
345 if have['zope.interface'] and have['twisted'] and have['foolscap']:
346 # Note that we list the kernel here, though the bulk of it is
346 # We only list IPython.kernel for testing using twisted.trial as
347 # twisted-based, because nose picks up doctests that twisted doesn't.
347 # nose and twisted.trial have conflicts that make the testing system
348 nose_pkg_names.append('kernel')
348 # unstable.
349 trial_pkg_names.append('kernel')
349 trial_pkg_names.append('kernel')
350
350
351 # For debugging this code, only load quick stuff
351 # For debugging this code, only load quick stuff
352 #nose_pkg_names = ['core', 'extensions'] # dbg
352 #nose_pkg_names = ['core', 'extensions'] # dbg
353 #trial_pkg_names = [] # dbg
353 #trial_pkg_names = [] # dbg
354
354
355 # Make fully qualified package names prepending 'IPython.' to our name lists
355 # Make fully qualified package names prepending 'IPython.' to our name lists
356 nose_packages = ['IPython.%s' % m for m in nose_pkg_names ]
356 nose_packages = ['IPython.%s' % m for m in nose_pkg_names ]
357 trial_packages = ['IPython.%s' % m for m in trial_pkg_names ]
357 trial_packages = ['IPython.%s' % m for m in trial_pkg_names ]
358
358
359 # Make runners
359 # Make runners
360 runners = [ (v, IPTester('iptest', params=v)) for v in nose_packages ]
360 runners = [ (v, IPTester('iptest', params=v)) for v in nose_packages ]
361 runners.extend([ (v, IPTester('trial', params=v)) for v in trial_packages ])
361 runners.extend([ (v, IPTester('trial', params=v)) for v in trial_packages ])
362
362
363 return runners
363 return runners
364
364
365
365
366 def run_iptest():
366 def run_iptest():
367 """Run the IPython test suite using nose.
367 """Run the IPython test suite using nose.
368
368
369 This function is called when this script is **not** called with the form
369 This function is called when this script is **not** called with the form
370 `iptest all`. It simply calls nose with appropriate command line flags
370 `iptest all`. It simply calls nose with appropriate command line flags
371 and accepts all of the standard nose arguments.
371 and accepts all of the standard nose arguments.
372 """
372 """
373
373
374 warnings.filterwarnings('ignore',
374 warnings.filterwarnings('ignore',
375 'This will be removed soon. Use IPython.testing.util instead')
375 'This will be removed soon. Use IPython.testing.util instead')
376
376
377 argv = sys.argv + [ '--detailed-errors', # extra info in tracebacks
377 argv = sys.argv + [ '--detailed-errors', # extra info in tracebacks
378
378
379 # Loading ipdoctest causes problems with Twisted, but
379 # Loading ipdoctest causes problems with Twisted, but
380 # our test suite runner now separates things and runs
380 # our test suite runner now separates things and runs
381 # all Twisted tests with trial.
381 # all Twisted tests with trial.
382 '--with-ipdoctest',
382 '--with-ipdoctest',
383 '--ipdoctest-tests','--ipdoctest-extension=txt',
383 '--ipdoctest-tests','--ipdoctest-extension=txt',
384
384
385 # We add --exe because of setuptools' imbecility (it
385 # We add --exe because of setuptools' imbecility (it
386 # blindly does chmod +x on ALL files). Nose does the
386 # blindly does chmod +x on ALL files). Nose does the
387 # right thing and it tries to avoid executables,
387 # right thing and it tries to avoid executables,
388 # setuptools unfortunately forces our hand here. This
388 # setuptools unfortunately forces our hand here. This
389 # has been discussed on the distutils list and the
389 # has been discussed on the distutils list and the
390 # setuptools devs refuse to fix this problem!
390 # setuptools devs refuse to fix this problem!
391 '--exe',
391 '--exe',
392 ]
392 ]
393
393
394 if nose.__version__ >= '0.11':
394 if nose.__version__ >= '0.11':
395 # I don't fully understand why we need this one, but depending on what
395 # I don't fully understand why we need this one, but depending on what
396 # directory the test suite is run from, if we don't give it, 0 tests
396 # directory the test suite is run from, if we don't give it, 0 tests
397 # get run. Specifically, if the test suite is run from the source dir
397 # get run. Specifically, if the test suite is run from the source dir
398 # with an argument (like 'iptest.py IPython.core', 0 tests are run,
398 # with an argument (like 'iptest.py IPython.core', 0 tests are run,
399 # even if the same call done in this directory works fine). It appears
399 # even if the same call done in this directory works fine). It appears
400 # that if the requested package is in the current dir, nose bails early
400 # that if the requested package is in the current dir, nose bails early
401 # by default. Since it's otherwise harmless, leave it in by default
401 # by default. Since it's otherwise harmless, leave it in by default
402 # for nose >= 0.11, though unfortunately nose 0.10 doesn't support it.
402 # for nose >= 0.11, though unfortunately nose 0.10 doesn't support it.
403 argv.append('--traverse-namespace')
403 argv.append('--traverse-namespace')
404
404
405 # Construct list of plugins, omitting the existing doctest plugin, which
405 # Construct list of plugins, omitting the existing doctest plugin, which
406 # ours replaces (and extends).
406 # ours replaces (and extends).
407 plugins = [IPythonDoctest(make_exclude())]
407 plugins = [IPythonDoctest(make_exclude())]
408 for p in nose.plugins.builtin.plugins:
408 for p in nose.plugins.builtin.plugins:
409 plug = p()
409 plug = p()
410 if plug.name == 'doctest':
410 if plug.name == 'doctest':
411 continue
411 continue
412 plugins.append(plug)
412 plugins.append(plug)
413
413
414 # We need a global ipython running in this process
414 # We need a global ipython running in this process
415 globalipapp.start_ipython()
415 globalipapp.start_ipython()
416 # Now nose can run
416 # Now nose can run
417 TestProgram(argv=argv, plugins=plugins)
417 TestProgram(argv=argv, plugins=plugins)
418
418
419
419
420 def run_iptestall():
420 def run_iptestall():
421 """Run the entire IPython test suite by calling nose and trial.
421 """Run the entire IPython test suite by calling nose and trial.
422
422
423 This function constructs :class:`IPTester` instances for all IPython
423 This function constructs :class:`IPTester` instances for all IPython
424 modules and package and then runs each of them. This causes the modules
424 modules and package and then runs each of them. This causes the modules
425 and packages of IPython to be tested each in their own subprocess using
425 and packages of IPython to be tested each in their own subprocess using
426 nose or twisted.trial appropriately.
426 nose or twisted.trial appropriately.
427 """
427 """
428
428
429 runners = make_runners()
429 runners = make_runners()
430
430
431 # Run the test runners in a temporary dir so we can nuke it when finished
431 # Run the test runners in a temporary dir so we can nuke it when finished
432 # to clean up any junk files left over by accident. This also makes it
432 # to clean up any junk files left over by accident. This also makes it
433 # robust against being run in non-writeable directories by mistake, as the
433 # robust against being run in non-writeable directories by mistake, as the
434 # temp dir will always be user-writeable.
434 # temp dir will always be user-writeable.
435 curdir = os.getcwd()
435 curdir = os.getcwd()
436 testdir = tempfile.gettempdir()
436 testdir = tempfile.gettempdir()
437 os.chdir(testdir)
437 os.chdir(testdir)
438
438
439 # Run all test runners, tracking execution time
439 # Run all test runners, tracking execution time
440 failed = []
440 failed = []
441 t_start = time.time()
441 t_start = time.time()
442 try:
442 try:
443 for (name, runner) in runners:
443 for (name, runner) in runners:
444 print '*'*70
444 print '*'*70
445 print 'IPython test group:',name
445 print 'IPython test group:',name
446 res = runner.run()
446 res = runner.run()
447 if res:
447 if res:
448 failed.append( (name, runner) )
448 failed.append( (name, runner) )
449 finally:
449 finally:
450 os.chdir(curdir)
450 os.chdir(curdir)
451 t_end = time.time()
451 t_end = time.time()
452 t_tests = t_end - t_start
452 t_tests = t_end - t_start
453 nrunners = len(runners)
453 nrunners = len(runners)
454 nfail = len(failed)
454 nfail = len(failed)
455 # summarize results
455 # summarize results
456 print
456 print
457 print '*'*70
457 print '*'*70
458 print 'Test suite completed for system with the following information:'
458 print 'Test suite completed for system with the following information:'
459 print report()
459 print report()
460 print 'Ran %s test groups in %.3fs' % (nrunners, t_tests)
460 print 'Ran %s test groups in %.3fs' % (nrunners, t_tests)
461 print
461 print
462 print 'Status:'
462 print 'Status:'
463 if not failed:
463 if not failed:
464 print 'OK'
464 print 'OK'
465 else:
465 else:
466 # If anything went wrong, point out what command to rerun manually to
466 # If anything went wrong, point out what command to rerun manually to
467 # see the actual errors and individual summary
467 # see the actual errors and individual summary
468 print 'ERROR - %s out of %s test groups failed.' % (nfail, nrunners)
468 print 'ERROR - %s out of %s test groups failed.' % (nfail, nrunners)
469 for name, failed_runner in failed:
469 for name, failed_runner in failed:
470 print '-'*40
470 print '-'*40
471 print 'Runner failed:',name
471 print 'Runner failed:',name
472 print 'You may wish to rerun this one individually, with:'
472 print 'You may wish to rerun this one individually, with:'
473 print ' '.join(failed_runner.call_args)
473 print ' '.join(failed_runner.call_args)
474 print
474 print
475
475
476
476
477 def main():
477 def main():
478 for arg in sys.argv[1:]:
478 for arg in sys.argv[1:]:
479 if arg.startswith('IPython'):
479 if arg.startswith('IPython'):
480 # This is in-process
480 # This is in-process
481 run_iptest()
481 run_iptest()
482 else:
482 else:
483 # This starts subprocesses
483 # This starts subprocesses
484 run_iptestall()
484 run_iptestall()
485
485
486
486
487 if __name__ == '__main__':
487 if __name__ == '__main__':
488 main()
488 main()
@@ -1,282 +1,292 b''
1 """Generic testing tools that do NOT depend on Twisted.
1 """Generic testing tools that do NOT depend on Twisted.
2
2
3 In particular, this module exposes a set of top-level assert* functions that
3 In particular, this module exposes a set of top-level assert* functions that
4 can be used in place of nose.tools.assert* in method generators (the ones in
4 can be used in place of nose.tools.assert* in method generators (the ones in
5 nose can not, at least as of nose 0.10.4).
5 nose can not, at least as of nose 0.10.4).
6
6
7 Note: our testing package contains testing.util, which does depend on Twisted
7 Note: our testing package contains testing.util, which does depend on Twisted
8 and provides utilities for tests that manage Deferreds. All testing support
8 and provides utilities for tests that manage Deferreds. All testing support
9 tools that only depend on nose, IPython or the standard library should go here
9 tools that only depend on nose, IPython or the standard library should go here
10 instead.
10 instead.
11
11
12
12
13 Authors
13 Authors
14 -------
14 -------
15 - Fernando Perez <Fernando.Perez@berkeley.edu>
15 - Fernando Perez <Fernando.Perez@berkeley.edu>
16 """
16 """
17
17
18 from __future__ import absolute_import
18 from __future__ import absolute_import
19
19
20 #-----------------------------------------------------------------------------
20 #-----------------------------------------------------------------------------
21 # Copyright (C) 2009 The IPython Development Team
21 # Copyright (C) 2009 The IPython Development Team
22 #
22 #
23 # Distributed under the terms of the BSD License. The full license is in
23 # Distributed under the terms of the BSD License. The full license is in
24 # the file COPYING, distributed as part of this software.
24 # the file COPYING, distributed as part of this software.
25 #-----------------------------------------------------------------------------
25 #-----------------------------------------------------------------------------
26
26
27 #-----------------------------------------------------------------------------
27 #-----------------------------------------------------------------------------
28 # Imports
28 # Imports
29 #-----------------------------------------------------------------------------
29 #-----------------------------------------------------------------------------
30
30
31 import os
31 import os
32 import re
32 import re
33 import sys
33 import sys
34
34
35 try:
35 try:
36 # These tools are used by parts of the runtime, so we make the nose
36 # These tools are used by parts of the runtime, so we make the nose
37 # dependency optional at this point. Nose is a hard dependency to run the
37 # dependency optional at this point. Nose is a hard dependency to run the
38 # test suite, but NOT to use ipython itself.
38 # test suite, but NOT to use ipython itself.
39 import nose.tools as nt
39 import nose.tools as nt
40 has_nose = True
40 has_nose = True
41 except ImportError:
41 except ImportError:
42 has_nose = False
42 has_nose = False
43
43
44 from IPython.config.loader import Config
44 from IPython.utils.process import find_cmd, getoutputerror
45 from IPython.utils.process import find_cmd, getoutputerror
45 from IPython.utils.text import list_strings
46 from IPython.utils.text import list_strings
46 from IPython.utils.io import temp_pyfile
47 from IPython.utils.io import temp_pyfile
47
48
48 from . import decorators as dec
49 from . import decorators as dec
49
50
50 #-----------------------------------------------------------------------------
51 #-----------------------------------------------------------------------------
51 # Globals
52 # Globals
52 #-----------------------------------------------------------------------------
53 #-----------------------------------------------------------------------------
53
54
54 # By default, we assume IPython has been installed. But if the test suite is
55 # By default, we assume IPython has been installed. But if the test suite is
55 # being run from a source tree that has NOT been installed yet, this flag can
56 # being run from a source tree that has NOT been installed yet, this flag can
56 # be set to False by the entry point scripts, to let us know that we must call
57 # be set to False by the entry point scripts, to let us know that we must call
57 # the source tree versions of the scripts which manipulate sys.path instead of
58 # the source tree versions of the scripts which manipulate sys.path instead of
58 # assuming that things exist system-wide.
59 # assuming that things exist system-wide.
59 INSTALLED = True
60 INSTALLED = True
60
61
61 # Make a bunch of nose.tools assert wrappers that can be used in test
62 # Make a bunch of nose.tools assert wrappers that can be used in test
62 # generators. This will expose an assert* function for each one in nose.tools.
63 # generators. This will expose an assert* function for each one in nose.tools.
63
64
64 _tpl = """
65 _tpl = """
65 def %(name)s(*a,**kw):
66 def %(name)s(*a,**kw):
66 return nt.%(name)s(*a,**kw)
67 return nt.%(name)s(*a,**kw)
67 """
68 """
68
69
69 if has_nose:
70 if has_nose:
70 for _x in [a for a in dir(nt) if a.startswith('assert')]:
71 for _x in [a for a in dir(nt) if a.startswith('assert')]:
71 exec _tpl % dict(name=_x)
72 exec _tpl % dict(name=_x)
72
73
73 #-----------------------------------------------------------------------------
74 #-----------------------------------------------------------------------------
74 # Functions and classes
75 # Functions and classes
75 #-----------------------------------------------------------------------------
76 #-----------------------------------------------------------------------------
76
77
77 # The docstring for full_path doctests differently on win32 (different path
78 # The docstring for full_path doctests differently on win32 (different path
78 # separator) so just skip the doctest there. The example remains informative.
79 # separator) so just skip the doctest there. The example remains informative.
79 doctest_deco = dec.skip_doctest if sys.platform == 'win32' else dec.null_deco
80 doctest_deco = dec.skip_doctest if sys.platform == 'win32' else dec.null_deco
80
81
81 @doctest_deco
82 @doctest_deco
82 def full_path(startPath,files):
83 def full_path(startPath,files):
83 """Make full paths for all the listed files, based on startPath.
84 """Make full paths for all the listed files, based on startPath.
84
85
85 Only the base part of startPath is kept, since this routine is typically
86 Only the base part of startPath is kept, since this routine is typically
86 used with a script's __file__ variable as startPath. The base of startPath
87 used with a script's __file__ variable as startPath. The base of startPath
87 is then prepended to all the listed files, forming the output list.
88 is then prepended to all the listed files, forming the output list.
88
89
89 Parameters
90 Parameters
90 ----------
91 ----------
91 startPath : string
92 startPath : string
92 Initial path to use as the base for the results. This path is split
93 Initial path to use as the base for the results. This path is split
93 using os.path.split() and only its first component is kept.
94 using os.path.split() and only its first component is kept.
94
95
95 files : string or list
96 files : string or list
96 One or more files.
97 One or more files.
97
98
98 Examples
99 Examples
99 --------
100 --------
100
101
101 >>> full_path('/foo/bar.py',['a.txt','b.txt'])
102 >>> full_path('/foo/bar.py',['a.txt','b.txt'])
102 ['/foo/a.txt', '/foo/b.txt']
103 ['/foo/a.txt', '/foo/b.txt']
103
104
104 >>> full_path('/foo',['a.txt','b.txt'])
105 >>> full_path('/foo',['a.txt','b.txt'])
105 ['/a.txt', '/b.txt']
106 ['/a.txt', '/b.txt']
106
107
107 If a single file is given, the output is still a list:
108 If a single file is given, the output is still a list:
108 >>> full_path('/foo','a.txt')
109 >>> full_path('/foo','a.txt')
109 ['/a.txt']
110 ['/a.txt']
110 """
111 """
111
112
112 files = list_strings(files)
113 files = list_strings(files)
113 base = os.path.split(startPath)[0]
114 base = os.path.split(startPath)[0]
114 return [ os.path.join(base,f) for f in files ]
115 return [ os.path.join(base,f) for f in files ]
115
116
116
117
117 def parse_test_output(txt):
118 def parse_test_output(txt):
118 """Parse the output of a test run and return errors, failures.
119 """Parse the output of a test run and return errors, failures.
119
120
120 Parameters
121 Parameters
121 ----------
122 ----------
122 txt : str
123 txt : str
123 Text output of a test run, assumed to contain a line of one of the
124 Text output of a test run, assumed to contain a line of one of the
124 following forms::
125 following forms::
125 'FAILED (errors=1)'
126 'FAILED (errors=1)'
126 'FAILED (failures=1)'
127 'FAILED (failures=1)'
127 'FAILED (errors=1, failures=1)'
128 'FAILED (errors=1, failures=1)'
128
129
129 Returns
130 Returns
130 -------
131 -------
131 nerr, nfail: number of errors and failures.
132 nerr, nfail: number of errors and failures.
132 """
133 """
133
134
134 err_m = re.search(r'^FAILED \(errors=(\d+)\)', txt, re.MULTILINE)
135 err_m = re.search(r'^FAILED \(errors=(\d+)\)', txt, re.MULTILINE)
135 if err_m:
136 if err_m:
136 nerr = int(err_m.group(1))
137 nerr = int(err_m.group(1))
137 nfail = 0
138 nfail = 0
138 return nerr, nfail
139 return nerr, nfail
139
140
140 fail_m = re.search(r'^FAILED \(failures=(\d+)\)', txt, re.MULTILINE)
141 fail_m = re.search(r'^FAILED \(failures=(\d+)\)', txt, re.MULTILINE)
141 if fail_m:
142 if fail_m:
142 nerr = 0
143 nerr = 0
143 nfail = int(fail_m.group(1))
144 nfail = int(fail_m.group(1))
144 return nerr, nfail
145 return nerr, nfail
145
146
146 both_m = re.search(r'^FAILED \(errors=(\d+), failures=(\d+)\)', txt,
147 both_m = re.search(r'^FAILED \(errors=(\d+), failures=(\d+)\)', txt,
147 re.MULTILINE)
148 re.MULTILINE)
148 if both_m:
149 if both_m:
149 nerr = int(both_m.group(1))
150 nerr = int(both_m.group(1))
150 nfail = int(both_m.group(2))
151 nfail = int(both_m.group(2))
151 return nerr, nfail
152 return nerr, nfail
152
153
153 # If the input didn't match any of these forms, assume no error/failures
154 # If the input didn't match any of these forms, assume no error/failures
154 return 0, 0
155 return 0, 0
155
156
156
157
157 # So nose doesn't think this is a test
158 # So nose doesn't think this is a test
158 parse_test_output.__test__ = False
159 parse_test_output.__test__ = False
159
160
160
161
161 def default_argv():
162 def default_argv():
162 """Return a valid default argv for creating testing instances of ipython"""
163 """Return a valid default argv for creating testing instances of ipython"""
163
164
164 return ['--quick', # so no config file is loaded
165 return ['--quick', # so no config file is loaded
165 # Other defaults to minimize side effects on stdout
166 # Other defaults to minimize side effects on stdout
166 '--colors=NoColor', '--no-term-title','--no-banner',
167 '--colors=NoColor', '--no-term-title','--no-banner',
167 '--autocall=0']
168 '--autocall=0']
168
169
170
171 def default_config():
172 """Return a config object with good defaults for testing."""
173 config = Config()
174 config.InteractiveShell.colors = 'NoColor'
175 config.InteractiveShell.term_title = False,
176 config.InteractiveShell.autocall = 0
177 return config
178
169
179
170 def ipexec(fname, options=None):
180 def ipexec(fname, options=None):
171 """Utility to call 'ipython filename'.
181 """Utility to call 'ipython filename'.
172
182
173 Starts IPython witha minimal and safe configuration to make startup as fast
183 Starts IPython witha minimal and safe configuration to make startup as fast
174 as possible.
184 as possible.
175
185
176 Note that this starts IPython in a subprocess!
186 Note that this starts IPython in a subprocess!
177
187
178 Parameters
188 Parameters
179 ----------
189 ----------
180 fname : str
190 fname : str
181 Name of file to be executed (should have .py or .ipy extension).
191 Name of file to be executed (should have .py or .ipy extension).
182
192
183 options : optional, list
193 options : optional, list
184 Extra command-line flags to be passed to IPython.
194 Extra command-line flags to be passed to IPython.
185
195
186 Returns
196 Returns
187 -------
197 -------
188 (stdout, stderr) of ipython subprocess.
198 (stdout, stderr) of ipython subprocess.
189 """
199 """
190 if options is None: options = []
200 if options is None: options = []
191
201
192 # For these subprocess calls, eliminate all prompt printing so we only see
202 # For these subprocess calls, eliminate all prompt printing so we only see
193 # output from script execution
203 # output from script execution
194 prompt_opts = ['--prompt-in1=""', '--prompt-in2=""', '--prompt-out=""']
204 prompt_opts = ['--prompt-in1=""', '--prompt-in2=""', '--prompt-out=""']
195 cmdargs = ' '.join(default_argv() + prompt_opts + options)
205 cmdargs = ' '.join(default_argv() + prompt_opts + options)
196
206
197 _ip = get_ipython()
207 _ip = get_ipython()
198 test_dir = os.path.dirname(__file__)
208 test_dir = os.path.dirname(__file__)
199
209
200 # Find the ipython script from the package we're using, so that the test
210 # Find the ipython script from the package we're using, so that the test
201 # suite can be run from the source tree without an installed IPython
211 # suite can be run from the source tree without an installed IPython
202 p = os.path
212 p = os.path
203 if INSTALLED:
213 if INSTALLED:
204 ipython_cmd = find_cmd('ipython')
214 ipython_cmd = find_cmd('ipython')
205 else:
215 else:
206 ippath = p.abspath(p.join(p.dirname(__file__),'..','..'))
216 ippath = p.abspath(p.join(p.dirname(__file__),'..','..'))
207 ipython_script = p.join(ippath, 'ipython.py')
217 ipython_script = p.join(ippath, 'ipython.py')
208 ipython_cmd = 'python "%s"' % ipython_script
218 ipython_cmd = 'python "%s"' % ipython_script
209 # Absolute path for filename
219 # Absolute path for filename
210 full_fname = p.join(test_dir, fname)
220 full_fname = p.join(test_dir, fname)
211 full_cmd = '%s %s %s' % (ipython_cmd, cmdargs, full_fname)
221 full_cmd = '%s %s %s' % (ipython_cmd, cmdargs, full_fname)
212 #print >> sys.stderr, 'FULL CMD:', full_cmd # dbg
222 #print >> sys.stderr, 'FULL CMD:', full_cmd # dbg
213 return getoutputerror(full_cmd)
223 return getoutputerror(full_cmd)
214
224
215
225
216 def ipexec_validate(fname, expected_out, expected_err='',
226 def ipexec_validate(fname, expected_out, expected_err='',
217 options=None):
227 options=None):
218 """Utility to call 'ipython filename' and validate output/error.
228 """Utility to call 'ipython filename' and validate output/error.
219
229
220 This function raises an AssertionError if the validation fails.
230 This function raises an AssertionError if the validation fails.
221
231
222 Note that this starts IPython in a subprocess!
232 Note that this starts IPython in a subprocess!
223
233
224 Parameters
234 Parameters
225 ----------
235 ----------
226 fname : str
236 fname : str
227 Name of the file to be executed (should have .py or .ipy extension).
237 Name of the file to be executed (should have .py or .ipy extension).
228
238
229 expected_out : str
239 expected_out : str
230 Expected stdout of the process.
240 Expected stdout of the process.
231
241
232 expected_err : optional, str
242 expected_err : optional, str
233 Expected stderr of the process.
243 Expected stderr of the process.
234
244
235 options : optional, list
245 options : optional, list
236 Extra command-line flags to be passed to IPython.
246 Extra command-line flags to be passed to IPython.
237
247
238 Returns
248 Returns
239 -------
249 -------
240 None
250 None
241 """
251 """
242
252
243 import nose.tools as nt
253 import nose.tools as nt
244
254
245 out, err = ipexec(fname)
255 out, err = ipexec(fname)
246 #print 'OUT', out # dbg
256 #print 'OUT', out # dbg
247 #print 'ERR', err # dbg
257 #print 'ERR', err # dbg
248 # If there are any errors, we must check those befor stdout, as they may be
258 # If there are any errors, we must check those befor stdout, as they may be
249 # more informative than simply having an empty stdout.
259 # more informative than simply having an empty stdout.
250 if err:
260 if err:
251 if expected_err:
261 if expected_err:
252 nt.assert_equals(err.strip(), expected_err.strip())
262 nt.assert_equals(err.strip(), expected_err.strip())
253 else:
263 else:
254 raise ValueError('Running file %r produced error: %r' %
264 raise ValueError('Running file %r produced error: %r' %
255 (fname, err))
265 (fname, err))
256 # If no errors or output on stderr was expected, match stdout
266 # If no errors or output on stderr was expected, match stdout
257 nt.assert_equals(out.strip(), expected_out.strip())
267 nt.assert_equals(out.strip(), expected_out.strip())
258
268
259
269
260 class TempFileMixin(object):
270 class TempFileMixin(object):
261 """Utility class to create temporary Python/IPython files.
271 """Utility class to create temporary Python/IPython files.
262
272
263 Meant as a mixin class for test cases."""
273 Meant as a mixin class for test cases."""
264
274
265 def mktmp(self, src, ext='.py'):
275 def mktmp(self, src, ext='.py'):
266 """Make a valid python temp file."""
276 """Make a valid python temp file."""
267 fname, f = temp_pyfile(src, ext)
277 fname, f = temp_pyfile(src, ext)
268 self.tmpfile = f
278 self.tmpfile = f
269 self.fname = fname
279 self.fname = fname
270
280
271 def teardown(self):
281 def teardown(self):
272 if hasattr(self, 'tmpfile'):
282 if hasattr(self, 'tmpfile'):
273 # If the tmpfile wasn't made because of skipped tests, like in
283 # If the tmpfile wasn't made because of skipped tests, like in
274 # win32, there's nothing to cleanup.
284 # win32, there's nothing to cleanup.
275 self.tmpfile.close()
285 self.tmpfile.close()
276 try:
286 try:
277 os.unlink(self.fname)
287 os.unlink(self.fname)
278 except:
288 except:
279 # On Windows, even though we close the file, we still can't
289 # On Windows, even though we close the file, we still can't
280 # delete it. I have no clue why
290 # delete it. I have no clue why
281 pass
291 pass
282
292
@@ -1,342 +1,340 b''
1 # encoding: utf-8
1 # encoding: utf-8
2 """
2 """
3 Utilities for path handling.
3 Utilities for path handling.
4 """
4 """
5
5
6 #-----------------------------------------------------------------------------
6 #-----------------------------------------------------------------------------
7 # Copyright (C) 2008-2009 The IPython Development Team
7 # Copyright (C) 2008-2009 The IPython Development Team
8 #
8 #
9 # Distributed under the terms of the BSD License. The full license is in
9 # Distributed under the terms of the BSD License. The full license is in
10 # the file COPYING, distributed as part of this software.
10 # the file COPYING, distributed as part of this software.
11 #-----------------------------------------------------------------------------
11 #-----------------------------------------------------------------------------
12
12
13 #-----------------------------------------------------------------------------
13 #-----------------------------------------------------------------------------
14 # Imports
14 # Imports
15 #-----------------------------------------------------------------------------
15 #-----------------------------------------------------------------------------
16
16
17 import os
17 import os
18 import sys
18 import sys
19
19
20 import IPython
20 import IPython
21 from IPython.utils.process import xsys
21 from IPython.utils.process import xsys
22 from IPython.utils.importstring import import_item
22 from IPython.utils.importstring import import_item
23
23
24 #-----------------------------------------------------------------------------
24 #-----------------------------------------------------------------------------
25 # Code
25 # Code
26 #-----------------------------------------------------------------------------
26 #-----------------------------------------------------------------------------
27
27
28
28
29 def _get_long_path_name(path):
29 def _get_long_path_name(path):
30 """Dummy no-op."""
30 """Dummy no-op."""
31 return path
31 return path
32
32
33
33
34 if sys.platform == 'win32':
34 if sys.platform == 'win32':
35 def _get_long_path_name(path):
35 def _get_long_path_name(path):
36 """Get a long path name (expand ~) on Windows using ctypes.
36 """Get a long path name (expand ~) on Windows using ctypes.
37
37
38 Examples
38 Examples
39 --------
39 --------
40
40
41 >>> get_long_path_name('c:\\docume~1')
41 >>> get_long_path_name('c:\\docume~1')
42 u'c:\\\\Documents and Settings'
42 u'c:\\\\Documents and Settings'
43
43
44 """
44 """
45 try:
45 try:
46 import ctypes
46 import ctypes
47 except ImportError:
47 except ImportError:
48 raise ImportError('you need to have ctypes installed for this to work')
48 raise ImportError('you need to have ctypes installed for this to work')
49 _GetLongPathName = ctypes.windll.kernel32.GetLongPathNameW
49 _GetLongPathName = ctypes.windll.kernel32.GetLongPathNameW
50 _GetLongPathName.argtypes = [ctypes.c_wchar_p, ctypes.c_wchar_p,
50 _GetLongPathName.argtypes = [ctypes.c_wchar_p, ctypes.c_wchar_p,
51 ctypes.c_uint ]
51 ctypes.c_uint ]
52
52
53 buf = ctypes.create_unicode_buffer(260)
53 buf = ctypes.create_unicode_buffer(260)
54 rv = _GetLongPathName(path, buf, 260)
54 rv = _GetLongPathName(path, buf, 260)
55 if rv == 0 or rv > 260:
55 if rv == 0 or rv > 260:
56 return path
56 return path
57 else:
57 else:
58 return buf.value
58 return buf.value
59
59
60
60
61 def get_long_path_name(path):
61 def get_long_path_name(path):
62 """Expand a path into its long form.
62 """Expand a path into its long form.
63
63
64 On Windows this expands any ~ in the paths. On other platforms, it is
64 On Windows this expands any ~ in the paths. On other platforms, it is
65 a null operation.
65 a null operation.
66 """
66 """
67 return _get_long_path_name(path)
67 return _get_long_path_name(path)
68
68
69
69
70 def get_py_filename(name):
70 def get_py_filename(name):
71 """Return a valid python filename in the current directory.
71 """Return a valid python filename in the current directory.
72
72
73 If the given name is not a file, it adds '.py' and searches again.
73 If the given name is not a file, it adds '.py' and searches again.
74 Raises IOError with an informative message if the file isn't found."""
74 Raises IOError with an informative message if the file isn't found."""
75
75
76 name = os.path.expanduser(name)
76 name = os.path.expanduser(name)
77 if not os.path.isfile(name) and not name.endswith('.py'):
77 if not os.path.isfile(name) and not name.endswith('.py'):
78 name += '.py'
78 name += '.py'
79 if os.path.isfile(name):
79 if os.path.isfile(name):
80 return name
80 return name
81 else:
81 else:
82 raise IOError,'File `%s` not found.' % name
82 raise IOError,'File `%s` not found.' % name
83
83
84
84
85 def filefind(filename, path_dirs=None):
85 def filefind(filename, path_dirs=None):
86 """Find a file by looking through a sequence of paths.
86 """Find a file by looking through a sequence of paths.
87
87
88 This iterates through a sequence of paths looking for a file and returns
88 This iterates through a sequence of paths looking for a file and returns
89 the full, absolute path of the first occurence of the file. If no set of
89 the full, absolute path of the first occurence of the file. If no set of
90 path dirs is given, the filename is tested as is, after running through
90 path dirs is given, the filename is tested as is, after running through
91 :func:`expandvars` and :func:`expanduser`. Thus a simple call::
91 :func:`expandvars` and :func:`expanduser`. Thus a simple call::
92
92
93 filefind('myfile.txt')
93 filefind('myfile.txt')
94
94
95 will find the file in the current working dir, but::
95 will find the file in the current working dir, but::
96
96
97 filefind('~/myfile.txt')
97 filefind('~/myfile.txt')
98
98
99 Will find the file in the users home directory. This function does not
99 Will find the file in the users home directory. This function does not
100 automatically try any paths, such as the cwd or the user's home directory.
100 automatically try any paths, such as the cwd or the user's home directory.
101
101
102 Parameters
102 Parameters
103 ----------
103 ----------
104 filename : str
104 filename : str
105 The filename to look for.
105 The filename to look for.
106 path_dirs : str, None or sequence of str
106 path_dirs : str, None or sequence of str
107 The sequence of paths to look for the file in. If None, the filename
107 The sequence of paths to look for the file in. If None, the filename
108 need to be absolute or be in the cwd. If a string, the string is
108 need to be absolute or be in the cwd. If a string, the string is
109 put into a sequence and the searched. If a sequence, walk through
109 put into a sequence and the searched. If a sequence, walk through
110 each element and join with ``filename``, calling :func:`expandvars`
110 each element and join with ``filename``, calling :func:`expandvars`
111 and :func:`expanduser` before testing for existence.
111 and :func:`expanduser` before testing for existence.
112
112
113 Returns
113 Returns
114 -------
114 -------
115 Raises :exc:`IOError` or returns absolute path to file.
115 Raises :exc:`IOError` or returns absolute path to file.
116 """
116 """
117
117
118 # If paths are quoted, abspath gets confused, strip them...
118 # If paths are quoted, abspath gets confused, strip them...
119 filename = filename.strip('"').strip("'")
119 filename = filename.strip('"').strip("'")
120 # If the input is an absolute path, just check it exists
120 # If the input is an absolute path, just check it exists
121 if os.path.isabs(filename) and os.path.isfile(filename):
121 if os.path.isabs(filename) and os.path.isfile(filename):
122 return filename
122 return filename
123
123
124 if path_dirs is None:
124 if path_dirs is None:
125 path_dirs = ("",)
125 path_dirs = ("",)
126 elif isinstance(path_dirs, basestring):
126 elif isinstance(path_dirs, basestring):
127 path_dirs = (path_dirs,)
127 path_dirs = (path_dirs,)
128
128
129 for path in path_dirs:
129 for path in path_dirs:
130 if path == '.': path = os.getcwd()
130 if path == '.': path = os.getcwd()
131 testname = expand_path(os.path.join(path, filename))
131 testname = expand_path(os.path.join(path, filename))
132 if os.path.isfile(testname):
132 if os.path.isfile(testname):
133 return os.path.abspath(testname)
133 return os.path.abspath(testname)
134
134
135 raise IOError("File %r does not exist in any of the search paths: %r" %
135 raise IOError("File %r does not exist in any of the search paths: %r" %
136 (filename, path_dirs) )
136 (filename, path_dirs) )
137
137
138
138
139 class HomeDirError(Exception):
139 class HomeDirError(Exception):
140 pass
140 pass
141
141
142
142
143 def get_home_dir():
143 def get_home_dir():
144 """Return the closest possible equivalent to a 'home' directory.
144 """Return the closest possible equivalent to a 'home' directory.
145
145
146 * On POSIX, we try $HOME.
146 * On POSIX, we try $HOME.
147 * On Windows we try:
147 * On Windows we try:
148 - %HOME%: rare, but some people with unix-like setups may have defined it
148 - %HOME%: rare, but some people with unix-like setups may have defined it
149 - %HOMESHARE%
149 - %HOMESHARE%
150 - %HOMEDRIVE\%HOMEPATH%
150 - %HOMEDRIVE\%HOMEPATH%
151 - %USERPROFILE%
151 - %USERPROFILE%
152 - Registry hack
152 - Registry hack
153 * On Dos C:\
153 * On Dos C:\
154
154
155 Currently only Posix and NT are implemented, a HomeDirError exception is
155 Currently only Posix and NT are implemented, a HomeDirError exception is
156 raised for all other OSes.
156 raised for all other OSes.
157 """
157 """
158
158
159 isdir = os.path.isdir
159 isdir = os.path.isdir
160 env = os.environ
160 env = os.environ
161
161
162 # first, check py2exe distribution root directory for _ipython.
162 # first, check py2exe distribution root directory for _ipython.
163 # This overrides all. Normally does not exist.
163 # This overrides all. Normally does not exist.
164
164
165 if hasattr(sys, "frozen"): #Is frozen by py2exe
165 if hasattr(sys, "frozen"): #Is frozen by py2exe
166 if '\\library.zip\\' in IPython.__file__.lower():#libraries compressed to zip-file
166 if '\\library.zip\\' in IPython.__file__.lower():#libraries compressed to zip-file
167 root, rest = IPython.__file__.lower().split('library.zip')
167 root, rest = IPython.__file__.lower().split('library.zip')
168 else:
168 else:
169 root=os.path.join(os.path.split(IPython.__file__)[0],"../../")
169 root=os.path.join(os.path.split(IPython.__file__)[0],"../../")
170 root=os.path.abspath(root).rstrip('\\')
170 root=os.path.abspath(root).rstrip('\\')
171 if isdir(os.path.join(root, '_ipython')):
171 if isdir(os.path.join(root, '_ipython')):
172 os.environ["IPYKITROOT"] = root
172 os.environ["IPYKITROOT"] = root
173 return root.decode(sys.getfilesystemencoding())
173 return root.decode(sys.getfilesystemencoding())
174
174
175 if os.name == 'posix':
175 if os.name == 'posix':
176 # Linux, Unix, AIX, OS X
176 # Linux, Unix, AIX, OS X
177 try:
177 try:
178 homedir = env['HOME']
178 homedir = env['HOME']
179 except KeyError:
179 except KeyError:
180 raise HomeDirError('Undefined $HOME, IPython cannot proceed.')
180 raise HomeDirError('Undefined $HOME, IPython cannot proceed.')
181 else:
181 else:
182 return homedir.decode(sys.getfilesystemencoding())
182 return homedir.decode(sys.getfilesystemencoding())
183 elif os.name == 'nt':
183 elif os.name == 'nt':
184 # Now for win9x, XP, Vista, 7?
184 # Now for win9x, XP, Vista, 7?
185 # For some strange reason all of these return 'nt' for os.name.
185 # For some strange reason all of these return 'nt' for os.name.
186 # First look for a network home directory. This will return the UNC
186 # First look for a network home directory. This will return the UNC
187 # path (\\server\\Users\%username%) not the mapped path (Z:\). This
187 # path (\\server\\Users\%username%) not the mapped path (Z:\). This
188 # is needed when running IPython on cluster where all paths have to
188 # is needed when running IPython on cluster where all paths have to
189 # be UNC.
189 # be UNC.
190 try:
190 try:
191 # A user with a lot of unix tools in win32 may have defined $HOME,
191 # A user with a lot of unix tools in win32 may have defined $HOME,
192 # honor it if it exists, but otherwise let the more typical
192 # honor it if it exists, but otherwise let the more typical
193 # %HOMESHARE% variable be used.
193 # %HOMESHARE% variable be used.
194 homedir = env.get('HOME')
194 homedir = env.get('HOME')
195 if homedir is None:
195 if homedir is None:
196 homedir = env['HOMESHARE']
196 homedir = env['HOMESHARE']
197 except KeyError:
197 except KeyError:
198 pass
198 pass
199 else:
199 else:
200 if isdir(homedir):
200 if isdir(homedir):
201 return homedir.decode(sys.getfilesystemencoding())
201 return homedir.decode(sys.getfilesystemencoding())
202
202
203 # Now look for a local home directory
203 # Now look for a local home directory
204 try:
204 try:
205 homedir = os.path.join(env['HOMEDRIVE'],env['HOMEPATH'])
205 homedir = os.path.join(env['HOMEDRIVE'],env['HOMEPATH'])
206 except KeyError:
206 except KeyError:
207 pass
207 pass
208 else:
208 else:
209 if isdir(homedir):
209 if isdir(homedir):
210 return homedir.decode(sys.getfilesystemencoding())
210 return homedir.decode(sys.getfilesystemencoding())
211
211
212 # Now the users profile directory
212 # Now the users profile directory
213 try:
213 try:
214 homedir = os.path.join(env['USERPROFILE'])
214 homedir = os.path.join(env['USERPROFILE'])
215 except KeyError:
215 except KeyError:
216 pass
216 pass
217 else:
217 else:
218 if isdir(homedir):
218 if isdir(homedir):
219 return homedir.decode(sys.getfilesystemencoding())
219 return homedir.decode(sys.getfilesystemencoding())
220
220
221 # Use the registry to get the 'My Documents' folder.
221 # Use the registry to get the 'My Documents' folder.
222 try:
222 try:
223 import _winreg as wreg
223 import _winreg as wreg
224 key = wreg.OpenKey(
224 key = wreg.OpenKey(
225 wreg.HKEY_CURRENT_USER,
225 wreg.HKEY_CURRENT_USER,
226 "Software\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders"
226 "Software\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders"
227 )
227 )
228 homedir = wreg.QueryValueEx(key,'Personal')[0]
228 homedir = wreg.QueryValueEx(key,'Personal')[0]
229 key.Close()
229 key.Close()
230 except:
230 except:
231 pass
231 pass
232 else:
232 else:
233 if isdir(homedir):
233 if isdir(homedir):
234 return homedir.decode(sys.getfilesystemencoding())
234 return homedir.decode(sys.getfilesystemencoding())
235
235
236 # If all else fails, raise HomeDirError
236 # If all else fails, raise HomeDirError
237 raise HomeDirError('No valid home directory could be found')
237 raise HomeDirError('No valid home directory could be found')
238 elif os.name == 'dos':
238 elif os.name == 'dos':
239 # Desperate, may do absurd things in classic MacOS. May work under DOS.
239 # Desperate, may do absurd things in classic MacOS. May work under DOS.
240 return 'C:\\'.decode(sys.getfilesystemencoding())
240 return 'C:\\'.decode(sys.getfilesystemencoding())
241 else:
241 else:
242 raise HomeDirError('No valid home directory could be found for your OS')
242 raise HomeDirError('No valid home directory could be found for your OS')
243
243
244
244
245 def get_ipython_dir():
245 def get_ipython_dir():
246 """Get the IPython directory for this platform and user.
246 """Get the IPython directory for this platform and user.
247
247
248 This uses the logic in `get_home_dir` to find the home directory
248 This uses the logic in `get_home_dir` to find the home directory
249 and the adds .ipython to the end of the path.
249 and the adds .ipython to the end of the path.
250 """
250 """
251 ipdir_def = '.ipython'
251 ipdir_def = '.ipython'
252 print get_home_dir
253 home_dir = get_home_dir()
252 home_dir = get_home_dir()
254 print home_dir
255 #import pdb; pdb.set_trace() # dbg
253 #import pdb; pdb.set_trace() # dbg
256 ipdir = os.environ.get(
254 ipdir = os.environ.get(
257 'IPYTHON_DIR', os.environ.get(
255 'IPYTHON_DIR', os.environ.get(
258 'IPYTHONDIR', os.path.join(home_dir, ipdir_def)
256 'IPYTHONDIR', os.path.join(home_dir, ipdir_def)
259 )
257 )
260 )
258 )
261 return ipdir.decode(sys.getfilesystemencoding())
259 return ipdir.decode(sys.getfilesystemencoding())
262
260
263
261
264 def get_ipython_package_dir():
262 def get_ipython_package_dir():
265 """Get the base directory where IPython itself is installed."""
263 """Get the base directory where IPython itself is installed."""
266 ipdir = os.path.dirname(IPython.__file__)
264 ipdir = os.path.dirname(IPython.__file__)
267 return ipdir.decode(sys.getfilesystemencoding())
265 return ipdir.decode(sys.getfilesystemencoding())
268
266
269
267
270 def get_ipython_module_path(module_str):
268 def get_ipython_module_path(module_str):
271 """Find the path to an IPython module in this version of IPython.
269 """Find the path to an IPython module in this version of IPython.
272
270
273 This will always find the version of the module that is in this importable
271 This will always find the version of the module that is in this importable
274 IPython package. This will always return the path to the ``.py``
272 IPython package. This will always return the path to the ``.py``
275 version of the module.
273 version of the module.
276 """
274 """
277 if module_str == 'IPython':
275 if module_str == 'IPython':
278 return os.path.join(get_ipython_package_dir(), '__init__.py')
276 return os.path.join(get_ipython_package_dir(), '__init__.py')
279 mod = import_item(module_str)
277 mod = import_item(module_str)
280 the_path = mod.__file__.replace('.pyc', '.py')
278 the_path = mod.__file__.replace('.pyc', '.py')
281 the_path = the_path.replace('.pyo', '.py')
279 the_path = the_path.replace('.pyo', '.py')
282 return the_path.decode(sys.getfilesystemencoding())
280 return the_path.decode(sys.getfilesystemencoding())
283
281
284
282
285 def expand_path(s):
283 def expand_path(s):
286 """Expand $VARS and ~names in a string, like a shell
284 """Expand $VARS and ~names in a string, like a shell
287
285
288 :Examples:
286 :Examples:
289
287
290 In [2]: os.environ['FOO']='test'
288 In [2]: os.environ['FOO']='test'
291
289
292 In [3]: expand_path('variable FOO is $FOO')
290 In [3]: expand_path('variable FOO is $FOO')
293 Out[3]: 'variable FOO is test'
291 Out[3]: 'variable FOO is test'
294 """
292 """
295 # This is a pretty subtle hack. When expand user is given a UNC path
293 # This is a pretty subtle hack. When expand user is given a UNC path
296 # on Windows (\\server\share$\%username%), os.path.expandvars, removes
294 # on Windows (\\server\share$\%username%), os.path.expandvars, removes
297 # the $ to get (\\server\share\%username%). I think it considered $
295 # the $ to get (\\server\share\%username%). I think it considered $
298 # alone an empty var. But, we need the $ to remains there (it indicates
296 # alone an empty var. But, we need the $ to remains there (it indicates
299 # a hidden share).
297 # a hidden share).
300 if os.name=='nt':
298 if os.name=='nt':
301 s = s.replace('$\\', 'IPYTHON_TEMP')
299 s = s.replace('$\\', 'IPYTHON_TEMP')
302 s = os.path.expandvars(os.path.expanduser(s))
300 s = os.path.expandvars(os.path.expanduser(s))
303 if os.name=='nt':
301 if os.name=='nt':
304 s = s.replace('IPYTHON_TEMP', '$\\')
302 s = s.replace('IPYTHON_TEMP', '$\\')
305 return s
303 return s
306
304
307
305
308 def target_outdated(target,deps):
306 def target_outdated(target,deps):
309 """Determine whether a target is out of date.
307 """Determine whether a target is out of date.
310
308
311 target_outdated(target,deps) -> 1/0
309 target_outdated(target,deps) -> 1/0
312
310
313 deps: list of filenames which MUST exist.
311 deps: list of filenames which MUST exist.
314 target: single filename which may or may not exist.
312 target: single filename which may or may not exist.
315
313
316 If target doesn't exist or is older than any file listed in deps, return
314 If target doesn't exist or is older than any file listed in deps, return
317 true, otherwise return false.
315 true, otherwise return false.
318 """
316 """
319 try:
317 try:
320 target_time = os.path.getmtime(target)
318 target_time = os.path.getmtime(target)
321 except os.error:
319 except os.error:
322 return 1
320 return 1
323 for dep in deps:
321 for dep in deps:
324 dep_time = os.path.getmtime(dep)
322 dep_time = os.path.getmtime(dep)
325 if dep_time > target_time:
323 if dep_time > target_time:
326 #print "For target",target,"Dep failed:",dep # dbg
324 #print "For target",target,"Dep failed:",dep # dbg
327 #print "times (dep,tar):",dep_time,target_time # dbg
325 #print "times (dep,tar):",dep_time,target_time # dbg
328 return 1
326 return 1
329 return 0
327 return 0
330
328
331
329
332 def target_update(target,deps,cmd):
330 def target_update(target,deps,cmd):
333 """Update a target with a given command given a list of dependencies.
331 """Update a target with a given command given a list of dependencies.
334
332
335 target_update(target,deps,cmd) -> runs cmd if target is outdated.
333 target_update(target,deps,cmd) -> runs cmd if target is outdated.
336
334
337 This is just a wrapper around target_outdated() which calls the given
335 This is just a wrapper around target_outdated() which calls the given
338 command if target is outdated."""
336 command if target is outdated."""
339
337
340 if target_outdated(target,deps):
338 if target_outdated(target,deps):
341 xsys(cmd)
339 xsys(cmd)
342
340
@@ -1,388 +1,388 b''
1 .. _testing:
1 .. _testing:
2
2
3 ==========================================
3 ==========================================
4 Testing IPython for users and developers
4 Testing IPython for users and developers
5 ==========================================
5 ==========================================
6
6
7 Overview
7 Overview
8 ========
8 ========
9
9
10 It is extremely important that all code contributed to IPython has tests.
10 It is extremely important that all code contributed to IPython has tests.
11 Tests should be written as unittests, doctests or other entities that the
11 Tests should be written as unittests, doctests or other entities that the
12 IPython test system can detect. See below for more details on this.
12 IPython test system can detect. See below for more details on this.
13
13
14 Each subpackage in IPython should have its own :file:`tests` directory that
14 Each subpackage in IPython should have its own :file:`tests` directory that
15 contains all of the tests for that subpackage. All of the files in the
15 contains all of the tests for that subpackage. All of the files in the
16 :file:`tests` directory should have the word "tests" in them to enable
16 :file:`tests` directory should have the word "tests" in them to enable
17 the testing framework to find them.
17 the testing framework to find them.
18
18
19 In docstrings, examples (either using IPython prompts like ``In [1]:`` or
19 In docstrings, examples (either using IPython prompts like ``In [1]:`` or
20 'classic' python ``>>>`` ones) can and should be included. The testing system
20 'classic' python ``>>>`` ones) can and should be included. The testing system
21 will detect them as doctests and will run them; it offers control to skip parts
21 will detect them as doctests and will run them; it offers control to skip parts
22 or all of a specific doctest if the example is meant to be informative but
22 or all of a specific doctest if the example is meant to be informative but
23 shows non-reproducible information (like filesystem data).
23 shows non-reproducible information (like filesystem data).
24
24
25 If a subpackage has any dependencies beyond the Python standard library, the
25 If a subpackage has any dependencies beyond the Python standard library, the
26 tests for that subpackage should be skipped if the dependencies are not found.
26 tests for that subpackage should be skipped if the dependencies are not found.
27 This is very important so users don't get tests failing simply because they
27 This is very important so users don't get tests failing simply because they
28 don't have dependencies.
28 don't have dependencies.
29
29
30 The testing system we use is a hybrid of nose_ and Twisted's trial_ test runner.
30 The testing system we use is a hybrid of nose_ and Twisted's trial_ test runner.
31 We use both because nose detects more things than Twisted and allows for more
31 We use both because nose detects more things than Twisted and allows for more
32 flexible (and lighter-weight) ways of writing tests; in particular we've
32 flexible (and lighter-weight) ways of writing tests; in particular we've
33 developed a nose plugin that allows us to paste verbatim IPython sessions and
33 developed a nose plugin that allows us to paste verbatim IPython sessions and
34 test them as doctests, which is extremely important for us. But the parts of
34 test them as doctests, which is extremely important for us. But the parts of
35 IPython that depend on Twisted must be tested using trial, because only trial
35 IPython that depend on Twisted must be tested using trial, because only trial
36 manages the Twisted reactor correctly.
36 manages the Twisted reactor correctly.
37
37
38 .. _nose: http://code.google.com/p/python-nose
38 .. _nose: http://code.google.com/p/python-nose
39 .. _trial: http://twistedmatrix.com/trac/wiki/TwistedTrial
39 .. _trial: http://twistedmatrix.com/trac/wiki/TwistedTrial
40
40
41
41
42 For the impatient: running the tests
42 For the impatient: running the tests
43 ====================================
43 ====================================
44
44
45 You can run IPython from the source download directory without even installing
45 You can run IPython from the source download directory without even installing
46 it system-wide or having configure anything, by typing at the terminal:
46 it system-wide or having configure anything, by typing at the terminal:
47
47
48 .. code-block:: bash
48 .. code-block:: bash
49
49
50 python ipython.py
50 python ipython.py
51
51
52 and similarly, you can execute the built-in test suite with:
52 and similarly, you can execute the built-in test suite with:
53
53
54 .. code-block:: bash
54 .. code-block:: bash
55
55
56 python iptest.py
56 python iptest.py
57
57
58
58
59 This script manages intelligently both nose and trial, choosing the correct
59 This script manages intelligently both nose and trial, choosing the correct
60 test system for each of IPython's components.
60 test system for each of IPython's components.
61
61
62 Once you have either installed it or at least configured your system to be
62 Once you have either installed it or at least configured your system to be
63 able to import IPython, you can run the tests with:
63 able to import IPython, you can run the tests with:
64
64
65 .. code-block:: bash
65 .. code-block:: bash
66
66
67 python -c "import IPython; IPython.test()"
67 python -c "import IPython; IPython.test()"
68
68
69 This should work as long as IPython can be imported, even if you haven't fully
69 This should work as long as IPython can be imported, even if you haven't fully
70 installed the user-facing scripts yet (common in a development environment).
70 installed the user-facing scripts yet (common in a development environment).
71 Once you have installed IPython, you will have available system-wide a script
71 Once you have installed IPython, you will have available system-wide a script
72 called :file:`iptest` that does the exact same as the :file:`iptest.py` script
72 called :file:`iptest` that does the exact same as the :file:`iptest.py` script
73 in the source directory, so you can then test simply with:
73 in the source directory, so you can then test simply with:
74
74
75 .. code-block:: bash
75 .. code-block:: bash
76
76
77 iptest [args]
77 iptest [args]
78
78
79
79
80 Regardless of how you run things, you should eventually see something like:
80 Regardless of how you run things, you should eventually see something like:
81
81
82 .. code-block:: bash
82 .. code-block:: bash
83
83
84 **********************************************************************
84 **********************************************************************
85 Test suite completed for system with the following information:
85 Test suite completed for system with the following information:
86 IPython version: 0.11.bzr.r1340
86 IPython version: 0.11.bzr.r1340
87 BZR revision : 1340
87 BZR revision : 1340
88 Platform info : os.name -> posix, sys.platform -> linux2
88 Platform info : os.name -> posix, sys.platform -> linux2
89 : Linux-2.6.31-17-generic-i686-with-Ubuntu-9.10-karmic
89 : Linux-2.6.31-17-generic-i686-with-Ubuntu-9.10-karmic
90 Python info : 2.6.4 (r264:75706, Dec 7 2009, 18:45:15)
90 Python info : 2.6.4 (r264:75706, Dec 7 2009, 18:45:15)
91 [GCC 4.4.1]
91 [GCC 4.4.1]
92
92
93 Running from an installed IPython: True
93 Running from an installed IPython: True
94
94
95 Tools and libraries available at test time:
95 Tools and libraries available at test time:
96 curses foolscap gobject gtk pexpect twisted wx wx.aui zope.interface
96 curses foolscap gobject gtk pexpect twisted wx wx.aui zope.interface
97
97
98 Tools and libraries NOT available at test time:
98 Tools and libraries NOT available at test time:
99 objc
99 objc
100
100
101 Ran 11 test groups in 36.244s
101 Ran 11 test groups in 36.244s
102
102
103 Status:
103 Status:
104 OK
104 OK
105
105
106 If not, there will be a message indicating which test group failed and how to
106 If not, there will be a message indicating which test group failed and how to
107 rerun that group individually. For example, this tests the
107 rerun that group individually. For example, this tests the
108 :mod:`IPython.utils` subpackage, the :option:`-v` option shows progress
108 :mod:`IPython.utils` subpackage, the :option:`-v` option shows progress
109 indicators:
109 indicators:
110
110
111 .. code-block:: bash
111 .. code-block:: bash
112
112
113 $ python iptest.py -v IPython.utils
113 $ python iptest.py -v IPython.utils
114 ..........................SS..SSS............................S.S...
114 ..........................SS..SSS............................S.S...
115 .........................................................
115 .........................................................
116 ----------------------------------------------------------------------
116 ----------------------------------------------------------------------
117 Ran 125 tests in 0.119s
117 Ran 125 tests in 0.119s
118
118
119 OK (SKIP=7)
119 OK (SKIP=7)
120
120
121
121
122 Because the IPython test machinery is based on nose, you can use all nose
122 Because the IPython test machinery is based on nose, you can use all nose
123 options and syntax, typing ``iptest -h`` shows all available options. For
123 options and syntax, typing ``iptest -h`` shows all available options. For
124 example, this lets you run the specific test :func:`test_rehashx` inside the
124 example, this lets you run the specific test :func:`test_rehashx` inside the
125 :mod:`test_magic` module:
125 :mod:`test_magic` module:
126
126
127 .. code-block:: bash
127 .. code-block:: bash
128
128
129 $ python iptest.py -vv IPython.core.tests.test_magic:test_rehashx
129 $ python iptest.py -vv IPython.core.tests.test_magic:test_rehashx
130 IPython.core.tests.test_magic.test_rehashx(True,) ... ok
130 IPython.core.tests.test_magic.test_rehashx(True,) ... ok
131 IPython.core.tests.test_magic.test_rehashx(True,) ... ok
131 IPython.core.tests.test_magic.test_rehashx(True,) ... ok
132
132
133 ----------------------------------------------------------------------
133 ----------------------------------------------------------------------
134 Ran 2 tests in 0.100s
134 Ran 2 tests in 0.100s
135
135
136 OK
136 OK
137
137
138 When developing, the :option:`--pdb` and :option:`--pdb-failures` of nose are
138 When developing, the :option:`--pdb` and :option:`--pdb-failures` of nose are
139 particularly useful, these drop you into an interactive pdb session at the
139 particularly useful, these drop you into an interactive pdb session at the
140 point of the error or failure respectively.
140 point of the error or failure respectively.
141
141
142 To run Twisted-using tests, use the :command:`trial` command on a per file or
142 To run Twisted-using tests, use the :command:`trial` command on a per file or
143 package basis:
143 package basis:
144
144
145 .. code-block:: bash
145 .. code-block:: bash
146
146
147 trial IPython.kernel
147 trial IPython.kernel
148
148
149
149
150 For developers: writing tests
150 For developers: writing tests
151 =============================
151 =============================
152
152
153 By now IPython has a reasonable test suite, so the best way to see what's
153 By now IPython has a reasonable test suite, so the best way to see what's
154 available is to look at the :file:`tests` directory in most subpackages. But
154 available is to look at the :file:`tests` directory in most subpackages. But
155 here are a few pointers to make the process easier.
155 here are a few pointers to make the process easier.
156
156
157
157
158 Main tools: :mod:`IPython.testing`
158 Main tools: :mod:`IPython.testing`
159 ----------------------------------
159 ----------------------------------
160
160
161 The :mod:`IPython.testing` package is where all of the machinery to test
161 The :mod:`IPython.testing` package is where all of the machinery to test
162 IPython (rather than the tests for its various parts) lives. In particular,
162 IPython (rather than the tests for its various parts) lives. In particular,
163 the :mod:`iptest` module in there has all the smarts to control the test
163 the :mod:`iptest` module in there has all the smarts to control the test
164 process. In there, the :func:`make_exclude` function is used to build a
164 process. In there, the :func:`make_exclude` function is used to build a
165 blacklist of exclusions, these are modules that do not get even imported for
165 blacklist of exclusions, these are modules that do not get even imported for
166 tests. This is important so that things that would fail to even import because
166 tests. This is important so that things that would fail to even import because
167 of missing dependencies don't give errors to end users, as we stated above.
167 of missing dependencies don't give errors to end users, as we stated above.
168
168
169 The :mod:`decorators` module contains a lot of useful decorators, especially
169 The :mod:`decorators` module contains a lot of useful decorators, especially
170 useful to mark individual tests that should be skipped under certain conditions
170 useful to mark individual tests that should be skipped under certain conditions
171 (rather than blacklisting the package altogether because of a missing major
171 (rather than blacklisting the package altogether because of a missing major
172 dependency).
172 dependency).
173
173
174 Our nose plugin for doctests
174 Our nose plugin for doctests
175 ----------------------------
175 ----------------------------
176
176
177 The :mod:`plugin` subpackage in testing contains a nose plugin called
177 The :mod:`plugin` subpackage in testing contains a nose plugin called
178 :mod:`ipdoctest` that teaches nose about IPython syntax, so you can write
178 :mod:`ipdoctest` that teaches nose about IPython syntax, so you can write
179 doctests with IPython prompts. You can also mark doctest output with ``#
179 doctests with IPython prompts. You can also mark doctest output with ``#
180 random`` for the output corresponding to a single input to be ignored (stronger
180 random`` for the output corresponding to a single input to be ignored (stronger
181 than using ellipsis and useful to keep it as an example). If you want the
181 than using ellipsis and useful to keep it as an example). If you want the
182 entire docstring to be executed but none of the output from any input to be
182 entire docstring to be executed but none of the output from any input to be
183 checked, you can use the ``# all-random`` marker. The
183 checked, you can use the ``# all-random`` marker. The
184 :mod:`IPython.testing.plugin.dtexample` module contains examples of how to use
184 :mod:`IPython.testing.plugin.dtexample` module contains examples of how to use
185 these; for reference here is how to use ``# random``::
185 these; for reference here is how to use ``# random``::
186
186
187 def ranfunc():
187 def ranfunc():
188 """A function with some random output.
188 """A function with some random output.
189
189
190 Normal examples are verified as usual:
190 Normal examples are verified as usual:
191 >>> 1+3
191 >>> 1+3
192 4
192 4
193
193
194 But if you put '# random' in the output, it is ignored:
194 But if you put '# random' in the output, it is ignored:
195 >>> 1+3
195 >>> 1+3
196 junk goes here... # random
196 junk goes here... # random
197
197
198 >>> 1+2
198 >>> 1+2
199 again, anything goes #random
199 again, anything goes #random
200 if multiline, the random mark is only needed once.
200 if multiline, the random mark is only needed once.
201
201
202 >>> 1+2
202 >>> 1+2
203 You can also put the random marker at the end:
203 You can also put the random marker at the end:
204 # random
204 # random
205
205
206 >>> 1+2
206 >>> 1+2
207 # random
207 # random
208 .. or at the beginning.
208 .. or at the beginning.
209
209
210 More correct input is properly verified:
210 More correct input is properly verified:
211 >>> ranfunc()
211 >>> ranfunc()
212 'ranfunc'
212 'ranfunc'
213 """
213 """
214 return 'ranfunc'
214 return 'ranfunc'
215
215
216 and an example of ``# all-random``::
216 and an example of ``# all-random``::
217
217
218 def random_all():
218 def random_all():
219 """A function where we ignore the output of ALL examples.
219 """A function where we ignore the output of ALL examples.
220
220
221 Examples:
221 Examples:
222
222
223 # all-random
223 # all-random
224
224
225 This mark tells the testing machinery that all subsequent examples
225 This mark tells the testing machinery that all subsequent examples
226 should be treated as random (ignoring their output). They are still
226 should be treated as random (ignoring their output). They are still
227 executed, so if a they raise an error, it will be detected as such,
227 executed, so if a they raise an error, it will be detected as such,
228 but their output is completely ignored.
228 but their output is completely ignored.
229
229
230 >>> 1+3
230 >>> 1+3
231 junk goes here...
231 junk goes here...
232
232
233 >>> 1+3
233 >>> 1+3
234 klasdfj;
234 klasdfj;
235
235
236 In [8]: print 'hello'
236 In [8]: print 'hello'
237 world # random
237 world # random
238
238
239 In [9]: iprand()
239 In [9]: iprand()
240 Out[9]: 'iprand'
240 Out[9]: 'iprand'
241 """
241 """
242 return 'iprand'
242 return 'iprand'
243
243
244
244
245 When writing docstrings, you can use the ``@skip_doctest`` decorator to
245 When writing docstrings, you can use the ``@skip_doctest`` decorator to
246 indicate that a docstring should *not* be treated as a doctest at all. The
246 indicate that a docstring should *not* be treated as a doctest at all. The
247 difference betwee ``# all-random`` and ``@skip_doctest`` is that the former
247 difference between ``# all-random`` and ``@skip_doctest`` is that the former
248 executes the example but ignores output, while the latter doesn't execute any
248 executes the example but ignores output, while the latter doesn't execute any
249 code. ``@skip_doctest`` should be used for docstrings whose examples are
249 code. ``@skip_doctest`` should be used for docstrings whose examples are
250 purely informational.
250 purely informational.
251
251
252 If a given docstring fails under certain conditions but otherwise is a good
252 If a given docstring fails under certain conditions but otherwise is a good
253 doctest, you can use code like the following, that relies on the 'null'
253 doctest, you can use code like the following, that relies on the 'null'
254 decorator to leave the docstring intact where it works as a test::
254 decorator to leave the docstring intact where it works as a test::
255
255
256 # The docstring for full_path doctests differently on win32 (different path
256 # The docstring for full_path doctests differently on win32 (different path
257 # separator) so just skip the doctest there, and use a null decorator
257 # separator) so just skip the doctest there, and use a null decorator
258 # elsewhere:
258 # elsewhere:
259
259
260 doctest_deco = dec.skip_doctest if sys.platform == 'win32' else dec.null_deco
260 doctest_deco = dec.skip_doctest if sys.platform == 'win32' else dec.null_deco
261
261
262 @doctest_deco
262 @doctest_deco
263 def full_path(startPath,files):
263 def full_path(startPath,files):
264 """Make full paths for all the listed files, based on startPath..."""
264 """Make full paths for all the listed files, based on startPath..."""
265
265
266 # function body follows...
266 # function body follows...
267
267
268 With our nose plugin that understands IPython syntax, an extremely effective
268 With our nose plugin that understands IPython syntax, an extremely effective
269 way to write tests is to simply copy and paste an interactive session into a
269 way to write tests is to simply copy and paste an interactive session into a
270 docstring. You can writing this type of test, where your docstring is meant
270 docstring. You can writing this type of test, where your docstring is meant
271 *only* as a test, by prefixing the function name with ``doctest_`` and leaving
271 *only* as a test, by prefixing the function name with ``doctest_`` and leaving
272 its body *absolutely empty* other than the docstring. In
272 its body *absolutely empty* other than the docstring. In
273 :mod:`IPython.core.tests.test_magic` you can find several examples of this, but
273 :mod:`IPython.core.tests.test_magic` you can find several examples of this, but
274 for completeness sake, your code should look like this (a simple case)::
274 for completeness sake, your code should look like this (a simple case)::
275
275
276 def doctest_time():
276 def doctest_time():
277 """
277 """
278 In [10]: %time None
278 In [10]: %time None
279 CPU times: user 0.00 s, sys: 0.00 s, total: 0.00 s
279 CPU times: user 0.00 s, sys: 0.00 s, total: 0.00 s
280 Wall time: 0.00 s
280 Wall time: 0.00 s
281 """
281 """
282
282
283 This function is only analyzed for its docstring but it is not considered a
283 This function is only analyzed for its docstring but it is not considered a
284 separate test, which is why its body should be empty.
284 separate test, which is why its body should be empty.
285
285
286
286
287 Parametric tests done right
287 Parametric tests done right
288 ---------------------------
288 ---------------------------
289
289
290 If you need to run multiple tests inside the same standalone function or method
290 If you need to run multiple tests inside the same standalone function or method
291 of a :class:`unittest.TestCase` subclass, IPython provides the ``parametric``
291 of a :class:`unittest.TestCase` subclass, IPython provides the ``parametric``
292 decorator for this purpose. This is superior to how test generators work in
292 decorator for this purpose. This is superior to how test generators work in
293 nose, because IPython's keeps intact your stack, which makes debugging vastly
293 nose, because IPython's keeps intact your stack, which makes debugging vastly
294 easier. For example, these are some parametric tests both in class form and as
294 easier. For example, these are some parametric tests both in class form and as
295 a standalone function (choose in each situation the style that best fits the
295 a standalone function (choose in each situation the style that best fits the
296 problem at hand, since both work)::
296 problem at hand, since both work)::
297
297
298 from IPython.testing import decorators as dec
298 from IPython.testing import decorators as dec
299
299
300 def is_smaller(i,j):
300 def is_smaller(i,j):
301 assert i<j,"%s !< %s" % (i,j)
301 assert i<j,"%s !< %s" % (i,j)
302
302
303 class Tester(ParametricTestCase):
303 class Tester(ParametricTestCase):
304
304
305 def test_parametric(self):
305 def test_parametric(self):
306 yield is_smaller(3, 4)
306 yield is_smaller(3, 4)
307 x, y = 1, 2
307 x, y = 1, 2
308 yield is_smaller(x, y)
308 yield is_smaller(x, y)
309
309
310 @dec.parametric
310 @dec.parametric
311 def test_par_standalone():
311 def test_par_standalone():
312 yield is_smaller(3, 4)
312 yield is_smaller(3, 4)
313 x, y = 1, 2
313 x, y = 1, 2
314 yield is_smaller(x, y)
314 yield is_smaller(x, y)
315
315
316
316
317 Writing tests for Twisted-using code
317 Writing tests for Twisted-using code
318 ------------------------------------
318 ------------------------------------
319
319
320 Tests of Twisted [Twisted]_ using code should be written by subclassing the
320 Tests of Twisted [Twisted]_ using code should be written by subclassing the
321 ``TestCase`` class that comes with ``twisted.trial.unittest``. Furthermore, all
321 ``TestCase`` class that comes with ``twisted.trial.unittest``. Furthermore, all
322 :class:`Deferred` instances that are created in the test must be properly
322 :class:`Deferred` instances that are created in the test must be properly
323 chained and the final one *must* be the return value of the test method.
323 chained and the final one *must* be the return value of the test method.
324
324
325 .. note::
325 .. note::
326
326
327 The best place to see how to use the testing tools, are the tests for these
327 The best place to see how to use the testing tools, are the tests for these
328 tools themselves, which live in :mod:`IPython.testing.tests`.
328 tools themselves, which live in :mod:`IPython.testing.tests`.
329
329
330
330
331 Design requirements
331 Design requirements
332 ===================
332 ===================
333
333
334 This section is a set of notes on the key points of the IPython testing needs,
334 This section is a set of notes on the key points of the IPython testing needs,
335 that were used when writing the system and should be kept for reference as it
335 that were used when writing the system and should be kept for reference as it
336 eveolves.
336 eveolves.
337
337
338 Testing IPython in full requires modifications to the default behavior of nose
338 Testing IPython in full requires modifications to the default behavior of nose
339 and doctest, because the IPython prompt is not recognized to determine Python
339 and doctest, because the IPython prompt is not recognized to determine Python
340 input, and because IPython admits user input that is not valid Python (things
340 input, and because IPython admits user input that is not valid Python (things
341 like ``%magics`` and ``!system commands``.
341 like ``%magics`` and ``!system commands``.
342
342
343 We basically need to be able to test the following types of code:
343 We basically need to be able to test the following types of code:
344
344
345 1. Pure Python files containing normal tests. These are not a problem, since
345 1. Pure Python files containing normal tests. These are not a problem, since
346 Nose will pick them up as long as they conform to the (flexible) conventions
346 Nose will pick them up as long as they conform to the (flexible) conventions
347 used by nose to recognize tests.
347 used by nose to recognize tests.
348
348
349 2. Python files containing doctests. Here, we have two possibilities:
349 2. Python files containing doctests. Here, we have two possibilities:
350 - The prompts are the usual ``>>>`` and the input is pure Python.
350 - The prompts are the usual ``>>>`` and the input is pure Python.
351 - The prompts are of the form ``In [1]:`` and the input can contain extended
351 - The prompts are of the form ``In [1]:`` and the input can contain extended
352 IPython expressions.
352 IPython expressions.
353
353
354 In the first case, Nose will recognize the doctests as long as it is called
354 In the first case, Nose will recognize the doctests as long as it is called
355 with the ``--with-doctest`` flag. But the second case will likely require
355 with the ``--with-doctest`` flag. But the second case will likely require
356 modifications or the writing of a new doctest plugin for Nose that is
356 modifications or the writing of a new doctest plugin for Nose that is
357 IPython-aware.
357 IPython-aware.
358
358
359 3. ReStructuredText files that contain code blocks. For this type of file, we
359 3. ReStructuredText files that contain code blocks. For this type of file, we
360 have three distinct possibilities for the code blocks:
360 have three distinct possibilities for the code blocks:
361 - They use ``>>>`` prompts.
361 - They use ``>>>`` prompts.
362 - They use ``In [1]:`` prompts.
362 - They use ``In [1]:`` prompts.
363 - They are standalone blocks of pure Python code without any prompts.
363 - They are standalone blocks of pure Python code without any prompts.
364
364
365 The first two cases are similar to the situation #2 above, except that in
365 The first two cases are similar to the situation #2 above, except that in
366 this case the doctests must be extracted from input code blocks using
366 this case the doctests must be extracted from input code blocks using
367 docutils instead of from the Python docstrings.
367 docutils instead of from the Python docstrings.
368
368
369 In the third case, we must have a convention for distinguishing code blocks
369 In the third case, we must have a convention for distinguishing code blocks
370 that are meant for execution from others that may be snippets of shell code
370 that are meant for execution from others that may be snippets of shell code
371 or other examples not meant to be run. One possibility is to assume that
371 or other examples not meant to be run. One possibility is to assume that
372 all indented code blocks are meant for execution, but to have a special
372 all indented code blocks are meant for execution, but to have a special
373 docutils directive for input that should not be executed.
373 docutils directive for input that should not be executed.
374
374
375 For those code blocks that we will execute, the convention used will simply
375 For those code blocks that we will execute, the convention used will simply
376 be that they get called and are considered successful if they run to
376 be that they get called and are considered successful if they run to
377 completion without raising errors. This is similar to what Nose does for
377 completion without raising errors. This is similar to what Nose does for
378 standalone test functions, and by putting asserts or other forms of
378 standalone test functions, and by putting asserts or other forms of
379 exception-raising statements it becomes possible to have literate examples
379 exception-raising statements it becomes possible to have literate examples
380 that double as lightweight tests.
380 that double as lightweight tests.
381
381
382 4. Extension modules with doctests in function and method docstrings.
382 4. Extension modules with doctests in function and method docstrings.
383 Currently Nose simply can't find these docstrings correctly, because the
383 Currently Nose simply can't find these docstrings correctly, because the
384 underlying doctest DocTestFinder object fails there. Similarly to #2 above,
384 underlying doctest DocTestFinder object fails there. Similarly to #2 above,
385 the docstrings could have either pure python or IPython prompts.
385 the docstrings could have either pure python or IPython prompts.
386
386
387 Of these, only 3-c (reST with standalone code blocks) is not implemented at
387 Of these, only 3-c (reST with standalone code blocks) is not implemented at
388 this point.
388 this point.
@@ -1,642 +1,635 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """Sphinx directive to support embedded IPython code.
2 """Sphinx directive to support embedded IPython code.
3
3
4 This directive allows pasting of entire interactive IPython sessions, prompts
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
5 and all, and their code will actually get re-executed at doc build time, with
6 all prompts renumbered sequentially.
6 all prompts renumbered sequentially.
7
7
8 To enable this directive, simply list it in your Sphinx ``conf.py`` file
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
9 (making sure the directory where you placed it is visible to sphinx, as is
10 needed for all Sphinx directives).
10 needed for all Sphinx directives).
11
11
12 By default this directive assumes that your prompts are unchanged IPython ones,
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
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
14 config file will configure this directive for the following input/output
15 prompts ``Yade [1]:`` and ``-> [1]:``::
15 prompts ``Yade [1]:`` and ``-> [1]:``::
16
16
17 import ipython_directive as id
17 import ipython_directive as id
18 id.rgxin =re.compile(r'(?:In |Yade )\[(\d+)\]:\s?(.*)\s*')
18 id.rgxin =re.compile(r'(?:In |Yade )\[(\d+)\]:\s?(.*)\s*')
19 id.rgxout=re.compile(r'(?:Out| -> )\[(\d+)\]:\s?(.*)\s*')
19 id.rgxout=re.compile(r'(?:Out| -> )\[(\d+)\]:\s?(.*)\s*')
20 id.fmtin ='Yade [%d]:'
20 id.fmtin ='Yade [%d]:'
21 id.fmtout=' -> [%d]:'
21 id.fmtout=' -> [%d]:'
22
22
23 from IPython import Config
23 from IPython import Config
24 id.CONFIG = Config(
24 id.CONFIG = Config(
25 prompt_in1="Yade [\#]:",
25 prompt_in1="Yade [\#]:",
26 prompt_in2=" .\D..",
26 prompt_in2=" .\D..",
27 prompt_out=" -> [\#]:"
27 prompt_out=" -> [\#]:"
28 )
28 )
29 id.reconfig_shell()
29 id.reconfig_shell()
30
30
31 import ipython_console_highlighting as ich
31 import ipython_console_highlighting as ich
32 ich.IPythonConsoleLexer.input_prompt=
32 ich.IPythonConsoleLexer.input_prompt=
33 re.compile("(Yade \[[0-9]+\]: )|( \.\.\.+:)")
33 re.compile("(Yade \[[0-9]+\]: )|( \.\.\.+:)")
34 ich.IPythonConsoleLexer.output_prompt=
34 ich.IPythonConsoleLexer.output_prompt=
35 re.compile("(( -> )|(Out)\[[0-9]+\]: )|( \.\.\.+:)")
35 re.compile("(( -> )|(Out)\[[0-9]+\]: )|( \.\.\.+:)")
36 ich.IPythonConsoleLexer.continue_prompt=re.compile(" \.\.\.+:")
36 ich.IPythonConsoleLexer.continue_prompt=re.compile(" \.\.\.+:")
37
37
38
38
39 ToDo
39 ToDo
40 ----
40 ----
41
41
42 - Turn the ad-hoc test() function into a real test suite.
42 - Turn the ad-hoc test() function into a real test suite.
43 - Break up ipython-specific functionality from matplotlib stuff into better
43 - Break up ipython-specific functionality from matplotlib stuff into better
44 separated code.
44 separated code.
45 - Make sure %bookmarks used internally are removed on exit.
45 - Make sure %bookmarks used internally are removed on exit.
46
46
47
47
48 Authors
48 Authors
49 -------
49 -------
50
50
51 - John D Hunter: orignal author.
51 - John D Hunter: orignal author.
52 - Fernando Perez: refactoring, documentation, cleanups, port to 0.11.
52 - Fernando Perez: refactoring, documentation, cleanups, port to 0.11.
53 - VΓ‘clavΕ milauer <eudoxos-AT-arcig.cz>: Prompt generalizations.
53 - VΓ‘clavΕ milauer <eudoxos-AT-arcig.cz>: Prompt generalizations.
54 """
54 """
55
55
56 #-----------------------------------------------------------------------------
56 #-----------------------------------------------------------------------------
57 # Imports
57 # Imports
58 #-----------------------------------------------------------------------------
58 #-----------------------------------------------------------------------------
59
59
60 # Stdlib
60 # Stdlib
61 import cStringIO
61 import cStringIO
62 import imp
63 import os
62 import os
64 import re
63 import re
65 import shutil
66 import sys
64 import sys
67 import warnings
68
65
69 # To keep compatibility with various python versions
66 # To keep compatibility with various python versions
70 try:
67 try:
71 from hashlib import md5
68 from hashlib import md5
72 except ImportError:
69 except ImportError:
73 from md5 import md5
70 from md5 import md5
74
71
75 # Third-party
72 # Third-party
76 import matplotlib
73 import matplotlib
77 import sphinx
74 import sphinx
78 from docutils.parsers.rst import directives
75 from docutils.parsers.rst import directives
79
76
80 matplotlib.use('Agg')
77 matplotlib.use('Agg')
81
78
82 # Our own
79 # Our own
83 from IPython import Config, IPythonApp
80 from IPython import Config, InteractiveShell
84 from IPython.utils.io import Term, Tee
81 from IPython.utils.io import Term
85
82
86 #-----------------------------------------------------------------------------
83 #-----------------------------------------------------------------------------
87 # Globals
84 # Globals
88 #-----------------------------------------------------------------------------
85 #-----------------------------------------------------------------------------
89
86
90 sphinx_version = sphinx.__version__.split(".")
87 sphinx_version = sphinx.__version__.split(".")
91 # The split is necessary for sphinx beta versions where the string is
88 # The split is necessary for sphinx beta versions where the string is
92 # '6b1'
89 # '6b1'
93 sphinx_version = tuple([int(re.split('[a-z]', x)[0])
90 sphinx_version = tuple([int(re.split('[a-z]', x)[0])
94 for x in sphinx_version[:2]])
91 for x in sphinx_version[:2]])
95
92
96 COMMENT, INPUT, OUTPUT = range(3)
93 COMMENT, INPUT, OUTPUT = range(3)
97 CONFIG = Config()
94 CONFIG = Config()
98 rgxin = re.compile('In \[(\d+)\]:\s?(.*)\s*')
95 rgxin = re.compile('In \[(\d+)\]:\s?(.*)\s*')
99 rgxout = re.compile('Out\[(\d+)\]:\s?(.*)\s*')
96 rgxout = re.compile('Out\[(\d+)\]:\s?(.*)\s*')
100 fmtin = 'In [%d]:'
97 fmtin = 'In [%d]:'
101 fmtout = 'Out[%d]:'
98 fmtout = 'Out[%d]:'
102
99
103 #-----------------------------------------------------------------------------
100 #-----------------------------------------------------------------------------
104 # Functions and class declarations
101 # Functions and class declarations
105 #-----------------------------------------------------------------------------
102 #-----------------------------------------------------------------------------
106 def block_parser(part):
103 def block_parser(part):
107 """
104 """
108 part is a string of ipython text, comprised of at most one
105 part is a string of ipython text, comprised of at most one
109 input, one ouput, comments, and blank lines. The block parser
106 input, one ouput, comments, and blank lines. The block parser
110 parses the text into a list of::
107 parses the text into a list of::
111
108
112 blocks = [ (TOKEN0, data0), (TOKEN1, data1), ...]
109 blocks = [ (TOKEN0, data0), (TOKEN1, data1), ...]
113
110
114 where TOKEN is one of [COMMENT | INPUT | OUTPUT ] and
111 where TOKEN is one of [COMMENT | INPUT | OUTPUT ] and
115 data is, depending on the type of token::
112 data is, depending on the type of token::
116
113
117 COMMENT : the comment string
114 COMMENT : the comment string
118
115
119 INPUT: the (DECORATOR, INPUT_LINE, REST) where
116 INPUT: the (DECORATOR, INPUT_LINE, REST) where
120 DECORATOR: the input decorator (or None)
117 DECORATOR: the input decorator (or None)
121 INPUT_LINE: the input as string (possibly multi-line)
118 INPUT_LINE: the input as string (possibly multi-line)
122 REST : any stdout generated by the input line (not OUTPUT)
119 REST : any stdout generated by the input line (not OUTPUT)
123
120
124
121
125 OUTPUT: the output string, possibly multi-line
122 OUTPUT: the output string, possibly multi-line
126 """
123 """
127
124
128 block = []
125 block = []
129 lines = part.split('\n')
126 lines = part.split('\n')
130 N = len(lines)
127 N = len(lines)
131 i = 0
128 i = 0
132 decorator = None
129 decorator = None
133 while 1:
130 while 1:
134
131
135 if i==N:
132 if i==N:
136 # nothing left to parse -- the last line
133 # nothing left to parse -- the last line
137 break
134 break
138
135
139 line = lines[i]
136 line = lines[i]
140 i += 1
137 i += 1
141 line_stripped = line.strip()
138 line_stripped = line.strip()
142 if line_stripped.startswith('#'):
139 if line_stripped.startswith('#'):
143 block.append((COMMENT, line))
140 block.append((COMMENT, line))
144 continue
141 continue
145
142
146 if line_stripped.startswith('@'):
143 if line_stripped.startswith('@'):
147 # we're assuming at most one decorator -- may need to
144 # we're assuming at most one decorator -- may need to
148 # rethink
145 # rethink
149 decorator = line_stripped
146 decorator = line_stripped
150 continue
147 continue
151
148
152 # does this look like an input line?
149 # does this look like an input line?
153 matchin = rgxin.match(line)
150 matchin = rgxin.match(line)
154 if matchin:
151 if matchin:
155 lineno, inputline = int(matchin.group(1)), matchin.group(2)
152 lineno, inputline = int(matchin.group(1)), matchin.group(2)
156
153
157 # the ....: continuation string
154 # the ....: continuation string
158 continuation = ' %s:'%''.join(['.']*(len(str(lineno))+2))
155 continuation = ' %s:'%''.join(['.']*(len(str(lineno))+2))
159 Nc = len(continuation)
156 Nc = len(continuation)
160 # input lines can continue on for more than one line, if
157 # input lines can continue on for more than one line, if
161 # we have a '\' line continuation char or a function call
158 # we have a '\' line continuation char or a function call
162 # echo line 'print'. The input line can only be
159 # echo line 'print'. The input line can only be
163 # terminated by the end of the block or an output line, so
160 # 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
161 # we parse out the rest of the input line if it is
165 # multiline as well as any echo text
162 # multiline as well as any echo text
166
163
167 rest = []
164 rest = []
168 while i<N:
165 while i<N:
169
166
170 # look ahead; if the next line is blank, or a comment, or
167 # look ahead; if the next line is blank, or a comment, or
171 # an output line, we're done
168 # an output line, we're done
172
169
173 nextline = lines[i]
170 nextline = lines[i]
174 matchout = rgxout.match(nextline)
171 matchout = rgxout.match(nextline)
175 #print "nextline=%s, continuation=%s, starts=%s"%(nextline, continuation, nextline.startswith(continuation))
172 #print "nextline=%s, continuation=%s, starts=%s"%(nextline, continuation, nextline.startswith(continuation))
176 if matchout or nextline.startswith('#'):
173 if matchout or nextline.startswith('#'):
177 break
174 break
178 elif nextline.startswith(continuation):
175 elif nextline.startswith(continuation):
179 inputline += '\n' + nextline[Nc:]
176 inputline += '\n' + nextline[Nc:]
180 else:
177 else:
181 rest.append(nextline)
178 rest.append(nextline)
182 i+= 1
179 i+= 1
183
180
184 block.append((INPUT, (decorator, inputline, '\n'.join(rest))))
181 block.append((INPUT, (decorator, inputline, '\n'.join(rest))))
185 continue
182 continue
186
183
187 # if it looks like an output line grab all the text to the end
184 # if it looks like an output line grab all the text to the end
188 # of the block
185 # of the block
189 matchout = rgxout.match(line)
186 matchout = rgxout.match(line)
190 if matchout:
187 if matchout:
191 lineno, output = int(matchout.group(1)), matchout.group(2)
188 lineno, output = int(matchout.group(1)), matchout.group(2)
192 if i<N-1:
189 if i<N-1:
193 output = '\n'.join([output] + lines[i:])
190 output = '\n'.join([output] + lines[i:])
194
191
195 block.append((OUTPUT, output))
192 block.append((OUTPUT, output))
196 break
193 break
197
194
198 return block
195 return block
199
196
200
197
201 class EmbeddedSphinxShell(object):
198 class EmbeddedSphinxShell(object):
202 """An embedded IPython instance to run inside Sphinx"""
199 """An embedded IPython instance to run inside Sphinx"""
203
200
204 def __init__(self):
201 def __init__(self):
205
202
206 self.cout = cStringIO.StringIO()
203 self.cout = cStringIO.StringIO()
207 Term.cout = self.cout
204 Term.cout = self.cout
208 Term.cerr = self.cout
205 Term.cerr = self.cout
209
206
210 # For debugging, so we can see normal output, use this:
207 # For debugging, so we can see normal output, use this:
211 # from IPython.utils.io import Tee
208 # from IPython.utils.io import Tee
212 #Term.cout = Tee(self.cout, channel='stdout') # dbg
209 #Term.cout = Tee(self.cout, channel='stdout') # dbg
213 #Term.cerr = Tee(self.cout, channel='stderr') # dbg
210 #Term.cerr = Tee(self.cout, channel='stderr') # dbg
214
211
215 # Create config object for IPython
212 # Create config object for IPython
216 config = Config()
213 config = Config()
217 config.Global.display_banner = False
214 config.Global.display_banner = False
218 config.Global.exec_lines = ['import numpy as np',
215 config.Global.exec_lines = ['import numpy as np',
219 'from pylab import *'
216 'from pylab import *'
220 ]
217 ]
221 config.InteractiveShell.autocall = False
218 config.InteractiveShell.autocall = False
222 config.InteractiveShell.autoindent = False
219 config.InteractiveShell.autoindent = False
223 config.InteractiveShell.colors = 'NoColor'
220 config.InteractiveShell.colors = 'NoColor'
224
221
225 # Merge global config which can be used to override.
226 config._merge(CONFIG)
227
228 # Create and initialize ipython, but don't start its mainloop
222 # Create and initialize ipython, but don't start its mainloop
229 IP = IPythonApp(override_config=config)
223 IP = InteractiveShell(parent=None, config=config)
230 IP.initialize()
231
224
232 # Store a few parts of IPython we'll need.
225 # Store a few parts of IPython we'll need.
233 self.IP = IP.shell
226 self.IP = IP
234 self.user_ns = self.IP.user_ns
227 self.user_ns = self.IP.user_ns
235 self.user_global_ns = self.IP.user_global_ns
228 self.user_global_ns = self.IP.user_global_ns
236
229
237 self.input = ''
230 self.input = ''
238 self.output = ''
231 self.output = ''
239
232
240 self.is_verbatim = False
233 self.is_verbatim = False
241 self.is_doctest = False
234 self.is_doctest = False
242 self.is_suppress = False
235 self.is_suppress = False
243
236
244 # on the first call to the savefig decorator, we'll import
237 # on the first call to the savefig decorator, we'll import
245 # pyplot as plt so we can make a call to the plt.gcf().savefig
238 # pyplot as plt so we can make a call to the plt.gcf().savefig
246 self._pyplot_imported = False
239 self._pyplot_imported = False
247
240
248 # we need bookmark the current dir first so we can save
241 # we need bookmark the current dir first so we can save
249 # relative to it
242 # relative to it
250 self.process_input_line('bookmark ipy_basedir')
243 self.process_input_line('bookmark ipy_basedir')
251 self.cout.seek(0)
244 self.cout.seek(0)
252 self.cout.truncate(0)
245 self.cout.truncate(0)
253
246
254 def process_input_line(self, line):
247 def process_input_line(self, line):
255 """process the input, capturing stdout"""
248 """process the input, capturing stdout"""
256 #print "input='%s'"%self.input
249 #print "input='%s'"%self.input
257 stdout = sys.stdout
250 stdout = sys.stdout
258 try:
251 try:
259 sys.stdout = self.cout
252 sys.stdout = self.cout
260 self.IP.push_line(line)
253 self.IP.push_line(line)
261 finally:
254 finally:
262 sys.stdout = stdout
255 sys.stdout = stdout
263
256
264 # Callbacks for each type of token
257 # Callbacks for each type of token
265 def process_input(self, data, input_prompt, lineno):
258 def process_input(self, data, input_prompt, lineno):
266 """Process data block for INPUT token."""
259 """Process data block for INPUT token."""
267 decorator, input, rest = data
260 decorator, input, rest = data
268 image_file = None
261 image_file = None
269 #print 'INPUT:', data # dbg
262 #print 'INPUT:', data # dbg
270 is_verbatim = decorator=='@verbatim' or self.is_verbatim
263 is_verbatim = decorator=='@verbatim' or self.is_verbatim
271 is_doctest = decorator=='@doctest' or self.is_doctest
264 is_doctest = decorator=='@doctest' or self.is_doctest
272 is_suppress = decorator=='@suppress' or self.is_suppress
265 is_suppress = decorator=='@suppress' or self.is_suppress
273 is_savefig = decorator is not None and \
266 is_savefig = decorator is not None and \
274 decorator.startswith('@savefig')
267 decorator.startswith('@savefig')
275
268
276 input_lines = input.split('\n')
269 input_lines = input.split('\n')
277
270
278 continuation = ' %s:'%''.join(['.']*(len(str(lineno))+2))
271 continuation = ' %s:'%''.join(['.']*(len(str(lineno))+2))
279 Nc = len(continuation)
272 Nc = len(continuation)
280
273
281 if is_savefig:
274 if is_savefig:
282 saveargs = decorator.split(' ')
275 saveargs = decorator.split(' ')
283 filename = saveargs[1]
276 filename = saveargs[1]
284 outfile = os.path.join('_static/%s'%filename)
277 outfile = os.path.join('_static/%s'%filename)
285 # build out an image directive like
278 # build out an image directive like
286 # .. image:: somefile.png
279 # .. image:: somefile.png
287 # :width 4in
280 # :width 4in
288 #
281 #
289 # from an input like
282 # from an input like
290 # savefig somefile.png width=4in
283 # savefig somefile.png width=4in
291 imagerows = ['.. image:: %s'%outfile]
284 imagerows = ['.. image:: %s'%outfile]
292
285
293 for kwarg in saveargs[2:]:
286 for kwarg in saveargs[2:]:
294 arg, val = kwarg.split('=')
287 arg, val = kwarg.split('=')
295 arg = arg.strip()
288 arg = arg.strip()
296 val = val.strip()
289 val = val.strip()
297 imagerows.append(' :%s: %s'%(arg, val))
290 imagerows.append(' :%s: %s'%(arg, val))
298
291
299 image_file = outfile
292 image_file = outfile
300 image_directive = '\n'.join(imagerows)
293 image_directive = '\n'.join(imagerows)
301
294
302 # TODO: can we get "rest" from ipython
295 # TODO: can we get "rest" from ipython
303 #self.process_input_line('\n'.join(input_lines))
296 #self.process_input_line('\n'.join(input_lines))
304
297
305 ret = []
298 ret = []
306 is_semicolon = False
299 is_semicolon = False
307
300
308 for i, line in enumerate(input_lines):
301 for i, line in enumerate(input_lines):
309 if line.endswith(';'):
302 if line.endswith(';'):
310 is_semicolon = True
303 is_semicolon = True
311
304
312 if i==0:
305 if i==0:
313 # process the first input line
306 # process the first input line
314 if is_verbatim:
307 if is_verbatim:
315 self.process_input_line('')
308 self.process_input_line('')
316 else:
309 else:
317 # only submit the line in non-verbatim mode
310 # only submit the line in non-verbatim mode
318 self.process_input_line(line)
311 self.process_input_line(line)
319 formatted_line = '%s %s'%(input_prompt, line)
312 formatted_line = '%s %s'%(input_prompt, line)
320 else:
313 else:
321 # process a continuation line
314 # process a continuation line
322 if not is_verbatim:
315 if not is_verbatim:
323 self.process_input_line(line)
316 self.process_input_line(line)
324
317
325 formatted_line = '%s %s'%(continuation, line)
318 formatted_line = '%s %s'%(continuation, line)
326
319
327 if not is_suppress:
320 if not is_suppress:
328 ret.append(formatted_line)
321 ret.append(formatted_line)
329
322
330 if not is_suppress:
323 if not is_suppress:
331 if len(rest.strip()):
324 if len(rest.strip()):
332 if is_verbatim:
325 if is_verbatim:
333 # the "rest" is the standard output of the
326 # the "rest" is the standard output of the
334 # input, which needs to be added in
327 # input, which needs to be added in
335 # verbatim mode
328 # verbatim mode
336 ret.append(rest)
329 ret.append(rest)
337
330
338 self.cout.seek(0)
331 self.cout.seek(0)
339 output = self.cout.read()
332 output = self.cout.read()
340 if not is_suppress and not is_semicolon:
333 if not is_suppress and not is_semicolon:
341 ret.append(output)
334 ret.append(output)
342
335
343 self.cout.truncate(0)
336 self.cout.truncate(0)
344 return ret, input_lines, output, is_doctest, image_file
337 return ret, input_lines, output, is_doctest, image_file
345 #print 'OUTPUT', output # dbg
338 #print 'OUTPUT', output # dbg
346
339
347 def process_output(self, data, output_prompt,
340 def process_output(self, data, output_prompt,
348 input_lines, output, is_doctest, image_file):
341 input_lines, output, is_doctest, image_file):
349 """Process data block for OUTPUT token."""
342 """Process data block for OUTPUT token."""
350 if is_doctest:
343 if is_doctest:
351 submitted = data.strip()
344 submitted = data.strip()
352 found = output
345 found = output
353 if found is not None:
346 if found is not None:
354 found = found.strip()
347 found = found.strip()
355
348
356 # XXX - fperez: in 0.11, 'output' never comes with the prompt
349 # XXX - fperez: in 0.11, 'output' never comes with the prompt
357 # in it, just the actual output text. So I think all this code
350 # in it, just the actual output text. So I think all this code
358 # can be nuked...
351 # can be nuked...
359 ## ind = found.find(output_prompt)
352 ## ind = found.find(output_prompt)
360 ## if ind<0:
353 ## if ind<0:
361 ## e='output prompt="%s" does not match out line=%s' % \
354 ## e='output prompt="%s" does not match out line=%s' % \
362 ## (output_prompt, found)
355 ## (output_prompt, found)
363 ## raise RuntimeError(e)
356 ## raise RuntimeError(e)
364 ## found = found[len(output_prompt):].strip()
357 ## found = found[len(output_prompt):].strip()
365
358
366 if found!=submitted:
359 if found!=submitted:
367 e = ('doctest failure for input_lines="%s" with '
360 e = ('doctest failure for input_lines="%s" with '
368 'found_output="%s" and submitted output="%s"' %
361 'found_output="%s" and submitted output="%s"' %
369 (input_lines, found, submitted) )
362 (input_lines, found, submitted) )
370 raise RuntimeError(e)
363 raise RuntimeError(e)
371 #print 'doctest PASSED for input_lines="%s" with found_output="%s" and submitted output="%s"'%(input_lines, found, submitted)
364 #print 'doctest PASSED for input_lines="%s" with found_output="%s" and submitted output="%s"'%(input_lines, found, submitted)
372
365
373 def process_comment(self, data):
366 def process_comment(self, data):
374 """Process data block for COMMENT token."""
367 """Process data block for COMMENT token."""
375 if not self.is_suppress:
368 if not self.is_suppress:
376 return [data]
369 return [data]
377
370
378 def process_block(self, block):
371 def process_block(self, block):
379 """
372 """
380 process block from the block_parser and return a list of processed lines
373 process block from the block_parser and return a list of processed lines
381 """
374 """
382
375
383 ret = []
376 ret = []
384 output = None
377 output = None
385 input_lines = None
378 input_lines = None
386
379
387 m = rgxin.match(str(self.IP.outputcache.prompt1).strip())
380 m = rgxin.match(str(self.IP.outputcache.prompt1).strip())
388 lineno = int(m.group(1))
381 lineno = int(m.group(1))
389
382
390 input_prompt = fmtin%lineno
383 input_prompt = fmtin%lineno
391 output_prompt = fmtout%lineno
384 output_prompt = fmtout%lineno
392 image_file = None
385 image_file = None
393 image_directive = None
386 image_directive = None
394 # XXX - This needs a second refactor. There's too much state being
387 # XXX - This needs a second refactor. There's too much state being
395 # held globally, which makes for a very awkward interface and large,
388 # held globally, which makes for a very awkward interface and large,
396 # hard to test functions. I've already broken this up at least into
389 # hard to test functions. I've already broken this up at least into
397 # three separate processors to isolate the logic better, but this only
390 # three separate processors to isolate the logic better, but this only
398 # serves to highlight the coupling. Next we need to clean it up...
391 # serves to highlight the coupling. Next we need to clean it up...
399 for token, data in block:
392 for token, data in block:
400 if token==COMMENT:
393 if token==COMMENT:
401 out_data = self.process_comment(data)
394 out_data = self.process_comment(data)
402 elif token==INPUT:
395 elif token==INPUT:
403 out_data, input_lines, output, is_doctest, image_file= \
396 out_data, input_lines, output, is_doctest, image_file= \
404 self.process_input(data, input_prompt, lineno)
397 self.process_input(data, input_prompt, lineno)
405 elif token==OUTPUT:
398 elif token==OUTPUT:
406 out_data = \
399 out_data = \
407 self.process_output(data, output_prompt,
400 self.process_output(data, output_prompt,
408 input_lines, output, is_doctest,
401 input_lines, output, is_doctest,
409 image_file)
402 image_file)
410 if out_data:
403 if out_data:
411 ret.extend(out_data)
404 ret.extend(out_data)
412
405
413 if image_file is not None:
406 if image_file is not None:
414 self.ensure_pyplot()
407 self.ensure_pyplot()
415 command = 'plt.gcf().savefig("%s")'%image_file
408 command = 'plt.gcf().savefig("%s")'%image_file
416 print 'SAVEFIG', command # dbg
409 print 'SAVEFIG', command # dbg
417 self.process_input_line('bookmark ipy_thisdir')
410 self.process_input_line('bookmark ipy_thisdir')
418 self.process_input_line('cd -b ipy_basedir')
411 self.process_input_line('cd -b ipy_basedir')
419 self.process_input_line(command)
412 self.process_input_line(command)
420 self.process_input_line('cd -b ipy_thisdir')
413 self.process_input_line('cd -b ipy_thisdir')
421 self.cout.seek(0)
414 self.cout.seek(0)
422 self.cout.truncate(0)
415 self.cout.truncate(0)
423 return ret, image_directive
416 return ret, image_directive
424
417
425 def ensure_pyplot(self):
418 def ensure_pyplot(self):
426 if self._pyplot_imported:
419 if self._pyplot_imported:
427 return
420 return
428 self.process_input_line('import matplotlib.pyplot as plt')
421 self.process_input_line('import matplotlib.pyplot as plt')
429
422
430 # A global instance used below. XXX: not sure why this can't be created inside
423 # A global instance used below. XXX: not sure why this can't be created inside
431 # ipython_directive itself.
424 # ipython_directive itself.
432 shell = EmbeddedSphinxShell()
425 shell = EmbeddedSphinxShell()
433
426
434 def reconfig_shell():
427 def reconfig_shell():
435 """Called after setting module-level variables to re-instantiate
428 """Called after setting module-level variables to re-instantiate
436 with the set values (since shell is instantiated first at import-time
429 with the set values (since shell is instantiated first at import-time
437 when module variables have default values)"""
430 when module variables have default values)"""
438 global shell
431 global shell
439 shell = EmbeddedSphinxShell()
432 shell = EmbeddedSphinxShell()
440
433
441
434
442 def ipython_directive(name, arguments, options, content, lineno,
435 def ipython_directive(name, arguments, options, content, lineno,
443 content_offset, block_text, state, state_machine,
436 content_offset, block_text, state, state_machine,
444 ):
437 ):
445
438
446 debug = ipython_directive.DEBUG
439 debug = ipython_directive.DEBUG
447 shell.is_suppress = options.has_key('suppress')
440 shell.is_suppress = options.has_key('suppress')
448 shell.is_doctest = options.has_key('doctest')
441 shell.is_doctest = options.has_key('doctest')
449 shell.is_verbatim = options.has_key('verbatim')
442 shell.is_verbatim = options.has_key('verbatim')
450
443
451 #print 'ipy', shell.is_suppress, options
444 #print 'ipy', shell.is_suppress, options
452 parts = '\n'.join(content).split('\n\n')
445 parts = '\n'.join(content).split('\n\n')
453 lines = ['.. sourcecode:: ipython', '']
446 lines = ['.. sourcecode:: ipython', '']
454
447
455 figures = []
448 figures = []
456 for part in parts:
449 for part in parts:
457 block = block_parser(part)
450 block = block_parser(part)
458
451
459 if len(block):
452 if len(block):
460 rows, figure = shell.process_block(block)
453 rows, figure = shell.process_block(block)
461 for row in rows:
454 for row in rows:
462 lines.extend([' %s'%line for line in row.split('\n')])
455 lines.extend([' %s'%line for line in row.split('\n')])
463
456
464 if figure is not None:
457 if figure is not None:
465 figures.append(figure)
458 figures.append(figure)
466
459
467 for figure in figures:
460 for figure in figures:
468 lines.append('')
461 lines.append('')
469 lines.extend(figure.split('\n'))
462 lines.extend(figure.split('\n'))
470 lines.append('')
463 lines.append('')
471
464
472 #print lines
465 #print lines
473 if len(lines)>2:
466 if len(lines)>2:
474 if debug:
467 if debug:
475 print '\n'.join(lines)
468 print '\n'.join(lines)
476 else:
469 else:
477 #print 'INSERTING %d lines'%len(lines)
470 #print 'INSERTING %d lines'%len(lines)
478 state_machine.insert_input(
471 state_machine.insert_input(
479 lines, state_machine.input_lines.source(0))
472 lines, state_machine.input_lines.source(0))
480
473
481 return []
474 return []
482
475
483 ipython_directive.DEBUG = False
476 ipython_directive.DEBUG = False
484 ipython_directive.DEBUG = True # dbg
477 ipython_directive.DEBUG = True # dbg
485
478
486 # Enable as a proper Sphinx directive
479 # Enable as a proper Sphinx directive
487 def setup(app):
480 def setup(app):
488 setup.app = app
481 setup.app = app
489 options = {'suppress': directives.flag,
482 options = {'suppress': directives.flag,
490 'doctest': directives.flag,
483 'doctest': directives.flag,
491 'verbatim': directives.flag,
484 'verbatim': directives.flag,
492 }
485 }
493
486
494 app.add_directive('ipython', ipython_directive, True, (0, 2, 0), **options)
487 app.add_directive('ipython', ipython_directive, True, (0, 2, 0), **options)
495
488
496
489
497 # Simple smoke test, needs to be converted to a proper automatic test.
490 # Simple smoke test, needs to be converted to a proper automatic test.
498 def test():
491 def test():
499
492
500 examples = [
493 examples = [
501 r"""
494 r"""
502 In [9]: pwd
495 In [9]: pwd
503 Out[9]: '/home/jdhunter/py4science/book'
496 Out[9]: '/home/jdhunter/py4science/book'
504
497
505 In [10]: cd bookdata/
498 In [10]: cd bookdata/
506 /home/jdhunter/py4science/book/bookdata
499 /home/jdhunter/py4science/book/bookdata
507
500
508 In [2]: from pylab import *
501 In [2]: from pylab import *
509
502
510 In [2]: ion()
503 In [2]: ion()
511
504
512 In [3]: im = imread('stinkbug.png')
505 In [3]: im = imread('stinkbug.png')
513
506
514 @savefig mystinkbug.png width=4in
507 @savefig mystinkbug.png width=4in
515 In [4]: imshow(im)
508 In [4]: imshow(im)
516 Out[4]: <matplotlib.image.AxesImage object at 0x39ea850>
509 Out[4]: <matplotlib.image.AxesImage object at 0x39ea850>
517
510
518 """,
511 """,
519 r"""
512 r"""
520
513
521 In [1]: x = 'hello world'
514 In [1]: x = 'hello world'
522
515
523 # string methods can be
516 # string methods can be
524 # used to alter the string
517 # used to alter the string
525 @doctest
518 @doctest
526 In [2]: x.upper()
519 In [2]: x.upper()
527 Out[2]: 'HELLO WORLD'
520 Out[2]: 'HELLO WORLD'
528
521
529 @verbatim
522 @verbatim
530 In [3]: x.st<TAB>
523 In [3]: x.st<TAB>
531 x.startswith x.strip
524 x.startswith x.strip
532 """,
525 """,
533 r"""
526 r"""
534
527
535 In [130]: url = 'http://ichart.finance.yahoo.com/table.csv?s=CROX\
528 In [130]: url = 'http://ichart.finance.yahoo.com/table.csv?s=CROX\
536 .....: &d=9&e=22&f=2009&g=d&a=1&br=8&c=2006&ignore=.csv'
529 .....: &d=9&e=22&f=2009&g=d&a=1&br=8&c=2006&ignore=.csv'
537
530
538 In [131]: print url.split('&')
531 In [131]: print url.split('&')
539 ['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']
532 ['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']
540
533
541 In [60]: import urllib
534 In [60]: import urllib
542
535
543 """,
536 """,
544 r"""\
537 r"""\
545
538
546 In [133]: import numpy.random
539 In [133]: import numpy.random
547
540
548 @suppress
541 @suppress
549 In [134]: numpy.random.seed(2358)
542 In [134]: numpy.random.seed(2358)
550
543
551 @doctest
544 @doctest
552 In [135]: np.random.rand(10,2)
545 In [135]: np.random.rand(10,2)
553 Out[135]:
546 Out[135]:
554 array([[ 0.64524308, 0.59943846],
547 array([[ 0.64524308, 0.59943846],
555 [ 0.47102322, 0.8715456 ],
548 [ 0.47102322, 0.8715456 ],
556 [ 0.29370834, 0.74776844],
549 [ 0.29370834, 0.74776844],
557 [ 0.99539577, 0.1313423 ],
550 [ 0.99539577, 0.1313423 ],
558 [ 0.16250302, 0.21103583],
551 [ 0.16250302, 0.21103583],
559 [ 0.81626524, 0.1312433 ],
552 [ 0.81626524, 0.1312433 ],
560 [ 0.67338089, 0.72302393],
553 [ 0.67338089, 0.72302393],
561 [ 0.7566368 , 0.07033696],
554 [ 0.7566368 , 0.07033696],
562 [ 0.22591016, 0.77731835],
555 [ 0.22591016, 0.77731835],
563 [ 0.0072729 , 0.34273127]])
556 [ 0.0072729 , 0.34273127]])
564
557
565 """,
558 """,
566
559
567 r"""
560 r"""
568 In [106]: print x
561 In [106]: print x
569 jdh
562 jdh
570
563
571 In [109]: for i in range(10):
564 In [109]: for i in range(10):
572 .....: print i
565 .....: print i
573 .....:
566 .....:
574 .....:
567 .....:
575 0
568 0
576 1
569 1
577 2
570 2
578 3
571 3
579 4
572 4
580 5
573 5
581 6
574 6
582 7
575 7
583 8
576 8
584 9
577 9
585 """,
578 """,
586
579
587 r"""
580 r"""
588
581
589 In [144]: from pylab import *
582 In [144]: from pylab import *
590
583
591 In [145]: ion()
584 In [145]: ion()
592
585
593 # use a semicolon to suppress the output
586 # use a semicolon to suppress the output
594 @savefig test_hist.png width=4in
587 @savefig test_hist.png width=4in
595 In [151]: hist(np.random.randn(10000), 100);
588 In [151]: hist(np.random.randn(10000), 100);
596
589
597
590
598 @savefig test_plot.png width=4in
591 @savefig test_plot.png width=4in
599 In [151]: plot(np.random.randn(10000), 'o');
592 In [151]: plot(np.random.randn(10000), 'o');
600 """,
593 """,
601
594
602 r"""
595 r"""
603 # use a semicolon to suppress the output
596 # use a semicolon to suppress the output
604 In [151]: plt.clf()
597 In [151]: plt.clf()
605
598
606 @savefig plot_simple.png width=4in
599 @savefig plot_simple.png width=4in
607 In [151]: plot([1,2,3])
600 In [151]: plot([1,2,3])
608
601
609 @savefig hist_simple.png width=4in
602 @savefig hist_simple.png width=4in
610 In [151]: hist(np.random.randn(10000), 100);
603 In [151]: hist(np.random.randn(10000), 100);
611
604
612 """,
605 """,
613 r"""
606 r"""
614 # update the current fig
607 # update the current fig
615 In [151]: ylabel('number')
608 In [151]: ylabel('number')
616
609
617 In [152]: title('normal distribution')
610 In [152]: title('normal distribution')
618
611
619
612
620 @savefig hist_with_text.png
613 @savefig hist_with_text.png
621 In [153]: grid(True)
614 In [153]: grid(True)
622
615
623 """,
616 """,
624 ]
617 ]
625
618
626 #ipython_directive.DEBUG = True # dbg
619 #ipython_directive.DEBUG = True # dbg
627 #options = dict(suppress=True) # dbg
620 #options = dict(suppress=True) # dbg
628 options = dict()
621 options = dict()
629 for example in examples:
622 for example in examples:
630 content = example.split('\n')
623 content = example.split('\n')
631 ipython_directive('debug', arguments=None, options=options,
624 ipython_directive('debug', arguments=None, options=options,
632 content=content, lineno=0,
625 content=content, lineno=0,
633 content_offset=None, block_text=None,
626 content_offset=None, block_text=None,
634 state=None, state_machine=None,
627 state=None, state_machine=None,
635 )
628 )
636
629
637 # Run test suite as a script
630 # Run test suite as a script
638 if __name__=='__main__':
631 if __name__=='__main__':
639 if not os.path.isdir('_static'):
632 if not os.path.isdir('_static'):
640 os.mkdir('_static')
633 os.mkdir('_static')
641 test()
634 test()
642 print 'All OK? Check figures in _static/'
635 print 'All OK? Check figures in _static/'
General Comments 0
You need to be logged in to leave comments. Login now