##// END OF EJS Templates
cast unicode in oinspect.find_file
MinRK -
Show More
@@ -1,873 +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 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 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 except:
329 except:
330 return None
330 return None
331
331
332 return lineno
332 return lineno
333
333
334
334
335 class Inspector:
335 class Inspector:
336 def __init__(self, color_table=InspectColors,
336 def __init__(self, color_table=InspectColors,
337 code_color_table=PyColorize.ANSICodeColors,
337 code_color_table=PyColorize.ANSICodeColors,
338 scheme='NoColor',
338 scheme='NoColor',
339 str_detail_level=0):
339 str_detail_level=0):
340 self.color_table = color_table
340 self.color_table = color_table
341 self.parser = PyColorize.Parser(code_color_table,out='str')
341 self.parser = PyColorize.Parser(code_color_table,out='str')
342 self.format = self.parser.format
342 self.format = self.parser.format
343 self.str_detail_level = str_detail_level
343 self.str_detail_level = str_detail_level
344 self.set_active_scheme(scheme)
344 self.set_active_scheme(scheme)
345
345
346 def _getdef(self,obj,oname=''):
346 def _getdef(self,obj,oname=''):
347 """Return the definition header for any callable object.
347 """Return the definition header for any callable object.
348
348
349 If any exception is generated, None is returned instead and the
349 If any exception is generated, None is returned instead and the
350 exception is suppressed."""
350 exception is suppressed."""
351
351
352 try:
352 try:
353 hdef = oname + inspect.formatargspec(*getargspec(obj))
353 hdef = oname + inspect.formatargspec(*getargspec(obj))
354 return cast_unicode(hdef)
354 return cast_unicode(hdef)
355 except:
355 except:
356 return None
356 return None
357
357
358 def __head(self,h):
358 def __head(self,h):
359 """Return a header string with proper colors."""
359 """Return a header string with proper colors."""
360 return '%s%s%s' % (self.color_table.active_colors.header,h,
360 return '%s%s%s' % (self.color_table.active_colors.header,h,
361 self.color_table.active_colors.normal)
361 self.color_table.active_colors.normal)
362
362
363 def set_active_scheme(self, scheme):
363 def set_active_scheme(self, scheme):
364 self.color_table.set_active_scheme(scheme)
364 self.color_table.set_active_scheme(scheme)
365 self.parser.color_table.set_active_scheme(scheme)
365 self.parser.color_table.set_active_scheme(scheme)
366
366
367 def noinfo(self, msg, oname):
367 def noinfo(self, msg, oname):
368 """Generic message when no information is found."""
368 """Generic message when no information is found."""
369 print('No %s found' % msg, end=' ')
369 print('No %s found' % msg, end=' ')
370 if oname:
370 if oname:
371 print('for %s' % oname)
371 print('for %s' % oname)
372 else:
372 else:
373 print()
373 print()
374
374
375 def pdef(self, obj, oname=''):
375 def pdef(self, obj, oname=''):
376 """Print the definition header for any callable object.
376 """Print the definition header for any callable object.
377
377
378 If the object is a class, print the constructor information."""
378 If the object is a class, print the constructor information."""
379
379
380 if not callable(obj):
380 if not callable(obj):
381 print('Object is not callable.')
381 print('Object is not callable.')
382 return
382 return
383
383
384 header = ''
384 header = ''
385
385
386 if inspect.isclass(obj):
386 if inspect.isclass(obj):
387 header = self.__head('Class constructor information:\n')
387 header = self.__head('Class constructor information:\n')
388 obj = obj.__init__
388 obj = obj.__init__
389 elif (not py3compat.PY3) and type(obj) is types.InstanceType:
389 elif (not py3compat.PY3) and type(obj) is types.InstanceType:
390 obj = obj.__call__
390 obj = obj.__call__
391
391
392 output = self._getdef(obj,oname)
392 output = self._getdef(obj,oname)
393 if output is None:
393 if output is None:
394 self.noinfo('definition header',oname)
394 self.noinfo('definition header',oname)
395 else:
395 else:
396 print(header,self.format(output), end=' ', file=io.stdout)
396 print(header,self.format(output), end=' ', file=io.stdout)
397
397
398 # 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__.
399 @skip_doctest_py3
399 @skip_doctest_py3
400 def pdoc(self,obj,oname='',formatter = None):
400 def pdoc(self,obj,oname='',formatter = None):
401 """Print the docstring for any object.
401 """Print the docstring for any object.
402
402
403 Optional:
403 Optional:
404 -formatter: a function to run the docstring through for specially
404 -formatter: a function to run the docstring through for specially
405 formatted docstrings.
405 formatted docstrings.
406
406
407 Examples
407 Examples
408 --------
408 --------
409
409
410 In [1]: class NoInit:
410 In [1]: class NoInit:
411 ...: pass
411 ...: pass
412
412
413 In [2]: class NoDoc:
413 In [2]: class NoDoc:
414 ...: def __init__(self):
414 ...: def __init__(self):
415 ...: pass
415 ...: pass
416
416
417 In [3]: %pdoc NoDoc
417 In [3]: %pdoc NoDoc
418 No documentation found for NoDoc
418 No documentation found for NoDoc
419
419
420 In [4]: %pdoc NoInit
420 In [4]: %pdoc NoInit
421 No documentation found for NoInit
421 No documentation found for NoInit
422
422
423 In [5]: obj = NoInit()
423 In [5]: obj = NoInit()
424
424
425 In [6]: %pdoc obj
425 In [6]: %pdoc obj
426 No documentation found for obj
426 No documentation found for obj
427
427
428 In [5]: obj2 = NoDoc()
428 In [5]: obj2 = NoDoc()
429
429
430 In [6]: %pdoc obj2
430 In [6]: %pdoc obj2
431 No documentation found for obj2
431 No documentation found for obj2
432 """
432 """
433
433
434 head = self.__head # For convenience
434 head = self.__head # For convenience
435 lines = []
435 lines = []
436 ds = getdoc(obj)
436 ds = getdoc(obj)
437 if formatter:
437 if formatter:
438 ds = formatter(ds)
438 ds = formatter(ds)
439 if ds:
439 if ds:
440 lines.append(head("Class Docstring:"))
440 lines.append(head("Class Docstring:"))
441 lines.append(indent(ds))
441 lines.append(indent(ds))
442 if inspect.isclass(obj) and hasattr(obj, '__init__'):
442 if inspect.isclass(obj) and hasattr(obj, '__init__'):
443 init_ds = getdoc(obj.__init__)
443 init_ds = getdoc(obj.__init__)
444 if init_ds is not None:
444 if init_ds is not None:
445 lines.append(head("Constructor Docstring:"))
445 lines.append(head("Constructor Docstring:"))
446 lines.append(indent(init_ds))
446 lines.append(indent(init_ds))
447 elif hasattr(obj,'__call__'):
447 elif hasattr(obj,'__call__'):
448 call_ds = getdoc(obj.__call__)
448 call_ds = getdoc(obj.__call__)
449 if call_ds:
449 if call_ds:
450 lines.append(head("Calling Docstring:"))
450 lines.append(head("Calling Docstring:"))
451 lines.append(indent(call_ds))
451 lines.append(indent(call_ds))
452
452
453 if not lines:
453 if not lines:
454 self.noinfo('documentation',oname)
454 self.noinfo('documentation',oname)
455 else:
455 else:
456 page.page('\n'.join(lines))
456 page.page('\n'.join(lines))
457
457
458 def psource(self,obj,oname=''):
458 def psource(self,obj,oname=''):
459 """Print the source code for an object."""
459 """Print the source code for an object."""
460
460
461 # 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
462 linecache.checkcache()
462 linecache.checkcache()
463 try:
463 try:
464 src = getsource(obj)
464 src = getsource(obj)
465 except:
465 except:
466 self.noinfo('source',oname)
466 self.noinfo('source',oname)
467 else:
467 else:
468 page.page(self.format(src))
468 page.page(self.format(src))
469
469
470 def pfile(self, obj, oname=''):
470 def pfile(self, obj, oname=''):
471 """Show the whole file where an object was defined."""
471 """Show the whole file where an object was defined."""
472
472
473 lineno = find_source_lines(obj)
473 lineno = find_source_lines(obj)
474 if lineno is None:
474 if lineno is None:
475 self.noinfo('file', oname)
475 self.noinfo('file', oname)
476 return
476 return
477
477
478 ofile = find_file(obj)
478 ofile = find_file(obj)
479 # 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
480 # 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
481 # filesystem.
481 # filesystem.
482 if ofile.endswith(('.so', '.dll', '.pyd')):
482 if ofile.endswith(('.so', '.dll', '.pyd')):
483 print('File %r is binary, not printing.' % ofile)
483 print('File %r is binary, not printing.' % ofile)
484 elif not os.path.isfile(ofile):
484 elif not os.path.isfile(ofile):
485 print('File %r does not exist, not printing.' % ofile)
485 print('File %r does not exist, not printing.' % ofile)
486 else:
486 else:
487 # Print only text files, not extension binaries. Note that
487 # Print only text files, not extension binaries. Note that
488 # getsourcelines returns lineno with 1-offset and page() uses
488 # getsourcelines returns lineno with 1-offset and page() uses
489 # 0-offset, so we must adjust.
489 # 0-offset, so we must adjust.
490 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)
491
491
492 def _format_fields(self, fields, title_width=12):
492 def _format_fields(self, fields, title_width=12):
493 """Formats a list of fields for display.
493 """Formats a list of fields for display.
494
494
495 Parameters
495 Parameters
496 ----------
496 ----------
497 fields : list
497 fields : list
498 A list of 2-tuples: (field_title, field_content)
498 A list of 2-tuples: (field_title, field_content)
499 title_width : int
499 title_width : int
500 How many characters to pad titles to. Default 12.
500 How many characters to pad titles to. Default 12.
501 """
501 """
502 out = []
502 out = []
503 header = self.__head
503 header = self.__head
504 for title, content in fields:
504 for title, content in fields:
505 if len(content.splitlines()) > 1:
505 if len(content.splitlines()) > 1:
506 title = header(title + ":") + "\n"
506 title = header(title + ":") + "\n"
507 else:
507 else:
508 title = header((title+":").ljust(title_width))
508 title = header((title+":").ljust(title_width))
509 out.append(cast_unicode(title) + cast_unicode(content))
509 out.append(cast_unicode(title) + cast_unicode(content))
510 return "\n".join(out)
510 return "\n".join(out)
511
511
512 # 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)
513 pinfo_fields1 = [("Type", "type_name"),
513 pinfo_fields1 = [("Type", "type_name"),
514 ]
514 ]
515
515
516 pinfo_fields2 = [("String Form", "string_form"),
516 pinfo_fields2 = [("String Form", "string_form"),
517 ]
517 ]
518
518
519 pinfo_fields3 = [("Length", "length"),
519 pinfo_fields3 = [("Length", "length"),
520 ("File", "file"),
520 ("File", "file"),
521 ("Definition", "definition"),
521 ("Definition", "definition"),
522 ]
522 ]
523
523
524 pinfo_fields_obj = [("Class Docstring", "class_docstring"),
524 pinfo_fields_obj = [("Class Docstring", "class_docstring"),
525 ("Constructor Docstring","init_docstring"),
525 ("Constructor Docstring","init_docstring"),
526 ("Call def", "call_def"),
526 ("Call def", "call_def"),
527 ("Call docstring", "call_docstring")]
527 ("Call docstring", "call_docstring")]
528
528
529 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):
530 """Show detailed information about an object.
530 """Show detailed information about an object.
531
531
532 Optional arguments:
532 Optional arguments:
533
533
534 - oname: name of the variable pointing to the object.
534 - oname: name of the variable pointing to the object.
535
535
536 - formatter: special formatter for docstrings (see pdoc)
536 - formatter: special formatter for docstrings (see pdoc)
537
537
538 - info: a structure with some information fields which may have been
538 - info: a structure with some information fields which may have been
539 precomputed already.
539 precomputed already.
540
540
541 - detail_level: if set to 1, more information is given.
541 - detail_level: if set to 1, more information is given.
542 """
542 """
543 info = self.info(obj, oname=oname, formatter=formatter,
543 info = self.info(obj, oname=oname, formatter=formatter,
544 info=info, detail_level=detail_level)
544 info=info, detail_level=detail_level)
545 displayfields = []
545 displayfields = []
546 def add_fields(fields):
546 def add_fields(fields):
547 for title, key in fields:
547 for title, key in fields:
548 field = info[key]
548 field = info[key]
549 if field is not None:
549 if field is not None:
550 displayfields.append((title, field.rstrip()))
550 displayfields.append((title, field.rstrip()))
551
551
552 add_fields(self.pinfo_fields1)
552 add_fields(self.pinfo_fields1)
553
553
554 # Base class for old-style instances
554 # Base class for old-style instances
555 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']:
556 displayfields.append(("Base Class", info['base_class'].rstrip()))
556 displayfields.append(("Base Class", info['base_class'].rstrip()))
557
557
558 add_fields(self.pinfo_fields2)
558 add_fields(self.pinfo_fields2)
559
559
560 # Namespace
560 # Namespace
561 if info['namespace'] != 'Interactive':
561 if info['namespace'] != 'Interactive':
562 displayfields.append(("Namespace", info['namespace'].rstrip()))
562 displayfields.append(("Namespace", info['namespace'].rstrip()))
563
563
564 add_fields(self.pinfo_fields3)
564 add_fields(self.pinfo_fields3)
565
565
566 # Source or docstring, depending on detail level and whether
566 # Source or docstring, depending on detail level and whether
567 # source found.
567 # source found.
568 if detail_level > 0 and info['source'] is not None:
568 if detail_level > 0 and info['source'] is not None:
569 displayfields.append(("Source",
569 displayfields.append(("Source",
570 self.format(cast_unicode(info['source']))))
570 self.format(cast_unicode(info['source']))))
571 elif info['docstring'] is not None:
571 elif info['docstring'] is not None:
572 displayfields.append(("Docstring", info["docstring"]))
572 displayfields.append(("Docstring", info["docstring"]))
573
573
574 # Constructor info for classes
574 # Constructor info for classes
575 if info['isclass']:
575 if info['isclass']:
576 if info['init_definition'] or info['init_docstring']:
576 if info['init_definition'] or info['init_docstring']:
577 displayfields.append(("Constructor information", ""))
577 displayfields.append(("Constructor information", ""))
578 if info['init_definition'] is not None:
578 if info['init_definition'] is not None:
579 displayfields.append((" Definition",
579 displayfields.append((" Definition",
580 info['init_definition'].rstrip()))
580 info['init_definition'].rstrip()))
581 if info['init_docstring'] is not None:
581 if info['init_docstring'] is not None:
582 displayfields.append((" Docstring",
582 displayfields.append((" Docstring",
583 indent(info['init_docstring'])))
583 indent(info['init_docstring'])))
584
584
585 # Info for objects:
585 # Info for objects:
586 else:
586 else:
587 add_fields(self.pinfo_fields_obj)
587 add_fields(self.pinfo_fields_obj)
588
588
589 # Finally send to printer/pager:
589 # Finally send to printer/pager:
590 if displayfields:
590 if displayfields:
591 page.page(self._format_fields(displayfields))
591 page.page(self._format_fields(displayfields))
592
592
593 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):
594 """Compute a dict with detailed information about an object.
594 """Compute a dict with detailed information about an object.
595
595
596 Optional arguments:
596 Optional arguments:
597
597
598 - oname: name of the variable pointing to the object.
598 - oname: name of the variable pointing to the object.
599
599
600 - formatter: special formatter for docstrings (see pdoc)
600 - formatter: special formatter for docstrings (see pdoc)
601
601
602 - info: a structure with some information fields which may have been
602 - info: a structure with some information fields which may have been
603 precomputed already.
603 precomputed already.
604
604
605 - detail_level: if set to 1, more information is given.
605 - detail_level: if set to 1, more information is given.
606 """
606 """
607
607
608 obj_type = type(obj)
608 obj_type = type(obj)
609
609
610 header = self.__head
610 header = self.__head
611 if info is None:
611 if info is None:
612 ismagic = 0
612 ismagic = 0
613 isalias = 0
613 isalias = 0
614 ospace = ''
614 ospace = ''
615 else:
615 else:
616 ismagic = info.ismagic
616 ismagic = info.ismagic
617 isalias = info.isalias
617 isalias = info.isalias
618 ospace = info.namespace
618 ospace = info.namespace
619
619
620 # Get docstring, special-casing aliases:
620 # Get docstring, special-casing aliases:
621 if isalias:
621 if isalias:
622 if not callable(obj):
622 if not callable(obj):
623 try:
623 try:
624 ds = "Alias to the system command:\n %s" % obj[1]
624 ds = "Alias to the system command:\n %s" % obj[1]
625 except:
625 except:
626 ds = "Alias: " + str(obj)
626 ds = "Alias: " + str(obj)
627 else:
627 else:
628 ds = "Alias to " + str(obj)
628 ds = "Alias to " + str(obj)
629 if obj.__doc__:
629 if obj.__doc__:
630 ds += "\nDocstring:\n" + obj.__doc__
630 ds += "\nDocstring:\n" + obj.__doc__
631 else:
631 else:
632 ds = getdoc(obj)
632 ds = getdoc(obj)
633 if ds is None:
633 if ds is None:
634 ds = '<no docstring>'
634 ds = '<no docstring>'
635 if formatter is not None:
635 if formatter is not None:
636 ds = formatter(ds)
636 ds = formatter(ds)
637
637
638 # 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
639 out = dict(name=oname, found=True, isalias=isalias, ismagic=ismagic)
639 out = dict(name=oname, found=True, isalias=isalias, ismagic=ismagic)
640
640
641 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)
642 shalf = int((string_max -5)/2)
642 shalf = int((string_max -5)/2)
643
643
644 if ismagic:
644 if ismagic:
645 obj_type_name = 'Magic function'
645 obj_type_name = 'Magic function'
646 elif isalias:
646 elif isalias:
647 obj_type_name = 'System alias'
647 obj_type_name = 'System alias'
648 else:
648 else:
649 obj_type_name = obj_type.__name__
649 obj_type_name = obj_type.__name__
650 out['type_name'] = obj_type_name
650 out['type_name'] = obj_type_name
651
651
652 try:
652 try:
653 bclass = obj.__class__
653 bclass = obj.__class__
654 out['base_class'] = str(bclass)
654 out['base_class'] = str(bclass)
655 except: pass
655 except: pass
656
656
657 # String form, but snip if too long in ? form (full in ??)
657 # String form, but snip if too long in ? form (full in ??)
658 if detail_level >= self.str_detail_level:
658 if detail_level >= self.str_detail_level:
659 try:
659 try:
660 ostr = str(obj)
660 ostr = str(obj)
661 str_head = 'string_form'
661 str_head = 'string_form'
662 if not detail_level and len(ostr)>string_max:
662 if not detail_level and len(ostr)>string_max:
663 ostr = ostr[:shalf] + ' <...> ' + ostr[-shalf:]
663 ostr = ostr[:shalf] + ' <...> ' + ostr[-shalf:]
664 ostr = ("\n" + " " * len(str_head.expandtabs())).\
664 ostr = ("\n" + " " * len(str_head.expandtabs())).\
665 join(q.strip() for q in ostr.split("\n"))
665 join(q.strip() for q in ostr.split("\n"))
666 out[str_head] = ostr
666 out[str_head] = ostr
667 except:
667 except:
668 pass
668 pass
669
669
670 if ospace:
670 if ospace:
671 out['namespace'] = ospace
671 out['namespace'] = ospace
672
672
673 # Length (for strings and lists)
673 # Length (for strings and lists)
674 try:
674 try:
675 out['length'] = str(len(obj))
675 out['length'] = str(len(obj))
676 except: pass
676 except: pass
677
677
678 # Filename where object was defined
678 # Filename where object was defined
679 binary_file = False
679 binary_file = False
680 fname = find_file(obj)
680 fname = find_file(obj)
681 if fname is None:
681 if fname is None:
682 # 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
683 # if the file was binary
683 # if the file was binary
684 binary_file = True
684 binary_file = True
685 else:
685 else:
686 if fname.endswith(('.so', '.dll', '.pyd')):
686 if fname.endswith(('.so', '.dll', '.pyd')):
687 binary_file = True
687 binary_file = True
688 elif fname.endswith('<string>'):
688 elif fname.endswith('<string>'):
689 fname = 'Dynamically generated function. No source code available.'
689 fname = 'Dynamically generated function. No source code available.'
690 out['file'] = fname
690 out['file'] = fname
691
691
692 # reconstruct the function definition and print it:
692 # reconstruct the function definition and print it:
693 defln = self._getdef(obj, oname)
693 defln = self._getdef(obj, oname)
694 if defln:
694 if defln:
695 out['definition'] = self.format(defln)
695 out['definition'] = self.format(defln)
696
696
697 # Docstrings only in detail 0 mode, since source contains them (we
697 # Docstrings only in detail 0 mode, since source contains them (we
698 # avoid repetitions). If source fails, we add them back, see below.
698 # avoid repetitions). If source fails, we add them back, see below.
699 if ds and detail_level == 0:
699 if ds and detail_level == 0:
700 out['docstring'] = ds
700 out['docstring'] = ds
701
701
702 # Original source code for any callable
702 # Original source code for any callable
703 if detail_level:
703 if detail_level:
704 # Flush the source cache because inspect can return out-of-date
704 # Flush the source cache because inspect can return out-of-date
705 # source
705 # source
706 linecache.checkcache()
706 linecache.checkcache()
707 source = None
707 source = None
708 try:
708 try:
709 try:
709 try:
710 source = getsource(obj, binary_file)
710 source = getsource(obj, binary_file)
711 except TypeError:
711 except TypeError:
712 if hasattr(obj, '__class__'):
712 if hasattr(obj, '__class__'):
713 source = getsource(obj.__class__, binary_file)
713 source = getsource(obj.__class__, binary_file)
714 if source is not None:
714 if source is not None:
715 out['source'] = source.rstrip()
715 out['source'] = source.rstrip()
716 except Exception:
716 except Exception:
717 pass
717 pass
718
718
719 if ds and source is None:
719 if ds and source is None:
720 out['docstring'] = ds
720 out['docstring'] = ds
721
721
722
722
723 # Constructor docstring for classes
723 # Constructor docstring for classes
724 if inspect.isclass(obj):
724 if inspect.isclass(obj):
725 out['isclass'] = True
725 out['isclass'] = True
726 # reconstruct the function definition and print it:
726 # reconstruct the function definition and print it:
727 try:
727 try:
728 obj_init = obj.__init__
728 obj_init = obj.__init__
729 except AttributeError:
729 except AttributeError:
730 init_def = init_ds = None
730 init_def = init_ds = None
731 else:
731 else:
732 init_def = self._getdef(obj_init,oname)
732 init_def = self._getdef(obj_init,oname)
733 init_ds = getdoc(obj_init)
733 init_ds = getdoc(obj_init)
734 # Skip Python's auto-generated docstrings
734 # Skip Python's auto-generated docstrings
735 if init_ds and \
735 if init_ds and \
736 init_ds.startswith('x.__init__(...) initializes'):
736 init_ds.startswith('x.__init__(...) initializes'):
737 init_ds = None
737 init_ds = None
738
738
739 if init_def or init_ds:
739 if init_def or init_ds:
740 if init_def:
740 if init_def:
741 out['init_definition'] = self.format(init_def)
741 out['init_definition'] = self.format(init_def)
742 if init_ds:
742 if init_ds:
743 out['init_docstring'] = init_ds
743 out['init_docstring'] = init_ds
744
744
745 # and class docstring for instances:
745 # and class docstring for instances:
746 else:
746 else:
747 # First, check whether the instance docstring is identical to the
747 # First, check whether the instance docstring is identical to the
748 # 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
749 # 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
750 # objects which use instance-customized docstrings.
750 # objects which use instance-customized docstrings.
751 if ds:
751 if ds:
752 try:
752 try:
753 cls = getattr(obj,'__class__')
753 cls = getattr(obj,'__class__')
754 except:
754 except:
755 class_ds = None
755 class_ds = None
756 else:
756 else:
757 class_ds = getdoc(cls)
757 class_ds = getdoc(cls)
758 # Skip Python's auto-generated docstrings
758 # Skip Python's auto-generated docstrings
759 if class_ds and \
759 if class_ds and \
760 (class_ds.startswith('function(code, globals[,') or \
760 (class_ds.startswith('function(code, globals[,') or \
761 class_ds.startswith('instancemethod(function, instance,') or \
761 class_ds.startswith('instancemethod(function, instance,') or \
762 class_ds.startswith('module(name[,') ):
762 class_ds.startswith('module(name[,') ):
763 class_ds = None
763 class_ds = None
764 if class_ds and ds != class_ds:
764 if class_ds and ds != class_ds:
765 out['class_docstring'] = class_ds
765 out['class_docstring'] = class_ds
766
766
767 # Next, try to show constructor docstrings
767 # Next, try to show constructor docstrings
768 try:
768 try:
769 init_ds = getdoc(obj.__init__)
769 init_ds = getdoc(obj.__init__)
770 # Skip Python's auto-generated docstrings
770 # Skip Python's auto-generated docstrings
771 if init_ds and \
771 if init_ds and \
772 init_ds.startswith('x.__init__(...) initializes'):
772 init_ds.startswith('x.__init__(...) initializes'):
773 init_ds = None
773 init_ds = None
774 except AttributeError:
774 except AttributeError:
775 init_ds = None
775 init_ds = None
776 if init_ds:
776 if init_ds:
777 out['init_docstring'] = init_ds
777 out['init_docstring'] = init_ds
778
778
779 # Call form docstring for callable instances
779 # Call form docstring for callable instances
780 if hasattr(obj, '__call__'):
780 if hasattr(obj, '__call__'):
781 call_def = self._getdef(obj.__call__, oname)
781 call_def = self._getdef(obj.__call__, oname)
782 if call_def is not None:
782 if call_def is not None:
783 out['call_def'] = self.format(call_def)
783 out['call_def'] = self.format(call_def)
784 call_ds = getdoc(obj.__call__)
784 call_ds = getdoc(obj.__call__)
785 # Skip Python's auto-generated docstrings
785 # Skip Python's auto-generated docstrings
786 if call_ds and call_ds.startswith('x.__call__(...) <==> x(...)'):
786 if call_ds and call_ds.startswith('x.__call__(...) <==> x(...)'):
787 call_ds = None
787 call_ds = None
788 if call_ds:
788 if call_ds:
789 out['call_docstring'] = call_ds
789 out['call_docstring'] = call_ds
790
790
791 # 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
792 # 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
793 # from its __call__ method.
793 # from its __call__ method.
794
794
795 if inspect.isclass(obj):
795 if inspect.isclass(obj):
796 # Old-style classes need not have an __init__
796 # Old-style classes need not have an __init__
797 callable_obj = getattr(obj, "__init__", None)
797 callable_obj = getattr(obj, "__init__", None)
798 elif callable(obj):
798 elif callable(obj):
799 callable_obj = obj
799 callable_obj = obj
800 else:
800 else:
801 callable_obj = None
801 callable_obj = None
802
802
803 if callable_obj:
803 if callable_obj:
804 try:
804 try:
805 args, varargs, varkw, defaults = getargspec(callable_obj)
805 args, varargs, varkw, defaults = getargspec(callable_obj)
806 except (TypeError, AttributeError):
806 except (TypeError, AttributeError):
807 # For extensions/builtins we can't retrieve the argspec
807 # For extensions/builtins we can't retrieve the argspec
808 pass
808 pass
809 else:
809 else:
810 out['argspec'] = dict(args=args, varargs=varargs,
810 out['argspec'] = dict(args=args, varargs=varargs,
811 varkw=varkw, defaults=defaults)
811 varkw=varkw, defaults=defaults)
812
812
813 return object_info(**out)
813 return object_info(**out)
814
814
815
815
816 def psearch(self,pattern,ns_table,ns_search=[],
816 def psearch(self,pattern,ns_table,ns_search=[],
817 ignore_case=False,show_all=False):
817 ignore_case=False,show_all=False):
818 """Search namespaces with wildcards for objects.
818 """Search namespaces with wildcards for objects.
819
819
820 Arguments:
820 Arguments:
821
821
822 - pattern: string containing shell-like wildcards to use in namespace
822 - pattern: string containing shell-like wildcards to use in namespace
823 searches and optionally a type specification to narrow the search to
823 searches and optionally a type specification to narrow the search to
824 objects of that type.
824 objects of that type.
825
825
826 - ns_table: dict of name->namespaces for search.
826 - ns_table: dict of name->namespaces for search.
827
827
828 Optional arguments:
828 Optional arguments:
829
829
830 - ns_search: list of namespace names to include in search.
830 - ns_search: list of namespace names to include in search.
831
831
832 - ignore_case(False): make the search case-insensitive.
832 - ignore_case(False): make the search case-insensitive.
833
833
834 - show_all(False): show all names, including those starting with
834 - show_all(False): show all names, including those starting with
835 underscores.
835 underscores.
836 """
836 """
837 #print 'ps pattern:<%r>' % pattern # dbg
837 #print 'ps pattern:<%r>' % pattern # dbg
838
838
839 # defaults
839 # defaults
840 type_pattern = 'all'
840 type_pattern = 'all'
841 filter = ''
841 filter = ''
842
842
843 cmds = pattern.split()
843 cmds = pattern.split()
844 len_cmds = len(cmds)
844 len_cmds = len(cmds)
845 if len_cmds == 1:
845 if len_cmds == 1:
846 # Only filter pattern given
846 # Only filter pattern given
847 filter = cmds[0]
847 filter = cmds[0]
848 elif len_cmds == 2:
848 elif len_cmds == 2:
849 # Both filter and type specified
849 # Both filter and type specified
850 filter,type_pattern = cmds
850 filter,type_pattern = cmds
851 else:
851 else:
852 raise ValueError('invalid argument string for psearch: <%s>' %
852 raise ValueError('invalid argument string for psearch: <%s>' %
853 pattern)
853 pattern)
854
854
855 # filter search namespaces
855 # filter search namespaces
856 for name in ns_search:
856 for name in ns_search:
857 if name not in ns_table:
857 if name not in ns_table:
858 raise ValueError('invalid namespace <%s>. Valid names: %s' %
858 raise ValueError('invalid namespace <%s>. Valid names: %s' %
859 (name,ns_table.keys()))
859 (name,ns_table.keys()))
860
860
861 #print 'type_pattern:',type_pattern # dbg
861 #print 'type_pattern:',type_pattern # dbg
862 search_result, namespaces_seen = set(), set()
862 search_result, namespaces_seen = set(), set()
863 for ns_name in ns_search:
863 for ns_name in ns_search:
864 ns = ns_table[ns_name]
864 ns = ns_table[ns_name]
865 # 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.
866 if id(ns) in namespaces_seen:
866 if id(ns) in namespaces_seen:
867 continue
867 continue
868 namespaces_seen.add(id(ns))
868 namespaces_seen.add(id(ns))
869 tmp_res = list_namespace(ns, type_pattern, filter,
869 tmp_res = list_namespace(ns, type_pattern, filter,
870 ignore_case=ignore_case, show_all=show_all)
870 ignore_case=ignore_case, show_all=show_all)
871 search_result.update(tmp_res)
871 search_result.update(tmp_res)
872
872
873 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