##// END OF EJS Templates
handle multiple decorators in oinspect...
Min RK -
Show More
@@ -1,928 +1,927 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 9
10 10 # Copyright (c) IPython Development Team.
11 11 # Distributed under the terms of the Modified BSD License.
12 12
13 13 from __future__ import print_function
14 14
15 15 __all__ = ['Inspector','InspectColors']
16 16
17 17 # stdlib modules
18 18 import inspect
19 19 import linecache
20 20 import os
21 21 from textwrap import dedent
22 22 import types
23 23 import io as stdlib_io
24 24
25 25 try:
26 26 from itertools import izip_longest
27 27 except ImportError:
28 28 from itertools import zip_longest as izip_longest
29 29
30 30 # IPython's own
31 31 from IPython.core import page
32 32 from IPython.lib.pretty import pretty
33 33 from IPython.testing.skipdoctest import skip_doctest_py3
34 34 from IPython.utils import PyColorize
35 35 from IPython.utils import io
36 36 from IPython.utils import openpy
37 37 from IPython.utils import py3compat
38 38 from IPython.utils.dir2 import safe_hasattr
39 39 from IPython.utils.path import compress_user
40 40 from IPython.utils.text import indent
41 41 from IPython.utils.wildcard import list_namespace
42 42 from IPython.utils.coloransi import TermColors, ColorScheme, ColorSchemeTable
43 43 from IPython.utils.py3compat import cast_unicode, string_types, PY3
44 44 from IPython.utils.signatures import signature
45 45
46 46 # builtin docstrings to ignore
47 47 _func_call_docstring = types.FunctionType.__call__.__doc__
48 48 _object_init_docstring = object.__init__.__doc__
49 49 _builtin_type_docstrings = {
50 50 inspect.getdoc(t) for t in (types.ModuleType, types.MethodType,
51 51 types.FunctionType, property)
52 52 }
53 53
54 54 _builtin_func_type = type(all)
55 55 _builtin_meth_type = type(str.upper) # Bound methods have the same type as builtin functions
56 56 #****************************************************************************
57 57 # Builtin color schemes
58 58
59 59 Colors = TermColors # just a shorthand
60 60
61 61 # Build a few color schemes
62 62 NoColor = ColorScheme(
63 63 'NoColor',{
64 64 'header' : Colors.NoColor,
65 65 'normal' : Colors.NoColor # color off (usu. Colors.Normal)
66 66 } )
67 67
68 68 LinuxColors = ColorScheme(
69 69 'Linux',{
70 70 'header' : Colors.LightRed,
71 71 'normal' : Colors.Normal # color off (usu. Colors.Normal)
72 72 } )
73 73
74 74 LightBGColors = ColorScheme(
75 75 'LightBG',{
76 76 'header' : Colors.Red,
77 77 'normal' : Colors.Normal # color off (usu. Colors.Normal)
78 78 } )
79 79
80 80 # Build table of color schemes (needed by the parser)
81 81 InspectColors = ColorSchemeTable([NoColor,LinuxColors,LightBGColors],
82 82 'Linux')
83 83
84 84 #****************************************************************************
85 85 # Auxiliary functions and objects
86 86
87 87 # See the messaging spec for the definition of all these fields. This list
88 88 # effectively defines the order of display
89 89 info_fields = ['type_name', 'base_class', 'string_form', 'namespace',
90 90 'length', 'file', 'definition', 'docstring', 'source',
91 91 'init_definition', 'class_docstring', 'init_docstring',
92 92 'call_def', 'call_docstring',
93 93 # These won't be printed but will be used to determine how to
94 94 # format the object
95 95 'ismagic', 'isalias', 'isclass', 'argspec', 'found', 'name'
96 96 ]
97 97
98 98
99 99 def object_info(**kw):
100 100 """Make an object info dict with all fields present."""
101 101 infodict = dict(izip_longest(info_fields, [None]))
102 102 infodict.update(kw)
103 103 return infodict
104 104
105 105
106 106 def get_encoding(obj):
107 107 """Get encoding for python source file defining obj
108 108
109 109 Returns None if obj is not defined in a sourcefile.
110 110 """
111 111 ofile = find_file(obj)
112 112 # run contents of file through pager starting at line where the object
113 113 # is defined, as long as the file isn't binary and is actually on the
114 114 # filesystem.
115 115 if ofile is None:
116 116 return None
117 117 elif ofile.endswith(('.so', '.dll', '.pyd')):
118 118 return None
119 119 elif not os.path.isfile(ofile):
120 120 return None
121 121 else:
122 122 # Print only text files, not extension binaries. Note that
123 123 # getsourcelines returns lineno with 1-offset and page() uses
124 124 # 0-offset, so we must adjust.
125 125 with stdlib_io.open(ofile, 'rb') as buffer: # Tweaked to use io.open for Python 2
126 126 encoding, lines = openpy.detect_encoding(buffer.readline)
127 127 return encoding
128 128
129 129 def getdoc(obj):
130 130 """Stable wrapper around inspect.getdoc.
131 131
132 132 This can't crash because of attribute problems.
133 133
134 134 It also attempts to call a getdoc() method on the given object. This
135 135 allows objects which provide their docstrings via non-standard mechanisms
136 136 (like Pyro proxies) to still be inspected by ipython's ? system."""
137 137 # Allow objects to offer customized documentation via a getdoc method:
138 138 try:
139 139 ds = obj.getdoc()
140 140 except Exception:
141 141 pass
142 142 else:
143 143 # if we get extra info, we add it to the normal docstring.
144 144 if isinstance(ds, string_types):
145 145 return inspect.cleandoc(ds)
146 146
147 147 try:
148 148 docstr = inspect.getdoc(obj)
149 149 encoding = get_encoding(obj)
150 150 return py3compat.cast_unicode(docstr, encoding=encoding)
151 151 except Exception:
152 152 # Harden against an inspect failure, which can occur with
153 153 # SWIG-wrapped extensions.
154 154 raise
155 155 return None
156 156
157 157
158 158 def getsource(obj, oname=''):
159 159 """Wrapper around inspect.getsource.
160 160
161 161 This can be modified by other projects to provide customized source
162 162 extraction.
163 163
164 164 Parameters
165 165 ----------
166 166 obj : object
167 167 an object whose source code we will attempt to extract
168 168 oname : str
169 169 (optional) a name under which the object is known
170 170
171 171 Returns
172 172 -------
173 173 src : unicode or None
174 174
175 175 """
176 176
177 177 if isinstance(obj, property):
178 178 sources = []
179 179 for attrname in ['fget', 'fset', 'fdel']:
180 180 fn = getattr(obj, attrname)
181 181 if fn is not None:
182 182 encoding = get_encoding(fn)
183 183 oname_prefix = ('%s.' % oname) if oname else ''
184 184 sources.append(cast_unicode(
185 185 ''.join(('# ', oname_prefix, attrname)),
186 186 encoding=encoding))
187 187 if inspect.isfunction(fn):
188 188 sources.append(dedent(getsource(fn)))
189 189 else:
190 190 # Default str/repr only prints function name,
191 191 # pretty.pretty prints module name too.
192 192 sources.append(cast_unicode(
193 193 '%s%s = %s\n' % (
194 194 oname_prefix, attrname, pretty(fn)),
195 195 encoding=encoding))
196 196 if sources:
197 197 return '\n'.join(sources)
198 198 else:
199 199 return None
200 200
201 201 else:
202 202 # Get source for non-property objects.
203 203
204 # '__wrapped__' attribute is used by some decorators (e.g. ones defined
205 # functools) to provide access to the decorated function.
206 if hasattr(obj, "__wrapped__"):
207 obj = obj.__wrapped__
204 obj = _get_wrapped(obj)
208 205
209 206 try:
210 207 src = inspect.getsource(obj)
211 208 except TypeError:
212 209 # The object itself provided no meaningful source, try looking for
213 210 # its class definition instead.
214 211 if hasattr(obj, '__class__'):
215 212 try:
216 213 src = inspect.getsource(obj.__class__)
217 214 except TypeError:
218 215 return None
219 216
220 217 encoding = get_encoding(obj)
221 218 return cast_unicode(src, encoding=encoding)
222 219
223 220
224 221 def is_simple_callable(obj):
225 222 """True if obj is a function ()"""
226 223 return (inspect.isfunction(obj) or inspect.ismethod(obj) or \
227 224 isinstance(obj, _builtin_func_type) or isinstance(obj, _builtin_meth_type))
228 225
229 226
230 227 def getargspec(obj):
231 228 """Wrapper around :func:`inspect.getfullargspec` on Python 3, and
232 229 :func:inspect.getargspec` on Python 2.
233 230
234 231 In addition to functions and methods, this can also handle objects with a
235 232 ``__call__`` attribute.
236 233 """
237 234 if safe_hasattr(obj, '__call__') and not is_simple_callable(obj):
238 235 obj = obj.__call__
239 236
240 237 return inspect.getfullargspec(obj) if PY3 else inspect.getargspec(obj)
241 238
242 239
243 240 def format_argspec(argspec):
244 241 """Format argspect, convenience wrapper around inspect's.
245 242
246 243 This takes a dict instead of ordered arguments and calls
247 244 inspect.format_argspec with the arguments in the necessary order.
248 245 """
249 246 return inspect.formatargspec(argspec['args'], argspec['varargs'],
250 247 argspec['varkw'], argspec['defaults'])
251 248
252 249
253 250 def call_tip(oinfo, format_call=True):
254 251 """Extract call tip data from an oinfo dict.
255 252
256 253 Parameters
257 254 ----------
258 255 oinfo : dict
259 256
260 257 format_call : bool, optional
261 258 If True, the call line is formatted and returned as a string. If not, a
262 259 tuple of (name, argspec) is returned.
263 260
264 261 Returns
265 262 -------
266 263 call_info : None, str or (str, dict) tuple.
267 264 When format_call is True, the whole call information is formattted as a
268 265 single string. Otherwise, the object's name and its argspec dict are
269 266 returned. If no call information is available, None is returned.
270 267
271 268 docstring : str or None
272 269 The most relevant docstring for calling purposes is returned, if
273 270 available. The priority is: call docstring for callable instances, then
274 271 constructor docstring for classes, then main object's docstring otherwise
275 272 (regular functions).
276 273 """
277 274 # Get call definition
278 275 argspec = oinfo.get('argspec')
279 276 if argspec is None:
280 277 call_line = None
281 278 else:
282 279 # Callable objects will have 'self' as their first argument, prune
283 280 # it out if it's there for clarity (since users do *not* pass an
284 281 # extra first argument explicitly).
285 282 try:
286 283 has_self = argspec['args'][0] == 'self'
287 284 except (KeyError, IndexError):
288 285 pass
289 286 else:
290 287 if has_self:
291 288 argspec['args'] = argspec['args'][1:]
292 289
293 290 call_line = oinfo['name']+format_argspec(argspec)
294 291
295 292 # Now get docstring.
296 293 # The priority is: call docstring, constructor docstring, main one.
297 294 doc = oinfo.get('call_docstring')
298 295 if doc is None:
299 296 doc = oinfo.get('init_docstring')
300 297 if doc is None:
301 298 doc = oinfo.get('docstring','')
302 299
303 300 return call_line, doc
304 301
305 302
303 def _get_wrapped(obj):
304 """Get the original object if wrapped in one or more @decorators"""
305 while safe_hasattr(obj, '__wrapped__'):
306 obj = obj.__wrapped__
307 return obj
308
306 309 def find_file(obj):
307 310 """Find the absolute path to the file where an object was defined.
308 311
309 312 This is essentially a robust wrapper around `inspect.getabsfile`.
310 313
311 314 Returns None if no file can be found.
312 315
313 316 Parameters
314 317 ----------
315 318 obj : any Python object
316 319
317 320 Returns
318 321 -------
319 322 fname : str
320 323 The absolute path to the file where the object was defined.
321 324 """
322 # get source if obj was decorated with @decorator
323 if safe_hasattr(obj, '__wrapped__'):
324 obj = obj.__wrapped__
325 obj = _get_wrapped(obj)
325 326
326 327 fname = None
327 328 try:
328 329 fname = inspect.getabsfile(obj)
329 330 except TypeError:
330 331 # For an instance, the file that matters is where its class was
331 332 # declared.
332 333 if hasattr(obj, '__class__'):
333 334 try:
334 335 fname = inspect.getabsfile(obj.__class__)
335 336 except TypeError:
336 337 # Can happen for builtins
337 338 pass
338 339 except:
339 340 pass
340 341 return cast_unicode(fname)
341 342
342 343
343 344 def find_source_lines(obj):
344 345 """Find the line number in a file where an object was defined.
345 346
346 347 This is essentially a robust wrapper around `inspect.getsourcelines`.
347 348
348 349 Returns None if no file can be found.
349 350
350 351 Parameters
351 352 ----------
352 353 obj : any Python object
353 354
354 355 Returns
355 356 -------
356 357 lineno : int
357 358 The line number where the object definition starts.
358 359 """
359 # get source if obj was decorated with @decorator
360 if safe_hasattr(obj, '__wrapped__'):
361 obj = obj.__wrapped__
360 obj = _get_wrapped(obj)
362 361
363 362 try:
364 363 try:
365 364 lineno = inspect.getsourcelines(obj)[1]
366 365 except TypeError:
367 366 # For instances, try the class object like getsource() does
368 367 if hasattr(obj, '__class__'):
369 368 lineno = inspect.getsourcelines(obj.__class__)[1]
370 369 else:
371 370 lineno = None
372 371 except:
373 372 return None
374 373
375 374 return lineno
376 375
377 376
378 377 class Inspector:
379 378 def __init__(self, color_table=InspectColors,
380 379 code_color_table=PyColorize.ANSICodeColors,
381 380 scheme='NoColor',
382 381 str_detail_level=0):
383 382 self.color_table = color_table
384 383 self.parser = PyColorize.Parser(code_color_table,out='str')
385 384 self.format = self.parser.format
386 385 self.str_detail_level = str_detail_level
387 386 self.set_active_scheme(scheme)
388 387
389 388 def _getdef(self,obj,oname=''):
390 389 """Return the call signature for any callable object.
391 390
392 391 If any exception is generated, None is returned instead and the
393 392 exception is suppressed."""
394 393 try:
395 394 hdef = oname + str(signature(obj))
396 395 return cast_unicode(hdef)
397 396 except:
398 397 return None
399 398
400 399 def __head(self,h):
401 400 """Return a header string with proper colors."""
402 401 return '%s%s%s' % (self.color_table.active_colors.header,h,
403 402 self.color_table.active_colors.normal)
404 403
405 404 def set_active_scheme(self, scheme):
406 405 self.color_table.set_active_scheme(scheme)
407 406 self.parser.color_table.set_active_scheme(scheme)
408 407
409 408 def noinfo(self, msg, oname):
410 409 """Generic message when no information is found."""
411 410 print('No %s found' % msg, end=' ')
412 411 if oname:
413 412 print('for %s' % oname)
414 413 else:
415 414 print()
416 415
417 416 def pdef(self, obj, oname=''):
418 417 """Print the call signature for any callable object.
419 418
420 419 If the object is a class, print the constructor information."""
421 420
422 421 if not callable(obj):
423 422 print('Object is not callable.')
424 423 return
425 424
426 425 header = ''
427 426
428 427 if inspect.isclass(obj):
429 428 header = self.__head('Class constructor information:\n')
430 429 obj = obj.__init__
431 430 elif (not py3compat.PY3) and type(obj) is types.InstanceType:
432 431 obj = obj.__call__
433 432
434 433 output = self._getdef(obj,oname)
435 434 if output is None:
436 435 self.noinfo('definition header',oname)
437 436 else:
438 437 print(header,self.format(output), end=' ', file=io.stdout)
439 438
440 439 # In Python 3, all classes are new-style, so they all have __init__.
441 440 @skip_doctest_py3
442 441 def pdoc(self,obj,oname='',formatter = None):
443 442 """Print the docstring for any object.
444 443
445 444 Optional:
446 445 -formatter: a function to run the docstring through for specially
447 446 formatted docstrings.
448 447
449 448 Examples
450 449 --------
451 450
452 451 In [1]: class NoInit:
453 452 ...: pass
454 453
455 454 In [2]: class NoDoc:
456 455 ...: def __init__(self):
457 456 ...: pass
458 457
459 458 In [3]: %pdoc NoDoc
460 459 No documentation found for NoDoc
461 460
462 461 In [4]: %pdoc NoInit
463 462 No documentation found for NoInit
464 463
465 464 In [5]: obj = NoInit()
466 465
467 466 In [6]: %pdoc obj
468 467 No documentation found for obj
469 468
470 469 In [5]: obj2 = NoDoc()
471 470
472 471 In [6]: %pdoc obj2
473 472 No documentation found for obj2
474 473 """
475 474
476 475 head = self.__head # For convenience
477 476 lines = []
478 477 ds = getdoc(obj)
479 478 if formatter:
480 479 ds = formatter(ds)
481 480 if ds:
482 481 lines.append(head("Class docstring:"))
483 482 lines.append(indent(ds))
484 483 if inspect.isclass(obj) and hasattr(obj, '__init__'):
485 484 init_ds = getdoc(obj.__init__)
486 485 if init_ds is not None:
487 486 lines.append(head("Init docstring:"))
488 487 lines.append(indent(init_ds))
489 488 elif hasattr(obj,'__call__'):
490 489 call_ds = getdoc(obj.__call__)
491 490 if call_ds:
492 491 lines.append(head("Call docstring:"))
493 492 lines.append(indent(call_ds))
494 493
495 494 if not lines:
496 495 self.noinfo('documentation',oname)
497 496 else:
498 497 page.page('\n'.join(lines))
499 498
500 499 def psource(self, obj, oname=''):
501 500 """Print the source code for an object."""
502 501
503 502 # Flush the source cache because inspect can return out-of-date source
504 503 linecache.checkcache()
505 504 try:
506 505 src = getsource(obj, oname=oname)
507 506 except Exception:
508 507 src = None
509 508
510 509 if src is None:
511 510 self.noinfo('source', oname)
512 511 else:
513 512 page.page(self.format(src))
514 513
515 514 def pfile(self, obj, oname=''):
516 515 """Show the whole file where an object was defined."""
517 516
518 517 lineno = find_source_lines(obj)
519 518 if lineno is None:
520 519 self.noinfo('file', oname)
521 520 return
522 521
523 522 ofile = find_file(obj)
524 523 # run contents of file through pager starting at line where the object
525 524 # is defined, as long as the file isn't binary and is actually on the
526 525 # filesystem.
527 526 if ofile.endswith(('.so', '.dll', '.pyd')):
528 527 print('File %r is binary, not printing.' % ofile)
529 528 elif not os.path.isfile(ofile):
530 529 print('File %r does not exist, not printing.' % ofile)
531 530 else:
532 531 # Print only text files, not extension binaries. Note that
533 532 # getsourcelines returns lineno with 1-offset and page() uses
534 533 # 0-offset, so we must adjust.
535 534 page.page(self.format(openpy.read_py_file(ofile, skip_encoding_cookie=False)), lineno - 1)
536 535
537 536 def _format_fields(self, fields, title_width=0):
538 537 """Formats a list of fields for display.
539 538
540 539 Parameters
541 540 ----------
542 541 fields : list
543 542 A list of 2-tuples: (field_title, field_content)
544 543 title_width : int
545 544 How many characters to pad titles to. Default to longest title.
546 545 """
547 546 out = []
548 547 header = self.__head
549 548 if title_width == 0:
550 549 title_width = max(len(title) + 2 for title, _ in fields)
551 550 for title, content in fields:
552 551 if len(content.splitlines()) > 1:
553 552 title = header(title + ":") + "\n"
554 553 else:
555 554 title = header((title+":").ljust(title_width))
556 555 out.append(cast_unicode(title) + cast_unicode(content))
557 556 return "\n".join(out)
558 557
559 558 def _format_info(self, obj, oname='', formatter=None, info=None, detail_level=0):
560 559 """Format an info dict as text"""
561 560 info = self.info(obj, oname=oname, formatter=formatter,
562 561 info=info, detail_level=detail_level)
563 562 displayfields = []
564 563 def add_fields(fields):
565 564 for title, key in fields:
566 565 field = info[key]
567 566 if field is not None:
568 567 displayfields.append((title, field.rstrip()))
569 568
570 569 if info['isalias']:
571 570 add_fields([('Repr', "string_form")])
572 571
573 572 elif info['ismagic']:
574 573 if detail_level > 0 and info['source'] is not None:
575 574 add_fields([("Source", "source")])
576 575 else:
577 576 add_fields([("Docstring", "docstring")])
578 577
579 578 add_fields([("File", "file"),
580 579 ])
581 580
582 581 elif info['isclass'] or is_simple_callable(obj):
583 582 # Functions, methods, classes
584 583 add_fields([("Signature", "definition"),
585 584 ("Init signature", "init_definition"),
586 585 ])
587 586 if detail_level > 0 and info['source'] is not None:
588 587 add_fields([("Source", "source")])
589 588 else:
590 589 add_fields([("Docstring", "docstring"),
591 590 ("Init docstring", "init_docstring"),
592 591 ])
593 592
594 593 add_fields([('File', 'file'),
595 594 ('Type', 'type_name'),
596 595 ])
597 596
598 597 else:
599 598 # General Python objects
600 599 add_fields([("Type", "type_name")])
601 600
602 601 # Base class for old-style instances
603 602 if (not py3compat.PY3) and isinstance(obj, types.InstanceType) and info['base_class']:
604 603 displayfields.append(("Base Class", info['base_class'].rstrip()))
605 604
606 605 add_fields([("String form", "string_form")])
607 606
608 607 # Namespace
609 608 if info['namespace'] != 'Interactive':
610 609 displayfields.append(("Namespace", info['namespace'].rstrip()))
611 610
612 611 add_fields([("Length", "length"),
613 612 ("File", "file"),
614 613 ("Signature", "definition"),
615 614 ])
616 615
617 616 # Source or docstring, depending on detail level and whether
618 617 # source found.
619 618 if detail_level > 0 and info['source'] is not None:
620 619 displayfields.append(("Source",
621 620 self.format(cast_unicode(info['source']))))
622 621 elif info['docstring'] is not None:
623 622 displayfields.append(("Docstring", info["docstring"]))
624 623
625 624 add_fields([("Class docstring", "class_docstring"),
626 625 ("Init docstring", "init_docstring"),
627 626 ("Call signature", "call_def"),
628 627 ("Call docstring", "call_docstring")])
629 628
630 629 if displayfields:
631 630 return self._format_fields(displayfields)
632 631 else:
633 632 return u''
634 633
635 634 def pinfo(self, obj, oname='', formatter=None, info=None, detail_level=0):
636 635 """Show detailed information about an object.
637 636
638 637 Optional arguments:
639 638
640 639 - oname: name of the variable pointing to the object.
641 640
642 641 - formatter: special formatter for docstrings (see pdoc)
643 642
644 643 - info: a structure with some information fields which may have been
645 644 precomputed already.
646 645
647 646 - detail_level: if set to 1, more information is given.
648 647 """
649 648 text = self._format_info(obj, oname, formatter, info, detail_level)
650 649 if text:
651 650 page.page(text)
652 651
653 652 def info(self, obj, oname='', formatter=None, info=None, detail_level=0):
654 653 """Compute a dict with detailed information about an object.
655 654
656 655 Optional arguments:
657 656
658 657 - oname: name of the variable pointing to the object.
659 658
660 659 - formatter: special formatter for docstrings (see pdoc)
661 660
662 661 - info: a structure with some information fields which may have been
663 662 precomputed already.
664 663
665 664 - detail_level: if set to 1, more information is given.
666 665 """
667 666
668 667 obj_type = type(obj)
669 668
670 669 if info is None:
671 670 ismagic = 0
672 671 isalias = 0
673 672 ospace = ''
674 673 else:
675 674 ismagic = info.ismagic
676 675 isalias = info.isalias
677 676 ospace = info.namespace
678 677
679 678 # Get docstring, special-casing aliases:
680 679 if isalias:
681 680 if not callable(obj):
682 681 try:
683 682 ds = "Alias to the system command:\n %s" % obj[1]
684 683 except:
685 684 ds = "Alias: " + str(obj)
686 685 else:
687 686 ds = "Alias to " + str(obj)
688 687 if obj.__doc__:
689 688 ds += "\nDocstring:\n" + obj.__doc__
690 689 else:
691 690 ds = getdoc(obj)
692 691 if ds is None:
693 692 ds = '<no docstring>'
694 693 if formatter is not None:
695 694 ds = formatter(ds)
696 695
697 696 # store output in a dict, we initialize it here and fill it as we go
698 697 out = dict(name=oname, found=True, isalias=isalias, ismagic=ismagic)
699 698
700 699 string_max = 200 # max size of strings to show (snipped if longer)
701 700 shalf = int((string_max -5)/2)
702 701
703 702 if ismagic:
704 703 obj_type_name = 'Magic function'
705 704 elif isalias:
706 705 obj_type_name = 'System alias'
707 706 else:
708 707 obj_type_name = obj_type.__name__
709 708 out['type_name'] = obj_type_name
710 709
711 710 try:
712 711 bclass = obj.__class__
713 712 out['base_class'] = str(bclass)
714 713 except: pass
715 714
716 715 # String form, but snip if too long in ? form (full in ??)
717 716 if detail_level >= self.str_detail_level:
718 717 try:
719 718 ostr = str(obj)
720 719 str_head = 'string_form'
721 720 if not detail_level and len(ostr)>string_max:
722 721 ostr = ostr[:shalf] + ' <...> ' + ostr[-shalf:]
723 722 ostr = ("\n" + " " * len(str_head.expandtabs())).\
724 723 join(q.strip() for q in ostr.split("\n"))
725 724 out[str_head] = ostr
726 725 except:
727 726 pass
728 727
729 728 if ospace:
730 729 out['namespace'] = ospace
731 730
732 731 # Length (for strings and lists)
733 732 try:
734 733 out['length'] = str(len(obj))
735 734 except: pass
736 735
737 736 # Filename where object was defined
738 737 binary_file = False
739 738 fname = find_file(obj)
740 739 if fname is None:
741 740 # if anything goes wrong, we don't want to show source, so it's as
742 741 # if the file was binary
743 742 binary_file = True
744 743 else:
745 744 if fname.endswith(('.so', '.dll', '.pyd')):
746 745 binary_file = True
747 746 elif fname.endswith('<string>'):
748 747 fname = 'Dynamically generated function. No source code available.'
749 748 out['file'] = compress_user(fname)
750 749
751 750 # Original source code for a callable, class or property.
752 751 if detail_level:
753 752 # Flush the source cache because inspect can return out-of-date
754 753 # source
755 754 linecache.checkcache()
756 755 try:
757 756 if isinstance(obj, property) or not binary_file:
758 757 src = getsource(obj, oname)
759 758 if src is not None:
760 759 src = src.rstrip()
761 760 out['source'] = src
762 761
763 762 except Exception:
764 763 pass
765 764
766 765 # Add docstring only if no source is to be shown (avoid repetitions).
767 766 if ds and out.get('source', None) is None:
768 767 out['docstring'] = ds
769 768
770 769 # Constructor docstring for classes
771 770 if inspect.isclass(obj):
772 771 out['isclass'] = True
773 772 # reconstruct the function definition and print it:
774 773 try:
775 774 obj_init = obj.__init__
776 775 except AttributeError:
777 776 init_def = init_ds = None
778 777 else:
779 778 init_def = self._getdef(obj_init,oname)
780 779 init_ds = getdoc(obj_init)
781 780 # Skip Python's auto-generated docstrings
782 781 if init_ds == _object_init_docstring:
783 782 init_ds = None
784 783
785 784 if init_def or init_ds:
786 785 if init_def:
787 786 out['init_definition'] = self.format(init_def)
788 787 if init_ds:
789 788 out['init_docstring'] = init_ds
790 789
791 790 # and class docstring for instances:
792 791 else:
793 792 # reconstruct the function definition and print it:
794 793 defln = self._getdef(obj, oname)
795 794 if defln:
796 795 out['definition'] = self.format(defln)
797 796
798 797 # First, check whether the instance docstring is identical to the
799 798 # class one, and print it separately if they don't coincide. In
800 799 # most cases they will, but it's nice to print all the info for
801 800 # objects which use instance-customized docstrings.
802 801 if ds:
803 802 try:
804 803 cls = getattr(obj,'__class__')
805 804 except:
806 805 class_ds = None
807 806 else:
808 807 class_ds = getdoc(cls)
809 808 # Skip Python's auto-generated docstrings
810 809 if class_ds in _builtin_type_docstrings:
811 810 class_ds = None
812 811 if class_ds and ds != class_ds:
813 812 out['class_docstring'] = class_ds
814 813
815 814 # Next, try to show constructor docstrings
816 815 try:
817 816 init_ds = getdoc(obj.__init__)
818 817 # Skip Python's auto-generated docstrings
819 818 if init_ds == _object_init_docstring:
820 819 init_ds = None
821 820 except AttributeError:
822 821 init_ds = None
823 822 if init_ds:
824 823 out['init_docstring'] = init_ds
825 824
826 825 # Call form docstring for callable instances
827 826 if safe_hasattr(obj, '__call__') and not is_simple_callable(obj):
828 827 call_def = self._getdef(obj.__call__, oname)
829 828 if call_def:
830 829 call_def = self.format(call_def)
831 830 # it may never be the case that call def and definition differ,
832 831 # but don't include the same signature twice
833 832 if call_def != out.get('definition'):
834 833 out['call_def'] = call_def
835 834 call_ds = getdoc(obj.__call__)
836 835 # Skip Python's auto-generated docstrings
837 836 if call_ds == _func_call_docstring:
838 837 call_ds = None
839 838 if call_ds:
840 839 out['call_docstring'] = call_ds
841 840
842 841 # Compute the object's argspec as a callable. The key is to decide
843 842 # whether to pull it from the object itself, from its __init__ or
844 843 # from its __call__ method.
845 844
846 845 if inspect.isclass(obj):
847 846 # Old-style classes need not have an __init__
848 847 callable_obj = getattr(obj, "__init__", None)
849 848 elif callable(obj):
850 849 callable_obj = obj
851 850 else:
852 851 callable_obj = None
853 852
854 853 if callable_obj:
855 854 try:
856 855 argspec = getargspec(callable_obj)
857 856 except (TypeError, AttributeError):
858 857 # For extensions/builtins we can't retrieve the argspec
859 858 pass
860 859 else:
861 860 # named tuples' _asdict() method returns an OrderedDict, but we
862 861 # we want a normal
863 862 out['argspec'] = argspec_dict = dict(argspec._asdict())
864 863 # We called this varkw before argspec became a named tuple.
865 864 # With getfullargspec it's also called varkw.
866 865 if 'varkw' not in argspec_dict:
867 866 argspec_dict['varkw'] = argspec_dict.pop('keywords')
868 867
869 868 return object_info(**out)
870 869
871 870 def psearch(self,pattern,ns_table,ns_search=[],
872 871 ignore_case=False,show_all=False):
873 872 """Search namespaces with wildcards for objects.
874 873
875 874 Arguments:
876 875
877 876 - pattern: string containing shell-like wildcards to use in namespace
878 877 searches and optionally a type specification to narrow the search to
879 878 objects of that type.
880 879
881 880 - ns_table: dict of name->namespaces for search.
882 881
883 882 Optional arguments:
884 883
885 884 - ns_search: list of namespace names to include in search.
886 885
887 886 - ignore_case(False): make the search case-insensitive.
888 887
889 888 - show_all(False): show all names, including those starting with
890 889 underscores.
891 890 """
892 891 #print 'ps pattern:<%r>' % pattern # dbg
893 892
894 893 # defaults
895 894 type_pattern = 'all'
896 895 filter = ''
897 896
898 897 cmds = pattern.split()
899 898 len_cmds = len(cmds)
900 899 if len_cmds == 1:
901 900 # Only filter pattern given
902 901 filter = cmds[0]
903 902 elif len_cmds == 2:
904 903 # Both filter and type specified
905 904 filter,type_pattern = cmds
906 905 else:
907 906 raise ValueError('invalid argument string for psearch: <%s>' %
908 907 pattern)
909 908
910 909 # filter search namespaces
911 910 for name in ns_search:
912 911 if name not in ns_table:
913 912 raise ValueError('invalid namespace <%s>. Valid names: %s' %
914 913 (name,ns_table.keys()))
915 914
916 915 #print 'type_pattern:',type_pattern # dbg
917 916 search_result, namespaces_seen = set(), set()
918 917 for ns_name in ns_search:
919 918 ns = ns_table[ns_name]
920 919 # Normally, locals and globals are the same, so we just check one.
921 920 if id(ns) in namespaces_seen:
922 921 continue
923 922 namespaces_seen.add(id(ns))
924 923 tmp_res = list_namespace(ns, type_pattern, filter,
925 924 ignore_case=ignore_case, show_all=show_all)
926 925 search_result.update(tmp_res)
927 926
928 927 page.page('\n'.join(sorted(search_result)))
@@ -1,384 +1,386 b''
1 1 """Tests for the object inspection functionality.
2 2 """
3 3 #-----------------------------------------------------------------------------
4 4 # Copyright (C) 2010-2011 The IPython Development Team.
5 5 #
6 6 # Distributed under the terms of the BSD License.
7 7 #
8 8 # The full license is in the file COPYING.txt, distributed with this software.
9 9 #-----------------------------------------------------------------------------
10 10
11 11 #-----------------------------------------------------------------------------
12 12 # Imports
13 13 #-----------------------------------------------------------------------------
14 14 from __future__ import print_function
15 15
16 16 # Stdlib imports
17 17 import os
18 18 import re
19 19 import sys
20 20
21 21 # Third-party imports
22 22 import nose.tools as nt
23 23
24 24 # Our own imports
25 25 from .. import oinspect
26 26 from IPython.core.magic import (Magics, magics_class, line_magic,
27 27 cell_magic, line_cell_magic,
28 28 register_line_magic, register_cell_magic,
29 29 register_line_cell_magic)
30 30 from decorator import decorator
31 31 from IPython.testing.decorators import skipif
32 32 from IPython.testing.tools import AssertPrints
33 33 from IPython.utils.path import compress_user
34 34 from IPython.utils import py3compat
35 35
36 36
37 37 #-----------------------------------------------------------------------------
38 38 # Globals and constants
39 39 #-----------------------------------------------------------------------------
40 40
41 41 inspector = oinspect.Inspector()
42 42 ip = get_ipython()
43 43
44 44 #-----------------------------------------------------------------------------
45 45 # Local utilities
46 46 #-----------------------------------------------------------------------------
47 47
48 48 # WARNING: since this test checks the line number where a function is
49 49 # defined, if any code is inserted above, the following line will need to be
50 50 # updated. Do NOT insert any whitespace between the next line and the function
51 51 # definition below.
52 52 THIS_LINE_NUMBER = 52 # Put here the actual number of this line
53 53 def test_find_source_lines():
54 54 nt.assert_equal(oinspect.find_source_lines(test_find_source_lines),
55 55 THIS_LINE_NUMBER+1)
56 56
57 57
58 58 # A couple of utilities to ensure these tests work the same from a source or a
59 59 # binary install
60 60 def pyfile(fname):
61 61 return os.path.normcase(re.sub('.py[co]$', '.py', fname))
62 62
63 63
64 64 def match_pyfiles(f1, f2):
65 65 nt.assert_equal(pyfile(f1), pyfile(f2))
66 66
67 67
68 68 def test_find_file():
69 69 match_pyfiles(oinspect.find_file(test_find_file), os.path.abspath(__file__))
70 70
71 71
72 72 def test_find_file_decorated1():
73 73
74 74 @decorator
75 75 def noop1(f):
76 76 def wrapper():
77 77 return f(*a, **kw)
78 78 return wrapper
79 79
80 80 @noop1
81 81 def f(x):
82 82 "My docstring"
83 83
84 84 match_pyfiles(oinspect.find_file(f), os.path.abspath(__file__))
85 85 nt.assert_equal(f.__doc__, "My docstring")
86 86
87 87
88 88 def test_find_file_decorated2():
89 89
90 90 @decorator
91 91 def noop2(f, *a, **kw):
92 92 return f(*a, **kw)
93 93
94 94 @noop2
95 @noop2
96 @noop2
95 97 def f(x):
96 98 "My docstring 2"
97 99
98 100 match_pyfiles(oinspect.find_file(f), os.path.abspath(__file__))
99 101 nt.assert_equal(f.__doc__, "My docstring 2")
100 102
101 103
102 104 def test_find_file_magic():
103 105 run = ip.find_line_magic('run')
104 106 nt.assert_not_equal(oinspect.find_file(run), None)
105 107
106 108
107 109 # A few generic objects we can then inspect in the tests below
108 110
109 111 class Call(object):
110 112 """This is the class docstring."""
111 113
112 114 def __init__(self, x, y=1):
113 115 """This is the constructor docstring."""
114 116
115 117 def __call__(self, *a, **kw):
116 118 """This is the call docstring."""
117 119
118 120 def method(self, x, z=2):
119 121 """Some method's docstring"""
120 122
121 123 class SimpleClass(object):
122 124 def method(self, x, z=2):
123 125 """Some method's docstring"""
124 126
125 127
126 128 class OldStyle:
127 129 """An old-style class for testing."""
128 130 pass
129 131
130 132
131 133 def f(x, y=2, *a, **kw):
132 134 """A simple function."""
133 135
134 136
135 137 def g(y, z=3, *a, **kw):
136 138 pass # no docstring
137 139
138 140
139 141 @register_line_magic
140 142 def lmagic(line):
141 143 "A line magic"
142 144
143 145
144 146 @register_cell_magic
145 147 def cmagic(line, cell):
146 148 "A cell magic"
147 149
148 150
149 151 @register_line_cell_magic
150 152 def lcmagic(line, cell=None):
151 153 "A line/cell magic"
152 154
153 155
154 156 @magics_class
155 157 class SimpleMagics(Magics):
156 158 @line_magic
157 159 def Clmagic(self, cline):
158 160 "A class-based line magic"
159 161
160 162 @cell_magic
161 163 def Ccmagic(self, cline, ccell):
162 164 "A class-based cell magic"
163 165
164 166 @line_cell_magic
165 167 def Clcmagic(self, cline, ccell=None):
166 168 "A class-based line/cell magic"
167 169
168 170
169 171 class Awkward(object):
170 172 def __getattr__(self, name):
171 173 raise Exception(name)
172 174
173 175
174 176 def check_calltip(obj, name, call, docstring):
175 177 """Generic check pattern all calltip tests will use"""
176 178 info = inspector.info(obj, name)
177 179 call_line, ds = oinspect.call_tip(info)
178 180 nt.assert_equal(call_line, call)
179 181 nt.assert_equal(ds, docstring)
180 182
181 183 #-----------------------------------------------------------------------------
182 184 # Tests
183 185 #-----------------------------------------------------------------------------
184 186
185 187 def test_calltip_class():
186 188 check_calltip(Call, 'Call', 'Call(x, y=1)', Call.__init__.__doc__)
187 189
188 190
189 191 def test_calltip_instance():
190 192 c = Call(1)
191 193 check_calltip(c, 'c', 'c(*a, **kw)', c.__call__.__doc__)
192 194
193 195
194 196 def test_calltip_method():
195 197 c = Call(1)
196 198 check_calltip(c.method, 'c.method', 'c.method(x, z=2)', c.method.__doc__)
197 199
198 200
199 201 def test_calltip_function():
200 202 check_calltip(f, 'f', 'f(x, y=2, *a, **kw)', f.__doc__)
201 203
202 204
203 205 def test_calltip_function2():
204 206 check_calltip(g, 'g', 'g(y, z=3, *a, **kw)', '<no docstring>')
205 207
206 208
207 209 @skipif(sys.version_info >= (3, 5))
208 210 def test_calltip_builtin():
209 211 check_calltip(sum, 'sum', None, sum.__doc__)
210 212
211 213
212 214 def test_calltip_line_magic():
213 215 check_calltip(lmagic, 'lmagic', 'lmagic(line)', "A line magic")
214 216
215 217
216 218 def test_calltip_cell_magic():
217 219 check_calltip(cmagic, 'cmagic', 'cmagic(line, cell)', "A cell magic")
218 220
219 221
220 222 def test_calltip_line_cell_magic():
221 223 check_calltip(lcmagic, 'lcmagic', 'lcmagic(line, cell=None)',
222 224 "A line/cell magic")
223 225
224 226
225 227 def test_class_magics():
226 228 cm = SimpleMagics(ip)
227 229 ip.register_magics(cm)
228 230 check_calltip(cm.Clmagic, 'Clmagic', 'Clmagic(cline)',
229 231 "A class-based line magic")
230 232 check_calltip(cm.Ccmagic, 'Ccmagic', 'Ccmagic(cline, ccell)',
231 233 "A class-based cell magic")
232 234 check_calltip(cm.Clcmagic, 'Clcmagic', 'Clcmagic(cline, ccell=None)',
233 235 "A class-based line/cell magic")
234 236
235 237
236 238 def test_info():
237 239 "Check that Inspector.info fills out various fields as expected."
238 240 i = inspector.info(Call, oname='Call')
239 241 nt.assert_equal(i['type_name'], 'type')
240 242 expted_class = str(type(type)) # <class 'type'> (Python 3) or <type 'type'>
241 243 nt.assert_equal(i['base_class'], expted_class)
242 244 nt.assert_equal(i['string_form'], "<class 'IPython.core.tests.test_oinspect.Call'>")
243 245 fname = __file__
244 246 if fname.endswith(".pyc"):
245 247 fname = fname[:-1]
246 248 # case-insensitive comparison needed on some filesystems
247 249 # e.g. Windows:
248 250 nt.assert_equal(i['file'].lower(), compress_user(fname).lower())
249 251 nt.assert_equal(i['definition'], None)
250 252 nt.assert_equal(i['docstring'], Call.__doc__)
251 253 nt.assert_equal(i['source'], None)
252 254 nt.assert_true(i['isclass'])
253 255 nt.assert_equal(i['init_definition'], "Call(self, x, y=1)\n")
254 256 nt.assert_equal(i['init_docstring'], Call.__init__.__doc__)
255 257
256 258 i = inspector.info(Call, detail_level=1)
257 259 nt.assert_not_equal(i['source'], None)
258 260 nt.assert_equal(i['docstring'], None)
259 261
260 262 c = Call(1)
261 263 c.__doc__ = "Modified instance docstring"
262 264 i = inspector.info(c)
263 265 nt.assert_equal(i['type_name'], 'Call')
264 266 nt.assert_equal(i['docstring'], "Modified instance docstring")
265 267 nt.assert_equal(i['class_docstring'], Call.__doc__)
266 268 nt.assert_equal(i['init_docstring'], Call.__init__.__doc__)
267 269 nt.assert_equal(i['call_docstring'], Call.__call__.__doc__)
268 270
269 271 # Test old-style classes, which for example may not have an __init__ method.
270 272 if not py3compat.PY3:
271 273 i = inspector.info(OldStyle)
272 274 nt.assert_equal(i['type_name'], 'classobj')
273 275
274 276 i = inspector.info(OldStyle())
275 277 nt.assert_equal(i['type_name'], 'instance')
276 278 nt.assert_equal(i['docstring'], OldStyle.__doc__)
277 279
278 280 def test_info_awkward():
279 281 # Just test that this doesn't throw an error.
280 282 i = inspector.info(Awkward())
281 283
282 284 def test_calldef_none():
283 285 # We should ignore __call__ for all of these.
284 286 for obj in [f, SimpleClass().method, any, str.upper]:
285 287 print(obj)
286 288 i = inspector.info(obj)
287 289 nt.assert_is(i['call_def'], None)
288 290
289 291 if py3compat.PY3:
290 292 exec("def f_kwarg(pos, *, kwonly): pass")
291 293
292 294 @skipif(not py3compat.PY3)
293 295 def test_definition_kwonlyargs():
294 296 i = inspector.info(f_kwarg, oname='f_kwarg') # analysis:ignore
295 297 nt.assert_equal(i['definition'], "f_kwarg(pos, *, kwonly)\n")
296 298
297 299 def test_getdoc():
298 300 class A(object):
299 301 """standard docstring"""
300 302 pass
301 303
302 304 class B(object):
303 305 """standard docstring"""
304 306 def getdoc(self):
305 307 return "custom docstring"
306 308
307 309 class C(object):
308 310 """standard docstring"""
309 311 def getdoc(self):
310 312 return None
311 313
312 314 a = A()
313 315 b = B()
314 316 c = C()
315 317
316 318 nt.assert_equal(oinspect.getdoc(a), "standard docstring")
317 319 nt.assert_equal(oinspect.getdoc(b), "custom docstring")
318 320 nt.assert_equal(oinspect.getdoc(c), "standard docstring")
319 321
320 322
321 323 def test_empty_property_has_no_source():
322 324 i = inspector.info(property(), detail_level=1)
323 325 nt.assert_is(i['source'], None)
324 326
325 327
326 328 def test_property_sources():
327 329 import zlib
328 330
329 331 class A(object):
330 332 @property
331 333 def foo(self):
332 334 return 'bar'
333 335
334 336 foo = foo.setter(lambda self, v: setattr(self, 'bar', v))
335 337
336 338 id = property(id)
337 339 compress = property(zlib.compress)
338 340
339 341 i = inspector.info(A.foo, detail_level=1)
340 342 nt.assert_in('def foo(self):', i['source'])
341 343 nt.assert_in('lambda self, v:', i['source'])
342 344
343 345 i = inspector.info(A.id, detail_level=1)
344 346 nt.assert_in('fget = <function id>', i['source'])
345 347
346 348 i = inspector.info(A.compress, detail_level=1)
347 349 nt.assert_in('fget = <function zlib.compress>', i['source'])
348 350
349 351
350 352 def test_property_docstring_is_in_info_for_detail_level_0():
351 353 class A(object):
352 354 @property
353 355 def foobar():
354 356 """This is `foobar` property."""
355 357 pass
356 358
357 359 ip.user_ns['a_obj'] = A()
358 360 nt.assert_equals(
359 361 'This is `foobar` property.',
360 362 ip.object_inspect('a_obj.foobar', detail_level=0)['docstring'])
361 363
362 364 ip.user_ns['a_cls'] = A
363 365 nt.assert_equals(
364 366 'This is `foobar` property.',
365 367 ip.object_inspect('a_cls.foobar', detail_level=0)['docstring'])
366 368
367 369
368 370 def test_pdef():
369 371 # See gh-1914
370 372 def foo(): pass
371 373 inspector.pdef(foo, 'foo')
372 374
373 375 def test_pinfo_nonascii():
374 376 # See gh-1177
375 377 from . import nonascii2
376 378 ip.user_ns['nonascii2'] = nonascii2
377 379 ip._inspect('pinfo', 'nonascii2', detail_level=1)
378 380
379 381 def test_pinfo_magic():
380 382 with AssertPrints('Docstring:'):
381 383 ip._inspect('pinfo', 'lsmagic', detail_level=0)
382 384
383 385 with AssertPrints('Source:'):
384 386 ip._inspect('pinfo', 'lsmagic', detail_level=1)
General Comments 0
You need to be logged in to leave comments. Login now