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