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

274 statements  

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

2 

3 

4from logging import error 

5import io 

6import os 

7import platform 

8from pprint import pformat 

9import sys 

10from warnings import warn 

11 

12from traitlets.utils.importstring import import_item 

13from IPython.core import magic_arguments, page 

14from IPython.core.error import UsageError 

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

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

17from IPython.testing.skipdoctest import skip_doctest 

18from IPython.utils.ipstruct import Struct 

19 

20 

21class MagicsDisplay: 

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

23 self.ignore = ignore if ignore else [] 

24 self.magics_manager = magics_manager 

25 

26 def _lsmagic(self): 

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

28 mesc = magic_escapes['line'] 

29 cesc = magic_escapes['cell'] 

30 mman = self.magics_manager 

31 magics = mman.lsmagic() 

32 out = ['Available line magics:', 

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

34 '', 

35 'Available cell magics:', 

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

37 '', 

38 mman.auto_status()] 

39 return '\n'.join(out) 

40 

41 def _repr_pretty_(self, p, cycle): 

42 p.text(self._lsmagic()) 

43 

44 def __repr__(self): 

45 return self.__str__() 

46 

47 def __str__(self): 

48 return self._lsmagic() 

49 

50 def _jsonable(self): 

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

52 

53 replaces object instances with their class names as strings 

54 """ 

55 magic_dict = {} 

56 mman = self.magics_manager 

57 magics = mman.lsmagic() 

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

59 d = {} 

60 magic_dict[key] = d 

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

62 try: 

63 classname = obj.__self__.__class__.__name__ 

64 except AttributeError: 

65 classname = 'Other' 

66 

67 d[name] = classname 

68 return magic_dict 

69 

70 def _repr_json_(self): 

71 return self._jsonable() 

72 

73 

74@magics_class 

75class BasicMagics(Magics): 

76 """Magics that provide central IPython functionality. 

77 

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

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

80 

81 @skip_doctest 

82 @magic_arguments.magic_arguments() 

83 @magic_arguments.argument( 

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

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

86 ) 

87 @magic_arguments.argument( 

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

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

90 ) 

91 @magic_arguments.argument( 

92 'name', 

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

94 ) 

95 @magic_arguments.argument( 

96 'target', 

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

98 ) 

99 @magic_arguments.argument( 

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

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

102 ) 

103 @line_magic 

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

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

106 

107 Examples 

108 -------- 

109 :: 

110 

111 In [1]: %alias_magic t timeit 

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

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

114 

115 In [2]: %t -n1 pass 

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

117 

118 In [3]: %%t -n1 

119 ...: pass 

120 ...: 

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

122 

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

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

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

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

127 

128 In [6]: %whereami 

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

130 

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

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

133 """ 

134 

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

136 shell = self.shell 

137 mman = self.shell.magics_manager 

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

139 

140 target = args.target.lstrip(escs) 

141 name = args.name.lstrip(escs) 

142 

143 params = args.params 

144 if (params and 

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

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

147 params = params[1:-1] 

148 

149 # Find the requested magics. 

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

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

152 if args.line and m_line is None: 

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

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

155 if args.cell and m_cell is None: 

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

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

158 

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

160 # that are available. 

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

162 if not m_line and not m_cell: 

163 raise UsageError( 

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

165 ) 

166 args.line = bool(m_line) 

167 args.cell = bool(m_cell) 

168 

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

170 

171 if args.line: 

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

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

174 magic_escapes['line'], name, 

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

176 

177 if args.cell: 

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

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

180 magic_escapes['cell'], name, 

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

182 

183 @line_magic 

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

185 """List currently available magic functions.""" 

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

187 

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

189 """Return docstrings from magic functions.""" 

190 mman = self.shell.magics_manager 

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

192 

193 if rest: 

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

195 else: 

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

197 

198 return ''.join( 

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

200 indent(dedent(fndoc))) 

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

202 + 

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

204 indent(dedent(fndoc))) 

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

206 ) 

207 

208 @line_magic 

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

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

211 

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

213 """ 

214 

215 mode = '' 

216 try: 

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

218 except IndexError: 

219 pass 

220 

221 brief = (mode == 'brief') 

222 rest = (mode == 'rest') 

223 magic_docs = self._magic_docs(brief, rest) 

224 

225 if mode == 'latex': 

226 print(self.format_latex(magic_docs)) 

227 return 

228 else: 

229 magic_docs = format_screen(magic_docs) 

230 

231 out = [""" 

232IPython's 'magic' functions 

233=========================== 

234 

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

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

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

238 

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

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

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

242time the given statement:: 

243 

244 %timeit range(1000) 

245 

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

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

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

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

250For example:: 

251 

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

253 numpy.linalg.svd(x) 

254 

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

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

257 

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

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

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

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

262the very start of the cell. 

263 

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

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

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

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

268 

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

270to 'mydir', if it exists. 

271 

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

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

274 

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

276 magic_docs, 

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

278 str(self.lsmagic()), 

279 ] 

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

281 

282 

283 @line_magic 

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

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

286 

287 %page [options] OBJECT 

288 

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

290 

291 Options: 

292 

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

294 

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

296 

297 # Process options/args 

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

299 raw = 'r' in opts 

300 

301 oname = args and args or '_' 

302 info = self.shell._ofind(oname) 

303 if info.found: 

304 if raw: 

305 txt = str(info.obj) 

306 else: 

307 txt = pformat(info.obj) 

308 page.page(txt) 

309 else: 

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

311 

312 @line_magic 

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

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

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

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

317 print('Pretty printing has been turned', 

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

319 

320 @line_magic 

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

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

323 

324 Examples 

325 -------- 

326 To get a plain black and white terminal:: 

327 

328 %colors nocolor 

329 """ 

330 

331 

332 new_theme = parameter_s.strip() 

333 if not new_theme: 

334 from IPython.utils.PyColorize import theme_table 

335 

336 raise UsageError( 

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

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

339 ) 

340 

341 self.shell.colors = new_theme 

342 

343 @line_magic 

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

345 """Switch modes for the exception handlers. 

346 

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

348 

349 If called without arguments, acts as a toggle. 

350 

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

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

353 True`` value set. 

354 """ 

355 

356 def xmode_switch_err(name): 

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

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

359 

360 shell = self.shell 

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

362 shell.InteractiveTB.skip_hidden = False 

363 return 

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

365 shell.InteractiveTB.skip_hidden = True 

366 return 

367 

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

369 try: 

370 shell.InteractiveTB.set_mode(mode=new_mode) 

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

372 except: 

373 raise 

374 xmode_switch_err('user') 

375 

376 @line_magic 

377 def quickref(self, arg): 

378 """ Show a quick reference sheet """ 

379 from IPython.core.usage import quick_reference 

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

381 page.page(qr) 

382 

383 @line_magic 

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

385 """Toggle doctest mode on and off. 

386 

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

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

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

390 session into doctests. It does so by: 

391 

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

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

394 - Disabling pretty-printing of output. 

395 

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

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

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

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

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

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

402 can be pasted back into an editor. 

403 

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

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

406 your existing IPython session. 

407 """ 

408 

409 # Shorthands 

410 shell = self.shell 

411 meta = shell.meta 

412 disp_formatter = self.shell.display_formatter 

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

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

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

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

417 save_dstore = dstore.setdefault 

418 

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

420 mode = save_dstore('mode',False) 

421 save_dstore('rc_pprint',ptformatter.pprint) 

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

423 save_dstore('rc_separate_out',shell.separate_out) 

424 save_dstore('rc_separate_out2',shell.separate_out2) 

425 save_dstore('rc_separate_in',shell.separate_in) 

426 save_dstore('rc_active_types',disp_formatter.active_types) 

427 

428 if not mode: 

429 # turn on 

430 

431 # Prompt separators like plain python 

432 shell.separate_in = '' 

433 shell.separate_out = '' 

434 shell.separate_out2 = '' 

435 

436 

437 ptformatter.pprint = False 

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

439 

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

441 else: 

442 # turn off 

443 shell.separate_in = dstore.rc_separate_in 

444 

445 shell.separate_out = dstore.rc_separate_out 

446 shell.separate_out2 = dstore.rc_separate_out2 

447 

448 ptformatter.pprint = dstore.rc_pprint 

449 disp_formatter.active_types = dstore.rc_active_types 

450 

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

452 

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

454 # the mode we're switching to. 

455 shell.switch_doctest_mode(not mode) 

456 

457 # Store new mode and inform 

458 dstore.mode = bool(not mode) 

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

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

461 

462 @line_magic 

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

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

465 

466 %gui [GUINAME] 

467 

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

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

470 can now be enabled at runtime and keyboard 

471 interrupts should work without any problems. The following toolkits 

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

473 

474 %gui wx # enable wxPython event loop integration 

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

476 # with the latest version available. 

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

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

479 %gui gtk # enable PyGTK event loop integration 

480 %gui gtk3 # enable Gtk3 event loop integration 

481 %gui gtk4 # enable Gtk4 event loop integration 

482 %gui tk # enable Tk event loop integration 

483 %gui osx # enable Cocoa event loop integration 

484 # (requires %matplotlib 1.1) 

485 %gui # disable all event loop integration 

486 

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

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

489 we have already handled that. 

490 """ 

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

492 if arg=='': arg = None 

493 try: 

494 return self.shell.enable_gui(arg) 

495 except Exception as e: 

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

497 # hook up the GUI 

498 error(str(e)) 

499 

500 @skip_doctest 

501 @line_magic 

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

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

504 

505 Can set either integer precision or a format string. 

506 

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

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

509 

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

511 

512 Examples 

513 -------- 

514 :: 

515 

516 In [1]: from math import pi 

517 

518 In [2]: %precision 3 

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

520 

521 In [3]: pi 

522 Out[3]: 3.142 

523 

524 In [4]: %precision %i 

525 Out[4]: '%i' 

526 

527 In [5]: pi 

528 Out[5]: 3 

529 

530 In [6]: %precision %e 

531 Out[6]: '%e' 

532 

533 In [7]: pi**10 

534 Out[7]: 9.364805e+04 

535 

536 In [8]: %precision 

537 Out[8]: '%r' 

538 

539 In [9]: pi**10 

540 Out[9]: 93648.047476082982 

541 """ 

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

543 ptformatter.float_precision = s 

544 return ptformatter.float_format 

545 

546 @magic_arguments.magic_arguments() 

547 @magic_arguments.argument( 

548 'filename', type=str, 

549 help='Notebook name or filename' 

550 ) 

551 @line_magic 

552 def notebook(self, s): 

553 """Export and convert IPython notebooks. 

554 

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

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

557 """ 

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

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

560 

561 from nbformat import write, v4 

562 

563 cells = [] 

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

565 outputs = self.shell.history_manager.outputs 

566 exceptions = self.shell.history_manager.exceptions 

567 

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

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

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

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

572 for output in outputs[execution_count]: 

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

574 if output.output_type == "out_stream": 

575 text = data if isinstance(data, list) else [data] 

576 cell.outputs.append(v4.new_output("stream", text=text)) 

577 elif output.output_type == "err_stream": 

578 text = data if isinstance(data, list) else [data] 

579 err_output = v4.new_output("stream", text=text) 

580 err_output.name = "stderr" 

581 cell.outputs.append(err_output) 

582 elif output.output_type == "execute_result": 

583 cell.outputs.append( 

584 v4.new_output( 

585 "execute_result", 

586 data={mime_type: data}, 

587 execution_count=execution_count, 

588 ) 

589 ) 

590 elif output.output_type == "display_data": 

591 cell.outputs.append( 

592 v4.new_output( 

593 "display_data", 

594 data={mime_type: data}, 

595 ) 

596 ) 

597 else: 

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

599 

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

601 if execution_count in exceptions: 

602 cell.outputs.append( 

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

604 ) 

605 cells.append(cell) 

606 

607 kernel_language_info = self._get_kernel_language_info() 

608 

609 nb = v4.new_notebook( 

610 cells=cells, 

611 metadata={ 

612 "kernelspec": { 

613 "display_name": "Python 3 (ipykernel)", 

614 "language": "python", 

615 "name": "python3", 

616 }, 

617 "language_info": kernel_language_info 

618 or { 

619 "codemirror_mode": { 

620 "name": "ipython", 

621 "version": sys.version_info[0], 

622 }, 

623 "file_extension": ".py", 

624 "mimetype": "text/x-python", 

625 "name": "python", 

626 "nbconvert_exporter": "python", 

627 "pygments_lexer": "ipython3", 

628 "version": platform.python_version(), 

629 }, 

630 }, 

631 ) 

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

633 write(nb, f, version=4) 

634 

635 def _get_kernel_language_info(self) -> dict | None: 

636 """Get language info from kernel, useful when used in Jupyter Console where kernels exist.""" 

637 if not hasattr(self.shell, "kernel"): 

638 return 

639 if not hasattr(self.shell.kernel, "language_info"): 

640 return 

641 if not isinstance(self.shell.kernel.language_info, dict): 

642 return 

643 return self.shell.kernel.language_info 

644 

645@magics_class 

646class AsyncMagics(BasicMagics): 

647 

648 @line_magic 

649 def autoawait(self, parameter_s): 

650 """ 

651 Allow to change the status of the autoawait option. 

652 

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

654 

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

656 and whether it is activated. 

657 

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

659 

660 - False/false/off deactivate autoawait integration 

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

662 loop 

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

664 with said library. 

665 

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

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

668 deactivate running asynchronous code. Turning on Asynchronous code with 

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

670 

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

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

673 runner, and activate autoawait. 

674 

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

676 set it as the runner, and activate autoawait. 

677 

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

679 across version of IPython and Python. 

680 """ 

681 

682 param = parameter_s.strip() 

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

684 

685 if not param: 

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

687 d[self.shell.autoawait], 

688 self.shell.loop_runner 

689 )) 

690 return None 

691 

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

693 self.shell.autoawait = False 

694 return None 

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

696 self.shell.autoawait = True 

697 return None 

698 

699 if param in self.shell.loop_runner_map: 

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

701 return None 

702 

703 if param in self.shell.user_ns : 

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

705 self.shell.autoawait = True 

706 return None 

707 

708 runner = import_item(param) 

709 

710 self.shell.loop_runner = runner 

711 self.shell.autoawait = True