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