##// END OF EJS Templates
merge functionality in io and openpy relating to encoding...
Jörgen Stenarson -
Show More
@@ -1,529 +1,535 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, openpy
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 try:
356 encoding, _ = openpy.detect_encoding(lambda :lines[:2].pop(0))
357 except SyntaxError:
358 encoding = "ascii"
356 start = max(start, 0)
359 start = max(start, 0)
357 start = min(start, len(lines) - context)
360 start = min(start, len(lines) - context)
358 lines = lines[start : start + context]
361 lines = lines[start : start + context]
359
362
360 for i,line in enumerate(lines):
363 for i,line in enumerate(lines):
361 show_arrow = (start + 1 + i == lineno)
364 show_arrow = (start + 1 + i == lineno)
362 linetpl = (frame is self.curframe or show_arrow) \
365 linetpl = (frame is self.curframe or show_arrow) \
363 and tpl_line_em \
366 and tpl_line_em \
364 or tpl_line
367 or tpl_line
365 ret.append(self.__format_line(linetpl, filename,
368 ret.append(self.__format_line(linetpl, filename,
366 start + 1 + i, line.decode(encoding),
369 start + 1 + i, line.decode(encoding, errors="replace"),
367 arrow = show_arrow) )
370 arrow = show_arrow) )
368 return ''.join(ret)
371 return ''.join(ret)
369
372
370 def __format_line(self, tpl_line, filename, lineno, line, arrow = False):
373 def __format_line(self, tpl_line, filename, lineno, line, arrow = False):
371 bp_mark = ""
374 bp_mark = ""
372 bp_mark_color = ""
375 bp_mark_color = ""
373
376
374 scheme = self.color_scheme_table.active_scheme_name
377 scheme = self.color_scheme_table.active_scheme_name
375 new_line, err = self.parser.format2(line, 'str', scheme)
378 new_line, err = self.parser.format2(line, 'str', scheme)
376 if not err: line = new_line
379 if not err: line = new_line
377
380
378 bp = None
381 bp = None
379 if lineno in self.get_file_breaks(filename):
382 if lineno in self.get_file_breaks(filename):
380 bps = self.get_breaks(filename, lineno)
383 bps = self.get_breaks(filename, lineno)
381 bp = bps[-1]
384 bp = bps[-1]
382
385
383 if bp:
386 if bp:
384 Colors = self.color_scheme_table.active_colors
387 Colors = self.color_scheme_table.active_colors
385 bp_mark = str(bp.number)
388 bp_mark = str(bp.number)
386 bp_mark_color = Colors.breakpoint_enabled
389 bp_mark_color = Colors.breakpoint_enabled
387 if not bp.enabled:
390 if not bp.enabled:
388 bp_mark_color = Colors.breakpoint_disabled
391 bp_mark_color = Colors.breakpoint_disabled
389
392
390 numbers_width = 7
393 numbers_width = 7
391 if arrow:
394 if arrow:
392 # This is the line with the error
395 # This is the line with the error
393 pad = numbers_width - len(str(lineno)) - len(bp_mark)
396 pad = numbers_width - len(str(lineno)) - len(bp_mark)
394 if pad >= 3:
397 if pad >= 3:
395 marker = '-'*(pad-3) + '-> '
398 marker = '-'*(pad-3) + '-> '
396 elif pad == 2:
399 elif pad == 2:
397 marker = '> '
400 marker = '> '
398 elif pad == 1:
401 elif pad == 1:
399 marker = '>'
402 marker = '>'
400 else:
403 else:
401 marker = ''
404 marker = ''
402 num = '%s%s' % (marker, str(lineno))
405 num = '%s%s' % (marker, str(lineno))
403 line = tpl_line % (bp_mark_color + bp_mark, num, line)
406 line = tpl_line % (bp_mark_color + bp_mark, num, line)
404 else:
407 else:
405 num = '%*s' % (numbers_width - len(bp_mark), str(lineno))
408 num = '%*s' % (numbers_width - len(bp_mark), str(lineno))
406 line = tpl_line % (bp_mark_color + bp_mark, num, line)
409 line = tpl_line % (bp_mark_color + bp_mark, num, line)
407
410
408 return line
411 return line
409
412
410 def list_command_pydb(self, arg):
413 def list_command_pydb(self, arg):
411 """List command to use if we have a newer pydb installed"""
414 """List command to use if we have a newer pydb installed"""
412 filename, first, last = OldPdb.parse_list_cmd(self, arg)
415 filename, first, last = OldPdb.parse_list_cmd(self, arg)
413 if filename is not None:
416 if filename is not None:
414 self.print_list_lines(filename, first, last)
417 self.print_list_lines(filename, first, last)
415
418
416 def print_list_lines(self, filename, first, last):
419 def print_list_lines(self, filename, first, last):
417 """The printing (as opposed to the parsing part of a 'list'
420 """The printing (as opposed to the parsing part of a 'list'
418 command."""
421 command."""
419 try:
422 try:
420 Colors = self.color_scheme_table.active_colors
423 Colors = self.color_scheme_table.active_colors
421 ColorsNormal = Colors.Normal
424 ColorsNormal = Colors.Normal
422 tpl_line = '%%s%s%%s %s%%s' % (Colors.lineno, ColorsNormal)
425 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)
426 tpl_line_em = '%%s%s%%s %s%%s%s' % (Colors.linenoEm, Colors.line, ColorsNormal)
424 src = []
427 src = []
425 lines = linecache.getlines(filename)
428 lines = linecache.getlines(filename)
426 encoding = io.guess_encoding(lines)
429 try:
430 encoding, _ = openpy.detect_encoding(lambda :lines[:2].pop(0))
431 except SyntaxError:
432 encoding = "ascii"
427 for lineno in range(first, last+1):
433 for lineno in range(first, last+1):
428 line = lines[lineno].decode(encoding)
434 line = lines[lineno].decode(encoding, errors="replace")
429 if not line:
435 if not line:
430 break
436 break
431
437
432 if lineno == self.curframe.f_lineno:
438 if lineno == self.curframe.f_lineno:
433 line = self.__format_line(tpl_line_em, filename, lineno, line, arrow = True)
439 line = self.__format_line(tpl_line_em, filename, lineno, line, arrow = True)
434 else:
440 else:
435 line = self.__format_line(tpl_line, filename, lineno, line, arrow = False)
441 line = self.__format_line(tpl_line, filename, lineno, line, arrow = False)
436
442
437 src.append(line)
443 src.append(line)
438 self.lineno = lineno
444 self.lineno = lineno
439
445
440 print(''.join(src), file=io.stdout)
446 print(''.join(src), file=io.stdout)
441
447
442 except KeyboardInterrupt:
448 except KeyboardInterrupt:
443 pass
449 pass
444
450
445 def do_list(self, arg):
451 def do_list(self, arg):
446 self.lastcmd = 'list'
452 self.lastcmd = 'list'
447 last = None
453 last = None
448 if arg:
454 if arg:
449 try:
455 try:
450 x = eval(arg, {}, {})
456 x = eval(arg, {}, {})
451 if type(x) == type(()):
457 if type(x) == type(()):
452 first, last = x
458 first, last = x
453 first = int(first)
459 first = int(first)
454 last = int(last)
460 last = int(last)
455 if last < first:
461 if last < first:
456 # Assume it's a count
462 # Assume it's a count
457 last = first + last
463 last = first + last
458 else:
464 else:
459 first = max(1, int(x) - 5)
465 first = max(1, int(x) - 5)
460 except:
466 except:
461 print('*** Error in argument:', repr(arg))
467 print('*** Error in argument:', repr(arg))
462 return
468 return
463 elif self.lineno is None:
469 elif self.lineno is None:
464 first = max(1, self.curframe.f_lineno - 5)
470 first = max(1, self.curframe.f_lineno - 5)
465 else:
471 else:
466 first = self.lineno + 1
472 first = self.lineno + 1
467 if last is None:
473 if last is None:
468 last = first + 10
474 last = first + 10
469 self.print_list_lines(self.curframe.f_code.co_filename, first, last)
475 self.print_list_lines(self.curframe.f_code.co_filename, first, last)
470
476
471 # vds: >>
477 # vds: >>
472 lineno = first
478 lineno = first
473 filename = self.curframe.f_code.co_filename
479 filename = self.curframe.f_code.co_filename
474 self.shell.hooks.synchronize_with_editor(filename, lineno, 0)
480 self.shell.hooks.synchronize_with_editor(filename, lineno, 0)
475 # vds: <<
481 # vds: <<
476
482
477 do_l = do_list
483 do_l = do_list
478
484
479 def do_pdef(self, arg):
485 def do_pdef(self, arg):
480 """The debugger interface to magic_pdef"""
486 """The debugger interface to magic_pdef"""
481 namespaces = [('Locals', self.curframe.f_locals),
487 namespaces = [('Locals', self.curframe.f_locals),
482 ('Globals', self.curframe.f_globals)]
488 ('Globals', self.curframe.f_globals)]
483 self.shell.find_line_magic('pdef')(arg, namespaces=namespaces)
489 self.shell.find_line_magic('pdef')(arg, namespaces=namespaces)
484
490
485 def do_pdoc(self, arg):
491 def do_pdoc(self, arg):
486 """The debugger interface to magic_pdoc"""
492 """The debugger interface to magic_pdoc"""
487 namespaces = [('Locals', self.curframe.f_locals),
493 namespaces = [('Locals', self.curframe.f_locals),
488 ('Globals', self.curframe.f_globals)]
494 ('Globals', self.curframe.f_globals)]
489 self.shell.find_line_magic('pdoc')(arg, namespaces=namespaces)
495 self.shell.find_line_magic('pdoc')(arg, namespaces=namespaces)
490
496
491 def do_pinfo(self, arg):
497 def do_pinfo(self, arg):
492 """The debugger equivalant of ?obj"""
498 """The debugger equivalant of ?obj"""
493 namespaces = [('Locals', self.curframe.f_locals),
499 namespaces = [('Locals', self.curframe.f_locals),
494 ('Globals', self.curframe.f_globals)]
500 ('Globals', self.curframe.f_globals)]
495 self.shell.find_line_magic('pinfo')("pinfo %s" % arg,
501 self.shell.find_line_magic('pinfo')("pinfo %s" % arg,
496 namespaces=namespaces)
502 namespaces=namespaces)
497
503
498 def checkline(self, filename, lineno):
504 def checkline(self, filename, lineno):
499 """Check whether specified line seems to be executable.
505 """Check whether specified line seems to be executable.
500
506
501 Return `lineno` if it is, 0 if not (e.g. a docstring, comment, blank
507 Return `lineno` if it is, 0 if not (e.g. a docstring, comment, blank
502 line or EOF). Warning: testing is not comprehensive.
508 line or EOF). Warning: testing is not comprehensive.
503 """
509 """
504 #######################################################################
510 #######################################################################
505 # XXX Hack! Use python-2.5 compatible code for this call, because with
511 # XXX Hack! Use python-2.5 compatible code for this call, because with
506 # all of our changes, we've drifted from the pdb api in 2.6. For now,
512 # all of our changes, we've drifted from the pdb api in 2.6. For now,
507 # changing:
513 # changing:
508 #
514 #
509 #line = linecache.getline(filename, lineno, self.curframe.f_globals)
515 #line = linecache.getline(filename, lineno, self.curframe.f_globals)
510 # to:
516 # to:
511 #
517 #
512 line = linecache.getline(filename, lineno)
518 line = linecache.getline(filename, lineno)
513 #
519 #
514 # does the trick. But in reality, we need to fix this by reconciling
520 # does the trick. But in reality, we need to fix this by reconciling
515 # our updates with the new Pdb APIs in Python 2.6.
521 # our updates with the new Pdb APIs in Python 2.6.
516 #
522 #
517 # End hack. The rest of this method is copied verbatim from 2.6 pdb.py
523 # End hack. The rest of this method is copied verbatim from 2.6 pdb.py
518 #######################################################################
524 #######################################################################
519
525
520 if not line:
526 if not line:
521 print('End of file', file=self.stdout)
527 print('End of file', file=self.stdout)
522 return 0
528 return 0
523 line = line.strip()
529 line = line.strip()
524 # Don't allow setting breakpoint at a blank line
530 # Don't allow setting breakpoint at a blank line
525 if (not line or (line[0] == '#') or
531 if (not line or (line[0] == '#') or
526 (line[:3] == '"""') or line[:3] == "'''"):
532 (line[:3] == '"""') or line[:3] == "'''"):
527 print('*** Blank or comment', file=self.stdout)
533 print('*** Blank or comment', file=self.stdout)
528 return 0
534 return 0
529 return lineno
535 return lineno
@@ -1,842 +1,843 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """Tools for inspecting Python objects.
2 """Tools for inspecting Python objects.
3
3
4 Uses syntax highlighting for presenting the various information elements.
4 Uses syntax highlighting for presenting the various information elements.
5
5
6 Similar in spirit to the inspect module, but all calls take a name argument to
6 Similar in spirit to the inspect module, but all calls take a name argument to
7 reference the name under which an object is being read.
7 reference the name under which an object is being read.
8 """
8 """
9
9
10 #*****************************************************************************
10 #*****************************************************************************
11 # Copyright (C) 2001-2004 Fernando Perez <fperez@colorado.edu>
11 # Copyright (C) 2001-2004 Fernando Perez <fperez@colorado.edu>
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 from __future__ import print_function
16 from __future__ import print_function
17
17
18 __all__ = ['Inspector','InspectColors']
18 __all__ = ['Inspector','InspectColors']
19
19
20 # stdlib modules
20 # stdlib modules
21 import __builtin__
21 import __builtin__
22 import inspect
22 import inspect
23 import linecache
23 import linecache
24 import os
24 import os
25 import sys
25 import sys
26 import types
26 import types
27 from collections import namedtuple
27 from collections import namedtuple
28 try:
28 try:
29 from itertools import izip_longest
29 from itertools import izip_longest
30 except ImportError:
30 except ImportError:
31 from itertools import zip_longest as izip_longest
31 from itertools import zip_longest as izip_longest
32
32
33 # IPython's own
33 # IPython's own
34 from IPython.core import page
34 from IPython.core import page
35 from IPython.testing.skipdoctest import skip_doctest_py3
35 from IPython.testing.skipdoctest import skip_doctest_py3
36 from IPython.utils import PyColorize
36 from IPython.utils import PyColorize
37 from IPython.utils import io
37 from IPython.utils import io
38 from IPython.utils import openpy
38 from IPython.utils import py3compat
39 from IPython.utils import py3compat
39 from IPython.utils.text import indent
40 from IPython.utils.text import indent
40 from IPython.utils.wildcard import list_namespace
41 from IPython.utils.wildcard import list_namespace
41 from IPython.utils.coloransi import *
42 from IPython.utils.coloransi import *
42
43
43 #****************************************************************************
44 #****************************************************************************
44 # Builtin color schemes
45 # Builtin color schemes
45
46
46 Colors = TermColors # just a shorthand
47 Colors = TermColors # just a shorthand
47
48
48 # Build a few color schemes
49 # Build a few color schemes
49 NoColor = ColorScheme(
50 NoColor = ColorScheme(
50 'NoColor',{
51 'NoColor',{
51 'header' : Colors.NoColor,
52 'header' : Colors.NoColor,
52 'normal' : Colors.NoColor # color off (usu. Colors.Normal)
53 'normal' : Colors.NoColor # color off (usu. Colors.Normal)
53 } )
54 } )
54
55
55 LinuxColors = ColorScheme(
56 LinuxColors = ColorScheme(
56 'Linux',{
57 'Linux',{
57 'header' : Colors.LightRed,
58 'header' : Colors.LightRed,
58 'normal' : Colors.Normal # color off (usu. Colors.Normal)
59 'normal' : Colors.Normal # color off (usu. Colors.Normal)
59 } )
60 } )
60
61
61 LightBGColors = ColorScheme(
62 LightBGColors = ColorScheme(
62 'LightBG',{
63 'LightBG',{
63 'header' : Colors.Red,
64 'header' : Colors.Red,
64 'normal' : Colors.Normal # color off (usu. Colors.Normal)
65 'normal' : Colors.Normal # color off (usu. Colors.Normal)
65 } )
66 } )
66
67
67 # Build table of color schemes (needed by the parser)
68 # Build table of color schemes (needed by the parser)
68 InspectColors = ColorSchemeTable([NoColor,LinuxColors,LightBGColors],
69 InspectColors = ColorSchemeTable([NoColor,LinuxColors,LightBGColors],
69 'Linux')
70 'Linux')
70
71
71 #****************************************************************************
72 #****************************************************************************
72 # Auxiliary functions and objects
73 # Auxiliary functions and objects
73
74
74 # See the messaging spec for the definition of all these fields. This list
75 # See the messaging spec for the definition of all these fields. This list
75 # effectively defines the order of display
76 # effectively defines the order of display
76 info_fields = ['type_name', 'base_class', 'string_form', 'namespace',
77 info_fields = ['type_name', 'base_class', 'string_form', 'namespace',
77 'length', 'file', 'definition', 'docstring', 'source',
78 'length', 'file', 'definition', 'docstring', 'source',
78 'init_definition', 'class_docstring', 'init_docstring',
79 'init_definition', 'class_docstring', 'init_docstring',
79 'call_def', 'call_docstring',
80 'call_def', 'call_docstring',
80 # These won't be printed but will be used to determine how to
81 # These won't be printed but will be used to determine how to
81 # format the object
82 # format the object
82 'ismagic', 'isalias', 'isclass', 'argspec', 'found', 'name'
83 'ismagic', 'isalias', 'isclass', 'argspec', 'found', 'name'
83 ]
84 ]
84
85
85
86
86 def object_info(**kw):
87 def object_info(**kw):
87 """Make an object info dict with all fields present."""
88 """Make an object info dict with all fields present."""
88 infodict = dict(izip_longest(info_fields, [None]))
89 infodict = dict(izip_longest(info_fields, [None]))
89 infodict.update(kw)
90 infodict.update(kw)
90 return infodict
91 return infodict
91
92
92
93
93 def getdoc(obj):
94 def getdoc(obj):
94 """Stable wrapper around inspect.getdoc.
95 """Stable wrapper around inspect.getdoc.
95
96
96 This can't crash because of attribute problems.
97 This can't crash because of attribute problems.
97
98
98 It also attempts to call a getdoc() method on the given object. This
99 It also attempts to call a getdoc() method on the given object. This
99 allows objects which provide their docstrings via non-standard mechanisms
100 allows objects which provide their docstrings via non-standard mechanisms
100 (like Pyro proxies) to still be inspected by ipython's ? system."""
101 (like Pyro proxies) to still be inspected by ipython's ? system."""
101 # Allow objects to offer customized documentation via a getdoc method:
102 # Allow objects to offer customized documentation via a getdoc method:
102 try:
103 try:
103 ds = obj.getdoc()
104 ds = obj.getdoc()
104 except Exception:
105 except Exception:
105 pass
106 pass
106 else:
107 else:
107 # if we get extra info, we add it to the normal docstring.
108 # if we get extra info, we add it to the normal docstring.
108 if isinstance(ds, basestring):
109 if isinstance(ds, basestring):
109 return inspect.cleandoc(ds)
110 return inspect.cleandoc(ds)
110
111
111 try:
112 try:
112 return inspect.getdoc(obj)
113 return inspect.getdoc(obj)
113 except Exception:
114 except Exception:
114 # Harden against an inspect failure, which can occur with
115 # Harden against an inspect failure, which can occur with
115 # SWIG-wrapped extensions.
116 # SWIG-wrapped extensions.
116 return None
117 return None
117
118
118
119
119 def getsource(obj,is_binary=False):
120 def getsource(obj,is_binary=False):
120 """Wrapper around inspect.getsource.
121 """Wrapper around inspect.getsource.
121
122
122 This can be modified by other projects to provide customized source
123 This can be modified by other projects to provide customized source
123 extraction.
124 extraction.
124
125
125 Inputs:
126 Inputs:
126
127
127 - obj: an object whose source code we will attempt to extract.
128 - obj: an object whose source code we will attempt to extract.
128
129
129 Optional inputs:
130 Optional inputs:
130
131
131 - is_binary: whether the object is known to come from a binary source.
132 - is_binary: whether the object is known to come from a binary source.
132 This implementation will skip returning any output for binary objects, but
133 This implementation will skip returning any output for binary objects, but
133 custom extractors may know how to meaningfully process them."""
134 custom extractors may know how to meaningfully process them."""
134
135
135 if is_binary:
136 if is_binary:
136 return None
137 return None
137 else:
138 else:
138 # get source if obj was decorated with @decorator
139 # get source if obj was decorated with @decorator
139 if hasattr(obj,"__wrapped__"):
140 if hasattr(obj,"__wrapped__"):
140 obj = obj.__wrapped__
141 obj = obj.__wrapped__
141 try:
142 try:
142 src = inspect.getsource(obj)
143 src = inspect.getsource(obj)
143 except TypeError:
144 except TypeError:
144 if hasattr(obj,'__class__'):
145 if hasattr(obj,'__class__'):
145 src = inspect.getsource(obj.__class__)
146 src = inspect.getsource(obj.__class__)
146 return src
147 return src
147
148
148 def getargspec(obj):
149 def getargspec(obj):
149 """Get the names and default values of a function's arguments.
150 """Get the names and default values of a function's arguments.
150
151
151 A tuple of four things is returned: (args, varargs, varkw, defaults).
152 A tuple of four things is returned: (args, varargs, varkw, defaults).
152 'args' is a list of the argument names (it may contain nested lists).
153 'args' is a list of the argument names (it may contain nested lists).
153 'varargs' and 'varkw' are the names of the * and ** arguments or None.
154 'varargs' and 'varkw' are the names of the * and ** arguments or None.
154 'defaults' is an n-tuple of the default values of the last n arguments.
155 'defaults' is an n-tuple of the default values of the last n arguments.
155
156
156 Modified version of inspect.getargspec from the Python Standard
157 Modified version of inspect.getargspec from the Python Standard
157 Library."""
158 Library."""
158
159
159 if inspect.isfunction(obj):
160 if inspect.isfunction(obj):
160 func_obj = obj
161 func_obj = obj
161 elif inspect.ismethod(obj):
162 elif inspect.ismethod(obj):
162 func_obj = obj.im_func
163 func_obj = obj.im_func
163 elif hasattr(obj, '__call__'):
164 elif hasattr(obj, '__call__'):
164 func_obj = obj.__call__
165 func_obj = obj.__call__
165 else:
166 else:
166 raise TypeError('arg is not a Python function')
167 raise TypeError('arg is not a Python function')
167 args, varargs, varkw = inspect.getargs(func_obj.func_code)
168 args, varargs, varkw = inspect.getargs(func_obj.func_code)
168 return args, varargs, varkw, func_obj.func_defaults
169 return args, varargs, varkw, func_obj.func_defaults
169
170
170
171
171 def format_argspec(argspec):
172 def format_argspec(argspec):
172 """Format argspect, convenience wrapper around inspect's.
173 """Format argspect, convenience wrapper around inspect's.
173
174
174 This takes a dict instead of ordered arguments and calls
175 This takes a dict instead of ordered arguments and calls
175 inspect.format_argspec with the arguments in the necessary order.
176 inspect.format_argspec with the arguments in the necessary order.
176 """
177 """
177 return inspect.formatargspec(argspec['args'], argspec['varargs'],
178 return inspect.formatargspec(argspec['args'], argspec['varargs'],
178 argspec['varkw'], argspec['defaults'])
179 argspec['varkw'], argspec['defaults'])
179
180
180
181
181 def call_tip(oinfo, format_call=True):
182 def call_tip(oinfo, format_call=True):
182 """Extract call tip data from an oinfo dict.
183 """Extract call tip data from an oinfo dict.
183
184
184 Parameters
185 Parameters
185 ----------
186 ----------
186 oinfo : dict
187 oinfo : dict
187
188
188 format_call : bool, optional
189 format_call : bool, optional
189 If True, the call line is formatted and returned as a string. If not, a
190 If True, the call line is formatted and returned as a string. If not, a
190 tuple of (name, argspec) is returned.
191 tuple of (name, argspec) is returned.
191
192
192 Returns
193 Returns
193 -------
194 -------
194 call_info : None, str or (str, dict) tuple.
195 call_info : None, str or (str, dict) tuple.
195 When format_call is True, the whole call information is formattted as a
196 When format_call is True, the whole call information is formattted as a
196 single string. Otherwise, the object's name and its argspec dict are
197 single string. Otherwise, the object's name and its argspec dict are
197 returned. If no call information is available, None is returned.
198 returned. If no call information is available, None is returned.
198
199
199 docstring : str or None
200 docstring : str or None
200 The most relevant docstring for calling purposes is returned, if
201 The most relevant docstring for calling purposes is returned, if
201 available. The priority is: call docstring for callable instances, then
202 available. The priority is: call docstring for callable instances, then
202 constructor docstring for classes, then main object's docstring otherwise
203 constructor docstring for classes, then main object's docstring otherwise
203 (regular functions).
204 (regular functions).
204 """
205 """
205 # Get call definition
206 # Get call definition
206 argspec = oinfo.get('argspec')
207 argspec = oinfo.get('argspec')
207 if argspec is None:
208 if argspec is None:
208 call_line = None
209 call_line = None
209 else:
210 else:
210 # Callable objects will have 'self' as their first argument, prune
211 # Callable objects will have 'self' as their first argument, prune
211 # it out if it's there for clarity (since users do *not* pass an
212 # it out if it's there for clarity (since users do *not* pass an
212 # extra first argument explicitly).
213 # extra first argument explicitly).
213 try:
214 try:
214 has_self = argspec['args'][0] == 'self'
215 has_self = argspec['args'][0] == 'self'
215 except (KeyError, IndexError):
216 except (KeyError, IndexError):
216 pass
217 pass
217 else:
218 else:
218 if has_self:
219 if has_self:
219 argspec['args'] = argspec['args'][1:]
220 argspec['args'] = argspec['args'][1:]
220
221
221 call_line = oinfo['name']+format_argspec(argspec)
222 call_line = oinfo['name']+format_argspec(argspec)
222
223
223 # Now get docstring.
224 # Now get docstring.
224 # The priority is: call docstring, constructor docstring, main one.
225 # The priority is: call docstring, constructor docstring, main one.
225 doc = oinfo.get('call_docstring')
226 doc = oinfo.get('call_docstring')
226 if doc is None:
227 if doc is None:
227 doc = oinfo.get('init_docstring')
228 doc = oinfo.get('init_docstring')
228 if doc is None:
229 if doc is None:
229 doc = oinfo.get('docstring','')
230 doc = oinfo.get('docstring','')
230
231
231 return call_line, doc
232 return call_line, doc
232
233
233
234
234 def find_file(obj):
235 def find_file(obj):
235 """Find the absolute path to the file where an object was defined.
236 """Find the absolute path to the file where an object was defined.
236
237
237 This is essentially a robust wrapper around `inspect.getabsfile`.
238 This is essentially a robust wrapper around `inspect.getabsfile`.
238
239
239 Returns None if no file can be found.
240 Returns None if no file can be found.
240
241
241 Parameters
242 Parameters
242 ----------
243 ----------
243 obj : any Python object
244 obj : any Python object
244
245
245 Returns
246 Returns
246 -------
247 -------
247 fname : str
248 fname : str
248 The absolute path to the file where the object was defined.
249 The absolute path to the file where the object was defined.
249 """
250 """
250 # get source if obj was decorated with @decorator
251 # get source if obj was decorated with @decorator
251 if hasattr(obj, '__wrapped__'):
252 if hasattr(obj, '__wrapped__'):
252 obj = obj.__wrapped__
253 obj = obj.__wrapped__
253
254
254 fname = None
255 fname = None
255 try:
256 try:
256 fname = inspect.getabsfile(obj)
257 fname = inspect.getabsfile(obj)
257 except TypeError:
258 except TypeError:
258 # For an instance, the file that matters is where its class was
259 # For an instance, the file that matters is where its class was
259 # declared.
260 # declared.
260 if hasattr(obj, '__class__'):
261 if hasattr(obj, '__class__'):
261 try:
262 try:
262 fname = inspect.getabsfile(obj.__class__)
263 fname = inspect.getabsfile(obj.__class__)
263 except TypeError:
264 except TypeError:
264 # Can happen for builtins
265 # Can happen for builtins
265 pass
266 pass
266 except:
267 except:
267 pass
268 pass
268 return fname
269 return fname
269
270
270
271
271 def find_source_lines(obj):
272 def find_source_lines(obj):
272 """Find the line number in a file where an object was defined.
273 """Find the line number in a file where an object was defined.
273
274
274 This is essentially a robust wrapper around `inspect.getsourcelines`.
275 This is essentially a robust wrapper around `inspect.getsourcelines`.
275
276
276 Returns None if no file can be found.
277 Returns None if no file can be found.
277
278
278 Parameters
279 Parameters
279 ----------
280 ----------
280 obj : any Python object
281 obj : any Python object
281
282
282 Returns
283 Returns
283 -------
284 -------
284 lineno : int
285 lineno : int
285 The line number where the object definition starts.
286 The line number where the object definition starts.
286 """
287 """
287 # get source if obj was decorated with @decorator
288 # get source if obj was decorated with @decorator
288 if hasattr(obj, '__wrapped__'):
289 if hasattr(obj, '__wrapped__'):
289 obj = obj.__wrapped__
290 obj = obj.__wrapped__
290
291
291 try:
292 try:
292 try:
293 try:
293 lineno = inspect.getsourcelines(obj)[1]
294 lineno = inspect.getsourcelines(obj)[1]
294 except TypeError:
295 except TypeError:
295 # For instances, try the class object like getsource() does
296 # For instances, try the class object like getsource() does
296 if hasattr(obj, '__class__'):
297 if hasattr(obj, '__class__'):
297 lineno = inspect.getsourcelines(obj.__class__)[1]
298 lineno = inspect.getsourcelines(obj.__class__)[1]
298 except:
299 except:
299 return None
300 return None
300
301
301 return lineno
302 return lineno
302
303
303
304
304 class Inspector:
305 class Inspector:
305 def __init__(self, color_table=InspectColors,
306 def __init__(self, color_table=InspectColors,
306 code_color_table=PyColorize.ANSICodeColors,
307 code_color_table=PyColorize.ANSICodeColors,
307 scheme='NoColor',
308 scheme='NoColor',
308 str_detail_level=0):
309 str_detail_level=0):
309 self.color_table = color_table
310 self.color_table = color_table
310 self.parser = PyColorize.Parser(code_color_table,out='str')
311 self.parser = PyColorize.Parser(code_color_table,out='str')
311 self.format = self.parser.format
312 self.format = self.parser.format
312 self.str_detail_level = str_detail_level
313 self.str_detail_level = str_detail_level
313 self.set_active_scheme(scheme)
314 self.set_active_scheme(scheme)
314
315
315 def _getdef(self,obj,oname=''):
316 def _getdef(self,obj,oname=''):
316 """Return the definition header for any callable object.
317 """Return the definition header for any callable object.
317
318
318 If any exception is generated, None is returned instead and the
319 If any exception is generated, None is returned instead and the
319 exception is suppressed."""
320 exception is suppressed."""
320
321
321 try:
322 try:
322 # We need a plain string here, NOT unicode!
323 # We need a plain string here, NOT unicode!
323 hdef = oname + inspect.formatargspec(*getargspec(obj))
324 hdef = oname + inspect.formatargspec(*getargspec(obj))
324 return py3compat.unicode_to_str(hdef, 'ascii')
325 return py3compat.unicode_to_str(hdef, 'ascii')
325 except:
326 except:
326 return None
327 return None
327
328
328 def __head(self,h):
329 def __head(self,h):
329 """Return a header string with proper colors."""
330 """Return a header string with proper colors."""
330 return '%s%s%s' % (self.color_table.active_colors.header,h,
331 return '%s%s%s' % (self.color_table.active_colors.header,h,
331 self.color_table.active_colors.normal)
332 self.color_table.active_colors.normal)
332
333
333 def set_active_scheme(self, scheme):
334 def set_active_scheme(self, scheme):
334 self.color_table.set_active_scheme(scheme)
335 self.color_table.set_active_scheme(scheme)
335 self.parser.color_table.set_active_scheme(scheme)
336 self.parser.color_table.set_active_scheme(scheme)
336
337
337 def noinfo(self, msg, oname):
338 def noinfo(self, msg, oname):
338 """Generic message when no information is found."""
339 """Generic message when no information is found."""
339 print('No %s found' % msg, end=' ')
340 print('No %s found' % msg, end=' ')
340 if oname:
341 if oname:
341 print('for %s' % oname)
342 print('for %s' % oname)
342 else:
343 else:
343 print()
344 print()
344
345
345 def pdef(self, obj, oname=''):
346 def pdef(self, obj, oname=''):
346 """Print the definition header for any callable object.
347 """Print the definition header for any callable object.
347
348
348 If the object is a class, print the constructor information."""
349 If the object is a class, print the constructor information."""
349
350
350 if not callable(obj):
351 if not callable(obj):
351 print('Object is not callable.')
352 print('Object is not callable.')
352 return
353 return
353
354
354 header = ''
355 header = ''
355
356
356 if inspect.isclass(obj):
357 if inspect.isclass(obj):
357 header = self.__head('Class constructor information:\n')
358 header = self.__head('Class constructor information:\n')
358 obj = obj.__init__
359 obj = obj.__init__
359 elif (not py3compat.PY3) and type(obj) is types.InstanceType:
360 elif (not py3compat.PY3) and type(obj) is types.InstanceType:
360 obj = obj.__call__
361 obj = obj.__call__
361
362
362 output = self._getdef(obj,oname)
363 output = self._getdef(obj,oname)
363 if output is None:
364 if output is None:
364 self.noinfo('definition header',oname)
365 self.noinfo('definition header',oname)
365 else:
366 else:
366 print(header,self.format(output), end=' ', file=io.stdout)
367 print(header,self.format(output), end=' ', file=io.stdout)
367
368
368 # In Python 3, all classes are new-style, so they all have __init__.
369 # In Python 3, all classes are new-style, so they all have __init__.
369 @skip_doctest_py3
370 @skip_doctest_py3
370 def pdoc(self,obj,oname='',formatter = None):
371 def pdoc(self,obj,oname='',formatter = None):
371 """Print the docstring for any object.
372 """Print the docstring for any object.
372
373
373 Optional:
374 Optional:
374 -formatter: a function to run the docstring through for specially
375 -formatter: a function to run the docstring through for specially
375 formatted docstrings.
376 formatted docstrings.
376
377
377 Examples
378 Examples
378 --------
379 --------
379
380
380 In [1]: class NoInit:
381 In [1]: class NoInit:
381 ...: pass
382 ...: pass
382
383
383 In [2]: class NoDoc:
384 In [2]: class NoDoc:
384 ...: def __init__(self):
385 ...: def __init__(self):
385 ...: pass
386 ...: pass
386
387
387 In [3]: %pdoc NoDoc
388 In [3]: %pdoc NoDoc
388 No documentation found for NoDoc
389 No documentation found for NoDoc
389
390
390 In [4]: %pdoc NoInit
391 In [4]: %pdoc NoInit
391 No documentation found for NoInit
392 No documentation found for NoInit
392
393
393 In [5]: obj = NoInit()
394 In [5]: obj = NoInit()
394
395
395 In [6]: %pdoc obj
396 In [6]: %pdoc obj
396 No documentation found for obj
397 No documentation found for obj
397
398
398 In [5]: obj2 = NoDoc()
399 In [5]: obj2 = NoDoc()
399
400
400 In [6]: %pdoc obj2
401 In [6]: %pdoc obj2
401 No documentation found for obj2
402 No documentation found for obj2
402 """
403 """
403
404
404 head = self.__head # For convenience
405 head = self.__head # For convenience
405 lines = []
406 lines = []
406 ds = getdoc(obj)
407 ds = getdoc(obj)
407 if formatter:
408 if formatter:
408 ds = formatter(ds)
409 ds = formatter(ds)
409 if ds:
410 if ds:
410 lines.append(head("Class Docstring:"))
411 lines.append(head("Class Docstring:"))
411 lines.append(indent(ds))
412 lines.append(indent(ds))
412 if inspect.isclass(obj) and hasattr(obj, '__init__'):
413 if inspect.isclass(obj) and hasattr(obj, '__init__'):
413 init_ds = getdoc(obj.__init__)
414 init_ds = getdoc(obj.__init__)
414 if init_ds is not None:
415 if init_ds is not None:
415 lines.append(head("Constructor Docstring:"))
416 lines.append(head("Constructor Docstring:"))
416 lines.append(indent(init_ds))
417 lines.append(indent(init_ds))
417 elif hasattr(obj,'__call__'):
418 elif hasattr(obj,'__call__'):
418 call_ds = getdoc(obj.__call__)
419 call_ds = getdoc(obj.__call__)
419 if call_ds:
420 if call_ds:
420 lines.append(head("Calling Docstring:"))
421 lines.append(head("Calling Docstring:"))
421 lines.append(indent(call_ds))
422 lines.append(indent(call_ds))
422
423
423 if not lines:
424 if not lines:
424 self.noinfo('documentation',oname)
425 self.noinfo('documentation',oname)
425 else:
426 else:
426 page.page('\n'.join(lines))
427 page.page('\n'.join(lines))
427
428
428 def psource(self,obj,oname=''):
429 def psource(self,obj,oname=''):
429 """Print the source code for an object."""
430 """Print the source code for an object."""
430
431
431 # Flush the source cache because inspect can return out-of-date source
432 # Flush the source cache because inspect can return out-of-date source
432 linecache.checkcache()
433 linecache.checkcache()
433 try:
434 try:
434 src = getsource(obj)
435 src = getsource(obj)
435 except:
436 except:
436 self.noinfo('source',oname)
437 self.noinfo('source',oname)
437 else:
438 else:
438 page.page(self.format(py3compat.unicode_to_str(src)))
439 page.page(self.format(py3compat.unicode_to_str(src)))
439
440
440 def pfile(self, obj, oname=''):
441 def pfile(self, obj, oname=''):
441 """Show the whole file where an object was defined."""
442 """Show the whole file where an object was defined."""
442
443
443 lineno = find_source_lines(obj)
444 lineno = find_source_lines(obj)
444 if lineno is None:
445 if lineno is None:
445 self.noinfo('file', oname)
446 self.noinfo('file', oname)
446 return
447 return
447
448
448 ofile = find_file(obj)
449 ofile = find_file(obj)
449 # run contents of file through pager starting at line where the object
450 # run contents of file through pager starting at line where the object
450 # is defined, as long as the file isn't binary and is actually on the
451 # is defined, as long as the file isn't binary and is actually on the
451 # filesystem.
452 # filesystem.
452 if ofile.endswith(('.so', '.dll', '.pyd')):
453 if ofile.endswith(('.so', '.dll', '.pyd')):
453 print('File %r is binary, not printing.' % ofile)
454 print('File %r is binary, not printing.' % ofile)
454 elif not os.path.isfile(ofile):
455 elif not os.path.isfile(ofile):
455 print('File %r does not exist, not printing.' % ofile)
456 print('File %r does not exist, not printing.' % ofile)
456 else:
457 else:
457 # Print only text files, not extension binaries. Note that
458 # Print only text files, not extension binaries. Note that
458 # getsourcelines returns lineno with 1-offset and page() uses
459 # getsourcelines returns lineno with 1-offset and page() uses
459 # 0-offset, so we must adjust.
460 # 0-offset, so we must adjust.
460 page.page(self.format(io.source_to_unicode(open(ofile).read())), lineno-1)
461 page.page(self.format(openpy.read_py_file(ofile, skip_encoding_cookie=False)), lineno - 1)
461
462
462 def _format_fields(self, fields, title_width=12):
463 def _format_fields(self, fields, title_width=12):
463 """Formats a list of fields for display.
464 """Formats a list of fields for display.
464
465
465 Parameters
466 Parameters
466 ----------
467 ----------
467 fields : list
468 fields : list
468 A list of 2-tuples: (field_title, field_content)
469 A list of 2-tuples: (field_title, field_content)
469 title_width : int
470 title_width : int
470 How many characters to pad titles to. Default 12.
471 How many characters to pad titles to. Default 12.
471 """
472 """
472 out = []
473 out = []
473 header = self.__head
474 header = self.__head
474 for title, content in fields:
475 for title, content in fields:
475 if len(content.splitlines()) > 1:
476 if len(content.splitlines()) > 1:
476 title = header(title + ":") + "\n"
477 title = header(title + ":") + "\n"
477 else:
478 else:
478 title = header((title+":").ljust(title_width))
479 title = header((title+":").ljust(title_width))
479 out.append(title + content)
480 out.append(title + content)
480 return "\n".join(out)
481 return "\n".join(out)
481
482
482 # The fields to be displayed by pinfo: (fancy_name, key_in_info_dict)
483 # The fields to be displayed by pinfo: (fancy_name, key_in_info_dict)
483 pinfo_fields1 = [("Type", "type_name"),
484 pinfo_fields1 = [("Type", "type_name"),
484 ]
485 ]
485
486
486 pinfo_fields2 = [("String Form", "string_form"),
487 pinfo_fields2 = [("String Form", "string_form"),
487 ]
488 ]
488
489
489 pinfo_fields3 = [("Length", "length"),
490 pinfo_fields3 = [("Length", "length"),
490 ("File", "file"),
491 ("File", "file"),
491 ("Definition", "definition"),
492 ("Definition", "definition"),
492 ]
493 ]
493
494
494 pinfo_fields_obj = [("Class Docstring", "class_docstring"),
495 pinfo_fields_obj = [("Class Docstring", "class_docstring"),
495 ("Constructor Docstring","init_docstring"),
496 ("Constructor Docstring","init_docstring"),
496 ("Call def", "call_def"),
497 ("Call def", "call_def"),
497 ("Call docstring", "call_docstring")]
498 ("Call docstring", "call_docstring")]
498
499
499 def pinfo(self,obj,oname='',formatter=None,info=None,detail_level=0):
500 def pinfo(self,obj,oname='',formatter=None,info=None,detail_level=0):
500 """Show detailed information about an object.
501 """Show detailed information about an object.
501
502
502 Optional arguments:
503 Optional arguments:
503
504
504 - oname: name of the variable pointing to the object.
505 - oname: name of the variable pointing to the object.
505
506
506 - formatter: special formatter for docstrings (see pdoc)
507 - formatter: special formatter for docstrings (see pdoc)
507
508
508 - info: a structure with some information fields which may have been
509 - info: a structure with some information fields which may have been
509 precomputed already.
510 precomputed already.
510
511
511 - detail_level: if set to 1, more information is given.
512 - detail_level: if set to 1, more information is given.
512 """
513 """
513 info = self.info(obj, oname=oname, formatter=formatter,
514 info = self.info(obj, oname=oname, formatter=formatter,
514 info=info, detail_level=detail_level)
515 info=info, detail_level=detail_level)
515 displayfields = []
516 displayfields = []
516 def add_fields(fields):
517 def add_fields(fields):
517 for title, key in fields:
518 for title, key in fields:
518 field = info[key]
519 field = info[key]
519 if field is not None:
520 if field is not None:
520 displayfields.append((title, field.rstrip()))
521 displayfields.append((title, field.rstrip()))
521
522
522 add_fields(self.pinfo_fields1)
523 add_fields(self.pinfo_fields1)
523
524
524 # Base class for old-style instances
525 # Base class for old-style instances
525 if (not py3compat.PY3) and isinstance(obj, types.InstanceType) and info['base_class']:
526 if (not py3compat.PY3) and isinstance(obj, types.InstanceType) and info['base_class']:
526 displayfields.append(("Base Class", info['base_class'].rstrip()))
527 displayfields.append(("Base Class", info['base_class'].rstrip()))
527
528
528 add_fields(self.pinfo_fields2)
529 add_fields(self.pinfo_fields2)
529
530
530 # Namespace
531 # Namespace
531 if info['namespace'] != 'Interactive':
532 if info['namespace'] != 'Interactive':
532 displayfields.append(("Namespace", info['namespace'].rstrip()))
533 displayfields.append(("Namespace", info['namespace'].rstrip()))
533
534
534 add_fields(self.pinfo_fields3)
535 add_fields(self.pinfo_fields3)
535
536
536 # Source or docstring, depending on detail level and whether
537 # Source or docstring, depending on detail level and whether
537 # source found.
538 # source found.
538 if detail_level > 0 and info['source'] is not None:
539 if detail_level > 0 and info['source'] is not None:
539 displayfields.append(("Source", self.format(py3compat.cast_bytes_py2(info['source']))))
540 displayfields.append(("Source", self.format(py3compat.cast_bytes_py2(info['source']))))
540 elif info['docstring'] is not None:
541 elif info['docstring'] is not None:
541 displayfields.append(("Docstring", info["docstring"]))
542 displayfields.append(("Docstring", info["docstring"]))
542
543
543 # Constructor info for classes
544 # Constructor info for classes
544 if info['isclass']:
545 if info['isclass']:
545 if info['init_definition'] or info['init_docstring']:
546 if info['init_definition'] or info['init_docstring']:
546 displayfields.append(("Constructor information", ""))
547 displayfields.append(("Constructor information", ""))
547 if info['init_definition'] is not None:
548 if info['init_definition'] is not None:
548 displayfields.append((" Definition",
549 displayfields.append((" Definition",
549 info['init_definition'].rstrip()))
550 info['init_definition'].rstrip()))
550 if info['init_docstring'] is not None:
551 if info['init_docstring'] is not None:
551 displayfields.append((" Docstring",
552 displayfields.append((" Docstring",
552 indent(info['init_docstring'])))
553 indent(info['init_docstring'])))
553
554
554 # Info for objects:
555 # Info for objects:
555 else:
556 else:
556 add_fields(self.pinfo_fields_obj)
557 add_fields(self.pinfo_fields_obj)
557
558
558 # Finally send to printer/pager:
559 # Finally send to printer/pager:
559 if displayfields:
560 if displayfields:
560 page.page(self._format_fields(displayfields))
561 page.page(self._format_fields(displayfields))
561
562
562 def info(self, obj, oname='', formatter=None, info=None, detail_level=0):
563 def info(self, obj, oname='', formatter=None, info=None, detail_level=0):
563 """Compute a dict with detailed information about an object.
564 """Compute a dict with detailed information about an object.
564
565
565 Optional arguments:
566 Optional arguments:
566
567
567 - oname: name of the variable pointing to the object.
568 - oname: name of the variable pointing to the object.
568
569
569 - formatter: special formatter for docstrings (see pdoc)
570 - formatter: special formatter for docstrings (see pdoc)
570
571
571 - info: a structure with some information fields which may have been
572 - info: a structure with some information fields which may have been
572 precomputed already.
573 precomputed already.
573
574
574 - detail_level: if set to 1, more information is given.
575 - detail_level: if set to 1, more information is given.
575 """
576 """
576
577
577 obj_type = type(obj)
578 obj_type = type(obj)
578
579
579 header = self.__head
580 header = self.__head
580 if info is None:
581 if info is None:
581 ismagic = 0
582 ismagic = 0
582 isalias = 0
583 isalias = 0
583 ospace = ''
584 ospace = ''
584 else:
585 else:
585 ismagic = info.ismagic
586 ismagic = info.ismagic
586 isalias = info.isalias
587 isalias = info.isalias
587 ospace = info.namespace
588 ospace = info.namespace
588
589
589 # Get docstring, special-casing aliases:
590 # Get docstring, special-casing aliases:
590 if isalias:
591 if isalias:
591 if not callable(obj):
592 if not callable(obj):
592 try:
593 try:
593 ds = "Alias to the system command:\n %s" % obj[1]
594 ds = "Alias to the system command:\n %s" % obj[1]
594 except:
595 except:
595 ds = "Alias: " + str(obj)
596 ds = "Alias: " + str(obj)
596 else:
597 else:
597 ds = "Alias to " + str(obj)
598 ds = "Alias to " + str(obj)
598 if obj.__doc__:
599 if obj.__doc__:
599 ds += "\nDocstring:\n" + obj.__doc__
600 ds += "\nDocstring:\n" + obj.__doc__
600 else:
601 else:
601 ds = getdoc(obj)
602 ds = getdoc(obj)
602 if ds is None:
603 if ds is None:
603 ds = '<no docstring>'
604 ds = '<no docstring>'
604 if formatter is not None:
605 if formatter is not None:
605 ds = formatter(ds)
606 ds = formatter(ds)
606
607
607 # store output in a dict, we initialize it here and fill it as we go
608 # store output in a dict, we initialize it here and fill it as we go
608 out = dict(name=oname, found=True, isalias=isalias, ismagic=ismagic)
609 out = dict(name=oname, found=True, isalias=isalias, ismagic=ismagic)
609
610
610 string_max = 200 # max size of strings to show (snipped if longer)
611 string_max = 200 # max size of strings to show (snipped if longer)
611 shalf = int((string_max -5)/2)
612 shalf = int((string_max -5)/2)
612
613
613 if ismagic:
614 if ismagic:
614 obj_type_name = 'Magic function'
615 obj_type_name = 'Magic function'
615 elif isalias:
616 elif isalias:
616 obj_type_name = 'System alias'
617 obj_type_name = 'System alias'
617 else:
618 else:
618 obj_type_name = obj_type.__name__
619 obj_type_name = obj_type.__name__
619 out['type_name'] = obj_type_name
620 out['type_name'] = obj_type_name
620
621
621 try:
622 try:
622 bclass = obj.__class__
623 bclass = obj.__class__
623 out['base_class'] = str(bclass)
624 out['base_class'] = str(bclass)
624 except: pass
625 except: pass
625
626
626 # String form, but snip if too long in ? form (full in ??)
627 # String form, but snip if too long in ? form (full in ??)
627 if detail_level >= self.str_detail_level:
628 if detail_level >= self.str_detail_level:
628 try:
629 try:
629 ostr = str(obj)
630 ostr = str(obj)
630 str_head = 'string_form'
631 str_head = 'string_form'
631 if not detail_level and len(ostr)>string_max:
632 if not detail_level and len(ostr)>string_max:
632 ostr = ostr[:shalf] + ' <...> ' + ostr[-shalf:]
633 ostr = ostr[:shalf] + ' <...> ' + ostr[-shalf:]
633 ostr = ("\n" + " " * len(str_head.expandtabs())).\
634 ostr = ("\n" + " " * len(str_head.expandtabs())).\
634 join(q.strip() for q in ostr.split("\n"))
635 join(q.strip() for q in ostr.split("\n"))
635 out[str_head] = ostr
636 out[str_head] = ostr
636 except:
637 except:
637 pass
638 pass
638
639
639 if ospace:
640 if ospace:
640 out['namespace'] = ospace
641 out['namespace'] = ospace
641
642
642 # Length (for strings and lists)
643 # Length (for strings and lists)
643 try:
644 try:
644 out['length'] = str(len(obj))
645 out['length'] = str(len(obj))
645 except: pass
646 except: pass
646
647
647 # Filename where object was defined
648 # Filename where object was defined
648 binary_file = False
649 binary_file = False
649 fname = find_file(obj)
650 fname = find_file(obj)
650 if fname is None:
651 if fname is None:
651 # if anything goes wrong, we don't want to show source, so it's as
652 # if anything goes wrong, we don't want to show source, so it's as
652 # if the file was binary
653 # if the file was binary
653 binary_file = True
654 binary_file = True
654 else:
655 else:
655 if fname.endswith(('.so', '.dll', '.pyd')):
656 if fname.endswith(('.so', '.dll', '.pyd')):
656 binary_file = True
657 binary_file = True
657 elif fname.endswith('<string>'):
658 elif fname.endswith('<string>'):
658 fname = 'Dynamically generated function. No source code available.'
659 fname = 'Dynamically generated function. No source code available.'
659 out['file'] = fname
660 out['file'] = fname
660
661
661 # reconstruct the function definition and print it:
662 # reconstruct the function definition and print it:
662 defln = self._getdef(obj, oname)
663 defln = self._getdef(obj, oname)
663 if defln:
664 if defln:
664 out['definition'] = self.format(defln)
665 out['definition'] = self.format(defln)
665
666
666 # Docstrings only in detail 0 mode, since source contains them (we
667 # Docstrings only in detail 0 mode, since source contains them (we
667 # avoid repetitions). If source fails, we add them back, see below.
668 # avoid repetitions). If source fails, we add them back, see below.
668 if ds and detail_level == 0:
669 if ds and detail_level == 0:
669 out['docstring'] = ds
670 out['docstring'] = ds
670
671
671 # Original source code for any callable
672 # Original source code for any callable
672 if detail_level:
673 if detail_level:
673 # Flush the source cache because inspect can return out-of-date
674 # Flush the source cache because inspect can return out-of-date
674 # source
675 # source
675 linecache.checkcache()
676 linecache.checkcache()
676 source = None
677 source = None
677 try:
678 try:
678 try:
679 try:
679 source = getsource(obj, binary_file)
680 source = getsource(obj, binary_file)
680 except TypeError:
681 except TypeError:
681 if hasattr(obj, '__class__'):
682 if hasattr(obj, '__class__'):
682 source = getsource(obj.__class__, binary_file)
683 source = getsource(obj.__class__, binary_file)
683 if source is not None:
684 if source is not None:
684 out['source'] = source.rstrip()
685 out['source'] = source.rstrip()
685 except Exception:
686 except Exception:
686 pass
687 pass
687
688
688 if ds and source is None:
689 if ds and source is None:
689 out['docstring'] = ds
690 out['docstring'] = ds
690
691
691
692
692 # Constructor docstring for classes
693 # Constructor docstring for classes
693 if inspect.isclass(obj):
694 if inspect.isclass(obj):
694 out['isclass'] = True
695 out['isclass'] = True
695 # reconstruct the function definition and print it:
696 # reconstruct the function definition and print it:
696 try:
697 try:
697 obj_init = obj.__init__
698 obj_init = obj.__init__
698 except AttributeError:
699 except AttributeError:
699 init_def = init_ds = None
700 init_def = init_ds = None
700 else:
701 else:
701 init_def = self._getdef(obj_init,oname)
702 init_def = self._getdef(obj_init,oname)
702 init_ds = getdoc(obj_init)
703 init_ds = getdoc(obj_init)
703 # Skip Python's auto-generated docstrings
704 # Skip Python's auto-generated docstrings
704 if init_ds and \
705 if init_ds and \
705 init_ds.startswith('x.__init__(...) initializes'):
706 init_ds.startswith('x.__init__(...) initializes'):
706 init_ds = None
707 init_ds = None
707
708
708 if init_def or init_ds:
709 if init_def or init_ds:
709 if init_def:
710 if init_def:
710 out['init_definition'] = self.format(init_def)
711 out['init_definition'] = self.format(init_def)
711 if init_ds:
712 if init_ds:
712 out['init_docstring'] = init_ds
713 out['init_docstring'] = init_ds
713
714
714 # and class docstring for instances:
715 # and class docstring for instances:
715 else:
716 else:
716 # First, check whether the instance docstring is identical to the
717 # First, check whether the instance docstring is identical to the
717 # class one, and print it separately if they don't coincide. In
718 # class one, and print it separately if they don't coincide. In
718 # most cases they will, but it's nice to print all the info for
719 # most cases they will, but it's nice to print all the info for
719 # objects which use instance-customized docstrings.
720 # objects which use instance-customized docstrings.
720 if ds:
721 if ds:
721 try:
722 try:
722 cls = getattr(obj,'__class__')
723 cls = getattr(obj,'__class__')
723 except:
724 except:
724 class_ds = None
725 class_ds = None
725 else:
726 else:
726 class_ds = getdoc(cls)
727 class_ds = getdoc(cls)
727 # Skip Python's auto-generated docstrings
728 # Skip Python's auto-generated docstrings
728 if class_ds and \
729 if class_ds and \
729 (class_ds.startswith('function(code, globals[,') or \
730 (class_ds.startswith('function(code, globals[,') or \
730 class_ds.startswith('instancemethod(function, instance,') or \
731 class_ds.startswith('instancemethod(function, instance,') or \
731 class_ds.startswith('module(name[,') ):
732 class_ds.startswith('module(name[,') ):
732 class_ds = None
733 class_ds = None
733 if class_ds and ds != class_ds:
734 if class_ds and ds != class_ds:
734 out['class_docstring'] = class_ds
735 out['class_docstring'] = class_ds
735
736
736 # Next, try to show constructor docstrings
737 # Next, try to show constructor docstrings
737 try:
738 try:
738 init_ds = getdoc(obj.__init__)
739 init_ds = getdoc(obj.__init__)
739 # Skip Python's auto-generated docstrings
740 # Skip Python's auto-generated docstrings
740 if init_ds and \
741 if init_ds and \
741 init_ds.startswith('x.__init__(...) initializes'):
742 init_ds.startswith('x.__init__(...) initializes'):
742 init_ds = None
743 init_ds = None
743 except AttributeError:
744 except AttributeError:
744 init_ds = None
745 init_ds = None
745 if init_ds:
746 if init_ds:
746 out['init_docstring'] = init_ds
747 out['init_docstring'] = init_ds
747
748
748 # Call form docstring for callable instances
749 # Call form docstring for callable instances
749 if hasattr(obj, '__call__'):
750 if hasattr(obj, '__call__'):
750 call_def = self._getdef(obj.__call__, oname)
751 call_def = self._getdef(obj.__call__, oname)
751 if call_def is not None:
752 if call_def is not None:
752 out['call_def'] = self.format(call_def)
753 out['call_def'] = self.format(call_def)
753 call_ds = getdoc(obj.__call__)
754 call_ds = getdoc(obj.__call__)
754 # Skip Python's auto-generated docstrings
755 # Skip Python's auto-generated docstrings
755 if call_ds and call_ds.startswith('x.__call__(...) <==> x(...)'):
756 if call_ds and call_ds.startswith('x.__call__(...) <==> x(...)'):
756 call_ds = None
757 call_ds = None
757 if call_ds:
758 if call_ds:
758 out['call_docstring'] = call_ds
759 out['call_docstring'] = call_ds
759
760
760 # Compute the object's argspec as a callable. The key is to decide
761 # Compute the object's argspec as a callable. The key is to decide
761 # whether to pull it from the object itself, from its __init__ or
762 # whether to pull it from the object itself, from its __init__ or
762 # from its __call__ method.
763 # from its __call__ method.
763
764
764 if inspect.isclass(obj):
765 if inspect.isclass(obj):
765 # Old-style classes need not have an __init__
766 # Old-style classes need not have an __init__
766 callable_obj = getattr(obj, "__init__", None)
767 callable_obj = getattr(obj, "__init__", None)
767 elif callable(obj):
768 elif callable(obj):
768 callable_obj = obj
769 callable_obj = obj
769 else:
770 else:
770 callable_obj = None
771 callable_obj = None
771
772
772 if callable_obj:
773 if callable_obj:
773 try:
774 try:
774 args, varargs, varkw, defaults = getargspec(callable_obj)
775 args, varargs, varkw, defaults = getargspec(callable_obj)
775 except (TypeError, AttributeError):
776 except (TypeError, AttributeError):
776 # For extensions/builtins we can't retrieve the argspec
777 # For extensions/builtins we can't retrieve the argspec
777 pass
778 pass
778 else:
779 else:
779 out['argspec'] = dict(args=args, varargs=varargs,
780 out['argspec'] = dict(args=args, varargs=varargs,
780 varkw=varkw, defaults=defaults)
781 varkw=varkw, defaults=defaults)
781
782
782 return object_info(**out)
783 return object_info(**out)
783
784
784
785
785 def psearch(self,pattern,ns_table,ns_search=[],
786 def psearch(self,pattern,ns_table,ns_search=[],
786 ignore_case=False,show_all=False):
787 ignore_case=False,show_all=False):
787 """Search namespaces with wildcards for objects.
788 """Search namespaces with wildcards for objects.
788
789
789 Arguments:
790 Arguments:
790
791
791 - pattern: string containing shell-like wildcards to use in namespace
792 - pattern: string containing shell-like wildcards to use in namespace
792 searches and optionally a type specification to narrow the search to
793 searches and optionally a type specification to narrow the search to
793 objects of that type.
794 objects of that type.
794
795
795 - ns_table: dict of name->namespaces for search.
796 - ns_table: dict of name->namespaces for search.
796
797
797 Optional arguments:
798 Optional arguments:
798
799
799 - ns_search: list of namespace names to include in search.
800 - ns_search: list of namespace names to include in search.
800
801
801 - ignore_case(False): make the search case-insensitive.
802 - ignore_case(False): make the search case-insensitive.
802
803
803 - show_all(False): show all names, including those starting with
804 - show_all(False): show all names, including those starting with
804 underscores.
805 underscores.
805 """
806 """
806 #print 'ps pattern:<%r>' % pattern # dbg
807 #print 'ps pattern:<%r>' % pattern # dbg
807
808
808 # defaults
809 # defaults
809 type_pattern = 'all'
810 type_pattern = 'all'
810 filter = ''
811 filter = ''
811
812
812 cmds = pattern.split()
813 cmds = pattern.split()
813 len_cmds = len(cmds)
814 len_cmds = len(cmds)
814 if len_cmds == 1:
815 if len_cmds == 1:
815 # Only filter pattern given
816 # Only filter pattern given
816 filter = cmds[0]
817 filter = cmds[0]
817 elif len_cmds == 2:
818 elif len_cmds == 2:
818 # Both filter and type specified
819 # Both filter and type specified
819 filter,type_pattern = cmds
820 filter,type_pattern = cmds
820 else:
821 else:
821 raise ValueError('invalid argument string for psearch: <%s>' %
822 raise ValueError('invalid argument string for psearch: <%s>' %
822 pattern)
823 pattern)
823
824
824 # filter search namespaces
825 # filter search namespaces
825 for name in ns_search:
826 for name in ns_search:
826 if name not in ns_table:
827 if name not in ns_table:
827 raise ValueError('invalid namespace <%s>. Valid names: %s' %
828 raise ValueError('invalid namespace <%s>. Valid names: %s' %
828 (name,ns_table.keys()))
829 (name,ns_table.keys()))
829
830
830 #print 'type_pattern:',type_pattern # dbg
831 #print 'type_pattern:',type_pattern # dbg
831 search_result, namespaces_seen = set(), set()
832 search_result, namespaces_seen = set(), set()
832 for ns_name in ns_search:
833 for ns_name in ns_search:
833 ns = ns_table[ns_name]
834 ns = ns_table[ns_name]
834 # Normally, locals and globals are the same, so we just check one.
835 # Normally, locals and globals are the same, so we just check one.
835 if id(ns) in namespaces_seen:
836 if id(ns) in namespaces_seen:
836 continue
837 continue
837 namespaces_seen.add(id(ns))
838 namespaces_seen.add(id(ns))
838 tmp_res = list_namespace(ns, type_pattern, filter,
839 tmp_res = list_namespace(ns, type_pattern, filter,
839 ignore_case=ignore_case, show_all=show_all)
840 ignore_case=ignore_case, show_all=show_all)
840 search_result.update(tmp_res)
841 search_result.update(tmp_res)
841
842
842 page.page('\n'.join(sorted(search_result)))
843 page.page('\n'.join(sorted(search_result)))
@@ -1,409 +1,385 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 guess_encoding(lines):
159 """check list of lines for line matching the source code encoding pattern
160
161 Only check first two lines
162 """
163 reg = re.compile("#.*coding[:=]\s*([-\w.]+)")
164 for row in lines[:2]: #We only need to check the first two lines
165 result = reg.match(row)
166 if result:
167 coding = result.groups()[0]
168 break
169 else:
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))
179 return txt.decode(coding, errors="replace")
180
181
182 def file_read(filename):
158 def file_read(filename):
183 """Read a file and close it. Returns the file source."""
159 """Read a file and close it. Returns the file source."""
184 fobj = open(filename,'r');
160 fobj = open(filename,'r');
185 source = fobj.read();
161 source = fobj.read();
186 fobj.close()
162 fobj.close()
187 return source
163 return source
188
164
189
165
190 def file_readlines(filename):
166 def file_readlines(filename):
191 """Read a file and close it. Returns the file source using readlines()."""
167 """Read a file and close it. Returns the file source using readlines()."""
192 fobj = open(filename,'r');
168 fobj = open(filename,'r');
193 lines = fobj.readlines();
169 lines = fobj.readlines();
194 fobj.close()
170 fobj.close()
195 return lines
171 return lines
196
172
197
173
198 def raw_input_multi(header='', ps1='==> ', ps2='..> ',terminate_str = '.'):
174 def raw_input_multi(header='', ps1='==> ', ps2='..> ',terminate_str = '.'):
199 """Take multiple lines of input.
175 """Take multiple lines of input.
200
176
201 A list with each line of input as a separate element is returned when a
177 A list with each line of input as a separate element is returned when a
202 termination string is entered (defaults to a single '.'). Input can also
178 termination string is entered (defaults to a single '.'). Input can also
203 terminate via EOF (^D in Unix, ^Z-RET in Windows).
179 terminate via EOF (^D in Unix, ^Z-RET in Windows).
204
180
205 Lines of input which end in \\ are joined into single entries (and a
181 Lines of input which end in \\ are joined into single entries (and a
206 secondary continuation prompt is issued as long as the user terminates
182 secondary continuation prompt is issued as long as the user terminates
207 lines with \\). This allows entering very long strings which are still
183 lines with \\). This allows entering very long strings which are still
208 meant to be treated as single entities.
184 meant to be treated as single entities.
209 """
185 """
210
186
211 try:
187 try:
212 if header:
188 if header:
213 header += '\n'
189 header += '\n'
214 lines = [raw_input(header + ps1)]
190 lines = [raw_input(header + ps1)]
215 except EOFError:
191 except EOFError:
216 return []
192 return []
217 terminate = [terminate_str]
193 terminate = [terminate_str]
218 try:
194 try:
219 while lines[-1:] != terminate:
195 while lines[-1:] != terminate:
220 new_line = raw_input(ps1)
196 new_line = raw_input(ps1)
221 while new_line.endswith('\\'):
197 while new_line.endswith('\\'):
222 new_line = new_line[:-1] + raw_input(ps2)
198 new_line = new_line[:-1] + raw_input(ps2)
223 lines.append(new_line)
199 lines.append(new_line)
224
200
225 return lines[:-1] # don't return the termination command
201 return lines[:-1] # don't return the termination command
226 except EOFError:
202 except EOFError:
227 print()
203 print()
228 return lines
204 return lines
229
205
230
206
231 def raw_input_ext(prompt='', ps2='... '):
207 def raw_input_ext(prompt='', ps2='... '):
232 """Similar to raw_input(), but accepts extended lines if input ends with \\."""
208 """Similar to raw_input(), but accepts extended lines if input ends with \\."""
233
209
234 line = raw_input(prompt)
210 line = raw_input(prompt)
235 while line.endswith('\\'):
211 while line.endswith('\\'):
236 line = line[:-1] + raw_input(ps2)
212 line = line[:-1] + raw_input(ps2)
237 return line
213 return line
238
214
239
215
240 def ask_yes_no(prompt,default=None):
216 def ask_yes_no(prompt,default=None):
241 """Asks a question and returns a boolean (y/n) answer.
217 """Asks a question and returns a boolean (y/n) answer.
242
218
243 If default is given (one of 'y','n'), it is used if the user input is
219 If default is given (one of 'y','n'), it is used if the user input is
244 empty. Otherwise the question is repeated until an answer is given.
220 empty. Otherwise the question is repeated until an answer is given.
245
221
246 An EOF is treated as the default answer. If there is no default, an
222 An EOF is treated as the default answer. If there is no default, an
247 exception is raised to prevent infinite loops.
223 exception is raised to prevent infinite loops.
248
224
249 Valid answers are: y/yes/n/no (match is not case sensitive)."""
225 Valid answers are: y/yes/n/no (match is not case sensitive)."""
250
226
251 answers = {'y':True,'n':False,'yes':True,'no':False}
227 answers = {'y':True,'n':False,'yes':True,'no':False}
252 ans = None
228 ans = None
253 while ans not in answers.keys():
229 while ans not in answers.keys():
254 try:
230 try:
255 ans = raw_input(prompt+' ').lower()
231 ans = raw_input(prompt+' ').lower()
256 if not ans: # response was an empty string
232 if not ans: # response was an empty string
257 ans = default
233 ans = default
258 except KeyboardInterrupt:
234 except KeyboardInterrupt:
259 pass
235 pass
260 except EOFError:
236 except EOFError:
261 if default in answers.keys():
237 if default in answers.keys():
262 ans = default
238 ans = default
263 print()
239 print()
264 else:
240 else:
265 raise
241 raise
266
242
267 return answers[ans]
243 return answers[ans]
268
244
269
245
270 class NLprinter:
246 class NLprinter:
271 """Print an arbitrarily nested list, indicating index numbers.
247 """Print an arbitrarily nested list, indicating index numbers.
272
248
273 An instance of this class called nlprint is available and callable as a
249 An instance of this class called nlprint is available and callable as a
274 function.
250 function.
275
251
276 nlprint(list,indent=' ',sep=': ') -> prints indenting each level by 'indent'
252 nlprint(list,indent=' ',sep=': ') -> prints indenting each level by 'indent'
277 and using 'sep' to separate the index from the value. """
253 and using 'sep' to separate the index from the value. """
278
254
279 def __init__(self):
255 def __init__(self):
280 self.depth = 0
256 self.depth = 0
281
257
282 def __call__(self,lst,pos='',**kw):
258 def __call__(self,lst,pos='',**kw):
283 """Prints the nested list numbering levels."""
259 """Prints the nested list numbering levels."""
284 kw.setdefault('indent',' ')
260 kw.setdefault('indent',' ')
285 kw.setdefault('sep',': ')
261 kw.setdefault('sep',': ')
286 kw.setdefault('start',0)
262 kw.setdefault('start',0)
287 kw.setdefault('stop',len(lst))
263 kw.setdefault('stop',len(lst))
288 # we need to remove start and stop from kw so they don't propagate
264 # we need to remove start and stop from kw so they don't propagate
289 # into a recursive call for a nested list.
265 # into a recursive call for a nested list.
290 start = kw['start']; del kw['start']
266 start = kw['start']; del kw['start']
291 stop = kw['stop']; del kw['stop']
267 stop = kw['stop']; del kw['stop']
292 if self.depth == 0 and 'header' in kw.keys():
268 if self.depth == 0 and 'header' in kw.keys():
293 print(kw['header'])
269 print(kw['header'])
294
270
295 for idx in range(start,stop):
271 for idx in range(start,stop):
296 elem = lst[idx]
272 elem = lst[idx]
297 newpos = pos + str(idx)
273 newpos = pos + str(idx)
298 if type(elem)==type([]):
274 if type(elem)==type([]):
299 self.depth += 1
275 self.depth += 1
300 self.__call__(elem, newpos+",", **kw)
276 self.__call__(elem, newpos+",", **kw)
301 self.depth -= 1
277 self.depth -= 1
302 else:
278 else:
303 print(kw['indent']*self.depth + newpos + kw["sep"] + repr(elem))
279 print(kw['indent']*self.depth + newpos + kw["sep"] + repr(elem))
304
280
305 nlprint = NLprinter()
281 nlprint = NLprinter()
306
282
307
283
308 def temp_pyfile(src, ext='.py'):
284 def temp_pyfile(src, ext='.py'):
309 """Make a temporary python file, return filename and filehandle.
285 """Make a temporary python file, return filename and filehandle.
310
286
311 Parameters
287 Parameters
312 ----------
288 ----------
313 src : string or list of strings (no need for ending newlines if list)
289 src : string or list of strings (no need for ending newlines if list)
314 Source code to be written to the file.
290 Source code to be written to the file.
315
291
316 ext : optional, string
292 ext : optional, string
317 Extension for the generated file.
293 Extension for the generated file.
318
294
319 Returns
295 Returns
320 -------
296 -------
321 (filename, open filehandle)
297 (filename, open filehandle)
322 It is the caller's responsibility to close the open file and unlink it.
298 It is the caller's responsibility to close the open file and unlink it.
323 """
299 """
324 fname = tempfile.mkstemp(ext)[1]
300 fname = tempfile.mkstemp(ext)[1]
325 f = open(fname,'w')
301 f = open(fname,'w')
326 f.write(src)
302 f.write(src)
327 f.flush()
303 f.flush()
328 return fname, f
304 return fname, f
329
305
330
306
331 def raw_print(*args, **kw):
307 def raw_print(*args, **kw):
332 """Raw print to sys.__stdout__, otherwise identical interface to print()."""
308 """Raw print to sys.__stdout__, otherwise identical interface to print()."""
333
309
334 print(*args, sep=kw.get('sep', ' '), end=kw.get('end', '\n'),
310 print(*args, sep=kw.get('sep', ' '), end=kw.get('end', '\n'),
335 file=sys.__stdout__)
311 file=sys.__stdout__)
336 sys.__stdout__.flush()
312 sys.__stdout__.flush()
337
313
338
314
339 def raw_print_err(*args, **kw):
315 def raw_print_err(*args, **kw):
340 """Raw print to sys.__stderr__, otherwise identical interface to print()."""
316 """Raw print to sys.__stderr__, otherwise identical interface to print()."""
341
317
342 print(*args, sep=kw.get('sep', ' '), end=kw.get('end', '\n'),
318 print(*args, sep=kw.get('sep', ' '), end=kw.get('end', '\n'),
343 file=sys.__stderr__)
319 file=sys.__stderr__)
344 sys.__stderr__.flush()
320 sys.__stderr__.flush()
345
321
346
322
347 # Short aliases for quick debugging, do NOT use these in production code.
323 # Short aliases for quick debugging, do NOT use these in production code.
348 rprint = raw_print
324 rprint = raw_print
349 rprinte = raw_print_err
325 rprinte = raw_print_err
350
326
351
327
352 class CapturedIO(object):
328 class CapturedIO(object):
353 """Simple object for containing captured stdout/err StringIO objects"""
329 """Simple object for containing captured stdout/err StringIO objects"""
354
330
355 def __init__(self, stdout, stderr):
331 def __init__(self, stdout, stderr):
356 self._stdout = stdout
332 self._stdout = stdout
357 self._stderr = stderr
333 self._stderr = stderr
358
334
359 def __str__(self):
335 def __str__(self):
360 return self.stdout
336 return self.stdout
361
337
362 @property
338 @property
363 def stdout(self):
339 def stdout(self):
364 if not self._stdout:
340 if not self._stdout:
365 return ''
341 return ''
366 return self._stdout.getvalue()
342 return self._stdout.getvalue()
367
343
368 @property
344 @property
369 def stderr(self):
345 def stderr(self):
370 if not self._stderr:
346 if not self._stderr:
371 return ''
347 return ''
372 return self._stderr.getvalue()
348 return self._stderr.getvalue()
373
349
374 def show(self):
350 def show(self):
375 """write my output to sys.stdout/err as appropriate"""
351 """write my output to sys.stdout/err as appropriate"""
376 sys.stdout.write(self.stdout)
352 sys.stdout.write(self.stdout)
377 sys.stderr.write(self.stderr)
353 sys.stderr.write(self.stderr)
378 sys.stdout.flush()
354 sys.stdout.flush()
379 sys.stderr.flush()
355 sys.stderr.flush()
380
356
381 __call__ = show
357 __call__ = show
382
358
383
359
384 class capture_output(object):
360 class capture_output(object):
385 """context manager for capturing stdout/err"""
361 """context manager for capturing stdout/err"""
386 stdout = True
362 stdout = True
387 stderr = True
363 stderr = True
388
364
389 def __init__(self, stdout=True, stderr=True):
365 def __init__(self, stdout=True, stderr=True):
390 self.stdout = stdout
366 self.stdout = stdout
391 self.stderr = stderr
367 self.stderr = stderr
392
368
393 def __enter__(self):
369 def __enter__(self):
394 self.sys_stdout = sys.stdout
370 self.sys_stdout = sys.stdout
395 self.sys_stderr = sys.stderr
371 self.sys_stderr = sys.stderr
396
372
397 stdout = stderr = False
373 stdout = stderr = False
398 if self.stdout:
374 if self.stdout:
399 stdout = sys.stdout = StringIO()
375 stdout = sys.stdout = StringIO()
400 if self.stderr:
376 if self.stderr:
401 stderr = sys.stderr = StringIO()
377 stderr = sys.stderr = StringIO()
402
378
403 return CapturedIO(stdout, stderr)
379 return CapturedIO(stdout, stderr)
404
380
405 def __exit__(self, exc_type, exc_value, traceback):
381 def __exit__(self, exc_type, exc_value, traceback):
406 sys.stdout = self.sys_stdout
382 sys.stdout = self.sys_stdout
407 sys.stderr = self.sys_stderr
383 sys.stderr = self.sys_stderr
408
384
409
385
@@ -1,192 +1,204 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
10 from io import TextIOWrapper
11 import re
11 import re
12 from StringIO import StringIO
12 import urllib
13 import urllib
13
14
14 cookie_re = re.compile(ur"coding[:=]\s*([-\w.]+)", re.UNICODE)
15 cookie_re = re.compile(ur"coding[:=]\s*([-\w.]+)", re.UNICODE)
15 cookie_comment_re = re.compile(ur"^\s*#.*coding[:=]\s*([-\w.]+)", re.UNICODE)
16 cookie_comment_re = re.compile(ur"^\s*#.*coding[:=]\s*([-\w.]+)", re.UNICODE)
16
17
17 try:
18 try:
18 # Available in Python 3
19 # Available in Python 3
19 from tokenize import detect_encoding
20 from tokenize import detect_encoding
20 except ImportError:
21 except ImportError:
21 from codecs import lookup, BOM_UTF8
22 from codecs import lookup, BOM_UTF8
22
23
23 # Copied from Python 3.2 tokenize
24 # Copied from Python 3.2 tokenize
24 def _get_normal_name(orig_enc):
25 def _get_normal_name(orig_enc):
25 """Imitates get_normal_name in tokenizer.c."""
26 """Imitates get_normal_name in tokenizer.c."""
26 # Only care about the first 12 characters.
27 # Only care about the first 12 characters.
27 enc = orig_enc[:12].lower().replace("_", "-")
28 enc = orig_enc[:12].lower().replace("_", "-")
28 if enc == "utf-8" or enc.startswith("utf-8-"):
29 if enc == "utf-8" or enc.startswith("utf-8-"):
29 return "utf-8"
30 return "utf-8"
30 if enc in ("latin-1", "iso-8859-1", "iso-latin-1") or \
31 if enc in ("latin-1", "iso-8859-1", "iso-latin-1") or \
31 enc.startswith(("latin-1-", "iso-8859-1-", "iso-latin-1-")):
32 enc.startswith(("latin-1-", "iso-8859-1-", "iso-latin-1-")):
32 return "iso-8859-1"
33 return "iso-8859-1"
33 return orig_enc
34 return orig_enc
34
35
35 # Copied from Python 3.2 tokenize
36 # Copied from Python 3.2 tokenize
36 def detect_encoding(readline):
37 def detect_encoding(readline):
37 """
38 """
38 The detect_encoding() function is used to detect the encoding that should
39 The detect_encoding() function is used to detect the encoding that should
39 be used to decode a Python source file. It requires one argment, readline,
40 be used to decode a Python source file. It requires one argment, readline,
40 in the same way as the tokenize() generator.
41 in the same way as the tokenize() generator.
41
42
42 It will call readline a maximum of twice, and return the encoding used
43 It will call readline a maximum of twice, and return the encoding used
43 (as a string) and a list of any lines (left as bytes) it has read in.
44 (as a string) and a list of any lines (left as bytes) it has read in.
44
45
45 It detects the encoding from the presence of a utf-8 bom or an encoding
46 It detects the encoding from the presence of a utf-8 bom or an encoding
46 cookie as specified in pep-0263. If both a bom and a cookie are present,
47 cookie as specified in pep-0263. If both a bom and a cookie are present,
47 but disagree, a SyntaxError will be raised. If the encoding cookie is an
48 but disagree, a SyntaxError will be raised. If the encoding cookie is an
48 invalid charset, raise a SyntaxError. Note that if a utf-8 bom is found,
49 invalid charset, raise a SyntaxError. Note that if a utf-8 bom is found,
49 'utf-8-sig' is returned.
50 'utf-8-sig' is returned.
50
51
51 If no encoding is specified, then the default of 'utf-8' will be returned.
52 If no encoding is specified, then the default of 'utf-8' will be returned.
52 """
53 """
53 bom_found = False
54 bom_found = False
54 encoding = None
55 encoding = None
55 default = 'utf-8'
56 default = 'utf-8'
56 def read_or_stop():
57 def read_or_stop():
57 try:
58 try:
58 return readline()
59 return readline()
59 except StopIteration:
60 except StopIteration:
60 return b''
61 return b''
61
62
62 def find_cookie(line):
63 def find_cookie(line):
63 try:
64 try:
64 line_string = line.decode('ascii')
65 line_string = line.decode('ascii')
65 except UnicodeDecodeError:
66 except UnicodeDecodeError:
66 return None
67 return None
67
68
68 matches = cookie_re.findall(line_string)
69 matches = cookie_re.findall(line_string)
69 if not matches:
70 if not matches:
70 return None
71 return None
71 encoding = _get_normal_name(matches[0])
72 encoding = _get_normal_name(matches[0])
72 try:
73 try:
73 codec = lookup(encoding)
74 codec = lookup(encoding)
74 except LookupError:
75 except LookupError:
75 # This behaviour mimics the Python interpreter
76 # This behaviour mimics the Python interpreter
76 raise SyntaxError("unknown encoding: " + encoding)
77 raise SyntaxError("unknown encoding: " + encoding)
77
78
78 if bom_found:
79 if bom_found:
79 if codec.name != 'utf-8':
80 if codec.name != 'utf-8':
80 # This behaviour mimics the Python interpreter
81 # This behaviour mimics the Python interpreter
81 raise SyntaxError('encoding problem: utf-8')
82 raise SyntaxError('encoding problem: utf-8')
82 encoding += '-sig'
83 encoding += '-sig'
83 return encoding
84 return encoding
84
85
85 first = read_or_stop()
86 first = read_or_stop()
86 if first.startswith(BOM_UTF8):
87 if first.startswith(BOM_UTF8):
87 bom_found = True
88 bom_found = True
88 first = first[3:]
89 first = first[3:]
89 default = 'utf-8-sig'
90 default = 'utf-8-sig'
90 if not first:
91 if not first:
91 return default, []
92 return default, []
92
93
93 encoding = find_cookie(first)
94 encoding = find_cookie(first)
94 if encoding:
95 if encoding:
95 return encoding, [first]
96 return encoding, [first]
96
97
97 second = read_or_stop()
98 second = read_or_stop()
98 if not second:
99 if not second:
99 return default, [first]
100 return default, [first]
100
101
101 encoding = find_cookie(second)
102 encoding = find_cookie(second)
102 if encoding:
103 if encoding:
103 return encoding, [first, second]
104 return encoding, [first, second]
104
105
105 return default, [first, second]
106 return default, [first, second]
106
107
107 try:
108 try:
108 # Available in Python 3.2 and above.
109 # Available in Python 3.2 and above.
109 from tokenize import open
110 from tokenize import open
110 except ImportError:
111 except ImportError:
111 # Copied from Python 3.2 tokenize
112 # Copied from Python 3.2 tokenize
112 def open(filename):
113 def open(filename):
113 """Open a file in read only mode using the encoding detected by
114 """Open a file in read only mode using the encoding detected by
114 detect_encoding().
115 detect_encoding().
115 """
116 """
116 buffer = io.open(filename, 'rb') # Tweaked to use io.open for Python 2
117 buffer = io.open(filename, 'rb') # Tweaked to use io.open for Python 2
117 encoding, lines = detect_encoding(buffer.readline)
118 encoding, lines = detect_encoding(buffer.readline)
118 buffer.seek(0)
119 buffer.seek(0)
119 text = TextIOWrapper(buffer, encoding, line_buffering=True)
120 text = TextIOWrapper(buffer, encoding, line_buffering=True)
120 text.mode = 'r'
121 text.mode = 'r'
121 return text
122 return text
122
123
124 def source_to_unicode(txt):
125 """Converts string with python source code to unicode
126 """
127 if isinstance(txt, unicode):
128 return txt
129 try:
130 coding, _ = detect_encoding(StringIO(txt).readline)
131 except SyntaxError:
132 coding = "ascii"
133 return txt.decode(coding, errors="replace")
134
123 def strip_encoding_cookie(filelike):
135 def strip_encoding_cookie(filelike):
124 """Generator to pull lines from a text-mode file, skipping the encoding
136 """Generator to pull lines from a text-mode file, skipping the encoding
125 cookie if it is found in the first two lines.
137 cookie if it is found in the first two lines.
126 """
138 """
127 it = iter(filelike)
139 it = iter(filelike)
128 try:
140 try:
129 first = next(it)
141 first = next(it)
130 if not cookie_comment_re.match(first):
142 if not cookie_comment_re.match(first):
131 yield first
143 yield first
132 second = next(it)
144 second = next(it)
133 if not cookie_comment_re.match(second):
145 if not cookie_comment_re.match(second):
134 yield second
146 yield second
135 except StopIteration:
147 except StopIteration:
136 return
148 return
137
149
138 for line in it:
150 for line in it:
139 yield line
151 yield line
140
152
141 def read_py_file(filename, skip_encoding_cookie=True):
153 def read_py_file(filename, skip_encoding_cookie=True):
142 """Read a Python file, using the encoding declared inside the file.
154 """Read a Python file, using the encoding declared inside the file.
143
155
144 Parameters
156 Parameters
145 ----------
157 ----------
146 filename : str
158 filename : str
147 The path to the file to read.
159 The path to the file to read.
148 skip_encoding_cookie : bool
160 skip_encoding_cookie : bool
149 If True (the default), and the encoding declaration is found in the first
161 If True (the default), and the encoding declaration is found in the first
150 two lines, that line will be excluded from the output - compiling a
162 two lines, that line will be excluded from the output - compiling a
151 unicode string with an encoding declaration is a SyntaxError in Python 2.
163 unicode string with an encoding declaration is a SyntaxError in Python 2.
152
164
153 Returns
165 Returns
154 -------
166 -------
155 A unicode string containing the contents of the file.
167 A unicode string containing the contents of the file.
156 """
168 """
157 with open(filename) as f: # the open function defined in this module.
169 with open(filename) as f: # the open function defined in this module.
158 if skip_encoding_cookie:
170 if skip_encoding_cookie:
159 return "".join(strip_encoding_cookie(f))
171 return "".join(strip_encoding_cookie(f))
160 else:
172 else:
161 return f.read()
173 return f.read()
162
174
163 def read_py_url(url, errors='replace', skip_encoding_cookie=True):
175 def read_py_url(url, errors='replace', skip_encoding_cookie=True):
164 """Read a Python file from a URL, using the encoding declared inside the file.
176 """Read a Python file from a URL, using the encoding declared inside the file.
165
177
166 Parameters
178 Parameters
167 ----------
179 ----------
168 url : str
180 url : str
169 The URL from which to fetch the file.
181 The URL from which to fetch the file.
170 errors : str
182 errors : str
171 How to handle decoding errors in the file. Options are the same as for
183 How to handle decoding errors in the file. Options are the same as for
172 bytes.decode(), but here 'replace' is the default.
184 bytes.decode(), but here 'replace' is the default.
173 skip_encoding_cookie : bool
185 skip_encoding_cookie : bool
174 If True (the default), and the encoding declaration is found in the first
186 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
187 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.
188 unicode string with an encoding declaration is a SyntaxError in Python 2.
177
189
178 Returns
190 Returns
179 -------
191 -------
180 A unicode string containing the contents of the file.
192 A unicode string containing the contents of the file.
181 """
193 """
182 response = urllib.urlopen(url)
194 response = urllib.urlopen(url)
183 buffer = io.BytesIO(response.read())
195 buffer = io.BytesIO(response.read())
184 encoding, lines = detect_encoding(buffer.readline)
196 encoding, lines = detect_encoding(buffer.readline)
185 buffer.seek(0)
197 buffer.seek(0)
186 text = TextIOWrapper(buffer, encoding, errors=errors, line_buffering=True)
198 text = TextIOWrapper(buffer, encoding, errors=errors, line_buffering=True)
187 text.mode = 'r'
199 text.mode = 'r'
188 if skip_encoding_cookie:
200 if skip_encoding_cookie:
189 return "".join(strip_encoding_cookie(text))
201 return "".join(strip_encoding_cookie(text))
190 else:
202 else:
191 return text.read()
203 return text.read()
192
204
@@ -1,588 +1,590 b''
1 """A ZMQ-based subclass of InteractiveShell.
1 """A ZMQ-based subclass of InteractiveShell.
2
2
3 This code is meant to ease the refactoring of the base InteractiveShell into
3 This code is meant to ease the refactoring of the base InteractiveShell into
4 something with a cleaner architecture for 2-process use, without actually
4 something with a cleaner architecture for 2-process use, without actually
5 breaking InteractiveShell itself. So we're doing something a bit ugly, where
5 breaking InteractiveShell itself. So we're doing something a bit ugly, where
6 we subclass and override what we want to fix. Once this is working well, we
6 we subclass and override what we want to fix. Once this is working well, we
7 can go back to the base class and refactor the code for a cleaner inheritance
7 can go back to the base class and refactor the code for a cleaner inheritance
8 implementation that doesn't rely on so much monkeypatching.
8 implementation that doesn't rely on so much monkeypatching.
9
9
10 But this lets us maintain a fully working IPython as we develop the new
10 But this lets us maintain a fully working IPython as we develop the new
11 machinery. This should thus be thought of as scaffolding.
11 machinery. This should thus be thought of as scaffolding.
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 os
19 import os
20 import sys
20 import sys
21 import time
21 import time
22
22
23 # System library imports
23 # System library imports
24 from zmq.eventloop import ioloop
24 from zmq.eventloop import ioloop
25
25
26 # Our own
26 # Our own
27 from IPython.core.interactiveshell import (
27 from IPython.core.interactiveshell import (
28 InteractiveShell, InteractiveShellABC
28 InteractiveShell, InteractiveShellABC
29 )
29 )
30 from IPython.core import page
30 from IPython.core import page
31 from IPython.core.autocall import ZMQExitAutocall
31 from IPython.core.autocall import ZMQExitAutocall
32 from IPython.core.displaypub import DisplayPublisher
32 from IPython.core.displaypub import DisplayPublisher
33 from IPython.core.error import UsageError
33 from IPython.core.error import UsageError
34 from IPython.core.magics import MacroToEdit, CodeMagics
34 from IPython.core.magics import MacroToEdit, CodeMagics
35 from IPython.core.magic import magics_class, line_magic, Magics
35 from IPython.core.magic import magics_class, line_magic, Magics
36 from IPython.core.payloadpage import install_payload_page
36 from IPython.core.payloadpage import install_payload_page
37 from IPython.lib.kernel import (
37 from IPython.lib.kernel import (
38 get_connection_file, get_connection_info, connect_qtconsole
38 get_connection_file, get_connection_info, connect_qtconsole
39 )
39 )
40 from IPython.testing.skipdoctest import skip_doctest
40 from IPython.testing.skipdoctest import skip_doctest
41 from IPython.utils import io
41 from IPython.utils import io, openpy
42 from IPython.utils.jsonutil import json_clean, encode_images
42 from IPython.utils.jsonutil import json_clean, encode_images
43 from IPython.utils.process import arg_split
43 from IPython.utils.process import arg_split
44 from IPython.utils import py3compat
44 from IPython.utils import py3compat
45 from IPython.utils.traitlets import Instance, Type, Dict, CBool, CBytes
45 from IPython.utils.traitlets import Instance, Type, Dict, CBool, CBytes
46 from IPython.utils.warn import warn, error
46 from IPython.utils.warn import warn, error
47 from IPython.zmq.displayhook import ZMQShellDisplayHook
47 from IPython.zmq.displayhook import ZMQShellDisplayHook
48 from IPython.zmq.datapub import ZMQDataPublisher
48 from IPython.zmq.datapub import ZMQDataPublisher
49 from IPython.zmq.session import extract_header
49 from IPython.zmq.session import extract_header
50 from session import Session
50 from session import Session
51
51
52 #-----------------------------------------------------------------------------
52 #-----------------------------------------------------------------------------
53 # Functions and classes
53 # Functions and classes
54 #-----------------------------------------------------------------------------
54 #-----------------------------------------------------------------------------
55
55
56 class ZMQDisplayPublisher(DisplayPublisher):
56 class ZMQDisplayPublisher(DisplayPublisher):
57 """A display publisher that publishes data using a ZeroMQ PUB socket."""
57 """A display publisher that publishes data using a ZeroMQ PUB socket."""
58
58
59 session = Instance(Session)
59 session = Instance(Session)
60 pub_socket = Instance('zmq.Socket')
60 pub_socket = Instance('zmq.Socket')
61 parent_header = Dict({})
61 parent_header = Dict({})
62 topic = CBytes(b'displaypub')
62 topic = CBytes(b'displaypub')
63
63
64 def set_parent(self, parent):
64 def set_parent(self, parent):
65 """Set the parent for outbound messages."""
65 """Set the parent for outbound messages."""
66 self.parent_header = extract_header(parent)
66 self.parent_header = extract_header(parent)
67
67
68 def _flush_streams(self):
68 def _flush_streams(self):
69 """flush IO Streams prior to display"""
69 """flush IO Streams prior to display"""
70 sys.stdout.flush()
70 sys.stdout.flush()
71 sys.stderr.flush()
71 sys.stderr.flush()
72
72
73 def publish(self, source, data, metadata=None):
73 def publish(self, source, data, metadata=None):
74 self._flush_streams()
74 self._flush_streams()
75 if metadata is None:
75 if metadata is None:
76 metadata = {}
76 metadata = {}
77 self._validate_data(source, data, metadata)
77 self._validate_data(source, data, metadata)
78 content = {}
78 content = {}
79 content['source'] = source
79 content['source'] = source
80 content['data'] = encode_images(data)
80 content['data'] = encode_images(data)
81 content['metadata'] = metadata
81 content['metadata'] = metadata
82 self.session.send(
82 self.session.send(
83 self.pub_socket, u'display_data', json_clean(content),
83 self.pub_socket, u'display_data', json_clean(content),
84 parent=self.parent_header, ident=self.topic,
84 parent=self.parent_header, ident=self.topic,
85 )
85 )
86
86
87 def clear_output(self, stdout=True, stderr=True, other=True):
87 def clear_output(self, stdout=True, stderr=True, other=True):
88 content = dict(stdout=stdout, stderr=stderr, other=other)
88 content = dict(stdout=stdout, stderr=stderr, other=other)
89
89
90 if stdout:
90 if stdout:
91 print('\r', file=sys.stdout, end='')
91 print('\r', file=sys.stdout, end='')
92 if stderr:
92 if stderr:
93 print('\r', file=sys.stderr, end='')
93 print('\r', file=sys.stderr, end='')
94
94
95 self._flush_streams()
95 self._flush_streams()
96
96
97 self.session.send(
97 self.session.send(
98 self.pub_socket, u'clear_output', content,
98 self.pub_socket, u'clear_output', content,
99 parent=self.parent_header, ident=self.topic,
99 parent=self.parent_header, ident=self.topic,
100 )
100 )
101
101
102 @magics_class
102 @magics_class
103 class KernelMagics(Magics):
103 class KernelMagics(Magics):
104 #------------------------------------------------------------------------
104 #------------------------------------------------------------------------
105 # Magic overrides
105 # Magic overrides
106 #------------------------------------------------------------------------
106 #------------------------------------------------------------------------
107 # Once the base class stops inheriting from magic, this code needs to be
107 # Once the base class stops inheriting from magic, this code needs to be
108 # moved into a separate machinery as well. For now, at least isolate here
108 # moved into a separate machinery as well. For now, at least isolate here
109 # the magics which this class needs to implement differently from the base
109 # the magics which this class needs to implement differently from the base
110 # class, or that are unique to it.
110 # class, or that are unique to it.
111
111
112 @line_magic
112 @line_magic
113 def doctest_mode(self, parameter_s=''):
113 def doctest_mode(self, parameter_s=''):
114 """Toggle doctest mode on and off.
114 """Toggle doctest mode on and off.
115
115
116 This mode is intended to make IPython behave as much as possible like a
116 This mode is intended to make IPython behave as much as possible like a
117 plain Python shell, from the perspective of how its prompts, exceptions
117 plain Python shell, from the perspective of how its prompts, exceptions
118 and output look. This makes it easy to copy and paste parts of a
118 and output look. This makes it easy to copy and paste parts of a
119 session into doctests. It does so by:
119 session into doctests. It does so by:
120
120
121 - Changing the prompts to the classic ``>>>`` ones.
121 - Changing the prompts to the classic ``>>>`` ones.
122 - Changing the exception reporting mode to 'Plain'.
122 - Changing the exception reporting mode to 'Plain'.
123 - Disabling pretty-printing of output.
123 - Disabling pretty-printing of output.
124
124
125 Note that IPython also supports the pasting of code snippets that have
125 Note that IPython also supports the pasting of code snippets that have
126 leading '>>>' and '...' prompts in them. This means that you can paste
126 leading '>>>' and '...' prompts in them. This means that you can paste
127 doctests from files or docstrings (even if they have leading
127 doctests from files or docstrings (even if they have leading
128 whitespace), and the code will execute correctly. You can then use
128 whitespace), and the code will execute correctly. You can then use
129 '%history -t' to see the translated history; this will give you the
129 '%history -t' to see the translated history; this will give you the
130 input after removal of all the leading prompts and whitespace, which
130 input after removal of all the leading prompts and whitespace, which
131 can be pasted back into an editor.
131 can be pasted back into an editor.
132
132
133 With these features, you can switch into this mode easily whenever you
133 With these features, you can switch into this mode easily whenever you
134 need to do testing and changes to doctests, without having to leave
134 need to do testing and changes to doctests, without having to leave
135 your existing IPython session.
135 your existing IPython session.
136 """
136 """
137
137
138 from IPython.utils.ipstruct import Struct
138 from IPython.utils.ipstruct import Struct
139
139
140 # Shorthands
140 # Shorthands
141 shell = self.shell
141 shell = self.shell
142 disp_formatter = self.shell.display_formatter
142 disp_formatter = self.shell.display_formatter
143 ptformatter = disp_formatter.formatters['text/plain']
143 ptformatter = disp_formatter.formatters['text/plain']
144 # dstore is a data store kept in the instance metadata bag to track any
144 # dstore is a data store kept in the instance metadata bag to track any
145 # changes we make, so we can undo them later.
145 # changes we make, so we can undo them later.
146 dstore = shell.meta.setdefault('doctest_mode', Struct())
146 dstore = shell.meta.setdefault('doctest_mode', Struct())
147 save_dstore = dstore.setdefault
147 save_dstore = dstore.setdefault
148
148
149 # save a few values we'll need to recover later
149 # save a few values we'll need to recover later
150 mode = save_dstore('mode', False)
150 mode = save_dstore('mode', False)
151 save_dstore('rc_pprint', ptformatter.pprint)
151 save_dstore('rc_pprint', ptformatter.pprint)
152 save_dstore('rc_plain_text_only',disp_formatter.plain_text_only)
152 save_dstore('rc_plain_text_only',disp_formatter.plain_text_only)
153 save_dstore('xmode', shell.InteractiveTB.mode)
153 save_dstore('xmode', shell.InteractiveTB.mode)
154
154
155 if mode == False:
155 if mode == False:
156 # turn on
156 # turn on
157 ptformatter.pprint = False
157 ptformatter.pprint = False
158 disp_formatter.plain_text_only = True
158 disp_formatter.plain_text_only = True
159 shell.magic('xmode Plain')
159 shell.magic('xmode Plain')
160 else:
160 else:
161 # turn off
161 # turn off
162 ptformatter.pprint = dstore.rc_pprint
162 ptformatter.pprint = dstore.rc_pprint
163 disp_formatter.plain_text_only = dstore.rc_plain_text_only
163 disp_formatter.plain_text_only = dstore.rc_plain_text_only
164 shell.magic("xmode " + dstore.xmode)
164 shell.magic("xmode " + dstore.xmode)
165
165
166 # Store new mode and inform on console
166 # Store new mode and inform on console
167 dstore.mode = bool(1-int(mode))
167 dstore.mode = bool(1-int(mode))
168 mode_label = ['OFF','ON'][dstore.mode]
168 mode_label = ['OFF','ON'][dstore.mode]
169 print('Doctest mode is:', mode_label)
169 print('Doctest mode is:', mode_label)
170
170
171 # Send the payload back so that clients can modify their prompt display
171 # Send the payload back so that clients can modify their prompt display
172 payload = dict(
172 payload = dict(
173 source='IPython.zmq.zmqshell.ZMQInteractiveShell.doctest_mode',
173 source='IPython.zmq.zmqshell.ZMQInteractiveShell.doctest_mode',
174 mode=dstore.mode)
174 mode=dstore.mode)
175 shell.payload_manager.write_payload(payload)
175 shell.payload_manager.write_payload(payload)
176
176
177
177
178 _find_edit_target = CodeMagics._find_edit_target
178 _find_edit_target = CodeMagics._find_edit_target
179
179
180 @skip_doctest
180 @skip_doctest
181 @line_magic
181 @line_magic
182 def edit(self, parameter_s='', last_call=['','']):
182 def edit(self, parameter_s='', last_call=['','']):
183 """Bring up an editor and execute the resulting code.
183 """Bring up an editor and execute the resulting code.
184
184
185 Usage:
185 Usage:
186 %edit [options] [args]
186 %edit [options] [args]
187
187
188 %edit runs an external text editor. You will need to set the command for
188 %edit runs an external text editor. You will need to set the command for
189 this editor via the ``TerminalInteractiveShell.editor`` option in your
189 this editor via the ``TerminalInteractiveShell.editor`` option in your
190 configuration file before it will work.
190 configuration file before it will work.
191
191
192 This command allows you to conveniently edit multi-line code right in
192 This command allows you to conveniently edit multi-line code right in
193 your IPython session.
193 your IPython session.
194
194
195 If called without arguments, %edit opens up an empty editor with a
195 If called without arguments, %edit opens up an empty editor with a
196 temporary file and will execute the contents of this file when you
196 temporary file and will execute the contents of this file when you
197 close it (don't forget to save it!).
197 close it (don't forget to save it!).
198
198
199
199
200 Options:
200 Options:
201
201
202 -n <number>: open the editor at a specified line number. By default,
202 -n <number>: open the editor at a specified line number. By default,
203 the IPython editor hook uses the unix syntax 'editor +N filename', but
203 the IPython editor hook uses the unix syntax 'editor +N filename', but
204 you can configure this by providing your own modified hook if your
204 you can configure this by providing your own modified hook if your
205 favorite editor supports line-number specifications with a different
205 favorite editor supports line-number specifications with a different
206 syntax.
206 syntax.
207
207
208 -p: this will call the editor with the same data as the previous time
208 -p: this will call the editor with the same data as the previous time
209 it was used, regardless of how long ago (in your current session) it
209 it was used, regardless of how long ago (in your current session) it
210 was.
210 was.
211
211
212 -r: use 'raw' input. This option only applies to input taken from the
212 -r: use 'raw' input. This option only applies to input taken from the
213 user's history. By default, the 'processed' history is used, so that
213 user's history. By default, the 'processed' history is used, so that
214 magics are loaded in their transformed version to valid Python. If
214 magics are loaded in their transformed version to valid Python. If
215 this option is given, the raw input as typed as the command line is
215 this option is given, the raw input as typed as the command line is
216 used instead. When you exit the editor, it will be executed by
216 used instead. When you exit the editor, it will be executed by
217 IPython's own processor.
217 IPython's own processor.
218
218
219 -x: do not execute the edited code immediately upon exit. This is
219 -x: do not execute the edited code immediately upon exit. This is
220 mainly useful if you are editing programs which need to be called with
220 mainly useful if you are editing programs which need to be called with
221 command line arguments, which you can then do using %run.
221 command line arguments, which you can then do using %run.
222
222
223
223
224 Arguments:
224 Arguments:
225
225
226 If arguments are given, the following possibilites exist:
226 If arguments are given, the following possibilites exist:
227
227
228 - The arguments are numbers or pairs of colon-separated numbers (like
228 - The arguments are numbers or pairs of colon-separated numbers (like
229 1 4:8 9). These are interpreted as lines of previous input to be
229 1 4:8 9). These are interpreted as lines of previous input to be
230 loaded into the editor. The syntax is the same of the %macro command.
230 loaded into the editor. The syntax is the same of the %macro command.
231
231
232 - If the argument doesn't start with a number, it is evaluated as a
232 - If the argument doesn't start with a number, it is evaluated as a
233 variable and its contents loaded into the editor. You can thus edit
233 variable and its contents loaded into the editor. You can thus edit
234 any string which contains python code (including the result of
234 any string which contains python code (including the result of
235 previous edits).
235 previous edits).
236
236
237 - If the argument is the name of an object (other than a string),
237 - If the argument is the name of an object (other than a string),
238 IPython will try to locate the file where it was defined and open the
238 IPython will try to locate the file where it was defined and open the
239 editor at the point where it is defined. You can use `%edit function`
239 editor at the point where it is defined. You can use `%edit function`
240 to load an editor exactly at the point where 'function' is defined,
240 to load an editor exactly at the point where 'function' is defined,
241 edit it and have the file be executed automatically.
241 edit it and have the file be executed automatically.
242
242
243 If the object is a macro (see %macro for details), this opens up your
243 If the object is a macro (see %macro for details), this opens up your
244 specified editor with a temporary file containing the macro's data.
244 specified editor with a temporary file containing the macro's data.
245 Upon exit, the macro is reloaded with the contents of the file.
245 Upon exit, the macro is reloaded with the contents of the file.
246
246
247 Note: opening at an exact line is only supported under Unix, and some
247 Note: opening at an exact line is only supported under Unix, and some
248 editors (like kedit and gedit up to Gnome 2.8) do not understand the
248 editors (like kedit and gedit up to Gnome 2.8) do not understand the
249 '+NUMBER' parameter necessary for this feature. Good editors like
249 '+NUMBER' parameter necessary for this feature. Good editors like
250 (X)Emacs, vi, jed, pico and joe all do.
250 (X)Emacs, vi, jed, pico and joe all do.
251
251
252 - If the argument is not found as a variable, IPython will look for a
252 - If the argument is not found as a variable, IPython will look for a
253 file with that name (adding .py if necessary) and load it into the
253 file with that name (adding .py if necessary) and load it into the
254 editor. It will execute its contents with execfile() when you exit,
254 editor. It will execute its contents with execfile() when you exit,
255 loading any code in the file into your interactive namespace.
255 loading any code in the file into your interactive namespace.
256
256
257 After executing your code, %edit will return as output the code you
257 After executing your code, %edit will return as output the code you
258 typed in the editor (except when it was an existing file). This way
258 typed in the editor (except when it was an existing file). This way
259 you can reload the code in further invocations of %edit as a variable,
259 you can reload the code in further invocations of %edit as a variable,
260 via _<NUMBER> or Out[<NUMBER>], where <NUMBER> is the prompt number of
260 via _<NUMBER> or Out[<NUMBER>], where <NUMBER> is the prompt number of
261 the output.
261 the output.
262
262
263 Note that %edit is also available through the alias %ed.
263 Note that %edit is also available through the alias %ed.
264
264
265 This is an example of creating a simple function inside the editor and
265 This is an example of creating a simple function inside the editor and
266 then modifying it. First, start up the editor:
266 then modifying it. First, start up the editor:
267
267
268 In [1]: ed
268 In [1]: ed
269 Editing... done. Executing edited code...
269 Editing... done. Executing edited code...
270 Out[1]: 'def foo():n print "foo() was defined in an editing session"n'
270 Out[1]: 'def foo():n print "foo() was defined in an editing session"n'
271
271
272 We can then call the function foo():
272 We can then call the function foo():
273
273
274 In [2]: foo()
274 In [2]: foo()
275 foo() was defined in an editing session
275 foo() was defined in an editing session
276
276
277 Now we edit foo. IPython automatically loads the editor with the
277 Now we edit foo. IPython automatically loads the editor with the
278 (temporary) file where foo() was previously defined:
278 (temporary) file where foo() was previously defined:
279
279
280 In [3]: ed foo
280 In [3]: ed foo
281 Editing... done. Executing edited code...
281 Editing... done. Executing edited code...
282
282
283 And if we call foo() again we get the modified version:
283 And if we call foo() again we get the modified version:
284
284
285 In [4]: foo()
285 In [4]: foo()
286 foo() has now been changed!
286 foo() has now been changed!
287
287
288 Here is an example of how to edit a code snippet successive
288 Here is an example of how to edit a code snippet successive
289 times. First we call the editor:
289 times. First we call the editor:
290
290
291 In [5]: ed
291 In [5]: ed
292 Editing... done. Executing edited code...
292 Editing... done. Executing edited code...
293 hello
293 hello
294 Out[5]: "print 'hello'n"
294 Out[5]: "print 'hello'n"
295
295
296 Now we call it again with the previous output (stored in _):
296 Now we call it again with the previous output (stored in _):
297
297
298 In [6]: ed _
298 In [6]: ed _
299 Editing... done. Executing edited code...
299 Editing... done. Executing edited code...
300 hello world
300 hello world
301 Out[6]: "print 'hello world'n"
301 Out[6]: "print 'hello world'n"
302
302
303 Now we call it with the output #8 (stored in _8, also as Out[8]):
303 Now we call it with the output #8 (stored in _8, also as Out[8]):
304
304
305 In [7]: ed _8
305 In [7]: ed _8
306 Editing... done. Executing edited code...
306 Editing... done. Executing edited code...
307 hello again
307 hello again
308 Out[7]: "print 'hello again'n"
308 Out[7]: "print 'hello again'n"
309 """
309 """
310
310
311 opts,args = self.parse_options(parameter_s,'prn:')
311 opts,args = self.parse_options(parameter_s,'prn:')
312
312
313 try:
313 try:
314 filename, lineno, _ = CodeMagics._find_edit_target(self.shell, args, opts, last_call)
314 filename, lineno, _ = CodeMagics._find_edit_target(self.shell, args, opts, last_call)
315 except MacroToEdit as e:
315 except MacroToEdit as e:
316 # TODO: Implement macro editing over 2 processes.
316 # TODO: Implement macro editing over 2 processes.
317 print("Macro editing not yet implemented in 2-process model.")
317 print("Macro editing not yet implemented in 2-process model.")
318 return
318 return
319
319
320 # Make sure we send to the client an absolute path, in case the working
320 # Make sure we send to the client an absolute path, in case the working
321 # directory of client and kernel don't match
321 # directory of client and kernel don't match
322 filename = os.path.abspath(filename)
322 filename = os.path.abspath(filename)
323
323
324 payload = {
324 payload = {
325 'source' : 'IPython.zmq.zmqshell.ZMQInteractiveShell.edit_magic',
325 'source' : 'IPython.zmq.zmqshell.ZMQInteractiveShell.edit_magic',
326 'filename' : filename,
326 'filename' : filename,
327 'line_number' : lineno
327 'line_number' : lineno
328 }
328 }
329 self.shell.payload_manager.write_payload(payload)
329 self.shell.payload_manager.write_payload(payload)
330
330
331 # A few magics that are adapted to the specifics of using pexpect and a
331 # A few magics that are adapted to the specifics of using pexpect and a
332 # remote terminal
332 # remote terminal
333
333
334 @line_magic
334 @line_magic
335 def clear(self, arg_s):
335 def clear(self, arg_s):
336 """Clear the terminal."""
336 """Clear the terminal."""
337 if os.name == 'posix':
337 if os.name == 'posix':
338 self.shell.system("clear")
338 self.shell.system("clear")
339 else:
339 else:
340 self.shell.system("cls")
340 self.shell.system("cls")
341
341
342 if os.name == 'nt':
342 if os.name == 'nt':
343 # This is the usual name in windows
343 # This is the usual name in windows
344 cls = line_magic('cls')(clear)
344 cls = line_magic('cls')(clear)
345
345
346 # Terminal pagers won't work over pexpect, but we do have our own pager
346 # Terminal pagers won't work over pexpect, but we do have our own pager
347
347
348 @line_magic
348 @line_magic
349 def less(self, arg_s):
349 def less(self, arg_s):
350 """Show a file through the pager.
350 """Show a file through the pager.
351
351
352 Files ending in .py are syntax-highlighted."""
352 Files ending in .py are syntax-highlighted."""
353 if not arg_s:
353 if not arg_s:
354 raise UsageError('Missing filename.')
354 raise UsageError('Missing filename.')
355
355
356 cont = open(arg_s).read()
356 cont = open(arg_s).read()
357 if arg_s.endswith('.py'):
357 if arg_s.endswith('.py'):
358 cont = self.shell.pycolorize(io.source_to_unicode(cont))
358 cont = self.shell.pycolorize(openpy.read_py_file(arg_s, skip_encoding_cookie=False))
359 else:
360 cont = open(arg_s).read()
359 page.page(cont)
361 page.page(cont)
360
362
361 more = line_magic('more')(less)
363 more = line_magic('more')(less)
362
364
363 # Man calls a pager, so we also need to redefine it
365 # Man calls a pager, so we also need to redefine it
364 if os.name == 'posix':
366 if os.name == 'posix':
365 @line_magic
367 @line_magic
366 def man(self, arg_s):
368 def man(self, arg_s):
367 """Find the man page for the given command and display in pager."""
369 """Find the man page for the given command and display in pager."""
368 page.page(self.shell.getoutput('man %s | col -b' % arg_s,
370 page.page(self.shell.getoutput('man %s | col -b' % arg_s,
369 split=False))
371 split=False))
370
372
371 @line_magic
373 @line_magic
372 def connect_info(self, arg_s):
374 def connect_info(self, arg_s):
373 """Print information for connecting other clients to this kernel
375 """Print information for connecting other clients to this kernel
374
376
375 It will print the contents of this session's connection file, as well as
377 It will print the contents of this session's connection file, as well as
376 shortcuts for local clients.
378 shortcuts for local clients.
377
379
378 In the simplest case, when called from the most recently launched kernel,
380 In the simplest case, when called from the most recently launched kernel,
379 secondary clients can be connected, simply with:
381 secondary clients can be connected, simply with:
380
382
381 $> ipython <app> --existing
383 $> ipython <app> --existing
382
384
383 """
385 """
384
386
385 from IPython.core.application import BaseIPythonApplication as BaseIPApp
387 from IPython.core.application import BaseIPythonApplication as BaseIPApp
386
388
387 if BaseIPApp.initialized():
389 if BaseIPApp.initialized():
388 app = BaseIPApp.instance()
390 app = BaseIPApp.instance()
389 security_dir = app.profile_dir.security_dir
391 security_dir = app.profile_dir.security_dir
390 profile = app.profile
392 profile = app.profile
391 else:
393 else:
392 profile = 'default'
394 profile = 'default'
393 security_dir = ''
395 security_dir = ''
394
396
395 try:
397 try:
396 connection_file = get_connection_file()
398 connection_file = get_connection_file()
397 info = get_connection_info(unpack=False)
399 info = get_connection_info(unpack=False)
398 except Exception as e:
400 except Exception as e:
399 error("Could not get connection info: %r" % e)
401 error("Could not get connection info: %r" % e)
400 return
402 return
401
403
402 # add profile flag for non-default profile
404 # add profile flag for non-default profile
403 profile_flag = "--profile %s" % profile if profile != 'default' else ""
405 profile_flag = "--profile %s" % profile if profile != 'default' else ""
404
406
405 # if it's in the security dir, truncate to basename
407 # if it's in the security dir, truncate to basename
406 if security_dir == os.path.dirname(connection_file):
408 if security_dir == os.path.dirname(connection_file):
407 connection_file = os.path.basename(connection_file)
409 connection_file = os.path.basename(connection_file)
408
410
409
411
410 print (info + '\n')
412 print (info + '\n')
411 print ("Paste the above JSON into a file, and connect with:\n"
413 print ("Paste the above JSON into a file, and connect with:\n"
412 " $> ipython <app> --existing <file>\n"
414 " $> ipython <app> --existing <file>\n"
413 "or, if you are local, you can connect with just:\n"
415 "or, if you are local, you can connect with just:\n"
414 " $> ipython <app> --existing {0} {1}\n"
416 " $> ipython <app> --existing {0} {1}\n"
415 "or even just:\n"
417 "or even just:\n"
416 " $> ipython <app> --existing {1}\n"
418 " $> ipython <app> --existing {1}\n"
417 "if this is the most recent IPython session you have started.".format(
419 "if this is the most recent IPython session you have started.".format(
418 connection_file, profile_flag
420 connection_file, profile_flag
419 )
421 )
420 )
422 )
421
423
422 @line_magic
424 @line_magic
423 def qtconsole(self, arg_s):
425 def qtconsole(self, arg_s):
424 """Open a qtconsole connected to this kernel.
426 """Open a qtconsole connected to this kernel.
425
427
426 Useful for connecting a qtconsole to running notebooks, for better
428 Useful for connecting a qtconsole to running notebooks, for better
427 debugging.
429 debugging.
428 """
430 """
429
431
430 # %qtconsole should imply bind_kernel for engines:
432 # %qtconsole should imply bind_kernel for engines:
431 try:
433 try:
432 from IPython.parallel import bind_kernel
434 from IPython.parallel import bind_kernel
433 except ImportError:
435 except ImportError:
434 # technically possible, because parallel has higher pyzmq min-version
436 # technically possible, because parallel has higher pyzmq min-version
435 pass
437 pass
436 else:
438 else:
437 bind_kernel()
439 bind_kernel()
438
440
439 try:
441 try:
440 p = connect_qtconsole(argv=arg_split(arg_s, os.name=='posix'))
442 p = connect_qtconsole(argv=arg_split(arg_s, os.name=='posix'))
441 except Exception as e:
443 except Exception as e:
442 error("Could not start qtconsole: %r" % e)
444 error("Could not start qtconsole: %r" % e)
443 return
445 return
444
446
445 def safe_unicode(e):
447 def safe_unicode(e):
446 """unicode(e) with various fallbacks. Used for exceptions, which may not be
448 """unicode(e) with various fallbacks. Used for exceptions, which may not be
447 safe to call unicode() on.
449 safe to call unicode() on.
448 """
450 """
449 try:
451 try:
450 return unicode(e)
452 return unicode(e)
451 except UnicodeError:
453 except UnicodeError:
452 pass
454 pass
453
455
454 try:
456 try:
455 return py3compat.str_to_unicode(str(e))
457 return py3compat.str_to_unicode(str(e))
456 except UnicodeError:
458 except UnicodeError:
457 pass
459 pass
458
460
459 try:
461 try:
460 return py3compat.str_to_unicode(repr(e))
462 return py3compat.str_to_unicode(repr(e))
461 except UnicodeError:
463 except UnicodeError:
462 pass
464 pass
463
465
464 return u'Unrecoverably corrupt evalue'
466 return u'Unrecoverably corrupt evalue'
465
467
466
468
467 class ZMQInteractiveShell(InteractiveShell):
469 class ZMQInteractiveShell(InteractiveShell):
468 """A subclass of InteractiveShell for ZMQ."""
470 """A subclass of InteractiveShell for ZMQ."""
469
471
470 displayhook_class = Type(ZMQShellDisplayHook)
472 displayhook_class = Type(ZMQShellDisplayHook)
471 display_pub_class = Type(ZMQDisplayPublisher)
473 display_pub_class = Type(ZMQDisplayPublisher)
472 data_pub_class = Type(ZMQDataPublisher)
474 data_pub_class = Type(ZMQDataPublisher)
473
475
474 # Override the traitlet in the parent class, because there's no point using
476 # Override the traitlet in the parent class, because there's no point using
475 # readline for the kernel. Can be removed when the readline code is moved
477 # readline for the kernel. Can be removed when the readline code is moved
476 # to the terminal frontend.
478 # to the terminal frontend.
477 colors_force = CBool(True)
479 colors_force = CBool(True)
478 readline_use = CBool(False)
480 readline_use = CBool(False)
479 # autoindent has no meaning in a zmqshell, and attempting to enable it
481 # autoindent has no meaning in a zmqshell, and attempting to enable it
480 # will print a warning in the absence of readline.
482 # will print a warning in the absence of readline.
481 autoindent = CBool(False)
483 autoindent = CBool(False)
482
484
483 exiter = Instance(ZMQExitAutocall)
485 exiter = Instance(ZMQExitAutocall)
484 def _exiter_default(self):
486 def _exiter_default(self):
485 return ZMQExitAutocall(self)
487 return ZMQExitAutocall(self)
486
488
487 def _exit_now_changed(self, name, old, new):
489 def _exit_now_changed(self, name, old, new):
488 """stop eventloop when exit_now fires"""
490 """stop eventloop when exit_now fires"""
489 if new:
491 if new:
490 loop = ioloop.IOLoop.instance()
492 loop = ioloop.IOLoop.instance()
491 loop.add_timeout(time.time()+0.1, loop.stop)
493 loop.add_timeout(time.time()+0.1, loop.stop)
492
494
493 keepkernel_on_exit = None
495 keepkernel_on_exit = None
494
496
495 # Over ZeroMQ, GUI control isn't done with PyOS_InputHook as there is no
497 # Over ZeroMQ, GUI control isn't done with PyOS_InputHook as there is no
496 # interactive input being read; we provide event loop support in ipkernel
498 # interactive input being read; we provide event loop support in ipkernel
497 from .eventloops import enable_gui
499 from .eventloops import enable_gui
498 enable_gui = staticmethod(enable_gui)
500 enable_gui = staticmethod(enable_gui)
499
501
500 def init_environment(self):
502 def init_environment(self):
501 """Configure the user's environment.
503 """Configure the user's environment.
502
504
503 """
505 """
504 env = os.environ
506 env = os.environ
505 # These two ensure 'ls' produces nice coloring on BSD-derived systems
507 # These two ensure 'ls' produces nice coloring on BSD-derived systems
506 env['TERM'] = 'xterm-color'
508 env['TERM'] = 'xterm-color'
507 env['CLICOLOR'] = '1'
509 env['CLICOLOR'] = '1'
508 # Since normal pagers don't work at all (over pexpect we don't have
510 # Since normal pagers don't work at all (over pexpect we don't have
509 # single-key control of the subprocess), try to disable paging in
511 # single-key control of the subprocess), try to disable paging in
510 # subprocesses as much as possible.
512 # subprocesses as much as possible.
511 env['PAGER'] = 'cat'
513 env['PAGER'] = 'cat'
512 env['GIT_PAGER'] = 'cat'
514 env['GIT_PAGER'] = 'cat'
513
515
514 # And install the payload version of page.
516 # And install the payload version of page.
515 install_payload_page()
517 install_payload_page()
516
518
517 def auto_rewrite_input(self, cmd):
519 def auto_rewrite_input(self, cmd):
518 """Called to show the auto-rewritten input for autocall and friends.
520 """Called to show the auto-rewritten input for autocall and friends.
519
521
520 FIXME: this payload is currently not correctly processed by the
522 FIXME: this payload is currently not correctly processed by the
521 frontend.
523 frontend.
522 """
524 """
523 new = self.prompt_manager.render('rewrite') + cmd
525 new = self.prompt_manager.render('rewrite') + cmd
524 payload = dict(
526 payload = dict(
525 source='IPython.zmq.zmqshell.ZMQInteractiveShell.auto_rewrite_input',
527 source='IPython.zmq.zmqshell.ZMQInteractiveShell.auto_rewrite_input',
526 transformed_input=new,
528 transformed_input=new,
527 )
529 )
528 self.payload_manager.write_payload(payload)
530 self.payload_manager.write_payload(payload)
529
531
530 def ask_exit(self):
532 def ask_exit(self):
531 """Engage the exit actions."""
533 """Engage the exit actions."""
532 self.exit_now = True
534 self.exit_now = True
533 payload = dict(
535 payload = dict(
534 source='IPython.zmq.zmqshell.ZMQInteractiveShell.ask_exit',
536 source='IPython.zmq.zmqshell.ZMQInteractiveShell.ask_exit',
535 exit=True,
537 exit=True,
536 keepkernel=self.keepkernel_on_exit,
538 keepkernel=self.keepkernel_on_exit,
537 )
539 )
538 self.payload_manager.write_payload(payload)
540 self.payload_manager.write_payload(payload)
539
541
540 def _showtraceback(self, etype, evalue, stb):
542 def _showtraceback(self, etype, evalue, stb):
541
543
542 exc_content = {
544 exc_content = {
543 u'traceback' : stb,
545 u'traceback' : stb,
544 u'ename' : unicode(etype.__name__),
546 u'ename' : unicode(etype.__name__),
545 u'evalue' : safe_unicode(evalue)
547 u'evalue' : safe_unicode(evalue)
546 }
548 }
547
549
548 dh = self.displayhook
550 dh = self.displayhook
549 # Send exception info over pub socket for other clients than the caller
551 # Send exception info over pub socket for other clients than the caller
550 # to pick up
552 # to pick up
551 topic = None
553 topic = None
552 if dh.topic:
554 if dh.topic:
553 topic = dh.topic.replace(b'pyout', b'pyerr')
555 topic = dh.topic.replace(b'pyout', b'pyerr')
554
556
555 exc_msg = dh.session.send(dh.pub_socket, u'pyerr', json_clean(exc_content), dh.parent_header, ident=topic)
557 exc_msg = dh.session.send(dh.pub_socket, u'pyerr', json_clean(exc_content), dh.parent_header, ident=topic)
556
558
557 # FIXME - Hack: store exception info in shell object. Right now, the
559 # FIXME - Hack: store exception info in shell object. Right now, the
558 # caller is reading this info after the fact, we need to fix this logic
560 # caller is reading this info after the fact, we need to fix this logic
559 # to remove this hack. Even uglier, we need to store the error status
561 # to remove this hack. Even uglier, we need to store the error status
560 # here, because in the main loop, the logic that sets it is being
562 # here, because in the main loop, the logic that sets it is being
561 # skipped because runlines swallows the exceptions.
563 # skipped because runlines swallows the exceptions.
562 exc_content[u'status'] = u'error'
564 exc_content[u'status'] = u'error'
563 self._reply_content = exc_content
565 self._reply_content = exc_content
564 # /FIXME
566 # /FIXME
565
567
566 return exc_content
568 return exc_content
567
569
568 def set_next_input(self, text):
570 def set_next_input(self, text):
569 """Send the specified text to the frontend to be presented at the next
571 """Send the specified text to the frontend to be presented at the next
570 input cell."""
572 input cell."""
571 payload = dict(
573 payload = dict(
572 source='IPython.zmq.zmqshell.ZMQInteractiveShell.set_next_input',
574 source='IPython.zmq.zmqshell.ZMQInteractiveShell.set_next_input',
573 text=text
575 text=text
574 )
576 )
575 self.payload_manager.write_payload(payload)
577 self.payload_manager.write_payload(payload)
576
578
577 #-------------------------------------------------------------------------
579 #-------------------------------------------------------------------------
578 # Things related to magics
580 # Things related to magics
579 #-------------------------------------------------------------------------
581 #-------------------------------------------------------------------------
580
582
581 def init_magics(self):
583 def init_magics(self):
582 super(ZMQInteractiveShell, self).init_magics()
584 super(ZMQInteractiveShell, self).init_magics()
583 self.register_magics(KernelMagics)
585 self.register_magics(KernelMagics)
584 self.magics_manager.register_alias('ed', 'edit')
586 self.magics_manager.register_alias('ed', 'edit')
585
587
586
588
587
589
588 InteractiveShellABC.register(ZMQInteractiveShell)
590 InteractiveShellABC.register(ZMQInteractiveShell)
General Comments 0
You need to be logged in to leave comments. Login now