Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.8/site-packages/IPython/core/oinspect.py: 19%

496 statements  

« prev     ^ index     » next       coverage.py v7.2.2, created at 2023-03-26 06:07 +0000

1# -*- coding: utf-8 -*- 

2"""Tools for inspecting Python objects. 

3 

4Uses syntax highlighting for presenting the various information elements. 

5 

6Similar in spirit to the inspect module, but all calls take a name argument to 

7reference the name under which an object is being read. 

8""" 

9 

10# Copyright (c) IPython Development Team. 

11# Distributed under the terms of the Modified BSD License. 

12 

13__all__ = ['Inspector','InspectColors'] 

14 

15# stdlib modules 

16import ast 

17import inspect 

18from inspect import signature 

19import html 

20import linecache 

21import warnings 

22import os 

23from textwrap import dedent 

24import types 

25import io as stdlib_io 

26 

27from typing import Union 

28 

29# IPython's own 

30from IPython.core import page 

31from IPython.lib.pretty import pretty 

32from IPython.testing.skipdoctest import skip_doctest 

33from IPython.utils import PyColorize 

34from IPython.utils import openpy 

35from IPython.utils.dir2 import safe_hasattr 

36from IPython.utils.path import compress_user 

37from IPython.utils.text import indent 

38from IPython.utils.wildcard import list_namespace 

39from IPython.utils.wildcard import typestr2type 

40from IPython.utils.coloransi import TermColors, ColorScheme, ColorSchemeTable 

41from IPython.utils.py3compat import cast_unicode 

42from IPython.utils.colorable import Colorable 

43from IPython.utils.decorators import undoc 

44 

45from pygments import highlight 

46from pygments.lexers import PythonLexer 

47from pygments.formatters import HtmlFormatter 

48 

49def pylight(code): 

50 return highlight(code, PythonLexer(), HtmlFormatter(noclasses=True)) 

51 

52# builtin docstrings to ignore 

53_func_call_docstring = types.FunctionType.__call__.__doc__ 

54_object_init_docstring = object.__init__.__doc__ 

55_builtin_type_docstrings = { 

56 inspect.getdoc(t) for t in (types.ModuleType, types.MethodType, 

57 types.FunctionType, property) 

58} 

59 

60_builtin_func_type = type(all) 

61_builtin_meth_type = type(str.upper) # Bound methods have the same type as builtin functions 

62#**************************************************************************** 

63# Builtin color schemes 

64 

65Colors = TermColors # just a shorthand 

66 

67InspectColors = PyColorize.ANSICodeColors 

68 

69#**************************************************************************** 

70# Auxiliary functions and objects 

71 

72# See the messaging spec for the definition of all these fields. This list 

73# effectively defines the order of display 

74info_fields = ['type_name', 'base_class', 'string_form', 'namespace', 

75 'length', 'file', 'definition', 'docstring', 'source', 

76 'init_definition', 'class_docstring', 'init_docstring', 

77 'call_def', 'call_docstring', 

78 # These won't be printed but will be used to determine how to 

79 # format the object 

80 'ismagic', 'isalias', 'isclass', 'found', 'name' 

81 ] 

82 

83 

84def object_info(**kw): 

85 """Make an object info dict with all fields present.""" 

86 infodict = {k:None for k in info_fields} 

87 infodict.update(kw) 

88 return infodict 

89 

90 

91def get_encoding(obj): 

92 """Get encoding for python source file defining obj 

93 

94 Returns None if obj is not defined in a sourcefile. 

95 """ 

96 ofile = find_file(obj) 

97 # run contents of file through pager starting at line where the object 

98 # is defined, as long as the file isn't binary and is actually on the 

99 # filesystem. 

100 if ofile is None: 

101 return None 

102 elif ofile.endswith(('.so', '.dll', '.pyd')): 

103 return None 

104 elif not os.path.isfile(ofile): 

105 return None 

106 else: 

107 # Print only text files, not extension binaries. Note that 

108 # getsourcelines returns lineno with 1-offset and page() uses 

109 # 0-offset, so we must adjust. 

110 with stdlib_io.open(ofile, 'rb') as buffer: # Tweaked to use io.open for Python 2 

111 encoding, lines = openpy.detect_encoding(buffer.readline) 

112 return encoding 

113 

114def getdoc(obj) -> Union[str,None]: 

115 """Stable wrapper around inspect.getdoc. 

116 

117 This can't crash because of attribute problems. 

118 

119 It also attempts to call a getdoc() method on the given object. This 

120 allows objects which provide their docstrings via non-standard mechanisms 

121 (like Pyro proxies) to still be inspected by ipython's ? system. 

122 """ 

123 # Allow objects to offer customized documentation via a getdoc method: 

124 try: 

125 ds = obj.getdoc() 

126 except Exception: 

127 pass 

128 else: 

129 if isinstance(ds, str): 

130 return inspect.cleandoc(ds) 

131 docstr = inspect.getdoc(obj) 

132 return docstr 

133 

134 

135def getsource(obj, oname='') -> Union[str,None]: 

136 """Wrapper around inspect.getsource. 

137 

138 This can be modified by other projects to provide customized source 

139 extraction. 

140 

141 Parameters 

142 ---------- 

143 obj : object 

144 an object whose source code we will attempt to extract 

145 oname : str 

146 (optional) a name under which the object is known 

147 

148 Returns 

149 ------- 

150 src : unicode or None 

151 

152 """ 

153 

154 if isinstance(obj, property): 

155 sources = [] 

156 for attrname in ['fget', 'fset', 'fdel']: 

157 fn = getattr(obj, attrname) 

158 if fn is not None: 

159 encoding = get_encoding(fn) 

160 oname_prefix = ('%s.' % oname) if oname else '' 

161 sources.append(''.join(('# ', oname_prefix, attrname))) 

162 if inspect.isfunction(fn): 

163 sources.append(dedent(getsource(fn))) 

164 else: 

165 # Default str/repr only prints function name, 

166 # pretty.pretty prints module name too. 

167 sources.append( 

168 '%s%s = %s\n' % (oname_prefix, attrname, pretty(fn)) 

169 ) 

170 if sources: 

171 return '\n'.join(sources) 

172 else: 

173 return None 

174 

175 else: 

176 # Get source for non-property objects. 

177 

178 obj = _get_wrapped(obj) 

179 

180 try: 

181 src = inspect.getsource(obj) 

182 except TypeError: 

183 # The object itself provided no meaningful source, try looking for 

184 # its class definition instead. 

185 try: 

186 src = inspect.getsource(obj.__class__) 

187 except (OSError, TypeError): 

188 return None 

189 except OSError: 

190 return None 

191 

192 return src 

193 

194 

195def is_simple_callable(obj): 

196 """True if obj is a function ()""" 

197 return (inspect.isfunction(obj) or inspect.ismethod(obj) or \ 

198 isinstance(obj, _builtin_func_type) or isinstance(obj, _builtin_meth_type)) 

199 

200@undoc 

201def getargspec(obj): 

202 """Wrapper around :func:`inspect.getfullargspec` 

203 

204 In addition to functions and methods, this can also handle objects with a 

205 ``__call__`` attribute. 

206 

207 DEPRECATED: Deprecated since 7.10. Do not use, will be removed. 

208 """ 

209 

210 warnings.warn('`getargspec` function is deprecated as of IPython 7.10' 

211 'and will be removed in future versions.', DeprecationWarning, stacklevel=2) 

212 

213 if safe_hasattr(obj, '__call__') and not is_simple_callable(obj): 

214 obj = obj.__call__ 

215 

216 return inspect.getfullargspec(obj) 

217 

218@undoc 

219def format_argspec(argspec): 

220 """Format argspect, convenience wrapper around inspect's. 

221 

222 This takes a dict instead of ordered arguments and calls 

223 inspect.format_argspec with the arguments in the necessary order. 

224 

225 DEPRECATED (since 7.10): Do not use; will be removed in future versions. 

226 """ 

227 

228 warnings.warn('`format_argspec` function is deprecated as of IPython 7.10' 

229 'and will be removed in future versions.', DeprecationWarning, stacklevel=2) 

230 

231 

232 return inspect.formatargspec(argspec['args'], argspec['varargs'], 

233 argspec['varkw'], argspec['defaults']) 

234 

235@undoc 

236def call_tip(oinfo, format_call=True): 

237 """DEPRECATED since 6.0. Extract call tip data from an oinfo dict.""" 

238 warnings.warn( 

239 "`call_tip` function is deprecated as of IPython 6.0" 

240 "and will be removed in future versions.", 

241 DeprecationWarning, 

242 stacklevel=2, 

243 ) 

244 # Get call definition 

245 argspec = oinfo.get('argspec') 

246 if argspec is None: 

247 call_line = None 

248 else: 

249 # Callable objects will have 'self' as their first argument, prune 

250 # it out if it's there for clarity (since users do *not* pass an 

251 # extra first argument explicitly). 

252 try: 

253 has_self = argspec['args'][0] == 'self' 

254 except (KeyError, IndexError): 

255 pass 

256 else: 

257 if has_self: 

258 argspec['args'] = argspec['args'][1:] 

259 

260 call_line = oinfo['name']+format_argspec(argspec) 

261 

262 # Now get docstring. 

263 # The priority is: call docstring, constructor docstring, main one. 

264 doc = oinfo.get('call_docstring') 

265 if doc is None: 

266 doc = oinfo.get('init_docstring') 

267 if doc is None: 

268 doc = oinfo.get('docstring','') 

269 

270 return call_line, doc 

271 

272 

273def _get_wrapped(obj): 

274 """Get the original object if wrapped in one or more @decorators 

275 

276 Some objects automatically construct similar objects on any unrecognised 

277 attribute access (e.g. unittest.mock.call). To protect against infinite loops, 

278 this will arbitrarily cut off after 100 levels of obj.__wrapped__ 

279 attribute access. --TK, Jan 2016 

280 """ 

281 orig_obj = obj 

282 i = 0 

283 while safe_hasattr(obj, '__wrapped__'): 

284 obj = obj.__wrapped__ 

285 i += 1 

286 if i > 100: 

287 # __wrapped__ is probably a lie, so return the thing we started with 

288 return orig_obj 

289 return obj 

290 

291def find_file(obj) -> str: 

292 """Find the absolute path to the file where an object was defined. 

293 

294 This is essentially a robust wrapper around `inspect.getabsfile`. 

295 

296 Returns None if no file can be found. 

297 

298 Parameters 

299 ---------- 

300 obj : any Python object 

301 

302 Returns 

303 ------- 

304 fname : str 

305 The absolute path to the file where the object was defined. 

306 """ 

307 obj = _get_wrapped(obj) 

308 

309 fname = None 

310 try: 

311 fname = inspect.getabsfile(obj) 

312 except TypeError: 

313 # For an instance, the file that matters is where its class was 

314 # declared. 

315 try: 

316 fname = inspect.getabsfile(obj.__class__) 

317 except (OSError, TypeError): 

318 # Can happen for builtins 

319 pass 

320 except OSError: 

321 pass 

322 

323 return cast_unicode(fname) 

324 

325 

326def find_source_lines(obj): 

327 """Find the line number in a file where an object was defined. 

328 

329 This is essentially a robust wrapper around `inspect.getsourcelines`. 

330 

331 Returns None if no file can be found. 

332 

333 Parameters 

334 ---------- 

335 obj : any Python object 

336 

337 Returns 

338 ------- 

339 lineno : int 

340 The line number where the object definition starts. 

341 """ 

342 obj = _get_wrapped(obj) 

343 

344 try: 

345 lineno = inspect.getsourcelines(obj)[1] 

346 except TypeError: 

347 # For instances, try the class object like getsource() does 

348 try: 

349 lineno = inspect.getsourcelines(obj.__class__)[1] 

350 except (OSError, TypeError): 

351 return None 

352 except OSError: 

353 return None 

354 

355 return lineno 

356 

357class Inspector(Colorable): 

358 

359 def __init__(self, color_table=InspectColors, 

360 code_color_table=PyColorize.ANSICodeColors, 

361 scheme=None, 

362 str_detail_level=0, 

363 parent=None, config=None): 

364 super(Inspector, self).__init__(parent=parent, config=config) 

365 self.color_table = color_table 

366 self.parser = PyColorize.Parser(out='str', parent=self, style=scheme) 

367 self.format = self.parser.format 

368 self.str_detail_level = str_detail_level 

369 self.set_active_scheme(scheme) 

370 

371 def _getdef(self,obj,oname='') -> Union[str,None]: 

372 """Return the call signature for any callable object. 

373 

374 If any exception is generated, None is returned instead and the 

375 exception is suppressed.""" 

376 try: 

377 return _render_signature(signature(obj), oname) 

378 except: 

379 return None 

380 

381 def __head(self,h) -> str: 

382 """Return a header string with proper colors.""" 

383 return '%s%s%s' % (self.color_table.active_colors.header,h, 

384 self.color_table.active_colors.normal) 

385 

386 def set_active_scheme(self, scheme): 

387 if scheme is not None: 

388 self.color_table.set_active_scheme(scheme) 

389 self.parser.color_table.set_active_scheme(scheme) 

390 

391 def noinfo(self, msg, oname): 

392 """Generic message when no information is found.""" 

393 print('No %s found' % msg, end=' ') 

394 if oname: 

395 print('for %s' % oname) 

396 else: 

397 print() 

398 

399 def pdef(self, obj, oname=''): 

400 """Print the call signature for any callable object. 

401 

402 If the object is a class, print the constructor information.""" 

403 

404 if not callable(obj): 

405 print('Object is not callable.') 

406 return 

407 

408 header = '' 

409 

410 if inspect.isclass(obj): 

411 header = self.__head('Class constructor information:\n') 

412 

413 

414 output = self._getdef(obj,oname) 

415 if output is None: 

416 self.noinfo('definition header',oname) 

417 else: 

418 print(header,self.format(output), end=' ') 

419 

420 # In Python 3, all classes are new-style, so they all have __init__. 

421 @skip_doctest 

422 def pdoc(self, obj, oname='', formatter=None): 

423 """Print the docstring for any object. 

424 

425 Optional: 

426 -formatter: a function to run the docstring through for specially 

427 formatted docstrings. 

428 

429 Examples 

430 -------- 

431 In [1]: class NoInit: 

432 ...: pass 

433 

434 In [2]: class NoDoc: 

435 ...: def __init__(self): 

436 ...: pass 

437 

438 In [3]: %pdoc NoDoc 

439 No documentation found for NoDoc 

440 

441 In [4]: %pdoc NoInit 

442 No documentation found for NoInit 

443 

444 In [5]: obj = NoInit() 

445 

446 In [6]: %pdoc obj 

447 No documentation found for obj 

448 

449 In [5]: obj2 = NoDoc() 

450 

451 In [6]: %pdoc obj2 

452 No documentation found for obj2 

453 """ 

454 

455 head = self.__head # For convenience 

456 lines = [] 

457 ds = getdoc(obj) 

458 if formatter: 

459 ds = formatter(ds).get('plain/text', ds) 

460 if ds: 

461 lines.append(head("Class docstring:")) 

462 lines.append(indent(ds)) 

463 if inspect.isclass(obj) and hasattr(obj, '__init__'): 

464 init_ds = getdoc(obj.__init__) 

465 if init_ds is not None: 

466 lines.append(head("Init docstring:")) 

467 lines.append(indent(init_ds)) 

468 elif hasattr(obj,'__call__'): 

469 call_ds = getdoc(obj.__call__) 

470 if call_ds: 

471 lines.append(head("Call docstring:")) 

472 lines.append(indent(call_ds)) 

473 

474 if not lines: 

475 self.noinfo('documentation',oname) 

476 else: 

477 page.page('\n'.join(lines)) 

478 

479 def psource(self, obj, oname=''): 

480 """Print the source code for an object.""" 

481 

482 # Flush the source cache because inspect can return out-of-date source 

483 linecache.checkcache() 

484 try: 

485 src = getsource(obj, oname=oname) 

486 except Exception: 

487 src = None 

488 

489 if src is None: 

490 self.noinfo('source', oname) 

491 else: 

492 page.page(self.format(src)) 

493 

494 def pfile(self, obj, oname=''): 

495 """Show the whole file where an object was defined.""" 

496 

497 lineno = find_source_lines(obj) 

498 if lineno is None: 

499 self.noinfo('file', oname) 

500 return 

501 

502 ofile = find_file(obj) 

503 # run contents of file through pager starting at line where the object 

504 # is defined, as long as the file isn't binary and is actually on the 

505 # filesystem. 

506 if ofile.endswith(('.so', '.dll', '.pyd')): 

507 print('File %r is binary, not printing.' % ofile) 

508 elif not os.path.isfile(ofile): 

509 print('File %r does not exist, not printing.' % ofile) 

510 else: 

511 # Print only text files, not extension binaries. Note that 

512 # getsourcelines returns lineno with 1-offset and page() uses 

513 # 0-offset, so we must adjust. 

514 page.page(self.format(openpy.read_py_file(ofile, skip_encoding_cookie=False)), lineno - 1) 

515 

516 

517 def _mime_format(self, text:str, formatter=None) -> dict: 

518 """Return a mime bundle representation of the input text. 

519 

520 - if `formatter` is None, the returned mime bundle has 

521 a ``text/plain`` field, with the input text. 

522 a ``text/html`` field with a ``<pre>`` tag containing the input text. 

523 

524 - if ``formatter`` is not None, it must be a callable transforming the 

525 input text into a mime bundle. Default values for ``text/plain`` and 

526 ``text/html`` representations are the ones described above. 

527 

528 Note: 

529 

530 Formatters returning strings are supported but this behavior is deprecated. 

531 

532 """ 

533 defaults = { 

534 "text/plain": text, 

535 "text/html": f"<pre>{html.escape(text)}</pre>", 

536 } 

537 

538 if formatter is None: 

539 return defaults 

540 else: 

541 formatted = formatter(text) 

542 

543 if not isinstance(formatted, dict): 

544 # Handle the deprecated behavior of a formatter returning 

545 # a string instead of a mime bundle. 

546 return {"text/plain": formatted, "text/html": f"<pre>{formatted}</pre>"} 

547 

548 else: 

549 return dict(defaults, **formatted) 

550 

551 

552 def format_mime(self, bundle): 

553 """Format a mimebundle being created by _make_info_unformatted into a real mimebundle""" 

554 # Format text/plain mimetype 

555 if isinstance(bundle["text/plain"], (list, tuple)): 

556 # bundle['text/plain'] is a list of (head, formatted body) pairs 

557 lines = [] 

558 _len = max(len(h) for h, _ in bundle["text/plain"]) 

559 

560 for head, body in bundle["text/plain"]: 

561 body = body.strip("\n") 

562 delim = "\n" if "\n" in body else " " 

563 lines.append( 

564 f"{self.__head(head+':')}{(_len - len(head))*' '}{delim}{body}" 

565 ) 

566 

567 bundle["text/plain"] = "\n".join(lines) 

568 

569 # Format the text/html mimetype 

570 if isinstance(bundle["text/html"], (list, tuple)): 

571 # bundle['text/html'] is a list of (head, formatted body) pairs 

572 bundle["text/html"] = "\n".join( 

573 (f"<h1>{head}</h1>\n{body}" for (head, body) in bundle["text/html"]) 

574 ) 

575 return bundle 

576 

577 def _append_info_field( 

578 self, bundle, title: str, key: str, info, omit_sections, formatter 

579 ): 

580 """Append an info value to the unformatted mimebundle being constructed by _make_info_unformatted""" 

581 if title in omit_sections or key in omit_sections: 

582 return 

583 field = info[key] 

584 if field is not None: 

585 formatted_field = self._mime_format(field, formatter) 

586 bundle["text/plain"].append((title, formatted_field["text/plain"])) 

587 bundle["text/html"].append((title, formatted_field["text/html"])) 

588 

589 def _make_info_unformatted(self, obj, info, formatter, detail_level, omit_sections): 

590 """Assemble the mimebundle as unformatted lists of information""" 

591 bundle = { 

592 "text/plain": [], 

593 "text/html": [], 

594 } 

595 

596 # A convenience function to simplify calls below 

597 def append_field(bundle, title: str, key: str, formatter=None): 

598 self._append_info_field( 

599 bundle, 

600 title=title, 

601 key=key, 

602 info=info, 

603 omit_sections=omit_sections, 

604 formatter=formatter, 

605 ) 

606 

607 def code_formatter(text): 

608 return { 

609 'text/plain': self.format(text), 

610 'text/html': pylight(text) 

611 } 

612 

613 if info["isalias"]: 

614 append_field(bundle, "Repr", "string_form") 

615 

616 elif info['ismagic']: 

617 if detail_level > 0: 

618 append_field(bundle, "Source", "source", code_formatter) 

619 else: 

620 append_field(bundle, "Docstring", "docstring", formatter) 

621 append_field(bundle, "File", "file") 

622 

623 elif info['isclass'] or is_simple_callable(obj): 

624 # Functions, methods, classes 

625 append_field(bundle, "Signature", "definition", code_formatter) 

626 append_field(bundle, "Init signature", "init_definition", code_formatter) 

627 append_field(bundle, "Docstring", "docstring", formatter) 

628 if detail_level > 0 and info["source"]: 

629 append_field(bundle, "Source", "source", code_formatter) 

630 else: 

631 append_field(bundle, "Init docstring", "init_docstring", formatter) 

632 

633 append_field(bundle, "File", "file") 

634 append_field(bundle, "Type", "type_name") 

635 append_field(bundle, "Subclasses", "subclasses") 

636 

637 else: 

638 # General Python objects 

639 append_field(bundle, "Signature", "definition", code_formatter) 

640 append_field(bundle, "Call signature", "call_def", code_formatter) 

641 append_field(bundle, "Type", "type_name") 

642 append_field(bundle, "String form", "string_form") 

643 

644 # Namespace 

645 if info["namespace"] != "Interactive": 

646 append_field(bundle, "Namespace", "namespace") 

647 

648 append_field(bundle, "Length", "length") 

649 append_field(bundle, "File", "file") 

650 

651 # Source or docstring, depending on detail level and whether 

652 # source found. 

653 if detail_level > 0 and info["source"]: 

654 append_field(bundle, "Source", "source", code_formatter) 

655 else: 

656 append_field(bundle, "Docstring", "docstring", formatter) 

657 

658 append_field(bundle, "Class docstring", "class_docstring", formatter) 

659 append_field(bundle, "Init docstring", "init_docstring", formatter) 

660 append_field(bundle, "Call docstring", "call_docstring", formatter) 

661 return bundle 

662 

663 

664 def _get_info( 

665 self, obj, oname="", formatter=None, info=None, detail_level=0, omit_sections=() 

666 ): 

667 """Retrieve an info dict and format it. 

668 

669 Parameters 

670 ---------- 

671 obj : any 

672 Object to inspect and return info from 

673 oname : str (default: ''): 

674 Name of the variable pointing to `obj`. 

675 formatter : callable 

676 info 

677 already computed information 

678 detail_level : integer 

679 Granularity of detail level, if set to 1, give more information. 

680 omit_sections : container[str] 

681 Titles or keys to omit from output (can be set, tuple, etc., anything supporting `in`) 

682 """ 

683 

684 info = self.info(obj, oname=oname, info=info, detail_level=detail_level) 

685 bundle = self._make_info_unformatted( 

686 obj, info, formatter, detail_level=detail_level, omit_sections=omit_sections 

687 ) 

688 return self.format_mime(bundle) 

689 

690 def pinfo( 

691 self, 

692 obj, 

693 oname="", 

694 formatter=None, 

695 info=None, 

696 detail_level=0, 

697 enable_html_pager=True, 

698 omit_sections=(), 

699 ): 

700 """Show detailed information about an object. 

701 

702 Optional arguments: 

703 

704 - oname: name of the variable pointing to the object. 

705 

706 - formatter: callable (optional) 

707 A special formatter for docstrings. 

708 

709 The formatter is a callable that takes a string as an input 

710 and returns either a formatted string or a mime type bundle 

711 in the form of a dictionary. 

712 

713 Although the support of custom formatter returning a string 

714 instead of a mime type bundle is deprecated. 

715 

716 - info: a structure with some information fields which may have been 

717 precomputed already. 

718 

719 - detail_level: if set to 1, more information is given. 

720 

721 - omit_sections: set of section keys and titles to omit 

722 """ 

723 info = self._get_info( 

724 obj, oname, formatter, info, detail_level, omit_sections=omit_sections 

725 ) 

726 if not enable_html_pager: 

727 del info['text/html'] 

728 page.page(info) 

729 

730 def _info(self, obj, oname="", info=None, detail_level=0): 

731 """ 

732 Inspector.info() was likely improperly marked as deprecated 

733 while only a parameter was deprecated. We "un-deprecate" it. 

734 """ 

735 

736 warnings.warn( 

737 "The `Inspector.info()` method has been un-deprecated as of 8.0 " 

738 "and the `formatter=` keyword removed. `Inspector._info` is now " 

739 "an alias, and you can just call `.info()` directly.", 

740 DeprecationWarning, 

741 stacklevel=2, 

742 ) 

743 return self.info(obj, oname=oname, info=info, detail_level=detail_level) 

744 

745 def info(self, obj, oname="", info=None, detail_level=0) -> dict: 

746 """Compute a dict with detailed information about an object. 

747 

748 Parameters 

749 ---------- 

750 obj : any 

751 An object to find information about 

752 oname : str (default: '') 

753 Name of the variable pointing to `obj`. 

754 info : (default: None) 

755 A struct (dict like with attr access) with some information fields 

756 which may have been precomputed already. 

757 detail_level : int (default:0) 

758 If set to 1, more information is given. 

759 

760 Returns 

761 ------- 

762 An object info dict with known fields from `info_fields`. Keys are 

763 strings, values are string or None. 

764 """ 

765 

766 if info is None: 

767 ismagic = False 

768 isalias = False 

769 ospace = '' 

770 else: 

771 ismagic = info.ismagic 

772 isalias = info.isalias 

773 ospace = info.namespace 

774 

775 # Get docstring, special-casing aliases: 

776 if isalias: 

777 if not callable(obj): 

778 try: 

779 ds = "Alias to the system command:\n %s" % obj[1] 

780 except: 

781 ds = "Alias: " + str(obj) 

782 else: 

783 ds = "Alias to " + str(obj) 

784 if obj.__doc__: 

785 ds += "\nDocstring:\n" + obj.__doc__ 

786 else: 

787 ds = getdoc(obj) 

788 if ds is None: 

789 ds = '<no docstring>' 

790 

791 # store output in a dict, we initialize it here and fill it as we go 

792 out = dict(name=oname, found=True, isalias=isalias, ismagic=ismagic, subclasses=None) 

793 

794 string_max = 200 # max size of strings to show (snipped if longer) 

795 shalf = int((string_max - 5) / 2) 

796 

797 if ismagic: 

798 out['type_name'] = 'Magic function' 

799 elif isalias: 

800 out['type_name'] = 'System alias' 

801 else: 

802 out['type_name'] = type(obj).__name__ 

803 

804 try: 

805 bclass = obj.__class__ 

806 out['base_class'] = str(bclass) 

807 except: 

808 pass 

809 

810 # String form, but snip if too long in ? form (full in ??) 

811 if detail_level >= self.str_detail_level: 

812 try: 

813 ostr = str(obj) 

814 str_head = 'string_form' 

815 if not detail_level and len(ostr)>string_max: 

816 ostr = ostr[:shalf] + ' <...> ' + ostr[-shalf:] 

817 ostr = ("\n" + " " * len(str_head.expandtabs())).\ 

818 join(q.strip() for q in ostr.split("\n")) 

819 out[str_head] = ostr 

820 except: 

821 pass 

822 

823 if ospace: 

824 out['namespace'] = ospace 

825 

826 # Length (for strings and lists) 

827 try: 

828 out['length'] = str(len(obj)) 

829 except Exception: 

830 pass 

831 

832 # Filename where object was defined 

833 binary_file = False 

834 fname = find_file(obj) 

835 if fname is None: 

836 # if anything goes wrong, we don't want to show source, so it's as 

837 # if the file was binary 

838 binary_file = True 

839 else: 

840 if fname.endswith(('.so', '.dll', '.pyd')): 

841 binary_file = True 

842 elif fname.endswith('<string>'): 

843 fname = 'Dynamically generated function. No source code available.' 

844 out['file'] = compress_user(fname) 

845 

846 # Original source code for a callable, class or property. 

847 if detail_level: 

848 # Flush the source cache because inspect can return out-of-date 

849 # source 

850 linecache.checkcache() 

851 try: 

852 if isinstance(obj, property) or not binary_file: 

853 src = getsource(obj, oname) 

854 if src is not None: 

855 src = src.rstrip() 

856 out['source'] = src 

857 

858 except Exception: 

859 pass 

860 

861 # Add docstring only if no source is to be shown (avoid repetitions). 

862 if ds and not self._source_contains_docstring(out.get('source'), ds): 

863 out['docstring'] = ds 

864 

865 # Constructor docstring for classes 

866 if inspect.isclass(obj): 

867 out['isclass'] = True 

868 

869 # get the init signature: 

870 try: 

871 init_def = self._getdef(obj, oname) 

872 except AttributeError: 

873 init_def = None 

874 

875 # get the __init__ docstring 

876 try: 

877 obj_init = obj.__init__ 

878 except AttributeError: 

879 init_ds = None 

880 else: 

881 if init_def is None: 

882 # Get signature from init if top-level sig failed. 

883 # Can happen for built-in types (list, etc.). 

884 try: 

885 init_def = self._getdef(obj_init, oname) 

886 except AttributeError: 

887 pass 

888 init_ds = getdoc(obj_init) 

889 # Skip Python's auto-generated docstrings 

890 if init_ds == _object_init_docstring: 

891 init_ds = None 

892 

893 if init_def: 

894 out['init_definition'] = init_def 

895 

896 if init_ds: 

897 out['init_docstring'] = init_ds 

898 

899 names = [sub.__name__ for sub in type.__subclasses__(obj)] 

900 if len(names) < 10: 

901 all_names = ', '.join(names) 

902 else: 

903 all_names = ', '.join(names[:10]+['...']) 

904 out['subclasses'] = all_names 

905 # and class docstring for instances: 

906 else: 

907 # reconstruct the function definition and print it: 

908 defln = self._getdef(obj, oname) 

909 if defln: 

910 out['definition'] = defln 

911 

912 # First, check whether the instance docstring is identical to the 

913 # class one, and print it separately if they don't coincide. In 

914 # most cases they will, but it's nice to print all the info for 

915 # objects which use instance-customized docstrings. 

916 if ds: 

917 try: 

918 cls = getattr(obj,'__class__') 

919 except: 

920 class_ds = None 

921 else: 

922 class_ds = getdoc(cls) 

923 # Skip Python's auto-generated docstrings 

924 if class_ds in _builtin_type_docstrings: 

925 class_ds = None 

926 if class_ds and ds != class_ds: 

927 out['class_docstring'] = class_ds 

928 

929 # Next, try to show constructor docstrings 

930 try: 

931 init_ds = getdoc(obj.__init__) 

932 # Skip Python's auto-generated docstrings 

933 if init_ds == _object_init_docstring: 

934 init_ds = None 

935 except AttributeError: 

936 init_ds = None 

937 if init_ds: 

938 out['init_docstring'] = init_ds 

939 

940 # Call form docstring for callable instances 

941 if safe_hasattr(obj, '__call__') and not is_simple_callable(obj): 

942 call_def = self._getdef(obj.__call__, oname) 

943 if call_def and (call_def != out.get('definition')): 

944 # it may never be the case that call def and definition differ, 

945 # but don't include the same signature twice 

946 out['call_def'] = call_def 

947 call_ds = getdoc(obj.__call__) 

948 # Skip Python's auto-generated docstrings 

949 if call_ds == _func_call_docstring: 

950 call_ds = None 

951 if call_ds: 

952 out['call_docstring'] = call_ds 

953 

954 return object_info(**out) 

955 

956 @staticmethod 

957 def _source_contains_docstring(src, doc): 

958 """ 

959 Check whether the source *src* contains the docstring *doc*. 

960 

961 This is is helper function to skip displaying the docstring if the 

962 source already contains it, avoiding repetition of information. 

963 """ 

964 try: 

965 def_node, = ast.parse(dedent(src)).body 

966 return ast.get_docstring(def_node) == doc 

967 except Exception: 

968 # The source can become invalid or even non-existent (because it 

969 # is re-fetched from the source file) so the above code fail in 

970 # arbitrary ways. 

971 return False 

972 

973 def psearch(self,pattern,ns_table,ns_search=[], 

974 ignore_case=False,show_all=False, *, list_types=False): 

975 """Search namespaces with wildcards for objects. 

976 

977 Arguments: 

978 

979 - pattern: string containing shell-like wildcards to use in namespace 

980 searches and optionally a type specification to narrow the search to 

981 objects of that type. 

982 

983 - ns_table: dict of name->namespaces for search. 

984 

985 Optional arguments: 

986 

987 - ns_search: list of namespace names to include in search. 

988 

989 - ignore_case(False): make the search case-insensitive. 

990 

991 - show_all(False): show all names, including those starting with 

992 underscores. 

993 

994 - list_types(False): list all available object types for object matching. 

995 """ 

996 #print 'ps pattern:<%r>' % pattern # dbg 

997 

998 # defaults 

999 type_pattern = 'all' 

1000 filter = '' 

1001 

1002 # list all object types 

1003 if list_types: 

1004 page.page('\n'.join(sorted(typestr2type))) 

1005 return 

1006 

1007 cmds = pattern.split() 

1008 len_cmds = len(cmds) 

1009 if len_cmds == 1: 

1010 # Only filter pattern given 

1011 filter = cmds[0] 

1012 elif len_cmds == 2: 

1013 # Both filter and type specified 

1014 filter,type_pattern = cmds 

1015 else: 

1016 raise ValueError('invalid argument string for psearch: <%s>' % 

1017 pattern) 

1018 

1019 # filter search namespaces 

1020 for name in ns_search: 

1021 if name not in ns_table: 

1022 raise ValueError('invalid namespace <%s>. Valid names: %s' % 

1023 (name,ns_table.keys())) 

1024 

1025 #print 'type_pattern:',type_pattern # dbg 

1026 search_result, namespaces_seen = set(), set() 

1027 for ns_name in ns_search: 

1028 ns = ns_table[ns_name] 

1029 # Normally, locals and globals are the same, so we just check one. 

1030 if id(ns) in namespaces_seen: 

1031 continue 

1032 namespaces_seen.add(id(ns)) 

1033 tmp_res = list_namespace(ns, type_pattern, filter, 

1034 ignore_case=ignore_case, show_all=show_all) 

1035 search_result.update(tmp_res) 

1036 

1037 page.page('\n'.join(sorted(search_result))) 

1038 

1039 

1040def _render_signature(obj_signature, obj_name) -> str: 

1041 """ 

1042 This was mostly taken from inspect.Signature.__str__. 

1043 Look there for the comments. 

1044 The only change is to add linebreaks when this gets too long. 

1045 """ 

1046 result = [] 

1047 pos_only = False 

1048 kw_only = True 

1049 for param in obj_signature.parameters.values(): 

1050 if param.kind == inspect._POSITIONAL_ONLY: 

1051 pos_only = True 

1052 elif pos_only: 

1053 result.append('/') 

1054 pos_only = False 

1055 

1056 if param.kind == inspect._VAR_POSITIONAL: 

1057 kw_only = False 

1058 elif param.kind == inspect._KEYWORD_ONLY and kw_only: 

1059 result.append('*') 

1060 kw_only = False 

1061 

1062 result.append(str(param)) 

1063 

1064 if pos_only: 

1065 result.append('/') 

1066 

1067 # add up name, parameters, braces (2), and commas 

1068 if len(obj_name) + sum(len(r) + 2 for r in result) > 75: 

1069 # This doesn’t fit behind “Signature: ” in an inspect window. 

1070 rendered = '{}(\n{})'.format(obj_name, ''.join( 

1071 ' {},\n'.format(r) for r in result) 

1072 ) 

1073 else: 

1074 rendered = '{}({})'.format(obj_name, ', '.join(result)) 

1075 

1076 if obj_signature.return_annotation is not inspect._empty: 

1077 anno = inspect.formatannotation(obj_signature.return_annotation) 

1078 rendered += ' -> {}'.format(anno) 

1079 

1080 return rendered