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