##// END OF EJS Templates
Merge pull request #2882 from takluyver/utils-cleanup...
Bussonnier Matthias -
r9486:a3c4e796 merge
parent child Browse files
Show More
@@ -1,558 +1,559 b''
1 """Implementation of code management magic functions.
1 """Implementation of code management magic functions.
2 """
2 """
3 #-----------------------------------------------------------------------------
3 #-----------------------------------------------------------------------------
4 # Copyright (c) 2012 The IPython Development Team.
4 # Copyright (c) 2012 The IPython Development Team.
5 #
5 #
6 # Distributed under the terms of the Modified BSD License.
6 # Distributed under the terms of the Modified BSD License.
7 #
7 #
8 # The full license is in the file COPYING.txt, distributed with this software.
8 # The full license is in the file COPYING.txt, distributed with this software.
9 #-----------------------------------------------------------------------------
9 #-----------------------------------------------------------------------------
10
10
11 #-----------------------------------------------------------------------------
11 #-----------------------------------------------------------------------------
12 # Imports
12 # Imports
13 #-----------------------------------------------------------------------------
13 #-----------------------------------------------------------------------------
14
14
15 # Stdlib
15 # Stdlib
16 import inspect
16 import inspect
17 import io
17 import io
18 import os
18 import os
19 import re
19 import re
20 import sys
20 import sys
21
21
22 # Our own packages
22 # Our own packages
23 from IPython.core.error import TryNext, StdinNotImplementedError, UsageError
23 from IPython.core.error import TryNext, StdinNotImplementedError, UsageError
24 from IPython.core.macro import Macro
24 from IPython.core.macro import Macro
25 from IPython.core.magic import Magics, magics_class, line_magic
25 from IPython.core.magic import Magics, magics_class, line_magic
26 from IPython.core.oinspect import find_file, find_source_lines
26 from IPython.core.oinspect import find_file, find_source_lines
27 from IPython.testing.skipdoctest import skip_doctest
27 from IPython.testing.skipdoctest import skip_doctest
28 from IPython.utils import py3compat
28 from IPython.utils import py3compat
29 from IPython.utils.contexts import preserve_keys
29 from IPython.utils.contexts import preserve_keys
30 from IPython.utils.io import file_read
31 from IPython.utils.path import get_py_filename, unquote_filename
30 from IPython.utils.path import get_py_filename, unquote_filename
32 from IPython.utils.warn import warn
31 from IPython.utils.warn import warn
33
32
34 #-----------------------------------------------------------------------------
33 #-----------------------------------------------------------------------------
35 # Magic implementation classes
34 # Magic implementation classes
36 #-----------------------------------------------------------------------------
35 #-----------------------------------------------------------------------------
37
36
38 # Used for exception handling in magic_edit
37 # Used for exception handling in magic_edit
39 class MacroToEdit(ValueError): pass
38 class MacroToEdit(ValueError): pass
40
39
41 ipython_input_pat = re.compile(r"<ipython\-input\-(\d+)-[a-z\d]+>$")
40 ipython_input_pat = re.compile(r"<ipython\-input\-(\d+)-[a-z\d]+>$")
42
41
43 class InteractivelyDefined(Exception):
42 class InteractivelyDefined(Exception):
44 """Exception for interactively defined variable in magic_edit"""
43 """Exception for interactively defined variable in magic_edit"""
45 def __init__(self, index):
44 def __init__(self, index):
46 self.index = index
45 self.index = index
47
46
48
47
49 @magics_class
48 @magics_class
50 class CodeMagics(Magics):
49 class CodeMagics(Magics):
51 """Magics related to code management (loading, saving, editing, ...)."""
50 """Magics related to code management (loading, saving, editing, ...)."""
52
51
53 @line_magic
52 @line_magic
54 def save(self, parameter_s=''):
53 def save(self, parameter_s=''):
55 """Save a set of lines or a macro to a given filename.
54 """Save a set of lines or a macro to a given filename.
56
55
57 Usage:\\
56 Usage:\\
58 %save [options] filename n1-n2 n3-n4 ... n5 .. n6 ...
57 %save [options] filename n1-n2 n3-n4 ... n5 .. n6 ...
59
58
60 Options:
59 Options:
61
60
62 -r: use 'raw' input. By default, the 'processed' history is used,
61 -r: use 'raw' input. By default, the 'processed' history is used,
63 so that magics are loaded in their transformed version to valid
62 so that magics are loaded in their transformed version to valid
64 Python. If this option is given, the raw input as typed as the
63 Python. If this option is given, the raw input as typed as the
65 command line is used instead.
64 command line is used instead.
66
65
67 -f: force overwrite. If file exists, %save will prompt for overwrite
66 -f: force overwrite. If file exists, %save will prompt for overwrite
68 unless -f is given.
67 unless -f is given.
69
68
70 -a: append to the file instead of overwriting it.
69 -a: append to the file instead of overwriting it.
71
70
72 This function uses the same syntax as %history for input ranges,
71 This function uses the same syntax as %history for input ranges,
73 then saves the lines to the filename you specify.
72 then saves the lines to the filename you specify.
74
73
75 It adds a '.py' extension to the file if you don't do so yourself, and
74 It adds a '.py' extension to the file if you don't do so yourself, and
76 it asks for confirmation before overwriting existing files.
75 it asks for confirmation before overwriting existing files.
77
76
78 If `-r` option is used, the default extension is `.ipy`.
77 If `-r` option is used, the default extension is `.ipy`.
79 """
78 """
80
79
81 opts,args = self.parse_options(parameter_s,'fra',mode='list')
80 opts,args = self.parse_options(parameter_s,'fra',mode='list')
82 if not args:
81 if not args:
83 raise UsageError('Missing filename.')
82 raise UsageError('Missing filename.')
84 raw = 'r' in opts
83 raw = 'r' in opts
85 force = 'f' in opts
84 force = 'f' in opts
86 append = 'a' in opts
85 append = 'a' in opts
87 mode = 'a' if append else 'w'
86 mode = 'a' if append else 'w'
88 ext = u'.ipy' if raw else u'.py'
87 ext = u'.ipy' if raw else u'.py'
89 fname, codefrom = unquote_filename(args[0]), " ".join(args[1:])
88 fname, codefrom = unquote_filename(args[0]), " ".join(args[1:])
90 if not fname.endswith((u'.py',u'.ipy')):
89 if not fname.endswith((u'.py',u'.ipy')):
91 fname += ext
90 fname += ext
92 file_exists = os.path.isfile(fname)
91 file_exists = os.path.isfile(fname)
93 if file_exists and not force and not append:
92 if file_exists and not force and not append:
94 try:
93 try:
95 overwrite = self.shell.ask_yes_no('File `%s` exists. Overwrite (y/[N])? ' % fname, default='n')
94 overwrite = self.shell.ask_yes_no('File `%s` exists. Overwrite (y/[N])? ' % fname, default='n')
96 except StdinNotImplementedError:
95 except StdinNotImplementedError:
97 print "File `%s` exists. Use `%%save -f %s` to force overwrite" % (fname, parameter_s)
96 print "File `%s` exists. Use `%%save -f %s` to force overwrite" % (fname, parameter_s)
98 return
97 return
99 if not overwrite :
98 if not overwrite :
100 print 'Operation cancelled.'
99 print 'Operation cancelled.'
101 return
100 return
102 try:
101 try:
103 cmds = self.shell.find_user_code(codefrom,raw)
102 cmds = self.shell.find_user_code(codefrom,raw)
104 except (TypeError, ValueError) as e:
103 except (TypeError, ValueError) as e:
105 print e.args[0]
104 print e.args[0]
106 return
105 return
107 out = py3compat.cast_unicode(cmds)
106 out = py3compat.cast_unicode(cmds)
108 with io.open(fname, mode, encoding="utf-8") as f:
107 with io.open(fname, mode, encoding="utf-8") as f:
109 if not file_exists or not append:
108 if not file_exists or not append:
110 f.write(u"# coding: utf-8\n")
109 f.write(u"# coding: utf-8\n")
111 f.write(out)
110 f.write(out)
112 # make sure we end on a newline
111 # make sure we end on a newline
113 if not out.endswith(u'\n'):
112 if not out.endswith(u'\n'):
114 f.write(u'\n')
113 f.write(u'\n')
115 print 'The following commands were written to file `%s`:' % fname
114 print 'The following commands were written to file `%s`:' % fname
116 print cmds
115 print cmds
117
116
118 @line_magic
117 @line_magic
119 def pastebin(self, parameter_s=''):
118 def pastebin(self, parameter_s=''):
120 """Upload code to Github's Gist paste bin, returning the URL.
119 """Upload code to Github's Gist paste bin, returning the URL.
121
120
122 Usage:\\
121 Usage:\\
123 %pastebin [-d "Custom description"] 1-7
122 %pastebin [-d "Custom description"] 1-7
124
123
125 The argument can be an input history range, a filename, or the name of a
124 The argument can be an input history range, a filename, or the name of a
126 string or macro.
125 string or macro.
127
126
128 Options:
127 Options:
129
128
130 -d: Pass a custom description for the gist. The default will say
129 -d: Pass a custom description for the gist. The default will say
131 "Pasted from IPython".
130 "Pasted from IPython".
132 """
131 """
133 opts, args = self.parse_options(parameter_s, 'd:')
132 opts, args = self.parse_options(parameter_s, 'd:')
134
133
135 try:
134 try:
136 code = self.shell.find_user_code(args)
135 code = self.shell.find_user_code(args)
137 except (ValueError, TypeError) as e:
136 except (ValueError, TypeError) as e:
138 print e.args[0]
137 print e.args[0]
139 return
138 return
140
139
141 from urllib2 import urlopen # Deferred import
140 from urllib2 import urlopen # Deferred import
142 import json
141 import json
143 post_data = json.dumps({
142 post_data = json.dumps({
144 "description": opts.get('d', "Pasted from IPython"),
143 "description": opts.get('d', "Pasted from IPython"),
145 "public": True,
144 "public": True,
146 "files": {
145 "files": {
147 "file1.py": {
146 "file1.py": {
148 "content": code
147 "content": code
149 }
148 }
150 }
149 }
151 }).encode('utf-8')
150 }).encode('utf-8')
152
151
153 response = urlopen("https://api.github.com/gists", post_data)
152 response = urlopen("https://api.github.com/gists", post_data)
154 response_data = json.loads(response.read().decode('utf-8'))
153 response_data = json.loads(response.read().decode('utf-8'))
155 return response_data['html_url']
154 return response_data['html_url']
156
155
157 @line_magic
156 @line_magic
158 def loadpy(self, arg_s):
157 def loadpy(self, arg_s):
159 """Alias of `%load`
158 """Alias of `%load`
160
159
161 `%loadpy` has gained some flexibility and droped the requirement of a `.py`
160 `%loadpy` has gained some flexibility and droped the requirement of a `.py`
162 extension. So it has been renamed simply into %load. You can look at
161 extension. So it has been renamed simply into %load. You can look at
163 `%load`'s docstring for more info.
162 `%load`'s docstring for more info.
164 """
163 """
165 self.load(arg_s)
164 self.load(arg_s)
166
165
167 @line_magic
166 @line_magic
168 def load(self, arg_s):
167 def load(self, arg_s):
169 """Load code into the current frontend.
168 """Load code into the current frontend.
170
169
171 Usage:\\
170 Usage:\\
172 %load [options] source
171 %load [options] source
173
172
174 where source can be a filename, URL, input history range or macro
173 where source can be a filename, URL, input history range or macro
175
174
176 Options:
175 Options:
177 --------
176 --------
178 -y : Don't ask confirmation for loading source above 200 000 characters.
177 -y : Don't ask confirmation for loading source above 200 000 characters.
179
178
180 This magic command can either take a local filename, a URL, an history
179 This magic command can either take a local filename, a URL, an history
181 range (see %history) or a macro as argument, it will prompt for
180 range (see %history) or a macro as argument, it will prompt for
182 confirmation before loading source with more than 200 000 characters, unless
181 confirmation before loading source with more than 200 000 characters, unless
183 -y flag is passed or if the frontend does not support raw_input::
182 -y flag is passed or if the frontend does not support raw_input::
184
183
185 %load myscript.py
184 %load myscript.py
186 %load 7-27
185 %load 7-27
187 %load myMacro
186 %load myMacro
188 %load http://www.example.com/myscript.py
187 %load http://www.example.com/myscript.py
189 """
188 """
190 opts,args = self.parse_options(arg_s,'y')
189 opts,args = self.parse_options(arg_s,'y')
191 if not args:
190 if not args:
192 raise UsageError('Missing filename, URL, input history range, '
191 raise UsageError('Missing filename, URL, input history range, '
193 'or macro.')
192 'or macro.')
194
193
195 contents = self.shell.find_user_code(args)
194 contents = self.shell.find_user_code(args)
196 l = len(contents)
195 l = len(contents)
197
196
198 # 200 000 is ~ 2500 full 80 caracter lines
197 # 200 000 is ~ 2500 full 80 caracter lines
199 # so in average, more than 5000 lines
198 # so in average, more than 5000 lines
200 if l > 200000 and 'y' not in opts:
199 if l > 200000 and 'y' not in opts:
201 try:
200 try:
202 ans = self.shell.ask_yes_no(("The text you're trying to load seems pretty big"\
201 ans = self.shell.ask_yes_no(("The text you're trying to load seems pretty big"\
203 " (%d characters). Continue (y/[N]) ?" % l), default='n' )
202 " (%d characters). Continue (y/[N]) ?" % l), default='n' )
204 except StdinNotImplementedError:
203 except StdinNotImplementedError:
205 #asume yes if raw input not implemented
204 #asume yes if raw input not implemented
206 ans = True
205 ans = True
207
206
208 if ans is False :
207 if ans is False :
209 print 'Operation cancelled.'
208 print 'Operation cancelled.'
210 return
209 return
211
210
212 self.shell.set_next_input(contents)
211 self.shell.set_next_input(contents)
213
212
214 @staticmethod
213 @staticmethod
215 def _find_edit_target(shell, args, opts, last_call):
214 def _find_edit_target(shell, args, opts, last_call):
216 """Utility method used by magic_edit to find what to edit."""
215 """Utility method used by magic_edit to find what to edit."""
217
216
218 def make_filename(arg):
217 def make_filename(arg):
219 "Make a filename from the given args"
218 "Make a filename from the given args"
220 arg = unquote_filename(arg)
219 arg = unquote_filename(arg)
221 try:
220 try:
222 filename = get_py_filename(arg)
221 filename = get_py_filename(arg)
223 except IOError:
222 except IOError:
224 # If it ends with .py but doesn't already exist, assume we want
223 # If it ends with .py but doesn't already exist, assume we want
225 # a new file.
224 # a new file.
226 if arg.endswith('.py'):
225 if arg.endswith('.py'):
227 filename = arg
226 filename = arg
228 else:
227 else:
229 filename = None
228 filename = None
230 return filename
229 return filename
231
230
232 # Set a few locals from the options for convenience:
231 # Set a few locals from the options for convenience:
233 opts_prev = 'p' in opts
232 opts_prev = 'p' in opts
234 opts_raw = 'r' in opts
233 opts_raw = 'r' in opts
235
234
236 # custom exceptions
235 # custom exceptions
237 class DataIsObject(Exception): pass
236 class DataIsObject(Exception): pass
238
237
239 # Default line number value
238 # Default line number value
240 lineno = opts.get('n',None)
239 lineno = opts.get('n',None)
241
240
242 if opts_prev:
241 if opts_prev:
243 args = '_%s' % last_call[0]
242 args = '_%s' % last_call[0]
244 if args not in shell.user_ns:
243 if args not in shell.user_ns:
245 args = last_call[1]
244 args = last_call[1]
246
245
247 # by default this is done with temp files, except when the given
246 # by default this is done with temp files, except when the given
248 # arg is a filename
247 # arg is a filename
249 use_temp = True
248 use_temp = True
250
249
251 data = ''
250 data = ''
252
251
253 # First, see if the arguments should be a filename.
252 # First, see if the arguments should be a filename.
254 filename = make_filename(args)
253 filename = make_filename(args)
255 if filename:
254 if filename:
256 use_temp = False
255 use_temp = False
257 elif args:
256 elif args:
258 # Mode where user specifies ranges of lines, like in %macro.
257 # Mode where user specifies ranges of lines, like in %macro.
259 data = shell.extract_input_lines(args, opts_raw)
258 data = shell.extract_input_lines(args, opts_raw)
260 if not data:
259 if not data:
261 try:
260 try:
262 # Load the parameter given as a variable. If not a string,
261 # Load the parameter given as a variable. If not a string,
263 # process it as an object instead (below)
262 # process it as an object instead (below)
264
263
265 #print '*** args',args,'type',type(args) # dbg
264 #print '*** args',args,'type',type(args) # dbg
266 data = eval(args, shell.user_ns)
265 data = eval(args, shell.user_ns)
267 if not isinstance(data, basestring):
266 if not isinstance(data, basestring):
268 raise DataIsObject
267 raise DataIsObject
269
268
270 except (NameError,SyntaxError):
269 except (NameError,SyntaxError):
271 # given argument is not a variable, try as a filename
270 # given argument is not a variable, try as a filename
272 filename = make_filename(args)
271 filename = make_filename(args)
273 if filename is None:
272 if filename is None:
274 warn("Argument given (%s) can't be found as a variable "
273 warn("Argument given (%s) can't be found as a variable "
275 "or as a filename." % args)
274 "or as a filename." % args)
276 return (None, None, None)
275 return (None, None, None)
277 use_temp = False
276 use_temp = False
278
277
279 except DataIsObject:
278 except DataIsObject:
280 # macros have a special edit function
279 # macros have a special edit function
281 if isinstance(data, Macro):
280 if isinstance(data, Macro):
282 raise MacroToEdit(data)
281 raise MacroToEdit(data)
283
282
284 # For objects, try to edit the file where they are defined
283 # For objects, try to edit the file where they are defined
285 filename = find_file(data)
284 filename = find_file(data)
286 if filename:
285 if filename:
287 if 'fakemodule' in filename.lower() and \
286 if 'fakemodule' in filename.lower() and \
288 inspect.isclass(data):
287 inspect.isclass(data):
289 # class created by %edit? Try to find source
288 # class created by %edit? Try to find source
290 # by looking for method definitions instead, the
289 # by looking for method definitions instead, the
291 # __module__ in those classes is FakeModule.
290 # __module__ in those classes is FakeModule.
292 attrs = [getattr(data, aname) for aname in dir(data)]
291 attrs = [getattr(data, aname) for aname in dir(data)]
293 for attr in attrs:
292 for attr in attrs:
294 if not inspect.ismethod(attr):
293 if not inspect.ismethod(attr):
295 continue
294 continue
296 filename = find_file(attr)
295 filename = find_file(attr)
297 if filename and \
296 if filename and \
298 'fakemodule' not in filename.lower():
297 'fakemodule' not in filename.lower():
299 # change the attribute to be the edit
298 # change the attribute to be the edit
300 # target instead
299 # target instead
301 data = attr
300 data = attr
302 break
301 break
303
302
304 m = ipython_input_pat.match(os.path.basename(filename))
303 m = ipython_input_pat.match(os.path.basename(filename))
305 if m:
304 if m:
306 raise InteractivelyDefined(int(m.groups()[0]))
305 raise InteractivelyDefined(int(m.groups()[0]))
307
306
308 datafile = 1
307 datafile = 1
309 if filename is None:
308 if filename is None:
310 filename = make_filename(args)
309 filename = make_filename(args)
311 datafile = 1
310 datafile = 1
312 if filename is not None:
311 if filename is not None:
313 # only warn about this if we get a real name
312 # only warn about this if we get a real name
314 warn('Could not find file where `%s` is defined.\n'
313 warn('Could not find file where `%s` is defined.\n'
315 'Opening a file named `%s`' % (args, filename))
314 'Opening a file named `%s`' % (args, filename))
316 # Now, make sure we can actually read the source (if it was
315 # Now, make sure we can actually read the source (if it was
317 # in a temp file it's gone by now).
316 # in a temp file it's gone by now).
318 if datafile:
317 if datafile:
319 if lineno is None:
318 if lineno is None:
320 lineno = find_source_lines(data)
319 lineno = find_source_lines(data)
321 if lineno is None:
320 if lineno is None:
322 filename = make_filename(args)
321 filename = make_filename(args)
323 if filename is None:
322 if filename is None:
324 warn('The file where `%s` was defined '
323 warn('The file where `%s` was defined '
325 'cannot be read or found.' % data)
324 'cannot be read or found.' % data)
326 return (None, None, None)
325 return (None, None, None)
327 use_temp = False
326 use_temp = False
328
327
329 if use_temp:
328 if use_temp:
330 filename = shell.mktempfile(data)
329 filename = shell.mktempfile(data)
331 print 'IPython will make a temporary file named:',filename
330 print 'IPython will make a temporary file named:',filename
332
331
333 # use last_call to remember the state of the previous call, but don't
332 # use last_call to remember the state of the previous call, but don't
334 # let it be clobbered by successive '-p' calls.
333 # let it be clobbered by successive '-p' calls.
335 try:
334 try:
336 last_call[0] = shell.displayhook.prompt_count
335 last_call[0] = shell.displayhook.prompt_count
337 if not opts_prev:
336 if not opts_prev:
338 last_call[1] = args
337 last_call[1] = args
339 except:
338 except:
340 pass
339 pass
341
340
342
341
343 return filename, lineno, use_temp
342 return filename, lineno, use_temp
344
343
345 def _edit_macro(self,mname,macro):
344 def _edit_macro(self,mname,macro):
346 """open an editor with the macro data in a file"""
345 """open an editor with the macro data in a file"""
347 filename = self.shell.mktempfile(macro.value)
346 filename = self.shell.mktempfile(macro.value)
348 self.shell.hooks.editor(filename)
347 self.shell.hooks.editor(filename)
349
348
350 # and make a new macro object, to replace the old one
349 # and make a new macro object, to replace the old one
351 mfile = open(filename)
350 mfile = open(filename)
352 mvalue = mfile.read()
351 mvalue = mfile.read()
353 mfile.close()
352 mfile.close()
354 self.shell.user_ns[mname] = Macro(mvalue)
353 self.shell.user_ns[mname] = Macro(mvalue)
355
354
356 @skip_doctest
355 @skip_doctest
357 @line_magic
356 @line_magic
358 def edit(self, parameter_s='',last_call=['','']):
357 def edit(self, parameter_s='',last_call=['','']):
359 """Bring up an editor and execute the resulting code.
358 """Bring up an editor and execute the resulting code.
360
359
361 Usage:
360 Usage:
362 %edit [options] [args]
361 %edit [options] [args]
363
362
364 %edit runs IPython's editor hook. The default version of this hook is
363 %edit runs IPython's editor hook. The default version of this hook is
365 set to call the editor specified by your $EDITOR environment variable.
364 set to call the editor specified by your $EDITOR environment variable.
366 If this isn't found, it will default to vi under Linux/Unix and to
365 If this isn't found, it will default to vi under Linux/Unix and to
367 notepad under Windows. See the end of this docstring for how to change
366 notepad under Windows. See the end of this docstring for how to change
368 the editor hook.
367 the editor hook.
369
368
370 You can also set the value of this editor via the
369 You can also set the value of this editor via the
371 ``TerminalInteractiveShell.editor`` option in your configuration file.
370 ``TerminalInteractiveShell.editor`` option in your configuration file.
372 This is useful if you wish to use a different editor from your typical
371 This is useful if you wish to use a different editor from your typical
373 default with IPython (and for Windows users who typically don't set
372 default with IPython (and for Windows users who typically don't set
374 environment variables).
373 environment variables).
375
374
376 This command allows you to conveniently edit multi-line code right in
375 This command allows you to conveniently edit multi-line code right in
377 your IPython session.
376 your IPython session.
378
377
379 If called without arguments, %edit opens up an empty editor with a
378 If called without arguments, %edit opens up an empty editor with a
380 temporary file and will execute the contents of this file when you
379 temporary file and will execute the contents of this file when you
381 close it (don't forget to save it!).
380 close it (don't forget to save it!).
382
381
383
382
384 Options:
383 Options:
385
384
386 -n <number>: open the editor at a specified line number. By default,
385 -n <number>: open the editor at a specified line number. By default,
387 the IPython editor hook uses the unix syntax 'editor +N filename', but
386 the IPython editor hook uses the unix syntax 'editor +N filename', but
388 you can configure this by providing your own modified hook if your
387 you can configure this by providing your own modified hook if your
389 favorite editor supports line-number specifications with a different
388 favorite editor supports line-number specifications with a different
390 syntax.
389 syntax.
391
390
392 -p: this will call the editor with the same data as the previous time
391 -p: this will call the editor with the same data as the previous time
393 it was used, regardless of how long ago (in your current session) it
392 it was used, regardless of how long ago (in your current session) it
394 was.
393 was.
395
394
396 -r: use 'raw' input. This option only applies to input taken from the
395 -r: use 'raw' input. This option only applies to input taken from the
397 user's history. By default, the 'processed' history is used, so that
396 user's history. By default, the 'processed' history is used, so that
398 magics are loaded in their transformed version to valid Python. If
397 magics are loaded in their transformed version to valid Python. If
399 this option is given, the raw input as typed as the command line is
398 this option is given, the raw input as typed as the command line is
400 used instead. When you exit the editor, it will be executed by
399 used instead. When you exit the editor, it will be executed by
401 IPython's own processor.
400 IPython's own processor.
402
401
403 -x: do not execute the edited code immediately upon exit. This is
402 -x: do not execute the edited code immediately upon exit. This is
404 mainly useful if you are editing programs which need to be called with
403 mainly useful if you are editing programs which need to be called with
405 command line arguments, which you can then do using %run.
404 command line arguments, which you can then do using %run.
406
405
407
406
408 Arguments:
407 Arguments:
409
408
410 If arguments are given, the following possibilities exist:
409 If arguments are given, the following possibilities exist:
411
410
412 - If the argument is a filename, IPython will load that into the
411 - If the argument is a filename, IPython will load that into the
413 editor. It will execute its contents with execfile() when you exit,
412 editor. It will execute its contents with execfile() when you exit,
414 loading any code in the file into your interactive namespace.
413 loading any code in the file into your interactive namespace.
415
414
416 - The arguments are ranges of input history, e.g. "7 ~1/4-6".
415 - The arguments are ranges of input history, e.g. "7 ~1/4-6".
417 The syntax is the same as in the %history magic.
416 The syntax is the same as in the %history magic.
418
417
419 - If the argument is a string variable, its contents are loaded
418 - If the argument is a string variable, its contents are loaded
420 into the editor. You can thus edit any string which contains
419 into the editor. You can thus edit any string which contains
421 python code (including the result of previous edits).
420 python code (including the result of previous edits).
422
421
423 - If the argument is the name of an object (other than a string),
422 - If the argument is the name of an object (other than a string),
424 IPython will try to locate the file where it was defined and open the
423 IPython will try to locate the file where it was defined and open the
425 editor at the point where it is defined. You can use `%edit function`
424 editor at the point where it is defined. You can use `%edit function`
426 to load an editor exactly at the point where 'function' is defined,
425 to load an editor exactly at the point where 'function' is defined,
427 edit it and have the file be executed automatically.
426 edit it and have the file be executed automatically.
428
427
429 - If the object is a macro (see %macro for details), this opens up your
428 - If the object is a macro (see %macro for details), this opens up your
430 specified editor with a temporary file containing the macro's data.
429 specified editor with a temporary file containing the macro's data.
431 Upon exit, the macro is reloaded with the contents of the file.
430 Upon exit, the macro is reloaded with the contents of the file.
432
431
433 Note: opening at an exact line is only supported under Unix, and some
432 Note: opening at an exact line is only supported under Unix, and some
434 editors (like kedit and gedit up to Gnome 2.8) do not understand the
433 editors (like kedit and gedit up to Gnome 2.8) do not understand the
435 '+NUMBER' parameter necessary for this feature. Good editors like
434 '+NUMBER' parameter necessary for this feature. Good editors like
436 (X)Emacs, vi, jed, pico and joe all do.
435 (X)Emacs, vi, jed, pico and joe all do.
437
436
438 After executing your code, %edit will return as output the code you
437 After executing your code, %edit will return as output the code you
439 typed in the editor (except when it was an existing file). This way
438 typed in the editor (except when it was an existing file). This way
440 you can reload the code in further invocations of %edit as a variable,
439 you can reload the code in further invocations of %edit as a variable,
441 via _<NUMBER> or Out[<NUMBER>], where <NUMBER> is the prompt number of
440 via _<NUMBER> or Out[<NUMBER>], where <NUMBER> is the prompt number of
442 the output.
441 the output.
443
442
444 Note that %edit is also available through the alias %ed.
443 Note that %edit is also available through the alias %ed.
445
444
446 This is an example of creating a simple function inside the editor and
445 This is an example of creating a simple function inside the editor and
447 then modifying it. First, start up the editor::
446 then modifying it. First, start up the editor::
448
447
449 In [1]: edit
448 In [1]: edit
450 Editing... done. Executing edited code...
449 Editing... done. Executing edited code...
451 Out[1]: 'def foo():\\n print "foo() was defined in an editing
450 Out[1]: 'def foo():\\n print "foo() was defined in an editing
452 session"\\n'
451 session"\\n'
453
452
454 We can then call the function foo()::
453 We can then call the function foo()::
455
454
456 In [2]: foo()
455 In [2]: foo()
457 foo() was defined in an editing session
456 foo() was defined in an editing session
458
457
459 Now we edit foo. IPython automatically loads the editor with the
458 Now we edit foo. IPython automatically loads the editor with the
460 (temporary) file where foo() was previously defined::
459 (temporary) file where foo() was previously defined::
461
460
462 In [3]: edit foo
461 In [3]: edit foo
463 Editing... done. Executing edited code...
462 Editing... done. Executing edited code...
464
463
465 And if we call foo() again we get the modified version::
464 And if we call foo() again we get the modified version::
466
465
467 In [4]: foo()
466 In [4]: foo()
468 foo() has now been changed!
467 foo() has now been changed!
469
468
470 Here is an example of how to edit a code snippet successive
469 Here is an example of how to edit a code snippet successive
471 times. First we call the editor::
470 times. First we call the editor::
472
471
473 In [5]: edit
472 In [5]: edit
474 Editing... done. Executing edited code...
473 Editing... done. Executing edited code...
475 hello
474 hello
476 Out[5]: "print 'hello'\\n"
475 Out[5]: "print 'hello'\\n"
477
476
478 Now we call it again with the previous output (stored in _)::
477 Now we call it again with the previous output (stored in _)::
479
478
480 In [6]: edit _
479 In [6]: edit _
481 Editing... done. Executing edited code...
480 Editing... done. Executing edited code...
482 hello world
481 hello world
483 Out[6]: "print 'hello world'\\n"
482 Out[6]: "print 'hello world'\\n"
484
483
485 Now we call it with the output #8 (stored in _8, also as Out[8])::
484 Now we call it with the output #8 (stored in _8, also as Out[8])::
486
485
487 In [7]: edit _8
486 In [7]: edit _8
488 Editing... done. Executing edited code...
487 Editing... done. Executing edited code...
489 hello again
488 hello again
490 Out[7]: "print 'hello again'\\n"
489 Out[7]: "print 'hello again'\\n"
491
490
492
491
493 Changing the default editor hook:
492 Changing the default editor hook:
494
493
495 If you wish to write your own editor hook, you can put it in a
494 If you wish to write your own editor hook, you can put it in a
496 configuration file which you load at startup time. The default hook
495 configuration file which you load at startup time. The default hook
497 is defined in the IPython.core.hooks module, and you can use that as a
496 is defined in the IPython.core.hooks module, and you can use that as a
498 starting example for further modifications. That file also has
497 starting example for further modifications. That file also has
499 general instructions on how to set a new hook for use once you've
498 general instructions on how to set a new hook for use once you've
500 defined it."""
499 defined it."""
501 opts,args = self.parse_options(parameter_s,'prxn:')
500 opts,args = self.parse_options(parameter_s,'prxn:')
502
501
503 try:
502 try:
504 filename, lineno, is_temp = self._find_edit_target(self.shell,
503 filename, lineno, is_temp = self._find_edit_target(self.shell,
505 args, opts, last_call)
504 args, opts, last_call)
506 except MacroToEdit as e:
505 except MacroToEdit as e:
507 self._edit_macro(args, e.args[0])
506 self._edit_macro(args, e.args[0])
508 return
507 return
509 except InteractivelyDefined as e:
508 except InteractivelyDefined as e:
510 print "Editing In[%i]" % e.index
509 print "Editing In[%i]" % e.index
511 args = str(e.index)
510 args = str(e.index)
512 filename, lineno, is_temp = self._find_edit_target(self.shell,
511 filename, lineno, is_temp = self._find_edit_target(self.shell,
513 args, opts, last_call)
512 args, opts, last_call)
514 if filename is None:
513 if filename is None:
515 # nothing was found, warnings have already been issued,
514 # nothing was found, warnings have already been issued,
516 # just give up.
515 # just give up.
517 return
516 return
518
517
519 # do actual editing here
518 # do actual editing here
520 print 'Editing...',
519 print 'Editing...',
521 sys.stdout.flush()
520 sys.stdout.flush()
522 try:
521 try:
523 # Quote filenames that may have spaces in them
522 # Quote filenames that may have spaces in them
524 if ' ' in filename:
523 if ' ' in filename:
525 filename = "'%s'" % filename
524 filename = "'%s'" % filename
526 self.shell.hooks.editor(filename,lineno)
525 self.shell.hooks.editor(filename,lineno)
527 except TryNext:
526 except TryNext:
528 warn('Could not open editor')
527 warn('Could not open editor')
529 return
528 return
530
529
531 # XXX TODO: should this be generalized for all string vars?
530 # XXX TODO: should this be generalized for all string vars?
532 # For now, this is special-cased to blocks created by cpaste
531 # For now, this is special-cased to blocks created by cpaste
533 if args.strip() == 'pasted_block':
532 if args.strip() == 'pasted_block':
534 self.shell.user_ns['pasted_block'] = file_read(filename)
533 with open(filename, 'r') as f:
534 self.shell.user_ns['pasted_block'] = f.read()
535
535
536 if 'x' in opts: # -x prevents actual execution
536 if 'x' in opts: # -x prevents actual execution
537 print
537 print
538 else:
538 else:
539 print 'done. Executing edited code...'
539 print 'done. Executing edited code...'
540 with preserve_keys(self.shell.user_ns, '__file__'):
540 with preserve_keys(self.shell.user_ns, '__file__'):
541 if not is_temp:
541 if not is_temp:
542 self.shell.user_ns['__file__'] = filename
542 self.shell.user_ns['__file__'] = filename
543 if 'r' in opts: # Untranslated IPython code
543 if 'r' in opts: # Untranslated IPython code
544 self.shell.run_cell(file_read(filename),
544 with open(filename, 'r') as f:
545 store_history=False)
545 source = f.read()
546 self.shell.run_cell(source, store_history=False)
546 else:
547 else:
547 self.shell.safe_execfile(filename, self.shell.user_ns,
548 self.shell.safe_execfile(filename, self.shell.user_ns,
548 self.shell.user_ns)
549 self.shell.user_ns)
549
550
550 if is_temp:
551 if is_temp:
551 try:
552 try:
552 return open(filename).read()
553 return open(filename).read()
553 except IOError as msg:
554 except IOError as msg:
554 if msg.filename == filename:
555 if msg.filename == filename:
555 warn('File not found. Did you forget to save?')
556 warn('File not found. Did you forget to save?')
556 return
557 return
557 else:
558 else:
558 self.shell.showtraceback()
559 self.shell.showtraceback()
@@ -1,726 +1,726 b''
1 """Implementation of magic functions for interaction with the OS.
1 """Implementation of magic functions for interaction with the OS.
2
2
3 Note: this module is named 'osm' instead of 'os' to avoid a collision with the
3 Note: this module is named 'osm' instead of 'os' to avoid a collision with the
4 builtin.
4 builtin.
5 """
5 """
6 #-----------------------------------------------------------------------------
6 #-----------------------------------------------------------------------------
7 # Copyright (c) 2012 The IPython Development Team.
7 # Copyright (c) 2012 The IPython Development Team.
8 #
8 #
9 # Distributed under the terms of the Modified BSD License.
9 # Distributed under the terms of the Modified BSD License.
10 #
10 #
11 # The full license is in the file COPYING.txt, distributed with this software.
11 # The full license is in the file COPYING.txt, distributed with this software.
12 #-----------------------------------------------------------------------------
12 #-----------------------------------------------------------------------------
13
13
14 #-----------------------------------------------------------------------------
14 #-----------------------------------------------------------------------------
15 # Imports
15 # Imports
16 #-----------------------------------------------------------------------------
16 #-----------------------------------------------------------------------------
17
17
18 # Stdlib
18 # Stdlib
19 import io
19 import io
20 import os
20 import os
21 import re
21 import re
22 import sys
22 import sys
23 from pprint import pformat
23 from pprint import pformat
24
24
25 # Our own packages
25 # Our own packages
26 from IPython.core import magic_arguments
26 from IPython.core import magic_arguments
27 from IPython.core import oinspect
27 from IPython.core import oinspect
28 from IPython.core import page
28 from IPython.core import page
29 from IPython.core.error import UsageError
29 from IPython.core.error import UsageError
30 from IPython.core.magic import (
30 from IPython.core.magic import (
31 Magics, compress_dhist, magics_class, line_magic, cell_magic, line_cell_magic
31 Magics, compress_dhist, magics_class, line_magic, cell_magic, line_cell_magic
32 )
32 )
33 from IPython.testing.skipdoctest import skip_doctest
33 from IPython.testing.skipdoctest import skip_doctest
34 from IPython.utils.io import nlprint
35 from IPython.utils.openpy import source_to_unicode
34 from IPython.utils.openpy import source_to_unicode
36 from IPython.utils.path import unquote_filename
35 from IPython.utils.path import unquote_filename
37 from IPython.utils.process import abbrev_cwd
36 from IPython.utils.process import abbrev_cwd
38 from IPython.utils.terminal import set_term_title
37 from IPython.utils.terminal import set_term_title
39
38
40 #-----------------------------------------------------------------------------
39 #-----------------------------------------------------------------------------
41 # Magic implementation classes
40 # Magic implementation classes
42 #-----------------------------------------------------------------------------
41 #-----------------------------------------------------------------------------
43 @magics_class
42 @magics_class
44 class OSMagics(Magics):
43 class OSMagics(Magics):
45 """Magics to interact with the underlying OS (shell-type functionality).
44 """Magics to interact with the underlying OS (shell-type functionality).
46 """
45 """
47
46
48 @skip_doctest
47 @skip_doctest
49 @line_magic
48 @line_magic
50 def alias(self, parameter_s=''):
49 def alias(self, parameter_s=''):
51 """Define an alias for a system command.
50 """Define an alias for a system command.
52
51
53 '%alias alias_name cmd' defines 'alias_name' as an alias for 'cmd'
52 '%alias alias_name cmd' defines 'alias_name' as an alias for 'cmd'
54
53
55 Then, typing 'alias_name params' will execute the system command 'cmd
54 Then, typing 'alias_name params' will execute the system command 'cmd
56 params' (from your underlying operating system).
55 params' (from your underlying operating system).
57
56
58 Aliases have lower precedence than magic functions and Python normal
57 Aliases have lower precedence than magic functions and Python normal
59 variables, so if 'foo' is both a Python variable and an alias, the
58 variables, so if 'foo' is both a Python variable and an alias, the
60 alias can not be executed until 'del foo' removes the Python variable.
59 alias can not be executed until 'del foo' removes the Python variable.
61
60
62 You can use the %l specifier in an alias definition to represent the
61 You can use the %l specifier in an alias definition to represent the
63 whole line when the alias is called. For example::
62 whole line when the alias is called. For example::
64
63
65 In [2]: alias bracket echo "Input in brackets: <%l>"
64 In [2]: alias bracket echo "Input in brackets: <%l>"
66 In [3]: bracket hello world
65 In [3]: bracket hello world
67 Input in brackets: <hello world>
66 Input in brackets: <hello world>
68
67
69 You can also define aliases with parameters using %s specifiers (one
68 You can also define aliases with parameters using %s specifiers (one
70 per parameter)::
69 per parameter)::
71
70
72 In [1]: alias parts echo first %s second %s
71 In [1]: alias parts echo first %s second %s
73 In [2]: %parts A B
72 In [2]: %parts A B
74 first A second B
73 first A second B
75 In [3]: %parts A
74 In [3]: %parts A
76 Incorrect number of arguments: 2 expected.
75 Incorrect number of arguments: 2 expected.
77 parts is an alias to: 'echo first %s second %s'
76 parts is an alias to: 'echo first %s second %s'
78
77
79 Note that %l and %s are mutually exclusive. You can only use one or
78 Note that %l and %s are mutually exclusive. You can only use one or
80 the other in your aliases.
79 the other in your aliases.
81
80
82 Aliases expand Python variables just like system calls using ! or !!
81 Aliases expand Python variables just like system calls using ! or !!
83 do: all expressions prefixed with '$' get expanded. For details of
82 do: all expressions prefixed with '$' get expanded. For details of
84 the semantic rules, see PEP-215:
83 the semantic rules, see PEP-215:
85 http://www.python.org/peps/pep-0215.html. This is the library used by
84 http://www.python.org/peps/pep-0215.html. This is the library used by
86 IPython for variable expansion. If you want to access a true shell
85 IPython for variable expansion. If you want to access a true shell
87 variable, an extra $ is necessary to prevent its expansion by
86 variable, an extra $ is necessary to prevent its expansion by
88 IPython::
87 IPython::
89
88
90 In [6]: alias show echo
89 In [6]: alias show echo
91 In [7]: PATH='A Python string'
90 In [7]: PATH='A Python string'
92 In [8]: show $PATH
91 In [8]: show $PATH
93 A Python string
92 A Python string
94 In [9]: show $$PATH
93 In [9]: show $$PATH
95 /usr/local/lf9560/bin:/usr/local/intel/compiler70/ia32/bin:...
94 /usr/local/lf9560/bin:/usr/local/intel/compiler70/ia32/bin:...
96
95
97 You can use the alias facility to acess all of $PATH. See the %rehash
96 You can use the alias facility to acess all of $PATH. See the %rehash
98 and %rehashx functions, which automatically create aliases for the
97 and %rehashx functions, which automatically create aliases for the
99 contents of your $PATH.
98 contents of your $PATH.
100
99
101 If called with no parameters, %alias prints the current alias table."""
100 If called with no parameters, %alias prints the current alias table."""
102
101
103 par = parameter_s.strip()
102 par = parameter_s.strip()
104 if not par:
103 if not par:
105 aliases = sorted(self.shell.alias_manager.aliases)
104 aliases = sorted(self.shell.alias_manager.aliases)
106 # stored = self.shell.db.get('stored_aliases', {} )
105 # stored = self.shell.db.get('stored_aliases', {} )
107 # for k, v in stored:
106 # for k, v in stored:
108 # atab.append(k, v[0])
107 # atab.append(k, v[0])
109
108
110 print "Total number of aliases:", len(aliases)
109 print "Total number of aliases:", len(aliases)
111 sys.stdout.flush()
110 sys.stdout.flush()
112 return aliases
111 return aliases
113
112
114 # Now try to define a new one
113 # Now try to define a new one
115 try:
114 try:
116 alias,cmd = par.split(None, 1)
115 alias,cmd = par.split(None, 1)
117 except:
116 except:
118 print oinspect.getdoc(self.alias)
117 print oinspect.getdoc(self.alias)
119 else:
118 else:
120 self.shell.alias_manager.soft_define_alias(alias, cmd)
119 self.shell.alias_manager.soft_define_alias(alias, cmd)
121 # end magic_alias
120 # end magic_alias
122
121
123 @line_magic
122 @line_magic
124 def unalias(self, parameter_s=''):
123 def unalias(self, parameter_s=''):
125 """Remove an alias"""
124 """Remove an alias"""
126
125
127 aname = parameter_s.strip()
126 aname = parameter_s.strip()
128 self.shell.alias_manager.undefine_alias(aname)
127 self.shell.alias_manager.undefine_alias(aname)
129 stored = self.shell.db.get('stored_aliases', {} )
128 stored = self.shell.db.get('stored_aliases', {} )
130 if aname in stored:
129 if aname in stored:
131 print "Removing %stored alias",aname
130 print "Removing %stored alias",aname
132 del stored[aname]
131 del stored[aname]
133 self.shell.db['stored_aliases'] = stored
132 self.shell.db['stored_aliases'] = stored
134
133
135 @line_magic
134 @line_magic
136 def rehashx(self, parameter_s=''):
135 def rehashx(self, parameter_s=''):
137 """Update the alias table with all executable files in $PATH.
136 """Update the alias table with all executable files in $PATH.
138
137
139 This version explicitly checks that every entry in $PATH is a file
138 This version explicitly checks that every entry in $PATH is a file
140 with execute access (os.X_OK), so it is much slower than %rehash.
139 with execute access (os.X_OK), so it is much slower than %rehash.
141
140
142 Under Windows, it checks executability as a match against a
141 Under Windows, it checks executability as a match against a
143 '|'-separated string of extensions, stored in the IPython config
142 '|'-separated string of extensions, stored in the IPython config
144 variable win_exec_ext. This defaults to 'exe|com|bat'.
143 variable win_exec_ext. This defaults to 'exe|com|bat'.
145
144
146 This function also resets the root module cache of module completer,
145 This function also resets the root module cache of module completer,
147 used on slow filesystems.
146 used on slow filesystems.
148 """
147 """
149 from IPython.core.alias import InvalidAliasError
148 from IPython.core.alias import InvalidAliasError
150
149
151 # for the benefit of module completer in ipy_completers.py
150 # for the benefit of module completer in ipy_completers.py
152 del self.shell.db['rootmodules']
151 del self.shell.db['rootmodules']
153
152
154 path = [os.path.abspath(os.path.expanduser(p)) for p in
153 path = [os.path.abspath(os.path.expanduser(p)) for p in
155 os.environ.get('PATH','').split(os.pathsep)]
154 os.environ.get('PATH','').split(os.pathsep)]
156 path = filter(os.path.isdir,path)
155 path = filter(os.path.isdir,path)
157
156
158 syscmdlist = []
157 syscmdlist = []
159 # Now define isexec in a cross platform manner.
158 # Now define isexec in a cross platform manner.
160 if os.name == 'posix':
159 if os.name == 'posix':
161 isexec = lambda fname:os.path.isfile(fname) and \
160 isexec = lambda fname:os.path.isfile(fname) and \
162 os.access(fname,os.X_OK)
161 os.access(fname,os.X_OK)
163 else:
162 else:
164 try:
163 try:
165 winext = os.environ['pathext'].replace(';','|').replace('.','')
164 winext = os.environ['pathext'].replace(';','|').replace('.','')
166 except KeyError:
165 except KeyError:
167 winext = 'exe|com|bat|py'
166 winext = 'exe|com|bat|py'
168 if 'py' not in winext:
167 if 'py' not in winext:
169 winext += '|py'
168 winext += '|py'
170 execre = re.compile(r'(.*)\.(%s)$' % winext,re.IGNORECASE)
169 execre = re.compile(r'(.*)\.(%s)$' % winext,re.IGNORECASE)
171 isexec = lambda fname:os.path.isfile(fname) and execre.match(fname)
170 isexec = lambda fname:os.path.isfile(fname) and execre.match(fname)
172 savedir = os.getcwdu()
171 savedir = os.getcwdu()
173
172
174 # Now walk the paths looking for executables to alias.
173 # Now walk the paths looking for executables to alias.
175 try:
174 try:
176 # write the whole loop for posix/Windows so we don't have an if in
175 # write the whole loop for posix/Windows so we don't have an if in
177 # the innermost part
176 # the innermost part
178 if os.name == 'posix':
177 if os.name == 'posix':
179 for pdir in path:
178 for pdir in path:
180 os.chdir(pdir)
179 os.chdir(pdir)
181 for ff in os.listdir(pdir):
180 for ff in os.listdir(pdir):
182 if isexec(ff):
181 if isexec(ff):
183 try:
182 try:
184 # Removes dots from the name since ipython
183 # Removes dots from the name since ipython
185 # will assume names with dots to be python.
184 # will assume names with dots to be python.
186 self.shell.alias_manager.define_alias(
185 self.shell.alias_manager.define_alias(
187 ff.replace('.',''), ff)
186 ff.replace('.',''), ff)
188 except InvalidAliasError:
187 except InvalidAliasError:
189 pass
188 pass
190 else:
189 else:
191 syscmdlist.append(ff)
190 syscmdlist.append(ff)
192 else:
191 else:
193 no_alias = self.shell.alias_manager.no_alias
192 no_alias = self.shell.alias_manager.no_alias
194 for pdir in path:
193 for pdir in path:
195 os.chdir(pdir)
194 os.chdir(pdir)
196 for ff in os.listdir(pdir):
195 for ff in os.listdir(pdir):
197 base, ext = os.path.splitext(ff)
196 base, ext = os.path.splitext(ff)
198 if isexec(ff) and base.lower() not in no_alias:
197 if isexec(ff) and base.lower() not in no_alias:
199 if ext.lower() == '.exe':
198 if ext.lower() == '.exe':
200 ff = base
199 ff = base
201 try:
200 try:
202 # Removes dots from the name since ipython
201 # Removes dots from the name since ipython
203 # will assume names with dots to be python.
202 # will assume names with dots to be python.
204 self.shell.alias_manager.define_alias(
203 self.shell.alias_manager.define_alias(
205 base.lower().replace('.',''), ff)
204 base.lower().replace('.',''), ff)
206 except InvalidAliasError:
205 except InvalidAliasError:
207 pass
206 pass
208 syscmdlist.append(ff)
207 syscmdlist.append(ff)
209 self.shell.db['syscmdlist'] = syscmdlist
208 self.shell.db['syscmdlist'] = syscmdlist
210 finally:
209 finally:
211 os.chdir(savedir)
210 os.chdir(savedir)
212
211
213 @skip_doctest
212 @skip_doctest
214 @line_magic
213 @line_magic
215 def pwd(self, parameter_s=''):
214 def pwd(self, parameter_s=''):
216 """Return the current working directory path.
215 """Return the current working directory path.
217
216
218 Examples
217 Examples
219 --------
218 --------
220 ::
219 ::
221
220
222 In [9]: pwd
221 In [9]: pwd
223 Out[9]: '/home/tsuser/sprint/ipython'
222 Out[9]: '/home/tsuser/sprint/ipython'
224 """
223 """
225 return os.getcwdu()
224 return os.getcwdu()
226
225
227 @skip_doctest
226 @skip_doctest
228 @line_magic
227 @line_magic
229 def cd(self, parameter_s=''):
228 def cd(self, parameter_s=''):
230 """Change the current working directory.
229 """Change the current working directory.
231
230
232 This command automatically maintains an internal list of directories
231 This command automatically maintains an internal list of directories
233 you visit during your IPython session, in the variable _dh. The
232 you visit during your IPython session, in the variable _dh. The
234 command %dhist shows this history nicely formatted. You can also
233 command %dhist shows this history nicely formatted. You can also
235 do 'cd -<tab>' to see directory history conveniently.
234 do 'cd -<tab>' to see directory history conveniently.
236
235
237 Usage:
236 Usage:
238
237
239 cd 'dir': changes to directory 'dir'.
238 cd 'dir': changes to directory 'dir'.
240
239
241 cd -: changes to the last visited directory.
240 cd -: changes to the last visited directory.
242
241
243 cd -<n>: changes to the n-th directory in the directory history.
242 cd -<n>: changes to the n-th directory in the directory history.
244
243
245 cd --foo: change to directory that matches 'foo' in history
244 cd --foo: change to directory that matches 'foo' in history
246
245
247 cd -b <bookmark_name>: jump to a bookmark set by %bookmark
246 cd -b <bookmark_name>: jump to a bookmark set by %bookmark
248 (note: cd <bookmark_name> is enough if there is no
247 (note: cd <bookmark_name> is enough if there is no
249 directory <bookmark_name>, but a bookmark with the name exists.)
248 directory <bookmark_name>, but a bookmark with the name exists.)
250 'cd -b <tab>' allows you to tab-complete bookmark names.
249 'cd -b <tab>' allows you to tab-complete bookmark names.
251
250
252 Options:
251 Options:
253
252
254 -q: quiet. Do not print the working directory after the cd command is
253 -q: quiet. Do not print the working directory after the cd command is
255 executed. By default IPython's cd command does print this directory,
254 executed. By default IPython's cd command does print this directory,
256 since the default prompts do not display path information.
255 since the default prompts do not display path information.
257
256
258 Note that !cd doesn't work for this purpose because the shell where
257 Note that !cd doesn't work for this purpose because the shell where
259 !command runs is immediately discarded after executing 'command'.
258 !command runs is immediately discarded after executing 'command'.
260
259
261 Examples
260 Examples
262 --------
261 --------
263 ::
262 ::
264
263
265 In [10]: cd parent/child
264 In [10]: cd parent/child
266 /home/tsuser/parent/child
265 /home/tsuser/parent/child
267 """
266 """
268
267
269 oldcwd = os.getcwdu()
268 oldcwd = os.getcwdu()
270 numcd = re.match(r'(-)(\d+)$',parameter_s)
269 numcd = re.match(r'(-)(\d+)$',parameter_s)
271 # jump in directory history by number
270 # jump in directory history by number
272 if numcd:
271 if numcd:
273 nn = int(numcd.group(2))
272 nn = int(numcd.group(2))
274 try:
273 try:
275 ps = self.shell.user_ns['_dh'][nn]
274 ps = self.shell.user_ns['_dh'][nn]
276 except IndexError:
275 except IndexError:
277 print 'The requested directory does not exist in history.'
276 print 'The requested directory does not exist in history.'
278 return
277 return
279 else:
278 else:
280 opts = {}
279 opts = {}
281 elif parameter_s.startswith('--'):
280 elif parameter_s.startswith('--'):
282 ps = None
281 ps = None
283 fallback = None
282 fallback = None
284 pat = parameter_s[2:]
283 pat = parameter_s[2:]
285 dh = self.shell.user_ns['_dh']
284 dh = self.shell.user_ns['_dh']
286 # first search only by basename (last component)
285 # first search only by basename (last component)
287 for ent in reversed(dh):
286 for ent in reversed(dh):
288 if pat in os.path.basename(ent) and os.path.isdir(ent):
287 if pat in os.path.basename(ent) and os.path.isdir(ent):
289 ps = ent
288 ps = ent
290 break
289 break
291
290
292 if fallback is None and pat in ent and os.path.isdir(ent):
291 if fallback is None and pat in ent and os.path.isdir(ent):
293 fallback = ent
292 fallback = ent
294
293
295 # if we have no last part match, pick the first full path match
294 # if we have no last part match, pick the first full path match
296 if ps is None:
295 if ps is None:
297 ps = fallback
296 ps = fallback
298
297
299 if ps is None:
298 if ps is None:
300 print "No matching entry in directory history"
299 print "No matching entry in directory history"
301 return
300 return
302 else:
301 else:
303 opts = {}
302 opts = {}
304
303
305
304
306 else:
305 else:
307 #turn all non-space-escaping backslashes to slashes,
306 #turn all non-space-escaping backslashes to slashes,
308 # for c:\windows\directory\names\
307 # for c:\windows\directory\names\
309 parameter_s = re.sub(r'\\(?! )','/', parameter_s)
308 parameter_s = re.sub(r'\\(?! )','/', parameter_s)
310 opts,ps = self.parse_options(parameter_s,'qb',mode='string')
309 opts,ps = self.parse_options(parameter_s,'qb',mode='string')
311 # jump to previous
310 # jump to previous
312 if ps == '-':
311 if ps == '-':
313 try:
312 try:
314 ps = self.shell.user_ns['_dh'][-2]
313 ps = self.shell.user_ns['_dh'][-2]
315 except IndexError:
314 except IndexError:
316 raise UsageError('%cd -: No previous directory to change to.')
315 raise UsageError('%cd -: No previous directory to change to.')
317 # jump to bookmark if needed
316 # jump to bookmark if needed
318 else:
317 else:
319 if not os.path.isdir(ps) or 'b' in opts:
318 if not os.path.isdir(ps) or 'b' in opts:
320 bkms = self.shell.db.get('bookmarks', {})
319 bkms = self.shell.db.get('bookmarks', {})
321
320
322 if ps in bkms:
321 if ps in bkms:
323 target = bkms[ps]
322 target = bkms[ps]
324 print '(bookmark:%s) -> %s' % (ps, target)
323 print '(bookmark:%s) -> %s' % (ps, target)
325 ps = target
324 ps = target
326 else:
325 else:
327 if 'b' in opts:
326 if 'b' in opts:
328 raise UsageError("Bookmark '%s' not found. "
327 raise UsageError("Bookmark '%s' not found. "
329 "Use '%%bookmark -l' to see your bookmarks." % ps)
328 "Use '%%bookmark -l' to see your bookmarks." % ps)
330
329
331 # strip extra quotes on Windows, because os.chdir doesn't like them
330 # strip extra quotes on Windows, because os.chdir doesn't like them
332 ps = unquote_filename(ps)
331 ps = unquote_filename(ps)
333 # at this point ps should point to the target dir
332 # at this point ps should point to the target dir
334 if ps:
333 if ps:
335 try:
334 try:
336 os.chdir(os.path.expanduser(ps))
335 os.chdir(os.path.expanduser(ps))
337 if hasattr(self.shell, 'term_title') and self.shell.term_title:
336 if hasattr(self.shell, 'term_title') and self.shell.term_title:
338 set_term_title('IPython: ' + abbrev_cwd())
337 set_term_title('IPython: ' + abbrev_cwd())
339 except OSError:
338 except OSError:
340 print sys.exc_info()[1]
339 print sys.exc_info()[1]
341 else:
340 else:
342 cwd = os.getcwdu()
341 cwd = os.getcwdu()
343 dhist = self.shell.user_ns['_dh']
342 dhist = self.shell.user_ns['_dh']
344 if oldcwd != cwd:
343 if oldcwd != cwd:
345 dhist.append(cwd)
344 dhist.append(cwd)
346 self.shell.db['dhist'] = compress_dhist(dhist)[-100:]
345 self.shell.db['dhist'] = compress_dhist(dhist)[-100:]
347
346
348 else:
347 else:
349 os.chdir(self.shell.home_dir)
348 os.chdir(self.shell.home_dir)
350 if hasattr(self.shell, 'term_title') and self.shell.term_title:
349 if hasattr(self.shell, 'term_title') and self.shell.term_title:
351 set_term_title('IPython: ' + '~')
350 set_term_title('IPython: ' + '~')
352 cwd = os.getcwdu()
351 cwd = os.getcwdu()
353 dhist = self.shell.user_ns['_dh']
352 dhist = self.shell.user_ns['_dh']
354
353
355 if oldcwd != cwd:
354 if oldcwd != cwd:
356 dhist.append(cwd)
355 dhist.append(cwd)
357 self.shell.db['dhist'] = compress_dhist(dhist)[-100:]
356 self.shell.db['dhist'] = compress_dhist(dhist)[-100:]
358 if not 'q' in opts and self.shell.user_ns['_dh']:
357 if not 'q' in opts and self.shell.user_ns['_dh']:
359 print self.shell.user_ns['_dh'][-1]
358 print self.shell.user_ns['_dh'][-1]
360
359
361
360
362 @line_magic
361 @line_magic
363 def env(self, parameter_s=''):
362 def env(self, parameter_s=''):
364 """List environment variables."""
363 """List environment variables."""
365
364
366 return dict(os.environ)
365 return dict(os.environ)
367
366
368 @line_magic
367 @line_magic
369 def pushd(self, parameter_s=''):
368 def pushd(self, parameter_s=''):
370 """Place the current dir on stack and change directory.
369 """Place the current dir on stack and change directory.
371
370
372 Usage:\\
371 Usage:\\
373 %pushd ['dirname']
372 %pushd ['dirname']
374 """
373 """
375
374
376 dir_s = self.shell.dir_stack
375 dir_s = self.shell.dir_stack
377 tgt = os.path.expanduser(unquote_filename(parameter_s))
376 tgt = os.path.expanduser(unquote_filename(parameter_s))
378 cwd = os.getcwdu().replace(self.shell.home_dir,'~')
377 cwd = os.getcwdu().replace(self.shell.home_dir,'~')
379 if tgt:
378 if tgt:
380 self.cd(parameter_s)
379 self.cd(parameter_s)
381 dir_s.insert(0,cwd)
380 dir_s.insert(0,cwd)
382 return self.shell.magic('dirs')
381 return self.shell.magic('dirs')
383
382
384 @line_magic
383 @line_magic
385 def popd(self, parameter_s=''):
384 def popd(self, parameter_s=''):
386 """Change to directory popped off the top of the stack.
385 """Change to directory popped off the top of the stack.
387 """
386 """
388 if not self.shell.dir_stack:
387 if not self.shell.dir_stack:
389 raise UsageError("%popd on empty stack")
388 raise UsageError("%popd on empty stack")
390 top = self.shell.dir_stack.pop(0)
389 top = self.shell.dir_stack.pop(0)
391 self.cd(top)
390 self.cd(top)
392 print "popd ->",top
391 print "popd ->",top
393
392
394 @line_magic
393 @line_magic
395 def dirs(self, parameter_s=''):
394 def dirs(self, parameter_s=''):
396 """Return the current directory stack."""
395 """Return the current directory stack."""
397
396
398 return self.shell.dir_stack
397 return self.shell.dir_stack
399
398
400 @line_magic
399 @line_magic
401 def dhist(self, parameter_s=''):
400 def dhist(self, parameter_s=''):
402 """Print your history of visited directories.
401 """Print your history of visited directories.
403
402
404 %dhist -> print full history\\
403 %dhist -> print full history\\
405 %dhist n -> print last n entries only\\
404 %dhist n -> print last n entries only\\
406 %dhist n1 n2 -> print entries between n1 and n2 (n1 not included)\\
405 %dhist n1 n2 -> print entries between n1 and n2 (n2 not included)\\
407
406
408 This history is automatically maintained by the %cd command, and
407 This history is automatically maintained by the %cd command, and
409 always available as the global list variable _dh. You can use %cd -<n>
408 always available as the global list variable _dh. You can use %cd -<n>
410 to go to directory number <n>.
409 to go to directory number <n>.
411
410
412 Note that most of time, you should view directory history by entering
411 Note that most of time, you should view directory history by entering
413 cd -<TAB>.
412 cd -<TAB>.
414
413
415 """
414 """
416
415
417 dh = self.shell.user_ns['_dh']
416 dh = self.shell.user_ns['_dh']
418 if parameter_s:
417 if parameter_s:
419 try:
418 try:
420 args = map(int,parameter_s.split())
419 args = map(int,parameter_s.split())
421 except:
420 except:
422 self.arg_err(self.dhist)
421 self.arg_err(self.dhist)
423 return
422 return
424 if len(args) == 1:
423 if len(args) == 1:
425 ini,fin = max(len(dh)-(args[0]),0),len(dh)
424 ini,fin = max(len(dh)-(args[0]),0),len(dh)
426 elif len(args) == 2:
425 elif len(args) == 2:
427 ini,fin = args
426 ini,fin = args
427 fin = min(fin, len(dh))
428 else:
428 else:
429 self.arg_err(self.dhist)
429 self.arg_err(self.dhist)
430 return
430 return
431 else:
431 else:
432 ini,fin = 0,len(dh)
432 ini,fin = 0,len(dh)
433 nlprint(dh,
433 print 'Directory history (kept in _dh)'
434 header = 'Directory history (kept in _dh)',
434 for i in range(ini, fin):
435 start=ini,stop=fin)
435 print "%d: %s" % (i, dh[i])
436
436
437 @skip_doctest
437 @skip_doctest
438 @line_magic
438 @line_magic
439 def sc(self, parameter_s=''):
439 def sc(self, parameter_s=''):
440 """Shell capture - run shell command and capture output (DEPRECATED use !).
440 """Shell capture - run shell command and capture output (DEPRECATED use !).
441
441
442 DEPRECATED. Suboptimal, retained for backwards compatibility.
442 DEPRECATED. Suboptimal, retained for backwards compatibility.
443
443
444 You should use the form 'var = !command' instead. Example:
444 You should use the form 'var = !command' instead. Example:
445
445
446 "%sc -l myfiles = ls ~" should now be written as
446 "%sc -l myfiles = ls ~" should now be written as
447
447
448 "myfiles = !ls ~"
448 "myfiles = !ls ~"
449
449
450 myfiles.s, myfiles.l and myfiles.n still apply as documented
450 myfiles.s, myfiles.l and myfiles.n still apply as documented
451 below.
451 below.
452
452
453 --
453 --
454 %sc [options] varname=command
454 %sc [options] varname=command
455
455
456 IPython will run the given command using commands.getoutput(), and
456 IPython will run the given command using commands.getoutput(), and
457 will then update the user's interactive namespace with a variable
457 will then update the user's interactive namespace with a variable
458 called varname, containing the value of the call. Your command can
458 called varname, containing the value of the call. Your command can
459 contain shell wildcards, pipes, etc.
459 contain shell wildcards, pipes, etc.
460
460
461 The '=' sign in the syntax is mandatory, and the variable name you
461 The '=' sign in the syntax is mandatory, and the variable name you
462 supply must follow Python's standard conventions for valid names.
462 supply must follow Python's standard conventions for valid names.
463
463
464 (A special format without variable name exists for internal use)
464 (A special format without variable name exists for internal use)
465
465
466 Options:
466 Options:
467
467
468 -l: list output. Split the output on newlines into a list before
468 -l: list output. Split the output on newlines into a list before
469 assigning it to the given variable. By default the output is stored
469 assigning it to the given variable. By default the output is stored
470 as a single string.
470 as a single string.
471
471
472 -v: verbose. Print the contents of the variable.
472 -v: verbose. Print the contents of the variable.
473
473
474 In most cases you should not need to split as a list, because the
474 In most cases you should not need to split as a list, because the
475 returned value is a special type of string which can automatically
475 returned value is a special type of string which can automatically
476 provide its contents either as a list (split on newlines) or as a
476 provide its contents either as a list (split on newlines) or as a
477 space-separated string. These are convenient, respectively, either
477 space-separated string. These are convenient, respectively, either
478 for sequential processing or to be passed to a shell command.
478 for sequential processing or to be passed to a shell command.
479
479
480 For example::
480 For example::
481
481
482 # Capture into variable a
482 # Capture into variable a
483 In [1]: sc a=ls *py
483 In [1]: sc a=ls *py
484
484
485 # a is a string with embedded newlines
485 # a is a string with embedded newlines
486 In [2]: a
486 In [2]: a
487 Out[2]: 'setup.py\\nwin32_manual_post_install.py'
487 Out[2]: 'setup.py\\nwin32_manual_post_install.py'
488
488
489 # which can be seen as a list:
489 # which can be seen as a list:
490 In [3]: a.l
490 In [3]: a.l
491 Out[3]: ['setup.py', 'win32_manual_post_install.py']
491 Out[3]: ['setup.py', 'win32_manual_post_install.py']
492
492
493 # or as a whitespace-separated string:
493 # or as a whitespace-separated string:
494 In [4]: a.s
494 In [4]: a.s
495 Out[4]: 'setup.py win32_manual_post_install.py'
495 Out[4]: 'setup.py win32_manual_post_install.py'
496
496
497 # a.s is useful to pass as a single command line:
497 # a.s is useful to pass as a single command line:
498 In [5]: !wc -l $a.s
498 In [5]: !wc -l $a.s
499 146 setup.py
499 146 setup.py
500 130 win32_manual_post_install.py
500 130 win32_manual_post_install.py
501 276 total
501 276 total
502
502
503 # while the list form is useful to loop over:
503 # while the list form is useful to loop over:
504 In [6]: for f in a.l:
504 In [6]: for f in a.l:
505 ...: !wc -l $f
505 ...: !wc -l $f
506 ...:
506 ...:
507 146 setup.py
507 146 setup.py
508 130 win32_manual_post_install.py
508 130 win32_manual_post_install.py
509
509
510 Similarly, the lists returned by the -l option are also special, in
510 Similarly, the lists returned by the -l option are also special, in
511 the sense that you can equally invoke the .s attribute on them to
511 the sense that you can equally invoke the .s attribute on them to
512 automatically get a whitespace-separated string from their contents::
512 automatically get a whitespace-separated string from their contents::
513
513
514 In [7]: sc -l b=ls *py
514 In [7]: sc -l b=ls *py
515
515
516 In [8]: b
516 In [8]: b
517 Out[8]: ['setup.py', 'win32_manual_post_install.py']
517 Out[8]: ['setup.py', 'win32_manual_post_install.py']
518
518
519 In [9]: b.s
519 In [9]: b.s
520 Out[9]: 'setup.py win32_manual_post_install.py'
520 Out[9]: 'setup.py win32_manual_post_install.py'
521
521
522 In summary, both the lists and strings used for output capture have
522 In summary, both the lists and strings used for output capture have
523 the following special attributes::
523 the following special attributes::
524
524
525 .l (or .list) : value as list.
525 .l (or .list) : value as list.
526 .n (or .nlstr): value as newline-separated string.
526 .n (or .nlstr): value as newline-separated string.
527 .s (or .spstr): value as space-separated string.
527 .s (or .spstr): value as space-separated string.
528 """
528 """
529
529
530 opts,args = self.parse_options(parameter_s, 'lv')
530 opts,args = self.parse_options(parameter_s, 'lv')
531 # Try to get a variable name and command to run
531 # Try to get a variable name and command to run
532 try:
532 try:
533 # the variable name must be obtained from the parse_options
533 # the variable name must be obtained from the parse_options
534 # output, which uses shlex.split to strip options out.
534 # output, which uses shlex.split to strip options out.
535 var,_ = args.split('=', 1)
535 var,_ = args.split('=', 1)
536 var = var.strip()
536 var = var.strip()
537 # But the command has to be extracted from the original input
537 # But the command has to be extracted from the original input
538 # parameter_s, not on what parse_options returns, to avoid the
538 # parameter_s, not on what parse_options returns, to avoid the
539 # quote stripping which shlex.split performs on it.
539 # quote stripping which shlex.split performs on it.
540 _,cmd = parameter_s.split('=', 1)
540 _,cmd = parameter_s.split('=', 1)
541 except ValueError:
541 except ValueError:
542 var,cmd = '',''
542 var,cmd = '',''
543 # If all looks ok, proceed
543 # If all looks ok, proceed
544 split = 'l' in opts
544 split = 'l' in opts
545 out = self.shell.getoutput(cmd, split=split)
545 out = self.shell.getoutput(cmd, split=split)
546 if 'v' in opts:
546 if 'v' in opts:
547 print '%s ==\n%s' % (var, pformat(out))
547 print '%s ==\n%s' % (var, pformat(out))
548 if var:
548 if var:
549 self.shell.user_ns.update({var:out})
549 self.shell.user_ns.update({var:out})
550 else:
550 else:
551 return out
551 return out
552
552
553 @line_cell_magic
553 @line_cell_magic
554 def sx(self, line='', cell=None):
554 def sx(self, line='', cell=None):
555 """Shell execute - run shell command and capture output (!! is short-hand).
555 """Shell execute - run shell command and capture output (!! is short-hand).
556
556
557 %sx command
557 %sx command
558
558
559 IPython will run the given command using commands.getoutput(), and
559 IPython will run the given command using commands.getoutput(), and
560 return the result formatted as a list (split on '\\n'). Since the
560 return the result formatted as a list (split on '\\n'). Since the
561 output is _returned_, it will be stored in ipython's regular output
561 output is _returned_, it will be stored in ipython's regular output
562 cache Out[N] and in the '_N' automatic variables.
562 cache Out[N] and in the '_N' automatic variables.
563
563
564 Notes:
564 Notes:
565
565
566 1) If an input line begins with '!!', then %sx is automatically
566 1) If an input line begins with '!!', then %sx is automatically
567 invoked. That is, while::
567 invoked. That is, while::
568
568
569 !ls
569 !ls
570
570
571 causes ipython to simply issue system('ls'), typing::
571 causes ipython to simply issue system('ls'), typing::
572
572
573 !!ls
573 !!ls
574
574
575 is a shorthand equivalent to::
575 is a shorthand equivalent to::
576
576
577 %sx ls
577 %sx ls
578
578
579 2) %sx differs from %sc in that %sx automatically splits into a list,
579 2) %sx differs from %sc in that %sx automatically splits into a list,
580 like '%sc -l'. The reason for this is to make it as easy as possible
580 like '%sc -l'. The reason for this is to make it as easy as possible
581 to process line-oriented shell output via further python commands.
581 to process line-oriented shell output via further python commands.
582 %sc is meant to provide much finer control, but requires more
582 %sc is meant to provide much finer control, but requires more
583 typing.
583 typing.
584
584
585 3) Just like %sc -l, this is a list with special attributes:
585 3) Just like %sc -l, this is a list with special attributes:
586 ::
586 ::
587
587
588 .l (or .list) : value as list.
588 .l (or .list) : value as list.
589 .n (or .nlstr): value as newline-separated string.
589 .n (or .nlstr): value as newline-separated string.
590 .s (or .spstr): value as whitespace-separated string.
590 .s (or .spstr): value as whitespace-separated string.
591
591
592 This is very useful when trying to use such lists as arguments to
592 This is very useful when trying to use such lists as arguments to
593 system commands."""
593 system commands."""
594
594
595 if cell is None:
595 if cell is None:
596 # line magic
596 # line magic
597 return self.shell.getoutput(line)
597 return self.shell.getoutput(line)
598 else:
598 else:
599 opts,args = self.parse_options(line, '', 'out=')
599 opts,args = self.parse_options(line, '', 'out=')
600 output = self.shell.getoutput(cell)
600 output = self.shell.getoutput(cell)
601 out_name = opts.get('out', opts.get('o'))
601 out_name = opts.get('out', opts.get('o'))
602 if out_name:
602 if out_name:
603 self.shell.user_ns[out_name] = output
603 self.shell.user_ns[out_name] = output
604 else:
604 else:
605 return output
605 return output
606
606
607 system = line_cell_magic('system')(sx)
607 system = line_cell_magic('system')(sx)
608 bang = cell_magic('!')(sx)
608 bang = cell_magic('!')(sx)
609
609
610 @line_magic
610 @line_magic
611 def bookmark(self, parameter_s=''):
611 def bookmark(self, parameter_s=''):
612 """Manage IPython's bookmark system.
612 """Manage IPython's bookmark system.
613
613
614 %bookmark <name> - set bookmark to current dir
614 %bookmark <name> - set bookmark to current dir
615 %bookmark <name> <dir> - set bookmark to <dir>
615 %bookmark <name> <dir> - set bookmark to <dir>
616 %bookmark -l - list all bookmarks
616 %bookmark -l - list all bookmarks
617 %bookmark -d <name> - remove bookmark
617 %bookmark -d <name> - remove bookmark
618 %bookmark -r - remove all bookmarks
618 %bookmark -r - remove all bookmarks
619
619
620 You can later on access a bookmarked folder with::
620 You can later on access a bookmarked folder with::
621
621
622 %cd -b <name>
622 %cd -b <name>
623
623
624 or simply '%cd <name>' if there is no directory called <name> AND
624 or simply '%cd <name>' if there is no directory called <name> AND
625 there is such a bookmark defined.
625 there is such a bookmark defined.
626
626
627 Your bookmarks persist through IPython sessions, but they are
627 Your bookmarks persist through IPython sessions, but they are
628 associated with each profile."""
628 associated with each profile."""
629
629
630 opts,args = self.parse_options(parameter_s,'drl',mode='list')
630 opts,args = self.parse_options(parameter_s,'drl',mode='list')
631 if len(args) > 2:
631 if len(args) > 2:
632 raise UsageError("%bookmark: too many arguments")
632 raise UsageError("%bookmark: too many arguments")
633
633
634 bkms = self.shell.db.get('bookmarks',{})
634 bkms = self.shell.db.get('bookmarks',{})
635
635
636 if 'd' in opts:
636 if 'd' in opts:
637 try:
637 try:
638 todel = args[0]
638 todel = args[0]
639 except IndexError:
639 except IndexError:
640 raise UsageError(
640 raise UsageError(
641 "%bookmark -d: must provide a bookmark to delete")
641 "%bookmark -d: must provide a bookmark to delete")
642 else:
642 else:
643 try:
643 try:
644 del bkms[todel]
644 del bkms[todel]
645 except KeyError:
645 except KeyError:
646 raise UsageError(
646 raise UsageError(
647 "%%bookmark -d: Can't delete bookmark '%s'" % todel)
647 "%%bookmark -d: Can't delete bookmark '%s'" % todel)
648
648
649 elif 'r' in opts:
649 elif 'r' in opts:
650 bkms = {}
650 bkms = {}
651 elif 'l' in opts:
651 elif 'l' in opts:
652 bks = bkms.keys()
652 bks = bkms.keys()
653 bks.sort()
653 bks.sort()
654 if bks:
654 if bks:
655 size = max(map(len, bks))
655 size = max(map(len, bks))
656 else:
656 else:
657 size = 0
657 size = 0
658 fmt = '%-'+str(size)+'s -> %s'
658 fmt = '%-'+str(size)+'s -> %s'
659 print 'Current bookmarks:'
659 print 'Current bookmarks:'
660 for bk in bks:
660 for bk in bks:
661 print fmt % (bk, bkms[bk])
661 print fmt % (bk, bkms[bk])
662 else:
662 else:
663 if not args:
663 if not args:
664 raise UsageError("%bookmark: You must specify the bookmark name")
664 raise UsageError("%bookmark: You must specify the bookmark name")
665 elif len(args)==1:
665 elif len(args)==1:
666 bkms[args[0]] = os.getcwdu()
666 bkms[args[0]] = os.getcwdu()
667 elif len(args)==2:
667 elif len(args)==2:
668 bkms[args[0]] = args[1]
668 bkms[args[0]] = args[1]
669 self.shell.db['bookmarks'] = bkms
669 self.shell.db['bookmarks'] = bkms
670
670
671 @line_magic
671 @line_magic
672 def pycat(self, parameter_s=''):
672 def pycat(self, parameter_s=''):
673 """Show a syntax-highlighted file through a pager.
673 """Show a syntax-highlighted file through a pager.
674
674
675 This magic is similar to the cat utility, but it will assume the file
675 This magic is similar to the cat utility, but it will assume the file
676 to be Python source and will show it with syntax highlighting.
676 to be Python source and will show it with syntax highlighting.
677
677
678 This magic command can either take a local filename, an url,
678 This magic command can either take a local filename, an url,
679 an history range (see %history) or a macro as argument ::
679 an history range (see %history) or a macro as argument ::
680
680
681 %pycat myscript.py
681 %pycat myscript.py
682 %pycat 7-27
682 %pycat 7-27
683 %pycat myMacro
683 %pycat myMacro
684 %pycat http://www.example.com/myscript.py
684 %pycat http://www.example.com/myscript.py
685 """
685 """
686 if not parameter_s:
686 if not parameter_s:
687 raise UsageError('Missing filename, URL, input history range, '
687 raise UsageError('Missing filename, URL, input history range, '
688 'or macro.')
688 'or macro.')
689
689
690 try :
690 try :
691 cont = self.shell.find_user_code(parameter_s, skip_encoding_cookie=False)
691 cont = self.shell.find_user_code(parameter_s, skip_encoding_cookie=False)
692 except (ValueError, IOError):
692 except (ValueError, IOError):
693 print "Error: no such file, variable, URL, history range or macro"
693 print "Error: no such file, variable, URL, history range or macro"
694 return
694 return
695
695
696 page.page(self.shell.pycolorize(source_to_unicode(cont)))
696 page.page(self.shell.pycolorize(source_to_unicode(cont)))
697
697
698 @magic_arguments.magic_arguments()
698 @magic_arguments.magic_arguments()
699 @magic_arguments.argument(
699 @magic_arguments.argument(
700 '-a', '--amend', action='store_true', default=False,
700 '-a', '--amend', action='store_true', default=False,
701 help='Open file for amending if it exists'
701 help='Open file for amending if it exists'
702 )
702 )
703 @magic_arguments.argument(
703 @magic_arguments.argument(
704 'filename', type=unicode,
704 'filename', type=unicode,
705 help='file to write'
705 help='file to write'
706 )
706 )
707 @cell_magic
707 @cell_magic
708 def file(self, line, cell):
708 def file(self, line, cell):
709 """Write the contents of the cell to a file.
709 """Write the contents of the cell to a file.
710
710
711 For frontends that do not support stdin (Notebook), -f is implied.
711 For frontends that do not support stdin (Notebook), -f is implied.
712 """
712 """
713 args = magic_arguments.parse_argstring(self.file, line)
713 args = magic_arguments.parse_argstring(self.file, line)
714 filename = unquote_filename(args.filename)
714 filename = unquote_filename(args.filename)
715
715
716 if os.path.exists(filename):
716 if os.path.exists(filename):
717 if args.amend:
717 if args.amend:
718 print "Amending to %s" % filename
718 print "Amending to %s" % filename
719 else:
719 else:
720 print "Overwriting %s" % filename
720 print "Overwriting %s" % filename
721 else:
721 else:
722 print "Writing %s" % filename
722 print "Writing %s" % filename
723
723
724 mode = 'a' if args.amend else 'w'
724 mode = 'a' if args.amend else 'w'
725 with io.open(filename, mode, encoding='utf-8') as f:
725 with io.open(filename, mode, encoding='utf-8') as f:
726 f.write(cell)
726 f.write(cell)
@@ -1,1246 +1,1246 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """
2 """
3 ultratb.py -- Spice up your tracebacks!
3 ultratb.py -- Spice up your tracebacks!
4
4
5 * ColorTB
5 * ColorTB
6 I've always found it a bit hard to visually parse tracebacks in Python. The
6 I've always found it a bit hard to visually parse tracebacks in Python. The
7 ColorTB class is a solution to that problem. It colors the different parts of a
7 ColorTB class is a solution to that problem. It colors the different parts of a
8 traceback in a manner similar to what you would expect from a syntax-highlighting
8 traceback in a manner similar to what you would expect from a syntax-highlighting
9 text editor.
9 text editor.
10
10
11 Installation instructions for ColorTB:
11 Installation instructions for ColorTB:
12 import sys,ultratb
12 import sys,ultratb
13 sys.excepthook = ultratb.ColorTB()
13 sys.excepthook = ultratb.ColorTB()
14
14
15 * VerboseTB
15 * VerboseTB
16 I've also included a port of Ka-Ping Yee's "cgitb.py" that produces all kinds
16 I've also included a port of Ka-Ping Yee's "cgitb.py" that produces all kinds
17 of useful info when a traceback occurs. Ping originally had it spit out HTML
17 of useful info when a traceback occurs. Ping originally had it spit out HTML
18 and intended it for CGI programmers, but why should they have all the fun? I
18 and intended it for CGI programmers, but why should they have all the fun? I
19 altered it to spit out colored text to the terminal. It's a bit overwhelming,
19 altered it to spit out colored text to the terminal. It's a bit overwhelming,
20 but kind of neat, and maybe useful for long-running programs that you believe
20 but kind of neat, and maybe useful for long-running programs that you believe
21 are bug-free. If a crash *does* occur in that type of program you want details.
21 are bug-free. If a crash *does* occur in that type of program you want details.
22 Give it a shot--you'll love it or you'll hate it.
22 Give it a shot--you'll love it or you'll hate it.
23
23
24 Note:
24 Note:
25
25
26 The Verbose mode prints the variables currently visible where the exception
26 The Verbose mode prints the variables currently visible where the exception
27 happened (shortening their strings if too long). This can potentially be
27 happened (shortening their strings if too long). This can potentially be
28 very slow, if you happen to have a huge data structure whose string
28 very slow, if you happen to have a huge data structure whose string
29 representation is complex to compute. Your computer may appear to freeze for
29 representation is complex to compute. Your computer may appear to freeze for
30 a while with cpu usage at 100%. If this occurs, you can cancel the traceback
30 a while with cpu usage at 100%. If this occurs, you can cancel the traceback
31 with Ctrl-C (maybe hitting it more than once).
31 with Ctrl-C (maybe hitting it more than once).
32
32
33 If you encounter this kind of situation often, you may want to use the
33 If you encounter this kind of situation often, you may want to use the
34 Verbose_novars mode instead of the regular Verbose, which avoids formatting
34 Verbose_novars mode instead of the regular Verbose, which avoids formatting
35 variables (but otherwise includes the information and context given by
35 variables (but otherwise includes the information and context given by
36 Verbose).
36 Verbose).
37
37
38
38
39 Installation instructions for ColorTB:
39 Installation instructions for ColorTB:
40 import sys,ultratb
40 import sys,ultratb
41 sys.excepthook = ultratb.VerboseTB()
41 sys.excepthook = ultratb.VerboseTB()
42
42
43 Note: Much of the code in this module was lifted verbatim from the standard
43 Note: Much of the code in this module was lifted verbatim from the standard
44 library module 'traceback.py' and Ka-Ping Yee's 'cgitb.py'.
44 library module 'traceback.py' and Ka-Ping Yee's 'cgitb.py'.
45
45
46 * Color schemes
46 * Color schemes
47 The colors are defined in the class TBTools through the use of the
47 The colors are defined in the class TBTools through the use of the
48 ColorSchemeTable class. Currently the following exist:
48 ColorSchemeTable class. Currently the following exist:
49
49
50 - NoColor: allows all of this module to be used in any terminal (the color
50 - NoColor: allows all of this module to be used in any terminal (the color
51 escapes are just dummy blank strings).
51 escapes are just dummy blank strings).
52
52
53 - Linux: is meant to look good in a terminal like the Linux console (black
53 - Linux: is meant to look good in a terminal like the Linux console (black
54 or very dark background).
54 or very dark background).
55
55
56 - LightBG: similar to Linux but swaps dark/light colors to be more readable
56 - LightBG: similar to Linux but swaps dark/light colors to be more readable
57 in light background terminals.
57 in light background terminals.
58
58
59 You can implement other color schemes easily, the syntax is fairly
59 You can implement other color schemes easily, the syntax is fairly
60 self-explanatory. Please send back new schemes you develop to the author for
60 self-explanatory. Please send back new schemes you develop to the author for
61 possible inclusion in future releases.
61 possible inclusion in future releases.
62
62
63 Inheritance diagram:
63 Inheritance diagram:
64
64
65 .. inheritance-diagram:: IPython.core.ultratb
65 .. inheritance-diagram:: IPython.core.ultratb
66 :parts: 3
66 :parts: 3
67 """
67 """
68
68
69 #*****************************************************************************
69 #*****************************************************************************
70 # Copyright (C) 2001 Nathaniel Gray <n8gray@caltech.edu>
70 # Copyright (C) 2001 Nathaniel Gray <n8gray@caltech.edu>
71 # Copyright (C) 2001-2004 Fernando Perez <fperez@colorado.edu>
71 # Copyright (C) 2001-2004 Fernando Perez <fperez@colorado.edu>
72 #
72 #
73 # Distributed under the terms of the BSD License. The full license is in
73 # Distributed under the terms of the BSD License. The full license is in
74 # the file COPYING, distributed as part of this software.
74 # the file COPYING, distributed as part of this software.
75 #*****************************************************************************
75 #*****************************************************************************
76
76
77 from __future__ import unicode_literals
77 from __future__ import unicode_literals
78
78
79 import inspect
79 import inspect
80 import keyword
80 import keyword
81 import linecache
81 import linecache
82 import os
82 import os
83 import pydoc
83 import pydoc
84 import re
84 import re
85 import sys
85 import sys
86 import time
86 import time
87 import tokenize
87 import tokenize
88 import traceback
88 import traceback
89 import types
89 import types
90
90
91 try: # Python 2
91 try: # Python 2
92 generate_tokens = tokenize.generate_tokens
92 generate_tokens = tokenize.generate_tokens
93 except AttributeError: # Python 3
93 except AttributeError: # Python 3
94 generate_tokens = tokenize.tokenize
94 generate_tokens = tokenize.tokenize
95
95
96 # For purposes of monkeypatching inspect to fix a bug in it.
96 # For purposes of monkeypatching inspect to fix a bug in it.
97 from inspect import getsourcefile, getfile, getmodule,\
97 from inspect import getsourcefile, getfile, getmodule,\
98 ismodule, isclass, ismethod, isfunction, istraceback, isframe, iscode
98 ismodule, isclass, ismethod, isfunction, istraceback, isframe, iscode
99
99
100 # IPython's own modules
100 # IPython's own modules
101 # Modified pdb which doesn't damage IPython's readline handling
101 # Modified pdb which doesn't damage IPython's readline handling
102 from IPython.core import debugger, ipapi
102 from IPython.core import debugger, ipapi
103 from IPython.core.display_trap import DisplayTrap
103 from IPython.core.display_trap import DisplayTrap
104 from IPython.core.excolors import exception_colors
104 from IPython.core.excolors import exception_colors
105 from IPython.utils import PyColorize
105 from IPython.utils import PyColorize
106 from IPython.utils import io
106 from IPython.utils import io
107 from IPython.utils import openpy
107 from IPython.utils import path as util_path
108 from IPython.utils import path as util_path
108 from IPython.utils import py3compat
109 from IPython.utils import py3compat
109 from IPython.utils import pyfile
110 from IPython.utils import ulinecache
110 from IPython.utils import ulinecache
111 from IPython.utils.data import uniq_stable
111 from IPython.utils.data import uniq_stable
112 from IPython.utils.warn import info, error
112 from IPython.utils.warn import info, error
113
113
114 # Globals
114 # Globals
115 # amount of space to put line numbers before verbose tracebacks
115 # amount of space to put line numbers before verbose tracebacks
116 INDENT_SIZE = 8
116 INDENT_SIZE = 8
117
117
118 # Default color scheme. This is used, for example, by the traceback
118 # Default color scheme. This is used, for example, by the traceback
119 # formatter. When running in an actual IPython instance, the user's rc.colors
119 # formatter. When running in an actual IPython instance, the user's rc.colors
120 # value is used, but havinga module global makes this functionality available
120 # value is used, but havinga module global makes this functionality available
121 # to users of ultratb who are NOT running inside ipython.
121 # to users of ultratb who are NOT running inside ipython.
122 DEFAULT_SCHEME = 'NoColor'
122 DEFAULT_SCHEME = 'NoColor'
123
123
124 #---------------------------------------------------------------------------
124 #---------------------------------------------------------------------------
125 # Code begins
125 # Code begins
126
126
127 # Utility functions
127 # Utility functions
128 def inspect_error():
128 def inspect_error():
129 """Print a message about internal inspect errors.
129 """Print a message about internal inspect errors.
130
130
131 These are unfortunately quite common."""
131 These are unfortunately quite common."""
132
132
133 error('Internal Python error in the inspect module.\n'
133 error('Internal Python error in the inspect module.\n'
134 'Below is the traceback from this internal error.\n')
134 'Below is the traceback from this internal error.\n')
135
135
136 # This function is a monkeypatch we apply to the Python inspect module. We have
136 # This function is a monkeypatch we apply to the Python inspect module. We have
137 # now found when it's needed (see discussion on issue gh-1456), and we have a
137 # now found when it's needed (see discussion on issue gh-1456), and we have a
138 # test case (IPython.core.tests.test_ultratb.ChangedPyFileTest) that fails if
138 # test case (IPython.core.tests.test_ultratb.ChangedPyFileTest) that fails if
139 # the monkeypatch is not applied. TK, Aug 2012.
139 # the monkeypatch is not applied. TK, Aug 2012.
140 def findsource(object):
140 def findsource(object):
141 """Return the entire source file and starting line number for an object.
141 """Return the entire source file and starting line number for an object.
142
142
143 The argument may be a module, class, method, function, traceback, frame,
143 The argument may be a module, class, method, function, traceback, frame,
144 or code object. The source code is returned as a list of all the lines
144 or code object. The source code is returned as a list of all the lines
145 in the file and the line number indexes a line in that list. An IOError
145 in the file and the line number indexes a line in that list. An IOError
146 is raised if the source code cannot be retrieved.
146 is raised if the source code cannot be retrieved.
147
147
148 FIXED version with which we monkeypatch the stdlib to work around a bug."""
148 FIXED version with which we monkeypatch the stdlib to work around a bug."""
149
149
150 file = getsourcefile(object) or getfile(object)
150 file = getsourcefile(object) or getfile(object)
151 # If the object is a frame, then trying to get the globals dict from its
151 # If the object is a frame, then trying to get the globals dict from its
152 # module won't work. Instead, the frame object itself has the globals
152 # module won't work. Instead, the frame object itself has the globals
153 # dictionary.
153 # dictionary.
154 globals_dict = None
154 globals_dict = None
155 if inspect.isframe(object):
155 if inspect.isframe(object):
156 # XXX: can this ever be false?
156 # XXX: can this ever be false?
157 globals_dict = object.f_globals
157 globals_dict = object.f_globals
158 else:
158 else:
159 module = getmodule(object, file)
159 module = getmodule(object, file)
160 if module:
160 if module:
161 globals_dict = module.__dict__
161 globals_dict = module.__dict__
162 lines = linecache.getlines(file, globals_dict)
162 lines = linecache.getlines(file, globals_dict)
163 if not lines:
163 if not lines:
164 raise IOError('could not get source code')
164 raise IOError('could not get source code')
165
165
166 if ismodule(object):
166 if ismodule(object):
167 return lines, 0
167 return lines, 0
168
168
169 if isclass(object):
169 if isclass(object):
170 name = object.__name__
170 name = object.__name__
171 pat = re.compile(r'^(\s*)class\s*' + name + r'\b')
171 pat = re.compile(r'^(\s*)class\s*' + name + r'\b')
172 # make some effort to find the best matching class definition:
172 # make some effort to find the best matching class definition:
173 # use the one with the least indentation, which is the one
173 # use the one with the least indentation, which is the one
174 # that's most probably not inside a function definition.
174 # that's most probably not inside a function definition.
175 candidates = []
175 candidates = []
176 for i in range(len(lines)):
176 for i in range(len(lines)):
177 match = pat.match(lines[i])
177 match = pat.match(lines[i])
178 if match:
178 if match:
179 # if it's at toplevel, it's already the best one
179 # if it's at toplevel, it's already the best one
180 if lines[i][0] == 'c':
180 if lines[i][0] == 'c':
181 return lines, i
181 return lines, i
182 # else add whitespace to candidate list
182 # else add whitespace to candidate list
183 candidates.append((match.group(1), i))
183 candidates.append((match.group(1), i))
184 if candidates:
184 if candidates:
185 # this will sort by whitespace, and by line number,
185 # this will sort by whitespace, and by line number,
186 # less whitespace first
186 # less whitespace first
187 candidates.sort()
187 candidates.sort()
188 return lines, candidates[0][1]
188 return lines, candidates[0][1]
189 else:
189 else:
190 raise IOError('could not find class definition')
190 raise IOError('could not find class definition')
191
191
192 if ismethod(object):
192 if ismethod(object):
193 object = object.im_func
193 object = object.im_func
194 if isfunction(object):
194 if isfunction(object):
195 object = object.func_code
195 object = object.func_code
196 if istraceback(object):
196 if istraceback(object):
197 object = object.tb_frame
197 object = object.tb_frame
198 if isframe(object):
198 if isframe(object):
199 object = object.f_code
199 object = object.f_code
200 if iscode(object):
200 if iscode(object):
201 if not hasattr(object, 'co_firstlineno'):
201 if not hasattr(object, 'co_firstlineno'):
202 raise IOError('could not find function definition')
202 raise IOError('could not find function definition')
203 pat = re.compile(r'^(\s*def\s)|(.*(?<!\w)lambda(:|\s))|^(\s*@)')
203 pat = re.compile(r'^(\s*def\s)|(.*(?<!\w)lambda(:|\s))|^(\s*@)')
204 pmatch = pat.match
204 pmatch = pat.match
205 # fperez - fix: sometimes, co_firstlineno can give a number larger than
205 # fperez - fix: sometimes, co_firstlineno can give a number larger than
206 # the length of lines, which causes an error. Safeguard against that.
206 # the length of lines, which causes an error. Safeguard against that.
207 lnum = min(object.co_firstlineno,len(lines))-1
207 lnum = min(object.co_firstlineno,len(lines))-1
208 while lnum > 0:
208 while lnum > 0:
209 if pmatch(lines[lnum]): break
209 if pmatch(lines[lnum]): break
210 lnum -= 1
210 lnum -= 1
211
211
212 return lines, lnum
212 return lines, lnum
213 raise IOError('could not find code object')
213 raise IOError('could not find code object')
214
214
215 # Monkeypatch inspect to apply our bugfix. This code only works with Python >= 2.5
215 # Monkeypatch inspect to apply our bugfix. This code only works with Python >= 2.5
216 inspect.findsource = findsource
216 inspect.findsource = findsource
217
217
218 def fix_frame_records_filenames(records):
218 def fix_frame_records_filenames(records):
219 """Try to fix the filenames in each record from inspect.getinnerframes().
219 """Try to fix the filenames in each record from inspect.getinnerframes().
220
220
221 Particularly, modules loaded from within zip files have useless filenames
221 Particularly, modules loaded from within zip files have useless filenames
222 attached to their code object, and inspect.getinnerframes() just uses it.
222 attached to their code object, and inspect.getinnerframes() just uses it.
223 """
223 """
224 fixed_records = []
224 fixed_records = []
225 for frame, filename, line_no, func_name, lines, index in records:
225 for frame, filename, line_no, func_name, lines, index in records:
226 # Look inside the frame's globals dictionary for __file__, which should
226 # Look inside the frame's globals dictionary for __file__, which should
227 # be better.
227 # be better.
228 better_fn = frame.f_globals.get('__file__', None)
228 better_fn = frame.f_globals.get('__file__', None)
229 if isinstance(better_fn, str):
229 if isinstance(better_fn, str):
230 # Check the type just in case someone did something weird with
230 # Check the type just in case someone did something weird with
231 # __file__. It might also be None if the error occurred during
231 # __file__. It might also be None if the error occurred during
232 # import.
232 # import.
233 filename = better_fn
233 filename = better_fn
234 fixed_records.append((frame, filename, line_no, func_name, lines, index))
234 fixed_records.append((frame, filename, line_no, func_name, lines, index))
235 return fixed_records
235 return fixed_records
236
236
237
237
238 def _fixed_getinnerframes(etb, context=1,tb_offset=0):
238 def _fixed_getinnerframes(etb, context=1,tb_offset=0):
239 LNUM_POS, LINES_POS, INDEX_POS = 2, 4, 5
239 LNUM_POS, LINES_POS, INDEX_POS = 2, 4, 5
240
240
241 records = fix_frame_records_filenames(inspect.getinnerframes(etb, context))
241 records = fix_frame_records_filenames(inspect.getinnerframes(etb, context))
242
242
243 # If the error is at the console, don't build any context, since it would
243 # If the error is at the console, don't build any context, since it would
244 # otherwise produce 5 blank lines printed out (there is no file at the
244 # otherwise produce 5 blank lines printed out (there is no file at the
245 # console)
245 # console)
246 rec_check = records[tb_offset:]
246 rec_check = records[tb_offset:]
247 try:
247 try:
248 rname = rec_check[0][1]
248 rname = rec_check[0][1]
249 if rname == '<ipython console>' or rname.endswith('<string>'):
249 if rname == '<ipython console>' or rname.endswith('<string>'):
250 return rec_check
250 return rec_check
251 except IndexError:
251 except IndexError:
252 pass
252 pass
253
253
254 aux = traceback.extract_tb(etb)
254 aux = traceback.extract_tb(etb)
255 assert len(records) == len(aux)
255 assert len(records) == len(aux)
256 for i, (file, lnum, _, _) in zip(range(len(records)), aux):
256 for i, (file, lnum, _, _) in zip(range(len(records)), aux):
257 maybeStart = lnum-1 - context//2
257 maybeStart = lnum-1 - context//2
258 start = max(maybeStart, 0)
258 start = max(maybeStart, 0)
259 end = start + context
259 end = start + context
260 lines = ulinecache.getlines(file)[start:end]
260 lines = ulinecache.getlines(file)[start:end]
261 buf = list(records[i])
261 buf = list(records[i])
262 buf[LNUM_POS] = lnum
262 buf[LNUM_POS] = lnum
263 buf[INDEX_POS] = lnum - 1 - start
263 buf[INDEX_POS] = lnum - 1 - start
264 buf[LINES_POS] = lines
264 buf[LINES_POS] = lines
265 records[i] = tuple(buf)
265 records[i] = tuple(buf)
266 return records[tb_offset:]
266 return records[tb_offset:]
267
267
268 # Helper function -- largely belongs to VerboseTB, but we need the same
268 # Helper function -- largely belongs to VerboseTB, but we need the same
269 # functionality to produce a pseudo verbose TB for SyntaxErrors, so that they
269 # functionality to produce a pseudo verbose TB for SyntaxErrors, so that they
270 # can be recognized properly by ipython.el's py-traceback-line-re
270 # can be recognized properly by ipython.el's py-traceback-line-re
271 # (SyntaxErrors have to be treated specially because they have no traceback)
271 # (SyntaxErrors have to be treated specially because they have no traceback)
272
272
273 _parser = PyColorize.Parser()
273 _parser = PyColorize.Parser()
274
274
275 def _format_traceback_lines(lnum, index, lines, Colors, lvals=None,scheme=None):
275 def _format_traceback_lines(lnum, index, lines, Colors, lvals=None,scheme=None):
276 numbers_width = INDENT_SIZE - 1
276 numbers_width = INDENT_SIZE - 1
277 res = []
277 res = []
278 i = lnum - index
278 i = lnum - index
279
279
280 # This lets us get fully syntax-highlighted tracebacks.
280 # This lets us get fully syntax-highlighted tracebacks.
281 if scheme is None:
281 if scheme is None:
282 ipinst = ipapi.get()
282 ipinst = ipapi.get()
283 if ipinst is not None:
283 if ipinst is not None:
284 scheme = ipinst.colors
284 scheme = ipinst.colors
285 else:
285 else:
286 scheme = DEFAULT_SCHEME
286 scheme = DEFAULT_SCHEME
287
287
288 _line_format = _parser.format2
288 _line_format = _parser.format2
289
289
290 for line in lines:
290 for line in lines:
291 line = py3compat.cast_unicode(line)
291 line = py3compat.cast_unicode(line)
292
292
293 new_line, err = _line_format(line, 'str', scheme)
293 new_line, err = _line_format(line, 'str', scheme)
294 if not err: line = new_line
294 if not err: line = new_line
295
295
296 if i == lnum:
296 if i == lnum:
297 # This is the line with the error
297 # This is the line with the error
298 pad = numbers_width - len(str(i))
298 pad = numbers_width - len(str(i))
299 if pad >= 3:
299 if pad >= 3:
300 marker = '-'*(pad-3) + '-> '
300 marker = '-'*(pad-3) + '-> '
301 elif pad == 2:
301 elif pad == 2:
302 marker = '> '
302 marker = '> '
303 elif pad == 1:
303 elif pad == 1:
304 marker = '>'
304 marker = '>'
305 else:
305 else:
306 marker = ''
306 marker = ''
307 num = marker + str(i)
307 num = marker + str(i)
308 line = '%s%s%s %s%s' %(Colors.linenoEm, num,
308 line = '%s%s%s %s%s' %(Colors.linenoEm, num,
309 Colors.line, line, Colors.Normal)
309 Colors.line, line, Colors.Normal)
310 else:
310 else:
311 num = '%*s' % (numbers_width,i)
311 num = '%*s' % (numbers_width,i)
312 line = '%s%s%s %s' %(Colors.lineno, num,
312 line = '%s%s%s %s' %(Colors.lineno, num,
313 Colors.Normal, line)
313 Colors.Normal, line)
314
314
315 res.append(line)
315 res.append(line)
316 if lvals and i == lnum:
316 if lvals and i == lnum:
317 res.append(lvals + '\n')
317 res.append(lvals + '\n')
318 i = i + 1
318 i = i + 1
319 return res
319 return res
320
320
321
321
322 #---------------------------------------------------------------------------
322 #---------------------------------------------------------------------------
323 # Module classes
323 # Module classes
324 class TBTools(object):
324 class TBTools(object):
325 """Basic tools used by all traceback printer classes."""
325 """Basic tools used by all traceback printer classes."""
326
326
327 # Number of frames to skip when reporting tracebacks
327 # Number of frames to skip when reporting tracebacks
328 tb_offset = 0
328 tb_offset = 0
329
329
330 def __init__(self, color_scheme='NoColor', call_pdb=False, ostream=None):
330 def __init__(self, color_scheme='NoColor', call_pdb=False, ostream=None):
331 # Whether to call the interactive pdb debugger after printing
331 # Whether to call the interactive pdb debugger after printing
332 # tracebacks or not
332 # tracebacks or not
333 self.call_pdb = call_pdb
333 self.call_pdb = call_pdb
334
334
335 # Output stream to write to. Note that we store the original value in
335 # Output stream to write to. Note that we store the original value in
336 # a private attribute and then make the public ostream a property, so
336 # a private attribute and then make the public ostream a property, so
337 # that we can delay accessing io.stdout until runtime. The way
337 # that we can delay accessing io.stdout until runtime. The way
338 # things are written now, the io.stdout object is dynamically managed
338 # things are written now, the io.stdout object is dynamically managed
339 # so a reference to it should NEVER be stored statically. This
339 # so a reference to it should NEVER be stored statically. This
340 # property approach confines this detail to a single location, and all
340 # property approach confines this detail to a single location, and all
341 # subclasses can simply access self.ostream for writing.
341 # subclasses can simply access self.ostream for writing.
342 self._ostream = ostream
342 self._ostream = ostream
343
343
344 # Create color table
344 # Create color table
345 self.color_scheme_table = exception_colors()
345 self.color_scheme_table = exception_colors()
346
346
347 self.set_colors(color_scheme)
347 self.set_colors(color_scheme)
348 self.old_scheme = color_scheme # save initial value for toggles
348 self.old_scheme = color_scheme # save initial value for toggles
349
349
350 if call_pdb:
350 if call_pdb:
351 self.pdb = debugger.Pdb(self.color_scheme_table.active_scheme_name)
351 self.pdb = debugger.Pdb(self.color_scheme_table.active_scheme_name)
352 else:
352 else:
353 self.pdb = None
353 self.pdb = None
354
354
355 def _get_ostream(self):
355 def _get_ostream(self):
356 """Output stream that exceptions are written to.
356 """Output stream that exceptions are written to.
357
357
358 Valid values are:
358 Valid values are:
359
359
360 - None: the default, which means that IPython will dynamically resolve
360 - None: the default, which means that IPython will dynamically resolve
361 to io.stdout. This ensures compatibility with most tools, including
361 to io.stdout. This ensures compatibility with most tools, including
362 Windows (where plain stdout doesn't recognize ANSI escapes).
362 Windows (where plain stdout doesn't recognize ANSI escapes).
363
363
364 - Any object with 'write' and 'flush' attributes.
364 - Any object with 'write' and 'flush' attributes.
365 """
365 """
366 return io.stdout if self._ostream is None else self._ostream
366 return io.stdout if self._ostream is None else self._ostream
367
367
368 def _set_ostream(self, val):
368 def _set_ostream(self, val):
369 assert val is None or (hasattr(val, 'write') and hasattr(val, 'flush'))
369 assert val is None or (hasattr(val, 'write') and hasattr(val, 'flush'))
370 self._ostream = val
370 self._ostream = val
371
371
372 ostream = property(_get_ostream, _set_ostream)
372 ostream = property(_get_ostream, _set_ostream)
373
373
374 def set_colors(self,*args,**kw):
374 def set_colors(self,*args,**kw):
375 """Shorthand access to the color table scheme selector method."""
375 """Shorthand access to the color table scheme selector method."""
376
376
377 # Set own color table
377 # Set own color table
378 self.color_scheme_table.set_active_scheme(*args,**kw)
378 self.color_scheme_table.set_active_scheme(*args,**kw)
379 # for convenience, set Colors to the active scheme
379 # for convenience, set Colors to the active scheme
380 self.Colors = self.color_scheme_table.active_colors
380 self.Colors = self.color_scheme_table.active_colors
381 # Also set colors of debugger
381 # Also set colors of debugger
382 if hasattr(self,'pdb') and self.pdb is not None:
382 if hasattr(self,'pdb') and self.pdb is not None:
383 self.pdb.set_colors(*args,**kw)
383 self.pdb.set_colors(*args,**kw)
384
384
385 def color_toggle(self):
385 def color_toggle(self):
386 """Toggle between the currently active color scheme and NoColor."""
386 """Toggle between the currently active color scheme and NoColor."""
387
387
388 if self.color_scheme_table.active_scheme_name == 'NoColor':
388 if self.color_scheme_table.active_scheme_name == 'NoColor':
389 self.color_scheme_table.set_active_scheme(self.old_scheme)
389 self.color_scheme_table.set_active_scheme(self.old_scheme)
390 self.Colors = self.color_scheme_table.active_colors
390 self.Colors = self.color_scheme_table.active_colors
391 else:
391 else:
392 self.old_scheme = self.color_scheme_table.active_scheme_name
392 self.old_scheme = self.color_scheme_table.active_scheme_name
393 self.color_scheme_table.set_active_scheme('NoColor')
393 self.color_scheme_table.set_active_scheme('NoColor')
394 self.Colors = self.color_scheme_table.active_colors
394 self.Colors = self.color_scheme_table.active_colors
395
395
396 def stb2text(self, stb):
396 def stb2text(self, stb):
397 """Convert a structured traceback (a list) to a string."""
397 """Convert a structured traceback (a list) to a string."""
398 return '\n'.join(stb)
398 return '\n'.join(stb)
399
399
400 def text(self, etype, value, tb, tb_offset=None, context=5):
400 def text(self, etype, value, tb, tb_offset=None, context=5):
401 """Return formatted traceback.
401 """Return formatted traceback.
402
402
403 Subclasses may override this if they add extra arguments.
403 Subclasses may override this if they add extra arguments.
404 """
404 """
405 tb_list = self.structured_traceback(etype, value, tb,
405 tb_list = self.structured_traceback(etype, value, tb,
406 tb_offset, context)
406 tb_offset, context)
407 return self.stb2text(tb_list)
407 return self.stb2text(tb_list)
408
408
409 def structured_traceback(self, etype, evalue, tb, tb_offset=None,
409 def structured_traceback(self, etype, evalue, tb, tb_offset=None,
410 context=5, mode=None):
410 context=5, mode=None):
411 """Return a list of traceback frames.
411 """Return a list of traceback frames.
412
412
413 Must be implemented by each class.
413 Must be implemented by each class.
414 """
414 """
415 raise NotImplementedError()
415 raise NotImplementedError()
416
416
417
417
418 #---------------------------------------------------------------------------
418 #---------------------------------------------------------------------------
419 class ListTB(TBTools):
419 class ListTB(TBTools):
420 """Print traceback information from a traceback list, with optional color.
420 """Print traceback information from a traceback list, with optional color.
421
421
422 Calling requires 3 arguments: (etype, evalue, elist)
422 Calling requires 3 arguments: (etype, evalue, elist)
423 as would be obtained by::
423 as would be obtained by::
424
424
425 etype, evalue, tb = sys.exc_info()
425 etype, evalue, tb = sys.exc_info()
426 if tb:
426 if tb:
427 elist = traceback.extract_tb(tb)
427 elist = traceback.extract_tb(tb)
428 else:
428 else:
429 elist = None
429 elist = None
430
430
431 It can thus be used by programs which need to process the traceback before
431 It can thus be used by programs which need to process the traceback before
432 printing (such as console replacements based on the code module from the
432 printing (such as console replacements based on the code module from the
433 standard library).
433 standard library).
434
434
435 Because they are meant to be called without a full traceback (only a
435 Because they are meant to be called without a full traceback (only a
436 list), instances of this class can't call the interactive pdb debugger."""
436 list), instances of this class can't call the interactive pdb debugger."""
437
437
438 def __init__(self,color_scheme = 'NoColor', call_pdb=False, ostream=None):
438 def __init__(self,color_scheme = 'NoColor', call_pdb=False, ostream=None):
439 TBTools.__init__(self, color_scheme=color_scheme, call_pdb=call_pdb,
439 TBTools.__init__(self, color_scheme=color_scheme, call_pdb=call_pdb,
440 ostream=ostream)
440 ostream=ostream)
441
441
442 def __call__(self, etype, value, elist):
442 def __call__(self, etype, value, elist):
443 self.ostream.flush()
443 self.ostream.flush()
444 self.ostream.write(self.text(etype, value, elist))
444 self.ostream.write(self.text(etype, value, elist))
445 self.ostream.write('\n')
445 self.ostream.write('\n')
446
446
447 def structured_traceback(self, etype, value, elist, tb_offset=None,
447 def structured_traceback(self, etype, value, elist, tb_offset=None,
448 context=5):
448 context=5):
449 """Return a color formatted string with the traceback info.
449 """Return a color formatted string with the traceback info.
450
450
451 Parameters
451 Parameters
452 ----------
452 ----------
453 etype : exception type
453 etype : exception type
454 Type of the exception raised.
454 Type of the exception raised.
455
455
456 value : object
456 value : object
457 Data stored in the exception
457 Data stored in the exception
458
458
459 elist : list
459 elist : list
460 List of frames, see class docstring for details.
460 List of frames, see class docstring for details.
461
461
462 tb_offset : int, optional
462 tb_offset : int, optional
463 Number of frames in the traceback to skip. If not given, the
463 Number of frames in the traceback to skip. If not given, the
464 instance value is used (set in constructor).
464 instance value is used (set in constructor).
465
465
466 context : int, optional
466 context : int, optional
467 Number of lines of context information to print.
467 Number of lines of context information to print.
468
468
469 Returns
469 Returns
470 -------
470 -------
471 String with formatted exception.
471 String with formatted exception.
472 """
472 """
473 tb_offset = self.tb_offset if tb_offset is None else tb_offset
473 tb_offset = self.tb_offset if tb_offset is None else tb_offset
474 Colors = self.Colors
474 Colors = self.Colors
475 out_list = []
475 out_list = []
476 if elist:
476 if elist:
477
477
478 if tb_offset and len(elist) > tb_offset:
478 if tb_offset and len(elist) > tb_offset:
479 elist = elist[tb_offset:]
479 elist = elist[tb_offset:]
480
480
481 out_list.append('Traceback %s(most recent call last)%s:' %
481 out_list.append('Traceback %s(most recent call last)%s:' %
482 (Colors.normalEm, Colors.Normal) + '\n')
482 (Colors.normalEm, Colors.Normal) + '\n')
483 out_list.extend(self._format_list(elist))
483 out_list.extend(self._format_list(elist))
484 # The exception info should be a single entry in the list.
484 # The exception info should be a single entry in the list.
485 lines = ''.join(self._format_exception_only(etype, value))
485 lines = ''.join(self._format_exception_only(etype, value))
486 out_list.append(lines)
486 out_list.append(lines)
487
487
488 # Note: this code originally read:
488 # Note: this code originally read:
489
489
490 ## for line in lines[:-1]:
490 ## for line in lines[:-1]:
491 ## out_list.append(" "+line)
491 ## out_list.append(" "+line)
492 ## out_list.append(lines[-1])
492 ## out_list.append(lines[-1])
493
493
494 # This means it was indenting everything but the last line by a little
494 # This means it was indenting everything but the last line by a little
495 # bit. I've disabled this for now, but if we see ugliness somewhre we
495 # bit. I've disabled this for now, but if we see ugliness somewhre we
496 # can restore it.
496 # can restore it.
497
497
498 return out_list
498 return out_list
499
499
500 def _format_list(self, extracted_list):
500 def _format_list(self, extracted_list):
501 """Format a list of traceback entry tuples for printing.
501 """Format a list of traceback entry tuples for printing.
502
502
503 Given a list of tuples as returned by extract_tb() or
503 Given a list of tuples as returned by extract_tb() or
504 extract_stack(), return a list of strings ready for printing.
504 extract_stack(), return a list of strings ready for printing.
505 Each string in the resulting list corresponds to the item with the
505 Each string in the resulting list corresponds to the item with the
506 same index in the argument list. Each string ends in a newline;
506 same index in the argument list. Each string ends in a newline;
507 the strings may contain internal newlines as well, for those items
507 the strings may contain internal newlines as well, for those items
508 whose source text line is not None.
508 whose source text line is not None.
509
509
510 Lifted almost verbatim from traceback.py
510 Lifted almost verbatim from traceback.py
511 """
511 """
512
512
513 Colors = self.Colors
513 Colors = self.Colors
514 list = []
514 list = []
515 for filename, lineno, name, line in extracted_list[:-1]:
515 for filename, lineno, name, line in extracted_list[:-1]:
516 item = ' File %s"%s"%s, line %s%d%s, in %s%s%s\n' % \
516 item = ' File %s"%s"%s, line %s%d%s, in %s%s%s\n' % \
517 (Colors.filename, filename, Colors.Normal,
517 (Colors.filename, filename, Colors.Normal,
518 Colors.lineno, lineno, Colors.Normal,
518 Colors.lineno, lineno, Colors.Normal,
519 Colors.name, name, Colors.Normal)
519 Colors.name, name, Colors.Normal)
520 if line:
520 if line:
521 item += ' %s\n' % line.strip()
521 item += ' %s\n' % line.strip()
522 list.append(item)
522 list.append(item)
523 # Emphasize the last entry
523 # Emphasize the last entry
524 filename, lineno, name, line = extracted_list[-1]
524 filename, lineno, name, line = extracted_list[-1]
525 item = '%s File %s"%s"%s, line %s%d%s, in %s%s%s%s\n' % \
525 item = '%s File %s"%s"%s, line %s%d%s, in %s%s%s%s\n' % \
526 (Colors.normalEm,
526 (Colors.normalEm,
527 Colors.filenameEm, filename, Colors.normalEm,
527 Colors.filenameEm, filename, Colors.normalEm,
528 Colors.linenoEm, lineno, Colors.normalEm,
528 Colors.linenoEm, lineno, Colors.normalEm,
529 Colors.nameEm, name, Colors.normalEm,
529 Colors.nameEm, name, Colors.normalEm,
530 Colors.Normal)
530 Colors.Normal)
531 if line:
531 if line:
532 item += '%s %s%s\n' % (Colors.line, line.strip(),
532 item += '%s %s%s\n' % (Colors.line, line.strip(),
533 Colors.Normal)
533 Colors.Normal)
534 list.append(item)
534 list.append(item)
535 #from pprint import pformat; print 'LISTTB', pformat(list) # dbg
535 #from pprint import pformat; print 'LISTTB', pformat(list) # dbg
536 return list
536 return list
537
537
538 def _format_exception_only(self, etype, value):
538 def _format_exception_only(self, etype, value):
539 """Format the exception part of a traceback.
539 """Format the exception part of a traceback.
540
540
541 The arguments are the exception type and value such as given by
541 The arguments are the exception type and value such as given by
542 sys.exc_info()[:2]. The return value is a list of strings, each ending
542 sys.exc_info()[:2]. The return value is a list of strings, each ending
543 in a newline. Normally, the list contains a single string; however,
543 in a newline. Normally, the list contains a single string; however,
544 for SyntaxError exceptions, it contains several lines that (when
544 for SyntaxError exceptions, it contains several lines that (when
545 printed) display detailed information about where the syntax error
545 printed) display detailed information about where the syntax error
546 occurred. The message indicating which exception occurred is the
546 occurred. The message indicating which exception occurred is the
547 always last string in the list.
547 always last string in the list.
548
548
549 Also lifted nearly verbatim from traceback.py
549 Also lifted nearly verbatim from traceback.py
550 """
550 """
551 have_filedata = False
551 have_filedata = False
552 Colors = self.Colors
552 Colors = self.Colors
553 list = []
553 list = []
554 stype = Colors.excName + etype.__name__ + Colors.Normal
554 stype = Colors.excName + etype.__name__ + Colors.Normal
555 if value is None:
555 if value is None:
556 # Not sure if this can still happen in Python 2.6 and above
556 # Not sure if this can still happen in Python 2.6 and above
557 list.append( py3compat.cast_unicode(stype) + '\n')
557 list.append( py3compat.cast_unicode(stype) + '\n')
558 else:
558 else:
559 if issubclass(etype, SyntaxError):
559 if issubclass(etype, SyntaxError):
560 have_filedata = True
560 have_filedata = True
561 #print 'filename is',filename # dbg
561 #print 'filename is',filename # dbg
562 if not value.filename: value.filename = "<string>"
562 if not value.filename: value.filename = "<string>"
563 if value.lineno:
563 if value.lineno:
564 lineno = value.lineno
564 lineno = value.lineno
565 textline = ulinecache.getline(value.filename, value.lineno)
565 textline = ulinecache.getline(value.filename, value.lineno)
566 else:
566 else:
567 lineno = 'unknown'
567 lineno = 'unknown'
568 textline = ''
568 textline = ''
569 list.append('%s File %s"%s"%s, line %s%s%s\n' % \
569 list.append('%s File %s"%s"%s, line %s%s%s\n' % \
570 (Colors.normalEm,
570 (Colors.normalEm,
571 Colors.filenameEm, py3compat.cast_unicode(value.filename), Colors.normalEm,
571 Colors.filenameEm, py3compat.cast_unicode(value.filename), Colors.normalEm,
572 Colors.linenoEm, lineno, Colors.Normal ))
572 Colors.linenoEm, lineno, Colors.Normal ))
573 if textline == '':
573 if textline == '':
574 textline = py3compat.cast_unicode(value.text, "utf-8")
574 textline = py3compat.cast_unicode(value.text, "utf-8")
575
575
576 if textline is not None:
576 if textline is not None:
577 i = 0
577 i = 0
578 while i < len(textline) and textline[i].isspace():
578 while i < len(textline) and textline[i].isspace():
579 i += 1
579 i += 1
580 list.append('%s %s%s\n' % (Colors.line,
580 list.append('%s %s%s\n' % (Colors.line,
581 textline.strip(),
581 textline.strip(),
582 Colors.Normal))
582 Colors.Normal))
583 if value.offset is not None:
583 if value.offset is not None:
584 s = ' '
584 s = ' '
585 for c in textline[i:value.offset-1]:
585 for c in textline[i:value.offset-1]:
586 if c.isspace():
586 if c.isspace():
587 s += c
587 s += c
588 else:
588 else:
589 s += ' '
589 s += ' '
590 list.append('%s%s^%s\n' % (Colors.caret, s,
590 list.append('%s%s^%s\n' % (Colors.caret, s,
591 Colors.Normal) )
591 Colors.Normal) )
592
592
593 try:
593 try:
594 s = value.msg
594 s = value.msg
595 except Exception:
595 except Exception:
596 s = self._some_str(value)
596 s = self._some_str(value)
597 if s:
597 if s:
598 list.append('%s%s:%s %s\n' % (str(stype), Colors.excName,
598 list.append('%s%s:%s %s\n' % (str(stype), Colors.excName,
599 Colors.Normal, s))
599 Colors.Normal, s))
600 else:
600 else:
601 list.append('%s\n' % str(stype))
601 list.append('%s\n' % str(stype))
602
602
603 # sync with user hooks
603 # sync with user hooks
604 if have_filedata:
604 if have_filedata:
605 ipinst = ipapi.get()
605 ipinst = ipapi.get()
606 if ipinst is not None:
606 if ipinst is not None:
607 ipinst.hooks.synchronize_with_editor(value.filename, value.lineno, 0)
607 ipinst.hooks.synchronize_with_editor(value.filename, value.lineno, 0)
608
608
609 return list
609 return list
610
610
611 def get_exception_only(self, etype, value):
611 def get_exception_only(self, etype, value):
612 """Only print the exception type and message, without a traceback.
612 """Only print the exception type and message, without a traceback.
613
613
614 Parameters
614 Parameters
615 ----------
615 ----------
616 etype : exception type
616 etype : exception type
617 value : exception value
617 value : exception value
618 """
618 """
619 return ListTB.structured_traceback(self, etype, value, [])
619 return ListTB.structured_traceback(self, etype, value, [])
620
620
621
621
622 def show_exception_only(self, etype, evalue):
622 def show_exception_only(self, etype, evalue):
623 """Only print the exception type and message, without a traceback.
623 """Only print the exception type and message, without a traceback.
624
624
625 Parameters
625 Parameters
626 ----------
626 ----------
627 etype : exception type
627 etype : exception type
628 value : exception value
628 value : exception value
629 """
629 """
630 # This method needs to use __call__ from *this* class, not the one from
630 # This method needs to use __call__ from *this* class, not the one from
631 # a subclass whose signature or behavior may be different
631 # a subclass whose signature or behavior may be different
632 ostream = self.ostream
632 ostream = self.ostream
633 ostream.flush()
633 ostream.flush()
634 ostream.write('\n'.join(self.get_exception_only(etype, evalue)))
634 ostream.write('\n'.join(self.get_exception_only(etype, evalue)))
635 ostream.flush()
635 ostream.flush()
636
636
637 def _some_str(self, value):
637 def _some_str(self, value):
638 # Lifted from traceback.py
638 # Lifted from traceback.py
639 try:
639 try:
640 return str(value)
640 return str(value)
641 except:
641 except:
642 return '<unprintable %s object>' % type(value).__name__
642 return '<unprintable %s object>' % type(value).__name__
643
643
644 #----------------------------------------------------------------------------
644 #----------------------------------------------------------------------------
645 class VerboseTB(TBTools):
645 class VerboseTB(TBTools):
646 """A port of Ka-Ping Yee's cgitb.py module that outputs color text instead
646 """A port of Ka-Ping Yee's cgitb.py module that outputs color text instead
647 of HTML. Requires inspect and pydoc. Crazy, man.
647 of HTML. Requires inspect and pydoc. Crazy, man.
648
648
649 Modified version which optionally strips the topmost entries from the
649 Modified version which optionally strips the topmost entries from the
650 traceback, to be used with alternate interpreters (because their own code
650 traceback, to be used with alternate interpreters (because their own code
651 would appear in the traceback)."""
651 would appear in the traceback)."""
652
652
653 def __init__(self,color_scheme = 'Linux', call_pdb=False, ostream=None,
653 def __init__(self,color_scheme = 'Linux', call_pdb=False, ostream=None,
654 tb_offset=0, long_header=False, include_vars=True,
654 tb_offset=0, long_header=False, include_vars=True,
655 check_cache=None):
655 check_cache=None):
656 """Specify traceback offset, headers and color scheme.
656 """Specify traceback offset, headers and color scheme.
657
657
658 Define how many frames to drop from the tracebacks. Calling it with
658 Define how many frames to drop from the tracebacks. Calling it with
659 tb_offset=1 allows use of this handler in interpreters which will have
659 tb_offset=1 allows use of this handler in interpreters which will have
660 their own code at the top of the traceback (VerboseTB will first
660 their own code at the top of the traceback (VerboseTB will first
661 remove that frame before printing the traceback info)."""
661 remove that frame before printing the traceback info)."""
662 TBTools.__init__(self, color_scheme=color_scheme, call_pdb=call_pdb,
662 TBTools.__init__(self, color_scheme=color_scheme, call_pdb=call_pdb,
663 ostream=ostream)
663 ostream=ostream)
664 self.tb_offset = tb_offset
664 self.tb_offset = tb_offset
665 self.long_header = long_header
665 self.long_header = long_header
666 self.include_vars = include_vars
666 self.include_vars = include_vars
667 # By default we use linecache.checkcache, but the user can provide a
667 # By default we use linecache.checkcache, but the user can provide a
668 # different check_cache implementation. This is used by the IPython
668 # different check_cache implementation. This is used by the IPython
669 # kernel to provide tracebacks for interactive code that is cached,
669 # kernel to provide tracebacks for interactive code that is cached,
670 # by a compiler instance that flushes the linecache but preserves its
670 # by a compiler instance that flushes the linecache but preserves its
671 # own code cache.
671 # own code cache.
672 if check_cache is None:
672 if check_cache is None:
673 check_cache = linecache.checkcache
673 check_cache = linecache.checkcache
674 self.check_cache = check_cache
674 self.check_cache = check_cache
675
675
676 def structured_traceback(self, etype, evalue, etb, tb_offset=None,
676 def structured_traceback(self, etype, evalue, etb, tb_offset=None,
677 context=5):
677 context=5):
678 """Return a nice text document describing the traceback."""
678 """Return a nice text document describing the traceback."""
679
679
680 tb_offset = self.tb_offset if tb_offset is None else tb_offset
680 tb_offset = self.tb_offset if tb_offset is None else tb_offset
681
681
682 # some locals
682 # some locals
683 try:
683 try:
684 etype = etype.__name__
684 etype = etype.__name__
685 except AttributeError:
685 except AttributeError:
686 pass
686 pass
687 Colors = self.Colors # just a shorthand + quicker name lookup
687 Colors = self.Colors # just a shorthand + quicker name lookup
688 ColorsNormal = Colors.Normal # used a lot
688 ColorsNormal = Colors.Normal # used a lot
689 col_scheme = self.color_scheme_table.active_scheme_name
689 col_scheme = self.color_scheme_table.active_scheme_name
690 indent = ' '*INDENT_SIZE
690 indent = ' '*INDENT_SIZE
691 em_normal = '%s\n%s%s' % (Colors.valEm, indent,ColorsNormal)
691 em_normal = '%s\n%s%s' % (Colors.valEm, indent,ColorsNormal)
692 undefined = '%sundefined%s' % (Colors.em, ColorsNormal)
692 undefined = '%sundefined%s' % (Colors.em, ColorsNormal)
693 exc = '%s%s%s' % (Colors.excName,etype,ColorsNormal)
693 exc = '%s%s%s' % (Colors.excName,etype,ColorsNormal)
694
694
695 # some internal-use functions
695 # some internal-use functions
696 def text_repr(value):
696 def text_repr(value):
697 """Hopefully pretty robust repr equivalent."""
697 """Hopefully pretty robust repr equivalent."""
698 # this is pretty horrible but should always return *something*
698 # this is pretty horrible but should always return *something*
699 try:
699 try:
700 return pydoc.text.repr(value)
700 return pydoc.text.repr(value)
701 except KeyboardInterrupt:
701 except KeyboardInterrupt:
702 raise
702 raise
703 except:
703 except:
704 try:
704 try:
705 return repr(value)
705 return repr(value)
706 except KeyboardInterrupt:
706 except KeyboardInterrupt:
707 raise
707 raise
708 except:
708 except:
709 try:
709 try:
710 # all still in an except block so we catch
710 # all still in an except block so we catch
711 # getattr raising
711 # getattr raising
712 name = getattr(value, '__name__', None)
712 name = getattr(value, '__name__', None)
713 if name:
713 if name:
714 # ick, recursion
714 # ick, recursion
715 return text_repr(name)
715 return text_repr(name)
716 klass = getattr(value, '__class__', None)
716 klass = getattr(value, '__class__', None)
717 if klass:
717 if klass:
718 return '%s instance' % text_repr(klass)
718 return '%s instance' % text_repr(klass)
719 except KeyboardInterrupt:
719 except KeyboardInterrupt:
720 raise
720 raise
721 except:
721 except:
722 return 'UNRECOVERABLE REPR FAILURE'
722 return 'UNRECOVERABLE REPR FAILURE'
723 def eqrepr(value, repr=text_repr): return '=%s' % repr(value)
723 def eqrepr(value, repr=text_repr): return '=%s' % repr(value)
724 def nullrepr(value, repr=text_repr): return ''
724 def nullrepr(value, repr=text_repr): return ''
725
725
726 # meat of the code begins
726 # meat of the code begins
727 try:
727 try:
728 etype = etype.__name__
728 etype = etype.__name__
729 except AttributeError:
729 except AttributeError:
730 pass
730 pass
731
731
732 if self.long_header:
732 if self.long_header:
733 # Header with the exception type, python version, and date
733 # Header with the exception type, python version, and date
734 pyver = 'Python ' + sys.version.split()[0] + ': ' + sys.executable
734 pyver = 'Python ' + sys.version.split()[0] + ': ' + sys.executable
735 date = time.ctime(time.time())
735 date = time.ctime(time.time())
736
736
737 head = '%s%s%s\n%s%s%s\n%s' % (Colors.topline, '-'*75, ColorsNormal,
737 head = '%s%s%s\n%s%s%s\n%s' % (Colors.topline, '-'*75, ColorsNormal,
738 exc, ' '*(75-len(str(etype))-len(pyver)),
738 exc, ' '*(75-len(str(etype))-len(pyver)),
739 pyver, date.rjust(75) )
739 pyver, date.rjust(75) )
740 head += "\nA problem occured executing Python code. Here is the sequence of function"\
740 head += "\nA problem occured executing Python code. Here is the sequence of function"\
741 "\ncalls leading up to the error, with the most recent (innermost) call last."
741 "\ncalls leading up to the error, with the most recent (innermost) call last."
742 else:
742 else:
743 # Simplified header
743 # Simplified header
744 head = '%s%s%s\n%s%s' % (Colors.topline, '-'*75, ColorsNormal,exc,
744 head = '%s%s%s\n%s%s' % (Colors.topline, '-'*75, ColorsNormal,exc,
745 'Traceback (most recent call last)'.\
745 'Traceback (most recent call last)'.\
746 rjust(75 - len(str(etype)) ) )
746 rjust(75 - len(str(etype)) ) )
747 frames = []
747 frames = []
748 # Flush cache before calling inspect. This helps alleviate some of the
748 # Flush cache before calling inspect. This helps alleviate some of the
749 # problems with python 2.3's inspect.py.
749 # problems with python 2.3's inspect.py.
750 ##self.check_cache()
750 ##self.check_cache()
751 # Drop topmost frames if requested
751 # Drop topmost frames if requested
752 try:
752 try:
753 # Try the default getinnerframes and Alex's: Alex's fixes some
753 # Try the default getinnerframes and Alex's: Alex's fixes some
754 # problems, but it generates empty tracebacks for console errors
754 # problems, but it generates empty tracebacks for console errors
755 # (5 blanks lines) where none should be returned.
755 # (5 blanks lines) where none should be returned.
756 #records = inspect.getinnerframes(etb, context)[tb_offset:]
756 #records = inspect.getinnerframes(etb, context)[tb_offset:]
757 #print 'python records:', records # dbg
757 #print 'python records:', records # dbg
758 records = _fixed_getinnerframes(etb, context, tb_offset)
758 records = _fixed_getinnerframes(etb, context, tb_offset)
759 #print 'alex records:', records # dbg
759 #print 'alex records:', records # dbg
760 except:
760 except:
761
761
762 # FIXME: I've been getting many crash reports from python 2.3
762 # FIXME: I've been getting many crash reports from python 2.3
763 # users, traceable to inspect.py. If I can find a small test-case
763 # users, traceable to inspect.py. If I can find a small test-case
764 # to reproduce this, I should either write a better workaround or
764 # to reproduce this, I should either write a better workaround or
765 # file a bug report against inspect (if that's the real problem).
765 # file a bug report against inspect (if that's the real problem).
766 # So far, I haven't been able to find an isolated example to
766 # So far, I haven't been able to find an isolated example to
767 # reproduce the problem.
767 # reproduce the problem.
768 inspect_error()
768 inspect_error()
769 traceback.print_exc(file=self.ostream)
769 traceback.print_exc(file=self.ostream)
770 info('\nUnfortunately, your original traceback can not be constructed.\n')
770 info('\nUnfortunately, your original traceback can not be constructed.\n')
771 return ''
771 return ''
772
772
773 # build some color string templates outside these nested loops
773 # build some color string templates outside these nested loops
774 tpl_link = '%s%%s%s' % (Colors.filenameEm,ColorsNormal)
774 tpl_link = '%s%%s%s' % (Colors.filenameEm,ColorsNormal)
775 tpl_call = 'in %s%%s%s%%s%s' % (Colors.vName, Colors.valEm,
775 tpl_call = 'in %s%%s%s%%s%s' % (Colors.vName, Colors.valEm,
776 ColorsNormal)
776 ColorsNormal)
777 tpl_call_fail = 'in %s%%s%s(***failed resolving arguments***)%s' % \
777 tpl_call_fail = 'in %s%%s%s(***failed resolving arguments***)%s' % \
778 (Colors.vName, Colors.valEm, ColorsNormal)
778 (Colors.vName, Colors.valEm, ColorsNormal)
779 tpl_local_var = '%s%%s%s' % (Colors.vName, ColorsNormal)
779 tpl_local_var = '%s%%s%s' % (Colors.vName, ColorsNormal)
780 tpl_global_var = '%sglobal%s %s%%s%s' % (Colors.em, ColorsNormal,
780 tpl_global_var = '%sglobal%s %s%%s%s' % (Colors.em, ColorsNormal,
781 Colors.vName, ColorsNormal)
781 Colors.vName, ColorsNormal)
782 tpl_name_val = '%%s %s= %%s%s' % (Colors.valEm, ColorsNormal)
782 tpl_name_val = '%%s %s= %%s%s' % (Colors.valEm, ColorsNormal)
783 tpl_line = '%s%%s%s %%s' % (Colors.lineno, ColorsNormal)
783 tpl_line = '%s%%s%s %%s' % (Colors.lineno, ColorsNormal)
784 tpl_line_em = '%s%%s%s %%s%s' % (Colors.linenoEm,Colors.line,
784 tpl_line_em = '%s%%s%s %%s%s' % (Colors.linenoEm,Colors.line,
785 ColorsNormal)
785 ColorsNormal)
786
786
787 # now, loop over all records printing context and info
787 # now, loop over all records printing context and info
788 abspath = os.path.abspath
788 abspath = os.path.abspath
789 for frame, file, lnum, func, lines, index in records:
789 for frame, file, lnum, func, lines, index in records:
790 #print '*** record:',file,lnum,func,lines,index # dbg
790 #print '*** record:',file,lnum,func,lines,index # dbg
791 if not file:
791 if not file:
792 file = '?'
792 file = '?'
793 elif not(file.startswith(str("<")) and file.endswith(str(">"))):
793 elif not(file.startswith(str("<")) and file.endswith(str(">"))):
794 # Guess that filenames like <string> aren't real filenames, so
794 # Guess that filenames like <string> aren't real filenames, so
795 # don't call abspath on them.
795 # don't call abspath on them.
796 try:
796 try:
797 file = abspath(file)
797 file = abspath(file)
798 except OSError:
798 except OSError:
799 # Not sure if this can still happen: abspath now works with
799 # Not sure if this can still happen: abspath now works with
800 # file names like <string>
800 # file names like <string>
801 pass
801 pass
802 file = py3compat.cast_unicode(file, util_path.fs_encoding)
802 file = py3compat.cast_unicode(file, util_path.fs_encoding)
803 link = tpl_link % file
803 link = tpl_link % file
804 args, varargs, varkw, locals = inspect.getargvalues(frame)
804 args, varargs, varkw, locals = inspect.getargvalues(frame)
805
805
806 if func == '?':
806 if func == '?':
807 call = ''
807 call = ''
808 else:
808 else:
809 # Decide whether to include variable details or not
809 # Decide whether to include variable details or not
810 var_repr = self.include_vars and eqrepr or nullrepr
810 var_repr = self.include_vars and eqrepr or nullrepr
811 try:
811 try:
812 call = tpl_call % (func,inspect.formatargvalues(args,
812 call = tpl_call % (func,inspect.formatargvalues(args,
813 varargs, varkw,
813 varargs, varkw,
814 locals,formatvalue=var_repr))
814 locals,formatvalue=var_repr))
815 except KeyError:
815 except KeyError:
816 # This happens in situations like errors inside generator
816 # This happens in situations like errors inside generator
817 # expressions, where local variables are listed in the
817 # expressions, where local variables are listed in the
818 # line, but can't be extracted from the frame. I'm not
818 # line, but can't be extracted from the frame. I'm not
819 # 100% sure this isn't actually a bug in inspect itself,
819 # 100% sure this isn't actually a bug in inspect itself,
820 # but since there's no info for us to compute with, the
820 # but since there's no info for us to compute with, the
821 # best we can do is report the failure and move on. Here
821 # best we can do is report the failure and move on. Here
822 # we must *not* call any traceback construction again,
822 # we must *not* call any traceback construction again,
823 # because that would mess up use of %debug later on. So we
823 # because that would mess up use of %debug later on. So we
824 # simply report the failure and move on. The only
824 # simply report the failure and move on. The only
825 # limitation will be that this frame won't have locals
825 # limitation will be that this frame won't have locals
826 # listed in the call signature. Quite subtle problem...
826 # listed in the call signature. Quite subtle problem...
827 # I can't think of a good way to validate this in a unit
827 # I can't think of a good way to validate this in a unit
828 # test, but running a script consisting of:
828 # test, but running a script consisting of:
829 # dict( (k,v.strip()) for (k,v) in range(10) )
829 # dict( (k,v.strip()) for (k,v) in range(10) )
830 # will illustrate the error, if this exception catch is
830 # will illustrate the error, if this exception catch is
831 # disabled.
831 # disabled.
832 call = tpl_call_fail % func
832 call = tpl_call_fail % func
833
833
834 # Don't attempt to tokenize binary files.
834 # Don't attempt to tokenize binary files.
835 if file.endswith(('.so', '.pyd', '.dll')):
835 if file.endswith(('.so', '.pyd', '.dll')):
836 frames.append('%s %s\n' % (link,call))
836 frames.append('%s %s\n' % (link,call))
837 continue
837 continue
838 elif file.endswith(('.pyc','.pyo')):
838 elif file.endswith(('.pyc','.pyo')):
839 # Look up the corresponding source file.
839 # Look up the corresponding source file.
840 file = pyfile.source_from_cache(file)
840 file = openpy.source_from_cache(file)
841
841
842 def linereader(file=file, lnum=[lnum], getline=ulinecache.getline):
842 def linereader(file=file, lnum=[lnum], getline=ulinecache.getline):
843 line = getline(file, lnum[0])
843 line = getline(file, lnum[0])
844 lnum[0] += 1
844 lnum[0] += 1
845 return line
845 return line
846
846
847 # Build the list of names on this line of code where the exception
847 # Build the list of names on this line of code where the exception
848 # occurred.
848 # occurred.
849 try:
849 try:
850 names = []
850 names = []
851 name_cont = False
851 name_cont = False
852
852
853 for token_type, token, start, end, line in generate_tokens(linereader):
853 for token_type, token, start, end, line in generate_tokens(linereader):
854 # build composite names
854 # build composite names
855 if token_type == tokenize.NAME and token not in keyword.kwlist:
855 if token_type == tokenize.NAME and token not in keyword.kwlist:
856 if name_cont:
856 if name_cont:
857 # Continuation of a dotted name
857 # Continuation of a dotted name
858 try:
858 try:
859 names[-1].append(token)
859 names[-1].append(token)
860 except IndexError:
860 except IndexError:
861 names.append([token])
861 names.append([token])
862 name_cont = False
862 name_cont = False
863 else:
863 else:
864 # Regular new names. We append everything, the caller
864 # Regular new names. We append everything, the caller
865 # will be responsible for pruning the list later. It's
865 # will be responsible for pruning the list later. It's
866 # very tricky to try to prune as we go, b/c composite
866 # very tricky to try to prune as we go, b/c composite
867 # names can fool us. The pruning at the end is easy
867 # names can fool us. The pruning at the end is easy
868 # to do (or the caller can print a list with repeated
868 # to do (or the caller can print a list with repeated
869 # names if so desired.
869 # names if so desired.
870 names.append([token])
870 names.append([token])
871 elif token == '.':
871 elif token == '.':
872 name_cont = True
872 name_cont = True
873 elif token_type == tokenize.NEWLINE:
873 elif token_type == tokenize.NEWLINE:
874 break
874 break
875
875
876 except (IndexError, UnicodeDecodeError):
876 except (IndexError, UnicodeDecodeError):
877 # signals exit of tokenizer
877 # signals exit of tokenizer
878 pass
878 pass
879 except tokenize.TokenError as msg:
879 except tokenize.TokenError as msg:
880 _m = ("An unexpected error occurred while tokenizing input\n"
880 _m = ("An unexpected error occurred while tokenizing input\n"
881 "The following traceback may be corrupted or invalid\n"
881 "The following traceback may be corrupted or invalid\n"
882 "The error message is: %s\n" % msg)
882 "The error message is: %s\n" % msg)
883 error(_m)
883 error(_m)
884
884
885 # Join composite names (e.g. "dict.fromkeys")
885 # Join composite names (e.g. "dict.fromkeys")
886 names = ['.'.join(n) for n in names]
886 names = ['.'.join(n) for n in names]
887 # prune names list of duplicates, but keep the right order
887 # prune names list of duplicates, but keep the right order
888 unique_names = uniq_stable(names)
888 unique_names = uniq_stable(names)
889
889
890 # Start loop over vars
890 # Start loop over vars
891 lvals = []
891 lvals = []
892 if self.include_vars:
892 if self.include_vars:
893 for name_full in unique_names:
893 for name_full in unique_names:
894 name_base = name_full.split('.',1)[0]
894 name_base = name_full.split('.',1)[0]
895 if name_base in frame.f_code.co_varnames:
895 if name_base in frame.f_code.co_varnames:
896 if name_base in locals:
896 if name_base in locals:
897 try:
897 try:
898 value = repr(eval(name_full,locals))
898 value = repr(eval(name_full,locals))
899 except:
899 except:
900 value = undefined
900 value = undefined
901 else:
901 else:
902 value = undefined
902 value = undefined
903 name = tpl_local_var % name_full
903 name = tpl_local_var % name_full
904 else:
904 else:
905 if name_base in frame.f_globals:
905 if name_base in frame.f_globals:
906 try:
906 try:
907 value = repr(eval(name_full,frame.f_globals))
907 value = repr(eval(name_full,frame.f_globals))
908 except:
908 except:
909 value = undefined
909 value = undefined
910 else:
910 else:
911 value = undefined
911 value = undefined
912 name = tpl_global_var % name_full
912 name = tpl_global_var % name_full
913 lvals.append(tpl_name_val % (name,value))
913 lvals.append(tpl_name_val % (name,value))
914 if lvals:
914 if lvals:
915 lvals = '%s%s' % (indent,em_normal.join(lvals))
915 lvals = '%s%s' % (indent,em_normal.join(lvals))
916 else:
916 else:
917 lvals = ''
917 lvals = ''
918
918
919 level = '%s %s\n' % (link,call)
919 level = '%s %s\n' % (link,call)
920
920
921 if index is None:
921 if index is None:
922 frames.append(level)
922 frames.append(level)
923 else:
923 else:
924 frames.append('%s%s' % (level,''.join(
924 frames.append('%s%s' % (level,''.join(
925 _format_traceback_lines(lnum,index,lines,Colors,lvals,
925 _format_traceback_lines(lnum,index,lines,Colors,lvals,
926 col_scheme))))
926 col_scheme))))
927
927
928 # Get (safely) a string form of the exception info
928 # Get (safely) a string form of the exception info
929 try:
929 try:
930 etype_str,evalue_str = map(str,(etype,evalue))
930 etype_str,evalue_str = map(str,(etype,evalue))
931 except:
931 except:
932 # User exception is improperly defined.
932 # User exception is improperly defined.
933 etype,evalue = str,sys.exc_info()[:2]
933 etype,evalue = str,sys.exc_info()[:2]
934 etype_str,evalue_str = map(str,(etype,evalue))
934 etype_str,evalue_str = map(str,(etype,evalue))
935 # ... and format it
935 # ... and format it
936 exception = ['%s%s%s: %s' % (Colors.excName, etype_str,
936 exception = ['%s%s%s: %s' % (Colors.excName, etype_str,
937 ColorsNormal, py3compat.cast_unicode(evalue_str))]
937 ColorsNormal, py3compat.cast_unicode(evalue_str))]
938 if (not py3compat.PY3) and type(evalue) is types.InstanceType:
938 if (not py3compat.PY3) and type(evalue) is types.InstanceType:
939 try:
939 try:
940 names = [w for w in dir(evalue) if isinstance(w, basestring)]
940 names = [w for w in dir(evalue) if isinstance(w, basestring)]
941 except:
941 except:
942 # Every now and then, an object with funny inernals blows up
942 # Every now and then, an object with funny inernals blows up
943 # when dir() is called on it. We do the best we can to report
943 # when dir() is called on it. We do the best we can to report
944 # the problem and continue
944 # the problem and continue
945 _m = '%sException reporting error (object with broken dir())%s:'
945 _m = '%sException reporting error (object with broken dir())%s:'
946 exception.append(_m % (Colors.excName,ColorsNormal))
946 exception.append(_m % (Colors.excName,ColorsNormal))
947 etype_str,evalue_str = map(str,sys.exc_info()[:2])
947 etype_str,evalue_str = map(str,sys.exc_info()[:2])
948 exception.append('%s%s%s: %s' % (Colors.excName,etype_str,
948 exception.append('%s%s%s: %s' % (Colors.excName,etype_str,
949 ColorsNormal, py3compat.cast_unicode(evalue_str)))
949 ColorsNormal, py3compat.cast_unicode(evalue_str)))
950 names = []
950 names = []
951 for name in names:
951 for name in names:
952 value = text_repr(getattr(evalue, name))
952 value = text_repr(getattr(evalue, name))
953 exception.append('\n%s%s = %s' % (indent, name, value))
953 exception.append('\n%s%s = %s' % (indent, name, value))
954
954
955 # vds: >>
955 # vds: >>
956 if records:
956 if records:
957 filepath, lnum = records[-1][1:3]
957 filepath, lnum = records[-1][1:3]
958 #print "file:", str(file), "linenb", str(lnum) # dbg
958 #print "file:", str(file), "linenb", str(lnum) # dbg
959 filepath = os.path.abspath(filepath)
959 filepath = os.path.abspath(filepath)
960 ipinst = ipapi.get()
960 ipinst = ipapi.get()
961 if ipinst is not None:
961 if ipinst is not None:
962 ipinst.hooks.synchronize_with_editor(filepath, lnum, 0)
962 ipinst.hooks.synchronize_with_editor(filepath, lnum, 0)
963 # vds: <<
963 # vds: <<
964
964
965 # return all our info assembled as a single string
965 # return all our info assembled as a single string
966 # return '%s\n\n%s\n%s' % (head,'\n'.join(frames),''.join(exception[0]) )
966 # return '%s\n\n%s\n%s' % (head,'\n'.join(frames),''.join(exception[0]) )
967 return [head] + frames + [''.join(exception[0])]
967 return [head] + frames + [''.join(exception[0])]
968
968
969 def debugger(self,force=False):
969 def debugger(self,force=False):
970 """Call up the pdb debugger if desired, always clean up the tb
970 """Call up the pdb debugger if desired, always clean up the tb
971 reference.
971 reference.
972
972
973 Keywords:
973 Keywords:
974
974
975 - force(False): by default, this routine checks the instance call_pdb
975 - force(False): by default, this routine checks the instance call_pdb
976 flag and does not actually invoke the debugger if the flag is false.
976 flag and does not actually invoke the debugger if the flag is false.
977 The 'force' option forces the debugger to activate even if the flag
977 The 'force' option forces the debugger to activate even if the flag
978 is false.
978 is false.
979
979
980 If the call_pdb flag is set, the pdb interactive debugger is
980 If the call_pdb flag is set, the pdb interactive debugger is
981 invoked. In all cases, the self.tb reference to the current traceback
981 invoked. In all cases, the self.tb reference to the current traceback
982 is deleted to prevent lingering references which hamper memory
982 is deleted to prevent lingering references which hamper memory
983 management.
983 management.
984
984
985 Note that each call to pdb() does an 'import readline', so if your app
985 Note that each call to pdb() does an 'import readline', so if your app
986 requires a special setup for the readline completers, you'll have to
986 requires a special setup for the readline completers, you'll have to
987 fix that by hand after invoking the exception handler."""
987 fix that by hand after invoking the exception handler."""
988
988
989 if force or self.call_pdb:
989 if force or self.call_pdb:
990 if self.pdb is None:
990 if self.pdb is None:
991 self.pdb = debugger.Pdb(
991 self.pdb = debugger.Pdb(
992 self.color_scheme_table.active_scheme_name)
992 self.color_scheme_table.active_scheme_name)
993 # the system displayhook may have changed, restore the original
993 # the system displayhook may have changed, restore the original
994 # for pdb
994 # for pdb
995 display_trap = DisplayTrap(hook=sys.__displayhook__)
995 display_trap = DisplayTrap(hook=sys.__displayhook__)
996 with display_trap:
996 with display_trap:
997 self.pdb.reset()
997 self.pdb.reset()
998 # Find the right frame so we don't pop up inside ipython itself
998 # Find the right frame so we don't pop up inside ipython itself
999 if hasattr(self,'tb') and self.tb is not None:
999 if hasattr(self,'tb') and self.tb is not None:
1000 etb = self.tb
1000 etb = self.tb
1001 else:
1001 else:
1002 etb = self.tb = sys.last_traceback
1002 etb = self.tb = sys.last_traceback
1003 while self.tb is not None and self.tb.tb_next is not None:
1003 while self.tb is not None and self.tb.tb_next is not None:
1004 self.tb = self.tb.tb_next
1004 self.tb = self.tb.tb_next
1005 if etb and etb.tb_next:
1005 if etb and etb.tb_next:
1006 etb = etb.tb_next
1006 etb = etb.tb_next
1007 self.pdb.botframe = etb.tb_frame
1007 self.pdb.botframe = etb.tb_frame
1008 self.pdb.interaction(self.tb.tb_frame, self.tb)
1008 self.pdb.interaction(self.tb.tb_frame, self.tb)
1009
1009
1010 if hasattr(self,'tb'):
1010 if hasattr(self,'tb'):
1011 del self.tb
1011 del self.tb
1012
1012
1013 def handler(self, info=None):
1013 def handler(self, info=None):
1014 (etype, evalue, etb) = info or sys.exc_info()
1014 (etype, evalue, etb) = info or sys.exc_info()
1015 self.tb = etb
1015 self.tb = etb
1016 ostream = self.ostream
1016 ostream = self.ostream
1017 ostream.flush()
1017 ostream.flush()
1018 ostream.write(self.text(etype, evalue, etb))
1018 ostream.write(self.text(etype, evalue, etb))
1019 ostream.write('\n')
1019 ostream.write('\n')
1020 ostream.flush()
1020 ostream.flush()
1021
1021
1022 # Changed so an instance can just be called as VerboseTB_inst() and print
1022 # Changed so an instance can just be called as VerboseTB_inst() and print
1023 # out the right info on its own.
1023 # out the right info on its own.
1024 def __call__(self, etype=None, evalue=None, etb=None):
1024 def __call__(self, etype=None, evalue=None, etb=None):
1025 """This hook can replace sys.excepthook (for Python 2.1 or higher)."""
1025 """This hook can replace sys.excepthook (for Python 2.1 or higher)."""
1026 if etb is None:
1026 if etb is None:
1027 self.handler()
1027 self.handler()
1028 else:
1028 else:
1029 self.handler((etype, evalue, etb))
1029 self.handler((etype, evalue, etb))
1030 try:
1030 try:
1031 self.debugger()
1031 self.debugger()
1032 except KeyboardInterrupt:
1032 except KeyboardInterrupt:
1033 print "\nKeyboardInterrupt"
1033 print "\nKeyboardInterrupt"
1034
1034
1035 #----------------------------------------------------------------------------
1035 #----------------------------------------------------------------------------
1036 class FormattedTB(VerboseTB, ListTB):
1036 class FormattedTB(VerboseTB, ListTB):
1037 """Subclass ListTB but allow calling with a traceback.
1037 """Subclass ListTB but allow calling with a traceback.
1038
1038
1039 It can thus be used as a sys.excepthook for Python > 2.1.
1039 It can thus be used as a sys.excepthook for Python > 2.1.
1040
1040
1041 Also adds 'Context' and 'Verbose' modes, not available in ListTB.
1041 Also adds 'Context' and 'Verbose' modes, not available in ListTB.
1042
1042
1043 Allows a tb_offset to be specified. This is useful for situations where
1043 Allows a tb_offset to be specified. This is useful for situations where
1044 one needs to remove a number of topmost frames from the traceback (such as
1044 one needs to remove a number of topmost frames from the traceback (such as
1045 occurs with python programs that themselves execute other python code,
1045 occurs with python programs that themselves execute other python code,
1046 like Python shells). """
1046 like Python shells). """
1047
1047
1048 def __init__(self, mode='Plain', color_scheme='Linux', call_pdb=False,
1048 def __init__(self, mode='Plain', color_scheme='Linux', call_pdb=False,
1049 ostream=None,
1049 ostream=None,
1050 tb_offset=0, long_header=False, include_vars=False,
1050 tb_offset=0, long_header=False, include_vars=False,
1051 check_cache=None):
1051 check_cache=None):
1052
1052
1053 # NEVER change the order of this list. Put new modes at the end:
1053 # NEVER change the order of this list. Put new modes at the end:
1054 self.valid_modes = ['Plain','Context','Verbose']
1054 self.valid_modes = ['Plain','Context','Verbose']
1055 self.verbose_modes = self.valid_modes[1:3]
1055 self.verbose_modes = self.valid_modes[1:3]
1056
1056
1057 VerboseTB.__init__(self, color_scheme=color_scheme, call_pdb=call_pdb,
1057 VerboseTB.__init__(self, color_scheme=color_scheme, call_pdb=call_pdb,
1058 ostream=ostream, tb_offset=tb_offset,
1058 ostream=ostream, tb_offset=tb_offset,
1059 long_header=long_header, include_vars=include_vars,
1059 long_header=long_header, include_vars=include_vars,
1060 check_cache=check_cache)
1060 check_cache=check_cache)
1061
1061
1062 # Different types of tracebacks are joined with different separators to
1062 # Different types of tracebacks are joined with different separators to
1063 # form a single string. They are taken from this dict
1063 # form a single string. They are taken from this dict
1064 self._join_chars = dict(Plain='', Context='\n', Verbose='\n')
1064 self._join_chars = dict(Plain='', Context='\n', Verbose='\n')
1065 # set_mode also sets the tb_join_char attribute
1065 # set_mode also sets the tb_join_char attribute
1066 self.set_mode(mode)
1066 self.set_mode(mode)
1067
1067
1068 def _extract_tb(self,tb):
1068 def _extract_tb(self,tb):
1069 if tb:
1069 if tb:
1070 return traceback.extract_tb(tb)
1070 return traceback.extract_tb(tb)
1071 else:
1071 else:
1072 return None
1072 return None
1073
1073
1074 def structured_traceback(self, etype, value, tb, tb_offset=None, context=5):
1074 def structured_traceback(self, etype, value, tb, tb_offset=None, context=5):
1075 tb_offset = self.tb_offset if tb_offset is None else tb_offset
1075 tb_offset = self.tb_offset if tb_offset is None else tb_offset
1076 mode = self.mode
1076 mode = self.mode
1077 if mode in self.verbose_modes:
1077 if mode in self.verbose_modes:
1078 # Verbose modes need a full traceback
1078 # Verbose modes need a full traceback
1079 return VerboseTB.structured_traceback(
1079 return VerboseTB.structured_traceback(
1080 self, etype, value, tb, tb_offset, context
1080 self, etype, value, tb, tb_offset, context
1081 )
1081 )
1082 else:
1082 else:
1083 # We must check the source cache because otherwise we can print
1083 # We must check the source cache because otherwise we can print
1084 # out-of-date source code.
1084 # out-of-date source code.
1085 self.check_cache()
1085 self.check_cache()
1086 # Now we can extract and format the exception
1086 # Now we can extract and format the exception
1087 elist = self._extract_tb(tb)
1087 elist = self._extract_tb(tb)
1088 return ListTB.structured_traceback(
1088 return ListTB.structured_traceback(
1089 self, etype, value, elist, tb_offset, context
1089 self, etype, value, elist, tb_offset, context
1090 )
1090 )
1091
1091
1092 def stb2text(self, stb):
1092 def stb2text(self, stb):
1093 """Convert a structured traceback (a list) to a string."""
1093 """Convert a structured traceback (a list) to a string."""
1094 return self.tb_join_char.join(stb)
1094 return self.tb_join_char.join(stb)
1095
1095
1096
1096
1097 def set_mode(self,mode=None):
1097 def set_mode(self,mode=None):
1098 """Switch to the desired mode.
1098 """Switch to the desired mode.
1099
1099
1100 If mode is not specified, cycles through the available modes."""
1100 If mode is not specified, cycles through the available modes."""
1101
1101
1102 if not mode:
1102 if not mode:
1103 new_idx = ( self.valid_modes.index(self.mode) + 1 ) % \
1103 new_idx = ( self.valid_modes.index(self.mode) + 1 ) % \
1104 len(self.valid_modes)
1104 len(self.valid_modes)
1105 self.mode = self.valid_modes[new_idx]
1105 self.mode = self.valid_modes[new_idx]
1106 elif mode not in self.valid_modes:
1106 elif mode not in self.valid_modes:
1107 raise ValueError('Unrecognized mode in FormattedTB: <'+mode+'>\n'
1107 raise ValueError('Unrecognized mode in FormattedTB: <'+mode+'>\n'
1108 'Valid modes: '+str(self.valid_modes))
1108 'Valid modes: '+str(self.valid_modes))
1109 else:
1109 else:
1110 self.mode = mode
1110 self.mode = mode
1111 # include variable details only in 'Verbose' mode
1111 # include variable details only in 'Verbose' mode
1112 self.include_vars = (self.mode == self.valid_modes[2])
1112 self.include_vars = (self.mode == self.valid_modes[2])
1113 # Set the join character for generating text tracebacks
1113 # Set the join character for generating text tracebacks
1114 self.tb_join_char = self._join_chars[self.mode]
1114 self.tb_join_char = self._join_chars[self.mode]
1115
1115
1116 # some convenient shorcuts
1116 # some convenient shorcuts
1117 def plain(self):
1117 def plain(self):
1118 self.set_mode(self.valid_modes[0])
1118 self.set_mode(self.valid_modes[0])
1119
1119
1120 def context(self):
1120 def context(self):
1121 self.set_mode(self.valid_modes[1])
1121 self.set_mode(self.valid_modes[1])
1122
1122
1123 def verbose(self):
1123 def verbose(self):
1124 self.set_mode(self.valid_modes[2])
1124 self.set_mode(self.valid_modes[2])
1125
1125
1126 #----------------------------------------------------------------------------
1126 #----------------------------------------------------------------------------
1127 class AutoFormattedTB(FormattedTB):
1127 class AutoFormattedTB(FormattedTB):
1128 """A traceback printer which can be called on the fly.
1128 """A traceback printer which can be called on the fly.
1129
1129
1130 It will find out about exceptions by itself.
1130 It will find out about exceptions by itself.
1131
1131
1132 A brief example::
1132 A brief example::
1133
1133
1134 AutoTB = AutoFormattedTB(mode = 'Verbose',color_scheme='Linux')
1134 AutoTB = AutoFormattedTB(mode = 'Verbose',color_scheme='Linux')
1135 try:
1135 try:
1136 ...
1136 ...
1137 except:
1137 except:
1138 AutoTB() # or AutoTB(out=logfile) where logfile is an open file object
1138 AutoTB() # or AutoTB(out=logfile) where logfile is an open file object
1139 """
1139 """
1140
1140
1141 def __call__(self,etype=None,evalue=None,etb=None,
1141 def __call__(self,etype=None,evalue=None,etb=None,
1142 out=None,tb_offset=None):
1142 out=None,tb_offset=None):
1143 """Print out a formatted exception traceback.
1143 """Print out a formatted exception traceback.
1144
1144
1145 Optional arguments:
1145 Optional arguments:
1146 - out: an open file-like object to direct output to.
1146 - out: an open file-like object to direct output to.
1147
1147
1148 - tb_offset: the number of frames to skip over in the stack, on a
1148 - tb_offset: the number of frames to skip over in the stack, on a
1149 per-call basis (this overrides temporarily the instance's tb_offset
1149 per-call basis (this overrides temporarily the instance's tb_offset
1150 given at initialization time. """
1150 given at initialization time. """
1151
1151
1152
1152
1153 if out is None:
1153 if out is None:
1154 out = self.ostream
1154 out = self.ostream
1155 out.flush()
1155 out.flush()
1156 out.write(self.text(etype, evalue, etb, tb_offset))
1156 out.write(self.text(etype, evalue, etb, tb_offset))
1157 out.write('\n')
1157 out.write('\n')
1158 out.flush()
1158 out.flush()
1159 # FIXME: we should remove the auto pdb behavior from here and leave
1159 # FIXME: we should remove the auto pdb behavior from here and leave
1160 # that to the clients.
1160 # that to the clients.
1161 try:
1161 try:
1162 self.debugger()
1162 self.debugger()
1163 except KeyboardInterrupt:
1163 except KeyboardInterrupt:
1164 print "\nKeyboardInterrupt"
1164 print "\nKeyboardInterrupt"
1165
1165
1166 def structured_traceback(self, etype=None, value=None, tb=None,
1166 def structured_traceback(self, etype=None, value=None, tb=None,
1167 tb_offset=None, context=5):
1167 tb_offset=None, context=5):
1168 if etype is None:
1168 if etype is None:
1169 etype,value,tb = sys.exc_info()
1169 etype,value,tb = sys.exc_info()
1170 self.tb = tb
1170 self.tb = tb
1171 return FormattedTB.structured_traceback(
1171 return FormattedTB.structured_traceback(
1172 self, etype, value, tb, tb_offset, context)
1172 self, etype, value, tb, tb_offset, context)
1173
1173
1174 #---------------------------------------------------------------------------
1174 #---------------------------------------------------------------------------
1175
1175
1176 # A simple class to preserve Nathan's original functionality.
1176 # A simple class to preserve Nathan's original functionality.
1177 class ColorTB(FormattedTB):
1177 class ColorTB(FormattedTB):
1178 """Shorthand to initialize a FormattedTB in Linux colors mode."""
1178 """Shorthand to initialize a FormattedTB in Linux colors mode."""
1179 def __init__(self,color_scheme='Linux',call_pdb=0):
1179 def __init__(self,color_scheme='Linux',call_pdb=0):
1180 FormattedTB.__init__(self,color_scheme=color_scheme,
1180 FormattedTB.__init__(self,color_scheme=color_scheme,
1181 call_pdb=call_pdb)
1181 call_pdb=call_pdb)
1182
1182
1183
1183
1184 class SyntaxTB(ListTB):
1184 class SyntaxTB(ListTB):
1185 """Extension which holds some state: the last exception value"""
1185 """Extension which holds some state: the last exception value"""
1186
1186
1187 def __init__(self,color_scheme = 'NoColor'):
1187 def __init__(self,color_scheme = 'NoColor'):
1188 ListTB.__init__(self,color_scheme)
1188 ListTB.__init__(self,color_scheme)
1189 self.last_syntax_error = None
1189 self.last_syntax_error = None
1190
1190
1191 def __call__(self, etype, value, elist):
1191 def __call__(self, etype, value, elist):
1192 self.last_syntax_error = value
1192 self.last_syntax_error = value
1193 ListTB.__call__(self,etype,value,elist)
1193 ListTB.__call__(self,etype,value,elist)
1194
1194
1195 def clear_err_state(self):
1195 def clear_err_state(self):
1196 """Return the current error state and clear it"""
1196 """Return the current error state and clear it"""
1197 e = self.last_syntax_error
1197 e = self.last_syntax_error
1198 self.last_syntax_error = None
1198 self.last_syntax_error = None
1199 return e
1199 return e
1200
1200
1201 def stb2text(self, stb):
1201 def stb2text(self, stb):
1202 """Convert a structured traceback (a list) to a string."""
1202 """Convert a structured traceback (a list) to a string."""
1203 return ''.join(stb)
1203 return ''.join(stb)
1204
1204
1205
1205
1206 #----------------------------------------------------------------------------
1206 #----------------------------------------------------------------------------
1207 # module testing (minimal)
1207 # module testing (minimal)
1208 if __name__ == "__main__":
1208 if __name__ == "__main__":
1209 def spam(c, d_e):
1209 def spam(c, d_e):
1210 (d, e) = d_e
1210 (d, e) = d_e
1211 x = c + d
1211 x = c + d
1212 y = c * d
1212 y = c * d
1213 foo(x, y)
1213 foo(x, y)
1214
1214
1215 def foo(a, b, bar=1):
1215 def foo(a, b, bar=1):
1216 eggs(a, b + bar)
1216 eggs(a, b + bar)
1217
1217
1218 def eggs(f, g, z=globals()):
1218 def eggs(f, g, z=globals()):
1219 h = f + g
1219 h = f + g
1220 i = f - g
1220 i = f - g
1221 return h / i
1221 return h / i
1222
1222
1223 print ''
1223 print ''
1224 print '*** Before ***'
1224 print '*** Before ***'
1225 try:
1225 try:
1226 print spam(1, (2, 3))
1226 print spam(1, (2, 3))
1227 except:
1227 except:
1228 traceback.print_exc()
1228 traceback.print_exc()
1229 print ''
1229 print ''
1230
1230
1231 handler = ColorTB()
1231 handler = ColorTB()
1232 print '*** ColorTB ***'
1232 print '*** ColorTB ***'
1233 try:
1233 try:
1234 print spam(1, (2, 3))
1234 print spam(1, (2, 3))
1235 except:
1235 except:
1236 handler(*sys.exc_info())
1236 handler(*sys.exc_info())
1237 print ''
1237 print ''
1238
1238
1239 handler = VerboseTB()
1239 handler = VerboseTB()
1240 print '*** VerboseTB ***'
1240 print '*** VerboseTB ***'
1241 try:
1241 try:
1242 print spam(1, (2, 3))
1242 print spam(1, (2, 3))
1243 except:
1243 except:
1244 handler(*sys.exc_info())
1244 handler(*sys.exc_info())
1245 print ''
1245 print ''
1246
1246
@@ -1,509 +1,509 b''
1 """IPython extension to reload modules before executing user code.
1 """IPython extension to reload modules before executing user code.
2
2
3 ``autoreload`` reloads modules automatically before entering the execution of
3 ``autoreload`` reloads modules automatically before entering the execution of
4 code typed at the IPython prompt.
4 code typed at the IPython prompt.
5
5
6 This makes for example the following workflow possible:
6 This makes for example the following workflow possible:
7
7
8 .. sourcecode:: ipython
8 .. sourcecode:: ipython
9
9
10 In [1]: %load_ext autoreload
10 In [1]: %load_ext autoreload
11
11
12 In [2]: %autoreload 2
12 In [2]: %autoreload 2
13
13
14 In [3]: from foo import some_function
14 In [3]: from foo import some_function
15
15
16 In [4]: some_function()
16 In [4]: some_function()
17 Out[4]: 42
17 Out[4]: 42
18
18
19 In [5]: # open foo.py in an editor and change some_function to return 43
19 In [5]: # open foo.py in an editor and change some_function to return 43
20
20
21 In [6]: some_function()
21 In [6]: some_function()
22 Out[6]: 43
22 Out[6]: 43
23
23
24 The module was reloaded without reloading it explicitly, and the object
24 The module was reloaded without reloading it explicitly, and the object
25 imported with ``from foo import ...`` was also updated.
25 imported with ``from foo import ...`` was also updated.
26
26
27 Usage
27 Usage
28 =====
28 =====
29
29
30 The following magic commands are provided:
30 The following magic commands are provided:
31
31
32 ``%autoreload``
32 ``%autoreload``
33
33
34 Reload all modules (except those excluded by ``%aimport``)
34 Reload all modules (except those excluded by ``%aimport``)
35 automatically now.
35 automatically now.
36
36
37 ``%autoreload 0``
37 ``%autoreload 0``
38
38
39 Disable automatic reloading.
39 Disable automatic reloading.
40
40
41 ``%autoreload 1``
41 ``%autoreload 1``
42
42
43 Reload all modules imported with ``%aimport`` every time before
43 Reload all modules imported with ``%aimport`` every time before
44 executing the Python code typed.
44 executing the Python code typed.
45
45
46 ``%autoreload 2``
46 ``%autoreload 2``
47
47
48 Reload all modules (except those excluded by ``%aimport``) every
48 Reload all modules (except those excluded by ``%aimport``) every
49 time before executing the Python code typed.
49 time before executing the Python code typed.
50
50
51 ``%aimport``
51 ``%aimport``
52
52
53 List modules which are to be automatically imported or not to be imported.
53 List modules which are to be automatically imported or not to be imported.
54
54
55 ``%aimport foo``
55 ``%aimport foo``
56
56
57 Import module 'foo' and mark it to be autoreloaded for ``%autoreload 1``
57 Import module 'foo' and mark it to be autoreloaded for ``%autoreload 1``
58
58
59 ``%aimport -foo``
59 ``%aimport -foo``
60
60
61 Mark module 'foo' to not be autoreloaded.
61 Mark module 'foo' to not be autoreloaded.
62
62
63 Caveats
63 Caveats
64 =======
64 =======
65
65
66 Reloading Python modules in a reliable way is in general difficult,
66 Reloading Python modules in a reliable way is in general difficult,
67 and unexpected things may occur. ``%autoreload`` tries to work around
67 and unexpected things may occur. ``%autoreload`` tries to work around
68 common pitfalls by replacing function code objects and parts of
68 common pitfalls by replacing function code objects and parts of
69 classes previously in the module with new versions. This makes the
69 classes previously in the module with new versions. This makes the
70 following things to work:
70 following things to work:
71
71
72 - Functions and classes imported via 'from xxx import foo' are upgraded
72 - Functions and classes imported via 'from xxx import foo' are upgraded
73 to new versions when 'xxx' is reloaded.
73 to new versions when 'xxx' is reloaded.
74
74
75 - Methods and properties of classes are upgraded on reload, so that
75 - Methods and properties of classes are upgraded on reload, so that
76 calling 'c.foo()' on an object 'c' created before the reload causes
76 calling 'c.foo()' on an object 'c' created before the reload causes
77 the new code for 'foo' to be executed.
77 the new code for 'foo' to be executed.
78
78
79 Some of the known remaining caveats are:
79 Some of the known remaining caveats are:
80
80
81 - Replacing code objects does not always succeed: changing a @property
81 - Replacing code objects does not always succeed: changing a @property
82 in a class to an ordinary method or a method to a member variable
82 in a class to an ordinary method or a method to a member variable
83 can cause problems (but in old objects only).
83 can cause problems (but in old objects only).
84
84
85 - Functions that are removed (eg. via monkey-patching) from a module
85 - Functions that are removed (eg. via monkey-patching) from a module
86 before it is reloaded are not upgraded.
86 before it is reloaded are not upgraded.
87
87
88 - C extension modules cannot be reloaded, and so cannot be autoreloaded.
88 - C extension modules cannot be reloaded, and so cannot be autoreloaded.
89 """
89 """
90 from __future__ import print_function
90 from __future__ import print_function
91
91
92 skip_doctest = True
92 skip_doctest = True
93
93
94 #-----------------------------------------------------------------------------
94 #-----------------------------------------------------------------------------
95 # Copyright (C) 2000 Thomas Heller
95 # Copyright (C) 2000 Thomas Heller
96 # Copyright (C) 2008 Pauli Virtanen <pav@iki.fi>
96 # Copyright (C) 2008 Pauli Virtanen <pav@iki.fi>
97 # Copyright (C) 2012 The IPython Development Team
97 # Copyright (C) 2012 The IPython Development Team
98 #
98 #
99 # Distributed under the terms of the BSD License. The full license is in
99 # Distributed under the terms of the BSD License. The full license is in
100 # the file COPYING, distributed as part of this software.
100 # the file COPYING, distributed as part of this software.
101 #-----------------------------------------------------------------------------
101 #-----------------------------------------------------------------------------
102 #
102 #
103 # This IPython module is written by Pauli Virtanen, based on the autoreload
103 # This IPython module is written by Pauli Virtanen, based on the autoreload
104 # code by Thomas Heller.
104 # code by Thomas Heller.
105
105
106 #-----------------------------------------------------------------------------
106 #-----------------------------------------------------------------------------
107 # Imports
107 # Imports
108 #-----------------------------------------------------------------------------
108 #-----------------------------------------------------------------------------
109
109
110 import os
110 import os
111 import sys
111 import sys
112 import traceback
112 import traceback
113 import types
113 import types
114 import weakref
114 import weakref
115
115
116 try:
116 try:
117 # Reload is not defined by default in Python3.
117 # Reload is not defined by default in Python3.
118 reload
118 reload
119 except NameError:
119 except NameError:
120 from imp import reload
120 from imp import reload
121
121
122 from IPython.utils import pyfile
122 from IPython.utils import openpy
123 from IPython.utils.py3compat import PY3
123 from IPython.utils.py3compat import PY3
124
124
125 #------------------------------------------------------------------------------
125 #------------------------------------------------------------------------------
126 # Autoreload functionality
126 # Autoreload functionality
127 #------------------------------------------------------------------------------
127 #------------------------------------------------------------------------------
128
128
129 class ModuleReloader(object):
129 class ModuleReloader(object):
130 enabled = False
130 enabled = False
131 """Whether this reloader is enabled"""
131 """Whether this reloader is enabled"""
132
132
133 failed = {}
133 failed = {}
134 """Modules that failed to reload: {module: mtime-on-failed-reload, ...}"""
134 """Modules that failed to reload: {module: mtime-on-failed-reload, ...}"""
135
135
136 modules = {}
136 modules = {}
137 """Modules specially marked as autoreloadable."""
137 """Modules specially marked as autoreloadable."""
138
138
139 skip_modules = {}
139 skip_modules = {}
140 """Modules specially marked as not autoreloadable."""
140 """Modules specially marked as not autoreloadable."""
141
141
142 check_all = True
142 check_all = True
143 """Autoreload all modules, not just those listed in 'modules'"""
143 """Autoreload all modules, not just those listed in 'modules'"""
144
144
145 old_objects = {}
145 old_objects = {}
146 """(module-name, name) -> weakref, for replacing old code objects"""
146 """(module-name, name) -> weakref, for replacing old code objects"""
147
147
148 def mark_module_skipped(self, module_name):
148 def mark_module_skipped(self, module_name):
149 """Skip reloading the named module in the future"""
149 """Skip reloading the named module in the future"""
150 try:
150 try:
151 del self.modules[module_name]
151 del self.modules[module_name]
152 except KeyError:
152 except KeyError:
153 pass
153 pass
154 self.skip_modules[module_name] = True
154 self.skip_modules[module_name] = True
155
155
156 def mark_module_reloadable(self, module_name):
156 def mark_module_reloadable(self, module_name):
157 """Reload the named module in the future (if it is imported)"""
157 """Reload the named module in the future (if it is imported)"""
158 try:
158 try:
159 del self.skip_modules[module_name]
159 del self.skip_modules[module_name]
160 except KeyError:
160 except KeyError:
161 pass
161 pass
162 self.modules[module_name] = True
162 self.modules[module_name] = True
163
163
164 def aimport_module(self, module_name):
164 def aimport_module(self, module_name):
165 """Import a module, and mark it reloadable
165 """Import a module, and mark it reloadable
166
166
167 Returns
167 Returns
168 -------
168 -------
169 top_module : module
169 top_module : module
170 The imported module if it is top-level, or the top-level
170 The imported module if it is top-level, or the top-level
171 top_name : module
171 top_name : module
172 Name of top_module
172 Name of top_module
173
173
174 """
174 """
175 self.mark_module_reloadable(module_name)
175 self.mark_module_reloadable(module_name)
176
176
177 __import__(module_name)
177 __import__(module_name)
178 top_name = module_name.split('.')[0]
178 top_name = module_name.split('.')[0]
179 top_module = sys.modules[top_name]
179 top_module = sys.modules[top_name]
180 return top_module, top_name
180 return top_module, top_name
181
181
182 def check(self, check_all=False):
182 def check(self, check_all=False):
183 """Check whether some modules need to be reloaded."""
183 """Check whether some modules need to be reloaded."""
184
184
185 if not self.enabled and not check_all:
185 if not self.enabled and not check_all:
186 return
186 return
187
187
188 if check_all or self.check_all:
188 if check_all or self.check_all:
189 modules = sys.modules.keys()
189 modules = sys.modules.keys()
190 else:
190 else:
191 modules = self.modules.keys()
191 modules = self.modules.keys()
192
192
193 for modname in modules:
193 for modname in modules:
194 m = sys.modules.get(modname, None)
194 m = sys.modules.get(modname, None)
195
195
196 if modname in self.skip_modules:
196 if modname in self.skip_modules:
197 continue
197 continue
198
198
199 if not hasattr(m, '__file__'):
199 if not hasattr(m, '__file__'):
200 continue
200 continue
201
201
202 if m.__name__ == '__main__':
202 if m.__name__ == '__main__':
203 # we cannot reload(__main__)
203 # we cannot reload(__main__)
204 continue
204 continue
205
205
206 filename = m.__file__
206 filename = m.__file__
207 path, ext = os.path.splitext(filename)
207 path, ext = os.path.splitext(filename)
208
208
209 if ext.lower() == '.py':
209 if ext.lower() == '.py':
210 pyc_filename = pyfile.cache_from_source(filename)
210 pyc_filename = openpy.cache_from_source(filename)
211 py_filename = filename
211 py_filename = filename
212 else:
212 else:
213 pyc_filename = filename
213 pyc_filename = filename
214 try:
214 try:
215 py_filename = pyfile.source_from_cache(filename)
215 py_filename = openpy.source_from_cache(filename)
216 except ValueError:
216 except ValueError:
217 continue
217 continue
218
218
219 try:
219 try:
220 pymtime = os.stat(py_filename).st_mtime
220 pymtime = os.stat(py_filename).st_mtime
221 if pymtime <= os.stat(pyc_filename).st_mtime:
221 if pymtime <= os.stat(pyc_filename).st_mtime:
222 continue
222 continue
223 if self.failed.get(py_filename, None) == pymtime:
223 if self.failed.get(py_filename, None) == pymtime:
224 continue
224 continue
225 except OSError:
225 except OSError:
226 continue
226 continue
227
227
228 try:
228 try:
229 superreload(m, reload, self.old_objects)
229 superreload(m, reload, self.old_objects)
230 if py_filename in self.failed:
230 if py_filename in self.failed:
231 del self.failed[py_filename]
231 del self.failed[py_filename]
232 except:
232 except:
233 print("[autoreload of %s failed: %s]" % (
233 print("[autoreload of %s failed: %s]" % (
234 modname, traceback.format_exc(1)), file=sys.stderr)
234 modname, traceback.format_exc(1)), file=sys.stderr)
235 self.failed[py_filename] = pymtime
235 self.failed[py_filename] = pymtime
236
236
237 #------------------------------------------------------------------------------
237 #------------------------------------------------------------------------------
238 # superreload
238 # superreload
239 #------------------------------------------------------------------------------
239 #------------------------------------------------------------------------------
240
240
241 if PY3:
241 if PY3:
242 func_attrs = ['__code__', '__defaults__', '__doc__',
242 func_attrs = ['__code__', '__defaults__', '__doc__',
243 '__closure__', '__globals__', '__dict__']
243 '__closure__', '__globals__', '__dict__']
244 else:
244 else:
245 func_attrs = ['func_code', 'func_defaults', 'func_doc',
245 func_attrs = ['func_code', 'func_defaults', 'func_doc',
246 'func_closure', 'func_globals', 'func_dict']
246 'func_closure', 'func_globals', 'func_dict']
247
247
248
248
249 def update_function(old, new):
249 def update_function(old, new):
250 """Upgrade the code object of a function"""
250 """Upgrade the code object of a function"""
251 for name in func_attrs:
251 for name in func_attrs:
252 try:
252 try:
253 setattr(old, name, getattr(new, name))
253 setattr(old, name, getattr(new, name))
254 except (AttributeError, TypeError):
254 except (AttributeError, TypeError):
255 pass
255 pass
256
256
257
257
258 def update_class(old, new):
258 def update_class(old, new):
259 """Replace stuff in the __dict__ of a class, and upgrade
259 """Replace stuff in the __dict__ of a class, and upgrade
260 method code objects"""
260 method code objects"""
261 for key in old.__dict__.keys():
261 for key in old.__dict__.keys():
262 old_obj = getattr(old, key)
262 old_obj = getattr(old, key)
263
263
264 try:
264 try:
265 new_obj = getattr(new, key)
265 new_obj = getattr(new, key)
266 except AttributeError:
266 except AttributeError:
267 # obsolete attribute: remove it
267 # obsolete attribute: remove it
268 try:
268 try:
269 delattr(old, key)
269 delattr(old, key)
270 except (AttributeError, TypeError):
270 except (AttributeError, TypeError):
271 pass
271 pass
272 continue
272 continue
273
273
274 if update_generic(old_obj, new_obj): continue
274 if update_generic(old_obj, new_obj): continue
275
275
276 try:
276 try:
277 setattr(old, key, getattr(new, key))
277 setattr(old, key, getattr(new, key))
278 except (AttributeError, TypeError):
278 except (AttributeError, TypeError):
279 pass # skip non-writable attributes
279 pass # skip non-writable attributes
280
280
281
281
282 def update_property(old, new):
282 def update_property(old, new):
283 """Replace get/set/del functions of a property"""
283 """Replace get/set/del functions of a property"""
284 update_generic(old.fdel, new.fdel)
284 update_generic(old.fdel, new.fdel)
285 update_generic(old.fget, new.fget)
285 update_generic(old.fget, new.fget)
286 update_generic(old.fset, new.fset)
286 update_generic(old.fset, new.fset)
287
287
288
288
289 def isinstance2(a, b, typ):
289 def isinstance2(a, b, typ):
290 return isinstance(a, typ) and isinstance(b, typ)
290 return isinstance(a, typ) and isinstance(b, typ)
291
291
292
292
293 UPDATE_RULES = [
293 UPDATE_RULES = [
294 (lambda a, b: isinstance2(a, b, type),
294 (lambda a, b: isinstance2(a, b, type),
295 update_class),
295 update_class),
296 (lambda a, b: isinstance2(a, b, types.FunctionType),
296 (lambda a, b: isinstance2(a, b, types.FunctionType),
297 update_function),
297 update_function),
298 (lambda a, b: isinstance2(a, b, property),
298 (lambda a, b: isinstance2(a, b, property),
299 update_property),
299 update_property),
300 ]
300 ]
301
301
302
302
303 if PY3:
303 if PY3:
304 UPDATE_RULES.extend([(lambda a, b: isinstance2(a, b, types.MethodType),
304 UPDATE_RULES.extend([(lambda a, b: isinstance2(a, b, types.MethodType),
305 lambda a, b: update_function(a.__func__, b.__func__)),
305 lambda a, b: update_function(a.__func__, b.__func__)),
306 ])
306 ])
307 else:
307 else:
308 UPDATE_RULES.extend([(lambda a, b: isinstance2(a, b, types.ClassType),
308 UPDATE_RULES.extend([(lambda a, b: isinstance2(a, b, types.ClassType),
309 update_class),
309 update_class),
310 (lambda a, b: isinstance2(a, b, types.MethodType),
310 (lambda a, b: isinstance2(a, b, types.MethodType),
311 lambda a, b: update_function(a.im_func, b.im_func)),
311 lambda a, b: update_function(a.im_func, b.im_func)),
312 ])
312 ])
313
313
314
314
315 def update_generic(a, b):
315 def update_generic(a, b):
316 for type_check, update in UPDATE_RULES:
316 for type_check, update in UPDATE_RULES:
317 if type_check(a, b):
317 if type_check(a, b):
318 update(a, b)
318 update(a, b)
319 return True
319 return True
320 return False
320 return False
321
321
322
322
323 class StrongRef(object):
323 class StrongRef(object):
324 def __init__(self, obj):
324 def __init__(self, obj):
325 self.obj = obj
325 self.obj = obj
326 def __call__(self):
326 def __call__(self):
327 return self.obj
327 return self.obj
328
328
329
329
330 def superreload(module, reload=reload, old_objects={}):
330 def superreload(module, reload=reload, old_objects={}):
331 """Enhanced version of the builtin reload function.
331 """Enhanced version of the builtin reload function.
332
332
333 superreload remembers objects previously in the module, and
333 superreload remembers objects previously in the module, and
334
334
335 - upgrades the class dictionary of every old class in the module
335 - upgrades the class dictionary of every old class in the module
336 - upgrades the code object of every old function and method
336 - upgrades the code object of every old function and method
337 - clears the module's namespace before reloading
337 - clears the module's namespace before reloading
338
338
339 """
339 """
340
340
341 # collect old objects in the module
341 # collect old objects in the module
342 for name, obj in module.__dict__.items():
342 for name, obj in module.__dict__.items():
343 if not hasattr(obj, '__module__') or obj.__module__ != module.__name__:
343 if not hasattr(obj, '__module__') or obj.__module__ != module.__name__:
344 continue
344 continue
345 key = (module.__name__, name)
345 key = (module.__name__, name)
346 try:
346 try:
347 old_objects.setdefault(key, []).append(weakref.ref(obj))
347 old_objects.setdefault(key, []).append(weakref.ref(obj))
348 except TypeError:
348 except TypeError:
349 # weakref doesn't work for all types;
349 # weakref doesn't work for all types;
350 # create strong references for 'important' cases
350 # create strong references for 'important' cases
351 if not PY3 and isinstance(obj, types.ClassType):
351 if not PY3 and isinstance(obj, types.ClassType):
352 old_objects.setdefault(key, []).append(StrongRef(obj))
352 old_objects.setdefault(key, []).append(StrongRef(obj))
353
353
354 # reload module
354 # reload module
355 try:
355 try:
356 # clear namespace first from old cruft
356 # clear namespace first from old cruft
357 old_dict = module.__dict__.copy()
357 old_dict = module.__dict__.copy()
358 old_name = module.__name__
358 old_name = module.__name__
359 module.__dict__.clear()
359 module.__dict__.clear()
360 module.__dict__['__name__'] = old_name
360 module.__dict__['__name__'] = old_name
361 module.__dict__['__loader__'] = old_dict['__loader__']
361 module.__dict__['__loader__'] = old_dict['__loader__']
362 except (TypeError, AttributeError, KeyError):
362 except (TypeError, AttributeError, KeyError):
363 pass
363 pass
364
364
365 try:
365 try:
366 module = reload(module)
366 module = reload(module)
367 except:
367 except:
368 # restore module dictionary on failed reload
368 # restore module dictionary on failed reload
369 module.__dict__.update(old_dict)
369 module.__dict__.update(old_dict)
370 raise
370 raise
371
371
372 # iterate over all objects and update functions & classes
372 # iterate over all objects and update functions & classes
373 for name, new_obj in module.__dict__.items():
373 for name, new_obj in module.__dict__.items():
374 key = (module.__name__, name)
374 key = (module.__name__, name)
375 if key not in old_objects: continue
375 if key not in old_objects: continue
376
376
377 new_refs = []
377 new_refs = []
378 for old_ref in old_objects[key]:
378 for old_ref in old_objects[key]:
379 old_obj = old_ref()
379 old_obj = old_ref()
380 if old_obj is None: continue
380 if old_obj is None: continue
381 new_refs.append(old_ref)
381 new_refs.append(old_ref)
382 update_generic(old_obj, new_obj)
382 update_generic(old_obj, new_obj)
383
383
384 if new_refs:
384 if new_refs:
385 old_objects[key] = new_refs
385 old_objects[key] = new_refs
386 else:
386 else:
387 del old_objects[key]
387 del old_objects[key]
388
388
389 return module
389 return module
390
390
391 #------------------------------------------------------------------------------
391 #------------------------------------------------------------------------------
392 # IPython connectivity
392 # IPython connectivity
393 #------------------------------------------------------------------------------
393 #------------------------------------------------------------------------------
394
394
395 from IPython.core.hooks import TryNext
395 from IPython.core.hooks import TryNext
396 from IPython.core.magic import Magics, magics_class, line_magic
396 from IPython.core.magic import Magics, magics_class, line_magic
397
397
398 @magics_class
398 @magics_class
399 class AutoreloadMagics(Magics):
399 class AutoreloadMagics(Magics):
400 def __init__(self, *a, **kw):
400 def __init__(self, *a, **kw):
401 super(AutoreloadMagics, self).__init__(*a, **kw)
401 super(AutoreloadMagics, self).__init__(*a, **kw)
402 self._reloader = ModuleReloader()
402 self._reloader = ModuleReloader()
403 self._reloader.check_all = False
403 self._reloader.check_all = False
404
404
405 @line_magic
405 @line_magic
406 def autoreload(self, parameter_s=''):
406 def autoreload(self, parameter_s=''):
407 r"""%autoreload => Reload modules automatically
407 r"""%autoreload => Reload modules automatically
408
408
409 %autoreload
409 %autoreload
410 Reload all modules (except those excluded by %aimport) automatically
410 Reload all modules (except those excluded by %aimport) automatically
411 now.
411 now.
412
412
413 %autoreload 0
413 %autoreload 0
414 Disable automatic reloading.
414 Disable automatic reloading.
415
415
416 %autoreload 1
416 %autoreload 1
417 Reload all modules imported with %aimport every time before executing
417 Reload all modules imported with %aimport every time before executing
418 the Python code typed.
418 the Python code typed.
419
419
420 %autoreload 2
420 %autoreload 2
421 Reload all modules (except those excluded by %aimport) every time
421 Reload all modules (except those excluded by %aimport) every time
422 before executing the Python code typed.
422 before executing the Python code typed.
423
423
424 Reloading Python modules in a reliable way is in general
424 Reloading Python modules in a reliable way is in general
425 difficult, and unexpected things may occur. %autoreload tries to
425 difficult, and unexpected things may occur. %autoreload tries to
426 work around common pitfalls by replacing function code objects and
426 work around common pitfalls by replacing function code objects and
427 parts of classes previously in the module with new versions. This
427 parts of classes previously in the module with new versions. This
428 makes the following things to work:
428 makes the following things to work:
429
429
430 - Functions and classes imported via 'from xxx import foo' are upgraded
430 - Functions and classes imported via 'from xxx import foo' are upgraded
431 to new versions when 'xxx' is reloaded.
431 to new versions when 'xxx' is reloaded.
432
432
433 - Methods and properties of classes are upgraded on reload, so that
433 - Methods and properties of classes are upgraded on reload, so that
434 calling 'c.foo()' on an object 'c' created before the reload causes
434 calling 'c.foo()' on an object 'c' created before the reload causes
435 the new code for 'foo' to be executed.
435 the new code for 'foo' to be executed.
436
436
437 Some of the known remaining caveats are:
437 Some of the known remaining caveats are:
438
438
439 - Replacing code objects does not always succeed: changing a @property
439 - Replacing code objects does not always succeed: changing a @property
440 in a class to an ordinary method or a method to a member variable
440 in a class to an ordinary method or a method to a member variable
441 can cause problems (but in old objects only).
441 can cause problems (but in old objects only).
442
442
443 - Functions that are removed (eg. via monkey-patching) from a module
443 - Functions that are removed (eg. via monkey-patching) from a module
444 before it is reloaded are not upgraded.
444 before it is reloaded are not upgraded.
445
445
446 - C extension modules cannot be reloaded, and so cannot be
446 - C extension modules cannot be reloaded, and so cannot be
447 autoreloaded.
447 autoreloaded.
448
448
449 """
449 """
450 if parameter_s == '':
450 if parameter_s == '':
451 self._reloader.check(True)
451 self._reloader.check(True)
452 elif parameter_s == '0':
452 elif parameter_s == '0':
453 self._reloader.enabled = False
453 self._reloader.enabled = False
454 elif parameter_s == '1':
454 elif parameter_s == '1':
455 self._reloader.check_all = False
455 self._reloader.check_all = False
456 self._reloader.enabled = True
456 self._reloader.enabled = True
457 elif parameter_s == '2':
457 elif parameter_s == '2':
458 self._reloader.check_all = True
458 self._reloader.check_all = True
459 self._reloader.enabled = True
459 self._reloader.enabled = True
460
460
461 @line_magic
461 @line_magic
462 def aimport(self, parameter_s='', stream=None):
462 def aimport(self, parameter_s='', stream=None):
463 """%aimport => Import modules for automatic reloading.
463 """%aimport => Import modules for automatic reloading.
464
464
465 %aimport
465 %aimport
466 List modules to automatically import and not to import.
466 List modules to automatically import and not to import.
467
467
468 %aimport foo
468 %aimport foo
469 Import module 'foo' and mark it to be autoreloaded for %autoreload 1
469 Import module 'foo' and mark it to be autoreloaded for %autoreload 1
470
470
471 %aimport -foo
471 %aimport -foo
472 Mark module 'foo' to not be autoreloaded for %autoreload 1
472 Mark module 'foo' to not be autoreloaded for %autoreload 1
473 """
473 """
474 modname = parameter_s
474 modname = parameter_s
475 if not modname:
475 if not modname:
476 to_reload = self._reloader.modules.keys()
476 to_reload = self._reloader.modules.keys()
477 to_reload.sort()
477 to_reload.sort()
478 to_skip = self._reloader.skip_modules.keys()
478 to_skip = self._reloader.skip_modules.keys()
479 to_skip.sort()
479 to_skip.sort()
480 if stream is None:
480 if stream is None:
481 stream = sys.stdout
481 stream = sys.stdout
482 if self._reloader.check_all:
482 if self._reloader.check_all:
483 stream.write("Modules to reload:\nall-except-skipped\n")
483 stream.write("Modules to reload:\nall-except-skipped\n")
484 else:
484 else:
485 stream.write("Modules to reload:\n%s\n" % ' '.join(to_reload))
485 stream.write("Modules to reload:\n%s\n" % ' '.join(to_reload))
486 stream.write("\nModules to skip:\n%s\n" % ' '.join(to_skip))
486 stream.write("\nModules to skip:\n%s\n" % ' '.join(to_skip))
487 elif modname.startswith('-'):
487 elif modname.startswith('-'):
488 modname = modname[1:]
488 modname = modname[1:]
489 self._reloader.mark_module_skipped(modname)
489 self._reloader.mark_module_skipped(modname)
490 else:
490 else:
491 top_module, top_name = self._reloader.aimport_module(modname)
491 top_module, top_name = self._reloader.aimport_module(modname)
492
492
493 # Inject module to user namespace
493 # Inject module to user namespace
494 self.shell.push({top_name: top_module})
494 self.shell.push({top_name: top_module})
495
495
496 def pre_run_code_hook(self, ip):
496 def pre_run_code_hook(self, ip):
497 if not self._reloader.enabled:
497 if not self._reloader.enabled:
498 raise TryNext
498 raise TryNext
499 try:
499 try:
500 self._reloader.check()
500 self._reloader.check()
501 except:
501 except:
502 pass
502 pass
503
503
504
504
505 def load_ipython_extension(ip):
505 def load_ipython_extension(ip):
506 """Load the extension in IPython."""
506 """Load the extension in IPython."""
507 auto_reload = AutoreloadMagics(ip)
507 auto_reload = AutoreloadMagics(ip)
508 ip.register_magics(auto_reload)
508 ip.register_magics(auto_reload)
509 ip.set_hook('pre_run_code_hook', auto_reload.pre_run_code_hook)
509 ip.set_hook('pre_run_code_hook', auto_reload.pre_run_code_hook)
@@ -1,582 +1,582 b''
1 """Module for interactive demos using IPython.
1 """Module for interactive demos using IPython.
2
2
3 This module implements a few classes for running Python scripts interactively
3 This module implements a few classes for running Python scripts interactively
4 in IPython for demonstrations. With very simple markup (a few tags in
4 in IPython for demonstrations. With very simple markup (a few tags in
5 comments), you can control points where the script stops executing and returns
5 comments), you can control points where the script stops executing and returns
6 control to IPython.
6 control to IPython.
7
7
8
8
9 Provided classes
9 Provided classes
10 ----------------
10 ----------------
11
11
12 The classes are (see their docstrings for further details):
12 The classes are (see their docstrings for further details):
13
13
14 - Demo: pure python demos
14 - Demo: pure python demos
15
15
16 - IPythonDemo: demos with input to be processed by IPython as if it had been
16 - IPythonDemo: demos with input to be processed by IPython as if it had been
17 typed interactively (so magics work, as well as any other special syntax you
17 typed interactively (so magics work, as well as any other special syntax you
18 may have added via input prefilters).
18 may have added via input prefilters).
19
19
20 - LineDemo: single-line version of the Demo class. These demos are executed
20 - LineDemo: single-line version of the Demo class. These demos are executed
21 one line at a time, and require no markup.
21 one line at a time, and require no markup.
22
22
23 - IPythonLineDemo: IPython version of the LineDemo class (the demo is
23 - IPythonLineDemo: IPython version of the LineDemo class (the demo is
24 executed a line at a time, but processed via IPython).
24 executed a line at a time, but processed via IPython).
25
25
26 - ClearMixin: mixin to make Demo classes with less visual clutter. It
26 - ClearMixin: mixin to make Demo classes with less visual clutter. It
27 declares an empty marquee and a pre_cmd that clears the screen before each
27 declares an empty marquee and a pre_cmd that clears the screen before each
28 block (see Subclassing below).
28 block (see Subclassing below).
29
29
30 - ClearDemo, ClearIPDemo: mixin-enabled versions of the Demo and IPythonDemo
30 - ClearDemo, ClearIPDemo: mixin-enabled versions of the Demo and IPythonDemo
31 classes.
31 classes.
32
32
33 Inheritance diagram:
33 Inheritance diagram:
34
34
35 .. inheritance-diagram:: IPython.lib.demo
35 .. inheritance-diagram:: IPython.lib.demo
36 :parts: 3
36 :parts: 3
37
37
38 Subclassing
38 Subclassing
39 -----------
39 -----------
40
40
41 The classes here all include a few methods meant to make customization by
41 The classes here all include a few methods meant to make customization by
42 subclassing more convenient. Their docstrings below have some more details:
42 subclassing more convenient. Their docstrings below have some more details:
43
43
44 - marquee(): generates a marquee to provide visible on-screen markers at each
44 - marquee(): generates a marquee to provide visible on-screen markers at each
45 block start and end.
45 block start and end.
46
46
47 - pre_cmd(): run right before the execution of each block.
47 - pre_cmd(): run right before the execution of each block.
48
48
49 - post_cmd(): run right after the execution of each block. If the block
49 - post_cmd(): run right after the execution of each block. If the block
50 raises an exception, this is NOT called.
50 raises an exception, this is NOT called.
51
51
52
52
53 Operation
53 Operation
54 ---------
54 ---------
55
55
56 The file is run in its own empty namespace (though you can pass it a string of
56 The file is run in its own empty namespace (though you can pass it a string of
57 arguments as if in a command line environment, and it will see those as
57 arguments as if in a command line environment, and it will see those as
58 sys.argv). But at each stop, the global IPython namespace is updated with the
58 sys.argv). But at each stop, the global IPython namespace is updated with the
59 current internal demo namespace, so you can work interactively with the data
59 current internal demo namespace, so you can work interactively with the data
60 accumulated so far.
60 accumulated so far.
61
61
62 By default, each block of code is printed (with syntax highlighting) before
62 By default, each block of code is printed (with syntax highlighting) before
63 executing it and you have to confirm execution. This is intended to show the
63 executing it and you have to confirm execution. This is intended to show the
64 code to an audience first so you can discuss it, and only proceed with
64 code to an audience first so you can discuss it, and only proceed with
65 execution once you agree. There are a few tags which allow you to modify this
65 execution once you agree. There are a few tags which allow you to modify this
66 behavior.
66 behavior.
67
67
68 The supported tags are:
68 The supported tags are:
69
69
70 # <demo> stop
70 # <demo> stop
71
71
72 Defines block boundaries, the points where IPython stops execution of the
72 Defines block boundaries, the points where IPython stops execution of the
73 file and returns to the interactive prompt.
73 file and returns to the interactive prompt.
74
74
75 You can optionally mark the stop tag with extra dashes before and after the
75 You can optionally mark the stop tag with extra dashes before and after the
76 word 'stop', to help visually distinguish the blocks in a text editor:
76 word 'stop', to help visually distinguish the blocks in a text editor:
77
77
78 # <demo> --- stop ---
78 # <demo> --- stop ---
79
79
80
80
81 # <demo> silent
81 # <demo> silent
82
82
83 Make a block execute silently (and hence automatically). Typically used in
83 Make a block execute silently (and hence automatically). Typically used in
84 cases where you have some boilerplate or initialization code which you need
84 cases where you have some boilerplate or initialization code which you need
85 executed but do not want to be seen in the demo.
85 executed but do not want to be seen in the demo.
86
86
87 # <demo> auto
87 # <demo> auto
88
88
89 Make a block execute automatically, but still being printed. Useful for
89 Make a block execute automatically, but still being printed. Useful for
90 simple code which does not warrant discussion, since it avoids the extra
90 simple code which does not warrant discussion, since it avoids the extra
91 manual confirmation.
91 manual confirmation.
92
92
93 # <demo> auto_all
93 # <demo> auto_all
94
94
95 This tag can _only_ be in the first block, and if given it overrides the
95 This tag can _only_ be in the first block, and if given it overrides the
96 individual auto tags to make the whole demo fully automatic (no block asks
96 individual auto tags to make the whole demo fully automatic (no block asks
97 for confirmation). It can also be given at creation time (or the attribute
97 for confirmation). It can also be given at creation time (or the attribute
98 set later) to override what's in the file.
98 set later) to override what's in the file.
99
99
100 While _any_ python file can be run as a Demo instance, if there are no stop
100 While _any_ python file can be run as a Demo instance, if there are no stop
101 tags the whole file will run in a single block (no different that calling
101 tags the whole file will run in a single block (no different that calling
102 first %pycat and then %run). The minimal markup to make this useful is to
102 first %pycat and then %run). The minimal markup to make this useful is to
103 place a set of stop tags; the other tags are only there to let you fine-tune
103 place a set of stop tags; the other tags are only there to let you fine-tune
104 the execution.
104 the execution.
105
105
106 This is probably best explained with the simple example file below. You can
106 This is probably best explained with the simple example file below. You can
107 copy this into a file named ex_demo.py, and try running it via::
107 copy this into a file named ex_demo.py, and try running it via::
108
108
109 from IPython.demo import Demo
109 from IPython.demo import Demo
110 d = Demo('ex_demo.py')
110 d = Demo('ex_demo.py')
111 d()
111 d()
112
112
113 Each time you call the demo object, it runs the next block. The demo object
113 Each time you call the demo object, it runs the next block. The demo object
114 has a few useful methods for navigation, like again(), edit(), jump(), seek()
114 has a few useful methods for navigation, like again(), edit(), jump(), seek()
115 and back(). It can be reset for a new run via reset() or reloaded from disk
115 and back(). It can be reset for a new run via reset() or reloaded from disk
116 (in case you've edited the source) via reload(). See their docstrings below.
116 (in case you've edited the source) via reload(). See their docstrings below.
117
117
118 Note: To make this simpler to explore, a file called "demo-exercizer.py" has
118 Note: To make this simpler to explore, a file called "demo-exercizer.py" has
119 been added to the "docs/examples/core" directory. Just cd to this directory in
119 been added to the "docs/examples/core" directory. Just cd to this directory in
120 an IPython session, and type::
120 an IPython session, and type::
121
121
122 %run demo-exercizer.py
122 %run demo-exercizer.py
123
123
124 and then follow the directions.
124 and then follow the directions.
125
125
126 Example
126 Example
127 -------
127 -------
128
128
129 The following is a very simple example of a valid demo file.
129 The following is a very simple example of a valid demo file.
130
130
131 ::
131 ::
132
132
133 #################### EXAMPLE DEMO <ex_demo.py> ###############################
133 #################### EXAMPLE DEMO <ex_demo.py> ###############################
134 '''A simple interactive demo to illustrate the use of IPython's Demo class.'''
134 '''A simple interactive demo to illustrate the use of IPython's Demo class.'''
135
135
136 print 'Hello, welcome to an interactive IPython demo.'
136 print 'Hello, welcome to an interactive IPython demo.'
137
137
138 # The mark below defines a block boundary, which is a point where IPython will
138 # The mark below defines a block boundary, which is a point where IPython will
139 # stop execution and return to the interactive prompt. The dashes are actually
139 # stop execution and return to the interactive prompt. The dashes are actually
140 # optional and used only as a visual aid to clearly separate blocks while
140 # optional and used only as a visual aid to clearly separate blocks while
141 # editing the demo code.
141 # editing the demo code.
142 # <demo> stop
142 # <demo> stop
143
143
144 x = 1
144 x = 1
145 y = 2
145 y = 2
146
146
147 # <demo> stop
147 # <demo> stop
148
148
149 # the mark below makes this block as silent
149 # the mark below makes this block as silent
150 # <demo> silent
150 # <demo> silent
151
151
152 print 'This is a silent block, which gets executed but not printed.'
152 print 'This is a silent block, which gets executed but not printed.'
153
153
154 # <demo> stop
154 # <demo> stop
155 # <demo> auto
155 # <demo> auto
156 print 'This is an automatic block.'
156 print 'This is an automatic block.'
157 print 'It is executed without asking for confirmation, but printed.'
157 print 'It is executed without asking for confirmation, but printed.'
158 z = x+y
158 z = x+y
159
159
160 print 'z=',x
160 print 'z=',x
161
161
162 # <demo> stop
162 # <demo> stop
163 # This is just another normal block.
163 # This is just another normal block.
164 print 'z is now:', z
164 print 'z is now:', z
165
165
166 print 'bye!'
166 print 'bye!'
167 ################### END EXAMPLE DEMO <ex_demo.py> ############################
167 ################### END EXAMPLE DEMO <ex_demo.py> ############################
168 """
168 """
169
169
170 from __future__ import unicode_literals
170 from __future__ import unicode_literals
171
171
172 #*****************************************************************************
172 #*****************************************************************************
173 # Copyright (C) 2005-2006 Fernando Perez. <Fernando.Perez@colorado.edu>
173 # Copyright (C) 2005-2006 Fernando Perez. <Fernando.Perez@colorado.edu>
174 #
174 #
175 # Distributed under the terms of the BSD License. The full license is in
175 # Distributed under the terms of the BSD License. The full license is in
176 # the file COPYING, distributed as part of this software.
176 # the file COPYING, distributed as part of this software.
177 #
177 #
178 #*****************************************************************************
178 #*****************************************************************************
179 from __future__ import print_function
179 from __future__ import print_function
180
180
181 import os
181 import os
182 import re
182 import re
183 import shlex
183 import shlex
184 import sys
184 import sys
185
185
186 from IPython.utils import io
186 from IPython.utils import io
187 from IPython.utils.io import file_read
188 from IPython.utils.text import marquee
187 from IPython.utils.text import marquee
189 from IPython.utils import openpy
188 from IPython.utils import openpy
190 __all__ = ['Demo','IPythonDemo','LineDemo','IPythonLineDemo','DemoError']
189 __all__ = ['Demo','IPythonDemo','LineDemo','IPythonLineDemo','DemoError']
191
190
192 class DemoError(Exception): pass
191 class DemoError(Exception): pass
193
192
194 def re_mark(mark):
193 def re_mark(mark):
195 return re.compile(r'^\s*#\s+<demo>\s+%s\s*$' % mark,re.MULTILINE)
194 return re.compile(r'^\s*#\s+<demo>\s+%s\s*$' % mark,re.MULTILINE)
196
195
197 class Demo(object):
196 class Demo(object):
198
197
199 re_stop = re_mark('-*\s?stop\s?-*')
198 re_stop = re_mark('-*\s?stop\s?-*')
200 re_silent = re_mark('silent')
199 re_silent = re_mark('silent')
201 re_auto = re_mark('auto')
200 re_auto = re_mark('auto')
202 re_auto_all = re_mark('auto_all')
201 re_auto_all = re_mark('auto_all')
203
202
204 def __init__(self,src,title='',arg_str='',auto_all=None):
203 def __init__(self,src,title='',arg_str='',auto_all=None):
205 """Make a new demo object. To run the demo, simply call the object.
204 """Make a new demo object. To run the demo, simply call the object.
206
205
207 See the module docstring for full details and an example (you can use
206 See the module docstring for full details and an example (you can use
208 IPython.Demo? in IPython to see it).
207 IPython.Demo? in IPython to see it).
209
208
210 Inputs:
209 Inputs:
211
210
212 - src is either a file, or file-like object, or a
211 - src is either a file, or file-like object, or a
213 string that can be resolved to a filename.
212 string that can be resolved to a filename.
214
213
215 Optional inputs:
214 Optional inputs:
216
215
217 - title: a string to use as the demo name. Of most use when the demo
216 - title: a string to use as the demo name. Of most use when the demo
218 you are making comes from an object that has no filename, or if you
217 you are making comes from an object that has no filename, or if you
219 want an alternate denotation distinct from the filename.
218 want an alternate denotation distinct from the filename.
220
219
221 - arg_str(''): a string of arguments, internally converted to a list
220 - arg_str(''): a string of arguments, internally converted to a list
222 just like sys.argv, so the demo script can see a similar
221 just like sys.argv, so the demo script can see a similar
223 environment.
222 environment.
224
223
225 - auto_all(None): global flag to run all blocks automatically without
224 - auto_all(None): global flag to run all blocks automatically without
226 confirmation. This attribute overrides the block-level tags and
225 confirmation. This attribute overrides the block-level tags and
227 applies to the whole demo. It is an attribute of the object, and
226 applies to the whole demo. It is an attribute of the object, and
228 can be changed at runtime simply by reassigning it to a boolean
227 can be changed at runtime simply by reassigning it to a boolean
229 value.
228 value.
230 """
229 """
231 if hasattr(src, "read"):
230 if hasattr(src, "read"):
232 # It seems to be a file or a file-like object
231 # It seems to be a file or a file-like object
233 self.fname = "from a file-like object"
232 self.fname = "from a file-like object"
234 if title == '':
233 if title == '':
235 self.title = "from a file-like object"
234 self.title = "from a file-like object"
236 else:
235 else:
237 self.title = title
236 self.title = title
238 else:
237 else:
239 # Assume it's a string or something that can be converted to one
238 # Assume it's a string or something that can be converted to one
240 self.fname = src
239 self.fname = src
241 if title == '':
240 if title == '':
242 (filepath, filename) = os.path.split(src)
241 (filepath, filename) = os.path.split(src)
243 self.title = filename
242 self.title = filename
244 else:
243 else:
245 self.title = title
244 self.title = title
246 self.sys_argv = [src] + shlex.split(arg_str)
245 self.sys_argv = [src] + shlex.split(arg_str)
247 self.auto_all = auto_all
246 self.auto_all = auto_all
248 self.src = src
247 self.src = src
249
248
250 # get a few things from ipython. While it's a bit ugly design-wise,
249 # get a few things from ipython. While it's a bit ugly design-wise,
251 # it ensures that things like color scheme and the like are always in
250 # it ensures that things like color scheme and the like are always in
252 # sync with the ipython mode being used. This class is only meant to
251 # sync with the ipython mode being used. This class is only meant to
253 # be used inside ipython anyways, so it's OK.
252 # be used inside ipython anyways, so it's OK.
254 ip = get_ipython() # this is in builtins whenever IPython is running
253 ip = get_ipython() # this is in builtins whenever IPython is running
255 self.ip_ns = ip.user_ns
254 self.ip_ns = ip.user_ns
256 self.ip_colorize = ip.pycolorize
255 self.ip_colorize = ip.pycolorize
257 self.ip_showtb = ip.showtraceback
256 self.ip_showtb = ip.showtraceback
258 self.ip_run_cell = ip.run_cell
257 self.ip_run_cell = ip.run_cell
259 self.shell = ip
258 self.shell = ip
260
259
261 # load user data and initialize data structures
260 # load user data and initialize data structures
262 self.reload()
261 self.reload()
263
262
264 def fload(self):
263 def fload(self):
265 """Load file object."""
264 """Load file object."""
266 # read data and parse into blocks
265 # read data and parse into blocks
267 if hasattr(self, 'fobj') and self.fobj is not None:
266 if hasattr(self, 'fobj') and self.fobj is not None:
268 self.fobj.close()
267 self.fobj.close()
269 if hasattr(self.src, "read"):
268 if hasattr(self.src, "read"):
270 # It seems to be a file or a file-like object
269 # It seems to be a file or a file-like object
271 self.fobj = self.src
270 self.fobj = self.src
272 else:
271 else:
273 # Assume it's a string or something that can be converted to one
272 # Assume it's a string or something that can be converted to one
274 self.fobj = openpy.open(self.fname)
273 self.fobj = openpy.open(self.fname)
275
274
276 def reload(self):
275 def reload(self):
277 """Reload source from disk and initialize state."""
276 """Reload source from disk and initialize state."""
278 self.fload()
277 self.fload()
279
278
280 self.src = "".join(openpy.strip_encoding_cookie(self.fobj))
279 self.src = "".join(openpy.strip_encoding_cookie(self.fobj))
281 src_b = [b.strip() for b in self.re_stop.split(self.src) if b]
280 src_b = [b.strip() for b in self.re_stop.split(self.src) if b]
282 self._silent = [bool(self.re_silent.findall(b)) for b in src_b]
281 self._silent = [bool(self.re_silent.findall(b)) for b in src_b]
283 self._auto = [bool(self.re_auto.findall(b)) for b in src_b]
282 self._auto = [bool(self.re_auto.findall(b)) for b in src_b]
284
283
285 # if auto_all is not given (def. None), we read it from the file
284 # if auto_all is not given (def. None), we read it from the file
286 if self.auto_all is None:
285 if self.auto_all is None:
287 self.auto_all = bool(self.re_auto_all.findall(src_b[0]))
286 self.auto_all = bool(self.re_auto_all.findall(src_b[0]))
288 else:
287 else:
289 self.auto_all = bool(self.auto_all)
288 self.auto_all = bool(self.auto_all)
290
289
291 # Clean the sources from all markup so it doesn't get displayed when
290 # Clean the sources from all markup so it doesn't get displayed when
292 # running the demo
291 # running the demo
293 src_blocks = []
292 src_blocks = []
294 auto_strip = lambda s: self.re_auto.sub('',s)
293 auto_strip = lambda s: self.re_auto.sub('',s)
295 for i,b in enumerate(src_b):
294 for i,b in enumerate(src_b):
296 if self._auto[i]:
295 if self._auto[i]:
297 src_blocks.append(auto_strip(b))
296 src_blocks.append(auto_strip(b))
298 else:
297 else:
299 src_blocks.append(b)
298 src_blocks.append(b)
300 # remove the auto_all marker
299 # remove the auto_all marker
301 src_blocks[0] = self.re_auto_all.sub('',src_blocks[0])
300 src_blocks[0] = self.re_auto_all.sub('',src_blocks[0])
302
301
303 self.nblocks = len(src_blocks)
302 self.nblocks = len(src_blocks)
304 self.src_blocks = src_blocks
303 self.src_blocks = src_blocks
305
304
306 # also build syntax-highlighted source
305 # also build syntax-highlighted source
307 self.src_blocks_colored = map(self.ip_colorize,self.src_blocks)
306 self.src_blocks_colored = map(self.ip_colorize,self.src_blocks)
308
307
309 # ensure clean namespace and seek offset
308 # ensure clean namespace and seek offset
310 self.reset()
309 self.reset()
311
310
312 def reset(self):
311 def reset(self):
313 """Reset the namespace and seek pointer to restart the demo"""
312 """Reset the namespace and seek pointer to restart the demo"""
314 self.user_ns = {}
313 self.user_ns = {}
315 self.finished = False
314 self.finished = False
316 self.block_index = 0
315 self.block_index = 0
317
316
318 def _validate_index(self,index):
317 def _validate_index(self,index):
319 if index<0 or index>=self.nblocks:
318 if index<0 or index>=self.nblocks:
320 raise ValueError('invalid block index %s' % index)
319 raise ValueError('invalid block index %s' % index)
321
320
322 def _get_index(self,index):
321 def _get_index(self,index):
323 """Get the current block index, validating and checking status.
322 """Get the current block index, validating and checking status.
324
323
325 Returns None if the demo is finished"""
324 Returns None if the demo is finished"""
326
325
327 if index is None:
326 if index is None:
328 if self.finished:
327 if self.finished:
329 print('Demo finished. Use <demo_name>.reset() if you want to rerun it.', file=io.stdout)
328 print('Demo finished. Use <demo_name>.reset() if you want to rerun it.', file=io.stdout)
330 return None
329 return None
331 index = self.block_index
330 index = self.block_index
332 else:
331 else:
333 self._validate_index(index)
332 self._validate_index(index)
334 return index
333 return index
335
334
336 def seek(self,index):
335 def seek(self,index):
337 """Move the current seek pointer to the given block.
336 """Move the current seek pointer to the given block.
338
337
339 You can use negative indices to seek from the end, with identical
338 You can use negative indices to seek from the end, with identical
340 semantics to those of Python lists."""
339 semantics to those of Python lists."""
341 if index<0:
340 if index<0:
342 index = self.nblocks + index
341 index = self.nblocks + index
343 self._validate_index(index)
342 self._validate_index(index)
344 self.block_index = index
343 self.block_index = index
345 self.finished = False
344 self.finished = False
346
345
347 def back(self,num=1):
346 def back(self,num=1):
348 """Move the seek pointer back num blocks (default is 1)."""
347 """Move the seek pointer back num blocks (default is 1)."""
349 self.seek(self.block_index-num)
348 self.seek(self.block_index-num)
350
349
351 def jump(self,num=1):
350 def jump(self,num=1):
352 """Jump a given number of blocks relative to the current one.
351 """Jump a given number of blocks relative to the current one.
353
352
354 The offset can be positive or negative, defaults to 1."""
353 The offset can be positive or negative, defaults to 1."""
355 self.seek(self.block_index+num)
354 self.seek(self.block_index+num)
356
355
357 def again(self):
356 def again(self):
358 """Move the seek pointer back one block and re-execute."""
357 """Move the seek pointer back one block and re-execute."""
359 self.back(1)
358 self.back(1)
360 self()
359 self()
361
360
362 def edit(self,index=None):
361 def edit(self,index=None):
363 """Edit a block.
362 """Edit a block.
364
363
365 If no number is given, use the last block executed.
364 If no number is given, use the last block executed.
366
365
367 This edits the in-memory copy of the demo, it does NOT modify the
366 This edits the in-memory copy of the demo, it does NOT modify the
368 original source file. If you want to do that, simply open the file in
367 original source file. If you want to do that, simply open the file in
369 an editor and use reload() when you make changes to the file. This
368 an editor and use reload() when you make changes to the file. This
370 method is meant to let you change a block during a demonstration for
369 method is meant to let you change a block during a demonstration for
371 explanatory purposes, without damaging your original script."""
370 explanatory purposes, without damaging your original script."""
372
371
373 index = self._get_index(index)
372 index = self._get_index(index)
374 if index is None:
373 if index is None:
375 return
374 return
376 # decrease the index by one (unless we're at the very beginning), so
375 # decrease the index by one (unless we're at the very beginning), so
377 # that the default demo.edit() call opens up the sblock we've last run
376 # that the default demo.edit() call opens up the sblock we've last run
378 if index>0:
377 if index>0:
379 index -= 1
378 index -= 1
380
379
381 filename = self.shell.mktempfile(self.src_blocks[index])
380 filename = self.shell.mktempfile(self.src_blocks[index])
382 self.shell.hooks.editor(filename,1)
381 self.shell.hooks.editor(filename,1)
383 new_block = file_read(filename)
382 with open(filename, 'r') as f:
383 new_block = f.read()
384 # update the source and colored block
384 # update the source and colored block
385 self.src_blocks[index] = new_block
385 self.src_blocks[index] = new_block
386 self.src_blocks_colored[index] = self.ip_colorize(new_block)
386 self.src_blocks_colored[index] = self.ip_colorize(new_block)
387 self.block_index = index
387 self.block_index = index
388 # call to run with the newly edited index
388 # call to run with the newly edited index
389 self()
389 self()
390
390
391 def show(self,index=None):
391 def show(self,index=None):
392 """Show a single block on screen"""
392 """Show a single block on screen"""
393
393
394 index = self._get_index(index)
394 index = self._get_index(index)
395 if index is None:
395 if index is None:
396 return
396 return
397
397
398 print(self.marquee('<%s> block # %s (%s remaining)' %
398 print(self.marquee('<%s> block # %s (%s remaining)' %
399 (self.title,index,self.nblocks-index-1)), file=io.stdout)
399 (self.title,index,self.nblocks-index-1)), file=io.stdout)
400 print((self.src_blocks_colored[index]), file=io.stdout)
400 print((self.src_blocks_colored[index]), file=io.stdout)
401 sys.stdout.flush()
401 sys.stdout.flush()
402
402
403 def show_all(self):
403 def show_all(self):
404 """Show entire demo on screen, block by block"""
404 """Show entire demo on screen, block by block"""
405
405
406 fname = self.title
406 fname = self.title
407 title = self.title
407 title = self.title
408 nblocks = self.nblocks
408 nblocks = self.nblocks
409 silent = self._silent
409 silent = self._silent
410 marquee = self.marquee
410 marquee = self.marquee
411 for index,block in enumerate(self.src_blocks_colored):
411 for index,block in enumerate(self.src_blocks_colored):
412 if silent[index]:
412 if silent[index]:
413 print(marquee('<%s> SILENT block # %s (%s remaining)' %
413 print(marquee('<%s> SILENT block # %s (%s remaining)' %
414 (title,index,nblocks-index-1)), file=io.stdout)
414 (title,index,nblocks-index-1)), file=io.stdout)
415 else:
415 else:
416 print(marquee('<%s> block # %s (%s remaining)' %
416 print(marquee('<%s> block # %s (%s remaining)' %
417 (title,index,nblocks-index-1)), file=io.stdout)
417 (title,index,nblocks-index-1)), file=io.stdout)
418 print(block, end=' ', file=io.stdout)
418 print(block, end=' ', file=io.stdout)
419 sys.stdout.flush()
419 sys.stdout.flush()
420
420
421 def run_cell(self,source):
421 def run_cell(self,source):
422 """Execute a string with one or more lines of code"""
422 """Execute a string with one or more lines of code"""
423
423
424 exec source in self.user_ns
424 exec source in self.user_ns
425
425
426 def __call__(self,index=None):
426 def __call__(self,index=None):
427 """run a block of the demo.
427 """run a block of the demo.
428
428
429 If index is given, it should be an integer >=1 and <= nblocks. This
429 If index is given, it should be an integer >=1 and <= nblocks. This
430 means that the calling convention is one off from typical Python
430 means that the calling convention is one off from typical Python
431 lists. The reason for the inconsistency is that the demo always
431 lists. The reason for the inconsistency is that the demo always
432 prints 'Block n/N, and N is the total, so it would be very odd to use
432 prints 'Block n/N, and N is the total, so it would be very odd to use
433 zero-indexing here."""
433 zero-indexing here."""
434
434
435 index = self._get_index(index)
435 index = self._get_index(index)
436 if index is None:
436 if index is None:
437 return
437 return
438 try:
438 try:
439 marquee = self.marquee
439 marquee = self.marquee
440 next_block = self.src_blocks[index]
440 next_block = self.src_blocks[index]
441 self.block_index += 1
441 self.block_index += 1
442 if self._silent[index]:
442 if self._silent[index]:
443 print(marquee('Executing silent block # %s (%s remaining)' %
443 print(marquee('Executing silent block # %s (%s remaining)' %
444 (index,self.nblocks-index-1)), file=io.stdout)
444 (index,self.nblocks-index-1)), file=io.stdout)
445 else:
445 else:
446 self.pre_cmd()
446 self.pre_cmd()
447 self.show(index)
447 self.show(index)
448 if self.auto_all or self._auto[index]:
448 if self.auto_all or self._auto[index]:
449 print(marquee('output:'), file=io.stdout)
449 print(marquee('output:'), file=io.stdout)
450 else:
450 else:
451 print(marquee('Press <q> to quit, <Enter> to execute...'), end=' ', file=io.stdout)
451 print(marquee('Press <q> to quit, <Enter> to execute...'), end=' ', file=io.stdout)
452 ans = raw_input().strip()
452 ans = raw_input().strip()
453 if ans:
453 if ans:
454 print(marquee('Block NOT executed'), file=io.stdout)
454 print(marquee('Block NOT executed'), file=io.stdout)
455 return
455 return
456 try:
456 try:
457 save_argv = sys.argv
457 save_argv = sys.argv
458 sys.argv = self.sys_argv
458 sys.argv = self.sys_argv
459 self.run_cell(next_block)
459 self.run_cell(next_block)
460 self.post_cmd()
460 self.post_cmd()
461 finally:
461 finally:
462 sys.argv = save_argv
462 sys.argv = save_argv
463
463
464 except:
464 except:
465 self.ip_showtb(filename=self.fname)
465 self.ip_showtb(filename=self.fname)
466 else:
466 else:
467 self.ip_ns.update(self.user_ns)
467 self.ip_ns.update(self.user_ns)
468
468
469 if self.block_index == self.nblocks:
469 if self.block_index == self.nblocks:
470 mq1 = self.marquee('END OF DEMO')
470 mq1 = self.marquee('END OF DEMO')
471 if mq1:
471 if mq1:
472 # avoid spurious print >>io.stdout,s if empty marquees are used
472 # avoid spurious print >>io.stdout,s if empty marquees are used
473 print(file=io.stdout)
473 print(file=io.stdout)
474 print(mq1, file=io.stdout)
474 print(mq1, file=io.stdout)
475 print(self.marquee('Use <demo_name>.reset() if you want to rerun it.'), file=io.stdout)
475 print(self.marquee('Use <demo_name>.reset() if you want to rerun it.'), file=io.stdout)
476 self.finished = True
476 self.finished = True
477
477
478 # These methods are meant to be overridden by subclasses who may wish to
478 # These methods are meant to be overridden by subclasses who may wish to
479 # customize the behavior of of their demos.
479 # customize the behavior of of their demos.
480 def marquee(self,txt='',width=78,mark='*'):
480 def marquee(self,txt='',width=78,mark='*'):
481 """Return the input string centered in a 'marquee'."""
481 """Return the input string centered in a 'marquee'."""
482 return marquee(txt,width,mark)
482 return marquee(txt,width,mark)
483
483
484 def pre_cmd(self):
484 def pre_cmd(self):
485 """Method called before executing each block."""
485 """Method called before executing each block."""
486 pass
486 pass
487
487
488 def post_cmd(self):
488 def post_cmd(self):
489 """Method called after executing each block."""
489 """Method called after executing each block."""
490 pass
490 pass
491
491
492
492
493 class IPythonDemo(Demo):
493 class IPythonDemo(Demo):
494 """Class for interactive demos with IPython's input processing applied.
494 """Class for interactive demos with IPython's input processing applied.
495
495
496 This subclasses Demo, but instead of executing each block by the Python
496 This subclasses Demo, but instead of executing each block by the Python
497 interpreter (via exec), it actually calls IPython on it, so that any input
497 interpreter (via exec), it actually calls IPython on it, so that any input
498 filters which may be in place are applied to the input block.
498 filters which may be in place are applied to the input block.
499
499
500 If you have an interactive environment which exposes special input
500 If you have an interactive environment which exposes special input
501 processing, you can use this class instead to write demo scripts which
501 processing, you can use this class instead to write demo scripts which
502 operate exactly as if you had typed them interactively. The default Demo
502 operate exactly as if you had typed them interactively. The default Demo
503 class requires the input to be valid, pure Python code.
503 class requires the input to be valid, pure Python code.
504 """
504 """
505
505
506 def run_cell(self,source):
506 def run_cell(self,source):
507 """Execute a string with one or more lines of code"""
507 """Execute a string with one or more lines of code"""
508
508
509 self.shell.run_cell(source)
509 self.shell.run_cell(source)
510
510
511 class LineDemo(Demo):
511 class LineDemo(Demo):
512 """Demo where each line is executed as a separate block.
512 """Demo where each line is executed as a separate block.
513
513
514 The input script should be valid Python code.
514 The input script should be valid Python code.
515
515
516 This class doesn't require any markup at all, and it's meant for simple
516 This class doesn't require any markup at all, and it's meant for simple
517 scripts (with no nesting or any kind of indentation) which consist of
517 scripts (with no nesting or any kind of indentation) which consist of
518 multiple lines of input to be executed, one at a time, as if they had been
518 multiple lines of input to be executed, one at a time, as if they had been
519 typed in the interactive prompt.
519 typed in the interactive prompt.
520
520
521 Note: the input can not have *any* indentation, which means that only
521 Note: the input can not have *any* indentation, which means that only
522 single-lines of input are accepted, not even function definitions are
522 single-lines of input are accepted, not even function definitions are
523 valid."""
523 valid."""
524
524
525 def reload(self):
525 def reload(self):
526 """Reload source from disk and initialize state."""
526 """Reload source from disk and initialize state."""
527 # read data and parse into blocks
527 # read data and parse into blocks
528 self.fload()
528 self.fload()
529 lines = self.fobj.readlines()
529 lines = self.fobj.readlines()
530 src_b = [l for l in lines if l.strip()]
530 src_b = [l for l in lines if l.strip()]
531 nblocks = len(src_b)
531 nblocks = len(src_b)
532 self.src = ''.join(lines)
532 self.src = ''.join(lines)
533 self._silent = [False]*nblocks
533 self._silent = [False]*nblocks
534 self._auto = [True]*nblocks
534 self._auto = [True]*nblocks
535 self.auto_all = True
535 self.auto_all = True
536 self.nblocks = nblocks
536 self.nblocks = nblocks
537 self.src_blocks = src_b
537 self.src_blocks = src_b
538
538
539 # also build syntax-highlighted source
539 # also build syntax-highlighted source
540 self.src_blocks_colored = map(self.ip_colorize,self.src_blocks)
540 self.src_blocks_colored = map(self.ip_colorize,self.src_blocks)
541
541
542 # ensure clean namespace and seek offset
542 # ensure clean namespace and seek offset
543 self.reset()
543 self.reset()
544
544
545
545
546 class IPythonLineDemo(IPythonDemo,LineDemo):
546 class IPythonLineDemo(IPythonDemo,LineDemo):
547 """Variant of the LineDemo class whose input is processed by IPython."""
547 """Variant of the LineDemo class whose input is processed by IPython."""
548 pass
548 pass
549
549
550
550
551 class ClearMixin(object):
551 class ClearMixin(object):
552 """Use this mixin to make Demo classes with less visual clutter.
552 """Use this mixin to make Demo classes with less visual clutter.
553
553
554 Demos using this mixin will clear the screen before every block and use
554 Demos using this mixin will clear the screen before every block and use
555 blank marquees.
555 blank marquees.
556
556
557 Note that in order for the methods defined here to actually override those
557 Note that in order for the methods defined here to actually override those
558 of the classes it's mixed with, it must go /first/ in the inheritance
558 of the classes it's mixed with, it must go /first/ in the inheritance
559 tree. For example:
559 tree. For example:
560
560
561 class ClearIPDemo(ClearMixin,IPythonDemo): pass
561 class ClearIPDemo(ClearMixin,IPythonDemo): pass
562
562
563 will provide an IPythonDemo class with the mixin's features.
563 will provide an IPythonDemo class with the mixin's features.
564 """
564 """
565
565
566 def marquee(self,txt='',width=78,mark='*'):
566 def marquee(self,txt='',width=78,mark='*'):
567 """Blank marquee that returns '' no matter what the input."""
567 """Blank marquee that returns '' no matter what the input."""
568 return ''
568 return ''
569
569
570 def pre_cmd(self):
570 def pre_cmd(self):
571 """Method called before executing each block.
571 """Method called before executing each block.
572
572
573 This one simply clears the screen."""
573 This one simply clears the screen."""
574 from IPython.utils.terminal import term_clear
574 from IPython.utils.terminal import term_clear
575 term_clear()
575 term_clear()
576
576
577 class ClearDemo(ClearMixin,Demo):
577 class ClearDemo(ClearMixin,Demo):
578 pass
578 pass
579
579
580
580
581 class ClearIPDemo(ClearMixin,IPythonDemo):
581 class ClearIPDemo(ClearMixin,IPythonDemo):
582 pass
582 pass
@@ -1,197 +1,198 b''
1 """Posix-specific implementation of process utilities.
1 """Posix-specific implementation of process utilities.
2
2
3 This file is only meant to be imported by process.py, not by end-users.
3 This file is only meant to be imported by process.py, not by end-users.
4 """
4 """
5
5
6 #-----------------------------------------------------------------------------
6 #-----------------------------------------------------------------------------
7 # Copyright (C) 2010-2011 The IPython Development Team
7 # Copyright (C) 2010-2011 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 from __future__ import print_function
16 from __future__ import print_function
17
17
18 # Stdlib
18 # Stdlib
19 import subprocess as sp
19 import subprocess as sp
20 import sys
20 import sys
21
21
22 from IPython.external import pexpect
22 from IPython.external import pexpect
23
23
24 # Our own
24 # Our own
25 from .autoattr import auto_attr
26 from ._process_common import getoutput, arg_split
25 from ._process_common import getoutput, arg_split
27 from IPython.utils import py3compat
26 from IPython.utils import py3compat
28 from IPython.utils.encoding import DEFAULT_ENCODING
27 from IPython.utils.encoding import DEFAULT_ENCODING
29
28
30 #-----------------------------------------------------------------------------
29 #-----------------------------------------------------------------------------
31 # Function definitions
30 # Function definitions
32 #-----------------------------------------------------------------------------
31 #-----------------------------------------------------------------------------
33
32
34 def _find_cmd(cmd):
33 def _find_cmd(cmd):
35 """Find the full path to a command using which."""
34 """Find the full path to a command using which."""
36
35
37 path = sp.Popen(['/usr/bin/env', 'which', cmd],
36 path = sp.Popen(['/usr/bin/env', 'which', cmd],
38 stdout=sp.PIPE, stderr=sp.PIPE).communicate()[0]
37 stdout=sp.PIPE, stderr=sp.PIPE).communicate()[0]
39 return py3compat.bytes_to_str(path)
38 return py3compat.bytes_to_str(path)
40
39
41
40
42 class ProcessHandler(object):
41 class ProcessHandler(object):
43 """Execute subprocesses under the control of pexpect.
42 """Execute subprocesses under the control of pexpect.
44 """
43 """
45 # Timeout in seconds to wait on each reading of the subprocess' output.
44 # Timeout in seconds to wait on each reading of the subprocess' output.
46 # This should not be set too low to avoid cpu overusage from our side,
45 # This should not be set too low to avoid cpu overusage from our side,
47 # since we read in a loop whose period is controlled by this timeout.
46 # since we read in a loop whose period is controlled by this timeout.
48 read_timeout = 0.05
47 read_timeout = 0.05
49
48
50 # Timeout to give a process if we receive SIGINT, between sending the
49 # Timeout to give a process if we receive SIGINT, between sending the
51 # SIGINT to the process and forcefully terminating it.
50 # SIGINT to the process and forcefully terminating it.
52 terminate_timeout = 0.2
51 terminate_timeout = 0.2
53
52
54 # File object where stdout and stderr of the subprocess will be written
53 # File object where stdout and stderr of the subprocess will be written
55 logfile = None
54 logfile = None
56
55
57 # Shell to call for subprocesses to execute
56 # Shell to call for subprocesses to execute
58 sh = None
57 _sh = None
59
58
60 @auto_attr
59 @property
61 def sh(self):
60 def sh(self):
62 sh = pexpect.which('sh')
61 if self._sh is None:
63 if sh is None:
62 self._sh = pexpect.which('sh')
64 raise OSError('"sh" shell not found')
63 if self._sh is None:
65 return sh
64 raise OSError('"sh" shell not found')
65
66 return self._sh
66
67
67 def __init__(self, logfile=None, read_timeout=None, terminate_timeout=None):
68 def __init__(self, logfile=None, read_timeout=None, terminate_timeout=None):
68 """Arguments are used for pexpect calls."""
69 """Arguments are used for pexpect calls."""
69 self.read_timeout = (ProcessHandler.read_timeout if read_timeout is
70 self.read_timeout = (ProcessHandler.read_timeout if read_timeout is
70 None else read_timeout)
71 None else read_timeout)
71 self.terminate_timeout = (ProcessHandler.terminate_timeout if
72 self.terminate_timeout = (ProcessHandler.terminate_timeout if
72 terminate_timeout is None else
73 terminate_timeout is None else
73 terminate_timeout)
74 terminate_timeout)
74 self.logfile = sys.stdout if logfile is None else logfile
75 self.logfile = sys.stdout if logfile is None else logfile
75
76
76 def getoutput(self, cmd):
77 def getoutput(self, cmd):
77 """Run a command and return its stdout/stderr as a string.
78 """Run a command and return its stdout/stderr as a string.
78
79
79 Parameters
80 Parameters
80 ----------
81 ----------
81 cmd : str
82 cmd : str
82 A command to be executed in the system shell.
83 A command to be executed in the system shell.
83
84
84 Returns
85 Returns
85 -------
86 -------
86 output : str
87 output : str
87 A string containing the combination of stdout and stderr from the
88 A string containing the combination of stdout and stderr from the
88 subprocess, in whatever order the subprocess originally wrote to its
89 subprocess, in whatever order the subprocess originally wrote to its
89 file descriptors (so the order of the information in this string is the
90 file descriptors (so the order of the information in this string is the
90 correct order as would be seen if running the command in a terminal).
91 correct order as would be seen if running the command in a terminal).
91 """
92 """
92 try:
93 try:
93 return pexpect.run(self.sh, args=['-c', cmd]).replace('\r\n', '\n')
94 return pexpect.run(self.sh, args=['-c', cmd]).replace('\r\n', '\n')
94 except KeyboardInterrupt:
95 except KeyboardInterrupt:
95 print('^C', file=sys.stderr, end='')
96 print('^C', file=sys.stderr, end='')
96
97
97 def getoutput_pexpect(self, cmd):
98 def getoutput_pexpect(self, cmd):
98 """Run a command and return its stdout/stderr as a string.
99 """Run a command and return its stdout/stderr as a string.
99
100
100 Parameters
101 Parameters
101 ----------
102 ----------
102 cmd : str
103 cmd : str
103 A command to be executed in the system shell.
104 A command to be executed in the system shell.
104
105
105 Returns
106 Returns
106 -------
107 -------
107 output : str
108 output : str
108 A string containing the combination of stdout and stderr from the
109 A string containing the combination of stdout and stderr from the
109 subprocess, in whatever order the subprocess originally wrote to its
110 subprocess, in whatever order the subprocess originally wrote to its
110 file descriptors (so the order of the information in this string is the
111 file descriptors (so the order of the information in this string is the
111 correct order as would be seen if running the command in a terminal).
112 correct order as would be seen if running the command in a terminal).
112 """
113 """
113 try:
114 try:
114 return pexpect.run(self.sh, args=['-c', cmd]).replace('\r\n', '\n')
115 return pexpect.run(self.sh, args=['-c', cmd]).replace('\r\n', '\n')
115 except KeyboardInterrupt:
116 except KeyboardInterrupt:
116 print('^C', file=sys.stderr, end='')
117 print('^C', file=sys.stderr, end='')
117
118
118 def system(self, cmd):
119 def system(self, cmd):
119 """Execute a command in a subshell.
120 """Execute a command in a subshell.
120
121
121 Parameters
122 Parameters
122 ----------
123 ----------
123 cmd : str
124 cmd : str
124 A command to be executed in the system shell.
125 A command to be executed in the system shell.
125
126
126 Returns
127 Returns
127 -------
128 -------
128 int : child's exitstatus
129 int : child's exitstatus
129 """
130 """
130 # Get likely encoding for the output.
131 # Get likely encoding for the output.
131 enc = DEFAULT_ENCODING
132 enc = DEFAULT_ENCODING
132
133
133 # Patterns to match on the output, for pexpect. We read input and
134 # Patterns to match on the output, for pexpect. We read input and
134 # allow either a short timeout or EOF
135 # allow either a short timeout or EOF
135 patterns = [pexpect.TIMEOUT, pexpect.EOF]
136 patterns = [pexpect.TIMEOUT, pexpect.EOF]
136 # the index of the EOF pattern in the list.
137 # the index of the EOF pattern in the list.
137 # even though we know it's 1, this call means we don't have to worry if
138 # even though we know it's 1, this call means we don't have to worry if
138 # we change the above list, and forget to change this value:
139 # we change the above list, and forget to change this value:
139 EOF_index = patterns.index(pexpect.EOF)
140 EOF_index = patterns.index(pexpect.EOF)
140 # The size of the output stored so far in the process output buffer.
141 # The size of the output stored so far in the process output buffer.
141 # Since pexpect only appends to this buffer, each time we print we
142 # Since pexpect only appends to this buffer, each time we print we
142 # record how far we've printed, so that next time we only print *new*
143 # record how far we've printed, so that next time we only print *new*
143 # content from the buffer.
144 # content from the buffer.
144 out_size = 0
145 out_size = 0
145 try:
146 try:
146 # Since we're not really searching the buffer for text patterns, we
147 # Since we're not really searching the buffer for text patterns, we
147 # can set pexpect's search window to be tiny and it won't matter.
148 # can set pexpect's search window to be tiny and it won't matter.
148 # We only search for the 'patterns' timeout or EOF, which aren't in
149 # We only search for the 'patterns' timeout or EOF, which aren't in
149 # the text itself.
150 # the text itself.
150 #child = pexpect.spawn(pcmd, searchwindowsize=1)
151 #child = pexpect.spawn(pcmd, searchwindowsize=1)
151 if hasattr(pexpect, 'spawnb'):
152 if hasattr(pexpect, 'spawnb'):
152 child = pexpect.spawnb(self.sh, args=['-c', cmd]) # Pexpect-U
153 child = pexpect.spawnb(self.sh, args=['-c', cmd]) # Pexpect-U
153 else:
154 else:
154 child = pexpect.spawn(self.sh, args=['-c', cmd]) # Vanilla Pexpect
155 child = pexpect.spawn(self.sh, args=['-c', cmd]) # Vanilla Pexpect
155 flush = sys.stdout.flush
156 flush = sys.stdout.flush
156 while True:
157 while True:
157 # res is the index of the pattern that caused the match, so we
158 # res is the index of the pattern that caused the match, so we
158 # know whether we've finished (if we matched EOF) or not
159 # know whether we've finished (if we matched EOF) or not
159 res_idx = child.expect_list(patterns, self.read_timeout)
160 res_idx = child.expect_list(patterns, self.read_timeout)
160 print(child.before[out_size:].decode(enc, 'replace'), end='')
161 print(child.before[out_size:].decode(enc, 'replace'), end='')
161 flush()
162 flush()
162 if res_idx==EOF_index:
163 if res_idx==EOF_index:
163 break
164 break
164 # Update the pointer to what we've already printed
165 # Update the pointer to what we've already printed
165 out_size = len(child.before)
166 out_size = len(child.before)
166 except KeyboardInterrupt:
167 except KeyboardInterrupt:
167 # We need to send ^C to the process. The ascii code for '^C' is 3
168 # We need to send ^C to the process. The ascii code for '^C' is 3
168 # (the character is known as ETX for 'End of Text', see
169 # (the character is known as ETX for 'End of Text', see
169 # curses.ascii.ETX).
170 # curses.ascii.ETX).
170 child.sendline(chr(3))
171 child.sendline(chr(3))
171 # Read and print any more output the program might produce on its
172 # Read and print any more output the program might produce on its
172 # way out.
173 # way out.
173 try:
174 try:
174 out_size = len(child.before)
175 out_size = len(child.before)
175 child.expect_list(patterns, self.terminate_timeout)
176 child.expect_list(patterns, self.terminate_timeout)
176 print(child.before[out_size:].decode(enc, 'replace'), end='')
177 print(child.before[out_size:].decode(enc, 'replace'), end='')
177 sys.stdout.flush()
178 sys.stdout.flush()
178 except KeyboardInterrupt:
179 except KeyboardInterrupt:
179 # Impatient users tend to type it multiple times
180 # Impatient users tend to type it multiple times
180 pass
181 pass
181 finally:
182 finally:
182 # Ensure the subprocess really is terminated
183 # Ensure the subprocess really is terminated
183 child.terminate(force=True)
184 child.terminate(force=True)
184 # add isalive check, to ensure exitstatus is set:
185 # add isalive check, to ensure exitstatus is set:
185 child.isalive()
186 child.isalive()
186 return child.exitstatus
187 return child.exitstatus
187
188
188
189
189 # Make system() with a functional interface for outside use. Note that we use
190 # Make system() with a functional interface for outside use. Note that we use
190 # getoutput() from the _common utils, which is built on top of popen(). Using
191 # getoutput() from the _common utils, which is built on top of popen(). Using
191 # pexpect to get subprocess output produces difficult to parse output, since
192 # pexpect to get subprocess output produces difficult to parse output, since
192 # programs think they are talking to a tty and produce highly formatted output
193 # programs think they are talking to a tty and produce highly formatted output
193 # (ls is a good example) that makes them hard.
194 # (ls is a good example) that makes them hard.
194 system = ProcessHandler().system
195 system = ProcessHandler().system
195
196
196
197
197
198
@@ -1,96 +1,35 b''
1 # encoding: utf-8
1 # encoding: utf-8
2 """Utilities for working with data structures like lists, dicts and tuples.
2 """Utilities for working with data structures like lists, dicts and tuples.
3 """
3 """
4
4
5 #-----------------------------------------------------------------------------
5 #-----------------------------------------------------------------------------
6 # Copyright (C) 2008-2011 The IPython Development Team
6 # Copyright (C) 2008-2011 The IPython Development Team
7 #
7 #
8 # Distributed under the terms of the BSD License. The full license is in
8 # Distributed under the terms of the BSD License. The full license is in
9 # the file COPYING, distributed as part of this software.
9 # the file COPYING, distributed as part of this software.
10 #-----------------------------------------------------------------------------
10 #-----------------------------------------------------------------------------
11
11
12 #-----------------------------------------------------------------------------
13 # Imports
14 #-----------------------------------------------------------------------------
15
16 import types
17
18 #-----------------------------------------------------------------------------
19 # Code
20 #-----------------------------------------------------------------------------
21
22 def uniq_stable(elems):
12 def uniq_stable(elems):
23 """uniq_stable(elems) -> list
13 """uniq_stable(elems) -> list
24
14
25 Return from an iterable, a list of all the unique elements in the input,
15 Return from an iterable, a list of all the unique elements in the input,
26 but maintaining the order in which they first appear.
16 but maintaining the order in which they first appear.
27
17
28 Note: All elements in the input must be hashable for this routine
18 Note: All elements in the input must be hashable for this routine
29 to work, as it internally uses a set for efficiency reasons.
19 to work, as it internally uses a set for efficiency reasons.
30 """
20 """
31 seen = set()
21 seen = set()
32 return [x for x in elems if x not in seen and not seen.add(x)]
22 return [x for x in elems if x not in seen and not seen.add(x)]
33
23
34
24
35 def sort_compare(lst1, lst2, inplace=1):
36 """Sort and compare two lists.
37
38 By default it does it in place, thus modifying the lists. Use inplace = 0
39 to avoid that (at the cost of temporary copy creation)."""
40 if not inplace:
41 lst1 = lst1[:]
42 lst2 = lst2[:]
43 lst1.sort(); lst2.sort()
44 return lst1 == lst2
45
46
47 def list2dict(lst):
48 """Takes a list of (key,value) pairs and turns it into a dict."""
49
50 dic = {}
51 for k,v in lst: dic[k] = v
52 return dic
53
54
55 def list2dict2(lst, default=''):
56 """Takes a list and turns it into a dict.
57 Much slower than list2dict, but more versatile. This version can take
58 lists with sublists of arbitrary length (including sclars)."""
59
60 dic = {}
61 for elem in lst:
62 if type(elem) in (types.ListType,types.TupleType):
63 size = len(elem)
64 if size == 0:
65 pass
66 elif size == 1:
67 dic[elem] = default
68 else:
69 k,v = elem[0], elem[1:]
70 if len(v) == 1: v = v[0]
71 dic[k] = v
72 else:
73 dic[elem] = default
74 return dic
75
76
77 def flatten(seq):
25 def flatten(seq):
78 """Flatten a list of lists (NOT recursive, only works for 2d lists)."""
26 """Flatten a list of lists (NOT recursive, only works for 2d lists)."""
79
27
80 return [x for subseq in seq for x in subseq]
28 return [x for subseq in seq for x in subseq]
81
29
82
83 def get_slice(seq, start=0, stop=None, step=1):
84 """Get a slice of a sequence with variable step. Specify start,stop,step."""
85 if stop == None:
86 stop = len(seq)
87 item = lambda i: seq[i]
88 return map(item,xrange(start,stop,step))
89
90
30
91 def chop(seq, size):
31 def chop(seq, size):
92 """Chop a sequence into chunks of the given size."""
32 """Chop a sequence into chunks of the given size."""
93 chunk = lambda i: seq[i:i+size]
33 return [seq[i:i+size] for i in xrange(0,len(seq),size)]
94 return map(chunk,xrange(0,len(seq),size))
95
34
96
35
@@ -1,384 +1,288 b''
1 # encoding: utf-8
1 # encoding: utf-8
2 """
2 """
3 IO related utilities.
3 IO related utilities.
4 """
4 """
5
5
6 #-----------------------------------------------------------------------------
6 #-----------------------------------------------------------------------------
7 # Copyright (C) 2008-2011 The IPython Development Team
7 # Copyright (C) 2008-2011 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 from __future__ import print_function
12 from __future__ import print_function
13
13
14 #-----------------------------------------------------------------------------
14 #-----------------------------------------------------------------------------
15 # Imports
15 # Imports
16 #-----------------------------------------------------------------------------
16 #-----------------------------------------------------------------------------
17 import os
17 import os
18 import sys
18 import sys
19 import tempfile
19 import tempfile
20 from StringIO import StringIO
20 from StringIO import StringIO
21
21
22 #-----------------------------------------------------------------------------
22 #-----------------------------------------------------------------------------
23 # Code
23 # Code
24 #-----------------------------------------------------------------------------
24 #-----------------------------------------------------------------------------
25
25
26
26
27 class IOStream:
27 class IOStream:
28
28
29 def __init__(self,stream, fallback=None):
29 def __init__(self,stream, fallback=None):
30 if not hasattr(stream,'write') or not hasattr(stream,'flush'):
30 if not hasattr(stream,'write') or not hasattr(stream,'flush'):
31 if fallback is not None:
31 if fallback is not None:
32 stream = fallback
32 stream = fallback
33 else:
33 else:
34 raise ValueError("fallback required, but not specified")
34 raise ValueError("fallback required, but not specified")
35 self.stream = stream
35 self.stream = stream
36 self._swrite = stream.write
36 self._swrite = stream.write
37
37
38 # clone all methods not overridden:
38 # clone all methods not overridden:
39 def clone(meth):
39 def clone(meth):
40 return not hasattr(self, meth) and not meth.startswith('_')
40 return not hasattr(self, meth) and not meth.startswith('_')
41 for meth in filter(clone, dir(stream)):
41 for meth in filter(clone, dir(stream)):
42 setattr(self, meth, getattr(stream, meth))
42 setattr(self, meth, getattr(stream, meth))
43
43
44 def write(self,data):
44 def write(self,data):
45 try:
45 try:
46 self._swrite(data)
46 self._swrite(data)
47 except:
47 except:
48 try:
48 try:
49 # print handles some unicode issues which may trip a plain
49 # print handles some unicode issues which may trip a plain
50 # write() call. Emulate write() by using an empty end
50 # write() call. Emulate write() by using an empty end
51 # argument.
51 # argument.
52 print(data, end='', file=self.stream)
52 print(data, end='', file=self.stream)
53 except:
53 except:
54 # if we get here, something is seriously broken.
54 # if we get here, something is seriously broken.
55 print('ERROR - failed to write data to stream:', self.stream,
55 print('ERROR - failed to write data to stream:', self.stream,
56 file=sys.stderr)
56 file=sys.stderr)
57
57
58 def writelines(self, lines):
58 def writelines(self, lines):
59 if isinstance(lines, basestring):
59 if isinstance(lines, basestring):
60 lines = [lines]
60 lines = [lines]
61 for line in lines:
61 for line in lines:
62 self.write(line)
62 self.write(line)
63
63
64 # This class used to have a writeln method, but regular files and streams
64 # This class used to have a writeln method, but regular files and streams
65 # in Python don't have this method. We need to keep this completely
65 # in Python don't have this method. We need to keep this completely
66 # compatible so we removed it.
66 # compatible so we removed it.
67
67
68 @property
68 @property
69 def closed(self):
69 def closed(self):
70 return self.stream.closed
70 return self.stream.closed
71
71
72 def close(self):
72 def close(self):
73 pass
73 pass
74
74
75 # setup stdin/stdout/stderr to sys.stdin/sys.stdout/sys.stderr
75 # setup stdin/stdout/stderr to sys.stdin/sys.stdout/sys.stderr
76 devnull = open(os.devnull, 'a')
76 devnull = open(os.devnull, 'a')
77 stdin = IOStream(sys.stdin, fallback=devnull)
77 stdin = IOStream(sys.stdin, fallback=devnull)
78 stdout = IOStream(sys.stdout, fallback=devnull)
78 stdout = IOStream(sys.stdout, fallback=devnull)
79 stderr = IOStream(sys.stderr, fallback=devnull)
79 stderr = IOStream(sys.stderr, fallback=devnull)
80
80
81 class IOTerm:
81 class IOTerm:
82 """ Term holds the file or file-like objects for handling I/O operations.
82 """ Term holds the file or file-like objects for handling I/O operations.
83
83
84 These are normally just sys.stdin, sys.stdout and sys.stderr but for
84 These are normally just sys.stdin, sys.stdout and sys.stderr but for
85 Windows they can can replaced to allow editing the strings before they are
85 Windows they can can replaced to allow editing the strings before they are
86 displayed."""
86 displayed."""
87
87
88 # In the future, having IPython channel all its I/O operations through
88 # In the future, having IPython channel all its I/O operations through
89 # this class will make it easier to embed it into other environments which
89 # this class will make it easier to embed it into other environments which
90 # are not a normal terminal (such as a GUI-based shell)
90 # are not a normal terminal (such as a GUI-based shell)
91 def __init__(self, stdin=None, stdout=None, stderr=None):
91 def __init__(self, stdin=None, stdout=None, stderr=None):
92 mymodule = sys.modules[__name__]
92 mymodule = sys.modules[__name__]
93 self.stdin = IOStream(stdin, mymodule.stdin)
93 self.stdin = IOStream(stdin, mymodule.stdin)
94 self.stdout = IOStream(stdout, mymodule.stdout)
94 self.stdout = IOStream(stdout, mymodule.stdout)
95 self.stderr = IOStream(stderr, mymodule.stderr)
95 self.stderr = IOStream(stderr, mymodule.stderr)
96
96
97
97
98 class Tee(object):
98 class Tee(object):
99 """A class to duplicate an output stream to stdout/err.
99 """A class to duplicate an output stream to stdout/err.
100
100
101 This works in a manner very similar to the Unix 'tee' command.
101 This works in a manner very similar to the Unix 'tee' command.
102
102
103 When the object is closed or deleted, it closes the original file given to
103 When the object is closed or deleted, it closes the original file given to
104 it for duplication.
104 it for duplication.
105 """
105 """
106 # Inspired by:
106 # Inspired by:
107 # http://mail.python.org/pipermail/python-list/2007-May/442737.html
107 # http://mail.python.org/pipermail/python-list/2007-May/442737.html
108
108
109 def __init__(self, file_or_name, mode="w", channel='stdout'):
109 def __init__(self, file_or_name, mode="w", channel='stdout'):
110 """Construct a new Tee object.
110 """Construct a new Tee object.
111
111
112 Parameters
112 Parameters
113 ----------
113 ----------
114 file_or_name : filename or open filehandle (writable)
114 file_or_name : filename or open filehandle (writable)
115 File that will be duplicated
115 File that will be duplicated
116
116
117 mode : optional, valid mode for open().
117 mode : optional, valid mode for open().
118 If a filename was give, open with this mode.
118 If a filename was give, open with this mode.
119
119
120 channel : str, one of ['stdout', 'stderr']
120 channel : str, one of ['stdout', 'stderr']
121 """
121 """
122 if channel not in ['stdout', 'stderr']:
122 if channel not in ['stdout', 'stderr']:
123 raise ValueError('Invalid channel spec %s' % channel)
123 raise ValueError('Invalid channel spec %s' % channel)
124
124
125 if hasattr(file_or_name, 'write') and hasattr(file_or_name, 'seek'):
125 if hasattr(file_or_name, 'write') and hasattr(file_or_name, 'seek'):
126 self.file = file_or_name
126 self.file = file_or_name
127 else:
127 else:
128 self.file = open(file_or_name, mode)
128 self.file = open(file_or_name, mode)
129 self.channel = channel
129 self.channel = channel
130 self.ostream = getattr(sys, channel)
130 self.ostream = getattr(sys, channel)
131 setattr(sys, channel, self)
131 setattr(sys, channel, self)
132 self._closed = False
132 self._closed = False
133
133
134 def close(self):
134 def close(self):
135 """Close the file and restore the channel."""
135 """Close the file and restore the channel."""
136 self.flush()
136 self.flush()
137 setattr(sys, self.channel, self.ostream)
137 setattr(sys, self.channel, self.ostream)
138 self.file.close()
138 self.file.close()
139 self._closed = True
139 self._closed = True
140
140
141 def write(self, data):
141 def write(self, data):
142 """Write data to both channels."""
142 """Write data to both channels."""
143 self.file.write(data)
143 self.file.write(data)
144 self.ostream.write(data)
144 self.ostream.write(data)
145 self.ostream.flush()
145 self.ostream.flush()
146
146
147 def flush(self):
147 def flush(self):
148 """Flush both channels."""
148 """Flush both channels."""
149 self.file.flush()
149 self.file.flush()
150 self.ostream.flush()
150 self.ostream.flush()
151
151
152 def __del__(self):
152 def __del__(self):
153 if not self._closed:
153 if not self._closed:
154 self.close()
154 self.close()
155
155
156
156
157 def file_read(filename):
158 """Read a file and close it. Returns the file source."""
159 fobj = open(filename,'r');
160 source = fobj.read();
161 fobj.close()
162 return source
163
164
165 def file_readlines(filename):
166 """Read a file and close it. Returns the file source using readlines()."""
167 fobj = open(filename,'r');
168 lines = fobj.readlines();
169 fobj.close()
170 return lines
171
172
173 def raw_input_multi(header='', ps1='==> ', ps2='..> ',terminate_str = '.'):
174 """Take multiple lines of input.
175
176 A list with each line of input as a separate element is returned when a
177 termination string is entered (defaults to a single '.'). Input can also
178 terminate via EOF (^D in Unix, ^Z-RET in Windows).
179
180 Lines of input which end in \\ are joined into single entries (and a
181 secondary continuation prompt is issued as long as the user terminates
182 lines with \\). This allows entering very long strings which are still
183 meant to be treated as single entities.
184 """
185
186 try:
187 if header:
188 header += '\n'
189 lines = [raw_input(header + ps1)]
190 except EOFError:
191 return []
192 terminate = [terminate_str]
193 try:
194 while lines[-1:] != terminate:
195 new_line = raw_input(ps1)
196 while new_line.endswith('\\'):
197 new_line = new_line[:-1] + raw_input(ps2)
198 lines.append(new_line)
199
200 return lines[:-1] # don't return the termination command
201 except EOFError:
202 print()
203 return lines
204
205
206 def raw_input_ext(prompt='', ps2='... '):
207 """Similar to raw_input(), but accepts extended lines if input ends with \\."""
208
209 line = raw_input(prompt)
210 while line.endswith('\\'):
211 line = line[:-1] + raw_input(ps2)
212 return line
213
214
215 def ask_yes_no(prompt,default=None):
157 def ask_yes_no(prompt,default=None):
216 """Asks a question and returns a boolean (y/n) answer.
158 """Asks a question and returns a boolean (y/n) answer.
217
159
218 If default is given (one of 'y','n'), it is used if the user input is
160 If default is given (one of 'y','n'), it is used if the user input is
219 empty. Otherwise the question is repeated until an answer is given.
161 empty. Otherwise the question is repeated until an answer is given.
220
162
221 An EOF is treated as the default answer. If there is no default, an
163 An EOF is treated as the default answer. If there is no default, an
222 exception is raised to prevent infinite loops.
164 exception is raised to prevent infinite loops.
223
165
224 Valid answers are: y/yes/n/no (match is not case sensitive)."""
166 Valid answers are: y/yes/n/no (match is not case sensitive)."""
225
167
226 answers = {'y':True,'n':False,'yes':True,'no':False}
168 answers = {'y':True,'n':False,'yes':True,'no':False}
227 ans = None
169 ans = None
228 while ans not in answers.keys():
170 while ans not in answers.keys():
229 try:
171 try:
230 ans = raw_input(prompt+' ').lower()
172 ans = raw_input(prompt+' ').lower()
231 if not ans: # response was an empty string
173 if not ans: # response was an empty string
232 ans = default
174 ans = default
233 except KeyboardInterrupt:
175 except KeyboardInterrupt:
234 pass
176 pass
235 except EOFError:
177 except EOFError:
236 if default in answers.keys():
178 if default in answers.keys():
237 ans = default
179 ans = default
238 print()
180 print()
239 else:
181 else:
240 raise
182 raise
241
183
242 return answers[ans]
184 return answers[ans]
243
185
244
186
245 class NLprinter:
246 """Print an arbitrarily nested list, indicating index numbers.
247
248 An instance of this class called nlprint is available and callable as a
249 function.
250
251 nlprint(list,indent=' ',sep=': ') -> prints indenting each level by 'indent'
252 and using 'sep' to separate the index from the value. """
253
254 def __init__(self):
255 self.depth = 0
256
257 def __call__(self,lst,pos='',**kw):
258 """Prints the nested list numbering levels."""
259 kw.setdefault('indent',' ')
260 kw.setdefault('sep',': ')
261 kw.setdefault('start',0)
262 kw.setdefault('stop',len(lst))
263 # we need to remove start and stop from kw so they don't propagate
264 # into a recursive call for a nested list.
265 start = kw['start']; del kw['start']
266 stop = kw['stop']; del kw['stop']
267 if self.depth == 0 and 'header' in kw.keys():
268 print(kw['header'])
269
270 for idx in range(start,stop):
271 elem = lst[idx]
272 newpos = pos + str(idx)
273 if type(elem)==type([]):
274 self.depth += 1
275 self.__call__(elem, newpos+",", **kw)
276 self.depth -= 1
277 else:
278 print(kw['indent']*self.depth + newpos + kw["sep"] + repr(elem))
279
280 nlprint = NLprinter()
281
282
283 def temp_pyfile(src, ext='.py'):
187 def temp_pyfile(src, ext='.py'):
284 """Make a temporary python file, return filename and filehandle.
188 """Make a temporary python file, return filename and filehandle.
285
189
286 Parameters
190 Parameters
287 ----------
191 ----------
288 src : string or list of strings (no need for ending newlines if list)
192 src : string or list of strings (no need for ending newlines if list)
289 Source code to be written to the file.
193 Source code to be written to the file.
290
194
291 ext : optional, string
195 ext : optional, string
292 Extension for the generated file.
196 Extension for the generated file.
293
197
294 Returns
198 Returns
295 -------
199 -------
296 (filename, open filehandle)
200 (filename, open filehandle)
297 It is the caller's responsibility to close the open file and unlink it.
201 It is the caller's responsibility to close the open file and unlink it.
298 """
202 """
299 fname = tempfile.mkstemp(ext)[1]
203 fname = tempfile.mkstemp(ext)[1]
300 f = open(fname,'w')
204 f = open(fname,'w')
301 f.write(src)
205 f.write(src)
302 f.flush()
206 f.flush()
303 return fname, f
207 return fname, f
304
208
305
209
306 def raw_print(*args, **kw):
210 def raw_print(*args, **kw):
307 """Raw print to sys.__stdout__, otherwise identical interface to print()."""
211 """Raw print to sys.__stdout__, otherwise identical interface to print()."""
308
212
309 print(*args, sep=kw.get('sep', ' '), end=kw.get('end', '\n'),
213 print(*args, sep=kw.get('sep', ' '), end=kw.get('end', '\n'),
310 file=sys.__stdout__)
214 file=sys.__stdout__)
311 sys.__stdout__.flush()
215 sys.__stdout__.flush()
312
216
313
217
314 def raw_print_err(*args, **kw):
218 def raw_print_err(*args, **kw):
315 """Raw print to sys.__stderr__, otherwise identical interface to print()."""
219 """Raw print to sys.__stderr__, otherwise identical interface to print()."""
316
220
317 print(*args, sep=kw.get('sep', ' '), end=kw.get('end', '\n'),
221 print(*args, sep=kw.get('sep', ' '), end=kw.get('end', '\n'),
318 file=sys.__stderr__)
222 file=sys.__stderr__)
319 sys.__stderr__.flush()
223 sys.__stderr__.flush()
320
224
321
225
322 # Short aliases for quick debugging, do NOT use these in production code.
226 # Short aliases for quick debugging, do NOT use these in production code.
323 rprint = raw_print
227 rprint = raw_print
324 rprinte = raw_print_err
228 rprinte = raw_print_err
325
229
326
230
327 class CapturedIO(object):
231 class CapturedIO(object):
328 """Simple object for containing captured stdout/err StringIO objects"""
232 """Simple object for containing captured stdout/err StringIO objects"""
329
233
330 def __init__(self, stdout, stderr):
234 def __init__(self, stdout, stderr):
331 self._stdout = stdout
235 self._stdout = stdout
332 self._stderr = stderr
236 self._stderr = stderr
333
237
334 def __str__(self):
238 def __str__(self):
335 return self.stdout
239 return self.stdout
336
240
337 @property
241 @property
338 def stdout(self):
242 def stdout(self):
339 if not self._stdout:
243 if not self._stdout:
340 return ''
244 return ''
341 return self._stdout.getvalue()
245 return self._stdout.getvalue()
342
246
343 @property
247 @property
344 def stderr(self):
248 def stderr(self):
345 if not self._stderr:
249 if not self._stderr:
346 return ''
250 return ''
347 return self._stderr.getvalue()
251 return self._stderr.getvalue()
348
252
349 def show(self):
253 def show(self):
350 """write my output to sys.stdout/err as appropriate"""
254 """write my output to sys.stdout/err as appropriate"""
351 sys.stdout.write(self.stdout)
255 sys.stdout.write(self.stdout)
352 sys.stderr.write(self.stderr)
256 sys.stderr.write(self.stderr)
353 sys.stdout.flush()
257 sys.stdout.flush()
354 sys.stderr.flush()
258 sys.stderr.flush()
355
259
356 __call__ = show
260 __call__ = show
357
261
358
262
359 class capture_output(object):
263 class capture_output(object):
360 """context manager for capturing stdout/err"""
264 """context manager for capturing stdout/err"""
361 stdout = True
265 stdout = True
362 stderr = True
266 stderr = True
363
267
364 def __init__(self, stdout=True, stderr=True):
268 def __init__(self, stdout=True, stderr=True):
365 self.stdout = stdout
269 self.stdout = stdout
366 self.stderr = stderr
270 self.stderr = stderr
367
271
368 def __enter__(self):
272 def __enter__(self):
369 self.sys_stdout = sys.stdout
273 self.sys_stdout = sys.stdout
370 self.sys_stderr = sys.stderr
274 self.sys_stderr = sys.stderr
371
275
372 stdout = stderr = False
276 stdout = stderr = False
373 if self.stdout:
277 if self.stdout:
374 stdout = sys.stdout = StringIO()
278 stdout = sys.stdout = StringIO()
375 if self.stderr:
279 if self.stderr:
376 stderr = sys.stderr = StringIO()
280 stderr = sys.stderr = StringIO()
377
281
378 return CapturedIO(stdout, stderr)
282 return CapturedIO(stdout, stderr)
379
283
380 def __exit__(self, exc_type, exc_value, traceback):
284 def __exit__(self, exc_type, exc_value, traceback):
381 sys.stdout = self.sys_stdout
285 sys.stdout = self.sys_stdout
382 sys.stderr = self.sys_stderr
286 sys.stderr = self.sys_stderr
383
287
384
288
@@ -1,393 +1,391 b''
1 # encoding: utf-8
1 # encoding: utf-8
2 """A dict subclass that supports attribute style access.
2 """A dict subclass that supports attribute style access.
3
3
4 Authors:
4 Authors:
5
5
6 * Fernando Perez (original)
6 * Fernando Perez (original)
7 * Brian Granger (refactoring to a dict subclass)
7 * Brian Granger (refactoring to a dict subclass)
8 """
8 """
9
9
10 #-----------------------------------------------------------------------------
10 #-----------------------------------------------------------------------------
11 # Copyright (C) 2008-2011 The IPython Development Team
11 # Copyright (C) 2008-2011 The IPython Development Team
12 #
12 #
13 # Distributed under the terms of the BSD License. The full license is in
13 # Distributed under the terms of the BSD License. The full license is in
14 # the file COPYING, distributed as part of this software.
14 # the file COPYING, distributed as part of this software.
15 #-----------------------------------------------------------------------------
15 #-----------------------------------------------------------------------------
16
16
17 #-----------------------------------------------------------------------------
17 #-----------------------------------------------------------------------------
18 # Imports
18 # Imports
19 #-----------------------------------------------------------------------------
19 #-----------------------------------------------------------------------------
20
20
21 from IPython.utils.data import list2dict2
22
23 __all__ = ['Struct']
21 __all__ = ['Struct']
24
22
25 #-----------------------------------------------------------------------------
23 #-----------------------------------------------------------------------------
26 # Code
24 # Code
27 #-----------------------------------------------------------------------------
25 #-----------------------------------------------------------------------------
28
26
29
27
30 class Struct(dict):
28 class Struct(dict):
31 """A dict subclass with attribute style access.
29 """A dict subclass with attribute style access.
32
30
33 This dict subclass has a a few extra features:
31 This dict subclass has a a few extra features:
34
32
35 * Attribute style access.
33 * Attribute style access.
36 * Protection of class members (like keys, items) when using attribute
34 * Protection of class members (like keys, items) when using attribute
37 style access.
35 style access.
38 * The ability to restrict assignment to only existing keys.
36 * The ability to restrict assignment to only existing keys.
39 * Intelligent merging.
37 * Intelligent merging.
40 * Overloaded operators.
38 * Overloaded operators.
41 """
39 """
42 _allownew = True
40 _allownew = True
43 def __init__(self, *args, **kw):
41 def __init__(self, *args, **kw):
44 """Initialize with a dictionary, another Struct, or data.
42 """Initialize with a dictionary, another Struct, or data.
45
43
46 Parameters
44 Parameters
47 ----------
45 ----------
48 args : dict, Struct
46 args : dict, Struct
49 Initialize with one dict or Struct
47 Initialize with one dict or Struct
50 kw : dict
48 kw : dict
51 Initialize with key, value pairs.
49 Initialize with key, value pairs.
52
50
53 Examples
51 Examples
54 --------
52 --------
55
53
56 >>> s = Struct(a=10,b=30)
54 >>> s = Struct(a=10,b=30)
57 >>> s.a
55 >>> s.a
58 10
56 10
59 >>> s.b
57 >>> s.b
60 30
58 30
61 >>> s2 = Struct(s,c=30)
59 >>> s2 = Struct(s,c=30)
62 >>> sorted(s2.keys())
60 >>> sorted(s2.keys())
63 ['a', 'b', 'c']
61 ['a', 'b', 'c']
64 """
62 """
65 object.__setattr__(self, '_allownew', True)
63 object.__setattr__(self, '_allownew', True)
66 dict.__init__(self, *args, **kw)
64 dict.__init__(self, *args, **kw)
67
65
68 def __setitem__(self, key, value):
66 def __setitem__(self, key, value):
69 """Set an item with check for allownew.
67 """Set an item with check for allownew.
70
68
71 Examples
69 Examples
72 --------
70 --------
73
71
74 >>> s = Struct()
72 >>> s = Struct()
75 >>> s['a'] = 10
73 >>> s['a'] = 10
76 >>> s.allow_new_attr(False)
74 >>> s.allow_new_attr(False)
77 >>> s['a'] = 10
75 >>> s['a'] = 10
78 >>> s['a']
76 >>> s['a']
79 10
77 10
80 >>> try:
78 >>> try:
81 ... s['b'] = 20
79 ... s['b'] = 20
82 ... except KeyError:
80 ... except KeyError:
83 ... print 'this is not allowed'
81 ... print 'this is not allowed'
84 ...
82 ...
85 this is not allowed
83 this is not allowed
86 """
84 """
87 if not self._allownew and key not in self:
85 if not self._allownew and key not in self:
88 raise KeyError(
86 raise KeyError(
89 "can't create new attribute %s when allow_new_attr(False)" % key)
87 "can't create new attribute %s when allow_new_attr(False)" % key)
90 dict.__setitem__(self, key, value)
88 dict.__setitem__(self, key, value)
91
89
92 def __setattr__(self, key, value):
90 def __setattr__(self, key, value):
93 """Set an attr with protection of class members.
91 """Set an attr with protection of class members.
94
92
95 This calls :meth:`self.__setitem__` but convert :exc:`KeyError` to
93 This calls :meth:`self.__setitem__` but convert :exc:`KeyError` to
96 :exc:`AttributeError`.
94 :exc:`AttributeError`.
97
95
98 Examples
96 Examples
99 --------
97 --------
100
98
101 >>> s = Struct()
99 >>> s = Struct()
102 >>> s.a = 10
100 >>> s.a = 10
103 >>> s.a
101 >>> s.a
104 10
102 10
105 >>> try:
103 >>> try:
106 ... s.get = 10
104 ... s.get = 10
107 ... except AttributeError:
105 ... except AttributeError:
108 ... print "you can't set a class member"
106 ... print "you can't set a class member"
109 ...
107 ...
110 you can't set a class member
108 you can't set a class member
111 """
109 """
112 # If key is an str it might be a class member or instance var
110 # If key is an str it might be a class member or instance var
113 if isinstance(key, str):
111 if isinstance(key, str):
114 # I can't simply call hasattr here because it calls getattr, which
112 # I can't simply call hasattr here because it calls getattr, which
115 # calls self.__getattr__, which returns True for keys in
113 # calls self.__getattr__, which returns True for keys in
116 # self._data. But I only want keys in the class and in
114 # self._data. But I only want keys in the class and in
117 # self.__dict__
115 # self.__dict__
118 if key in self.__dict__ or hasattr(Struct, key):
116 if key in self.__dict__ or hasattr(Struct, key):
119 raise AttributeError(
117 raise AttributeError(
120 'attr %s is a protected member of class Struct.' % key
118 'attr %s is a protected member of class Struct.' % key
121 )
119 )
122 try:
120 try:
123 self.__setitem__(key, value)
121 self.__setitem__(key, value)
124 except KeyError as e:
122 except KeyError as e:
125 raise AttributeError(e)
123 raise AttributeError(e)
126
124
127 def __getattr__(self, key):
125 def __getattr__(self, key):
128 """Get an attr by calling :meth:`dict.__getitem__`.
126 """Get an attr by calling :meth:`dict.__getitem__`.
129
127
130 Like :meth:`__setattr__`, this method converts :exc:`KeyError` to
128 Like :meth:`__setattr__`, this method converts :exc:`KeyError` to
131 :exc:`AttributeError`.
129 :exc:`AttributeError`.
132
130
133 Examples
131 Examples
134 --------
132 --------
135
133
136 >>> s = Struct(a=10)
134 >>> s = Struct(a=10)
137 >>> s.a
135 >>> s.a
138 10
136 10
139 >>> type(s.get)
137 >>> type(s.get)
140 <... 'builtin_function_or_method'>
138 <... 'builtin_function_or_method'>
141 >>> try:
139 >>> try:
142 ... s.b
140 ... s.b
143 ... except AttributeError:
141 ... except AttributeError:
144 ... print "I don't have that key"
142 ... print "I don't have that key"
145 ...
143 ...
146 I don't have that key
144 I don't have that key
147 """
145 """
148 try:
146 try:
149 result = self[key]
147 result = self[key]
150 except KeyError:
148 except KeyError:
151 raise AttributeError(key)
149 raise AttributeError(key)
152 else:
150 else:
153 return result
151 return result
154
152
155 def __iadd__(self, other):
153 def __iadd__(self, other):
156 """s += s2 is a shorthand for s.merge(s2).
154 """s += s2 is a shorthand for s.merge(s2).
157
155
158 Examples
156 Examples
159 --------
157 --------
160
158
161 >>> s = Struct(a=10,b=30)
159 >>> s = Struct(a=10,b=30)
162 >>> s2 = Struct(a=20,c=40)
160 >>> s2 = Struct(a=20,c=40)
163 >>> s += s2
161 >>> s += s2
164 >>> sorted(s.keys())
162 >>> sorted(s.keys())
165 ['a', 'b', 'c']
163 ['a', 'b', 'c']
166 """
164 """
167 self.merge(other)
165 self.merge(other)
168 return self
166 return self
169
167
170 def __add__(self,other):
168 def __add__(self,other):
171 """s + s2 -> New Struct made from s.merge(s2).
169 """s + s2 -> New Struct made from s.merge(s2).
172
170
173 Examples
171 Examples
174 --------
172 --------
175
173
176 >>> s1 = Struct(a=10,b=30)
174 >>> s1 = Struct(a=10,b=30)
177 >>> s2 = Struct(a=20,c=40)
175 >>> s2 = Struct(a=20,c=40)
178 >>> s = s1 + s2
176 >>> s = s1 + s2
179 >>> sorted(s.keys())
177 >>> sorted(s.keys())
180 ['a', 'b', 'c']
178 ['a', 'b', 'c']
181 """
179 """
182 sout = self.copy()
180 sout = self.copy()
183 sout.merge(other)
181 sout.merge(other)
184 return sout
182 return sout
185
183
186 def __sub__(self,other):
184 def __sub__(self,other):
187 """s1 - s2 -> remove keys in s2 from s1.
185 """s1 - s2 -> remove keys in s2 from s1.
188
186
189 Examples
187 Examples
190 --------
188 --------
191
189
192 >>> s1 = Struct(a=10,b=30)
190 >>> s1 = Struct(a=10,b=30)
193 >>> s2 = Struct(a=40)
191 >>> s2 = Struct(a=40)
194 >>> s = s1 - s2
192 >>> s = s1 - s2
195 >>> s
193 >>> s
196 {'b': 30}
194 {'b': 30}
197 """
195 """
198 sout = self.copy()
196 sout = self.copy()
199 sout -= other
197 sout -= other
200 return sout
198 return sout
201
199
202 def __isub__(self,other):
200 def __isub__(self,other):
203 """Inplace remove keys from self that are in other.
201 """Inplace remove keys from self that are in other.
204
202
205 Examples
203 Examples
206 --------
204 --------
207
205
208 >>> s1 = Struct(a=10,b=30)
206 >>> s1 = Struct(a=10,b=30)
209 >>> s2 = Struct(a=40)
207 >>> s2 = Struct(a=40)
210 >>> s1 -= s2
208 >>> s1 -= s2
211 >>> s1
209 >>> s1
212 {'b': 30}
210 {'b': 30}
213 """
211 """
214 for k in other.keys():
212 for k in other.keys():
215 if k in self:
213 if k in self:
216 del self[k]
214 del self[k]
217 return self
215 return self
218
216
219 def __dict_invert(self, data):
217 def __dict_invert(self, data):
220 """Helper function for merge.
218 """Helper function for merge.
221
219
222 Takes a dictionary whose values are lists and returns a dict with
220 Takes a dictionary whose values are lists and returns a dict with
223 the elements of each list as keys and the original keys as values.
221 the elements of each list as keys and the original keys as values.
224 """
222 """
225 outdict = {}
223 outdict = {}
226 for k,lst in data.items():
224 for k,lst in data.items():
227 if isinstance(lst, str):
225 if isinstance(lst, str):
228 lst = lst.split()
226 lst = lst.split()
229 for entry in lst:
227 for entry in lst:
230 outdict[entry] = k
228 outdict[entry] = k
231 return outdict
229 return outdict
232
230
233 def dict(self):
231 def dict(self):
234 return self
232 return self
235
233
236 def copy(self):
234 def copy(self):
237 """Return a copy as a Struct.
235 """Return a copy as a Struct.
238
236
239 Examples
237 Examples
240 --------
238 --------
241
239
242 >>> s = Struct(a=10,b=30)
240 >>> s = Struct(a=10,b=30)
243 >>> s2 = s.copy()
241 >>> s2 = s.copy()
244 >>> type(s2) is Struct
242 >>> type(s2) is Struct
245 True
243 True
246 """
244 """
247 return Struct(dict.copy(self))
245 return Struct(dict.copy(self))
248
246
249 def hasattr(self, key):
247 def hasattr(self, key):
250 """hasattr function available as a method.
248 """hasattr function available as a method.
251
249
252 Implemented like has_key.
250 Implemented like has_key.
253
251
254 Examples
252 Examples
255 --------
253 --------
256
254
257 >>> s = Struct(a=10)
255 >>> s = Struct(a=10)
258 >>> s.hasattr('a')
256 >>> s.hasattr('a')
259 True
257 True
260 >>> s.hasattr('b')
258 >>> s.hasattr('b')
261 False
259 False
262 >>> s.hasattr('get')
260 >>> s.hasattr('get')
263 False
261 False
264 """
262 """
265 return key in self
263 return key in self
266
264
267 def allow_new_attr(self, allow = True):
265 def allow_new_attr(self, allow = True):
268 """Set whether new attributes can be created in this Struct.
266 """Set whether new attributes can be created in this Struct.
269
267
270 This can be used to catch typos by verifying that the attribute user
268 This can be used to catch typos by verifying that the attribute user
271 tries to change already exists in this Struct.
269 tries to change already exists in this Struct.
272 """
270 """
273 object.__setattr__(self, '_allownew', allow)
271 object.__setattr__(self, '_allownew', allow)
274
272
275 def merge(self, __loc_data__=None, __conflict_solve=None, **kw):
273 def merge(self, __loc_data__=None, __conflict_solve=None, **kw):
276 """Merge two Structs with customizable conflict resolution.
274 """Merge two Structs with customizable conflict resolution.
277
275
278 This is similar to :meth:`update`, but much more flexible. First, a
276 This is similar to :meth:`update`, but much more flexible. First, a
279 dict is made from data+key=value pairs. When merging this dict with
277 dict is made from data+key=value pairs. When merging this dict with
280 the Struct S, the optional dictionary 'conflict' is used to decide
278 the Struct S, the optional dictionary 'conflict' is used to decide
281 what to do.
279 what to do.
282
280
283 If conflict is not given, the default behavior is to preserve any keys
281 If conflict is not given, the default behavior is to preserve any keys
284 with their current value (the opposite of the :meth:`update` method's
282 with their current value (the opposite of the :meth:`update` method's
285 behavior).
283 behavior).
286
284
287 Parameters
285 Parameters
288 ----------
286 ----------
289 __loc_data : dict, Struct
287 __loc_data : dict, Struct
290 The data to merge into self
288 The data to merge into self
291 __conflict_solve : dict
289 __conflict_solve : dict
292 The conflict policy dict. The keys are binary functions used to
290 The conflict policy dict. The keys are binary functions used to
293 resolve the conflict and the values are lists of strings naming
291 resolve the conflict and the values are lists of strings naming
294 the keys the conflict resolution function applies to. Instead of
292 the keys the conflict resolution function applies to. Instead of
295 a list of strings a space separated string can be used, like
293 a list of strings a space separated string can be used, like
296 'a b c'.
294 'a b c'.
297 kw : dict
295 kw : dict
298 Additional key, value pairs to merge in
296 Additional key, value pairs to merge in
299
297
300 Notes
298 Notes
301 -----
299 -----
302
300
303 The `__conflict_solve` dict is a dictionary of binary functions which will be used to
301 The `__conflict_solve` dict is a dictionary of binary functions which will be used to
304 solve key conflicts. Here is an example::
302 solve key conflicts. Here is an example::
305
303
306 __conflict_solve = dict(
304 __conflict_solve = dict(
307 func1=['a','b','c'],
305 func1=['a','b','c'],
308 func2=['d','e']
306 func2=['d','e']
309 )
307 )
310
308
311 In this case, the function :func:`func1` will be used to resolve
309 In this case, the function :func:`func1` will be used to resolve
312 keys 'a', 'b' and 'c' and the function :func:`func2` will be used for
310 keys 'a', 'b' and 'c' and the function :func:`func2` will be used for
313 keys 'd' and 'e'. This could also be written as::
311 keys 'd' and 'e'. This could also be written as::
314
312
315 __conflict_solve = dict(func1='a b c',func2='d e')
313 __conflict_solve = dict(func1='a b c',func2='d e')
316
314
317 These functions will be called for each key they apply to with the
315 These functions will be called for each key they apply to with the
318 form::
316 form::
319
317
320 func1(self['a'], other['a'])
318 func1(self['a'], other['a'])
321
319
322 The return value is used as the final merged value.
320 The return value is used as the final merged value.
323
321
324 As a convenience, merge() provides five (the most commonly needed)
322 As a convenience, merge() provides five (the most commonly needed)
325 pre-defined policies: preserve, update, add, add_flip and add_s. The
323 pre-defined policies: preserve, update, add, add_flip and add_s. The
326 easiest explanation is their implementation::
324 easiest explanation is their implementation::
327
325
328 preserve = lambda old,new: old
326 preserve = lambda old,new: old
329 update = lambda old,new: new
327 update = lambda old,new: new
330 add = lambda old,new: old + new
328 add = lambda old,new: old + new
331 add_flip = lambda old,new: new + old # note change of order!
329 add_flip = lambda old,new: new + old # note change of order!
332 add_s = lambda old,new: old + ' ' + new # only for str!
330 add_s = lambda old,new: old + ' ' + new # only for str!
333
331
334 You can use those four words (as strings) as keys instead
332 You can use those four words (as strings) as keys instead
335 of defining them as functions, and the merge method will substitute
333 of defining them as functions, and the merge method will substitute
336 the appropriate functions for you.
334 the appropriate functions for you.
337
335
338 For more complicated conflict resolution policies, you still need to
336 For more complicated conflict resolution policies, you still need to
339 construct your own functions.
337 construct your own functions.
340
338
341 Examples
339 Examples
342 --------
340 --------
343
341
344 This show the default policy:
342 This show the default policy:
345
343
346 >>> s = Struct(a=10,b=30)
344 >>> s = Struct(a=10,b=30)
347 >>> s2 = Struct(a=20,c=40)
345 >>> s2 = Struct(a=20,c=40)
348 >>> s.merge(s2)
346 >>> s.merge(s2)
349 >>> sorted(s.items())
347 >>> sorted(s.items())
350 [('a', 10), ('b', 30), ('c', 40)]
348 [('a', 10), ('b', 30), ('c', 40)]
351
349
352 Now, show how to specify a conflict dict:
350 Now, show how to specify a conflict dict:
353
351
354 >>> s = Struct(a=10,b=30)
352 >>> s = Struct(a=10,b=30)
355 >>> s2 = Struct(a=20,b=40)
353 >>> s2 = Struct(a=20,b=40)
356 >>> conflict = {'update':'a','add':'b'}
354 >>> conflict = {'update':'a','add':'b'}
357 >>> s.merge(s2,conflict)
355 >>> s.merge(s2,conflict)
358 >>> sorted(s.items())
356 >>> sorted(s.items())
359 [('a', 20), ('b', 70)]
357 [('a', 20), ('b', 70)]
360 """
358 """
361
359
362 data_dict = dict(__loc_data__,**kw)
360 data_dict = dict(__loc_data__,**kw)
363
361
364 # policies for conflict resolution: two argument functions which return
362 # policies for conflict resolution: two argument functions which return
365 # the value that will go in the new struct
363 # the value that will go in the new struct
366 preserve = lambda old,new: old
364 preserve = lambda old,new: old
367 update = lambda old,new: new
365 update = lambda old,new: new
368 add = lambda old,new: old + new
366 add = lambda old,new: old + new
369 add_flip = lambda old,new: new + old # note change of order!
367 add_flip = lambda old,new: new + old # note change of order!
370 add_s = lambda old,new: old + ' ' + new
368 add_s = lambda old,new: old + ' ' + new
371
369
372 # default policy is to keep current keys when there's a conflict
370 # default policy is to keep current keys when there's a conflict
373 conflict_solve = list2dict2(self.keys(), default = preserve)
371 conflict_solve = dict.fromkeys(self, preserve)
374
372
375 # the conflict_solve dictionary is given by the user 'inverted': we
373 # the conflict_solve dictionary is given by the user 'inverted': we
376 # need a name-function mapping, it comes as a function -> names
374 # need a name-function mapping, it comes as a function -> names
377 # dict. Make a local copy (b/c we'll make changes), replace user
375 # dict. Make a local copy (b/c we'll make changes), replace user
378 # strings for the three builtin policies and invert it.
376 # strings for the three builtin policies and invert it.
379 if __conflict_solve:
377 if __conflict_solve:
380 inv_conflict_solve_user = __conflict_solve.copy()
378 inv_conflict_solve_user = __conflict_solve.copy()
381 for name, func in [('preserve',preserve), ('update',update),
379 for name, func in [('preserve',preserve), ('update',update),
382 ('add',add), ('add_flip',add_flip),
380 ('add',add), ('add_flip',add_flip),
383 ('add_s',add_s)]:
381 ('add_s',add_s)]:
384 if name in inv_conflict_solve_user.keys():
382 if name in inv_conflict_solve_user.keys():
385 inv_conflict_solve_user[func] = inv_conflict_solve_user[name]
383 inv_conflict_solve_user[func] = inv_conflict_solve_user[name]
386 del inv_conflict_solve_user[name]
384 del inv_conflict_solve_user[name]
387 conflict_solve.update(self.__dict_invert(inv_conflict_solve_user))
385 conflict_solve.update(self.__dict_invert(inv_conflict_solve_user))
388 for key in data_dict:
386 for key in data_dict:
389 if key not in self:
387 if key not in self:
390 self[key] = data_dict[key]
388 self[key] = data_dict[key]
391 else:
389 else:
392 self[key] = conflict_solve[key](self[key],data_dict[key])
390 self[key] = conflict_solve[key](self[key],data_dict[key])
393
391
@@ -1,219 +1,239 b''
1 """
1 """
2 Tools to open .py files as Unicode, using the encoding specified within the file,
2 Tools to open .py files as Unicode, using the encoding specified within the file,
3 as per PEP 263.
3 as per PEP 263.
4
4
5 Much of the code is taken from the tokenize module in Python 3.2.
5 Much of the code is taken from the tokenize module in Python 3.2.
6 """
6 """
7 from __future__ import absolute_import
7 from __future__ import absolute_import
8
8
9 import io
9 import io
10 from io import TextIOWrapper, BytesIO
10 from io import TextIOWrapper, BytesIO
11 import os.path
11 import re
12 import re
12
13
13 cookie_re = re.compile(ur"coding[:=]\s*([-\w.]+)", re.UNICODE)
14 cookie_re = re.compile(ur"coding[:=]\s*([-\w.]+)", re.UNICODE)
14 cookie_comment_re = re.compile(ur"^\s*#.*coding[:=]\s*([-\w.]+)", re.UNICODE)
15 cookie_comment_re = re.compile(ur"^\s*#.*coding[:=]\s*([-\w.]+)", re.UNICODE)
15
16
16 try:
17 try:
17 # Available in Python 3
18 # Available in Python 3
18 from tokenize import detect_encoding
19 from tokenize import detect_encoding
19 except ImportError:
20 except ImportError:
20 from codecs import lookup, BOM_UTF8
21 from codecs import lookup, BOM_UTF8
21
22
22 # Copied from Python 3.2 tokenize
23 # Copied from Python 3.2 tokenize
23 def _get_normal_name(orig_enc):
24 def _get_normal_name(orig_enc):
24 """Imitates get_normal_name in tokenizer.c."""
25 """Imitates get_normal_name in tokenizer.c."""
25 # Only care about the first 12 characters.
26 # Only care about the first 12 characters.
26 enc = orig_enc[:12].lower().replace("_", "-")
27 enc = orig_enc[:12].lower().replace("_", "-")
27 if enc == "utf-8" or enc.startswith("utf-8-"):
28 if enc == "utf-8" or enc.startswith("utf-8-"):
28 return "utf-8"
29 return "utf-8"
29 if enc in ("latin-1", "iso-8859-1", "iso-latin-1") or \
30 if enc in ("latin-1", "iso-8859-1", "iso-latin-1") or \
30 enc.startswith(("latin-1-", "iso-8859-1-", "iso-latin-1-")):
31 enc.startswith(("latin-1-", "iso-8859-1-", "iso-latin-1-")):
31 return "iso-8859-1"
32 return "iso-8859-1"
32 return orig_enc
33 return orig_enc
33
34
34 # Copied from Python 3.2 tokenize
35 # Copied from Python 3.2 tokenize
35 def detect_encoding(readline):
36 def detect_encoding(readline):
36 """
37 """
37 The detect_encoding() function is used to detect the encoding that should
38 The detect_encoding() function is used to detect the encoding that should
38 be used to decode a Python source file. It requires one argment, readline,
39 be used to decode a Python source file. It requires one argment, readline,
39 in the same way as the tokenize() generator.
40 in the same way as the tokenize() generator.
40
41
41 It will call readline a maximum of twice, and return the encoding used
42 It will call readline a maximum of twice, and return the encoding used
42 (as a string) and a list of any lines (left as bytes) it has read in.
43 (as a string) and a list of any lines (left as bytes) it has read in.
43
44
44 It detects the encoding from the presence of a utf-8 bom or an encoding
45 It detects the encoding from the presence of a utf-8 bom or an encoding
45 cookie as specified in pep-0263. If both a bom and a cookie are present,
46 cookie as specified in pep-0263. If both a bom and a cookie are present,
46 but disagree, a SyntaxError will be raised. If the encoding cookie is an
47 but disagree, a SyntaxError will be raised. If the encoding cookie is an
47 invalid charset, raise a SyntaxError. Note that if a utf-8 bom is found,
48 invalid charset, raise a SyntaxError. Note that if a utf-8 bom is found,
48 'utf-8-sig' is returned.
49 'utf-8-sig' is returned.
49
50
50 If no encoding is specified, then the default of 'utf-8' will be returned.
51 If no encoding is specified, then the default of 'utf-8' will be returned.
51 """
52 """
52 bom_found = False
53 bom_found = False
53 encoding = None
54 encoding = None
54 default = 'utf-8'
55 default = 'utf-8'
55 def read_or_stop():
56 def read_or_stop():
56 try:
57 try:
57 return readline()
58 return readline()
58 except StopIteration:
59 except StopIteration:
59 return b''
60 return b''
60
61
61 def find_cookie(line):
62 def find_cookie(line):
62 try:
63 try:
63 line_string = line.decode('ascii')
64 line_string = line.decode('ascii')
64 except UnicodeDecodeError:
65 except UnicodeDecodeError:
65 return None
66 return None
66
67
67 matches = cookie_re.findall(line_string)
68 matches = cookie_re.findall(line_string)
68 if not matches:
69 if not matches:
69 return None
70 return None
70 encoding = _get_normal_name(matches[0])
71 encoding = _get_normal_name(matches[0])
71 try:
72 try:
72 codec = lookup(encoding)
73 codec = lookup(encoding)
73 except LookupError:
74 except LookupError:
74 # This behaviour mimics the Python interpreter
75 # This behaviour mimics the Python interpreter
75 raise SyntaxError("unknown encoding: " + encoding)
76 raise SyntaxError("unknown encoding: " + encoding)
76
77
77 if bom_found:
78 if bom_found:
78 if codec.name != 'utf-8':
79 if codec.name != 'utf-8':
79 # This behaviour mimics the Python interpreter
80 # This behaviour mimics the Python interpreter
80 raise SyntaxError('encoding problem: utf-8')
81 raise SyntaxError('encoding problem: utf-8')
81 encoding += '-sig'
82 encoding += '-sig'
82 return encoding
83 return encoding
83
84
84 first = read_or_stop()
85 first = read_or_stop()
85 if first.startswith(BOM_UTF8):
86 if first.startswith(BOM_UTF8):
86 bom_found = True
87 bom_found = True
87 first = first[3:]
88 first = first[3:]
88 default = 'utf-8-sig'
89 default = 'utf-8-sig'
89 if not first:
90 if not first:
90 return default, []
91 return default, []
91
92
92 encoding = find_cookie(first)
93 encoding = find_cookie(first)
93 if encoding:
94 if encoding:
94 return encoding, [first]
95 return encoding, [first]
95
96
96 second = read_or_stop()
97 second = read_or_stop()
97 if not second:
98 if not second:
98 return default, [first]
99 return default, [first]
99
100
100 encoding = find_cookie(second)
101 encoding = find_cookie(second)
101 if encoding:
102 if encoding:
102 return encoding, [first, second]
103 return encoding, [first, second]
103
104
104 return default, [first, second]
105 return default, [first, second]
105
106
106 try:
107 try:
107 # Available in Python 3.2 and above.
108 # Available in Python 3.2 and above.
108 from tokenize import open
109 from tokenize import open
109 except ImportError:
110 except ImportError:
110 # Copied from Python 3.2 tokenize
111 # Copied from Python 3.2 tokenize
111 def open(filename):
112 def open(filename):
112 """Open a file in read only mode using the encoding detected by
113 """Open a file in read only mode using the encoding detected by
113 detect_encoding().
114 detect_encoding().
114 """
115 """
115 buffer = io.open(filename, 'rb') # Tweaked to use io.open for Python 2
116 buffer = io.open(filename, 'rb') # Tweaked to use io.open for Python 2
116 encoding, lines = detect_encoding(buffer.readline)
117 encoding, lines = detect_encoding(buffer.readline)
117 buffer.seek(0)
118 buffer.seek(0)
118 text = TextIOWrapper(buffer, encoding, line_buffering=True)
119 text = TextIOWrapper(buffer, encoding, line_buffering=True)
119 text.mode = 'r'
120 text.mode = 'r'
120 return text
121 return text
121
122
122 def source_to_unicode(txt, errors='replace', skip_encoding_cookie=True):
123 def source_to_unicode(txt, errors='replace', skip_encoding_cookie=True):
123 """Converts a bytes string with python source code to unicode.
124 """Converts a bytes string with python source code to unicode.
124
125
125 Unicode strings are passed through unchanged. Byte strings are checked
126 Unicode strings are passed through unchanged. Byte strings are checked
126 for the python source file encoding cookie to determine encoding.
127 for the python source file encoding cookie to determine encoding.
127 txt can be either a bytes buffer or a string containing the source
128 txt can be either a bytes buffer or a string containing the source
128 code.
129 code.
129 """
130 """
130 if isinstance(txt, unicode):
131 if isinstance(txt, unicode):
131 return txt
132 return txt
132 if isinstance(txt, bytes):
133 if isinstance(txt, bytes):
133 buffer = BytesIO(txt)
134 buffer = BytesIO(txt)
134 else:
135 else:
135 buffer = txt
136 buffer = txt
136 try:
137 try:
137 encoding, _ = detect_encoding(buffer.readline)
138 encoding, _ = detect_encoding(buffer.readline)
138 except SyntaxError:
139 except SyntaxError:
139 encoding = "ascii"
140 encoding = "ascii"
140 buffer.seek(0)
141 buffer.seek(0)
141 text = TextIOWrapper(buffer, encoding, errors=errors, line_buffering=True)
142 text = TextIOWrapper(buffer, encoding, errors=errors, line_buffering=True)
142 text.mode = 'r'
143 text.mode = 'r'
143 if skip_encoding_cookie:
144 if skip_encoding_cookie:
144 return u"".join(strip_encoding_cookie(text))
145 return u"".join(strip_encoding_cookie(text))
145 else:
146 else:
146 return text.read()
147 return text.read()
147
148
148 def strip_encoding_cookie(filelike):
149 def strip_encoding_cookie(filelike):
149 """Generator to pull lines from a text-mode file, skipping the encoding
150 """Generator to pull lines from a text-mode file, skipping the encoding
150 cookie if it is found in the first two lines.
151 cookie if it is found in the first two lines.
151 """
152 """
152 it = iter(filelike)
153 it = iter(filelike)
153 try:
154 try:
154 first = next(it)
155 first = next(it)
155 if not cookie_comment_re.match(first):
156 if not cookie_comment_re.match(first):
156 yield first
157 yield first
157 second = next(it)
158 second = next(it)
158 if not cookie_comment_re.match(second):
159 if not cookie_comment_re.match(second):
159 yield second
160 yield second
160 except StopIteration:
161 except StopIteration:
161 return
162 return
162
163
163 for line in it:
164 for line in it:
164 yield line
165 yield line
165
166
166 def read_py_file(filename, skip_encoding_cookie=True):
167 def read_py_file(filename, skip_encoding_cookie=True):
167 """Read a Python file, using the encoding declared inside the file.
168 """Read a Python file, using the encoding declared inside the file.
168
169
169 Parameters
170 Parameters
170 ----------
171 ----------
171 filename : str
172 filename : str
172 The path to the file to read.
173 The path to the file to read.
173 skip_encoding_cookie : bool
174 skip_encoding_cookie : bool
174 If True (the default), and the encoding declaration is found in the first
175 If True (the default), and the encoding declaration is found in the first
175 two lines, that line will be excluded from the output - compiling a
176 two lines, that line will be excluded from the output - compiling a
176 unicode string with an encoding declaration is a SyntaxError in Python 2.
177 unicode string with an encoding declaration is a SyntaxError in Python 2.
177
178
178 Returns
179 Returns
179 -------
180 -------
180 A unicode string containing the contents of the file.
181 A unicode string containing the contents of the file.
181 """
182 """
182 with open(filename) as f: # the open function defined in this module.
183 with open(filename) as f: # the open function defined in this module.
183 if skip_encoding_cookie:
184 if skip_encoding_cookie:
184 return "".join(strip_encoding_cookie(f))
185 return "".join(strip_encoding_cookie(f))
185 else:
186 else:
186 return f.read()
187 return f.read()
187
188
188 def read_py_url(url, errors='replace', skip_encoding_cookie=True):
189 def read_py_url(url, errors='replace', skip_encoding_cookie=True):
189 """Read a Python file from a URL, using the encoding declared inside the file.
190 """Read a Python file from a URL, using the encoding declared inside the file.
190
191
191 Parameters
192 Parameters
192 ----------
193 ----------
193 url : str
194 url : str
194 The URL from which to fetch the file.
195 The URL from which to fetch the file.
195 errors : str
196 errors : str
196 How to handle decoding errors in the file. Options are the same as for
197 How to handle decoding errors in the file. Options are the same as for
197 bytes.decode(), but here 'replace' is the default.
198 bytes.decode(), but here 'replace' is the default.
198 skip_encoding_cookie : bool
199 skip_encoding_cookie : bool
199 If True (the default), and the encoding declaration is found in the first
200 If True (the default), and the encoding declaration is found in the first
200 two lines, that line will be excluded from the output - compiling a
201 two lines, that line will be excluded from the output - compiling a
201 unicode string with an encoding declaration is a SyntaxError in Python 2.
202 unicode string with an encoding declaration is a SyntaxError in Python 2.
202
203
203 Returns
204 Returns
204 -------
205 -------
205 A unicode string containing the contents of the file.
206 A unicode string containing the contents of the file.
206 """
207 """
207 from urllib import urlopen # Deferred import for faster start
208 from urllib import urlopen # Deferred import for faster start
208 response = urlopen(url)
209 response = urlopen(url)
209 buffer = io.BytesIO(response.read())
210 buffer = io.BytesIO(response.read())
210 return source_to_unicode(buffer, errors, skip_encoding_cookie)
211 return source_to_unicode(buffer, errors, skip_encoding_cookie)
211
212
212 def _list_readline(x):
213 def _list_readline(x):
213 """Given a list, returns a readline() function that returns the next element
214 """Given a list, returns a readline() function that returns the next element
214 with each call.
215 with each call.
215 """
216 """
216 x = iter(x)
217 x = iter(x)
217 def readline():
218 def readline():
218 return next(x)
219 return next(x)
219 return readline
220 return readline
221
222 # Code for going between .py files and cached .pyc files ----------------------
223
224 try: # Python 3.2, see PEP 3147
225 from imp import source_from_cache, cache_from_source
226 except ImportError:
227 # Python <= 3.1: .pyc files go next to .py
228 def source_from_cache(path):
229 basename, ext = os.path.splitext(path)
230 if ext not in ('.pyc', '.pyo'):
231 raise ValueError('Not a cached Python file extension', ext)
232 # Should we look for .pyw files?
233 return basename + '.py'
234
235 def cache_from_source(path, debug_override=None):
236 if debug_override is None:
237 debug_override = __debug__
238 basename, ext = os.path.splitext(path)
239 return basename + '.pyc' if debug_override else '.pyo'
@@ -1,824 +1,717 b''
1 # encoding: utf-8
1 # encoding: utf-8
2 """
2 """
3 Utilities for working with strings and text.
3 Utilities for working with strings and text.
4
4
5 Inheritance diagram:
5 Inheritance diagram:
6
6
7 .. inheritance-diagram:: IPython.utils.text
7 .. inheritance-diagram:: IPython.utils.text
8 :parts: 3
8 :parts: 3
9 """
9 """
10
10
11 #-----------------------------------------------------------------------------
11 #-----------------------------------------------------------------------------
12 # Copyright (C) 2008-2011 The IPython Development Team
12 # Copyright (C) 2008-2011 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 __main__
22 import __main__
23
23
24 import os
24 import os
25 import re
25 import re
26 import sys
26 import sys
27 import textwrap
27 import textwrap
28 from string import Formatter
28 from string import Formatter
29
29
30 from IPython.external.path import path
30 from IPython.external.path import path
31 from IPython.testing.skipdoctest import skip_doctest_py3, skip_doctest
31 from IPython.testing.skipdoctest import skip_doctest_py3, skip_doctest
32 from IPython.utils import py3compat
32 from IPython.utils import py3compat
33 from IPython.utils.io import nlprint
34 from IPython.utils.data import flatten
33 from IPython.utils.data import flatten
35
34
36 #-----------------------------------------------------------------------------
35 #-----------------------------------------------------------------------------
37 # Code
36 # Code
38 #-----------------------------------------------------------------------------
37 #-----------------------------------------------------------------------------
39
38
40 def unquote_ends(istr):
41 """Remove a single pair of quotes from the endpoints of a string."""
42
43 if not istr:
44 return istr
45 if (istr[0]=="'" and istr[-1]=="'") or \
46 (istr[0]=='"' and istr[-1]=='"'):
47 return istr[1:-1]
48 else:
49 return istr
50
51
52 class LSString(str):
39 class LSString(str):
53 """String derivative with a special access attributes.
40 """String derivative with a special access attributes.
54
41
55 These are normal strings, but with the special attributes:
42 These are normal strings, but with the special attributes:
56
43
57 .l (or .list) : value as list (split on newlines).
44 .l (or .list) : value as list (split on newlines).
58 .n (or .nlstr): original value (the string itself).
45 .n (or .nlstr): original value (the string itself).
59 .s (or .spstr): value as whitespace-separated string.
46 .s (or .spstr): value as whitespace-separated string.
60 .p (or .paths): list of path objects
47 .p (or .paths): list of path objects
61
48
62 Any values which require transformations are computed only once and
49 Any values which require transformations are computed only once and
63 cached.
50 cached.
64
51
65 Such strings are very useful to efficiently interact with the shell, which
52 Such strings are very useful to efficiently interact with the shell, which
66 typically only understands whitespace-separated options for commands."""
53 typically only understands whitespace-separated options for commands."""
67
54
68 def get_list(self):
55 def get_list(self):
69 try:
56 try:
70 return self.__list
57 return self.__list
71 except AttributeError:
58 except AttributeError:
72 self.__list = self.split('\n')
59 self.__list = self.split('\n')
73 return self.__list
60 return self.__list
74
61
75 l = list = property(get_list)
62 l = list = property(get_list)
76
63
77 def get_spstr(self):
64 def get_spstr(self):
78 try:
65 try:
79 return self.__spstr
66 return self.__spstr
80 except AttributeError:
67 except AttributeError:
81 self.__spstr = self.replace('\n',' ')
68 self.__spstr = self.replace('\n',' ')
82 return self.__spstr
69 return self.__spstr
83
70
84 s = spstr = property(get_spstr)
71 s = spstr = property(get_spstr)
85
72
86 def get_nlstr(self):
73 def get_nlstr(self):
87 return self
74 return self
88
75
89 n = nlstr = property(get_nlstr)
76 n = nlstr = property(get_nlstr)
90
77
91 def get_paths(self):
78 def get_paths(self):
92 try:
79 try:
93 return self.__paths
80 return self.__paths
94 except AttributeError:
81 except AttributeError:
95 self.__paths = [path(p) for p in self.split('\n') if os.path.exists(p)]
82 self.__paths = [path(p) for p in self.split('\n') if os.path.exists(p)]
96 return self.__paths
83 return self.__paths
97
84
98 p = paths = property(get_paths)
85 p = paths = property(get_paths)
99
86
100 # FIXME: We need to reimplement type specific displayhook and then add this
87 # FIXME: We need to reimplement type specific displayhook and then add this
101 # back as a custom printer. This should also be moved outside utils into the
88 # back as a custom printer. This should also be moved outside utils into the
102 # core.
89 # core.
103
90
104 # def print_lsstring(arg):
91 # def print_lsstring(arg):
105 # """ Prettier (non-repr-like) and more informative printer for LSString """
92 # """ Prettier (non-repr-like) and more informative printer for LSString """
106 # print "LSString (.p, .n, .l, .s available). Value:"
93 # print "LSString (.p, .n, .l, .s available). Value:"
107 # print arg
94 # print arg
108 #
95 #
109 #
96 #
110 # print_lsstring = result_display.when_type(LSString)(print_lsstring)
97 # print_lsstring = result_display.when_type(LSString)(print_lsstring)
111
98
112
99
113 class SList(list):
100 class SList(list):
114 """List derivative with a special access attributes.
101 """List derivative with a special access attributes.
115
102
116 These are normal lists, but with the special attributes:
103 These are normal lists, but with the special attributes:
117
104
118 .l (or .list) : value as list (the list itself).
105 .l (or .list) : value as list (the list itself).
119 .n (or .nlstr): value as a string, joined on newlines.
106 .n (or .nlstr): value as a string, joined on newlines.
120 .s (or .spstr): value as a string, joined on spaces.
107 .s (or .spstr): value as a string, joined on spaces.
121 .p (or .paths): list of path objects
108 .p (or .paths): list of path objects
122
109
123 Any values which require transformations are computed only once and
110 Any values which require transformations are computed only once and
124 cached."""
111 cached."""
125
112
126 def get_list(self):
113 def get_list(self):
127 return self
114 return self
128
115
129 l = list = property(get_list)
116 l = list = property(get_list)
130
117
131 def get_spstr(self):
118 def get_spstr(self):
132 try:
119 try:
133 return self.__spstr
120 return self.__spstr
134 except AttributeError:
121 except AttributeError:
135 self.__spstr = ' '.join(self)
122 self.__spstr = ' '.join(self)
136 return self.__spstr
123 return self.__spstr
137
124
138 s = spstr = property(get_spstr)
125 s = spstr = property(get_spstr)
139
126
140 def get_nlstr(self):
127 def get_nlstr(self):
141 try:
128 try:
142 return self.__nlstr
129 return self.__nlstr
143 except AttributeError:
130 except AttributeError:
144 self.__nlstr = '\n'.join(self)
131 self.__nlstr = '\n'.join(self)
145 return self.__nlstr
132 return self.__nlstr
146
133
147 n = nlstr = property(get_nlstr)
134 n = nlstr = property(get_nlstr)
148
135
149 def get_paths(self):
136 def get_paths(self):
150 try:
137 try:
151 return self.__paths
138 return self.__paths
152 except AttributeError:
139 except AttributeError:
153 self.__paths = [path(p) for p in self if os.path.exists(p)]
140 self.__paths = [path(p) for p in self if os.path.exists(p)]
154 return self.__paths
141 return self.__paths
155
142
156 p = paths = property(get_paths)
143 p = paths = property(get_paths)
157
144
158 def grep(self, pattern, prune = False, field = None):
145 def grep(self, pattern, prune = False, field = None):
159 """ Return all strings matching 'pattern' (a regex or callable)
146 """ Return all strings matching 'pattern' (a regex or callable)
160
147
161 This is case-insensitive. If prune is true, return all items
148 This is case-insensitive. If prune is true, return all items
162 NOT matching the pattern.
149 NOT matching the pattern.
163
150
164 If field is specified, the match must occur in the specified
151 If field is specified, the match must occur in the specified
165 whitespace-separated field.
152 whitespace-separated field.
166
153
167 Examples::
154 Examples::
168
155
169 a.grep( lambda x: x.startswith('C') )
156 a.grep( lambda x: x.startswith('C') )
170 a.grep('Cha.*log', prune=1)
157 a.grep('Cha.*log', prune=1)
171 a.grep('chm', field=-1)
158 a.grep('chm', field=-1)
172 """
159 """
173
160
174 def match_target(s):
161 def match_target(s):
175 if field is None:
162 if field is None:
176 return s
163 return s
177 parts = s.split()
164 parts = s.split()
178 try:
165 try:
179 tgt = parts[field]
166 tgt = parts[field]
180 return tgt
167 return tgt
181 except IndexError:
168 except IndexError:
182 return ""
169 return ""
183
170
184 if isinstance(pattern, basestring):
171 if isinstance(pattern, basestring):
185 pred = lambda x : re.search(pattern, x, re.IGNORECASE)
172 pred = lambda x : re.search(pattern, x, re.IGNORECASE)
186 else:
173 else:
187 pred = pattern
174 pred = pattern
188 if not prune:
175 if not prune:
189 return SList([el for el in self if pred(match_target(el))])
176 return SList([el for el in self if pred(match_target(el))])
190 else:
177 else:
191 return SList([el for el in self if not pred(match_target(el))])
178 return SList([el for el in self if not pred(match_target(el))])
192
179
193 def fields(self, *fields):
180 def fields(self, *fields):
194 """ Collect whitespace-separated fields from string list
181 """ Collect whitespace-separated fields from string list
195
182
196 Allows quick awk-like usage of string lists.
183 Allows quick awk-like usage of string lists.
197
184
198 Example data (in var a, created by 'a = !ls -l')::
185 Example data (in var a, created by 'a = !ls -l')::
199 -rwxrwxrwx 1 ville None 18 Dec 14 2006 ChangeLog
186 -rwxrwxrwx 1 ville None 18 Dec 14 2006 ChangeLog
200 drwxrwxrwx+ 6 ville None 0 Oct 24 18:05 IPython
187 drwxrwxrwx+ 6 ville None 0 Oct 24 18:05 IPython
201
188
202 a.fields(0) is ['-rwxrwxrwx', 'drwxrwxrwx+']
189 a.fields(0) is ['-rwxrwxrwx', 'drwxrwxrwx+']
203 a.fields(1,0) is ['1 -rwxrwxrwx', '6 drwxrwxrwx+']
190 a.fields(1,0) is ['1 -rwxrwxrwx', '6 drwxrwxrwx+']
204 (note the joining by space).
191 (note the joining by space).
205 a.fields(-1) is ['ChangeLog', 'IPython']
192 a.fields(-1) is ['ChangeLog', 'IPython']
206
193
207 IndexErrors are ignored.
194 IndexErrors are ignored.
208
195
209 Without args, fields() just split()'s the strings.
196 Without args, fields() just split()'s the strings.
210 """
197 """
211 if len(fields) == 0:
198 if len(fields) == 0:
212 return [el.split() for el in self]
199 return [el.split() for el in self]
213
200
214 res = SList()
201 res = SList()
215 for el in [f.split() for f in self]:
202 for el in [f.split() for f in self]:
216 lineparts = []
203 lineparts = []
217
204
218 for fd in fields:
205 for fd in fields:
219 try:
206 try:
220 lineparts.append(el[fd])
207 lineparts.append(el[fd])
221 except IndexError:
208 except IndexError:
222 pass
209 pass
223 if lineparts:
210 if lineparts:
224 res.append(" ".join(lineparts))
211 res.append(" ".join(lineparts))
225
212
226 return res
213 return res
227
214
228 def sort(self,field= None, nums = False):
215 def sort(self,field= None, nums = False):
229 """ sort by specified fields (see fields())
216 """ sort by specified fields (see fields())
230
217
231 Example::
218 Example::
232 a.sort(1, nums = True)
219 a.sort(1, nums = True)
233
220
234 Sorts a by second field, in numerical order (so that 21 > 3)
221 Sorts a by second field, in numerical order (so that 21 > 3)
235
222
236 """
223 """
237
224
238 #decorate, sort, undecorate
225 #decorate, sort, undecorate
239 if field is not None:
226 if field is not None:
240 dsu = [[SList([line]).fields(field), line] for line in self]
227 dsu = [[SList([line]).fields(field), line] for line in self]
241 else:
228 else:
242 dsu = [[line, line] for line in self]
229 dsu = [[line, line] for line in self]
243 if nums:
230 if nums:
244 for i in range(len(dsu)):
231 for i in range(len(dsu)):
245 numstr = "".join([ch for ch in dsu[i][0] if ch.isdigit()])
232 numstr = "".join([ch for ch in dsu[i][0] if ch.isdigit()])
246 try:
233 try:
247 n = int(numstr)
234 n = int(numstr)
248 except ValueError:
235 except ValueError:
249 n = 0;
236 n = 0;
250 dsu[i][0] = n
237 dsu[i][0] = n
251
238
252
239
253 dsu.sort()
240 dsu.sort()
254 return SList([t[1] for t in dsu])
241 return SList([t[1] for t in dsu])
255
242
256
243
257 # FIXME: We need to reimplement type specific displayhook and then add this
244 # FIXME: We need to reimplement type specific displayhook and then add this
258 # back as a custom printer. This should also be moved outside utils into the
245 # back as a custom printer. This should also be moved outside utils into the
259 # core.
246 # core.
260
247
261 # def print_slist(arg):
248 # def print_slist(arg):
262 # """ Prettier (non-repr-like) and more informative printer for SList """
249 # """ Prettier (non-repr-like) and more informative printer for SList """
263 # print "SList (.p, .n, .l, .s, .grep(), .fields(), sort() available):"
250 # print "SList (.p, .n, .l, .s, .grep(), .fields(), sort() available):"
264 # if hasattr(arg, 'hideonce') and arg.hideonce:
251 # if hasattr(arg, 'hideonce') and arg.hideonce:
265 # arg.hideonce = False
252 # arg.hideonce = False
266 # return
253 # return
267 #
254 #
268 # nlprint(arg)
255 # nlprint(arg) # This was a nested list printer, now removed.
269 #
256 #
270 # print_slist = result_display.when_type(SList)(print_slist)
257 # print_slist = result_display.when_type(SList)(print_slist)
271
258
272
259
273 def esc_quotes(strng):
274 """Return the input string with single and double quotes escaped out"""
275
276 return strng.replace('"','\\"').replace("'","\\'")
277
278
279 def qw(words,flat=0,sep=None,maxsplit=-1):
280 """Similar to Perl's qw() operator, but with some more options.
281
282 qw(words,flat=0,sep=' ',maxsplit=-1) -> words.split(sep,maxsplit)
283
284 words can also be a list itself, and with flat=1, the output will be
285 recursively flattened.
286
287 Examples:
288
289 >>> qw('1 2')
290 ['1', '2']
291
292 >>> qw(['a b','1 2',['m n','p q']])
293 [['a', 'b'], ['1', '2'], [['m', 'n'], ['p', 'q']]]
294
295 >>> qw(['a b','1 2',['m n','p q']],flat=1)
296 ['a', 'b', '1', '2', 'm', 'n', 'p', 'q']
297 """
298
299 if isinstance(words, basestring):
300 return [word.strip() for word in words.split(sep,maxsplit)
301 if word and not word.isspace() ]
302 if flat:
303 return flatten(map(qw,words,[1]*len(words)))
304 return map(qw,words)
305
306
307 def qwflat(words,sep=None,maxsplit=-1):
308 """Calls qw(words) in flat mode. It's just a convenient shorthand."""
309 return qw(words,1,sep,maxsplit)
310
311
312 def qw_lol(indata):
313 """qw_lol('a b') -> [['a','b']],
314 otherwise it's just a call to qw().
315
316 We need this to make sure the modules_some keys *always* end up as a
317 list of lists."""
318
319 if isinstance(indata, basestring):
320 return [qw(indata)]
321 else:
322 return qw(indata)
323
324
325 def grep(pat,list,case=1):
326 """Simple minded grep-like function.
327 grep(pat,list) returns occurrences of pat in list, None on failure.
328
329 It only does simple string matching, with no support for regexps. Use the
330 option case=0 for case-insensitive matching."""
331
332 # This is pretty crude. At least it should implement copying only references
333 # to the original data in case it's big. Now it copies the data for output.
334 out=[]
335 if case:
336 for term in list:
337 if term.find(pat)>-1: out.append(term)
338 else:
339 lpat=pat.lower()
340 for term in list:
341 if term.lower().find(lpat)>-1: out.append(term)
342
343 if len(out): return out
344 else: return None
345
346
347 def dgrep(pat,*opts):
348 """Return grep() on dir()+dir(__builtins__).
349
350 A very common use of grep() when working interactively."""
351
352 return grep(pat,dir(__main__)+dir(__main__.__builtins__),*opts)
353
354
355 def idgrep(pat):
356 """Case-insensitive dgrep()"""
357
358 return dgrep(pat,0)
359
360
361 def igrep(pat,list):
362 """Synonym for case-insensitive grep."""
363
364 return grep(pat,list,case=0)
365
366
367 def indent(instr,nspaces=4, ntabs=0, flatten=False):
260 def indent(instr,nspaces=4, ntabs=0, flatten=False):
368 """Indent a string a given number of spaces or tabstops.
261 """Indent a string a given number of spaces or tabstops.
369
262
370 indent(str,nspaces=4,ntabs=0) -> indent str by ntabs+nspaces.
263 indent(str,nspaces=4,ntabs=0) -> indent str by ntabs+nspaces.
371
264
372 Parameters
265 Parameters
373 ----------
266 ----------
374
267
375 instr : basestring
268 instr : basestring
376 The string to be indented.
269 The string to be indented.
377 nspaces : int (default: 4)
270 nspaces : int (default: 4)
378 The number of spaces to be indented.
271 The number of spaces to be indented.
379 ntabs : int (default: 0)
272 ntabs : int (default: 0)
380 The number of tabs to be indented.
273 The number of tabs to be indented.
381 flatten : bool (default: False)
274 flatten : bool (default: False)
382 Whether to scrub existing indentation. If True, all lines will be
275 Whether to scrub existing indentation. If True, all lines will be
383 aligned to the same indentation. If False, existing indentation will
276 aligned to the same indentation. If False, existing indentation will
384 be strictly increased.
277 be strictly increased.
385
278
386 Returns
279 Returns
387 -------
280 -------
388
281
389 str|unicode : string indented by ntabs and nspaces.
282 str|unicode : string indented by ntabs and nspaces.
390
283
391 """
284 """
392 if instr is None:
285 if instr is None:
393 return
286 return
394 ind = '\t'*ntabs+' '*nspaces
287 ind = '\t'*ntabs+' '*nspaces
395 if flatten:
288 if flatten:
396 pat = re.compile(r'^\s*', re.MULTILINE)
289 pat = re.compile(r'^\s*', re.MULTILINE)
397 else:
290 else:
398 pat = re.compile(r'^', re.MULTILINE)
291 pat = re.compile(r'^', re.MULTILINE)
399 outstr = re.sub(pat, ind, instr)
292 outstr = re.sub(pat, ind, instr)
400 if outstr.endswith(os.linesep+ind):
293 if outstr.endswith(os.linesep+ind):
401 return outstr[:-len(ind)]
294 return outstr[:-len(ind)]
402 else:
295 else:
403 return outstr
296 return outstr
404
297
405
298
406 def list_strings(arg):
299 def list_strings(arg):
407 """Always return a list of strings, given a string or list of strings
300 """Always return a list of strings, given a string or list of strings
408 as input.
301 as input.
409
302
410 :Examples:
303 :Examples:
411
304
412 In [7]: list_strings('A single string')
305 In [7]: list_strings('A single string')
413 Out[7]: ['A single string']
306 Out[7]: ['A single string']
414
307
415 In [8]: list_strings(['A single string in a list'])
308 In [8]: list_strings(['A single string in a list'])
416 Out[8]: ['A single string in a list']
309 Out[8]: ['A single string in a list']
417
310
418 In [9]: list_strings(['A','list','of','strings'])
311 In [9]: list_strings(['A','list','of','strings'])
419 Out[9]: ['A', 'list', 'of', 'strings']
312 Out[9]: ['A', 'list', 'of', 'strings']
420 """
313 """
421
314
422 if isinstance(arg,basestring): return [arg]
315 if isinstance(arg,basestring): return [arg]
423 else: return arg
316 else: return arg
424
317
425
318
426 def marquee(txt='',width=78,mark='*'):
319 def marquee(txt='',width=78,mark='*'):
427 """Return the input string centered in a 'marquee'.
320 """Return the input string centered in a 'marquee'.
428
321
429 :Examples:
322 :Examples:
430
323
431 In [16]: marquee('A test',40)
324 In [16]: marquee('A test',40)
432 Out[16]: '**************** A test ****************'
325 Out[16]: '**************** A test ****************'
433
326
434 In [17]: marquee('A test',40,'-')
327 In [17]: marquee('A test',40,'-')
435 Out[17]: '---------------- A test ----------------'
328 Out[17]: '---------------- A test ----------------'
436
329
437 In [18]: marquee('A test',40,' ')
330 In [18]: marquee('A test',40,' ')
438 Out[18]: ' A test '
331 Out[18]: ' A test '
439
332
440 """
333 """
441 if not txt:
334 if not txt:
442 return (mark*width)[:width]
335 return (mark*width)[:width]
443 nmark = (width-len(txt)-2)//len(mark)//2
336 nmark = (width-len(txt)-2)//len(mark)//2
444 if nmark < 0: nmark =0
337 if nmark < 0: nmark =0
445 marks = mark*nmark
338 marks = mark*nmark
446 return '%s %s %s' % (marks,txt,marks)
339 return '%s %s %s' % (marks,txt,marks)
447
340
448
341
449 ini_spaces_re = re.compile(r'^(\s+)')
342 ini_spaces_re = re.compile(r'^(\s+)')
450
343
451 def num_ini_spaces(strng):
344 def num_ini_spaces(strng):
452 """Return the number of initial spaces in a string"""
345 """Return the number of initial spaces in a string"""
453
346
454 ini_spaces = ini_spaces_re.match(strng)
347 ini_spaces = ini_spaces_re.match(strng)
455 if ini_spaces:
348 if ini_spaces:
456 return ini_spaces.end()
349 return ini_spaces.end()
457 else:
350 else:
458 return 0
351 return 0
459
352
460
353
461 def format_screen(strng):
354 def format_screen(strng):
462 """Format a string for screen printing.
355 """Format a string for screen printing.
463
356
464 This removes some latex-type format codes."""
357 This removes some latex-type format codes."""
465 # Paragraph continue
358 # Paragraph continue
466 par_re = re.compile(r'\\$',re.MULTILINE)
359 par_re = re.compile(r'\\$',re.MULTILINE)
467 strng = par_re.sub('',strng)
360 strng = par_re.sub('',strng)
468 return strng
361 return strng
469
362
470
363
471 def dedent(text):
364 def dedent(text):
472 """Equivalent of textwrap.dedent that ignores unindented first line.
365 """Equivalent of textwrap.dedent that ignores unindented first line.
473
366
474 This means it will still dedent strings like:
367 This means it will still dedent strings like:
475 '''foo
368 '''foo
476 is a bar
369 is a bar
477 '''
370 '''
478
371
479 For use in wrap_paragraphs.
372 For use in wrap_paragraphs.
480 """
373 """
481
374
482 if text.startswith('\n'):
375 if text.startswith('\n'):
483 # text starts with blank line, don't ignore the first line
376 # text starts with blank line, don't ignore the first line
484 return textwrap.dedent(text)
377 return textwrap.dedent(text)
485
378
486 # split first line
379 # split first line
487 splits = text.split('\n',1)
380 splits = text.split('\n',1)
488 if len(splits) == 1:
381 if len(splits) == 1:
489 # only one line
382 # only one line
490 return textwrap.dedent(text)
383 return textwrap.dedent(text)
491
384
492 first, rest = splits
385 first, rest = splits
493 # dedent everything but the first line
386 # dedent everything but the first line
494 rest = textwrap.dedent(rest)
387 rest = textwrap.dedent(rest)
495 return '\n'.join([first, rest])
388 return '\n'.join([first, rest])
496
389
497
390
498 def wrap_paragraphs(text, ncols=80):
391 def wrap_paragraphs(text, ncols=80):
499 """Wrap multiple paragraphs to fit a specified width.
392 """Wrap multiple paragraphs to fit a specified width.
500
393
501 This is equivalent to textwrap.wrap, but with support for multiple
394 This is equivalent to textwrap.wrap, but with support for multiple
502 paragraphs, as separated by empty lines.
395 paragraphs, as separated by empty lines.
503
396
504 Returns
397 Returns
505 -------
398 -------
506
399
507 list of complete paragraphs, wrapped to fill `ncols` columns.
400 list of complete paragraphs, wrapped to fill `ncols` columns.
508 """
401 """
509 paragraph_re = re.compile(r'\n(\s*\n)+', re.MULTILINE)
402 paragraph_re = re.compile(r'\n(\s*\n)+', re.MULTILINE)
510 text = dedent(text).strip()
403 text = dedent(text).strip()
511 paragraphs = paragraph_re.split(text)[::2] # every other entry is space
404 paragraphs = paragraph_re.split(text)[::2] # every other entry is space
512 out_ps = []
405 out_ps = []
513 indent_re = re.compile(r'\n\s+', re.MULTILINE)
406 indent_re = re.compile(r'\n\s+', re.MULTILINE)
514 for p in paragraphs:
407 for p in paragraphs:
515 # presume indentation that survives dedent is meaningful formatting,
408 # presume indentation that survives dedent is meaningful formatting,
516 # so don't fill unless text is flush.
409 # so don't fill unless text is flush.
517 if indent_re.search(p) is None:
410 if indent_re.search(p) is None:
518 # wrap paragraph
411 # wrap paragraph
519 p = textwrap.fill(p, ncols)
412 p = textwrap.fill(p, ncols)
520 out_ps.append(p)
413 out_ps.append(p)
521 return out_ps
414 return out_ps
522
415
523
416
524 def long_substr(data):
417 def long_substr(data):
525 """Return the longest common substring in a list of strings.
418 """Return the longest common substring in a list of strings.
526
419
527 Credit: http://stackoverflow.com/questions/2892931/longest-common-substring-from-more-than-two-strings-python
420 Credit: http://stackoverflow.com/questions/2892931/longest-common-substring-from-more-than-two-strings-python
528 """
421 """
529 substr = ''
422 substr = ''
530 if len(data) > 1 and len(data[0]) > 0:
423 if len(data) > 1 and len(data[0]) > 0:
531 for i in range(len(data[0])):
424 for i in range(len(data[0])):
532 for j in range(len(data[0])-i+1):
425 for j in range(len(data[0])-i+1):
533 if j > len(substr) and all(data[0][i:i+j] in x for x in data):
426 if j > len(substr) and all(data[0][i:i+j] in x for x in data):
534 substr = data[0][i:i+j]
427 substr = data[0][i:i+j]
535 elif len(data) == 1:
428 elif len(data) == 1:
536 substr = data[0]
429 substr = data[0]
537 return substr
430 return substr
538
431
539
432
540 def strip_email_quotes(text):
433 def strip_email_quotes(text):
541 """Strip leading email quotation characters ('>').
434 """Strip leading email quotation characters ('>').
542
435
543 Removes any combination of leading '>' interspersed with whitespace that
436 Removes any combination of leading '>' interspersed with whitespace that
544 appears *identically* in all lines of the input text.
437 appears *identically* in all lines of the input text.
545
438
546 Parameters
439 Parameters
547 ----------
440 ----------
548 text : str
441 text : str
549
442
550 Examples
443 Examples
551 --------
444 --------
552
445
553 Simple uses::
446 Simple uses::
554
447
555 In [2]: strip_email_quotes('> > text')
448 In [2]: strip_email_quotes('> > text')
556 Out[2]: 'text'
449 Out[2]: 'text'
557
450
558 In [3]: strip_email_quotes('> > text\\n> > more')
451 In [3]: strip_email_quotes('> > text\\n> > more')
559 Out[3]: 'text\\nmore'
452 Out[3]: 'text\\nmore'
560
453
561 Note how only the common prefix that appears in all lines is stripped::
454 Note how only the common prefix that appears in all lines is stripped::
562
455
563 In [4]: strip_email_quotes('> > text\\n> > more\\n> more...')
456 In [4]: strip_email_quotes('> > text\\n> > more\\n> more...')
564 Out[4]: '> text\\n> more\\nmore...'
457 Out[4]: '> text\\n> more\\nmore...'
565
458
566 So if any line has no quote marks ('>') , then none are stripped from any
459 So if any line has no quote marks ('>') , then none are stripped from any
567 of them ::
460 of them ::
568
461
569 In [5]: strip_email_quotes('> > text\\n> > more\\nlast different')
462 In [5]: strip_email_quotes('> > text\\n> > more\\nlast different')
570 Out[5]: '> > text\\n> > more\\nlast different'
463 Out[5]: '> > text\\n> > more\\nlast different'
571 """
464 """
572 lines = text.splitlines()
465 lines = text.splitlines()
573 matches = set()
466 matches = set()
574 for line in lines:
467 for line in lines:
575 prefix = re.match(r'^(\s*>[ >]*)', line)
468 prefix = re.match(r'^(\s*>[ >]*)', line)
576 if prefix:
469 if prefix:
577 matches.add(prefix.group(1))
470 matches.add(prefix.group(1))
578 else:
471 else:
579 break
472 break
580 else:
473 else:
581 prefix = long_substr(list(matches))
474 prefix = long_substr(list(matches))
582 if prefix:
475 if prefix:
583 strip = len(prefix)
476 strip = len(prefix)
584 text = '\n'.join([ ln[strip:] for ln in lines])
477 text = '\n'.join([ ln[strip:] for ln in lines])
585 return text
478 return text
586
479
587
480
588 class EvalFormatter(Formatter):
481 class EvalFormatter(Formatter):
589 """A String Formatter that allows evaluation of simple expressions.
482 """A String Formatter that allows evaluation of simple expressions.
590
483
591 Note that this version interprets a : as specifying a format string (as per
484 Note that this version interprets a : as specifying a format string (as per
592 standard string formatting), so if slicing is required, you must explicitly
485 standard string formatting), so if slicing is required, you must explicitly
593 create a slice.
486 create a slice.
594
487
595 This is to be used in templating cases, such as the parallel batch
488 This is to be used in templating cases, such as the parallel batch
596 script templates, where simple arithmetic on arguments is useful.
489 script templates, where simple arithmetic on arguments is useful.
597
490
598 Examples
491 Examples
599 --------
492 --------
600
493
601 In [1]: f = EvalFormatter()
494 In [1]: f = EvalFormatter()
602 In [2]: f.format('{n//4}', n=8)
495 In [2]: f.format('{n//4}', n=8)
603 Out [2]: '2'
496 Out [2]: '2'
604
497
605 In [3]: f.format("{greeting[slice(2,4)]}", greeting="Hello")
498 In [3]: f.format("{greeting[slice(2,4)]}", greeting="Hello")
606 Out [3]: 'll'
499 Out [3]: 'll'
607 """
500 """
608 def get_field(self, name, args, kwargs):
501 def get_field(self, name, args, kwargs):
609 v = eval(name, kwargs)
502 v = eval(name, kwargs)
610 return v, name
503 return v, name
611
504
612
505
613 @skip_doctest_py3
506 @skip_doctest_py3
614 class FullEvalFormatter(Formatter):
507 class FullEvalFormatter(Formatter):
615 """A String Formatter that allows evaluation of simple expressions.
508 """A String Formatter that allows evaluation of simple expressions.
616
509
617 Any time a format key is not found in the kwargs,
510 Any time a format key is not found in the kwargs,
618 it will be tried as an expression in the kwargs namespace.
511 it will be tried as an expression in the kwargs namespace.
619
512
620 Note that this version allows slicing using [1:2], so you cannot specify
513 Note that this version allows slicing using [1:2], so you cannot specify
621 a format string. Use :class:`EvalFormatter` to permit format strings.
514 a format string. Use :class:`EvalFormatter` to permit format strings.
622
515
623 Examples
516 Examples
624 --------
517 --------
625
518
626 In [1]: f = FullEvalFormatter()
519 In [1]: f = FullEvalFormatter()
627 In [2]: f.format('{n//4}', n=8)
520 In [2]: f.format('{n//4}', n=8)
628 Out[2]: u'2'
521 Out[2]: u'2'
629
522
630 In [3]: f.format('{list(range(5))[2:4]}')
523 In [3]: f.format('{list(range(5))[2:4]}')
631 Out[3]: u'[2, 3]'
524 Out[3]: u'[2, 3]'
632
525
633 In [4]: f.format('{3*2}')
526 In [4]: f.format('{3*2}')
634 Out[4]: u'6'
527 Out[4]: u'6'
635 """
528 """
636 # copied from Formatter._vformat with minor changes to allow eval
529 # copied from Formatter._vformat with minor changes to allow eval
637 # and replace the format_spec code with slicing
530 # and replace the format_spec code with slicing
638 def _vformat(self, format_string, args, kwargs, used_args, recursion_depth):
531 def _vformat(self, format_string, args, kwargs, used_args, recursion_depth):
639 if recursion_depth < 0:
532 if recursion_depth < 0:
640 raise ValueError('Max string recursion exceeded')
533 raise ValueError('Max string recursion exceeded')
641 result = []
534 result = []
642 for literal_text, field_name, format_spec, conversion in \
535 for literal_text, field_name, format_spec, conversion in \
643 self.parse(format_string):
536 self.parse(format_string):
644
537
645 # output the literal text
538 # output the literal text
646 if literal_text:
539 if literal_text:
647 result.append(literal_text)
540 result.append(literal_text)
648
541
649 # if there's a field, output it
542 # if there's a field, output it
650 if field_name is not None:
543 if field_name is not None:
651 # this is some markup, find the object and do
544 # this is some markup, find the object and do
652 # the formatting
545 # the formatting
653
546
654 if format_spec:
547 if format_spec:
655 # override format spec, to allow slicing:
548 # override format spec, to allow slicing:
656 field_name = ':'.join([field_name, format_spec])
549 field_name = ':'.join([field_name, format_spec])
657
550
658 # eval the contents of the field for the object
551 # eval the contents of the field for the object
659 # to be formatted
552 # to be formatted
660 obj = eval(field_name, kwargs)
553 obj = eval(field_name, kwargs)
661
554
662 # do any conversion on the resulting object
555 # do any conversion on the resulting object
663 obj = self.convert_field(obj, conversion)
556 obj = self.convert_field(obj, conversion)
664
557
665 # format the object and append to the result
558 # format the object and append to the result
666 result.append(self.format_field(obj, ''))
559 result.append(self.format_field(obj, ''))
667
560
668 return u''.join(py3compat.cast_unicode(s) for s in result)
561 return u''.join(py3compat.cast_unicode(s) for s in result)
669
562
670
563
671 @skip_doctest_py3
564 @skip_doctest_py3
672 class DollarFormatter(FullEvalFormatter):
565 class DollarFormatter(FullEvalFormatter):
673 """Formatter allowing Itpl style $foo replacement, for names and attribute
566 """Formatter allowing Itpl style $foo replacement, for names and attribute
674 access only. Standard {foo} replacement also works, and allows full
567 access only. Standard {foo} replacement also works, and allows full
675 evaluation of its arguments.
568 evaluation of its arguments.
676
569
677 Examples
570 Examples
678 --------
571 --------
679 In [1]: f = DollarFormatter()
572 In [1]: f = DollarFormatter()
680 In [2]: f.format('{n//4}', n=8)
573 In [2]: f.format('{n//4}', n=8)
681 Out[2]: u'2'
574 Out[2]: u'2'
682
575
683 In [3]: f.format('23 * 76 is $result', result=23*76)
576 In [3]: f.format('23 * 76 is $result', result=23*76)
684 Out[3]: u'23 * 76 is 1748'
577 Out[3]: u'23 * 76 is 1748'
685
578
686 In [4]: f.format('$a or {b}', a=1, b=2)
579 In [4]: f.format('$a or {b}', a=1, b=2)
687 Out[4]: u'1 or 2'
580 Out[4]: u'1 or 2'
688 """
581 """
689 _dollar_pattern = re.compile("(.*?)\$(\$?[\w\.]+)")
582 _dollar_pattern = re.compile("(.*?)\$(\$?[\w\.]+)")
690 def parse(self, fmt_string):
583 def parse(self, fmt_string):
691 for literal_txt, field_name, format_spec, conversion \
584 for literal_txt, field_name, format_spec, conversion \
692 in Formatter.parse(self, fmt_string):
585 in Formatter.parse(self, fmt_string):
693
586
694 # Find $foo patterns in the literal text.
587 # Find $foo patterns in the literal text.
695 continue_from = 0
588 continue_from = 0
696 txt = ""
589 txt = ""
697 for m in self._dollar_pattern.finditer(literal_txt):
590 for m in self._dollar_pattern.finditer(literal_txt):
698 new_txt, new_field = m.group(1,2)
591 new_txt, new_field = m.group(1,2)
699 # $$foo --> $foo
592 # $$foo --> $foo
700 if new_field.startswith("$"):
593 if new_field.startswith("$"):
701 txt += new_txt + new_field
594 txt += new_txt + new_field
702 else:
595 else:
703 yield (txt + new_txt, new_field, "", None)
596 yield (txt + new_txt, new_field, "", None)
704 txt = ""
597 txt = ""
705 continue_from = m.end()
598 continue_from = m.end()
706
599
707 # Re-yield the {foo} style pattern
600 # Re-yield the {foo} style pattern
708 yield (txt + literal_txt[continue_from:], field_name, format_spec, conversion)
601 yield (txt + literal_txt[continue_from:], field_name, format_spec, conversion)
709
602
710 #-----------------------------------------------------------------------------
603 #-----------------------------------------------------------------------------
711 # Utils to columnize a list of string
604 # Utils to columnize a list of string
712 #-----------------------------------------------------------------------------
605 #-----------------------------------------------------------------------------
713
606
714 def _chunks(l, n):
607 def _chunks(l, n):
715 """Yield successive n-sized chunks from l."""
608 """Yield successive n-sized chunks from l."""
716 for i in xrange(0, len(l), n):
609 for i in xrange(0, len(l), n):
717 yield l[i:i+n]
610 yield l[i:i+n]
718
611
719
612
720 def _find_optimal(rlist , separator_size=2 , displaywidth=80):
613 def _find_optimal(rlist , separator_size=2 , displaywidth=80):
721 """Calculate optimal info to columnize a list of string"""
614 """Calculate optimal info to columnize a list of string"""
722 for nrow in range(1, len(rlist)+1) :
615 for nrow in range(1, len(rlist)+1) :
723 chk = map(max,_chunks(rlist, nrow))
616 chk = map(max,_chunks(rlist, nrow))
724 sumlength = sum(chk)
617 sumlength = sum(chk)
725 ncols = len(chk)
618 ncols = len(chk)
726 if sumlength+separator_size*(ncols-1) <= displaywidth :
619 if sumlength+separator_size*(ncols-1) <= displaywidth :
727 break;
620 break;
728 return {'columns_numbers' : ncols,
621 return {'columns_numbers' : ncols,
729 'optimal_separator_width':(displaywidth - sumlength)/(ncols-1) if (ncols -1) else 0,
622 'optimal_separator_width':(displaywidth - sumlength)/(ncols-1) if (ncols -1) else 0,
730 'rows_numbers' : nrow,
623 'rows_numbers' : nrow,
731 'columns_width' : chk
624 'columns_width' : chk
732 }
625 }
733
626
734
627
735 def _get_or_default(mylist, i, default=None):
628 def _get_or_default(mylist, i, default=None):
736 """return list item number, or default if don't exist"""
629 """return list item number, or default if don't exist"""
737 if i >= len(mylist):
630 if i >= len(mylist):
738 return default
631 return default
739 else :
632 else :
740 return mylist[i]
633 return mylist[i]
741
634
742
635
743 @skip_doctest
636 @skip_doctest
744 def compute_item_matrix(items, empty=None, *args, **kwargs) :
637 def compute_item_matrix(items, empty=None, *args, **kwargs) :
745 """Returns a nested list, and info to columnize items
638 """Returns a nested list, and info to columnize items
746
639
747 Parameters
640 Parameters
748 ----------
641 ----------
749
642
750 items :
643 items :
751 list of strings to columize
644 list of strings to columize
752 empty : (default None)
645 empty : (default None)
753 default value to fill list if needed
646 default value to fill list if needed
754 separator_size : int (default=2)
647 separator_size : int (default=2)
755 How much caracters will be used as a separation between each columns.
648 How much caracters will be used as a separation between each columns.
756 displaywidth : int (default=80)
649 displaywidth : int (default=80)
757 The width of the area onto wich the columns should enter
650 The width of the area onto wich the columns should enter
758
651
759 Returns
652 Returns
760 -------
653 -------
761
654
762 Returns a tuple of (strings_matrix, dict_info)
655 Returns a tuple of (strings_matrix, dict_info)
763
656
764 strings_matrix :
657 strings_matrix :
765
658
766 nested list of string, the outer most list contains as many list as
659 nested list of string, the outer most list contains as many list as
767 rows, the innermost lists have each as many element as colums. If the
660 rows, the innermost lists have each as many element as colums. If the
768 total number of elements in `items` does not equal the product of
661 total number of elements in `items` does not equal the product of
769 rows*columns, the last element of some lists are filled with `None`.
662 rows*columns, the last element of some lists are filled with `None`.
770
663
771 dict_info :
664 dict_info :
772 some info to make columnize easier:
665 some info to make columnize easier:
773
666
774 columns_numbers : number of columns
667 columns_numbers : number of columns
775 rows_numbers : number of rows
668 rows_numbers : number of rows
776 columns_width : list of with of each columns
669 columns_width : list of with of each columns
777 optimal_separator_width : best separator width between columns
670 optimal_separator_width : best separator width between columns
778
671
779 Examples
672 Examples
780 --------
673 --------
781
674
782 In [1]: l = ['aaa','b','cc','d','eeeee','f','g','h','i','j','k','l']
675 In [1]: l = ['aaa','b','cc','d','eeeee','f','g','h','i','j','k','l']
783 ...: compute_item_matrix(l,displaywidth=12)
676 ...: compute_item_matrix(l,displaywidth=12)
784 Out[1]:
677 Out[1]:
785 ([['aaa', 'f', 'k'],
678 ([['aaa', 'f', 'k'],
786 ['b', 'g', 'l'],
679 ['b', 'g', 'l'],
787 ['cc', 'h', None],
680 ['cc', 'h', None],
788 ['d', 'i', None],
681 ['d', 'i', None],
789 ['eeeee', 'j', None]],
682 ['eeeee', 'j', None]],
790 {'columns_numbers': 3,
683 {'columns_numbers': 3,
791 'columns_width': [5, 1, 1],
684 'columns_width': [5, 1, 1],
792 'optimal_separator_width': 2,
685 'optimal_separator_width': 2,
793 'rows_numbers': 5})
686 'rows_numbers': 5})
794
687
795 """
688 """
796 info = _find_optimal(map(len, items), *args, **kwargs)
689 info = _find_optimal(map(len, items), *args, **kwargs)
797 nrow, ncol = info['rows_numbers'], info['columns_numbers']
690 nrow, ncol = info['rows_numbers'], info['columns_numbers']
798 return ([[ _get_or_default(items, c*nrow+i, default=empty) for c in range(ncol) ] for i in range(nrow) ], info)
691 return ([[ _get_or_default(items, c*nrow+i, default=empty) for c in range(ncol) ] for i in range(nrow) ], info)
799
692
800
693
801 def columnize(items, separator=' ', displaywidth=80):
694 def columnize(items, separator=' ', displaywidth=80):
802 """ Transform a list of strings into a single string with columns.
695 """ Transform a list of strings into a single string with columns.
803
696
804 Parameters
697 Parameters
805 ----------
698 ----------
806 items : sequence of strings
699 items : sequence of strings
807 The strings to process.
700 The strings to process.
808
701
809 separator : str, optional [default is two spaces]
702 separator : str, optional [default is two spaces]
810 The string that separates columns.
703 The string that separates columns.
811
704
812 displaywidth : int, optional [default is 80]
705 displaywidth : int, optional [default is 80]
813 Width of the display in number of characters.
706 Width of the display in number of characters.
814
707
815 Returns
708 Returns
816 -------
709 -------
817 The formatted string.
710 The formatted string.
818 """
711 """
819 if not items :
712 if not items :
820 return '\n'
713 return '\n'
821 matrix, info = compute_item_matrix(items, separator_size=len(separator), displaywidth=displaywidth)
714 matrix, info = compute_item_matrix(items, separator_size=len(separator), displaywidth=displaywidth)
822 fmatrix = [filter(None, x) for x in matrix]
715 fmatrix = [filter(None, x) for x in matrix]
823 sjoin = lambda x : separator.join([ y.ljust(w, ' ') for y, w in zip(x, info['columns_width'])])
716 sjoin = lambda x : separator.join([ y.ljust(w, ' ') for y, w in zip(x, info['columns_width'])])
824 return '\n'.join(map(sjoin, fmatrix))+'\n'
717 return '\n'.join(map(sjoin, fmatrix))+'\n'
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
General Comments 0
You need to be logged in to leave comments. Login now