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