##// END OF EJS Templates
Use safe_hasattr in dir2...
Jeffrey Tratner -
Show More
@@ -1,882 +1,873 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 inspect
21 import inspect
22 import linecache
22 import linecache
23 import os
23 import os
24 import types
24 import types
25 import io as stdlib_io
25 import io as stdlib_io
26
26
27 try:
27 try:
28 from itertools import izip_longest
28 from itertools import izip_longest
29 except ImportError:
29 except ImportError:
30 from itertools import zip_longest as izip_longest
30 from itertools import zip_longest as izip_longest
31
31
32 # IPython's own
32 # IPython's own
33 from IPython.core import page
33 from IPython.core import page
34 from IPython.testing.skipdoctest import skip_doctest_py3
34 from IPython.testing.skipdoctest import skip_doctest_py3
35 from IPython.utils import PyColorize
35 from IPython.utils import PyColorize
36 from IPython.utils import io
36 from IPython.utils import io
37 from IPython.utils import openpy
37 from IPython.utils import openpy
38 from IPython.utils import py3compat
38 from IPython.utils import py3compat
39 from IPython.utils.dir2 import safe_hasattr
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 from IPython.utils.py3compat import cast_unicode
43 from IPython.utils.py3compat import cast_unicode
43
44
44 #****************************************************************************
45 #****************************************************************************
45 # Builtin color schemes
46 # Builtin color schemes
46
47
47 Colors = TermColors # just a shorthand
48 Colors = TermColors # just a shorthand
48
49
49 # Build a few color schemes
50 # Build a few color schemes
50 NoColor = ColorScheme(
51 NoColor = ColorScheme(
51 'NoColor',{
52 'NoColor',{
52 'header' : Colors.NoColor,
53 'header' : Colors.NoColor,
53 'normal' : Colors.NoColor # color off (usu. Colors.Normal)
54 'normal' : Colors.NoColor # color off (usu. Colors.Normal)
54 } )
55 } )
55
56
56 LinuxColors = ColorScheme(
57 LinuxColors = ColorScheme(
57 'Linux',{
58 'Linux',{
58 'header' : Colors.LightRed,
59 'header' : Colors.LightRed,
59 'normal' : Colors.Normal # color off (usu. Colors.Normal)
60 'normal' : Colors.Normal # color off (usu. Colors.Normal)
60 } )
61 } )
61
62
62 LightBGColors = ColorScheme(
63 LightBGColors = ColorScheme(
63 'LightBG',{
64 'LightBG',{
64 'header' : Colors.Red,
65 'header' : Colors.Red,
65 'normal' : Colors.Normal # color off (usu. Colors.Normal)
66 'normal' : Colors.Normal # color off (usu. Colors.Normal)
66 } )
67 } )
67
68
68 # Build table of color schemes (needed by the parser)
69 # Build table of color schemes (needed by the parser)
69 InspectColors = ColorSchemeTable([NoColor,LinuxColors,LightBGColors],
70 InspectColors = ColorSchemeTable([NoColor,LinuxColors,LightBGColors],
70 'Linux')
71 'Linux')
71
72
72 #****************************************************************************
73 #****************************************************************************
73 # Auxiliary functions and objects
74 # Auxiliary functions and objects
74
75
75 # See the messaging spec for the definition of all these fields. This list
76 # See the messaging spec for the definition of all these fields. This list
76 # effectively defines the order of display
77 # effectively defines the order of display
77 info_fields = ['type_name', 'base_class', 'string_form', 'namespace',
78 info_fields = ['type_name', 'base_class', 'string_form', 'namespace',
78 'length', 'file', 'definition', 'docstring', 'source',
79 'length', 'file', 'definition', 'docstring', 'source',
79 'init_definition', 'class_docstring', 'init_docstring',
80 'init_definition', 'class_docstring', 'init_docstring',
80 'call_def', 'call_docstring',
81 'call_def', 'call_docstring',
81 # These won't be printed but will be used to determine how to
82 # These won't be printed but will be used to determine how to
82 # format the object
83 # format the object
83 'ismagic', 'isalias', 'isclass', 'argspec', 'found', 'name'
84 'ismagic', 'isalias', 'isclass', 'argspec', 'found', 'name'
84 ]
85 ]
85
86
86
87
87 def object_info(**kw):
88 def object_info(**kw):
88 """Make an object info dict with all fields present."""
89 """Make an object info dict with all fields present."""
89 infodict = dict(izip_longest(info_fields, [None]))
90 infodict = dict(izip_longest(info_fields, [None]))
90 infodict.update(kw)
91 infodict.update(kw)
91 return infodict
92 return infodict
92
93
93
94
94 def get_encoding(obj):
95 def get_encoding(obj):
95 """Get encoding for python source file defining obj
96 """Get encoding for python source file defining obj
96
97
97 Returns None if obj is not defined in a sourcefile.
98 Returns None if obj is not defined in a sourcefile.
98 """
99 """
99 ofile = find_file(obj)
100 ofile = find_file(obj)
100 # run contents of file through pager starting at line where the object
101 # run contents of file through pager starting at line where the object
101 # is defined, as long as the file isn't binary and is actually on the
102 # is defined, as long as the file isn't binary and is actually on the
102 # filesystem.
103 # filesystem.
103 if ofile is None:
104 if ofile is None:
104 return None
105 return None
105 elif ofile.endswith(('.so', '.dll', '.pyd')):
106 elif ofile.endswith(('.so', '.dll', '.pyd')):
106 return None
107 return None
107 elif not os.path.isfile(ofile):
108 elif not os.path.isfile(ofile):
108 return None
109 return None
109 else:
110 else:
110 # Print only text files, not extension binaries. Note that
111 # Print only text files, not extension binaries. Note that
111 # getsourcelines returns lineno with 1-offset and page() uses
112 # getsourcelines returns lineno with 1-offset and page() uses
112 # 0-offset, so we must adjust.
113 # 0-offset, so we must adjust.
113 buffer = stdlib_io.open(ofile, 'rb') # Tweaked to use io.open for Python 2
114 buffer = stdlib_io.open(ofile, 'rb') # Tweaked to use io.open for Python 2
114 encoding, lines = openpy.detect_encoding(buffer.readline)
115 encoding, lines = openpy.detect_encoding(buffer.readline)
115 return encoding
116 return encoding
116
117
117 def getdoc(obj):
118 def getdoc(obj):
118 """Stable wrapper around inspect.getdoc.
119 """Stable wrapper around inspect.getdoc.
119
120
120 This can't crash because of attribute problems.
121 This can't crash because of attribute problems.
121
122
122 It also attempts to call a getdoc() method on the given object. This
123 It also attempts to call a getdoc() method on the given object. This
123 allows objects which provide their docstrings via non-standard mechanisms
124 allows objects which provide their docstrings via non-standard mechanisms
124 (like Pyro proxies) to still be inspected by ipython's ? system."""
125 (like Pyro proxies) to still be inspected by ipython's ? system."""
125 # Allow objects to offer customized documentation via a getdoc method:
126 # Allow objects to offer customized documentation via a getdoc method:
126 try:
127 try:
127 ds = obj.getdoc()
128 ds = obj.getdoc()
128 except Exception:
129 except Exception:
129 pass
130 pass
130 else:
131 else:
131 # if we get extra info, we add it to the normal docstring.
132 # if we get extra info, we add it to the normal docstring.
132 if isinstance(ds, basestring):
133 if isinstance(ds, basestring):
133 return inspect.cleandoc(ds)
134 return inspect.cleandoc(ds)
134
135
135 try:
136 try:
136 docstr = inspect.getdoc(obj)
137 docstr = inspect.getdoc(obj)
137 encoding = get_encoding(obj)
138 encoding = get_encoding(obj)
138 return py3compat.cast_unicode(docstr, encoding=encoding)
139 return py3compat.cast_unicode(docstr, encoding=encoding)
139 except Exception:
140 except Exception:
140 # Harden against an inspect failure, which can occur with
141 # Harden against an inspect failure, which can occur with
141 # SWIG-wrapped extensions.
142 # SWIG-wrapped extensions.
142 raise
143 raise
143 return None
144 return None
144
145
145
146
146 def getsource(obj,is_binary=False):
147 def getsource(obj,is_binary=False):
147 """Wrapper around inspect.getsource.
148 """Wrapper around inspect.getsource.
148
149
149 This can be modified by other projects to provide customized source
150 This can be modified by other projects to provide customized source
150 extraction.
151 extraction.
151
152
152 Inputs:
153 Inputs:
153
154
154 - obj: an object whose source code we will attempt to extract.
155 - obj: an object whose source code we will attempt to extract.
155
156
156 Optional inputs:
157 Optional inputs:
157
158
158 - is_binary: whether the object is known to come from a binary source.
159 - is_binary: whether the object is known to come from a binary source.
159 This implementation will skip returning any output for binary objects, but
160 This implementation will skip returning any output for binary objects, but
160 custom extractors may know how to meaningfully process them."""
161 custom extractors may know how to meaningfully process them."""
161
162
162 if is_binary:
163 if is_binary:
163 return None
164 return None
164 else:
165 else:
165 # get source if obj was decorated with @decorator
166 # get source if obj was decorated with @decorator
166 if hasattr(obj,"__wrapped__"):
167 if hasattr(obj,"__wrapped__"):
167 obj = obj.__wrapped__
168 obj = obj.__wrapped__
168 try:
169 try:
169 src = inspect.getsource(obj)
170 src = inspect.getsource(obj)
170 except TypeError:
171 except TypeError:
171 if hasattr(obj,'__class__'):
172 if hasattr(obj,'__class__'):
172 src = inspect.getsource(obj.__class__)
173 src = inspect.getsource(obj.__class__)
173 encoding = get_encoding(obj)
174 encoding = get_encoding(obj)
174 return cast_unicode(src, encoding=encoding)
175 return cast_unicode(src, encoding=encoding)
175
176
176 def getargspec(obj):
177 def getargspec(obj):
177 """Get the names and default values of a function's arguments.
178 """Get the names and default values of a function's arguments.
178
179
179 A tuple of four things is returned: (args, varargs, varkw, defaults).
180 A tuple of four things is returned: (args, varargs, varkw, defaults).
180 'args' is a list of the argument names (it may contain nested lists).
181 'args' is a list of the argument names (it may contain nested lists).
181 'varargs' and 'varkw' are the names of the * and ** arguments or None.
182 'varargs' and 'varkw' are the names of the * and ** arguments or None.
182 'defaults' is an n-tuple of the default values of the last n arguments.
183 'defaults' is an n-tuple of the default values of the last n arguments.
183
184
184 Modified version of inspect.getargspec from the Python Standard
185 Modified version of inspect.getargspec from the Python Standard
185 Library."""
186 Library."""
186
187
187 if inspect.isfunction(obj):
188 if inspect.isfunction(obj):
188 func_obj = obj
189 func_obj = obj
189 elif inspect.ismethod(obj):
190 elif inspect.ismethod(obj):
190 func_obj = obj.im_func
191 func_obj = obj.im_func
191 elif hasattr(obj, '__call__'):
192 elif hasattr(obj, '__call__'):
192 func_obj = obj.__call__
193 func_obj = obj.__call__
193 else:
194 else:
194 raise TypeError('arg is not a Python function')
195 raise TypeError('arg is not a Python function')
195 args, varargs, varkw = inspect.getargs(func_obj.func_code)
196 args, varargs, varkw = inspect.getargs(func_obj.func_code)
196 return args, varargs, varkw, func_obj.func_defaults
197 return args, varargs, varkw, func_obj.func_defaults
197
198
198
199
199 def format_argspec(argspec):
200 def format_argspec(argspec):
200 """Format argspect, convenience wrapper around inspect's.
201 """Format argspect, convenience wrapper around inspect's.
201
202
202 This takes a dict instead of ordered arguments and calls
203 This takes a dict instead of ordered arguments and calls
203 inspect.format_argspec with the arguments in the necessary order.
204 inspect.format_argspec with the arguments in the necessary order.
204 """
205 """
205 return inspect.formatargspec(argspec['args'], argspec['varargs'],
206 return inspect.formatargspec(argspec['args'], argspec['varargs'],
206 argspec['varkw'], argspec['defaults'])
207 argspec['varkw'], argspec['defaults'])
207
208
208
209
209 def call_tip(oinfo, format_call=True):
210 def call_tip(oinfo, format_call=True):
210 """Extract call tip data from an oinfo dict.
211 """Extract call tip data from an oinfo dict.
211
212
212 Parameters
213 Parameters
213 ----------
214 ----------
214 oinfo : dict
215 oinfo : dict
215
216
216 format_call : bool, optional
217 format_call : bool, optional
217 If True, the call line is formatted and returned as a string. If not, a
218 If True, the call line is formatted and returned as a string. If not, a
218 tuple of (name, argspec) is returned.
219 tuple of (name, argspec) is returned.
219
220
220 Returns
221 Returns
221 -------
222 -------
222 call_info : None, str or (str, dict) tuple.
223 call_info : None, str or (str, dict) tuple.
223 When format_call is True, the whole call information is formattted as a
224 When format_call is True, the whole call information is formattted as a
224 single string. Otherwise, the object's name and its argspec dict are
225 single string. Otherwise, the object's name and its argspec dict are
225 returned. If no call information is available, None is returned.
226 returned. If no call information is available, None is returned.
226
227
227 docstring : str or None
228 docstring : str or None
228 The most relevant docstring for calling purposes is returned, if
229 The most relevant docstring for calling purposes is returned, if
229 available. The priority is: call docstring for callable instances, then
230 available. The priority is: call docstring for callable instances, then
230 constructor docstring for classes, then main object's docstring otherwise
231 constructor docstring for classes, then main object's docstring otherwise
231 (regular functions).
232 (regular functions).
232 """
233 """
233 # Get call definition
234 # Get call definition
234 argspec = oinfo.get('argspec')
235 argspec = oinfo.get('argspec')
235 if argspec is None:
236 if argspec is None:
236 call_line = None
237 call_line = None
237 else:
238 else:
238 # Callable objects will have 'self' as their first argument, prune
239 # Callable objects will have 'self' as their first argument, prune
239 # it out if it's there for clarity (since users do *not* pass an
240 # it out if it's there for clarity (since users do *not* pass an
240 # extra first argument explicitly).
241 # extra first argument explicitly).
241 try:
242 try:
242 has_self = argspec['args'][0] == 'self'
243 has_self = argspec['args'][0] == 'self'
243 except (KeyError, IndexError):
244 except (KeyError, IndexError):
244 pass
245 pass
245 else:
246 else:
246 if has_self:
247 if has_self:
247 argspec['args'] = argspec['args'][1:]
248 argspec['args'] = argspec['args'][1:]
248
249
249 call_line = oinfo['name']+format_argspec(argspec)
250 call_line = oinfo['name']+format_argspec(argspec)
250
251
251 # Now get docstring.
252 # Now get docstring.
252 # The priority is: call docstring, constructor docstring, main one.
253 # The priority is: call docstring, constructor docstring, main one.
253 doc = oinfo.get('call_docstring')
254 doc = oinfo.get('call_docstring')
254 if doc is None:
255 if doc is None:
255 doc = oinfo.get('init_docstring')
256 doc = oinfo.get('init_docstring')
256 if doc is None:
257 if doc is None:
257 doc = oinfo.get('docstring','')
258 doc = oinfo.get('docstring','')
258
259
259 return call_line, doc
260 return call_line, doc
260
261
261 def safe_hasattr(obj, attr):
262 """In recent versions of Python, hasattr() only catches AttributeError.
263 This catches all errors.
264 """
265 try:
266 getattr(obj, attr)
267 return True
268 except:
269 return False
270
271
262
272 def find_file(obj):
263 def find_file(obj):
273 """Find the absolute path to the file where an object was defined.
264 """Find the absolute path to the file where an object was defined.
274
265
275 This is essentially a robust wrapper around `inspect.getabsfile`.
266 This is essentially a robust wrapper around `inspect.getabsfile`.
276
267
277 Returns None if no file can be found.
268 Returns None if no file can be found.
278
269
279 Parameters
270 Parameters
280 ----------
271 ----------
281 obj : any Python object
272 obj : any Python object
282
273
283 Returns
274 Returns
284 -------
275 -------
285 fname : str
276 fname : str
286 The absolute path to the file where the object was defined.
277 The absolute path to the file where the object was defined.
287 """
278 """
288 # get source if obj was decorated with @decorator
279 # get source if obj was decorated with @decorator
289 if safe_hasattr(obj, '__wrapped__'):
280 if safe_hasattr(obj, '__wrapped__'):
290 obj = obj.__wrapped__
281 obj = obj.__wrapped__
291
282
292 fname = None
283 fname = None
293 try:
284 try:
294 fname = inspect.getabsfile(obj)
285 fname = inspect.getabsfile(obj)
295 except TypeError:
286 except TypeError:
296 # For an instance, the file that matters is where its class was
287 # For an instance, the file that matters is where its class was
297 # declared.
288 # declared.
298 if hasattr(obj, '__class__'):
289 if hasattr(obj, '__class__'):
299 try:
290 try:
300 fname = inspect.getabsfile(obj.__class__)
291 fname = inspect.getabsfile(obj.__class__)
301 except TypeError:
292 except TypeError:
302 # Can happen for builtins
293 # Can happen for builtins
303 pass
294 pass
304 except:
295 except:
305 pass
296 pass
306 return cast_unicode(fname)
297 return cast_unicode(fname)
307
298
308
299
309 def find_source_lines(obj):
300 def find_source_lines(obj):
310 """Find the line number in a file where an object was defined.
301 """Find the line number in a file where an object was defined.
311
302
312 This is essentially a robust wrapper around `inspect.getsourcelines`.
303 This is essentially a robust wrapper around `inspect.getsourcelines`.
313
304
314 Returns None if no file can be found.
305 Returns None if no file can be found.
315
306
316 Parameters
307 Parameters
317 ----------
308 ----------
318 obj : any Python object
309 obj : any Python object
319
310
320 Returns
311 Returns
321 -------
312 -------
322 lineno : int
313 lineno : int
323 The line number where the object definition starts.
314 The line number where the object definition starts.
324 """
315 """
325 # get source if obj was decorated with @decorator
316 # get source if obj was decorated with @decorator
326 if safe_hasattr(obj, '__wrapped__'):
317 if safe_hasattr(obj, '__wrapped__'):
327 obj = obj.__wrapped__
318 obj = obj.__wrapped__
328
319
329 try:
320 try:
330 try:
321 try:
331 lineno = inspect.getsourcelines(obj)[1]
322 lineno = inspect.getsourcelines(obj)[1]
332 except TypeError:
323 except TypeError:
333 # For instances, try the class object like getsource() does
324 # For instances, try the class object like getsource() does
334 if hasattr(obj, '__class__'):
325 if hasattr(obj, '__class__'):
335 lineno = inspect.getsourcelines(obj.__class__)[1]
326 lineno = inspect.getsourcelines(obj.__class__)[1]
336 else:
327 else:
337 lineno = None
328 lineno = None
338 except:
329 except:
339 return None
330 return None
340
331
341 return lineno
332 return lineno
342
333
343
334
344 class Inspector:
335 class Inspector:
345 def __init__(self, color_table=InspectColors,
336 def __init__(self, color_table=InspectColors,
346 code_color_table=PyColorize.ANSICodeColors,
337 code_color_table=PyColorize.ANSICodeColors,
347 scheme='NoColor',
338 scheme='NoColor',
348 str_detail_level=0):
339 str_detail_level=0):
349 self.color_table = color_table
340 self.color_table = color_table
350 self.parser = PyColorize.Parser(code_color_table,out='str')
341 self.parser = PyColorize.Parser(code_color_table,out='str')
351 self.format = self.parser.format
342 self.format = self.parser.format
352 self.str_detail_level = str_detail_level
343 self.str_detail_level = str_detail_level
353 self.set_active_scheme(scheme)
344 self.set_active_scheme(scheme)
354
345
355 def _getdef(self,obj,oname=''):
346 def _getdef(self,obj,oname=''):
356 """Return the call signature for any callable object.
347 """Return the call signature for any callable object.
357
348
358 If any exception is generated, None is returned instead and the
349 If any exception is generated, None is returned instead and the
359 exception is suppressed."""
350 exception is suppressed."""
360
351
361 try:
352 try:
362 hdef = oname + inspect.formatargspec(*getargspec(obj))
353 hdef = oname + inspect.formatargspec(*getargspec(obj))
363 return cast_unicode(hdef)
354 return cast_unicode(hdef)
364 except:
355 except:
365 return None
356 return None
366
357
367 def __head(self,h):
358 def __head(self,h):
368 """Return a header string with proper colors."""
359 """Return a header string with proper colors."""
369 return '%s%s%s' % (self.color_table.active_colors.header,h,
360 return '%s%s%s' % (self.color_table.active_colors.header,h,
370 self.color_table.active_colors.normal)
361 self.color_table.active_colors.normal)
371
362
372 def set_active_scheme(self, scheme):
363 def set_active_scheme(self, scheme):
373 self.color_table.set_active_scheme(scheme)
364 self.color_table.set_active_scheme(scheme)
374 self.parser.color_table.set_active_scheme(scheme)
365 self.parser.color_table.set_active_scheme(scheme)
375
366
376 def noinfo(self, msg, oname):
367 def noinfo(self, msg, oname):
377 """Generic message when no information is found."""
368 """Generic message when no information is found."""
378 print('No %s found' % msg, end=' ')
369 print('No %s found' % msg, end=' ')
379 if oname:
370 if oname:
380 print('for %s' % oname)
371 print('for %s' % oname)
381 else:
372 else:
382 print()
373 print()
383
374
384 def pdef(self, obj, oname=''):
375 def pdef(self, obj, oname=''):
385 """Print the call signature for any callable object.
376 """Print the call signature for any callable object.
386
377
387 If the object is a class, print the constructor information."""
378 If the object is a class, print the constructor information."""
388
379
389 if not callable(obj):
380 if not callable(obj):
390 print('Object is not callable.')
381 print('Object is not callable.')
391 return
382 return
392
383
393 header = ''
384 header = ''
394
385
395 if inspect.isclass(obj):
386 if inspect.isclass(obj):
396 header = self.__head('Class constructor information:\n')
387 header = self.__head('Class constructor information:\n')
397 obj = obj.__init__
388 obj = obj.__init__
398 elif (not py3compat.PY3) and type(obj) is types.InstanceType:
389 elif (not py3compat.PY3) and type(obj) is types.InstanceType:
399 obj = obj.__call__
390 obj = obj.__call__
400
391
401 output = self._getdef(obj,oname)
392 output = self._getdef(obj,oname)
402 if output is None:
393 if output is None:
403 self.noinfo('definition header',oname)
394 self.noinfo('definition header',oname)
404 else:
395 else:
405 print(header,self.format(output), end=' ', file=io.stdout)
396 print(header,self.format(output), end=' ', file=io.stdout)
406
397
407 # In Python 3, all classes are new-style, so they all have __init__.
398 # In Python 3, all classes are new-style, so they all have __init__.
408 @skip_doctest_py3
399 @skip_doctest_py3
409 def pdoc(self,obj,oname='',formatter = None):
400 def pdoc(self,obj,oname='',formatter = None):
410 """Print the docstring for any object.
401 """Print the docstring for any object.
411
402
412 Optional:
403 Optional:
413 -formatter: a function to run the docstring through for specially
404 -formatter: a function to run the docstring through for specially
414 formatted docstrings.
405 formatted docstrings.
415
406
416 Examples
407 Examples
417 --------
408 --------
418
409
419 In [1]: class NoInit:
410 In [1]: class NoInit:
420 ...: pass
411 ...: pass
421
412
422 In [2]: class NoDoc:
413 In [2]: class NoDoc:
423 ...: def __init__(self):
414 ...: def __init__(self):
424 ...: pass
415 ...: pass
425
416
426 In [3]: %pdoc NoDoc
417 In [3]: %pdoc NoDoc
427 No documentation found for NoDoc
418 No documentation found for NoDoc
428
419
429 In [4]: %pdoc NoInit
420 In [4]: %pdoc NoInit
430 No documentation found for NoInit
421 No documentation found for NoInit
431
422
432 In [5]: obj = NoInit()
423 In [5]: obj = NoInit()
433
424
434 In [6]: %pdoc obj
425 In [6]: %pdoc obj
435 No documentation found for obj
426 No documentation found for obj
436
427
437 In [5]: obj2 = NoDoc()
428 In [5]: obj2 = NoDoc()
438
429
439 In [6]: %pdoc obj2
430 In [6]: %pdoc obj2
440 No documentation found for obj2
431 No documentation found for obj2
441 """
432 """
442
433
443 head = self.__head # For convenience
434 head = self.__head # For convenience
444 lines = []
435 lines = []
445 ds = getdoc(obj)
436 ds = getdoc(obj)
446 if formatter:
437 if formatter:
447 ds = formatter(ds)
438 ds = formatter(ds)
448 if ds:
439 if ds:
449 lines.append(head("Class Docstring:"))
440 lines.append(head("Class Docstring:"))
450 lines.append(indent(ds))
441 lines.append(indent(ds))
451 if inspect.isclass(obj) and hasattr(obj, '__init__'):
442 if inspect.isclass(obj) and hasattr(obj, '__init__'):
452 init_ds = getdoc(obj.__init__)
443 init_ds = getdoc(obj.__init__)
453 if init_ds is not None:
444 if init_ds is not None:
454 lines.append(head("Constructor Docstring:"))
445 lines.append(head("Constructor Docstring:"))
455 lines.append(indent(init_ds))
446 lines.append(indent(init_ds))
456 elif hasattr(obj,'__call__'):
447 elif hasattr(obj,'__call__'):
457 call_ds = getdoc(obj.__call__)
448 call_ds = getdoc(obj.__call__)
458 if call_ds:
449 if call_ds:
459 lines.append(head("Calling Docstring:"))
450 lines.append(head("Calling Docstring:"))
460 lines.append(indent(call_ds))
451 lines.append(indent(call_ds))
461
452
462 if not lines:
453 if not lines:
463 self.noinfo('documentation',oname)
454 self.noinfo('documentation',oname)
464 else:
455 else:
465 page.page('\n'.join(lines))
456 page.page('\n'.join(lines))
466
457
467 def psource(self,obj,oname=''):
458 def psource(self,obj,oname=''):
468 """Print the source code for an object."""
459 """Print the source code for an object."""
469
460
470 # Flush the source cache because inspect can return out-of-date source
461 # Flush the source cache because inspect can return out-of-date source
471 linecache.checkcache()
462 linecache.checkcache()
472 try:
463 try:
473 src = getsource(obj)
464 src = getsource(obj)
474 except:
465 except:
475 self.noinfo('source',oname)
466 self.noinfo('source',oname)
476 else:
467 else:
477 page.page(self.format(src))
468 page.page(self.format(src))
478
469
479 def pfile(self, obj, oname=''):
470 def pfile(self, obj, oname=''):
480 """Show the whole file where an object was defined."""
471 """Show the whole file where an object was defined."""
481
472
482 lineno = find_source_lines(obj)
473 lineno = find_source_lines(obj)
483 if lineno is None:
474 if lineno is None:
484 self.noinfo('file', oname)
475 self.noinfo('file', oname)
485 return
476 return
486
477
487 ofile = find_file(obj)
478 ofile = find_file(obj)
488 # run contents of file through pager starting at line where the object
479 # run contents of file through pager starting at line where the object
489 # is defined, as long as the file isn't binary and is actually on the
480 # is defined, as long as the file isn't binary and is actually on the
490 # filesystem.
481 # filesystem.
491 if ofile.endswith(('.so', '.dll', '.pyd')):
482 if ofile.endswith(('.so', '.dll', '.pyd')):
492 print('File %r is binary, not printing.' % ofile)
483 print('File %r is binary, not printing.' % ofile)
493 elif not os.path.isfile(ofile):
484 elif not os.path.isfile(ofile):
494 print('File %r does not exist, not printing.' % ofile)
485 print('File %r does not exist, not printing.' % ofile)
495 else:
486 else:
496 # Print only text files, not extension binaries. Note that
487 # Print only text files, not extension binaries. Note that
497 # getsourcelines returns lineno with 1-offset and page() uses
488 # getsourcelines returns lineno with 1-offset and page() uses
498 # 0-offset, so we must adjust.
489 # 0-offset, so we must adjust.
499 page.page(self.format(openpy.read_py_file(ofile, skip_encoding_cookie=False)), lineno - 1)
490 page.page(self.format(openpy.read_py_file(ofile, skip_encoding_cookie=False)), lineno - 1)
500
491
501 def _format_fields(self, fields, title_width=12):
492 def _format_fields(self, fields, title_width=12):
502 """Formats a list of fields for display.
493 """Formats a list of fields for display.
503
494
504 Parameters
495 Parameters
505 ----------
496 ----------
506 fields : list
497 fields : list
507 A list of 2-tuples: (field_title, field_content)
498 A list of 2-tuples: (field_title, field_content)
508 title_width : int
499 title_width : int
509 How many characters to pad titles to. Default 12.
500 How many characters to pad titles to. Default 12.
510 """
501 """
511 out = []
502 out = []
512 header = self.__head
503 header = self.__head
513 for title, content in fields:
504 for title, content in fields:
514 if len(content.splitlines()) > 1:
505 if len(content.splitlines()) > 1:
515 title = header(title + ":") + "\n"
506 title = header(title + ":") + "\n"
516 else:
507 else:
517 title = header((title+":").ljust(title_width))
508 title = header((title+":").ljust(title_width))
518 out.append(cast_unicode(title) + cast_unicode(content))
509 out.append(cast_unicode(title) + cast_unicode(content))
519 return "\n".join(out)
510 return "\n".join(out)
520
511
521 # The fields to be displayed by pinfo: (fancy_name, key_in_info_dict)
512 # The fields to be displayed by pinfo: (fancy_name, key_in_info_dict)
522 pinfo_fields1 = [("Type", "type_name"),
513 pinfo_fields1 = [("Type", "type_name"),
523 ]
514 ]
524
515
525 pinfo_fields2 = [("String Form", "string_form"),
516 pinfo_fields2 = [("String Form", "string_form"),
526 ]
517 ]
527
518
528 pinfo_fields3 = [("Length", "length"),
519 pinfo_fields3 = [("Length", "length"),
529 ("File", "file"),
520 ("File", "file"),
530 ("Definition", "definition"),
521 ("Definition", "definition"),
531 ]
522 ]
532
523
533 pinfo_fields_obj = [("Class Docstring", "class_docstring"),
524 pinfo_fields_obj = [("Class Docstring", "class_docstring"),
534 ("Constructor Docstring","init_docstring"),
525 ("Constructor Docstring","init_docstring"),
535 ("Call def", "call_def"),
526 ("Call def", "call_def"),
536 ("Call docstring", "call_docstring")]
527 ("Call docstring", "call_docstring")]
537
528
538 def pinfo(self,obj,oname='',formatter=None,info=None,detail_level=0):
529 def pinfo(self,obj,oname='',formatter=None,info=None,detail_level=0):
539 """Show detailed information about an object.
530 """Show detailed information about an object.
540
531
541 Optional arguments:
532 Optional arguments:
542
533
543 - oname: name of the variable pointing to the object.
534 - oname: name of the variable pointing to the object.
544
535
545 - formatter: special formatter for docstrings (see pdoc)
536 - formatter: special formatter for docstrings (see pdoc)
546
537
547 - info: a structure with some information fields which may have been
538 - info: a structure with some information fields which may have been
548 precomputed already.
539 precomputed already.
549
540
550 - detail_level: if set to 1, more information is given.
541 - detail_level: if set to 1, more information is given.
551 """
542 """
552 info = self.info(obj, oname=oname, formatter=formatter,
543 info = self.info(obj, oname=oname, formatter=formatter,
553 info=info, detail_level=detail_level)
544 info=info, detail_level=detail_level)
554 displayfields = []
545 displayfields = []
555 def add_fields(fields):
546 def add_fields(fields):
556 for title, key in fields:
547 for title, key in fields:
557 field = info[key]
548 field = info[key]
558 if field is not None:
549 if field is not None:
559 displayfields.append((title, field.rstrip()))
550 displayfields.append((title, field.rstrip()))
560
551
561 add_fields(self.pinfo_fields1)
552 add_fields(self.pinfo_fields1)
562
553
563 # Base class for old-style instances
554 # Base class for old-style instances
564 if (not py3compat.PY3) and isinstance(obj, types.InstanceType) and info['base_class']:
555 if (not py3compat.PY3) and isinstance(obj, types.InstanceType) and info['base_class']:
565 displayfields.append(("Base Class", info['base_class'].rstrip()))
556 displayfields.append(("Base Class", info['base_class'].rstrip()))
566
557
567 add_fields(self.pinfo_fields2)
558 add_fields(self.pinfo_fields2)
568
559
569 # Namespace
560 # Namespace
570 if info['namespace'] != 'Interactive':
561 if info['namespace'] != 'Interactive':
571 displayfields.append(("Namespace", info['namespace'].rstrip()))
562 displayfields.append(("Namespace", info['namespace'].rstrip()))
572
563
573 add_fields(self.pinfo_fields3)
564 add_fields(self.pinfo_fields3)
574
565
575 # Source or docstring, depending on detail level and whether
566 # Source or docstring, depending on detail level and whether
576 # source found.
567 # source found.
577 if detail_level > 0 and info['source'] is not None:
568 if detail_level > 0 and info['source'] is not None:
578 displayfields.append(("Source",
569 displayfields.append(("Source",
579 self.format(cast_unicode(info['source']))))
570 self.format(cast_unicode(info['source']))))
580 elif info['docstring'] is not None:
571 elif info['docstring'] is not None:
581 displayfields.append(("Docstring", info["docstring"]))
572 displayfields.append(("Docstring", info["docstring"]))
582
573
583 # Constructor info for classes
574 # Constructor info for classes
584 if info['isclass']:
575 if info['isclass']:
585 if info['init_definition'] or info['init_docstring']:
576 if info['init_definition'] or info['init_docstring']:
586 displayfields.append(("Constructor information", ""))
577 displayfields.append(("Constructor information", ""))
587 if info['init_definition'] is not None:
578 if info['init_definition'] is not None:
588 displayfields.append((" Definition",
579 displayfields.append((" Definition",
589 info['init_definition'].rstrip()))
580 info['init_definition'].rstrip()))
590 if info['init_docstring'] is not None:
581 if info['init_docstring'] is not None:
591 displayfields.append((" Docstring",
582 displayfields.append((" Docstring",
592 indent(info['init_docstring'])))
583 indent(info['init_docstring'])))
593
584
594 # Info for objects:
585 # Info for objects:
595 else:
586 else:
596 add_fields(self.pinfo_fields_obj)
587 add_fields(self.pinfo_fields_obj)
597
588
598 # Finally send to printer/pager:
589 # Finally send to printer/pager:
599 if displayfields:
590 if displayfields:
600 page.page(self._format_fields(displayfields))
591 page.page(self._format_fields(displayfields))
601
592
602 def info(self, obj, oname='', formatter=None, info=None, detail_level=0):
593 def info(self, obj, oname='', formatter=None, info=None, detail_level=0):
603 """Compute a dict with detailed information about an object.
594 """Compute a dict with detailed information about an object.
604
595
605 Optional arguments:
596 Optional arguments:
606
597
607 - oname: name of the variable pointing to the object.
598 - oname: name of the variable pointing to the object.
608
599
609 - formatter: special formatter for docstrings (see pdoc)
600 - formatter: special formatter for docstrings (see pdoc)
610
601
611 - info: a structure with some information fields which may have been
602 - info: a structure with some information fields which may have been
612 precomputed already.
603 precomputed already.
613
604
614 - detail_level: if set to 1, more information is given.
605 - detail_level: if set to 1, more information is given.
615 """
606 """
616
607
617 obj_type = type(obj)
608 obj_type = type(obj)
618
609
619 header = self.__head
610 header = self.__head
620 if info is None:
611 if info is None:
621 ismagic = 0
612 ismagic = 0
622 isalias = 0
613 isalias = 0
623 ospace = ''
614 ospace = ''
624 else:
615 else:
625 ismagic = info.ismagic
616 ismagic = info.ismagic
626 isalias = info.isalias
617 isalias = info.isalias
627 ospace = info.namespace
618 ospace = info.namespace
628
619
629 # Get docstring, special-casing aliases:
620 # Get docstring, special-casing aliases:
630 if isalias:
621 if isalias:
631 if not callable(obj):
622 if not callable(obj):
632 try:
623 try:
633 ds = "Alias to the system command:\n %s" % obj[1]
624 ds = "Alias to the system command:\n %s" % obj[1]
634 except:
625 except:
635 ds = "Alias: " + str(obj)
626 ds = "Alias: " + str(obj)
636 else:
627 else:
637 ds = "Alias to " + str(obj)
628 ds = "Alias to " + str(obj)
638 if obj.__doc__:
629 if obj.__doc__:
639 ds += "\nDocstring:\n" + obj.__doc__
630 ds += "\nDocstring:\n" + obj.__doc__
640 else:
631 else:
641 ds = getdoc(obj)
632 ds = getdoc(obj)
642 if ds is None:
633 if ds is None:
643 ds = '<no docstring>'
634 ds = '<no docstring>'
644 if formatter is not None:
635 if formatter is not None:
645 ds = formatter(ds)
636 ds = formatter(ds)
646
637
647 # store output in a dict, we initialize it here and fill it as we go
638 # store output in a dict, we initialize it here and fill it as we go
648 out = dict(name=oname, found=True, isalias=isalias, ismagic=ismagic)
639 out = dict(name=oname, found=True, isalias=isalias, ismagic=ismagic)
649
640
650 string_max = 200 # max size of strings to show (snipped if longer)
641 string_max = 200 # max size of strings to show (snipped if longer)
651 shalf = int((string_max -5)/2)
642 shalf = int((string_max -5)/2)
652
643
653 if ismagic:
644 if ismagic:
654 obj_type_name = 'Magic function'
645 obj_type_name = 'Magic function'
655 elif isalias:
646 elif isalias:
656 obj_type_name = 'System alias'
647 obj_type_name = 'System alias'
657 else:
648 else:
658 obj_type_name = obj_type.__name__
649 obj_type_name = obj_type.__name__
659 out['type_name'] = obj_type_name
650 out['type_name'] = obj_type_name
660
651
661 try:
652 try:
662 bclass = obj.__class__
653 bclass = obj.__class__
663 out['base_class'] = str(bclass)
654 out['base_class'] = str(bclass)
664 except: pass
655 except: pass
665
656
666 # String form, but snip if too long in ? form (full in ??)
657 # String form, but snip if too long in ? form (full in ??)
667 if detail_level >= self.str_detail_level:
658 if detail_level >= self.str_detail_level:
668 try:
659 try:
669 ostr = str(obj)
660 ostr = str(obj)
670 str_head = 'string_form'
661 str_head = 'string_form'
671 if not detail_level and len(ostr)>string_max:
662 if not detail_level and len(ostr)>string_max:
672 ostr = ostr[:shalf] + ' <...> ' + ostr[-shalf:]
663 ostr = ostr[:shalf] + ' <...> ' + ostr[-shalf:]
673 ostr = ("\n" + " " * len(str_head.expandtabs())).\
664 ostr = ("\n" + " " * len(str_head.expandtabs())).\
674 join(q.strip() for q in ostr.split("\n"))
665 join(q.strip() for q in ostr.split("\n"))
675 out[str_head] = ostr
666 out[str_head] = ostr
676 except:
667 except:
677 pass
668 pass
678
669
679 if ospace:
670 if ospace:
680 out['namespace'] = ospace
671 out['namespace'] = ospace
681
672
682 # Length (for strings and lists)
673 # Length (for strings and lists)
683 try:
674 try:
684 out['length'] = str(len(obj))
675 out['length'] = str(len(obj))
685 except: pass
676 except: pass
686
677
687 # Filename where object was defined
678 # Filename where object was defined
688 binary_file = False
679 binary_file = False
689 fname = find_file(obj)
680 fname = find_file(obj)
690 if fname is None:
681 if fname is None:
691 # if anything goes wrong, we don't want to show source, so it's as
682 # if anything goes wrong, we don't want to show source, so it's as
692 # if the file was binary
683 # if the file was binary
693 binary_file = True
684 binary_file = True
694 else:
685 else:
695 if fname.endswith(('.so', '.dll', '.pyd')):
686 if fname.endswith(('.so', '.dll', '.pyd')):
696 binary_file = True
687 binary_file = True
697 elif fname.endswith('<string>'):
688 elif fname.endswith('<string>'):
698 fname = 'Dynamically generated function. No source code available.'
689 fname = 'Dynamically generated function. No source code available.'
699 out['file'] = fname
690 out['file'] = fname
700
691
701 # reconstruct the function definition and print it:
692 # reconstruct the function definition and print it:
702 defln = self._getdef(obj, oname)
693 defln = self._getdef(obj, oname)
703 if defln:
694 if defln:
704 out['definition'] = self.format(defln)
695 out['definition'] = self.format(defln)
705
696
706 # Docstrings only in detail 0 mode, since source contains them (we
697 # Docstrings only in detail 0 mode, since source contains them (we
707 # avoid repetitions). If source fails, we add them back, see below.
698 # avoid repetitions). If source fails, we add them back, see below.
708 if ds and detail_level == 0:
699 if ds and detail_level == 0:
709 out['docstring'] = ds
700 out['docstring'] = ds
710
701
711 # Original source code for any callable
702 # Original source code for any callable
712 if detail_level:
703 if detail_level:
713 # Flush the source cache because inspect can return out-of-date
704 # Flush the source cache because inspect can return out-of-date
714 # source
705 # source
715 linecache.checkcache()
706 linecache.checkcache()
716 source = None
707 source = None
717 try:
708 try:
718 try:
709 try:
719 source = getsource(obj, binary_file)
710 source = getsource(obj, binary_file)
720 except TypeError:
711 except TypeError:
721 if hasattr(obj, '__class__'):
712 if hasattr(obj, '__class__'):
722 source = getsource(obj.__class__, binary_file)
713 source = getsource(obj.__class__, binary_file)
723 if source is not None:
714 if source is not None:
724 out['source'] = source.rstrip()
715 out['source'] = source.rstrip()
725 except Exception:
716 except Exception:
726 pass
717 pass
727
718
728 if ds and source is None:
719 if ds and source is None:
729 out['docstring'] = ds
720 out['docstring'] = ds
730
721
731
722
732 # Constructor docstring for classes
723 # Constructor docstring for classes
733 if inspect.isclass(obj):
724 if inspect.isclass(obj):
734 out['isclass'] = True
725 out['isclass'] = True
735 # reconstruct the function definition and print it:
726 # reconstruct the function definition and print it:
736 try:
727 try:
737 obj_init = obj.__init__
728 obj_init = obj.__init__
738 except AttributeError:
729 except AttributeError:
739 init_def = init_ds = None
730 init_def = init_ds = None
740 else:
731 else:
741 init_def = self._getdef(obj_init,oname)
732 init_def = self._getdef(obj_init,oname)
742 init_ds = getdoc(obj_init)
733 init_ds = getdoc(obj_init)
743 # Skip Python's auto-generated docstrings
734 # Skip Python's auto-generated docstrings
744 if init_ds and \
735 if init_ds and \
745 init_ds.startswith('x.__init__(...) initializes'):
736 init_ds.startswith('x.__init__(...) initializes'):
746 init_ds = None
737 init_ds = None
747
738
748 if init_def or init_ds:
739 if init_def or init_ds:
749 if init_def:
740 if init_def:
750 out['init_definition'] = self.format(init_def)
741 out['init_definition'] = self.format(init_def)
751 if init_ds:
742 if init_ds:
752 out['init_docstring'] = init_ds
743 out['init_docstring'] = init_ds
753
744
754 # and class docstring for instances:
745 # and class docstring for instances:
755 else:
746 else:
756 # First, check whether the instance docstring is identical to the
747 # First, check whether the instance docstring is identical to the
757 # class one, and print it separately if they don't coincide. In
748 # class one, and print it separately if they don't coincide. In
758 # most cases they will, but it's nice to print all the info for
749 # most cases they will, but it's nice to print all the info for
759 # objects which use instance-customized docstrings.
750 # objects which use instance-customized docstrings.
760 if ds:
751 if ds:
761 try:
752 try:
762 cls = getattr(obj,'__class__')
753 cls = getattr(obj,'__class__')
763 except:
754 except:
764 class_ds = None
755 class_ds = None
765 else:
756 else:
766 class_ds = getdoc(cls)
757 class_ds = getdoc(cls)
767 # Skip Python's auto-generated docstrings
758 # Skip Python's auto-generated docstrings
768 if class_ds and \
759 if class_ds and \
769 (class_ds.startswith('function(code, globals[,') or \
760 (class_ds.startswith('function(code, globals[,') or \
770 class_ds.startswith('instancemethod(function, instance,') or \
761 class_ds.startswith('instancemethod(function, instance,') or \
771 class_ds.startswith('module(name[,') ):
762 class_ds.startswith('module(name[,') ):
772 class_ds = None
763 class_ds = None
773 if class_ds and ds != class_ds:
764 if class_ds and ds != class_ds:
774 out['class_docstring'] = class_ds
765 out['class_docstring'] = class_ds
775
766
776 # Next, try to show constructor docstrings
767 # Next, try to show constructor docstrings
777 try:
768 try:
778 init_ds = getdoc(obj.__init__)
769 init_ds = getdoc(obj.__init__)
779 # Skip Python's auto-generated docstrings
770 # Skip Python's auto-generated docstrings
780 if init_ds and \
771 if init_ds and \
781 init_ds.startswith('x.__init__(...) initializes'):
772 init_ds.startswith('x.__init__(...) initializes'):
782 init_ds = None
773 init_ds = None
783 except AttributeError:
774 except AttributeError:
784 init_ds = None
775 init_ds = None
785 if init_ds:
776 if init_ds:
786 out['init_docstring'] = init_ds
777 out['init_docstring'] = init_ds
787
778
788 # Call form docstring for callable instances
779 # Call form docstring for callable instances
789 if safe_hasattr(obj, '__call__'):
780 if safe_hasattr(obj, '__call__'):
790 call_def = self._getdef(obj.__call__, oname)
781 call_def = self._getdef(obj.__call__, oname)
791 if call_def is not None:
782 if call_def is not None:
792 out['call_def'] = self.format(call_def)
783 out['call_def'] = self.format(call_def)
793 call_ds = getdoc(obj.__call__)
784 call_ds = getdoc(obj.__call__)
794 # Skip Python's auto-generated docstrings
785 # Skip Python's auto-generated docstrings
795 if call_ds and call_ds.startswith('x.__call__(...) <==> x(...)'):
786 if call_ds and call_ds.startswith('x.__call__(...) <==> x(...)'):
796 call_ds = None
787 call_ds = None
797 if call_ds:
788 if call_ds:
798 out['call_docstring'] = call_ds
789 out['call_docstring'] = call_ds
799
790
800 # Compute the object's argspec as a callable. The key is to decide
791 # Compute the object's argspec as a callable. The key is to decide
801 # whether to pull it from the object itself, from its __init__ or
792 # whether to pull it from the object itself, from its __init__ or
802 # from its __call__ method.
793 # from its __call__ method.
803
794
804 if inspect.isclass(obj):
795 if inspect.isclass(obj):
805 # Old-style classes need not have an __init__
796 # Old-style classes need not have an __init__
806 callable_obj = getattr(obj, "__init__", None)
797 callable_obj = getattr(obj, "__init__", None)
807 elif callable(obj):
798 elif callable(obj):
808 callable_obj = obj
799 callable_obj = obj
809 else:
800 else:
810 callable_obj = None
801 callable_obj = None
811
802
812 if callable_obj:
803 if callable_obj:
813 try:
804 try:
814 args, varargs, varkw, defaults = getargspec(callable_obj)
805 args, varargs, varkw, defaults = getargspec(callable_obj)
815 except (TypeError, AttributeError):
806 except (TypeError, AttributeError):
816 # For extensions/builtins we can't retrieve the argspec
807 # For extensions/builtins we can't retrieve the argspec
817 pass
808 pass
818 else:
809 else:
819 out['argspec'] = dict(args=args, varargs=varargs,
810 out['argspec'] = dict(args=args, varargs=varargs,
820 varkw=varkw, defaults=defaults)
811 varkw=varkw, defaults=defaults)
821
812
822 return object_info(**out)
813 return object_info(**out)
823
814
824
815
825 def psearch(self,pattern,ns_table,ns_search=[],
816 def psearch(self,pattern,ns_table,ns_search=[],
826 ignore_case=False,show_all=False):
817 ignore_case=False,show_all=False):
827 """Search namespaces with wildcards for objects.
818 """Search namespaces with wildcards for objects.
828
819
829 Arguments:
820 Arguments:
830
821
831 - pattern: string containing shell-like wildcards to use in namespace
822 - pattern: string containing shell-like wildcards to use in namespace
832 searches and optionally a type specification to narrow the search to
823 searches and optionally a type specification to narrow the search to
833 objects of that type.
824 objects of that type.
834
825
835 - ns_table: dict of name->namespaces for search.
826 - ns_table: dict of name->namespaces for search.
836
827
837 Optional arguments:
828 Optional arguments:
838
829
839 - ns_search: list of namespace names to include in search.
830 - ns_search: list of namespace names to include in search.
840
831
841 - ignore_case(False): make the search case-insensitive.
832 - ignore_case(False): make the search case-insensitive.
842
833
843 - show_all(False): show all names, including those starting with
834 - show_all(False): show all names, including those starting with
844 underscores.
835 underscores.
845 """
836 """
846 #print 'ps pattern:<%r>' % pattern # dbg
837 #print 'ps pattern:<%r>' % pattern # dbg
847
838
848 # defaults
839 # defaults
849 type_pattern = 'all'
840 type_pattern = 'all'
850 filter = ''
841 filter = ''
851
842
852 cmds = pattern.split()
843 cmds = pattern.split()
853 len_cmds = len(cmds)
844 len_cmds = len(cmds)
854 if len_cmds == 1:
845 if len_cmds == 1:
855 # Only filter pattern given
846 # Only filter pattern given
856 filter = cmds[0]
847 filter = cmds[0]
857 elif len_cmds == 2:
848 elif len_cmds == 2:
858 # Both filter and type specified
849 # Both filter and type specified
859 filter,type_pattern = cmds
850 filter,type_pattern = cmds
860 else:
851 else:
861 raise ValueError('invalid argument string for psearch: <%s>' %
852 raise ValueError('invalid argument string for psearch: <%s>' %
862 pattern)
853 pattern)
863
854
864 # filter search namespaces
855 # filter search namespaces
865 for name in ns_search:
856 for name in ns_search:
866 if name not in ns_table:
857 if name not in ns_table:
867 raise ValueError('invalid namespace <%s>. Valid names: %s' %
858 raise ValueError('invalid namespace <%s>. Valid names: %s' %
868 (name,ns_table.keys()))
859 (name,ns_table.keys()))
869
860
870 #print 'type_pattern:',type_pattern # dbg
861 #print 'type_pattern:',type_pattern # dbg
871 search_result, namespaces_seen = set(), set()
862 search_result, namespaces_seen = set(), set()
872 for ns_name in ns_search:
863 for ns_name in ns_search:
873 ns = ns_table[ns_name]
864 ns = ns_table[ns_name]
874 # Normally, locals and globals are the same, so we just check one.
865 # Normally, locals and globals are the same, so we just check one.
875 if id(ns) in namespaces_seen:
866 if id(ns) in namespaces_seen:
876 continue
867 continue
877 namespaces_seen.add(id(ns))
868 namespaces_seen.add(id(ns))
878 tmp_res = list_namespace(ns, type_pattern, filter,
869 tmp_res = list_namespace(ns, type_pattern, filter,
879 ignore_case=ignore_case, show_all=show_all)
870 ignore_case=ignore_case, show_all=show_all)
880 search_result.update(tmp_res)
871 search_result.update(tmp_res)
881
872
882 page.page('\n'.join(sorted(search_result)))
873 page.page('\n'.join(sorted(search_result)))
@@ -1,73 +1,83 b''
1 # encoding: utf-8
1 # encoding: utf-8
2 """A fancy version of Python's builtin :func:`dir` function.
2 """A fancy version of Python's builtin :func:`dir` function.
3 """
3 """
4
4
5 #-----------------------------------------------------------------------------
5 #-----------------------------------------------------------------------------
6 # Copyright (C) 2008-2011 The IPython Development Team
6 # Copyright (C) 2008-2011 The IPython Development Team
7 #
7 #
8 # Distributed under the terms of the BSD License. The full license is in
8 # Distributed under the terms of the BSD License. The full license is in
9 # the file COPYING, distributed as part of this software.
9 # the file COPYING, distributed as part of this software.
10 #-----------------------------------------------------------------------------
10 #-----------------------------------------------------------------------------
11
11
12 #-----------------------------------------------------------------------------
12 #-----------------------------------------------------------------------------
13 # Imports
13 # Imports
14 #-----------------------------------------------------------------------------
14 #-----------------------------------------------------------------------------
15
16 #-----------------------------------------------------------------------------
15 #-----------------------------------------------------------------------------
17 # Code
16 # Code
18 #-----------------------------------------------------------------------------
17 #-----------------------------------------------------------------------------
19
18
19
20 def safe_hasattr(obj, attr):
21 """In recent versions of Python, hasattr() only catches AttributeError.
22 This catches all errors.
23 """
24 try:
25 getattr(obj, attr)
26 return True
27 except:
28 return False
29
30
20 def get_class_members(cls):
31 def get_class_members(cls):
21 ret = dir(cls)
32 ret = dir(cls)
22 if hasattr(cls, '__bases__'):
33 if safe_hasattr(cls, '__bases__'):
23 try:
34 try:
24 bases = cls.__bases__
35 bases = cls.__bases__
25 except AttributeError:
36 except AttributeError:
26 # `obj` lied to hasattr (e.g. Pyro), ignore
37 # `obj` lied to hasattr (e.g. Pyro), ignore
27 pass
38 pass
28 else:
39 else:
29 for base in bases:
40 for base in bases:
30 ret.extend(get_class_members(base))
41 ret.extend(get_class_members(base))
31 return ret
42 return ret
32
43
33
44
34 def dir2(obj):
45 def dir2(obj):
35 """dir2(obj) -> list of strings
46 """dir2(obj) -> list of strings
36
47
37 Extended version of the Python builtin dir(), which does a few extra
48 Extended version of the Python builtin dir(), which does a few extra
38 checks, and supports common objects with unusual internals that confuse
49 checks, and supports common objects with unusual internals that confuse
39 dir(), such as Traits and PyCrust.
50 dir(), such as Traits and PyCrust.
40
51
41 This version is guaranteed to return only a list of true strings, whereas
52 This version is guaranteed to return only a list of true strings, whereas
42 dir() returns anything that objects inject into themselves, even if they
53 dir() returns anything that objects inject into themselves, even if they
43 are later not really valid for attribute access (many extension libraries
54 are later not really valid for attribute access (many extension libraries
44 have such bugs).
55 have such bugs).
45 """
56 """
46
57
47 # Start building the attribute list via dir(), and then complete it
58 # Start building the attribute list via dir(), and then complete it
48 # with a few extra special-purpose calls.
59 # with a few extra special-purpose calls.
49
60
50 words = set(dir(obj))
61 words = set(dir(obj))
51
62
52 if hasattr(obj, '__class__'):
63 if safe_hasattr(obj, '__class__'):
53 #words.add('__class__')
64 #words.add('__class__')
54 words |= set(get_class_members(obj.__class__))
65 words |= set(get_class_members(obj.__class__))
55
66
56
67
57 # for objects with Enthought's traits, add trait_names() list
68 # for objects with Enthought's traits, add trait_names() list
58 # for PyCrust-style, add _getAttributeNames() magic method list
69 # for PyCrust-style, add _getAttributeNames() magic method list
59 for attr in ('trait_names', '_getAttributeNames'):
70 for attr in ('trait_names', '_getAttributeNames'):
60 if hasattr(obj, attr):
71 try:
61 try:
72 func = getattr(obj, attr)
62 func = getattr(obj, attr)
73 if callable(func):
63 if callable(func):
74 words |= set(func())
64 words |= set(func())
75 except:
65 except:
76 # TypeError: obj is class not instance
66 # TypeError: obj is class not instance
77 pass
67 pass
68
78
69 # filter out non-string attributes which may be stuffed by dir() calls
79 # filter out non-string attributes which may be stuffed by dir() calls
70 # and poor coding in third-party modules
80 # and poor coding in third-party modules
71
81
72 words = [w for w in words if isinstance(w, basestring)]
82 words = [w for w in words if isinstance(w, basestring)]
73 return sorted(words)
83 return sorted(words)
@@ -1,52 +1,80 b''
1 import nose.tools as nt
1 import nose.tools as nt
2 from IPython.utils.dir2 import dir2
2 from IPython.utils.dir2 import dir2
3
3
4
4
5 class Base(object):
5 class Base(object):
6 x = 1
6 x = 1
7 z = 23
7 z = 23
8
8
9
9
10 def test_base():
10 def test_base():
11 res = dir2(Base())
11 res = dir2(Base())
12 assert ('x' in res)
12 assert ('x' in res)
13 assert ('z' in res)
13 assert ('z' in res)
14 assert ('y' not in res)
14 assert ('y' not in res)
15 assert ('__class__' in res)
15 assert ('__class__' in res)
16 nt.assert_equal(res.count('x'), 1)
16 nt.assert_equal(res.count('x'), 1)
17 nt.assert_equal(res.count('__class__'), 1)
17 nt.assert_equal(res.count('__class__'), 1)
18
18
19 def test_SubClass():
19 def test_SubClass():
20
20
21 class SubClass(Base):
21 class SubClass(Base):
22 y = 2
22 y = 2
23
23
24 res = dir2(SubClass())
24 res = dir2(SubClass())
25 assert ('y' in res)
25 assert ('y' in res)
26 nt.assert_equal(res.count('y'), 1)
26 nt.assert_equal(res.count('y'), 1)
27 nt.assert_equal(res.count('x'), 1)
27 nt.assert_equal(res.count('x'), 1)
28
28
29
29
30 def test_SubClass_with_trait_names_method():
30 def test_SubClass_with_trait_names_method():
31
31
32 class SubClass(Base):
32 class SubClass(Base):
33 y = 2
33 y = 2
34 def trait_names(self):
34 def trait_names(self):
35 return ['t', 'umbrella']
35 return ['t', 'umbrella']
36
36
37 res = dir2(SubClass())
37 res = dir2(SubClass())
38 assert('trait_names' in res)
38 assert('trait_names' in res)
39 assert('umbrella' in res)
39 assert('umbrella' in res)
40 nt.assert_equal(res[-6:], ['t', 'trait_names','umbrella', 'x','y','z'])
40 nt.assert_equal(res[-6:], ['t', 'trait_names','umbrella', 'x','y','z'])
41 nt.assert_equal(res.count('t'), 1)
41 nt.assert_equal(res.count('t'), 1)
42
42
43
43
44 def test_SubClass_with_trait_names_attr():
44 def test_SubClass_with_trait_names_attr():
45 # usecase: trait_names is used in a class describing psychological classification
45 # usecase: trait_names is used in a class describing psychological classification
46
46
47 class SubClass(Base):
47 class SubClass(Base):
48 y = 2
48 y = 2
49 trait_names = 44
49 trait_names = 44
50
50
51 res = dir2(SubClass())
51 res = dir2(SubClass())
52 assert('trait_names' in res)
52 assert('trait_names' in res)
53
54
55 def test_misbehaving_object_without_trait_names():
56 # dir2 shouldn't raise even when objects are dumb and raise
57 # something other than AttribteErrors on bad getattr.
58
59 class BadTraitNames(object):
60 @property
61 def trait_names(self):
62 raise KeyboardInterrupt("This should be caught")
63
64 def some_method(self):
65 pass
66
67 class MisbehavingGetattr(object):
68 def __getattr__(self):
69 raise KeyError("I should be caught")
70
71 def some_method(self):
72 pass
73
74 class SillierWithDir(MisbehavingGetattr):
75 def __dir__(self):
76 return ['some_method']
77
78 for bad_klass in (BadTraitNames, MisbehavingGetattr, SillierWithDir):
79 res = dir2(bad_klass())
80 assert('some_method' in res)
General Comments 0
You need to be logged in to leave comments. Login now