1 """Implementation of basic magic functions.""" 2 3 4 from logging import error 5 import io 6 import os 7 from pprint import pformat 8 import sys 9 from warnings import warn 10 11 from traitlets.utils.importstring import import_item 12 from IPython.core import magic_arguments, page 13 from IPython.core.error import UsageError 14 from IPython.core.magic import Magics, magics_class, line_magic, magic_escapes 15 from IPython.utils.text import format_screen, dedent, indent 16 from IPython.testing.skipdoctest import skip_doctest 17 from IPython.utils.ipstruct import Struct 18 19 20 class 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 __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 74 class 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 = [""" 231 IPython's 'magic' functions 232 =========================== 233 234 The magic function system provides a series of functions which allow you to 235 control the behavior of IPython itself, plus a lot of system-type 236 features. There are two kinds of magics, line-oriented and cell-oriented. 237 238 Line magics are prefixed with the % character and work much like OS 239 command-line calls: they get as an argument the rest of the line, where 240 arguments are passed without parentheses or quotes. For example, this will 241 time the given statement:: 242 243 %timeit range(1000) 244 245 Cell magics are prefixed with a double %%, and they are functions that get as 246 an argument not only the rest of the line, but also the lines below it in a 247 separate argument. These magics are called with two arguments: the rest of the 248 call line and the body of the cell, consisting of the lines below the first. 249 For example:: 250 251 %%timeit x = numpy.random.randn((100, 100)) 252 numpy.linalg.svd(x) 253 254 will time the execution of the numpy svd routine, running the assignment of x 255 as part of the setup phase, which is not timed. 256 257 In a line-oriented client (the terminal or Qt console IPython), starting a new 258 input with %% will automatically enter cell mode, and IPython will continue 259 reading input until a blank line is given. In the notebook, simply type the 260 whole cell as one entity, but keep in mind that the %% escape can only be at 261 the very start of the cell. 262 263 NOTE: 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 265 magics; cell magics always require an explicit '%%' escape. By default, 266 IPython ships with automagic on, so you should only rarely need the % escape. 267 268 Example: typing '%cd mydir' (without the quotes) changes your working directory 269 to 'mydir', if it exists. 270 271 For a list of the available magic functions, use %lsmagic. For a description 272 of any of them, type %magic_name?, e.g. '%cd?'. 273 274 Currently 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 for prompts, info system and exception handlers. 322 323 Currently implemented schemes: NoColor, Linux, LightBG. 324 325 Color scheme names are not case-sensitive. 326 327 Examples 328 -------- 329 To get a plain black and white terminal:: 330 331 %colors nocolor 332 """ 333 def color_switch_err(name): 334 warn('Error changing %s color schemes.\n%s' % 335 (name, sys.exc_info()[1]), stacklevel=2) 336 337 338 new_scheme = parameter_s.strip() 339 if not new_scheme: 340 raise UsageError( 341 "%colors: you must specify a color scheme. See '%colors?'") 342 # local shortcut 343 shell = self.shell 344 345 # Set shell colour scheme 346 try: 347 shell.colors = new_scheme 348 shell.refresh_style() 349 except: 350 color_switch_err('shell') 351 352 # Set exception colors 353 try: 354 shell.InteractiveTB.set_colors(scheme = new_scheme) 355 shell.SyntaxTB.set_colors(scheme = new_scheme) 356 except: 357 color_switch_err('exception') 358 359 # Set info (for 'object?') colors 360 if shell.color_info: 361 try: 362 shell.inspector.set_active_scheme(new_scheme) 363 except: 364 color_switch_err('object inspector') 365 else: 366 shell.inspector.set_active_scheme('NoColor') 367 368 @line_magic 369 def xmode(self, parameter_s=''): 370 """Switch modes for the exception handlers. 371 372 Valid modes: Plain, Context, Verbose, and Minimal. 373 374 If called without arguments, acts as a toggle. 375 376 When in verbose mode the value `--show` (and `--hide`) 377 will respectively show (or hide) frames with ``__tracebackhide__ = 378 True`` value set. 379 """ 380 381 def xmode_switch_err(name): 382 warn('Error changing %s exception modes.\n%s' % 383 (name,sys.exc_info()[1])) 384 385 shell = self.shell 386 if parameter_s.strip() == "--show": 387 shell.InteractiveTB.skip_hidden = False 388 return 389 if parameter_s.strip() == "--hide": 390 shell.InteractiveTB.skip_hidden = True 391 return 392 393 new_mode = parameter_s.strip().capitalize() 394 try: 395 shell.InteractiveTB.set_mode(mode=new_mode) 396 print('Exception reporting mode:',shell.InteractiveTB.mode) 397 except: 398 xmode_switch_err('user') 399 400 @line_magic 401 def quickref(self, arg): 402 """ Show a quick reference sheet """ 403 from IPython.core.usage import quick_reference 404 qr = quick_reference + self._magic_docs(brief=True) 405 page.page(qr) 406 407 @line_magic 408 def doctest_mode(self, parameter_s=''): 409 """Toggle doctest mode on and off. 410 411 This mode is intended to make IPython behave as much as possible like a 412 plain Python shell, from the perspective of how its prompts, exceptions 413 and output look. This makes it easy to copy and paste parts of a 414 session into doctests. It does so by: 415 416 - Changing the prompts to the classic ``>>>`` ones. 417 - Changing the exception reporting mode to 'Plain'. 418 - Disabling pretty-printing of output. 419 420 Note that IPython also supports the pasting of code snippets that have 421 leading '>>>' and '...' prompts in them. This means that you can paste 422 doctests from files or docstrings (even if they have leading 423 whitespace), and the code will execute correctly. You can then use 424 '%history -t' to see the translated history; this will give you the 425 input after removal of all the leading prompts and whitespace, which 426 can be pasted back into an editor. 427 428 With these features, you can switch into this mode easily whenever you 429 need to do testing and changes to doctests, without having to leave 430 your existing IPython session. 431 """ 432 433 # Shorthands 434 shell = self.shell 435 meta = shell.meta 436 disp_formatter = self.shell.display_formatter 437 ptformatter = disp_formatter.formatters['text/plain'] 438 # dstore is a data store kept in the instance metadata bag to track any 439 # changes we make, so we can undo them later. 440 dstore = meta.setdefault('doctest_mode',Struct()) 441 save_dstore = dstore.setdefault 442 443 # save a few values we'll need to recover later 444 mode = save_dstore('mode',False) 445 save_dstore('rc_pprint',ptformatter.pprint) 446 save_dstore('xmode',shell.InteractiveTB.mode) 447 save_dstore('rc_separate_out',shell.separate_out) 448 save_dstore('rc_separate_out2',shell.separate_out2) 449 save_dstore('rc_separate_in',shell.separate_in) 450 save_dstore('rc_active_types',disp_formatter.active_types) 451 452 if not mode: 453 # turn on 454 455 # Prompt separators like plain python 456 shell.separate_in = '' 457 shell.separate_out = '' 458 shell.separate_out2 = '' 459 460 461 ptformatter.pprint = False 462 disp_formatter.active_types = ['text/plain'] 463 464 shell.run_line_magic("xmode", "Plain") 465 else: 466 # turn off 467 shell.separate_in = dstore.rc_separate_in 468 469 shell.separate_out = dstore.rc_separate_out 470 shell.separate_out2 = dstore.rc_separate_out2 471 472 ptformatter.pprint = dstore.rc_pprint 473 disp_formatter.active_types = dstore.rc_active_types 474 475 shell.run_line_magic("xmode", dstore.xmode) 476 477 # mode here is the state before we switch; switch_doctest_mode takes 478 # the mode we're switching to. 479 shell.switch_doctest_mode(not mode) 480 481 # Store new mode and inform 482 dstore.mode = bool(not mode) 483 mode_label = ['OFF','ON'][dstore.mode] 484 print('Doctest mode is:', mode_label) 485 486 @line_magic 487 def gui(self, parameter_s=''): 488 """Enable or disable IPython GUI event loop integration. 489 490 %gui [GUINAME] 491 492 This magic replaces IPython's threaded shells that were activated 493 using the (pylab/wthread/etc.) command line flags. GUI toolkits 494 can now be enabled at runtime and keyboard 495 interrupts should work without any problems. The following toolkits 496 are supported: wxPython, PyQt4, PyGTK, Tk and Cocoa (OSX):: 497 498 %gui wx # enable wxPython event loop integration 499 %gui qt # enable PyQt/PySide event loop integration 500 # with the latest version available. 501 %gui qt6 # enable PyQt6/PySide6 event loop integration 502 %gui qt5 # enable PyQt5/PySide2 event loop integration 503 %gui gtk # enable PyGTK event loop integration 504 %gui gtk3 # enable Gtk3 event loop integration 505 %gui gtk4 # enable Gtk4 event loop integration 506 %gui tk # enable Tk event loop integration 507 %gui osx # enable Cocoa event loop integration 508 # (requires %matplotlib 1.1) 509 %gui # disable all event loop integration 510 511 WARNING: after any of these has been called you can simply create 512 an application object, but DO NOT start the event loop yourself, as 513 we have already handled that. 514 """ 515 opts, arg = self.parse_options(parameter_s, '') 516 if arg=='': arg = None 517 try: 518 return self.shell.enable_gui(arg) 519 except Exception as e: 520 # print simple error message, rather than traceback if we can't 521 # hook up the GUI 522 error(str(e)) 523 524 @skip_doctest 525 @line_magic 526 def precision(self, s=''): 527 """Set floating point precision for pretty printing. 528 529 Can set either integer precision or a format string. 530 531 If numpy has been imported and precision is an int, 532 numpy display precision will also be set, via ``numpy.set_printoptions``. 533 534 If no argument is given, defaults will be restored. 535 536 Examples 537 -------- 538 :: 539 540 In [1]: from math import pi 541 542 In [2]: %precision 3 543 Out[2]: '%.3f' 544 545 In [3]: pi 546 Out[3]: 3.142 547 548 In [4]: %precision %i 549 Out[4]: '%i' 550 551 In [5]: pi 552 Out[5]: 3 553 554 In [6]: %precision %e 555 Out[6]: '%e' 556 557 In [7]: pi**10 558 Out[7]: 9.364805e+04 559 560 In [8]: %precision 561 Out[8]: '%r' 562 563 In [9]: pi**10 564 Out[9]: 93648.047476082982 565 """ 566 ptformatter = self.shell.display_formatter.formatters['text/plain'] 567 ptformatter.float_precision = s 568 return ptformatter.float_format 569 570 @magic_arguments.magic_arguments() 571 @magic_arguments.argument( 572 'filename', type=str, 573 help='Notebook name or filename' 574 ) 575 @line_magic 576 def notebook(self, s): 577 """Export and convert IPython notebooks. 578 579 This function can export the current IPython history to a notebook file. 580 For example, to export the history to "foo.ipynb" do "%notebook foo.ipynb". 581 """ 582 args = magic_arguments.parse_argstring(self.notebook, s) 583 outfname = os.path.expanduser(args.filename) 584 585 from nbformat import write, v4 586 587 cells = [] 588 hist = list(self.shell.history_manager.get_range()) 589 if(len(hist)<=1): 590 raise ValueError('History is empty, cannot export') 591 for session, execution_count, source in hist[:-1]: 592 cells.append(v4.new_code_cell( 593 execution_count=execution_count, 594 source=source 595 )) 596 nb = v4.new_notebook(cells=cells) 597 with io.open(outfname, "w", encoding="utf-8") as f: 598 write(nb, f, version=4) 599 600 @magics_class 601 class AsyncMagics(BasicMagics): 602 603 @line_magic 604 def autoawait(self, parameter_s): 605 """ 606 Allow to change the status of the autoawait option. 607 608 This allow you to set a specific asynchronous code runner. 609 610 If no value is passed, print the currently used asynchronous integration 611 and whether it is activated. 612 613 It can take a number of value evaluated in the following order: 614 615 - False/false/off deactivate autoawait integration 616 - True/true/on activate autoawait integration using configured default 617 loop 618 - asyncio/curio/trio activate autoawait integration and use integration 619 with said library. 620 621 - `sync` turn on the pseudo-sync integration (mostly used for 622 `IPython.embed()` which does not run IPython with a real eventloop and 623 deactivate running asynchronous code. Turning on Asynchronous code with 624 the pseudo sync loop is undefined behavior and may lead IPython to crash. 625 626 If the passed parameter does not match any of the above and is a python 627 identifier, get said object from user namespace and set it as the 628 runner, and activate autoawait. 629 630 If the object is a fully qualified object name, attempt to import it and 631 set it as the runner, and activate autoawait. 632 633 The exact behavior of autoawait is experimental and subject to change 634 across version of IPython and Python. 635 """ 636 637 param = parameter_s.strip() 638 d = {True: "on", False: "off"} 639 640 if not param: 641 print("IPython autoawait is `{}`, and set to use `{}`".format( 642 d[self.shell.autoawait], 643 self.shell.loop_runner 644 )) 645 return None 646 647 if param.lower() in ('false', 'off'): 648 self.shell.autoawait = False 649 return None 650 if param.lower() in ('true', 'on'): 651 self.shell.autoawait = True 652 return None 653 654 if param in self.shell.loop_runner_map: 655 self.shell.loop_runner, self.shell.autoawait = self.shell.loop_runner_map[param] 656 return None 657 658 if param in self.shell.user_ns : 659 self.shell.loop_runner = self.shell.user_ns[param] 660 self.shell.autoawait = True 661 return None 662 663 runner = import_item(param) 664 665 self.shell.loop_runner = runner 666 self.shell.autoawait = True 667