##// END OF EJS Templates
determine encoding of source lines in %debug before colorizing
Jörgen Stenarson -
Show More
@@ -1,527 +1,529 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """
2 """
3 Pdb debugger class.
3 Pdb debugger class.
4
4
5 Modified from the standard pdb.Pdb class to avoid including readline, so that
5 Modified from the standard pdb.Pdb class to avoid including readline, so that
6 the command line completion of other programs which include this isn't
6 the command line completion of other programs which include this isn't
7 damaged.
7 damaged.
8
8
9 In the future, this class will be expanded with improvements over the standard
9 In the future, this class will be expanded with improvements over the standard
10 pdb.
10 pdb.
11
11
12 The code in this file is mainly lifted out of cmd.py in Python 2.2, with minor
12 The code in this file is mainly lifted out of cmd.py in Python 2.2, with minor
13 changes. Licensing should therefore be under the standard Python terms. For
13 changes. Licensing should therefore be under the standard Python terms. For
14 details on the PSF (Python Software Foundation) standard license, see:
14 details on the PSF (Python Software Foundation) standard license, see:
15
15
16 http://www.python.org/2.2.3/license.html"""
16 http://www.python.org/2.2.3/license.html"""
17
17
18 #*****************************************************************************
18 #*****************************************************************************
19 #
19 #
20 # This file is licensed under the PSF license.
20 # This file is licensed under the PSF license.
21 #
21 #
22 # Copyright (C) 2001 Python Software Foundation, www.python.org
22 # Copyright (C) 2001 Python Software Foundation, www.python.org
23 # Copyright (C) 2005-2006 Fernando Perez. <fperez@colorado.edu>
23 # Copyright (C) 2005-2006 Fernando Perez. <fperez@colorado.edu>
24 #
24 #
25 #
25 #
26 #*****************************************************************************
26 #*****************************************************************************
27 from __future__ import print_function
27 from __future__ import print_function
28
28
29 import bdb
29 import bdb
30 import linecache
30 import linecache
31 import sys
31 import sys
32
32
33 from IPython.utils import PyColorize
33 from IPython.utils import PyColorize
34 from IPython.core import ipapi
34 from IPython.core import ipapi
35 from IPython.utils import coloransi, io
35 from IPython.utils import coloransi, io
36 from IPython.core.excolors import exception_colors
36 from IPython.core.excolors import exception_colors
37
37
38 # See if we can use pydb.
38 # See if we can use pydb.
39 has_pydb = False
39 has_pydb = False
40 prompt = 'ipdb> '
40 prompt = 'ipdb> '
41 #We have to check this directly from sys.argv, config struct not yet available
41 #We have to check this directly from sys.argv, config struct not yet available
42 if '--pydb' in sys.argv:
42 if '--pydb' in sys.argv:
43 try:
43 try:
44 import pydb
44 import pydb
45 if hasattr(pydb.pydb, "runl") and pydb.version>'1.17':
45 if hasattr(pydb.pydb, "runl") and pydb.version>'1.17':
46 # Version 1.17 is broken, and that's what ships with Ubuntu Edgy, so we
46 # Version 1.17 is broken, and that's what ships with Ubuntu Edgy, so we
47 # better protect against it.
47 # better protect against it.
48 has_pydb = True
48 has_pydb = True
49 except ImportError:
49 except ImportError:
50 print("Pydb (http://bashdb.sourceforge.net/pydb/) does not seem to be available")
50 print("Pydb (http://bashdb.sourceforge.net/pydb/) does not seem to be available")
51
51
52 if has_pydb:
52 if has_pydb:
53 from pydb import Pdb as OldPdb
53 from pydb import Pdb as OldPdb
54 #print "Using pydb for %run -d and post-mortem" #dbg
54 #print "Using pydb for %run -d and post-mortem" #dbg
55 prompt = 'ipydb> '
55 prompt = 'ipydb> '
56 else:
56 else:
57 from pdb import Pdb as OldPdb
57 from pdb import Pdb as OldPdb
58
58
59 # Allow the set_trace code to operate outside of an ipython instance, even if
59 # Allow the set_trace code to operate outside of an ipython instance, even if
60 # it does so with some limitations. The rest of this support is implemented in
60 # it does so with some limitations. The rest of this support is implemented in
61 # the Tracer constructor.
61 # the Tracer constructor.
62 def BdbQuit_excepthook(et,ev,tb):
62 def BdbQuit_excepthook(et,ev,tb):
63 if et==bdb.BdbQuit:
63 if et==bdb.BdbQuit:
64 print('Exiting Debugger.')
64 print('Exiting Debugger.')
65 else:
65 else:
66 BdbQuit_excepthook.excepthook_ori(et,ev,tb)
66 BdbQuit_excepthook.excepthook_ori(et,ev,tb)
67
67
68 def BdbQuit_IPython_excepthook(self,et,ev,tb,tb_offset=None):
68 def BdbQuit_IPython_excepthook(self,et,ev,tb,tb_offset=None):
69 print('Exiting Debugger.')
69 print('Exiting Debugger.')
70
70
71
71
72 class Tracer(object):
72 class Tracer(object):
73 """Class for local debugging, similar to pdb.set_trace.
73 """Class for local debugging, similar to pdb.set_trace.
74
74
75 Instances of this class, when called, behave like pdb.set_trace, but
75 Instances of this class, when called, behave like pdb.set_trace, but
76 providing IPython's enhanced capabilities.
76 providing IPython's enhanced capabilities.
77
77
78 This is implemented as a class which must be initialized in your own code
78 This is implemented as a class which must be initialized in your own code
79 and not as a standalone function because we need to detect at runtime
79 and not as a standalone function because we need to detect at runtime
80 whether IPython is already active or not. That detection is done in the
80 whether IPython is already active or not. That detection is done in the
81 constructor, ensuring that this code plays nicely with a running IPython,
81 constructor, ensuring that this code plays nicely with a running IPython,
82 while functioning acceptably (though with limitations) if outside of it.
82 while functioning acceptably (though with limitations) if outside of it.
83 """
83 """
84
84
85 def __init__(self,colors=None):
85 def __init__(self,colors=None):
86 """Create a local debugger instance.
86 """Create a local debugger instance.
87
87
88 :Parameters:
88 :Parameters:
89
89
90 - `colors` (None): a string containing the name of the color scheme to
90 - `colors` (None): a string containing the name of the color scheme to
91 use, it must be one of IPython's valid color schemes. If not given, the
91 use, it must be one of IPython's valid color schemes. If not given, the
92 function will default to the current IPython scheme when running inside
92 function will default to the current IPython scheme when running inside
93 IPython, and to 'NoColor' otherwise.
93 IPython, and to 'NoColor' otherwise.
94
94
95 Usage example:
95 Usage example:
96
96
97 from IPython.core.debugger import Tracer; debug_here = Tracer()
97 from IPython.core.debugger import Tracer; debug_here = Tracer()
98
98
99 ... later in your code
99 ... later in your code
100 debug_here() # -> will open up the debugger at that point.
100 debug_here() # -> will open up the debugger at that point.
101
101
102 Once the debugger activates, you can use all of its regular commands to
102 Once the debugger activates, you can use all of its regular commands to
103 step through code, set breakpoints, etc. See the pdb documentation
103 step through code, set breakpoints, etc. See the pdb documentation
104 from the Python standard library for usage details.
104 from the Python standard library for usage details.
105 """
105 """
106
106
107 try:
107 try:
108 ip = get_ipython()
108 ip = get_ipython()
109 except NameError:
109 except NameError:
110 # Outside of ipython, we set our own exception hook manually
110 # Outside of ipython, we set our own exception hook manually
111 BdbQuit_excepthook.excepthook_ori = sys.excepthook
111 BdbQuit_excepthook.excepthook_ori = sys.excepthook
112 sys.excepthook = BdbQuit_excepthook
112 sys.excepthook = BdbQuit_excepthook
113 def_colors = 'NoColor'
113 def_colors = 'NoColor'
114 try:
114 try:
115 # Limited tab completion support
115 # Limited tab completion support
116 import readline
116 import readline
117 readline.parse_and_bind('tab: complete')
117 readline.parse_and_bind('tab: complete')
118 except ImportError:
118 except ImportError:
119 pass
119 pass
120 else:
120 else:
121 # In ipython, we use its custom exception handler mechanism
121 # In ipython, we use its custom exception handler mechanism
122 def_colors = ip.colors
122 def_colors = ip.colors
123 ip.set_custom_exc((bdb.BdbQuit,), BdbQuit_IPython_excepthook)
123 ip.set_custom_exc((bdb.BdbQuit,), BdbQuit_IPython_excepthook)
124
124
125 if colors is None:
125 if colors is None:
126 colors = def_colors
126 colors = def_colors
127
127
128 # The stdlib debugger internally uses a modified repr from the `repr`
128 # The stdlib debugger internally uses a modified repr from the `repr`
129 # module, that limits the length of printed strings to a hardcoded
129 # module, that limits the length of printed strings to a hardcoded
130 # limit of 30 characters. That much trimming is too aggressive, let's
130 # limit of 30 characters. That much trimming is too aggressive, let's
131 # at least raise that limit to 80 chars, which should be enough for
131 # at least raise that limit to 80 chars, which should be enough for
132 # most interactive uses.
132 # most interactive uses.
133 try:
133 try:
134 from repr import aRepr
134 from repr import aRepr
135 aRepr.maxstring = 80
135 aRepr.maxstring = 80
136 except:
136 except:
137 # This is only a user-facing convenience, so any error we encounter
137 # This is only a user-facing convenience, so any error we encounter
138 # here can be warned about but can be otherwise ignored. These
138 # here can be warned about but can be otherwise ignored. These
139 # printouts will tell us about problems if this API changes
139 # printouts will tell us about problems if this API changes
140 import traceback
140 import traceback
141 traceback.print_exc()
141 traceback.print_exc()
142
142
143 self.debugger = Pdb(colors)
143 self.debugger = Pdb(colors)
144
144
145 def __call__(self):
145 def __call__(self):
146 """Starts an interactive debugger at the point where called.
146 """Starts an interactive debugger at the point where called.
147
147
148 This is similar to the pdb.set_trace() function from the std lib, but
148 This is similar to the pdb.set_trace() function from the std lib, but
149 using IPython's enhanced debugger."""
149 using IPython's enhanced debugger."""
150
150
151 self.debugger.set_trace(sys._getframe().f_back)
151 self.debugger.set_trace(sys._getframe().f_back)
152
152
153
153
154 def decorate_fn_with_doc(new_fn, old_fn, additional_text=""):
154 def decorate_fn_with_doc(new_fn, old_fn, additional_text=""):
155 """Make new_fn have old_fn's doc string. This is particularly useful
155 """Make new_fn have old_fn's doc string. This is particularly useful
156 for the do_... commands that hook into the help system.
156 for the do_... commands that hook into the help system.
157 Adapted from from a comp.lang.python posting
157 Adapted from from a comp.lang.python posting
158 by Duncan Booth."""
158 by Duncan Booth."""
159 def wrapper(*args, **kw):
159 def wrapper(*args, **kw):
160 return new_fn(*args, **kw)
160 return new_fn(*args, **kw)
161 if old_fn.__doc__:
161 if old_fn.__doc__:
162 wrapper.__doc__ = old_fn.__doc__ + additional_text
162 wrapper.__doc__ = old_fn.__doc__ + additional_text
163 return wrapper
163 return wrapper
164
164
165
165
166 def _file_lines(fname):
166 def _file_lines(fname):
167 """Return the contents of a named file as a list of lines.
167 """Return the contents of a named file as a list of lines.
168
168
169 This function never raises an IOError exception: if the file can't be
169 This function never raises an IOError exception: if the file can't be
170 read, it simply returns an empty list."""
170 read, it simply returns an empty list."""
171
171
172 try:
172 try:
173 outfile = open(fname)
173 outfile = open(fname)
174 except IOError:
174 except IOError:
175 return []
175 return []
176 else:
176 else:
177 out = outfile.readlines()
177 out = outfile.readlines()
178 outfile.close()
178 outfile.close()
179 return out
179 return out
180
180
181
181
182 class Pdb(OldPdb):
182 class Pdb(OldPdb):
183 """Modified Pdb class, does not load readline."""
183 """Modified Pdb class, does not load readline."""
184
184
185 def __init__(self,color_scheme='NoColor',completekey=None,
185 def __init__(self,color_scheme='NoColor',completekey=None,
186 stdin=None, stdout=None):
186 stdin=None, stdout=None):
187
187
188 # Parent constructor:
188 # Parent constructor:
189 if has_pydb and completekey is None:
189 if has_pydb and completekey is None:
190 OldPdb.__init__(self,stdin=stdin,stdout=io.stdout)
190 OldPdb.__init__(self,stdin=stdin,stdout=io.stdout)
191 else:
191 else:
192 OldPdb.__init__(self,completekey,stdin,stdout)
192 OldPdb.__init__(self,completekey,stdin,stdout)
193
193
194 self.prompt = prompt # The default prompt is '(Pdb)'
194 self.prompt = prompt # The default prompt is '(Pdb)'
195
195
196 # IPython changes...
196 # IPython changes...
197 self.is_pydb = has_pydb
197 self.is_pydb = has_pydb
198
198
199 self.shell = ipapi.get()
199 self.shell = ipapi.get()
200
200
201 if self.is_pydb:
201 if self.is_pydb:
202
202
203 # interactiveshell.py's ipalias seems to want pdb's checkline
203 # interactiveshell.py's ipalias seems to want pdb's checkline
204 # which located in pydb.fn
204 # which located in pydb.fn
205 import pydb.fns
205 import pydb.fns
206 self.checkline = lambda filename, lineno: \
206 self.checkline = lambda filename, lineno: \
207 pydb.fns.checkline(self, filename, lineno)
207 pydb.fns.checkline(self, filename, lineno)
208
208
209 self.curframe = None
209 self.curframe = None
210 self.do_restart = self.new_do_restart
210 self.do_restart = self.new_do_restart
211
211
212 self.old_all_completions = self.shell.Completer.all_completions
212 self.old_all_completions = self.shell.Completer.all_completions
213 self.shell.Completer.all_completions=self.all_completions
213 self.shell.Completer.all_completions=self.all_completions
214
214
215 self.do_list = decorate_fn_with_doc(self.list_command_pydb,
215 self.do_list = decorate_fn_with_doc(self.list_command_pydb,
216 OldPdb.do_list)
216 OldPdb.do_list)
217 self.do_l = self.do_list
217 self.do_l = self.do_list
218 self.do_frame = decorate_fn_with_doc(self.new_do_frame,
218 self.do_frame = decorate_fn_with_doc(self.new_do_frame,
219 OldPdb.do_frame)
219 OldPdb.do_frame)
220
220
221 self.aliases = {}
221 self.aliases = {}
222
222
223 # Create color table: we copy the default one from the traceback
223 # Create color table: we copy the default one from the traceback
224 # module and add a few attributes needed for debugging
224 # module and add a few attributes needed for debugging
225 self.color_scheme_table = exception_colors()
225 self.color_scheme_table = exception_colors()
226
226
227 # shorthands
227 # shorthands
228 C = coloransi.TermColors
228 C = coloransi.TermColors
229 cst = self.color_scheme_table
229 cst = self.color_scheme_table
230
230
231 cst['NoColor'].colors.breakpoint_enabled = C.NoColor
231 cst['NoColor'].colors.breakpoint_enabled = C.NoColor
232 cst['NoColor'].colors.breakpoint_disabled = C.NoColor
232 cst['NoColor'].colors.breakpoint_disabled = C.NoColor
233
233
234 cst['Linux'].colors.breakpoint_enabled = C.LightRed
234 cst['Linux'].colors.breakpoint_enabled = C.LightRed
235 cst['Linux'].colors.breakpoint_disabled = C.Red
235 cst['Linux'].colors.breakpoint_disabled = C.Red
236
236
237 cst['LightBG'].colors.breakpoint_enabled = C.LightRed
237 cst['LightBG'].colors.breakpoint_enabled = C.LightRed
238 cst['LightBG'].colors.breakpoint_disabled = C.Red
238 cst['LightBG'].colors.breakpoint_disabled = C.Red
239
239
240 self.set_colors(color_scheme)
240 self.set_colors(color_scheme)
241
241
242 # Add a python parser so we can syntax highlight source while
242 # Add a python parser so we can syntax highlight source while
243 # debugging.
243 # debugging.
244 self.parser = PyColorize.Parser()
244 self.parser = PyColorize.Parser()
245
245
246 def set_colors(self, scheme):
246 def set_colors(self, scheme):
247 """Shorthand access to the color table scheme selector method."""
247 """Shorthand access to the color table scheme selector method."""
248 self.color_scheme_table.set_active_scheme(scheme)
248 self.color_scheme_table.set_active_scheme(scheme)
249
249
250 def interaction(self, frame, traceback):
250 def interaction(self, frame, traceback):
251 self.shell.set_completer_frame(frame)
251 self.shell.set_completer_frame(frame)
252 OldPdb.interaction(self, frame, traceback)
252 OldPdb.interaction(self, frame, traceback)
253
253
254 def new_do_up(self, arg):
254 def new_do_up(self, arg):
255 OldPdb.do_up(self, arg)
255 OldPdb.do_up(self, arg)
256 self.shell.set_completer_frame(self.curframe)
256 self.shell.set_completer_frame(self.curframe)
257 do_u = do_up = decorate_fn_with_doc(new_do_up, OldPdb.do_up)
257 do_u = do_up = decorate_fn_with_doc(new_do_up, OldPdb.do_up)
258
258
259 def new_do_down(self, arg):
259 def new_do_down(self, arg):
260 OldPdb.do_down(self, arg)
260 OldPdb.do_down(self, arg)
261 self.shell.set_completer_frame(self.curframe)
261 self.shell.set_completer_frame(self.curframe)
262
262
263 do_d = do_down = decorate_fn_with_doc(new_do_down, OldPdb.do_down)
263 do_d = do_down = decorate_fn_with_doc(new_do_down, OldPdb.do_down)
264
264
265 def new_do_frame(self, arg):
265 def new_do_frame(self, arg):
266 OldPdb.do_frame(self, arg)
266 OldPdb.do_frame(self, arg)
267 self.shell.set_completer_frame(self.curframe)
267 self.shell.set_completer_frame(self.curframe)
268
268
269 def new_do_quit(self, arg):
269 def new_do_quit(self, arg):
270
270
271 if hasattr(self, 'old_all_completions'):
271 if hasattr(self, 'old_all_completions'):
272 self.shell.Completer.all_completions=self.old_all_completions
272 self.shell.Completer.all_completions=self.old_all_completions
273
273
274
274
275 return OldPdb.do_quit(self, arg)
275 return OldPdb.do_quit(self, arg)
276
276
277 do_q = do_quit = decorate_fn_with_doc(new_do_quit, OldPdb.do_quit)
277 do_q = do_quit = decorate_fn_with_doc(new_do_quit, OldPdb.do_quit)
278
278
279 def new_do_restart(self, arg):
279 def new_do_restart(self, arg):
280 """Restart command. In the context of ipython this is exactly the same
280 """Restart command. In the context of ipython this is exactly the same
281 thing as 'quit'."""
281 thing as 'quit'."""
282 self.msg("Restart doesn't make sense here. Using 'quit' instead.")
282 self.msg("Restart doesn't make sense here. Using 'quit' instead.")
283 return self.do_quit(arg)
283 return self.do_quit(arg)
284
284
285 def postloop(self):
285 def postloop(self):
286 self.shell.set_completer_frame(None)
286 self.shell.set_completer_frame(None)
287
287
288 def print_stack_trace(self):
288 def print_stack_trace(self):
289 try:
289 try:
290 for frame_lineno in self.stack:
290 for frame_lineno in self.stack:
291 self.print_stack_entry(frame_lineno, context = 5)
291 self.print_stack_entry(frame_lineno, context = 5)
292 except KeyboardInterrupt:
292 except KeyboardInterrupt:
293 pass
293 pass
294
294
295 def print_stack_entry(self,frame_lineno,prompt_prefix='\n-> ',
295 def print_stack_entry(self,frame_lineno,prompt_prefix='\n-> ',
296 context = 3):
296 context = 3):
297 #frame, lineno = frame_lineno
297 #frame, lineno = frame_lineno
298 print(self.format_stack_entry(frame_lineno, '', context), file=io.stdout)
298 print(self.format_stack_entry(frame_lineno, '', context), file=io.stdout)
299
299
300 # vds: >>
300 # vds: >>
301 frame, lineno = frame_lineno
301 frame, lineno = frame_lineno
302 filename = frame.f_code.co_filename
302 filename = frame.f_code.co_filename
303 self.shell.hooks.synchronize_with_editor(filename, lineno, 0)
303 self.shell.hooks.synchronize_with_editor(filename, lineno, 0)
304 # vds: <<
304 # vds: <<
305
305
306 def format_stack_entry(self, frame_lineno, lprefix=': ', context = 3):
306 def format_stack_entry(self, frame_lineno, lprefix=': ', context = 3):
307 import linecache, repr
307 import linecache, repr
308
308
309 ret = []
309 ret = []
310
310
311 Colors = self.color_scheme_table.active_colors
311 Colors = self.color_scheme_table.active_colors
312 ColorsNormal = Colors.Normal
312 ColorsNormal = Colors.Normal
313 tpl_link = '%s%%s%s' % (Colors.filenameEm, ColorsNormal)
313 tpl_link = '%s%%s%s' % (Colors.filenameEm, ColorsNormal)
314 tpl_call = '%s%%s%s%%s%s' % (Colors.vName, Colors.valEm, ColorsNormal)
314 tpl_call = '%s%%s%s%%s%s' % (Colors.vName, Colors.valEm, ColorsNormal)
315 tpl_line = '%%s%s%%s %s%%s' % (Colors.lineno, ColorsNormal)
315 tpl_line = '%%s%s%%s %s%%s' % (Colors.lineno, ColorsNormal)
316 tpl_line_em = '%%s%s%%s %s%%s%s' % (Colors.linenoEm, Colors.line,
316 tpl_line_em = '%%s%s%%s %s%%s%s' % (Colors.linenoEm, Colors.line,
317 ColorsNormal)
317 ColorsNormal)
318
318
319 frame, lineno = frame_lineno
319 frame, lineno = frame_lineno
320
320
321 return_value = ''
321 return_value = ''
322 if '__return__' in frame.f_locals:
322 if '__return__' in frame.f_locals:
323 rv = frame.f_locals['__return__']
323 rv = frame.f_locals['__return__']
324 #return_value += '->'
324 #return_value += '->'
325 return_value += repr.repr(rv) + '\n'
325 return_value += repr.repr(rv) + '\n'
326 ret.append(return_value)
326 ret.append(return_value)
327
327
328 #s = filename + '(' + `lineno` + ')'
328 #s = filename + '(' + `lineno` + ')'
329 filename = self.canonic(frame.f_code.co_filename)
329 filename = self.canonic(frame.f_code.co_filename)
330 link = tpl_link % filename
330 link = tpl_link % filename
331
331
332 if frame.f_code.co_name:
332 if frame.f_code.co_name:
333 func = frame.f_code.co_name
333 func = frame.f_code.co_name
334 else:
334 else:
335 func = "<lambda>"
335 func = "<lambda>"
336
336
337 call = ''
337 call = ''
338 if func != '?':
338 if func != '?':
339 if '__args__' in frame.f_locals:
339 if '__args__' in frame.f_locals:
340 args = repr.repr(frame.f_locals['__args__'])
340 args = repr.repr(frame.f_locals['__args__'])
341 else:
341 else:
342 args = '()'
342 args = '()'
343 call = tpl_call % (func, args)
343 call = tpl_call % (func, args)
344
344
345 # The level info should be generated in the same format pdb uses, to
345 # The level info should be generated in the same format pdb uses, to
346 # avoid breaking the pdbtrack functionality of python-mode in *emacs.
346 # avoid breaking the pdbtrack functionality of python-mode in *emacs.
347 if frame is self.curframe:
347 if frame is self.curframe:
348 ret.append('> ')
348 ret.append('> ')
349 else:
349 else:
350 ret.append(' ')
350 ret.append(' ')
351 ret.append('%s(%s)%s\n' % (link,lineno,call))
351 ret.append('%s(%s)%s\n' % (link,lineno,call))
352
352
353 start = lineno - 1 - context//2
353 start = lineno - 1 - context//2
354 lines = linecache.getlines(filename)
354 lines = linecache.getlines(filename)
355 encoding = io.guess_encoding(lines)
355 start = max(start, 0)
356 start = max(start, 0)
356 start = min(start, len(lines) - context)
357 start = min(start, len(lines) - context)
357 lines = lines[start : start + context]
358 lines = lines[start : start + context]
358
359
359 for i,line in enumerate(lines):
360 for i,line in enumerate(lines):
360 show_arrow = (start + 1 + i == lineno)
361 show_arrow = (start + 1 + i == lineno)
361 linetpl = (frame is self.curframe or show_arrow) \
362 linetpl = (frame is self.curframe or show_arrow) \
362 and tpl_line_em \
363 and tpl_line_em \
363 or tpl_line
364 or tpl_line
364 ret.append(self.__format_line(linetpl, filename,
365 ret.append(self.__format_line(linetpl, filename,
365 start + 1 + i, line,
366 start + 1 + i, line.decode(encoding),
366 arrow = show_arrow) )
367 arrow = show_arrow) )
367
368 return ''.join(ret)
368 return ''.join(ret)
369
369
370 def __format_line(self, tpl_line, filename, lineno, line, arrow = False):
370 def __format_line(self, tpl_line, filename, lineno, line, arrow = False):
371 bp_mark = ""
371 bp_mark = ""
372 bp_mark_color = ""
372 bp_mark_color = ""
373
373
374 scheme = self.color_scheme_table.active_scheme_name
374 scheme = self.color_scheme_table.active_scheme_name
375 new_line, err = self.parser.format2(line, 'str', scheme)
375 new_line, err = self.parser.format2(line, 'str', scheme)
376 if not err: line = new_line
376 if not err: line = new_line
377
377
378 bp = None
378 bp = None
379 if lineno in self.get_file_breaks(filename):
379 if lineno in self.get_file_breaks(filename):
380 bps = self.get_breaks(filename, lineno)
380 bps = self.get_breaks(filename, lineno)
381 bp = bps[-1]
381 bp = bps[-1]
382
382
383 if bp:
383 if bp:
384 Colors = self.color_scheme_table.active_colors
384 Colors = self.color_scheme_table.active_colors
385 bp_mark = str(bp.number)
385 bp_mark = str(bp.number)
386 bp_mark_color = Colors.breakpoint_enabled
386 bp_mark_color = Colors.breakpoint_enabled
387 if not bp.enabled:
387 if not bp.enabled:
388 bp_mark_color = Colors.breakpoint_disabled
388 bp_mark_color = Colors.breakpoint_disabled
389
389
390 numbers_width = 7
390 numbers_width = 7
391 if arrow:
391 if arrow:
392 # This is the line with the error
392 # This is the line with the error
393 pad = numbers_width - len(str(lineno)) - len(bp_mark)
393 pad = numbers_width - len(str(lineno)) - len(bp_mark)
394 if pad >= 3:
394 if pad >= 3:
395 marker = '-'*(pad-3) + '-> '
395 marker = '-'*(pad-3) + '-> '
396 elif pad == 2:
396 elif pad == 2:
397 marker = '> '
397 marker = '> '
398 elif pad == 1:
398 elif pad == 1:
399 marker = '>'
399 marker = '>'
400 else:
400 else:
401 marker = ''
401 marker = ''
402 num = '%s%s' % (marker, str(lineno))
402 num = '%s%s' % (marker, str(lineno))
403 line = tpl_line % (bp_mark_color + bp_mark, num, line)
403 line = tpl_line % (bp_mark_color + bp_mark, num, line)
404 else:
404 else:
405 num = '%*s' % (numbers_width - len(bp_mark), str(lineno))
405 num = '%*s' % (numbers_width - len(bp_mark), str(lineno))
406 line = tpl_line % (bp_mark_color + bp_mark, num, line)
406 line = tpl_line % (bp_mark_color + bp_mark, num, line)
407
407
408 return line
408 return line
409
409
410 def list_command_pydb(self, arg):
410 def list_command_pydb(self, arg):
411 """List command to use if we have a newer pydb installed"""
411 """List command to use if we have a newer pydb installed"""
412 filename, first, last = OldPdb.parse_list_cmd(self, arg)
412 filename, first, last = OldPdb.parse_list_cmd(self, arg)
413 if filename is not None:
413 if filename is not None:
414 self.print_list_lines(filename, first, last)
414 self.print_list_lines(filename, first, last)
415
415
416 def print_list_lines(self, filename, first, last):
416 def print_list_lines(self, filename, first, last):
417 """The printing (as opposed to the parsing part of a 'list'
417 """The printing (as opposed to the parsing part of a 'list'
418 command."""
418 command."""
419 try:
419 try:
420 Colors = self.color_scheme_table.active_colors
420 Colors = self.color_scheme_table.active_colors
421 ColorsNormal = Colors.Normal
421 ColorsNormal = Colors.Normal
422 tpl_line = '%%s%s%%s %s%%s' % (Colors.lineno, ColorsNormal)
422 tpl_line = '%%s%s%%s %s%%s' % (Colors.lineno, ColorsNormal)
423 tpl_line_em = '%%s%s%%s %s%%s%s' % (Colors.linenoEm, Colors.line, ColorsNormal)
423 tpl_line_em = '%%s%s%%s %s%%s%s' % (Colors.linenoEm, Colors.line, ColorsNormal)
424 src = []
424 src = []
425 lines = linecache.getlines(filename)
426 encoding = io.guess_encoding(lines)
425 for lineno in range(first, last+1):
427 for lineno in range(first, last+1):
426 line = linecache.getline(filename, lineno)
428 line = lines[lineno].decode(encoding)
427 if not line:
429 if not line:
428 break
430 break
429
431
430 if lineno == self.curframe.f_lineno:
432 if lineno == self.curframe.f_lineno:
431 line = self.__format_line(tpl_line_em, filename, lineno, line, arrow = True)
433 line = self.__format_line(tpl_line_em, filename, lineno, line, arrow = True)
432 else:
434 else:
433 line = self.__format_line(tpl_line, filename, lineno, line, arrow = False)
435 line = self.__format_line(tpl_line, filename, lineno, line, arrow = False)
434
436
435 src.append(line)
437 src.append(line)
436 self.lineno = lineno
438 self.lineno = lineno
437
439
438 print(''.join(src), file=io.stdout)
440 print(''.join(src), file=io.stdout)
439
441
440 except KeyboardInterrupt:
442 except KeyboardInterrupt:
441 pass
443 pass
442
444
443 def do_list(self, arg):
445 def do_list(self, arg):
444 self.lastcmd = 'list'
446 self.lastcmd = 'list'
445 last = None
447 last = None
446 if arg:
448 if arg:
447 try:
449 try:
448 x = eval(arg, {}, {})
450 x = eval(arg, {}, {})
449 if type(x) == type(()):
451 if type(x) == type(()):
450 first, last = x
452 first, last = x
451 first = int(first)
453 first = int(first)
452 last = int(last)
454 last = int(last)
453 if last < first:
455 if last < first:
454 # Assume it's a count
456 # Assume it's a count
455 last = first + last
457 last = first + last
456 else:
458 else:
457 first = max(1, int(x) - 5)
459 first = max(1, int(x) - 5)
458 except:
460 except:
459 print('*** Error in argument:', repr(arg))
461 print('*** Error in argument:', repr(arg))
460 return
462 return
461 elif self.lineno is None:
463 elif self.lineno is None:
462 first = max(1, self.curframe.f_lineno - 5)
464 first = max(1, self.curframe.f_lineno - 5)
463 else:
465 else:
464 first = self.lineno + 1
466 first = self.lineno + 1
465 if last is None:
467 if last is None:
466 last = first + 10
468 last = first + 10
467 self.print_list_lines(self.curframe.f_code.co_filename, first, last)
469 self.print_list_lines(self.curframe.f_code.co_filename, first, last)
468
470
469 # vds: >>
471 # vds: >>
470 lineno = first
472 lineno = first
471 filename = self.curframe.f_code.co_filename
473 filename = self.curframe.f_code.co_filename
472 self.shell.hooks.synchronize_with_editor(filename, lineno, 0)
474 self.shell.hooks.synchronize_with_editor(filename, lineno, 0)
473 # vds: <<
475 # vds: <<
474
476
475 do_l = do_list
477 do_l = do_list
476
478
477 def do_pdef(self, arg):
479 def do_pdef(self, arg):
478 """The debugger interface to magic_pdef"""
480 """The debugger interface to magic_pdef"""
479 namespaces = [('Locals', self.curframe.f_locals),
481 namespaces = [('Locals', self.curframe.f_locals),
480 ('Globals', self.curframe.f_globals)]
482 ('Globals', self.curframe.f_globals)]
481 self.shell.find_line_magic('pdef')(arg, namespaces=namespaces)
483 self.shell.find_line_magic('pdef')(arg, namespaces=namespaces)
482
484
483 def do_pdoc(self, arg):
485 def do_pdoc(self, arg):
484 """The debugger interface to magic_pdoc"""
486 """The debugger interface to magic_pdoc"""
485 namespaces = [('Locals', self.curframe.f_locals),
487 namespaces = [('Locals', self.curframe.f_locals),
486 ('Globals', self.curframe.f_globals)]
488 ('Globals', self.curframe.f_globals)]
487 self.shell.find_line_magic('pdoc')(arg, namespaces=namespaces)
489 self.shell.find_line_magic('pdoc')(arg, namespaces=namespaces)
488
490
489 def do_pinfo(self, arg):
491 def do_pinfo(self, arg):
490 """The debugger equivalant of ?obj"""
492 """The debugger equivalant of ?obj"""
491 namespaces = [('Locals', self.curframe.f_locals),
493 namespaces = [('Locals', self.curframe.f_locals),
492 ('Globals', self.curframe.f_globals)]
494 ('Globals', self.curframe.f_globals)]
493 self.shell.find_line_magic('pinfo')("pinfo %s" % arg,
495 self.shell.find_line_magic('pinfo')("pinfo %s" % arg,
494 namespaces=namespaces)
496 namespaces=namespaces)
495
497
496 def checkline(self, filename, lineno):
498 def checkline(self, filename, lineno):
497 """Check whether specified line seems to be executable.
499 """Check whether specified line seems to be executable.
498
500
499 Return `lineno` if it is, 0 if not (e.g. a docstring, comment, blank
501 Return `lineno` if it is, 0 if not (e.g. a docstring, comment, blank
500 line or EOF). Warning: testing is not comprehensive.
502 line or EOF). Warning: testing is not comprehensive.
501 """
503 """
502 #######################################################################
504 #######################################################################
503 # XXX Hack! Use python-2.5 compatible code for this call, because with
505 # XXX Hack! Use python-2.5 compatible code for this call, because with
504 # all of our changes, we've drifted from the pdb api in 2.6. For now,
506 # all of our changes, we've drifted from the pdb api in 2.6. For now,
505 # changing:
507 # changing:
506 #
508 #
507 #line = linecache.getline(filename, lineno, self.curframe.f_globals)
509 #line = linecache.getline(filename, lineno, self.curframe.f_globals)
508 # to:
510 # to:
509 #
511 #
510 line = linecache.getline(filename, lineno)
512 line = linecache.getline(filename, lineno)
511 #
513 #
512 # does the trick. But in reality, we need to fix this by reconciling
514 # does the trick. But in reality, we need to fix this by reconciling
513 # our updates with the new Pdb APIs in Python 2.6.
515 # our updates with the new Pdb APIs in Python 2.6.
514 #
516 #
515 # End hack. The rest of this method is copied verbatim from 2.6 pdb.py
517 # End hack. The rest of this method is copied verbatim from 2.6 pdb.py
516 #######################################################################
518 #######################################################################
517
519
518 if not line:
520 if not line:
519 print('End of file', file=self.stdout)
521 print('End of file', file=self.stdout)
520 return 0
522 return 0
521 line = line.strip()
523 line = line.strip()
522 # Don't allow setting breakpoint at a blank line
524 # Don't allow setting breakpoint at a blank line
523 if (not line or (line[0] == '#') or
525 if (not line or (line[0] == '#') or
524 (line[:3] == '"""') or line[:3] == "'''"):
526 (line[:3] == '"""') or line[:3] == "'''"):
525 print('*** Blank or comment', file=self.stdout)
527 print('*** Blank or comment', file=self.stdout)
526 return 0
528 return 0
527 return lineno
529 return lineno
@@ -1,402 +1,409 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 re
17 import re
18 import os
18 import os
19 import sys
19 import sys
20 import tempfile
20 import tempfile
21 from StringIO import StringIO
21 from StringIO import StringIO
22
22
23 #-----------------------------------------------------------------------------
23 #-----------------------------------------------------------------------------
24 # Code
24 # Code
25 #-----------------------------------------------------------------------------
25 #-----------------------------------------------------------------------------
26
26
27
27
28 class IOStream:
28 class IOStream:
29
29
30 def __init__(self,stream, fallback=None):
30 def __init__(self,stream, fallback=None):
31 if not hasattr(stream,'write') or not hasattr(stream,'flush'):
31 if not hasattr(stream,'write') or not hasattr(stream,'flush'):
32 if fallback is not None:
32 if fallback is not None:
33 stream = fallback
33 stream = fallback
34 else:
34 else:
35 raise ValueError("fallback required, but not specified")
35 raise ValueError("fallback required, but not specified")
36 self.stream = stream
36 self.stream = stream
37 self._swrite = stream.write
37 self._swrite = stream.write
38
38
39 # clone all methods not overridden:
39 # clone all methods not overridden:
40 def clone(meth):
40 def clone(meth):
41 return not hasattr(self, meth) and not meth.startswith('_')
41 return not hasattr(self, meth) and not meth.startswith('_')
42 for meth in filter(clone, dir(stream)):
42 for meth in filter(clone, dir(stream)):
43 setattr(self, meth, getattr(stream, meth))
43 setattr(self, meth, getattr(stream, meth))
44
44
45 def write(self,data):
45 def write(self,data):
46 try:
46 try:
47 self._swrite(data)
47 self._swrite(data)
48 except:
48 except:
49 try:
49 try:
50 # print handles some unicode issues which may trip a plain
50 # print handles some unicode issues which may trip a plain
51 # write() call. Emulate write() by using an empty end
51 # write() call. Emulate write() by using an empty end
52 # argument.
52 # argument.
53 print(data, end='', file=self.stream)
53 print(data, end='', file=self.stream)
54 except:
54 except:
55 # if we get here, something is seriously broken.
55 # if we get here, something is seriously broken.
56 print('ERROR - failed to write data to stream:', self.stream,
56 print('ERROR - failed to write data to stream:', self.stream,
57 file=sys.stderr)
57 file=sys.stderr)
58
58
59 def writelines(self, lines):
59 def writelines(self, lines):
60 if isinstance(lines, basestring):
60 if isinstance(lines, basestring):
61 lines = [lines]
61 lines = [lines]
62 for line in lines:
62 for line in lines:
63 self.write(line)
63 self.write(line)
64
64
65 # This class used to have a writeln method, but regular files and streams
65 # This class used to have a writeln method, but regular files and streams
66 # in Python don't have this method. We need to keep this completely
66 # in Python don't have this method. We need to keep this completely
67 # compatible so we removed it.
67 # compatible so we removed it.
68
68
69 @property
69 @property
70 def closed(self):
70 def closed(self):
71 return self.stream.closed
71 return self.stream.closed
72
72
73 def close(self):
73 def close(self):
74 pass
74 pass
75
75
76 # setup stdin/stdout/stderr to sys.stdin/sys.stdout/sys.stderr
76 # setup stdin/stdout/stderr to sys.stdin/sys.stdout/sys.stderr
77 devnull = open(os.devnull, 'a')
77 devnull = open(os.devnull, 'a')
78 stdin = IOStream(sys.stdin, fallback=devnull)
78 stdin = IOStream(sys.stdin, fallback=devnull)
79 stdout = IOStream(sys.stdout, fallback=devnull)
79 stdout = IOStream(sys.stdout, fallback=devnull)
80 stderr = IOStream(sys.stderr, fallback=devnull)
80 stderr = IOStream(sys.stderr, fallback=devnull)
81
81
82 class IOTerm:
82 class IOTerm:
83 """ Term holds the file or file-like objects for handling I/O operations.
83 """ Term holds the file or file-like objects for handling I/O operations.
84
84
85 These are normally just sys.stdin, sys.stdout and sys.stderr but for
85 These are normally just sys.stdin, sys.stdout and sys.stderr but for
86 Windows they can can replaced to allow editing the strings before they are
86 Windows they can can replaced to allow editing the strings before they are
87 displayed."""
87 displayed."""
88
88
89 # In the future, having IPython channel all its I/O operations through
89 # In the future, having IPython channel all its I/O operations through
90 # this class will make it easier to embed it into other environments which
90 # this class will make it easier to embed it into other environments which
91 # are not a normal terminal (such as a GUI-based shell)
91 # are not a normal terminal (such as a GUI-based shell)
92 def __init__(self, stdin=None, stdout=None, stderr=None):
92 def __init__(self, stdin=None, stdout=None, stderr=None):
93 mymodule = sys.modules[__name__]
93 mymodule = sys.modules[__name__]
94 self.stdin = IOStream(stdin, mymodule.stdin)
94 self.stdin = IOStream(stdin, mymodule.stdin)
95 self.stdout = IOStream(stdout, mymodule.stdout)
95 self.stdout = IOStream(stdout, mymodule.stdout)
96 self.stderr = IOStream(stderr, mymodule.stderr)
96 self.stderr = IOStream(stderr, mymodule.stderr)
97
97
98
98
99 class Tee(object):
99 class Tee(object):
100 """A class to duplicate an output stream to stdout/err.
100 """A class to duplicate an output stream to stdout/err.
101
101
102 This works in a manner very similar to the Unix 'tee' command.
102 This works in a manner very similar to the Unix 'tee' command.
103
103
104 When the object is closed or deleted, it closes the original file given to
104 When the object is closed or deleted, it closes the original file given to
105 it for duplication.
105 it for duplication.
106 """
106 """
107 # Inspired by:
107 # Inspired by:
108 # http://mail.python.org/pipermail/python-list/2007-May/442737.html
108 # http://mail.python.org/pipermail/python-list/2007-May/442737.html
109
109
110 def __init__(self, file_or_name, mode="w", channel='stdout'):
110 def __init__(self, file_or_name, mode="w", channel='stdout'):
111 """Construct a new Tee object.
111 """Construct a new Tee object.
112
112
113 Parameters
113 Parameters
114 ----------
114 ----------
115 file_or_name : filename or open filehandle (writable)
115 file_or_name : filename or open filehandle (writable)
116 File that will be duplicated
116 File that will be duplicated
117
117
118 mode : optional, valid mode for open().
118 mode : optional, valid mode for open().
119 If a filename was give, open with this mode.
119 If a filename was give, open with this mode.
120
120
121 channel : str, one of ['stdout', 'stderr']
121 channel : str, one of ['stdout', 'stderr']
122 """
122 """
123 if channel not in ['stdout', 'stderr']:
123 if channel not in ['stdout', 'stderr']:
124 raise ValueError('Invalid channel spec %s' % channel)
124 raise ValueError('Invalid channel spec %s' % channel)
125
125
126 if hasattr(file_or_name, 'write') and hasattr(file_or_name, 'seek'):
126 if hasattr(file_or_name, 'write') and hasattr(file_or_name, 'seek'):
127 self.file = file_or_name
127 self.file = file_or_name
128 else:
128 else:
129 self.file = open(file_or_name, mode)
129 self.file = open(file_or_name, mode)
130 self.channel = channel
130 self.channel = channel
131 self.ostream = getattr(sys, channel)
131 self.ostream = getattr(sys, channel)
132 setattr(sys, channel, self)
132 setattr(sys, channel, self)
133 self._closed = False
133 self._closed = False
134
134
135 def close(self):
135 def close(self):
136 """Close the file and restore the channel."""
136 """Close the file and restore the channel."""
137 self.flush()
137 self.flush()
138 setattr(sys, self.channel, self.ostream)
138 setattr(sys, self.channel, self.ostream)
139 self.file.close()
139 self.file.close()
140 self._closed = True
140 self._closed = True
141
141
142 def write(self, data):
142 def write(self, data):
143 """Write data to both channels."""
143 """Write data to both channels."""
144 self.file.write(data)
144 self.file.write(data)
145 self.ostream.write(data)
145 self.ostream.write(data)
146 self.ostream.flush()
146 self.ostream.flush()
147
147
148 def flush(self):
148 def flush(self):
149 """Flush both channels."""
149 """Flush both channels."""
150 self.file.flush()
150 self.file.flush()
151 self.ostream.flush()
151 self.ostream.flush()
152
152
153 def __del__(self):
153 def __del__(self):
154 if not self._closed:
154 if not self._closed:
155 self.close()
155 self.close()
156
156
157
157
158 def source_to_unicode(txt):
158 def guess_encoding(lines):
159 """Converts string with python source code to unicode
159 """check list of lines for line matching the source code encoding pattern
160 """
161 if isinstance(txt, unicode):
162 return txt
163
160
161 Only check first two lines
162 """
164 reg = re.compile("#.*coding[:=]\s*([-\w.]+)")
163 reg = re.compile("#.*coding[:=]\s*([-\w.]+)")
165 for row in txt.split("\n", 2)[:2]: #We only need to check the first two lines
164 for row in lines[:2]: #We only need to check the first two lines
166 result = reg.match(row)
165 result = reg.match(row)
167 if result:
166 if result:
168 coding = result.groups()[0]
167 coding = result.groups()[0]
169 break
168 break
170 else:
169 else:
171 coding = "ascii"
170 coding = "ascii"
171 return coding
172
173 def source_to_unicode(txt):
174 """Converts string with python source code to unicode
175 """
176 if isinstance(txt, unicode):
177 return txt
178 coding = guess_encoding(txt.split("\n", 2))
172 return txt.decode(coding, errors="replace")
179 return txt.decode(coding, errors="replace")
173
180
174
181
175 def file_read(filename):
182 def file_read(filename):
176 """Read a file and close it. Returns the file source."""
183 """Read a file and close it. Returns the file source."""
177 fobj = open(filename,'r');
184 fobj = open(filename,'r');
178 source = fobj.read();
185 source = fobj.read();
179 fobj.close()
186 fobj.close()
180 return source
187 return source
181
188
182
189
183 def file_readlines(filename):
190 def file_readlines(filename):
184 """Read a file and close it. Returns the file source using readlines()."""
191 """Read a file and close it. Returns the file source using readlines()."""
185 fobj = open(filename,'r');
192 fobj = open(filename,'r');
186 lines = fobj.readlines();
193 lines = fobj.readlines();
187 fobj.close()
194 fobj.close()
188 return lines
195 return lines
189
196
190
197
191 def raw_input_multi(header='', ps1='==> ', ps2='..> ',terminate_str = '.'):
198 def raw_input_multi(header='', ps1='==> ', ps2='..> ',terminate_str = '.'):
192 """Take multiple lines of input.
199 """Take multiple lines of input.
193
200
194 A list with each line of input as a separate element is returned when a
201 A list with each line of input as a separate element is returned when a
195 termination string is entered (defaults to a single '.'). Input can also
202 termination string is entered (defaults to a single '.'). Input can also
196 terminate via EOF (^D in Unix, ^Z-RET in Windows).
203 terminate via EOF (^D in Unix, ^Z-RET in Windows).
197
204
198 Lines of input which end in \\ are joined into single entries (and a
205 Lines of input which end in \\ are joined into single entries (and a
199 secondary continuation prompt is issued as long as the user terminates
206 secondary continuation prompt is issued as long as the user terminates
200 lines with \\). This allows entering very long strings which are still
207 lines with \\). This allows entering very long strings which are still
201 meant to be treated as single entities.
208 meant to be treated as single entities.
202 """
209 """
203
210
204 try:
211 try:
205 if header:
212 if header:
206 header += '\n'
213 header += '\n'
207 lines = [raw_input(header + ps1)]
214 lines = [raw_input(header + ps1)]
208 except EOFError:
215 except EOFError:
209 return []
216 return []
210 terminate = [terminate_str]
217 terminate = [terminate_str]
211 try:
218 try:
212 while lines[-1:] != terminate:
219 while lines[-1:] != terminate:
213 new_line = raw_input(ps1)
220 new_line = raw_input(ps1)
214 while new_line.endswith('\\'):
221 while new_line.endswith('\\'):
215 new_line = new_line[:-1] + raw_input(ps2)
222 new_line = new_line[:-1] + raw_input(ps2)
216 lines.append(new_line)
223 lines.append(new_line)
217
224
218 return lines[:-1] # don't return the termination command
225 return lines[:-1] # don't return the termination command
219 except EOFError:
226 except EOFError:
220 print()
227 print()
221 return lines
228 return lines
222
229
223
230
224 def raw_input_ext(prompt='', ps2='... '):
231 def raw_input_ext(prompt='', ps2='... '):
225 """Similar to raw_input(), but accepts extended lines if input ends with \\."""
232 """Similar to raw_input(), but accepts extended lines if input ends with \\."""
226
233
227 line = raw_input(prompt)
234 line = raw_input(prompt)
228 while line.endswith('\\'):
235 while line.endswith('\\'):
229 line = line[:-1] + raw_input(ps2)
236 line = line[:-1] + raw_input(ps2)
230 return line
237 return line
231
238
232
239
233 def ask_yes_no(prompt,default=None):
240 def ask_yes_no(prompt,default=None):
234 """Asks a question and returns a boolean (y/n) answer.
241 """Asks a question and returns a boolean (y/n) answer.
235
242
236 If default is given (one of 'y','n'), it is used if the user input is
243 If default is given (one of 'y','n'), it is used if the user input is
237 empty. Otherwise the question is repeated until an answer is given.
244 empty. Otherwise the question is repeated until an answer is given.
238
245
239 An EOF is treated as the default answer. If there is no default, an
246 An EOF is treated as the default answer. If there is no default, an
240 exception is raised to prevent infinite loops.
247 exception is raised to prevent infinite loops.
241
248
242 Valid answers are: y/yes/n/no (match is not case sensitive)."""
249 Valid answers are: y/yes/n/no (match is not case sensitive)."""
243
250
244 answers = {'y':True,'n':False,'yes':True,'no':False}
251 answers = {'y':True,'n':False,'yes':True,'no':False}
245 ans = None
252 ans = None
246 while ans not in answers.keys():
253 while ans not in answers.keys():
247 try:
254 try:
248 ans = raw_input(prompt+' ').lower()
255 ans = raw_input(prompt+' ').lower()
249 if not ans: # response was an empty string
256 if not ans: # response was an empty string
250 ans = default
257 ans = default
251 except KeyboardInterrupt:
258 except KeyboardInterrupt:
252 pass
259 pass
253 except EOFError:
260 except EOFError:
254 if default in answers.keys():
261 if default in answers.keys():
255 ans = default
262 ans = default
256 print()
263 print()
257 else:
264 else:
258 raise
265 raise
259
266
260 return answers[ans]
267 return answers[ans]
261
268
262
269
263 class NLprinter:
270 class NLprinter:
264 """Print an arbitrarily nested list, indicating index numbers.
271 """Print an arbitrarily nested list, indicating index numbers.
265
272
266 An instance of this class called nlprint is available and callable as a
273 An instance of this class called nlprint is available and callable as a
267 function.
274 function.
268
275
269 nlprint(list,indent=' ',sep=': ') -> prints indenting each level by 'indent'
276 nlprint(list,indent=' ',sep=': ') -> prints indenting each level by 'indent'
270 and using 'sep' to separate the index from the value. """
277 and using 'sep' to separate the index from the value. """
271
278
272 def __init__(self):
279 def __init__(self):
273 self.depth = 0
280 self.depth = 0
274
281
275 def __call__(self,lst,pos='',**kw):
282 def __call__(self,lst,pos='',**kw):
276 """Prints the nested list numbering levels."""
283 """Prints the nested list numbering levels."""
277 kw.setdefault('indent',' ')
284 kw.setdefault('indent',' ')
278 kw.setdefault('sep',': ')
285 kw.setdefault('sep',': ')
279 kw.setdefault('start',0)
286 kw.setdefault('start',0)
280 kw.setdefault('stop',len(lst))
287 kw.setdefault('stop',len(lst))
281 # we need to remove start and stop from kw so they don't propagate
288 # we need to remove start and stop from kw so they don't propagate
282 # into a recursive call for a nested list.
289 # into a recursive call for a nested list.
283 start = kw['start']; del kw['start']
290 start = kw['start']; del kw['start']
284 stop = kw['stop']; del kw['stop']
291 stop = kw['stop']; del kw['stop']
285 if self.depth == 0 and 'header' in kw.keys():
292 if self.depth == 0 and 'header' in kw.keys():
286 print(kw['header'])
293 print(kw['header'])
287
294
288 for idx in range(start,stop):
295 for idx in range(start,stop):
289 elem = lst[idx]
296 elem = lst[idx]
290 newpos = pos + str(idx)
297 newpos = pos + str(idx)
291 if type(elem)==type([]):
298 if type(elem)==type([]):
292 self.depth += 1
299 self.depth += 1
293 self.__call__(elem, newpos+",", **kw)
300 self.__call__(elem, newpos+",", **kw)
294 self.depth -= 1
301 self.depth -= 1
295 else:
302 else:
296 print(kw['indent']*self.depth + newpos + kw["sep"] + repr(elem))
303 print(kw['indent']*self.depth + newpos + kw["sep"] + repr(elem))
297
304
298 nlprint = NLprinter()
305 nlprint = NLprinter()
299
306
300
307
301 def temp_pyfile(src, ext='.py'):
308 def temp_pyfile(src, ext='.py'):
302 """Make a temporary python file, return filename and filehandle.
309 """Make a temporary python file, return filename and filehandle.
303
310
304 Parameters
311 Parameters
305 ----------
312 ----------
306 src : string or list of strings (no need for ending newlines if list)
313 src : string or list of strings (no need for ending newlines if list)
307 Source code to be written to the file.
314 Source code to be written to the file.
308
315
309 ext : optional, string
316 ext : optional, string
310 Extension for the generated file.
317 Extension for the generated file.
311
318
312 Returns
319 Returns
313 -------
320 -------
314 (filename, open filehandle)
321 (filename, open filehandle)
315 It is the caller's responsibility to close the open file and unlink it.
322 It is the caller's responsibility to close the open file and unlink it.
316 """
323 """
317 fname = tempfile.mkstemp(ext)[1]
324 fname = tempfile.mkstemp(ext)[1]
318 f = open(fname,'w')
325 f = open(fname,'w')
319 f.write(src)
326 f.write(src)
320 f.flush()
327 f.flush()
321 return fname, f
328 return fname, f
322
329
323
330
324 def raw_print(*args, **kw):
331 def raw_print(*args, **kw):
325 """Raw print to sys.__stdout__, otherwise identical interface to print()."""
332 """Raw print to sys.__stdout__, otherwise identical interface to print()."""
326
333
327 print(*args, sep=kw.get('sep', ' '), end=kw.get('end', '\n'),
334 print(*args, sep=kw.get('sep', ' '), end=kw.get('end', '\n'),
328 file=sys.__stdout__)
335 file=sys.__stdout__)
329 sys.__stdout__.flush()
336 sys.__stdout__.flush()
330
337
331
338
332 def raw_print_err(*args, **kw):
339 def raw_print_err(*args, **kw):
333 """Raw print to sys.__stderr__, otherwise identical interface to print()."""
340 """Raw print to sys.__stderr__, otherwise identical interface to print()."""
334
341
335 print(*args, sep=kw.get('sep', ' '), end=kw.get('end', '\n'),
342 print(*args, sep=kw.get('sep', ' '), end=kw.get('end', '\n'),
336 file=sys.__stderr__)
343 file=sys.__stderr__)
337 sys.__stderr__.flush()
344 sys.__stderr__.flush()
338
345
339
346
340 # Short aliases for quick debugging, do NOT use these in production code.
347 # Short aliases for quick debugging, do NOT use these in production code.
341 rprint = raw_print
348 rprint = raw_print
342 rprinte = raw_print_err
349 rprinte = raw_print_err
343
350
344
351
345 class CapturedIO(object):
352 class CapturedIO(object):
346 """Simple object for containing captured stdout/err StringIO objects"""
353 """Simple object for containing captured stdout/err StringIO objects"""
347
354
348 def __init__(self, stdout, stderr):
355 def __init__(self, stdout, stderr):
349 self._stdout = stdout
356 self._stdout = stdout
350 self._stderr = stderr
357 self._stderr = stderr
351
358
352 def __str__(self):
359 def __str__(self):
353 return self.stdout
360 return self.stdout
354
361
355 @property
362 @property
356 def stdout(self):
363 def stdout(self):
357 if not self._stdout:
364 if not self._stdout:
358 return ''
365 return ''
359 return self._stdout.getvalue()
366 return self._stdout.getvalue()
360
367
361 @property
368 @property
362 def stderr(self):
369 def stderr(self):
363 if not self._stderr:
370 if not self._stderr:
364 return ''
371 return ''
365 return self._stderr.getvalue()
372 return self._stderr.getvalue()
366
373
367 def show(self):
374 def show(self):
368 """write my output to sys.stdout/err as appropriate"""
375 """write my output to sys.stdout/err as appropriate"""
369 sys.stdout.write(self.stdout)
376 sys.stdout.write(self.stdout)
370 sys.stderr.write(self.stderr)
377 sys.stderr.write(self.stderr)
371 sys.stdout.flush()
378 sys.stdout.flush()
372 sys.stderr.flush()
379 sys.stderr.flush()
373
380
374 __call__ = show
381 __call__ = show
375
382
376
383
377 class capture_output(object):
384 class capture_output(object):
378 """context manager for capturing stdout/err"""
385 """context manager for capturing stdout/err"""
379 stdout = True
386 stdout = True
380 stderr = True
387 stderr = True
381
388
382 def __init__(self, stdout=True, stderr=True):
389 def __init__(self, stdout=True, stderr=True):
383 self.stdout = stdout
390 self.stdout = stdout
384 self.stderr = stderr
391 self.stderr = stderr
385
392
386 def __enter__(self):
393 def __enter__(self):
387 self.sys_stdout = sys.stdout
394 self.sys_stdout = sys.stdout
388 self.sys_stderr = sys.stderr
395 self.sys_stderr = sys.stderr
389
396
390 stdout = stderr = False
397 stdout = stderr = False
391 if self.stdout:
398 if self.stdout:
392 stdout = sys.stdout = StringIO()
399 stdout = sys.stdout = StringIO()
393 if self.stderr:
400 if self.stderr:
394 stderr = sys.stderr = StringIO()
401 stderr = sys.stderr = StringIO()
395
402
396 return CapturedIO(stdout, stderr)
403 return CapturedIO(stdout, stderr)
397
404
398 def __exit__(self, exc_type, exc_value, traceback):
405 def __exit__(self, exc_type, exc_value, traceback):
399 sys.stdout = self.sys_stdout
406 sys.stdout = self.sys_stdout
400 sys.stderr = self.sys_stderr
407 sys.stderr = self.sys_stderr
401
408
402
409
General Comments 0
You need to be logged in to leave comments. Login now