##// END OF EJS Templates
Oinspect.py: Only show docstring for nonexisting/binary files...
vivainio -
Show More

The requested changes are too big and content was truncated. Show full diff

@@ -1,475 +1,483 b''
1 1 # -*- coding: utf-8 -*-
2 2 """Tools for inspecting Python objects.
3 3
4 4 Uses syntax highlighting for presenting the various information elements.
5 5
6 6 Similar in spirit to the inspect module, but all calls take a name argument to
7 7 reference the name under which an object is being read.
8 8
9 $Id: OInspect.py 1058 2006-01-22 14:30:01Z vivainio $
9 $Id: OInspect.py 1300 2006-05-15 16:27:36Z vivainio $
10 10 """
11 11
12 12 #*****************************************************************************
13 13 # Copyright (C) 2001-2004 Fernando Perez <fperez@colorado.edu>
14 14 #
15 15 # Distributed under the terms of the BSD License. The full license is in
16 16 # the file COPYING, distributed as part of this software.
17 17 #*****************************************************************************
18 18
19 19 from IPython import Release
20 20 __author__ = '%s <%s>' % Release.authors['Fernando']
21 21 __license__ = Release.license
22 22
23 23 __all__ = ['Inspector','InspectColors']
24 24
25 25 # stdlib modules
26 26 import __builtin__
27 27 import inspect
28 28 import linecache
29 29 import string
30 30 import StringIO
31 31 import types
32
32 import os
33 33 # IPython's own
34 34 from IPython import PyColorize
35 35 from IPython.genutils import page,indent,Term,mkdict
36 36 from IPython.Itpl import itpl
37 37 from IPython.wildcard import list_namespace
38 38 from IPython.ColorANSI import *
39 39
40 40 #****************************************************************************
41 41 # Builtin color schemes
42 42
43 43 Colors = TermColors # just a shorthand
44 44
45 45 # Build a few color schemes
46 46 NoColor = ColorScheme(
47 47 'NoColor',{
48 48 'header' : Colors.NoColor,
49 49 'normal' : Colors.NoColor # color off (usu. Colors.Normal)
50 50 } )
51 51
52 52 LinuxColors = ColorScheme(
53 53 'Linux',{
54 54 'header' : Colors.LightRed,
55 55 'normal' : Colors.Normal # color off (usu. Colors.Normal)
56 56 } )
57 57
58 58 LightBGColors = ColorScheme(
59 59 'LightBG',{
60 60 'header' : Colors.Red,
61 61 'normal' : Colors.Normal # color off (usu. Colors.Normal)
62 62 } )
63 63
64 64 # Build table of color schemes (needed by the parser)
65 65 InspectColors = ColorSchemeTable([NoColor,LinuxColors,LightBGColors],
66 66 'Linux')
67 67
68 68 #****************************************************************************
69 69 # Auxiliary functions
70 70 def getdoc(obj):
71 71 """Stable wrapper around inspect.getdoc.
72 72
73 73 This can't crash because of attribute problems.
74 74
75 75 It also attempts to call a getdoc() method on the given object. This
76 76 allows objects which provide their docstrings via non-standard mechanisms
77 77 (like Pyro proxies) to still be inspected by ipython's ? system."""
78 78
79 79 ds = None # default return value
80 80 try:
81 81 ds = inspect.getdoc(obj)
82 82 except:
83 83 # Harden against an inspect failure, which can occur with
84 84 # SWIG-wrapped extensions.
85 85 pass
86 86 # Allow objects to offer customized documentation via a getdoc method:
87 87 try:
88 88 ds2 = obj.getdoc()
89 89 except:
90 90 pass
91 91 else:
92 92 # if we get extra info, we add it to the normal docstring.
93 93 if ds is None:
94 94 ds = ds2
95 95 else:
96 96 ds = '%s\n%s' % (ds,ds2)
97 97 return ds
98 98
99 99 #****************************************************************************
100 100 # Class definitions
101 101
102 102 class myStringIO(StringIO.StringIO):
103 103 """Adds a writeln method to normal StringIO."""
104 104 def writeln(self,*arg,**kw):
105 105 """Does a write() and then a write('\n')"""
106 106 self.write(*arg,**kw)
107 107 self.write('\n')
108 108
109 109 class Inspector:
110 110 def __init__(self,color_table,code_color_table,scheme):
111 111 self.color_table = color_table
112 112 self.parser = PyColorize.Parser(code_color_table,out='str')
113 113 self.format = self.parser.format
114 114 self.set_active_scheme(scheme)
115 115
116 116 def __getargspec(self,obj):
117 117 """Get the names and default values of a function's arguments.
118 118
119 119 A tuple of four things is returned: (args, varargs, varkw, defaults).
120 120 'args' is a list of the argument names (it may contain nested lists).
121 121 'varargs' and 'varkw' are the names of the * and ** arguments or None.
122 122 'defaults' is an n-tuple of the default values of the last n arguments.
123 123
124 124 Modified version of inspect.getargspec from the Python Standard
125 125 Library."""
126 126
127 127 if inspect.isfunction(obj):
128 128 func_obj = obj
129 129 elif inspect.ismethod(obj):
130 130 func_obj = obj.im_func
131 131 else:
132 132 raise TypeError, 'arg is not a Python function'
133 133 args, varargs, varkw = inspect.getargs(func_obj.func_code)
134 134 return args, varargs, varkw, func_obj.func_defaults
135 135
136 136 def __getdef(self,obj,oname=''):
137 137 """Return the definition header for any callable object.
138 138
139 139 If any exception is generated, None is returned instead and the
140 140 exception is suppressed."""
141 141
142 142 try:
143 143 return oname + inspect.formatargspec(*self.__getargspec(obj))
144 144 except:
145 145 return None
146 146
147 147 def __head(self,h):
148 148 """Return a header string with proper colors."""
149 149 return '%s%s%s' % (self.color_table.active_colors.header,h,
150 150 self.color_table.active_colors.normal)
151 151
152 152 def set_active_scheme(self,scheme):
153 153 self.color_table.set_active_scheme(scheme)
154 154 self.parser.color_table.set_active_scheme(scheme)
155 155
156 156 def noinfo(self,msg,oname):
157 157 """Generic message when no information is found."""
158 158 print 'No %s found' % msg,
159 159 if oname:
160 160 print 'for %s' % oname
161 161 else:
162 162 print
163 163
164 164 def pdef(self,obj,oname=''):
165 165 """Print the definition header for any callable object.
166 166
167 167 If the object is a class, print the constructor information."""
168 168
169 169 if not callable(obj):
170 170 print 'Object is not callable.'
171 171 return
172 172
173 173 header = ''
174 174 if type(obj) is types.ClassType:
175 175 header = self.__head('Class constructor information:\n')
176 176 obj = obj.__init__
177 177 elif type(obj) is types.InstanceType:
178 178 obj = obj.__call__
179 179
180 180 output = self.__getdef(obj,oname)
181 181 if output is None:
182 182 self.noinfo('definition header',oname)
183 183 else:
184 184 print >>Term.cout, header,self.format(output),
185 185
186 186 def pdoc(self,obj,oname='',formatter = None):
187 187 """Print the docstring for any object.
188 188
189 189 Optional:
190 190 -formatter: a function to run the docstring through for specially
191 191 formatted docstrings."""
192 192
193 193 head = self.__head # so that itpl can find it even if private
194 194 ds = getdoc(obj)
195 195 if formatter:
196 196 ds = formatter(ds)
197 197 if type(obj) is types.ClassType:
198 198 init_ds = getdoc(obj.__init__)
199 199 output = itpl('$head("Class Docstring:")\n'
200 200 '$indent(ds)\n'
201 201 '$head("Constructor Docstring"):\n'
202 202 '$indent(init_ds)')
203 203 elif type(obj) is types.InstanceType and hasattr(obj,'__call__'):
204 204 call_ds = getdoc(obj.__call__)
205 205 if call_ds:
206 206 output = itpl('$head("Class Docstring:")\n$indent(ds)\n'
207 207 '$head("Calling Docstring:")\n$indent(call_ds)')
208 208 else:
209 209 output = ds
210 210 else:
211 211 output = ds
212 212 if output is None:
213 213 self.noinfo('documentation',oname)
214 214 return
215 215 page(output)
216 216
217 217 def psource(self,obj,oname=''):
218 218 """Print the source code for an object."""
219 219
220 220 # Flush the source cache because inspect can return out-of-date source
221 221 linecache.checkcache()
222 222 try:
223 223 src = inspect.getsource(obj)
224 224 except:
225 225 self.noinfo('source',oname)
226 226 else:
227 227 page(self.format(src))
228 228
229 229 def pfile(self,obj,oname=''):
230 230 """Show the whole file where an object was defined."""
231 231 try:
232 232 sourcelines,lineno = inspect.getsourcelines(obj)
233 233 except:
234 234 self.noinfo('file',oname)
235 235 else:
236 236 # run contents of file through pager starting at line
237 237 # where the object is defined
238 238 ofile = inspect.getabsfile(obj)
239 239
240 240 if (ofile.endswith('.so') or ofile.endswith('.dll')):
241 241 print 'File %r is binary, not printing.' % ofile
242 elif not os.path.isfile(ofile):
243 print 'File %r does not exist, not printing.' % ofile
242 244 else:
243 245 # Print only text files, not extension binaries.
244 246 page(self.format(open(ofile).read()),lineno)
245 247 #page(self.format(open(inspect.getabsfile(obj)).read()),lineno)
246 248
247 249 def pinfo(self,obj,oname='',formatter=None,info=None,detail_level=0):
248 250 """Show detailed information about an object.
249 251
250 252 Optional arguments:
251 253
252 254 - oname: name of the variable pointing to the object.
253 255
254 256 - formatter: special formatter for docstrings (see pdoc)
255 257
256 258 - info: a structure with some information fields which may have been
257 259 precomputed already.
258 260
259 261 - detail_level: if set to 1, more information is given.
260 262 """
261 263
262 264 obj_type = type(obj)
263 265
264 266 header = self.__head
265 267 if info is None:
266 268 ismagic = 0
267 269 isalias = 0
268 270 ospace = ''
269 271 else:
270 272 ismagic = info.ismagic
271 273 isalias = info.isalias
272 274 ospace = info.namespace
273 275 # Get docstring, special-casing aliases:
274 276 if isalias:
275 277 ds = "Alias to the system command:\n %s" % obj[1]
276 278 else:
277 279 ds = getdoc(obj)
278 280 if ds is None:
279 281 ds = '<no docstring>'
280 282 if formatter is not None:
281 283 ds = formatter(ds)
282 284
283 285 # store output in a list which gets joined with \n at the end.
284 286 out = myStringIO()
285 287
286 288 string_max = 200 # max size of strings to show (snipped if longer)
287 289 shalf = int((string_max -5)/2)
288 290
289 291 if ismagic:
290 292 obj_type_name = 'Magic function'
291 293 elif isalias:
292 294 obj_type_name = 'System alias'
293 295 else:
294 296 obj_type_name = obj_type.__name__
295 297 out.writeln(header('Type:\t\t')+obj_type_name)
296 298
297 299 try:
298 300 bclass = obj.__class__
299 301 out.writeln(header('Base Class:\t')+str(bclass))
300 302 except: pass
301 303
302 304 # String form, but snip if too long in ? form (full in ??)
303 305 try:
304 306 ostr = str(obj)
305 307 str_head = 'String Form:'
306 308 if not detail_level and len(ostr)>string_max:
307 309 ostr = ostr[:shalf] + ' <...> ' + ostr[-shalf:]
308 310 ostr = ("\n" + " " * len(str_head.expandtabs())).\
309 311 join(map(string.strip,ostr.split("\n")))
310 312 if ostr.find('\n') > -1:
311 313 # Print multi-line strings starting at the next line.
312 314 str_sep = '\n'
313 315 else:
314 316 str_sep = '\t'
315 317 out.writeln("%s%s%s" % (header(str_head),str_sep,ostr))
316 318 except:
317 319 pass
318 320
319 321 if ospace:
320 322 out.writeln(header('Namespace:\t')+ospace)
321 323
322 324 # Length (for strings and lists)
323 325 try:
324 326 length = str(len(obj))
325 327 out.writeln(header('Length:\t\t')+length)
326 328 except: pass
327 329
328 330 # Filename where object was defined
329 331 binary_file = False
330 332 try:
331 333 fname = inspect.getabsfile(obj)
332 334 if fname.endswith('<string>'):
333 335 fname = 'Dynamically generated function. No source code available.'
334 if fname.endswith('.so') or fname.endswith('.dll'):
336 if (fname.endswith('.so') or fname.endswith('.dll') or
337 not os.path.isfile(fname)):
335 338 binary_file = True
336 339 out.writeln(header('File:\t\t')+fname)
337 340 except:
338 341 # if anything goes wrong, we don't want to show source, so it's as
339 342 # if the file was binary
340 343 binary_file = True
341 344
342 345 # reconstruct the function definition and print it:
343 346 defln = self.__getdef(obj,oname)
344 347 if defln:
345 348 out.write(header('Definition:\t')+self.format(defln))
346 349
347 350 # Docstrings only in detail 0 mode, since source contains them (we
348 351 # avoid repetitions). If source fails, we add them back, see below.
349 352 if ds and detail_level == 0:
350 353 out.writeln(header('Docstring:\n') + indent(ds))
351 354
355
352 356 # Original source code for any callable
353 357 if detail_level:
354 358 # Flush the source cache because inspect can return out-of-date source
355 359 linecache.checkcache()
360 source_success = False
356 361 try:
357 362 if not binary_file:
358 363 source = self.format(inspect.getsource(obj))
359 364 out.write(header('Source:\n')+source.rstrip())
365 source_success = True
360 366 except:
361 if ds:
362 out.writeln(header('Docstring:\n') + indent(ds))
367 pass
368
369 if ds and not source_success:
370 out.writeln(header('Docstring [source file open failed]:\n') + indent(ds))
363 371
364 372 # Constructor docstring for classes
365 373 if obj_type is types.ClassType:
366 374 # reconstruct the function definition and print it:
367 375 try:
368 376 obj_init = obj.__init__
369 377 except AttributeError:
370 378 init_def = init_ds = None
371 379 else:
372 380 init_def = self.__getdef(obj_init,oname)
373 381 init_ds = getdoc(obj_init)
374 382
375 383 if init_def or init_ds:
376 384 out.writeln(header('\nConstructor information:'))
377 385 if init_def:
378 386 out.write(header('Definition:\t')+ self.format(init_def))
379 387 if init_ds:
380 388 out.writeln(header('Docstring:\n') + indent(init_ds))
381 389 # and class docstring for instances:
382 390 elif obj_type is types.InstanceType:
383 391
384 392 # First, check whether the instance docstring is identical to the
385 393 # class one, and print it separately if they don't coincide. In
386 394 # most cases they will, but it's nice to print all the info for
387 395 # objects which use instance-customized docstrings.
388 396 if ds:
389 397 class_ds = getdoc(obj.__class__)
390 398 if class_ds and ds != class_ds:
391 399 out.writeln(header('Class Docstring:\n') +
392 400 indent(class_ds))
393 401
394 402 # Next, try to show constructor docstrings
395 403 try:
396 404 init_ds = getdoc(obj.__init__)
397 405 except AttributeError:
398 406 init_ds = None
399 407 if init_ds:
400 408 out.writeln(header('Constructor Docstring:\n') +
401 409 indent(init_ds))
402 410
403 411 # Call form docstring for callable instances
404 412 if hasattr(obj,'__call__'):
405 413 out.writeln(header('Callable:\t')+'Yes')
406 414 call_def = self.__getdef(obj.__call__,oname)
407 415 if call_def is None:
408 416 out.write(header('Call def:\t')+
409 417 'Calling definition not available.')
410 418 else:
411 419 out.write(header('Call def:\t')+self.format(call_def))
412 420 call_ds = getdoc(obj.__call__)
413 421 if call_ds:
414 422 out.writeln(header('Call docstring:\n') + indent(call_ds))
415 423
416 424 # Finally send to printer/pager
417 425 output = out.getvalue()
418 426 if output:
419 427 page(output)
420 428 # end pinfo
421 429
422 430 def psearch(self,pattern,ns_table,ns_search=[],
423 431 ignore_case=False,show_all=False):
424 432 """Search namespaces with wildcards for objects.
425 433
426 434 Arguments:
427 435
428 436 - pattern: string containing shell-like wildcards to use in namespace
429 437 searches and optionally a type specification to narrow the search to
430 438 objects of that type.
431 439
432 440 - ns_table: dict of name->namespaces for search.
433 441
434 442 Optional arguments:
435 443
436 444 - ns_search: list of namespace names to include in search.
437 445
438 446 - ignore_case(False): make the search case-insensitive.
439 447
440 448 - show_all(False): show all names, including those starting with
441 449 underscores.
442 450 """
443 451 # defaults
444 452 type_pattern = 'all'
445 453 filter = ''
446 454
447 455 cmds = pattern.split()
448 456 len_cmds = len(cmds)
449 457 if len_cmds == 1:
450 458 # Only filter pattern given
451 459 filter = cmds[0]
452 460 elif len_cmds == 2:
453 461 # Both filter and type specified
454 462 filter,type_pattern = cmds
455 463 else:
456 464 raise ValueError('invalid argument string for psearch: <%s>' %
457 465 pattern)
458 466
459 467 # filter search namespaces
460 468 for name in ns_search:
461 469 if name not in ns_table:
462 470 raise ValueError('invalid namespace <%s>. Valid names: %s' %
463 471 (name,ns_table.keys()))
464 472
465 473 #print 'type_pattern:',type_pattern # dbg
466 474 search_result = []
467 475 for ns_name in ns_search:
468 476 ns = ns_table[ns_name]
469 477 tmp_res = list(list_namespace(ns,type_pattern,filter,
470 478 ignore_case=ignore_case,
471 479 show_all=show_all))
472 480 search_result.extend(tmp_res)
473 481 search_result.sort()
474 482
475 483 page('\n'.join(search_result))
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
General Comments 0
You need to be logged in to leave comments. Login now