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