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

Shortcuts on this page

r m x   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

262 statements  

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: 

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 __repr__(self): 

44 return self.__str__() 

45 

46 def __str__(self): 

47 return self._lsmagic() 

48 

49 def _jsonable(self): 

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

51 

52 replaces object instances with their class names as strings 

53 """ 

54 magic_dict = {} 

55 mman = self.magics_manager 

56 magics = mman.lsmagic() 

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

58 d = {} 

59 magic_dict[key] = d 

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

61 try: 

62 classname = obj.__self__.__class__.__name__ 

63 except AttributeError: 

64 classname = 'Other' 

65 

66 d[name] = classname 

67 return magic_dict 

68 

69 def _repr_json_(self): 

70 return self._jsonable() 

71 

72 

73@magics_class 

74class BasicMagics(Magics): 

75 """Magics that provide central IPython functionality. 

76 

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

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

79 

80 @skip_doctest 

81 @magic_arguments.magic_arguments() 

82 @magic_arguments.argument( 

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

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

85 ) 

86 @magic_arguments.argument( 

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

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

89 ) 

90 @magic_arguments.argument( 

91 'name', 

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

93 ) 

94 @magic_arguments.argument( 

95 'target', 

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

97 ) 

98 @magic_arguments.argument( 

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

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

101 ) 

102 @line_magic 

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

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

105 

106 Examples 

107 -------- 

108 :: 

109 

110 In [1]: %alias_magic t timeit 

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

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

113 

114 In [2]: %t -n1 pass 

115 107 ns ± 43.6 ns per loop (mean ± std. dev. of 7 runs, 1 loop each) 

116 

117 In [3]: %%t -n1 

118 ...: pass 

119 ...: 

120 107 ns ± 58.3 ns per loop (mean ± std. dev. of 7 runs, 1 loop each) 

121 

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

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

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

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

126 

127 In [6]: %whereami 

128 Out[6]: '/home/testuser' 

129 

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

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

132 """ 

133 

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

135 shell = self.shell 

136 mman = self.shell.magics_manager 

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

138 

139 target = args.target.lstrip(escs) 

140 name = args.name.lstrip(escs) 

141 

142 params = args.params 

143 if (params and 

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

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

146 params = params[1:-1] 

147 

148 # Find the requested magics. 

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

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

151 if args.line and m_line is None: 

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

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

154 if args.cell and m_cell is None: 

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

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

157 

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

159 # that are available. 

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

161 if not m_line and not m_cell: 

162 raise UsageError( 

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

164 ) 

165 args.line = bool(m_line) 

166 args.cell = bool(m_cell) 

167 

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

169 

170 if args.line: 

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

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

173 magic_escapes['line'], name, 

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

175 

176 if args.cell: 

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

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

179 magic_escapes['cell'], name, 

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

181 

182 @line_magic 

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

184 """List currently available magic functions.""" 

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

186 

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

188 """Return docstrings from magic functions.""" 

189 mman = self.shell.magics_manager 

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

191 

192 if rest: 

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

194 else: 

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

196 

197 return ''.join( 

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

199 indent(dedent(fndoc))) 

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

201 + 

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

203 indent(dedent(fndoc))) 

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

205 ) 

206 

207 @line_magic 

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

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

210 

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

212 """ 

213 

214 mode = '' 

215 try: 

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

217 except IndexError: 

218 pass 

219 

220 brief = (mode == 'brief') 

221 rest = (mode == 'rest') 

222 magic_docs = self._magic_docs(brief, rest) 

223 

224 if mode == 'latex': 

225 print(self.format_latex(magic_docs)) 

226 return 

227 else: 

228 magic_docs = format_screen(magic_docs) 

229 

230 out = [""" 

231IPython's 'magic' functions 

232=========================== 

233 

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

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

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

237 

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

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

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

241time the given statement:: 

242 

243 %timeit range(1000) 

244 

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

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

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

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

249For example:: 

250 

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

252 numpy.linalg.svd(x) 

253 

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

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

256 

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

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

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

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

261the very start of the cell. 

262 

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

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

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

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

267 

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

269to 'mydir', if it exists. 

270 

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

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

273 

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

275 magic_docs, 

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

277 str(self.lsmagic()), 

278 ] 

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

280 

281 

282 @line_magic 

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

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

285 

286 %page [options] OBJECT 

287 

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

289 

290 Options: 

291 

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

293 

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

295 

296 # Process options/args 

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

298 raw = 'r' in opts 

299 

300 oname = args and args or '_' 

301 info = self.shell._ofind(oname) 

302 if info.found: 

303 if raw: 

304 txt = str(info.obj) 

305 else: 

306 txt = pformat(info.obj) 

307 page.page(txt) 

308 else: 

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

310 

311 @line_magic 

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

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

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

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

316 print('Pretty printing has been turned', 

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

318 

319 @line_magic 

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

321 """Switch color scheme/theme globally for IPython 

322 

323 Examples 

324 -------- 

325 To get a plain black and white terminal:: 

326 

327 %colors nocolor 

328 """ 

329 

330 

331 new_theme = parameter_s.strip() 

332 if not new_theme: 

333 from IPython.utils.PyColorize import theme_table 

334 

335 raise UsageError( 

336 "%colors: you must specify a color theme. See '%colors?'." 

337 f" Available themes: {list(theme_table.keys())}" 

338 ) 

339 

340 self.shell.colors = new_theme 

341 

342 @line_magic 

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

344 """Switch modes for the exception handlers. 

345 

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

347 

348 If called without arguments, acts as a toggle. 

349 

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

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

352 True`` value set. 

353 """ 

354 

355 def xmode_switch_err(name): 

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

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

358 

359 shell = self.shell 

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

361 shell.InteractiveTB.skip_hidden = False 

362 return 

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

364 shell.InteractiveTB.skip_hidden = True 

365 return 

366 

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

368 try: 

369 shell.InteractiveTB.set_mode(mode=new_mode) 

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

371 except: 

372 raise 

373 xmode_switch_err('user') 

374 

375 @line_magic 

376 def quickref(self, arg): 

377 """ Show a quick reference sheet """ 

378 from IPython.core.usage import quick_reference 

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

380 page.page(qr) 

381 

382 @line_magic 

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

384 """Toggle doctest mode on and off. 

385 

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

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

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

389 session into doctests. It does so by: 

390 

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

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

393 - Disabling pretty-printing of output. 

394 

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

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

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

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

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

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

401 can be pasted back into an editor. 

402 

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

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

405 your existing IPython session. 

406 """ 

407 

408 # Shorthands 

409 shell = self.shell 

410 meta = shell.meta 

411 disp_formatter = self.shell.display_formatter 

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

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

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

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

416 save_dstore = dstore.setdefault 

417 

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

419 mode = save_dstore('mode',False) 

420 save_dstore('rc_pprint',ptformatter.pprint) 

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

422 save_dstore('rc_separate_out',shell.separate_out) 

423 save_dstore('rc_separate_out2',shell.separate_out2) 

424 save_dstore('rc_separate_in',shell.separate_in) 

425 save_dstore('rc_active_types',disp_formatter.active_types) 

426 

427 if not mode: 

428 # turn on 

429 

430 # Prompt separators like plain python 

431 shell.separate_in = '' 

432 shell.separate_out = '' 

433 shell.separate_out2 = '' 

434 

435 

436 ptformatter.pprint = False 

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

438 

439 shell.run_line_magic("xmode", "Plain") 

440 else: 

441 # turn off 

442 shell.separate_in = dstore.rc_separate_in 

443 

444 shell.separate_out = dstore.rc_separate_out 

445 shell.separate_out2 = dstore.rc_separate_out2 

446 

447 ptformatter.pprint = dstore.rc_pprint 

448 disp_formatter.active_types = dstore.rc_active_types 

449 

450 shell.run_line_magic("xmode", dstore.xmode) 

451 

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

453 # the mode we're switching to. 

454 shell.switch_doctest_mode(not mode) 

455 

456 # Store new mode and inform 

457 dstore.mode = bool(not mode) 

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

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

460 

461 @line_magic 

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

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

464 

465 %gui [GUINAME] 

466 

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

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

469 can now be enabled at runtime and keyboard 

470 interrupts should work without any problems. The following toolkits 

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

472 

473 %gui wx # enable wxPython event loop integration 

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

475 # with the latest version available. 

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

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

478 %gui gtk # enable PyGTK event loop integration 

479 %gui gtk3 # enable Gtk3 event loop integration 

480 %gui gtk4 # enable Gtk4 event loop integration 

481 %gui tk # enable Tk event loop integration 

482 %gui osx # enable Cocoa event loop integration 

483 # (requires %matplotlib 1.1) 

484 %gui # disable all event loop integration 

485 

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

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

488 we have already handled that. 

489 """ 

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

491 if arg=='': arg = None 

492 try: 

493 return self.shell.enable_gui(arg) 

494 except Exception as e: 

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

496 # hook up the GUI 

497 error(str(e)) 

498 

499 @skip_doctest 

500 @line_magic 

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

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

503 

504 Can set either integer precision or a format string. 

505 

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

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

508 

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

510 

511 Examples 

512 -------- 

513 :: 

514 

515 In [1]: from math import pi 

516 

517 In [2]: %precision 3 

518 Out[2]: '%.3f' 

519 

520 In [3]: pi 

521 Out[3]: 3.142 

522 

523 In [4]: %precision %i 

524 Out[4]: '%i' 

525 

526 In [5]: pi 

527 Out[5]: 3 

528 

529 In [6]: %precision %e 

530 Out[6]: '%e' 

531 

532 In [7]: pi**10 

533 Out[7]: 9.364805e+04 

534 

535 In [8]: %precision 

536 Out[8]: '%r' 

537 

538 In [9]: pi**10 

539 Out[9]: 93648.047476082982 

540 """ 

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

542 ptformatter.float_precision = s 

543 return ptformatter.float_format 

544 

545 @magic_arguments.magic_arguments() 

546 @magic_arguments.argument( 

547 'filename', type=str, 

548 help='Notebook name or filename' 

549 ) 

550 @line_magic 

551 def notebook(self, s): 

552 """Export and convert IPython notebooks. 

553 

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

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

556 """ 

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

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

559 

560 from nbformat import write, v4 

561 

562 cells = [] 

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

564 outputs = self.shell.history_manager.outputs 

565 exceptions = self.shell.history_manager.exceptions 

566 

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

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

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

570 cell = v4.new_code_cell(execution_count=execution_count, source=source) 

571 for output in outputs[execution_count]: 

572 for mime_type, data in output.bundle.items(): 

573 if output.output_type == "out_stream": 

574 cell.outputs.append(v4.new_output("stream", text=[data])) 

575 elif output.output_type == "err_stream": 

576 err_output = v4.new_output("stream", text=[data]) 

577 err_output.name = "stderr" 

578 cell.outputs.append(err_output) 

579 elif output.output_type == "execute_result": 

580 cell.outputs.append( 

581 v4.new_output( 

582 "execute_result", 

583 data={mime_type: data}, 

584 execution_count=execution_count, 

585 ) 

586 ) 

587 elif output.output_type == "display_data": 

588 cell.outputs.append( 

589 v4.new_output( 

590 "display_data", 

591 data={mime_type: data}, 

592 ) 

593 ) 

594 else: 

595 raise ValueError(f"Unknown output type: {output.output_type}") 

596 

597 # Check if this execution_count is in exceptions (current session) 

598 if execution_count in exceptions: 

599 cell.outputs.append( 

600 v4.new_output("error", **exceptions[execution_count]) 

601 ) 

602 cells.append(cell) 

603 

604 nb = v4.new_notebook(cells=cells) 

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

606 write(nb, f, version=4) 

607 

608@magics_class 

609class AsyncMagics(BasicMagics): 

610 

611 @line_magic 

612 def autoawait(self, parameter_s): 

613 """ 

614 Allow to change the status of the autoawait option. 

615 

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

617 

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

619 and whether it is activated. 

620 

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

622 

623 - False/false/off deactivate autoawait integration 

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

625 loop 

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

627 with said library. 

628 

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

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

631 deactivate running asynchronous code. Turning on Asynchronous code with 

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

633 

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

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

636 runner, and activate autoawait. 

637 

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

639 set it as the runner, and activate autoawait. 

640 

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

642 across version of IPython and Python. 

643 """ 

644 

645 param = parameter_s.strip() 

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

647 

648 if not param: 

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

650 d[self.shell.autoawait], 

651 self.shell.loop_runner 

652 )) 

653 return None 

654 

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

656 self.shell.autoawait = False 

657 return None 

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

659 self.shell.autoawait = True 

660 return None 

661 

662 if param in self.shell.loop_runner_map: 

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

664 return None 

665 

666 if param in self.shell.user_ns : 

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

668 self.shell.autoawait = True 

669 return None 

670 

671 runner = import_item(param) 

672 

673 self.shell.loop_runner = runner 

674 self.shell.autoawait = True