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