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