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