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