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