Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.8/site-packages/IPython/core/magics/basic.py: 24%

258 statements  

« prev     ^ index     » next       coverage.py v7.4.4, created at 2024-04-20 06:09 +0000

1"""Implementation of basic magic functions.""" 

2 

3 

4from logging import error 

5import io 

6import os 

7from pprint import pformat 

8import sys 

9from warnings import warn 

10 

11from traitlets.utils.importstring import import_item 

12from IPython.core import magic_arguments, page 

13from IPython.core.error import UsageError 

14from IPython.core.magic import Magics, magics_class, line_magic, magic_escapes 

15from IPython.utils.text import format_screen, dedent, indent 

16from IPython.testing.skipdoctest import skip_doctest 

17from IPython.utils.ipstruct import Struct 

18 

19 

20class MagicsDisplay(object): 

21 def __init__(self, magics_manager, ignore=None): 

22 self.ignore = ignore if ignore else [] 

23 self.magics_manager = magics_manager 

24 

25 def _lsmagic(self): 

26 """The main implementation of the %lsmagic""" 

27 mesc = magic_escapes['line'] 

28 cesc = magic_escapes['cell'] 

29 mman = self.magics_manager 

30 magics = mman.lsmagic() 

31 out = ['Available line magics:', 

32 mesc + (' '+mesc).join(sorted([m for m,v in magics['line'].items() if (v not in self.ignore)])), 

33 '', 

34 'Available cell magics:', 

35 cesc + (' '+cesc).join(sorted([m for m,v in magics['cell'].items() if (v not in self.ignore)])), 

36 '', 

37 mman.auto_status()] 

38 return '\n'.join(out) 

39 

40 def _repr_pretty_(self, p, cycle): 

41 p.text(self._lsmagic()) 

42 

43 def __str__(self): 

44 return self._lsmagic() 

45 

46 def _jsonable(self): 

47 """turn magics dict into jsonable dict of the same structure 

48 

49 replaces object instances with their class names as strings 

50 """ 

51 magic_dict = {} 

52 mman = self.magics_manager 

53 magics = mman.lsmagic() 

54 for key, subdict in magics.items(): 

55 d = {} 

56 magic_dict[key] = d 

57 for name, obj in subdict.items(): 

58 try: 

59 classname = obj.__self__.__class__.__name__ 

60 except AttributeError: 

61 classname = 'Other' 

62 

63 d[name] = classname 

64 return magic_dict 

65 

66 def _repr_json_(self): 

67 return self._jsonable() 

68 

69 

70@magics_class 

71class BasicMagics(Magics): 

72 """Magics that provide central IPython functionality. 

73 

74 These are various magics that don't fit into specific categories but that 

75 are all part of the base 'IPython experience'.""" 

76 

77 @skip_doctest 

78 @magic_arguments.magic_arguments() 

79 @magic_arguments.argument( 

80 '-l', '--line', action='store_true', 

81 help="""Create a line magic alias.""" 

82 ) 

83 @magic_arguments.argument( 

84 '-c', '--cell', action='store_true', 

85 help="""Create a cell magic alias.""" 

86 ) 

87 @magic_arguments.argument( 

88 'name', 

89 help="""Name of the magic to be created.""" 

90 ) 

91 @magic_arguments.argument( 

92 'target', 

93 help="""Name of the existing line or cell magic.""" 

94 ) 

95 @magic_arguments.argument( 

96 '-p', '--params', default=None, 

97 help="""Parameters passed to the magic function.""" 

98 ) 

99 @line_magic 

100 def alias_magic(self, line=''): 

101 """Create an alias for an existing line or cell magic. 

102 

103 Examples 

104 -------- 

105 :: 

106 

107 In [1]: %alias_magic t timeit 

108 Created `%t` as an alias for `%timeit`. 

109 Created `%%t` as an alias for `%%timeit`. 

110 

111 In [2]: %t -n1 pass 

112 1 loops, best of 3: 954 ns per loop 

113 

114 In [3]: %%t -n1 

115 ...: pass 

116 ...: 

117 1 loops, best of 3: 954 ns per loop 

118 

119 In [4]: %alias_magic --cell whereami pwd 

120 UsageError: Cell magic function `%%pwd` not found. 

121 In [5]: %alias_magic --line whereami pwd 

122 Created `%whereami` as an alias for `%pwd`. 

123 

124 In [6]: %whereami 

125 Out[6]: u'/home/testuser' 

126 

127 In [7]: %alias_magic h history "-p -l 30" --line 

128 Created `%h` as an alias for `%history -l 30`. 

129 """ 

130 

131 args = magic_arguments.parse_argstring(self.alias_magic, line) 

132 shell = self.shell 

133 mman = self.shell.magics_manager 

134 escs = ''.join(magic_escapes.values()) 

135 

136 target = args.target.lstrip(escs) 

137 name = args.name.lstrip(escs) 

138 

139 params = args.params 

140 if (params and 

141 ((params.startswith('"') and params.endswith('"')) 

142 or (params.startswith("'") and params.endswith("'")))): 

143 params = params[1:-1] 

144 

145 # Find the requested magics. 

146 m_line = shell.find_magic(target, 'line') 

147 m_cell = shell.find_magic(target, 'cell') 

148 if args.line and m_line is None: 

149 raise UsageError('Line magic function `%s%s` not found.' % 

150 (magic_escapes['line'], target)) 

151 if args.cell and m_cell is None: 

152 raise UsageError('Cell magic function `%s%s` not found.' % 

153 (magic_escapes['cell'], target)) 

154 

155 # If --line and --cell are not specified, default to the ones 

156 # that are available. 

157 if not args.line and not args.cell: 

158 if not m_line and not m_cell: 

159 raise UsageError( 

160 'No line or cell magic with name `%s` found.' % target 

161 ) 

162 args.line = bool(m_line) 

163 args.cell = bool(m_cell) 

164 

165 params_str = "" if params is None else " " + params 

166 

167 if args.line: 

168 mman.register_alias(name, target, 'line', params) 

169 print('Created `%s%s` as an alias for `%s%s%s`.' % ( 

170 magic_escapes['line'], name, 

171 magic_escapes['line'], target, params_str)) 

172 

173 if args.cell: 

174 mman.register_alias(name, target, 'cell', params) 

175 print('Created `%s%s` as an alias for `%s%s%s`.' % ( 

176 magic_escapes['cell'], name, 

177 magic_escapes['cell'], target, params_str)) 

178 

179 @line_magic 

180 def lsmagic(self, parameter_s=''): 

181 """List currently available magic functions.""" 

182 return MagicsDisplay(self.shell.magics_manager, ignore=[]) 

183 

184 def _magic_docs(self, brief=False, rest=False): 

185 """Return docstrings from magic functions.""" 

186 mman = self.shell.magics_manager 

187 docs = mman.lsmagic_docs(brief, missing='No documentation') 

188 

189 if rest: 

190 format_string = '**%s%s**::\n\n%s\n\n' 

191 else: 

192 format_string = '%s%s:\n%s\n' 

193 

194 return ''.join( 

195 [format_string % (magic_escapes['line'], fname, 

196 indent(dedent(fndoc))) 

197 for fname, fndoc in sorted(docs['line'].items())] 

198 + 

199 [format_string % (magic_escapes['cell'], fname, 

200 indent(dedent(fndoc))) 

201 for fname, fndoc in sorted(docs['cell'].items())] 

202 ) 

203 

204 @line_magic 

205 def magic(self, parameter_s=''): 

206 """Print information about the magic function system. 

207 

208 Supported formats: -latex, -brief, -rest 

209 """ 

210 

211 mode = '' 

212 try: 

213 mode = parameter_s.split()[0][1:] 

214 except IndexError: 

215 pass 

216 

217 brief = (mode == 'brief') 

218 rest = (mode == 'rest') 

219 magic_docs = self._magic_docs(brief, rest) 

220 

221 if mode == 'latex': 

222 print(self.format_latex(magic_docs)) 

223 return 

224 else: 

225 magic_docs = format_screen(magic_docs) 

226 

227 out = [""" 

228IPython's 'magic' functions 

229=========================== 

230 

231The magic function system provides a series of functions which allow you to 

232control the behavior of IPython itself, plus a lot of system-type 

233features. There are two kinds of magics, line-oriented and cell-oriented. 

234 

235Line magics are prefixed with the % character and work much like OS 

236command-line calls: they get as an argument the rest of the line, where 

237arguments are passed without parentheses or quotes. For example, this will 

238time the given statement:: 

239 

240 %timeit range(1000) 

241 

242Cell magics are prefixed with a double %%, and they are functions that get as 

243an argument not only the rest of the line, but also the lines below it in a 

244separate argument. These magics are called with two arguments: the rest of the 

245call line and the body of the cell, consisting of the lines below the first. 

246For example:: 

247 

248 %%timeit x = numpy.random.randn((100, 100)) 

249 numpy.linalg.svd(x) 

250 

251will time the execution of the numpy svd routine, running the assignment of x 

252as part of the setup phase, which is not timed. 

253 

254In a line-oriented client (the terminal or Qt console IPython), starting a new 

255input with %% will automatically enter cell mode, and IPython will continue 

256reading input until a blank line is given. In the notebook, simply type the 

257whole cell as one entity, but keep in mind that the %% escape can only be at 

258the very start of the cell. 

259 

260NOTE: If you have 'automagic' enabled (via the command line option or with the 

261%automagic function), you don't need to type in the % explicitly for line 

262magics; cell magics always require an explicit '%%' escape. By default, 

263IPython ships with automagic on, so you should only rarely need the % escape. 

264 

265Example: typing '%cd mydir' (without the quotes) changes your working directory 

266to 'mydir', if it exists. 

267 

268For a list of the available magic functions, use %lsmagic. For a description 

269of any of them, type %magic_name?, e.g. '%cd?'. 

270 

271Currently the magic system has the following functions:""", 

272 magic_docs, 

273 "Summary of magic functions (from %slsmagic):" % magic_escapes['line'], 

274 str(self.lsmagic()), 

275 ] 

276 page.page('\n'.join(out)) 

277 

278 

279 @line_magic 

280 def page(self, parameter_s=''): 

281 """Pretty print the object and display it through a pager. 

282 

283 %page [options] OBJECT 

284 

285 If no object is given, use _ (last output). 

286 

287 Options: 

288 

289 -r: page str(object), don't pretty-print it.""" 

290 

291 # After a function contributed by Olivier Aubert, slightly modified. 

292 

293 # Process options/args 

294 opts, args = self.parse_options(parameter_s, 'r') 

295 raw = 'r' in opts 

296 

297 oname = args and args or '_' 

298 info = self.shell._ofind(oname) 

299 if info.found: 

300 if raw: 

301 txt = str(info.obj) 

302 else: 

303 txt = pformat(info.obj) 

304 page.page(txt) 

305 else: 

306 print('Object `%s` not found' % oname) 

307 

308 @line_magic 

309 def pprint(self, parameter_s=''): 

310 """Toggle pretty printing on/off.""" 

311 ptformatter = self.shell.display_formatter.formatters['text/plain'] 

312 ptformatter.pprint = bool(1 - ptformatter.pprint) 

313 print('Pretty printing has been turned', 

314 ['OFF','ON'][ptformatter.pprint]) 

315 

316 @line_magic 

317 def colors(self, parameter_s=''): 

318 """Switch color scheme for prompts, info system and exception handlers. 

319 

320 Currently implemented schemes: NoColor, Linux, LightBG. 

321 

322 Color scheme names are not case-sensitive. 

323 

324 Examples 

325 -------- 

326 To get a plain black and white terminal:: 

327 

328 %colors nocolor 

329 """ 

330 def color_switch_err(name): 

331 warn('Error changing %s color schemes.\n%s' % 

332 (name, sys.exc_info()[1]), stacklevel=2) 

333 

334 

335 new_scheme = parameter_s.strip() 

336 if not new_scheme: 

337 raise UsageError( 

338 "%colors: you must specify a color scheme. See '%colors?'") 

339 # local shortcut 

340 shell = self.shell 

341 

342 # Set shell colour scheme 

343 try: 

344 shell.colors = new_scheme 

345 shell.refresh_style() 

346 except: 

347 color_switch_err('shell') 

348 

349 # Set exception colors 

350 try: 

351 shell.InteractiveTB.set_colors(scheme = new_scheme) 

352 shell.SyntaxTB.set_colors(scheme = new_scheme) 

353 except: 

354 color_switch_err('exception') 

355 

356 # Set info (for 'object?') colors 

357 if shell.color_info: 

358 try: 

359 shell.inspector.set_active_scheme(new_scheme) 

360 except: 

361 color_switch_err('object inspector') 

362 else: 

363 shell.inspector.set_active_scheme('NoColor') 

364 

365 @line_magic 

366 def xmode(self, parameter_s=''): 

367 """Switch modes for the exception handlers. 

368 

369 Valid modes: Plain, Context, Verbose, and Minimal. 

370 

371 If called without arguments, acts as a toggle. 

372 

373 When in verbose mode the value `--show` (and `--hide`) 

374 will respectively show (or hide) frames with ``__tracebackhide__ = 

375 True`` value set. 

376 """ 

377 

378 def xmode_switch_err(name): 

379 warn('Error changing %s exception modes.\n%s' % 

380 (name,sys.exc_info()[1])) 

381 

382 shell = self.shell 

383 if parameter_s.strip() == "--show": 

384 shell.InteractiveTB.skip_hidden = False 

385 return 

386 if parameter_s.strip() == "--hide": 

387 shell.InteractiveTB.skip_hidden = True 

388 return 

389 

390 new_mode = parameter_s.strip().capitalize() 

391 try: 

392 shell.InteractiveTB.set_mode(mode=new_mode) 

393 print('Exception reporting mode:',shell.InteractiveTB.mode) 

394 except: 

395 xmode_switch_err('user') 

396 

397 @line_magic 

398 def quickref(self, arg): 

399 """ Show a quick reference sheet """ 

400 from IPython.core.usage import quick_reference 

401 qr = quick_reference + self._magic_docs(brief=True) 

402 page.page(qr) 

403 

404 @line_magic 

405 def doctest_mode(self, parameter_s=''): 

406 """Toggle doctest mode on and off. 

407 

408 This mode is intended to make IPython behave as much as possible like a 

409 plain Python shell, from the perspective of how its prompts, exceptions 

410 and output look. This makes it easy to copy and paste parts of a 

411 session into doctests. It does so by: 

412 

413 - Changing the prompts to the classic ``>>>`` ones. 

414 - Changing the exception reporting mode to 'Plain'. 

415 - Disabling pretty-printing of output. 

416 

417 Note that IPython also supports the pasting of code snippets that have 

418 leading '>>>' and '...' prompts in them. This means that you can paste 

419 doctests from files or docstrings (even if they have leading 

420 whitespace), and the code will execute correctly. You can then use 

421 '%history -t' to see the translated history; this will give you the 

422 input after removal of all the leading prompts and whitespace, which 

423 can be pasted back into an editor. 

424 

425 With these features, you can switch into this mode easily whenever you 

426 need to do testing and changes to doctests, without having to leave 

427 your existing IPython session. 

428 """ 

429 

430 # Shorthands 

431 shell = self.shell 

432 meta = shell.meta 

433 disp_formatter = self.shell.display_formatter 

434 ptformatter = disp_formatter.formatters['text/plain'] 

435 # dstore is a data store kept in the instance metadata bag to track any 

436 # changes we make, so we can undo them later. 

437 dstore = meta.setdefault('doctest_mode',Struct()) 

438 save_dstore = dstore.setdefault 

439 

440 # save a few values we'll need to recover later 

441 mode = save_dstore('mode',False) 

442 save_dstore('rc_pprint',ptformatter.pprint) 

443 save_dstore('xmode',shell.InteractiveTB.mode) 

444 save_dstore('rc_separate_out',shell.separate_out) 

445 save_dstore('rc_separate_out2',shell.separate_out2) 

446 save_dstore('rc_separate_in',shell.separate_in) 

447 save_dstore('rc_active_types',disp_formatter.active_types) 

448 

449 if not mode: 

450 # turn on 

451 

452 # Prompt separators like plain python 

453 shell.separate_in = '' 

454 shell.separate_out = '' 

455 shell.separate_out2 = '' 

456 

457 

458 ptformatter.pprint = False 

459 disp_formatter.active_types = ['text/plain'] 

460 

461 shell.magic('xmode Plain') 

462 else: 

463 # turn off 

464 shell.separate_in = dstore.rc_separate_in 

465 

466 shell.separate_out = dstore.rc_separate_out 

467 shell.separate_out2 = dstore.rc_separate_out2 

468 

469 ptformatter.pprint = dstore.rc_pprint 

470 disp_formatter.active_types = dstore.rc_active_types 

471 

472 shell.magic('xmode ' + dstore.xmode) 

473 

474 # mode here is the state before we switch; switch_doctest_mode takes 

475 # the mode we're switching to. 

476 shell.switch_doctest_mode(not mode) 

477 

478 # Store new mode and inform 

479 dstore.mode = bool(not mode) 

480 mode_label = ['OFF','ON'][dstore.mode] 

481 print('Doctest mode is:', mode_label) 

482 

483 @line_magic 

484 def gui(self, parameter_s=''): 

485 """Enable or disable IPython GUI event loop integration. 

486 

487 %gui [GUINAME] 

488 

489 This magic replaces IPython's threaded shells that were activated 

490 using the (pylab/wthread/etc.) command line flags. GUI toolkits 

491 can now be enabled at runtime and keyboard 

492 interrupts should work without any problems. The following toolkits 

493 are supported: wxPython, PyQt4, PyGTK, Tk and Cocoa (OSX):: 

494 

495 %gui wx # enable wxPython event loop integration 

496 %gui qt # enable PyQt/PySide event loop integration 

497 # with the latest version available. 

498 %gui qt6 # enable PyQt6/PySide6 event loop integration 

499 %gui qt5 # enable PyQt5/PySide2 event loop integration 

500 %gui gtk # enable PyGTK event loop integration 

501 %gui gtk3 # enable Gtk3 event loop integration 

502 %gui gtk4 # enable Gtk4 event loop integration 

503 %gui tk # enable Tk event loop integration 

504 %gui osx # enable Cocoa event loop integration 

505 # (requires %matplotlib 1.1) 

506 %gui # disable all event loop integration 

507 

508 WARNING: after any of these has been called you can simply create 

509 an application object, but DO NOT start the event loop yourself, as 

510 we have already handled that. 

511 """ 

512 opts, arg = self.parse_options(parameter_s, '') 

513 if arg=='': arg = None 

514 try: 

515 return self.shell.enable_gui(arg) 

516 except Exception as e: 

517 # print simple error message, rather than traceback if we can't 

518 # hook up the GUI 

519 error(str(e)) 

520 

521 @skip_doctest 

522 @line_magic 

523 def precision(self, s=''): 

524 """Set floating point precision for pretty printing. 

525 

526 Can set either integer precision or a format string. 

527 

528 If numpy has been imported and precision is an int, 

529 numpy display precision will also be set, via ``numpy.set_printoptions``. 

530 

531 If no argument is given, defaults will be restored. 

532 

533 Examples 

534 -------- 

535 :: 

536 

537 In [1]: from math import pi 

538 

539 In [2]: %precision 3 

540 Out[2]: u'%.3f' 

541 

542 In [3]: pi 

543 Out[3]: 3.142 

544 

545 In [4]: %precision %i 

546 Out[4]: u'%i' 

547 

548 In [5]: pi 

549 Out[5]: 3 

550 

551 In [6]: %precision %e 

552 Out[6]: u'%e' 

553 

554 In [7]: pi**10 

555 Out[7]: 9.364805e+04 

556 

557 In [8]: %precision 

558 Out[8]: u'%r' 

559 

560 In [9]: pi**10 

561 Out[9]: 93648.047476082982 

562 """ 

563 ptformatter = self.shell.display_formatter.formatters['text/plain'] 

564 ptformatter.float_precision = s 

565 return ptformatter.float_format 

566 

567 @magic_arguments.magic_arguments() 

568 @magic_arguments.argument( 

569 'filename', type=str, 

570 help='Notebook name or filename' 

571 ) 

572 @line_magic 

573 def notebook(self, s): 

574 """Export and convert IPython notebooks. 

575 

576 This function can export the current IPython history to a notebook file. 

577 For example, to export the history to "foo.ipynb" do "%notebook foo.ipynb". 

578 """ 

579 args = magic_arguments.parse_argstring(self.notebook, s) 

580 outfname = os.path.expanduser(args.filename) 

581 

582 from nbformat import write, v4 

583 

584 cells = [] 

585 hist = list(self.shell.history_manager.get_range()) 

586 if(len(hist)<=1): 

587 raise ValueError('History is empty, cannot export') 

588 for session, execution_count, source in hist[:-1]: 

589 cells.append(v4.new_code_cell( 

590 execution_count=execution_count, 

591 source=source 

592 )) 

593 nb = v4.new_notebook(cells=cells) 

594 with io.open(outfname, "w", encoding="utf-8") as f: 

595 write(nb, f, version=4) 

596 

597@magics_class 

598class AsyncMagics(BasicMagics): 

599 

600 @line_magic 

601 def autoawait(self, parameter_s): 

602 """ 

603 Allow to change the status of the autoawait option. 

604 

605 This allow you to set a specific asynchronous code runner. 

606 

607 If no value is passed, print the currently used asynchronous integration 

608 and whether it is activated. 

609 

610 It can take a number of value evaluated in the following order: 

611 

612 - False/false/off deactivate autoawait integration 

613 - True/true/on activate autoawait integration using configured default 

614 loop 

615 - asyncio/curio/trio activate autoawait integration and use integration 

616 with said library. 

617 

618 - `sync` turn on the pseudo-sync integration (mostly used for 

619 `IPython.embed()` which does not run IPython with a real eventloop and 

620 deactivate running asynchronous code. Turning on Asynchronous code with 

621 the pseudo sync loop is undefined behavior and may lead IPython to crash. 

622 

623 If the passed parameter does not match any of the above and is a python 

624 identifier, get said object from user namespace and set it as the 

625 runner, and activate autoawait. 

626 

627 If the object is a fully qualified object name, attempt to import it and 

628 set it as the runner, and activate autoawait. 

629 

630 The exact behavior of autoawait is experimental and subject to change 

631 across version of IPython and Python. 

632 """ 

633 

634 param = parameter_s.strip() 

635 d = {True: "on", False: "off"} 

636 

637 if not param: 

638 print("IPython autoawait is `{}`, and set to use `{}`".format( 

639 d[self.shell.autoawait], 

640 self.shell.loop_runner 

641 )) 

642 return None 

643 

644 if param.lower() in ('false', 'off'): 

645 self.shell.autoawait = False 

646 return None 

647 if param.lower() in ('true', 'on'): 

648 self.shell.autoawait = True 

649 return None 

650 

651 if param in self.shell.loop_runner_map: 

652 self.shell.loop_runner, self.shell.autoawait = self.shell.loop_runner_map[param] 

653 return None 

654 

655 if param in self.shell.user_ns : 

656 self.shell.loop_runner = self.shell.user_ns[param] 

657 self.shell.autoawait = True 

658 return None 

659 

660 runner = import_item(param) 

661 

662 self.shell.loop_runner = runner 

663 self.shell.autoawait = True