##// END OF EJS Templates
Backport PR #10073: include docstring in detail_level=1 if no source is found...
Thomas Kluyver -
Show More
@@ -1,1011 +1,1011 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 body = body.strip('\n')
607 607 delim = '\n' if '\n' in body else ' '
608 608 text += self.__head(head+':') + (_len - len(head))*' ' +delim + body +'\n'
609 609
610 610 bundle['text/plain'] = text
611 611 return bundle
612 612
613 613 def _get_info(self, obj, oname='', formatter=None, info=None, detail_level=0):
614 614 """Retrieve an info dict and format it."""
615 615
616 616 info = self._info(obj, oname=oname, info=info, detail_level=detail_level)
617 617
618 618 _mime = {
619 619 'text/plain': [],
620 620 'text/html': '',
621 621 }
622 622
623 623 def append_field(bundle, title, key, formatter=None):
624 624 field = info[key]
625 625 if field is not None:
626 626 formatted_field = self._mime_format(field, formatter)
627 627 bundle['text/plain'].append((title, formatted_field['text/plain']))
628 628 bundle['text/html'] += '<h1>' + title + '</h1>\n' + formatted_field['text/html'] + '\n'
629 629
630 630 def code_formatter(text):
631 631 return {
632 632 'text/plain': self.format(text),
633 633 'text/html': pylight(text)
634 634 }
635 635
636 636 if info['isalias']:
637 637 append_field(_mime, 'Repr', 'string_form')
638 638
639 639 elif info['ismagic']:
640 640 if detail_level > 0:
641 641 append_field(_mime, 'Source', 'source', code_formatter)
642 642 else:
643 643 append_field(_mime, 'Docstring', 'docstring', formatter)
644 644 append_field(_mime, 'File', 'file')
645 645
646 646 elif info['isclass'] or is_simple_callable(obj):
647 647 # Functions, methods, classes
648 648 append_field(_mime, 'Signature', 'definition', code_formatter)
649 649 append_field(_mime, 'Init signature', 'init_definition', code_formatter)
650 if detail_level > 0:
650 if detail_level > 0 and info['source']:
651 651 append_field(_mime, 'Source', 'source', code_formatter)
652 652 else:
653 653 append_field(_mime, 'Docstring', 'docstring', formatter)
654 654 append_field(_mime, 'Init docstring', 'init_docstring', formatter)
655 655
656 656 append_field(_mime, 'File', 'file')
657 657 append_field(_mime, 'Type', 'type_name')
658 658
659 659 else:
660 660 # General Python objects
661 661 append_field(_mime, 'Signature', 'definition', code_formatter)
662 662 append_field(_mime, 'Call signature', 'call_def', code_formatter)
663 663
664 664 append_field(_mime, 'Type', 'type_name')
665 665
666 666 # Base class for old-style instances
667 667 if (not py3compat.PY3) and isinstance(obj, types.InstanceType) and info['base_class']:
668 668 append_field(_mime, 'Base Class', 'base_class')
669 669
670 670 append_field(_mime, 'String form', 'string_form')
671 671
672 672 # Namespace
673 673 if info['namespace'] != 'Interactive':
674 674 append_field(_mime, 'Namespace', 'namespace')
675 675
676 676 append_field(_mime, 'Length', 'length')
677 677 append_field(_mime, 'File', 'file')
678 678
679 679 # Source or docstring, depending on detail level and whether
680 680 # source found.
681 681 if detail_level > 0:
682 682 append_field(_mime, 'Source', 'source', code_formatter)
683 683 else:
684 684 append_field(_mime, 'Docstring', 'docstring', formatter)
685 685
686 686 append_field(_mime, 'Class docstring', 'class_docstring', formatter)
687 687 append_field(_mime, 'Init docstring', 'init_docstring', formatter)
688 688 append_field(_mime, 'Call docstring', 'call_docstring', formatter)
689 689
690 690
691 691 return self.format_mime(_mime)
692 692
693 693 def pinfo(self, obj, oname='', formatter=None, info=None, detail_level=0, enable_html_pager=True):
694 694 """Show detailed information about an object.
695 695
696 696 Optional arguments:
697 697
698 698 - oname: name of the variable pointing to the object.
699 699
700 700 - formatter: callable (optional)
701 701 A special formatter for docstrings.
702 702
703 703 The formatter is a callable that takes a string as an input
704 704 and returns either a formatted string or a mime type bundle
705 705 in the form of a dictionnary.
706 706
707 707 Although the support of custom formatter returning a string
708 708 instead of a mime type bundle is deprecated.
709 709
710 710 - info: a structure with some information fields which may have been
711 711 precomputed already.
712 712
713 713 - detail_level: if set to 1, more information is given.
714 714 """
715 715 info = self._get_info(obj, oname, formatter, info, detail_level)
716 716 if not enable_html_pager:
717 717 del info['text/html']
718 718 page.page(info)
719 719
720 720 def info(self, obj, oname='', formatter=None, info=None, detail_level=0):
721 721 """DEPRECATED. Compute a dict with detailed information about an object.
722 722 """
723 723 if formatter is not None:
724 724 warnings.warn('The `formatter` keyword argument to `Inspector.info`'
725 725 'is deprecated as of IPython 5.0 and will have no effects.',
726 726 DeprecationWarning, stacklevel=2)
727 727 return self._info(obj, oname=oname, info=info, detail_level=detail_level)
728 728
729 729 def _info(self, obj, oname='', info=None, detail_level=0):
730 730 """Compute a dict with detailed information about an object.
731 731
732 732 Optional arguments:
733 733
734 734 - oname: name of the variable pointing to the object.
735 735
736 736 - info: a structure with some information fields which may have been
737 737 precomputed already.
738 738
739 739 - detail_level: if set to 1, more information is given.
740 740 """
741 741
742 742 obj_type = type(obj)
743 743
744 744 if info is None:
745 745 ismagic = 0
746 746 isalias = 0
747 747 ospace = ''
748 748 else:
749 749 ismagic = info.ismagic
750 750 isalias = info.isalias
751 751 ospace = info.namespace
752 752
753 753 # Get docstring, special-casing aliases:
754 754 if isalias:
755 755 if not callable(obj):
756 756 try:
757 757 ds = "Alias to the system command:\n %s" % obj[1]
758 758 except:
759 759 ds = "Alias: " + str(obj)
760 760 else:
761 761 ds = "Alias to " + str(obj)
762 762 if obj.__doc__:
763 763 ds += "\nDocstring:\n" + obj.__doc__
764 764 else:
765 765 ds = getdoc(obj)
766 766 if ds is None:
767 767 ds = '<no docstring>'
768 768
769 769 # store output in a dict, we initialize it here and fill it as we go
770 770 out = dict(name=oname, found=True, isalias=isalias, ismagic=ismagic)
771 771
772 772 string_max = 200 # max size of strings to show (snipped if longer)
773 773 shalf = int((string_max - 5) / 2)
774 774
775 775 if ismagic:
776 776 obj_type_name = 'Magic function'
777 777 elif isalias:
778 778 obj_type_name = 'System alias'
779 779 else:
780 780 obj_type_name = obj_type.__name__
781 781 out['type_name'] = obj_type_name
782 782
783 783 try:
784 784 bclass = obj.__class__
785 785 out['base_class'] = str(bclass)
786 786 except: pass
787 787
788 788 # String form, but snip if too long in ? form (full in ??)
789 789 if detail_level >= self.str_detail_level:
790 790 try:
791 791 ostr = str(obj)
792 792 str_head = 'string_form'
793 793 if not detail_level and len(ostr)>string_max:
794 794 ostr = ostr[:shalf] + ' <...> ' + ostr[-shalf:]
795 795 ostr = ("\n" + " " * len(str_head.expandtabs())).\
796 796 join(q.strip() for q in ostr.split("\n"))
797 797 out[str_head] = ostr
798 798 except:
799 799 pass
800 800
801 801 if ospace:
802 802 out['namespace'] = ospace
803 803
804 804 # Length (for strings and lists)
805 805 try:
806 806 out['length'] = str(len(obj))
807 807 except: pass
808 808
809 809 # Filename where object was defined
810 810 binary_file = False
811 811 fname = find_file(obj)
812 812 if fname is None:
813 813 # if anything goes wrong, we don't want to show source, so it's as
814 814 # if the file was binary
815 815 binary_file = True
816 816 else:
817 817 if fname.endswith(('.so', '.dll', '.pyd')):
818 818 binary_file = True
819 819 elif fname.endswith('<string>'):
820 820 fname = 'Dynamically generated function. No source code available.'
821 821 out['file'] = compress_user(fname)
822 822
823 823 # Original source code for a callable, class or property.
824 824 if detail_level:
825 825 # Flush the source cache because inspect can return out-of-date
826 826 # source
827 827 linecache.checkcache()
828 828 try:
829 829 if isinstance(obj, property) or not binary_file:
830 830 src = getsource(obj, oname)
831 831 if src is not None:
832 832 src = src.rstrip()
833 833 out['source'] = src
834 834
835 835 except Exception:
836 836 pass
837 837
838 838 # Add docstring only if no source is to be shown (avoid repetitions).
839 839 if ds and out.get('source', None) is None:
840 840 out['docstring'] = ds
841 841
842 842 # Constructor docstring for classes
843 843 if inspect.isclass(obj):
844 844 out['isclass'] = True
845 845
846 846 # get the init signature:
847 847 try:
848 848 init_def = self._getdef(obj, oname)
849 849 except AttributeError:
850 850 init_def = None
851 851
852 852 # get the __init__ docstring
853 853 try:
854 854 obj_init = obj.__init__
855 855 except AttributeError:
856 856 init_ds = None
857 857 else:
858 858 if init_def is None:
859 859 # Get signature from init if top-level sig failed.
860 860 # Can happen for built-in types (list, etc.).
861 861 try:
862 862 init_def = self._getdef(obj_init, oname)
863 863 except AttributeError:
864 864 pass
865 865 init_ds = getdoc(obj_init)
866 866 # Skip Python's auto-generated docstrings
867 867 if init_ds == _object_init_docstring:
868 868 init_ds = None
869 869
870 870 if init_def:
871 871 out['init_definition'] = init_def
872 872
873 873 if init_ds:
874 874 out['init_docstring'] = init_ds
875 875
876 876 # and class docstring for instances:
877 877 else:
878 878 # reconstruct the function definition and print it:
879 879 defln = self._getdef(obj, oname)
880 880 if defln:
881 881 out['definition'] = defln
882 882
883 883 # First, check whether the instance docstring is identical to the
884 884 # class one, and print it separately if they don't coincide. In
885 885 # most cases they will, but it's nice to print all the info for
886 886 # objects which use instance-customized docstrings.
887 887 if ds:
888 888 try:
889 889 cls = getattr(obj,'__class__')
890 890 except:
891 891 class_ds = None
892 892 else:
893 893 class_ds = getdoc(cls)
894 894 # Skip Python's auto-generated docstrings
895 895 if class_ds in _builtin_type_docstrings:
896 896 class_ds = None
897 897 if class_ds and ds != class_ds:
898 898 out['class_docstring'] = class_ds
899 899
900 900 # Next, try to show constructor docstrings
901 901 try:
902 902 init_ds = getdoc(obj.__init__)
903 903 # Skip Python's auto-generated docstrings
904 904 if init_ds == _object_init_docstring:
905 905 init_ds = None
906 906 except AttributeError:
907 907 init_ds = None
908 908 if init_ds:
909 909 out['init_docstring'] = init_ds
910 910
911 911 # Call form docstring for callable instances
912 912 if safe_hasattr(obj, '__call__') and not is_simple_callable(obj):
913 913 call_def = self._getdef(obj.__call__, oname)
914 914 if call_def and (call_def != out.get('definition')):
915 915 # it may never be the case that call def and definition differ,
916 916 # but don't include the same signature twice
917 917 out['call_def'] = call_def
918 918 call_ds = getdoc(obj.__call__)
919 919 # Skip Python's auto-generated docstrings
920 920 if call_ds == _func_call_docstring:
921 921 call_ds = None
922 922 if call_ds:
923 923 out['call_docstring'] = call_ds
924 924
925 925 # Compute the object's argspec as a callable. The key is to decide
926 926 # whether to pull it from the object itself, from its __init__ or
927 927 # from its __call__ method.
928 928
929 929 if inspect.isclass(obj):
930 930 # Old-style classes need not have an __init__
931 931 callable_obj = getattr(obj, "__init__", None)
932 932 elif callable(obj):
933 933 callable_obj = obj
934 934 else:
935 935 callable_obj = None
936 936
937 937 if callable_obj is not None:
938 938 try:
939 939 argspec = getargspec(callable_obj)
940 940 except (TypeError, AttributeError):
941 941 # For extensions/builtins we can't retrieve the argspec
942 942 pass
943 943 else:
944 944 # named tuples' _asdict() method returns an OrderedDict, but we
945 945 # we want a normal
946 946 out['argspec'] = argspec_dict = dict(argspec._asdict())
947 947 # We called this varkw before argspec became a named tuple.
948 948 # With getfullargspec it's also called varkw.
949 949 if 'varkw' not in argspec_dict:
950 950 argspec_dict['varkw'] = argspec_dict.pop('keywords')
951 951
952 952 return object_info(**out)
953 953
954 954 def psearch(self,pattern,ns_table,ns_search=[],
955 955 ignore_case=False,show_all=False):
956 956 """Search namespaces with wildcards for objects.
957 957
958 958 Arguments:
959 959
960 960 - pattern: string containing shell-like wildcards to use in namespace
961 961 searches and optionally a type specification to narrow the search to
962 962 objects of that type.
963 963
964 964 - ns_table: dict of name->namespaces for search.
965 965
966 966 Optional arguments:
967 967
968 968 - ns_search: list of namespace names to include in search.
969 969
970 970 - ignore_case(False): make the search case-insensitive.
971 971
972 972 - show_all(False): show all names, including those starting with
973 973 underscores.
974 974 """
975 975 #print 'ps pattern:<%r>' % pattern # dbg
976 976
977 977 # defaults
978 978 type_pattern = 'all'
979 979 filter = ''
980 980
981 981 cmds = pattern.split()
982 982 len_cmds = len(cmds)
983 983 if len_cmds == 1:
984 984 # Only filter pattern given
985 985 filter = cmds[0]
986 986 elif len_cmds == 2:
987 987 # Both filter and type specified
988 988 filter,type_pattern = cmds
989 989 else:
990 990 raise ValueError('invalid argument string for psearch: <%s>' %
991 991 pattern)
992 992
993 993 # filter search namespaces
994 994 for name in ns_search:
995 995 if name not in ns_table:
996 996 raise ValueError('invalid namespace <%s>. Valid names: %s' %
997 997 (name,ns_table.keys()))
998 998
999 999 #print 'type_pattern:',type_pattern # dbg
1000 1000 search_result, namespaces_seen = set(), set()
1001 1001 for ns_name in ns_search:
1002 1002 ns = ns_table[ns_name]
1003 1003 # Normally, locals and globals are the same, so we just check one.
1004 1004 if id(ns) in namespaces_seen:
1005 1005 continue
1006 1006 namespaces_seen.add(id(ns))
1007 1007 tmp_res = list_namespace(ns, type_pattern, filter,
1008 1008 ignore_case=ignore_case, show_all=show_all)
1009 1009 search_result.update(tmp_res)
1010 1010
1011 1011 page.page('\n'.join(sorted(search_result)))
@@ -1,452 +1,475 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 from IPython.testing.tools import AssertPrints
22 from IPython.testing.tools import AssertPrints, AssertNotPrints
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 nt.assert_equals(
407 nt.assert_equal(
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 nt.assert_equals(
412 nt.assert_equal(
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 423 def test_pinfo_nonascii():
424 424 # See gh-1177
425 425 from . import nonascii2
426 426 ip.user_ns['nonascii2'] = nonascii2
427 427 ip._inspect('pinfo', 'nonascii2', detail_level=1)
428 428
429 429
430 def test_pinfo_docstring_no_source():
431 """Docstring should be included with detail_level=1 if there is no source"""
432 with AssertPrints('Docstring:'):
433 ip._inspect('pinfo', 'str.format', detail_level=0)
434 with AssertPrints('Docstring:'):
435 ip._inspect('pinfo', 'str.format', detail_level=1)
436
437
438 def test_pinfo_no_docstring_if_source():
439 """Docstring should not be included with detail_level=1 if source is found"""
440 def foo():
441 """foo has a docstring"""
442
443 ip.user_ns['foo'] = foo
444
445 with AssertPrints('Docstring:'):
446 ip._inspect('pinfo', 'foo', detail_level=0)
447 with AssertPrints('Source:'):
448 ip._inspect('pinfo', 'foo', detail_level=1)
449 with AssertNotPrints('Docstring:'):
450 ip._inspect('pinfo', 'foo', detail_level=1)
451
452
430 453 def test_pinfo_magic():
431 454 with AssertPrints('Docstring:'):
432 455 ip._inspect('pinfo', 'lsmagic', detail_level=0)
433 456
434 457 with AssertPrints('Source:'):
435 458 ip._inspect('pinfo', 'lsmagic', detail_level=1)
436 459
437 460
438 461 def test_init_colors():
439 462 # ensure colors are not present in signature info
440 463 info = inspector.info(HasSignature)
441 464 init_def = info['init_definition']
442 465 nt.assert_not_in('[0m', init_def)
443 466
444 467
445 468 def test_builtin_init():
446 469 info = inspector.info(list)
447 470 init_def = info['init_definition']
448 471 # Python < 3.4 can't get init definition from builtins,
449 472 # but still exercise the inspection in case of error-raising bugs.
450 473 if sys.version_info >= (3,4):
451 474 nt.assert_is_not_none(init_def)
452 475
General Comments 0
You need to be logged in to leave comments. Login now