##// END OF EJS Templates
PR: Add needs_local_scope to debug magic (#13960)...
Matthias Bussonnier -
r28162:83f90a3f merge
parent child Browse files
Show More
@@ -1,1516 +1,1522 b''
1 1 # -*- coding: utf-8 -*-
2 2 """Implementation of execution-related magic functions."""
3 3
4 4 # Copyright (c) IPython Development Team.
5 5 # Distributed under the terms of the Modified BSD License.
6 6
7 7
8 8 import ast
9 9 import bdb
10 10 import builtins as builtin_mod
11 11 import cProfile as profile
12 12 import gc
13 13 import itertools
14 14 import math
15 15 import os
16 16 import pstats
17 17 import re
18 18 import shlex
19 19 import sys
20 20 import time
21 21 import timeit
22 22 from ast import Module
23 23 from io import StringIO
24 24 from logging import error
25 25 from pathlib import Path
26 26 from pdb import Restart
27 27 from warnings import warn
28 28
29 29 from IPython.core import magic_arguments, oinspect, page
30 30 from IPython.core.error import UsageError
31 31 from IPython.core.macro import Macro
32 32 from IPython.core.magic import (
33 33 Magics,
34 34 cell_magic,
35 35 line_cell_magic,
36 36 line_magic,
37 37 magics_class,
38 38 needs_local_scope,
39 39 no_var_expand,
40 40 output_can_be_silenced,
41 41 on_off,
42 42 )
43 43 from IPython.testing.skipdoctest import skip_doctest
44 44 from IPython.utils.capture import capture_output
45 45 from IPython.utils.contexts import preserve_keys
46 46 from IPython.utils.ipstruct import Struct
47 47 from IPython.utils.module_paths import find_mod
48 48 from IPython.utils.path import get_py_filename, shellglob
49 49 from IPython.utils.timing import clock, clock2
50 50 from IPython.core.displayhook import DisplayHook
51 51
52 52 #-----------------------------------------------------------------------------
53 53 # Magic implementation classes
54 54 #-----------------------------------------------------------------------------
55 55
56 56
57 57 class TimeitResult(object):
58 58 """
59 59 Object returned by the timeit magic with info about the run.
60 60
61 61 Contains the following attributes :
62 62
63 63 loops: (int) number of loops done per measurement
64 64 repeat: (int) number of times the measurement has been repeated
65 65 best: (float) best execution time / number
66 66 all_runs: (list of float) execution time of each run (in s)
67 67 compile_time: (float) time of statement compilation (s)
68 68
69 69 """
70 70 def __init__(self, loops, repeat, best, worst, all_runs, compile_time, precision):
71 71 self.loops = loops
72 72 self.repeat = repeat
73 73 self.best = best
74 74 self.worst = worst
75 75 self.all_runs = all_runs
76 76 self.compile_time = compile_time
77 77 self._precision = precision
78 78 self.timings = [ dt / self.loops for dt in all_runs]
79 79
80 80 @property
81 81 def average(self):
82 82 return math.fsum(self.timings) / len(self.timings)
83 83
84 84 @property
85 85 def stdev(self):
86 86 mean = self.average
87 87 return (math.fsum([(x - mean) ** 2 for x in self.timings]) / len(self.timings)) ** 0.5
88 88
89 89 def __str__(self):
90 90 pm = '+-'
91 91 if hasattr(sys.stdout, 'encoding') and sys.stdout.encoding:
92 92 try:
93 93 u'\xb1'.encode(sys.stdout.encoding)
94 94 pm = u'\xb1'
95 95 except:
96 96 pass
97 97 return "{mean} {pm} {std} per loop (mean {pm} std. dev. of {runs} run{run_plural}, {loops:,} loop{loop_plural} each)".format(
98 98 pm=pm,
99 99 runs=self.repeat,
100 100 loops=self.loops,
101 101 loop_plural="" if self.loops == 1 else "s",
102 102 run_plural="" if self.repeat == 1 else "s",
103 103 mean=_format_time(self.average, self._precision),
104 104 std=_format_time(self.stdev, self._precision),
105 105 )
106 106
107 107 def _repr_pretty_(self, p , cycle):
108 108 unic = self.__str__()
109 109 p.text(u'<TimeitResult : '+unic+u'>')
110 110
111 111
112 112 class TimeitTemplateFiller(ast.NodeTransformer):
113 113 """Fill in the AST template for timing execution.
114 114
115 115 This is quite closely tied to the template definition, which is in
116 116 :meth:`ExecutionMagics.timeit`.
117 117 """
118 118 def __init__(self, ast_setup, ast_stmt):
119 119 self.ast_setup = ast_setup
120 120 self.ast_stmt = ast_stmt
121 121
122 122 def visit_FunctionDef(self, node):
123 123 "Fill in the setup statement"
124 124 self.generic_visit(node)
125 125 if node.name == "inner":
126 126 node.body[:1] = self.ast_setup.body
127 127
128 128 return node
129 129
130 130 def visit_For(self, node):
131 131 "Fill in the statement to be timed"
132 132 if getattr(getattr(node.body[0], 'value', None), 'id', None) == 'stmt':
133 133 node.body = self.ast_stmt.body
134 134 return node
135 135
136 136
137 137 class Timer(timeit.Timer):
138 138 """Timer class that explicitly uses self.inner
139 139
140 140 which is an undocumented implementation detail of CPython,
141 141 not shared by PyPy.
142 142 """
143 143 # Timer.timeit copied from CPython 3.4.2
144 144 def timeit(self, number=timeit.default_number):
145 145 """Time 'number' executions of the main statement.
146 146
147 147 To be precise, this executes the setup statement once, and
148 148 then returns the time it takes to execute the main statement
149 149 a number of times, as a float measured in seconds. The
150 150 argument is the number of times through the loop, defaulting
151 151 to one million. The main statement, the setup statement and
152 152 the timer function to be used are passed to the constructor.
153 153 """
154 154 it = itertools.repeat(None, number)
155 155 gcold = gc.isenabled()
156 156 gc.disable()
157 157 try:
158 158 timing = self.inner(it, self.timer)
159 159 finally:
160 160 if gcold:
161 161 gc.enable()
162 162 return timing
163 163
164 164
165 165 @magics_class
166 166 class ExecutionMagics(Magics):
167 167 """Magics related to code execution, debugging, profiling, etc.
168 168
169 169 """
170 170
171 171 def __init__(self, shell):
172 172 super(ExecutionMagics, self).__init__(shell)
173 173 # Default execution function used to actually run user code.
174 174 self.default_runner = None
175 175
176 176 @skip_doctest
177 177 @no_var_expand
178 178 @line_cell_magic
179 179 def prun(self, parameter_s='', cell=None):
180 180
181 181 """Run a statement through the python code profiler.
182 182
183 183 Usage, in line mode:
184 184 %prun [options] statement
185 185
186 186 Usage, in cell mode:
187 187 %%prun [options] [statement]
188 188 code...
189 189 code...
190 190
191 191 In cell mode, the additional code lines are appended to the (possibly
192 192 empty) statement in the first line. Cell mode allows you to easily
193 193 profile multiline blocks without having to put them in a separate
194 194 function.
195 195
196 196 The given statement (which doesn't require quote marks) is run via the
197 197 python profiler in a manner similar to the profile.run() function.
198 198 Namespaces are internally managed to work correctly; profile.run
199 199 cannot be used in IPython because it makes certain assumptions about
200 200 namespaces which do not hold under IPython.
201 201
202 202 Options:
203 203
204 204 -l <limit>
205 205 you can place restrictions on what or how much of the
206 206 profile gets printed. The limit value can be:
207 207
208 208 * A string: only information for function names containing this string
209 209 is printed.
210 210
211 211 * An integer: only these many lines are printed.
212 212
213 213 * A float (between 0 and 1): this fraction of the report is printed
214 214 (for example, use a limit of 0.4 to see the topmost 40% only).
215 215
216 216 You can combine several limits with repeated use of the option. For
217 217 example, ``-l __init__ -l 5`` will print only the topmost 5 lines of
218 218 information about class constructors.
219 219
220 220 -r
221 221 return the pstats.Stats object generated by the profiling. This
222 222 object has all the information about the profile in it, and you can
223 223 later use it for further analysis or in other functions.
224 224
225 225 -s <key>
226 226 sort profile by given key. You can provide more than one key
227 227 by using the option several times: '-s key1 -s key2 -s key3...'. The
228 228 default sorting key is 'time'.
229 229
230 230 The following is copied verbatim from the profile documentation
231 231 referenced below:
232 232
233 233 When more than one key is provided, additional keys are used as
234 234 secondary criteria when the there is equality in all keys selected
235 235 before them.
236 236
237 237 Abbreviations can be used for any key names, as long as the
238 238 abbreviation is unambiguous. The following are the keys currently
239 239 defined:
240 240
241 241 ============ =====================
242 242 Valid Arg Meaning
243 243 ============ =====================
244 244 "calls" call count
245 245 "cumulative" cumulative time
246 246 "file" file name
247 247 "module" file name
248 248 "pcalls" primitive call count
249 249 "line" line number
250 250 "name" function name
251 251 "nfl" name/file/line
252 252 "stdname" standard name
253 253 "time" internal time
254 254 ============ =====================
255 255
256 256 Note that all sorts on statistics are in descending order (placing
257 257 most time consuming items first), where as name, file, and line number
258 258 searches are in ascending order (i.e., alphabetical). The subtle
259 259 distinction between "nfl" and "stdname" is that the standard name is a
260 260 sort of the name as printed, which means that the embedded line
261 261 numbers get compared in an odd way. For example, lines 3, 20, and 40
262 262 would (if the file names were the same) appear in the string order
263 263 "20" "3" and "40". In contrast, "nfl" does a numeric compare of the
264 264 line numbers. In fact, sort_stats("nfl") is the same as
265 265 sort_stats("name", "file", "line").
266 266
267 267 -T <filename>
268 268 save profile results as shown on screen to a text
269 269 file. The profile is still shown on screen.
270 270
271 271 -D <filename>
272 272 save (via dump_stats) profile statistics to given
273 273 filename. This data is in a format understood by the pstats module, and
274 274 is generated by a call to the dump_stats() method of profile
275 275 objects. The profile is still shown on screen.
276 276
277 277 -q
278 278 suppress output to the pager. Best used with -T and/or -D above.
279 279
280 280 If you want to run complete programs under the profiler's control, use
281 281 ``%run -p [prof_opts] filename.py [args to program]`` where prof_opts
282 282 contains profiler specific options as described here.
283 283
284 284 You can read the complete documentation for the profile module with::
285 285
286 286 In [1]: import profile; profile.help()
287 287
288 288 .. versionchanged:: 7.3
289 289 User variables are no longer expanded,
290 290 the magic line is always left unmodified.
291 291
292 292 """
293 293 opts, arg_str = self.parse_options(parameter_s, 'D:l:rs:T:q',
294 294 list_all=True, posix=False)
295 295 if cell is not None:
296 296 arg_str += '\n' + cell
297 297 arg_str = self.shell.transform_cell(arg_str)
298 298 return self._run_with_profiler(arg_str, opts, self.shell.user_ns)
299 299
300 300 def _run_with_profiler(self, code, opts, namespace):
301 301 """
302 302 Run `code` with profiler. Used by ``%prun`` and ``%run -p``.
303 303
304 304 Parameters
305 305 ----------
306 306 code : str
307 307 Code to be executed.
308 308 opts : Struct
309 309 Options parsed by `self.parse_options`.
310 310 namespace : dict
311 311 A dictionary for Python namespace (e.g., `self.shell.user_ns`).
312 312
313 313 """
314 314
315 315 # Fill default values for unspecified options:
316 316 opts.merge(Struct(D=[''], l=[], s=['time'], T=['']))
317 317
318 318 prof = profile.Profile()
319 319 try:
320 320 prof = prof.runctx(code, namespace, namespace)
321 321 sys_exit = ''
322 322 except SystemExit:
323 323 sys_exit = """*** SystemExit exception caught in code being profiled."""
324 324
325 325 stats = pstats.Stats(prof).strip_dirs().sort_stats(*opts.s)
326 326
327 327 lims = opts.l
328 328 if lims:
329 329 lims = [] # rebuild lims with ints/floats/strings
330 330 for lim in opts.l:
331 331 try:
332 332 lims.append(int(lim))
333 333 except ValueError:
334 334 try:
335 335 lims.append(float(lim))
336 336 except ValueError:
337 337 lims.append(lim)
338 338
339 339 # Trap output.
340 340 stdout_trap = StringIO()
341 341 stats_stream = stats.stream
342 342 try:
343 343 stats.stream = stdout_trap
344 344 stats.print_stats(*lims)
345 345 finally:
346 346 stats.stream = stats_stream
347 347
348 348 output = stdout_trap.getvalue()
349 349 output = output.rstrip()
350 350
351 351 if 'q' not in opts:
352 352 page.page(output)
353 353 print(sys_exit, end=' ')
354 354
355 355 dump_file = opts.D[0]
356 356 text_file = opts.T[0]
357 357 if dump_file:
358 358 prof.dump_stats(dump_file)
359 359 print(
360 360 f"\n*** Profile stats marshalled to file {repr(dump_file)}.{sys_exit}"
361 361 )
362 362 if text_file:
363 363 pfile = Path(text_file)
364 364 pfile.touch(exist_ok=True)
365 365 pfile.write_text(output, encoding="utf-8")
366 366
367 367 print(
368 368 f"\n*** Profile printout saved to text file {repr(text_file)}.{sys_exit}"
369 369 )
370 370
371 371 if 'r' in opts:
372 372 return stats
373 373
374 374 return None
375 375
376 376 @line_magic
377 377 def pdb(self, parameter_s=''):
378 378 """Control the automatic calling of the pdb interactive debugger.
379 379
380 380 Call as '%pdb on', '%pdb 1', '%pdb off' or '%pdb 0'. If called without
381 381 argument it works as a toggle.
382 382
383 383 When an exception is triggered, IPython can optionally call the
384 384 interactive pdb debugger after the traceback printout. %pdb toggles
385 385 this feature on and off.
386 386
387 387 The initial state of this feature is set in your configuration
388 388 file (the option is ``InteractiveShell.pdb``).
389 389
390 390 If you want to just activate the debugger AFTER an exception has fired,
391 391 without having to type '%pdb on' and rerunning your code, you can use
392 392 the %debug magic."""
393 393
394 394 par = parameter_s.strip().lower()
395 395
396 396 if par:
397 397 try:
398 398 new_pdb = {'off':0,'0':0,'on':1,'1':1}[par]
399 399 except KeyError:
400 400 print ('Incorrect argument. Use on/1, off/0, '
401 401 'or nothing for a toggle.')
402 402 return
403 403 else:
404 404 # toggle
405 405 new_pdb = not self.shell.call_pdb
406 406
407 407 # set on the shell
408 408 self.shell.call_pdb = new_pdb
409 409 print('Automatic pdb calling has been turned',on_off(new_pdb))
410 410
411 411 @magic_arguments.magic_arguments()
412 412 @magic_arguments.argument('--breakpoint', '-b', metavar='FILE:LINE',
413 413 help="""
414 414 Set break point at LINE in FILE.
415 415 """
416 416 )
417 417 @magic_arguments.argument('statement', nargs='*',
418 418 help="""
419 419 Code to run in debugger.
420 420 You can omit this in cell magic mode.
421 421 """
422 422 )
423 423 @no_var_expand
424 424 @line_cell_magic
425 def debug(self, line='', cell=None):
425 @needs_local_scope
426 def debug(self, line="", cell=None, local_ns=None):
426 427 """Activate the interactive debugger.
427 428
428 429 This magic command support two ways of activating debugger.
429 430 One is to activate debugger before executing code. This way, you
430 431 can set a break point, to step through the code from the point.
431 432 You can use this mode by giving statements to execute and optionally
432 433 a breakpoint.
433 434
434 435 The other one is to activate debugger in post-mortem mode. You can
435 436 activate this mode simply running %debug without any argument.
436 437 If an exception has just occurred, this lets you inspect its stack
437 438 frames interactively. Note that this will always work only on the last
438 439 traceback that occurred, so you must call this quickly after an
439 440 exception that you wish to inspect has fired, because if another one
440 441 occurs, it clobbers the previous one.
441 442
442 443 If you want IPython to automatically do this on every exception, see
443 444 the %pdb magic for more details.
444 445
445 446 .. versionchanged:: 7.3
446 447 When running code, user variables are no longer expanded,
447 448 the magic line is always left unmodified.
448 449
449 450 """
450 451 args = magic_arguments.parse_argstring(self.debug, line)
451 452
452 453 if not (args.breakpoint or args.statement or cell):
453 454 self._debug_post_mortem()
454 455 elif not (args.breakpoint or cell):
455 456 # If there is no breakpoints, the line is just code to execute
456 self._debug_exec(line, None)
457 self._debug_exec(line, None, local_ns)
457 458 else:
458 459 # Here we try to reconstruct the code from the output of
459 460 # parse_argstring. This might not work if the code has spaces
460 461 # For example this fails for `print("a b")`
461 462 code = "\n".join(args.statement)
462 463 if cell:
463 464 code += "\n" + cell
464 self._debug_exec(code, args.breakpoint)
465 self._debug_exec(code, args.breakpoint, local_ns)
465 466
466 467 def _debug_post_mortem(self):
467 468 self.shell.debugger(force=True)
468 469
469 def _debug_exec(self, code, breakpoint):
470 def _debug_exec(self, code, breakpoint, local_ns=None):
470 471 if breakpoint:
471 472 (filename, bp_line) = breakpoint.rsplit(':', 1)
472 473 bp_line = int(bp_line)
473 474 else:
474 475 (filename, bp_line) = (None, None)
475 self._run_with_debugger(code, self.shell.user_ns, filename, bp_line)
476 self._run_with_debugger(
477 code, self.shell.user_ns, filename, bp_line, local_ns=local_ns
478 )
476 479
477 480 @line_magic
478 481 def tb(self, s):
479 482 """Print the last traceback.
480 483
481 484 Optionally, specify an exception reporting mode, tuning the
482 485 verbosity of the traceback. By default the currently-active exception
483 486 mode is used. See %xmode for changing exception reporting modes.
484 487
485 488 Valid modes: Plain, Context, Verbose, and Minimal.
486 489 """
487 490 interactive_tb = self.shell.InteractiveTB
488 491 if s:
489 492 # Switch exception reporting mode for this one call.
490 493 # Ensure it is switched back.
491 494 def xmode_switch_err(name):
492 495 warn('Error changing %s exception modes.\n%s' %
493 496 (name,sys.exc_info()[1]))
494 497
495 498 new_mode = s.strip().capitalize()
496 499 original_mode = interactive_tb.mode
497 500 try:
498 501 try:
499 502 interactive_tb.set_mode(mode=new_mode)
500 503 except Exception:
501 504 xmode_switch_err('user')
502 505 else:
503 506 self.shell.showtraceback()
504 507 finally:
505 508 interactive_tb.set_mode(mode=original_mode)
506 509 else:
507 510 self.shell.showtraceback()
508 511
509 512 @skip_doctest
510 513 @line_magic
511 514 def run(self, parameter_s='', runner=None,
512 515 file_finder=get_py_filename):
513 516 """Run the named file inside IPython as a program.
514 517
515 518 Usage::
516 519
517 520 %run [-n -i -e -G]
518 521 [( -t [-N<N>] | -d [-b<N>] | -p [profile options] )]
519 522 ( -m mod | filename ) [args]
520 523
521 524 The filename argument should be either a pure Python script (with
522 525 extension ``.py``), or a file with custom IPython syntax (such as
523 526 magics). If the latter, the file can be either a script with ``.ipy``
524 527 extension, or a Jupyter notebook with ``.ipynb`` extension. When running
525 528 a Jupyter notebook, the output from print statements and other
526 529 displayed objects will appear in the terminal (even matplotlib figures
527 530 will open, if a terminal-compliant backend is being used). Note that,
528 531 at the system command line, the ``jupyter run`` command offers similar
529 532 functionality for executing notebooks (albeit currently with some
530 533 differences in supported options).
531 534
532 535 Parameters after the filename are passed as command-line arguments to
533 536 the program (put in sys.argv). Then, control returns to IPython's
534 537 prompt.
535 538
536 539 This is similar to running at a system prompt ``python file args``,
537 540 but with the advantage of giving you IPython's tracebacks, and of
538 541 loading all variables into your interactive namespace for further use
539 542 (unless -p is used, see below).
540 543
541 544 The file is executed in a namespace initially consisting only of
542 545 ``__name__=='__main__'`` and sys.argv constructed as indicated. It thus
543 546 sees its environment as if it were being run as a stand-alone program
544 547 (except for sharing global objects such as previously imported
545 548 modules). But after execution, the IPython interactive namespace gets
546 549 updated with all variables defined in the program (except for __name__
547 550 and sys.argv). This allows for very convenient loading of code for
548 551 interactive work, while giving each program a 'clean sheet' to run in.
549 552
550 553 Arguments are expanded using shell-like glob match. Patterns
551 554 '*', '?', '[seq]' and '[!seq]' can be used. Additionally,
552 555 tilde '~' will be expanded into user's home directory. Unlike
553 556 real shells, quotation does not suppress expansions. Use
554 557 *two* back slashes (e.g. ``\\\\*``) to suppress expansions.
555 558 To completely disable these expansions, you can use -G flag.
556 559
557 560 On Windows systems, the use of single quotes `'` when specifying
558 561 a file is not supported. Use double quotes `"`.
559 562
560 563 Options:
561 564
562 565 -n
563 566 __name__ is NOT set to '__main__', but to the running file's name
564 567 without extension (as python does under import). This allows running
565 568 scripts and reloading the definitions in them without calling code
566 569 protected by an ``if __name__ == "__main__"`` clause.
567 570
568 571 -i
569 572 run the file in IPython's namespace instead of an empty one. This
570 573 is useful if you are experimenting with code written in a text editor
571 574 which depends on variables defined interactively.
572 575
573 576 -e
574 577 ignore sys.exit() calls or SystemExit exceptions in the script
575 578 being run. This is particularly useful if IPython is being used to
576 579 run unittests, which always exit with a sys.exit() call. In such
577 580 cases you are interested in the output of the test results, not in
578 581 seeing a traceback of the unittest module.
579 582
580 583 -t
581 584 print timing information at the end of the run. IPython will give
582 585 you an estimated CPU time consumption for your script, which under
583 586 Unix uses the resource module to avoid the wraparound problems of
584 587 time.clock(). Under Unix, an estimate of time spent on system tasks
585 588 is also given (for Windows platforms this is reported as 0.0).
586 589
587 590 If -t is given, an additional ``-N<N>`` option can be given, where <N>
588 591 must be an integer indicating how many times you want the script to
589 592 run. The final timing report will include total and per run results.
590 593
591 594 For example (testing the script uniq_stable.py)::
592 595
593 596 In [1]: run -t uniq_stable
594 597
595 598 IPython CPU timings (estimated):
596 599 User : 0.19597 s.
597 600 System: 0.0 s.
598 601
599 602 In [2]: run -t -N5 uniq_stable
600 603
601 604 IPython CPU timings (estimated):
602 605 Total runs performed: 5
603 606 Times : Total Per run
604 607 User : 0.910862 s, 0.1821724 s.
605 608 System: 0.0 s, 0.0 s.
606 609
607 610 -d
608 611 run your program under the control of pdb, the Python debugger.
609 612 This allows you to execute your program step by step, watch variables,
610 613 etc. Internally, what IPython does is similar to calling::
611 614
612 615 pdb.run('execfile("YOURFILENAME")')
613 616
614 617 with a breakpoint set on line 1 of your file. You can change the line
615 618 number for this automatic breakpoint to be <N> by using the -bN option
616 619 (where N must be an integer). For example::
617 620
618 621 %run -d -b40 myscript
619 622
620 623 will set the first breakpoint at line 40 in myscript.py. Note that
621 624 the first breakpoint must be set on a line which actually does
622 625 something (not a comment or docstring) for it to stop execution.
623 626
624 627 Or you can specify a breakpoint in a different file::
625 628
626 629 %run -d -b myotherfile.py:20 myscript
627 630
628 631 When the pdb debugger starts, you will see a (Pdb) prompt. You must
629 632 first enter 'c' (without quotes) to start execution up to the first
630 633 breakpoint.
631 634
632 635 Entering 'help' gives information about the use of the debugger. You
633 636 can easily see pdb's full documentation with "import pdb;pdb.help()"
634 637 at a prompt.
635 638
636 639 -p
637 640 run program under the control of the Python profiler module (which
638 641 prints a detailed report of execution times, function calls, etc).
639 642
640 643 You can pass other options after -p which affect the behavior of the
641 644 profiler itself. See the docs for %prun for details.
642 645
643 646 In this mode, the program's variables do NOT propagate back to the
644 647 IPython interactive namespace (because they remain in the namespace
645 648 where the profiler executes them).
646 649
647 650 Internally this triggers a call to %prun, see its documentation for
648 651 details on the options available specifically for profiling.
649 652
650 653 There is one special usage for which the text above doesn't apply:
651 654 if the filename ends with .ipy[nb], the file is run as ipython script,
652 655 just as if the commands were written on IPython prompt.
653 656
654 657 -m
655 658 specify module name to load instead of script path. Similar to
656 659 the -m option for the python interpreter. Use this option last if you
657 660 want to combine with other %run options. Unlike the python interpreter
658 661 only source modules are allowed no .pyc or .pyo files.
659 662 For example::
660 663
661 664 %run -m example
662 665
663 666 will run the example module.
664 667
665 668 -G
666 669 disable shell-like glob expansion of arguments.
667 670
668 671 """
669 672
670 673 # Logic to handle issue #3664
671 674 # Add '--' after '-m <module_name>' to ignore additional args passed to a module.
672 675 if '-m' in parameter_s and '--' not in parameter_s:
673 676 argv = shlex.split(parameter_s, posix=(os.name == 'posix'))
674 677 for idx, arg in enumerate(argv):
675 678 if arg and arg.startswith('-') and arg != '-':
676 679 if arg == '-m':
677 680 argv.insert(idx + 2, '--')
678 681 break
679 682 else:
680 683 # Positional arg, break
681 684 break
682 685 parameter_s = ' '.join(shlex.quote(arg) for arg in argv)
683 686
684 687 # get arguments and set sys.argv for program to be run.
685 688 opts, arg_lst = self.parse_options(parameter_s,
686 689 'nidtN:b:pD:l:rs:T:em:G',
687 690 mode='list', list_all=1)
688 691 if "m" in opts:
689 692 modulename = opts["m"][0]
690 693 modpath = find_mod(modulename)
691 694 if modpath is None:
692 695 msg = '%r is not a valid modulename on sys.path'%modulename
693 696 raise Exception(msg)
694 697 arg_lst = [modpath] + arg_lst
695 698 try:
696 699 fpath = None # initialize to make sure fpath is in scope later
697 700 fpath = arg_lst[0]
698 701 filename = file_finder(fpath)
699 702 except IndexError as e:
700 703 msg = 'you must provide at least a filename.'
701 704 raise Exception(msg) from e
702 705 except IOError as e:
703 706 try:
704 707 msg = str(e)
705 708 except UnicodeError:
706 709 msg = e.message
707 710 if os.name == 'nt' and re.match(r"^'.*'$",fpath):
708 711 warn('For Windows, use double quotes to wrap a filename: %run "mypath\\myfile.py"')
709 712 raise Exception(msg) from e
710 713 except TypeError:
711 714 if fpath in sys.meta_path:
712 715 filename = ""
713 716 else:
714 717 raise
715 718
716 719 if filename.lower().endswith(('.ipy', '.ipynb')):
717 720 with preserve_keys(self.shell.user_ns, '__file__'):
718 721 self.shell.user_ns['__file__'] = filename
719 722 self.shell.safe_execfile_ipy(filename, raise_exceptions=True)
720 723 return
721 724
722 725 # Control the response to exit() calls made by the script being run
723 726 exit_ignore = 'e' in opts
724 727
725 728 # Make sure that the running script gets a proper sys.argv as if it
726 729 # were run from a system shell.
727 730 save_argv = sys.argv # save it for later restoring
728 731
729 732 if 'G' in opts:
730 733 args = arg_lst[1:]
731 734 else:
732 735 # tilde and glob expansion
733 736 args = shellglob(map(os.path.expanduser, arg_lst[1:]))
734 737
735 738 sys.argv = [filename] + args # put in the proper filename
736 739
737 740 if 'n' in opts:
738 741 name = Path(filename).stem
739 742 else:
740 743 name = '__main__'
741 744
742 745 if 'i' in opts:
743 746 # Run in user's interactive namespace
744 747 prog_ns = self.shell.user_ns
745 748 __name__save = self.shell.user_ns['__name__']
746 749 prog_ns['__name__'] = name
747 750 main_mod = self.shell.user_module
748 751
749 752 # Since '%run foo' emulates 'python foo.py' at the cmd line, we must
750 753 # set the __file__ global in the script's namespace
751 754 # TK: Is this necessary in interactive mode?
752 755 prog_ns['__file__'] = filename
753 756 else:
754 757 # Run in a fresh, empty namespace
755 758
756 759 # The shell MUST hold a reference to prog_ns so after %run
757 760 # exits, the python deletion mechanism doesn't zero it out
758 761 # (leaving dangling references). See interactiveshell for details
759 762 main_mod = self.shell.new_main_mod(filename, name)
760 763 prog_ns = main_mod.__dict__
761 764
762 765 # pickle fix. See interactiveshell for an explanation. But we need to
763 766 # make sure that, if we overwrite __main__, we replace it at the end
764 767 main_mod_name = prog_ns['__name__']
765 768
766 769 if main_mod_name == '__main__':
767 770 restore_main = sys.modules['__main__']
768 771 else:
769 772 restore_main = False
770 773
771 774 # This needs to be undone at the end to prevent holding references to
772 775 # every single object ever created.
773 776 sys.modules[main_mod_name] = main_mod
774 777
775 778 if 'p' in opts or 'd' in opts:
776 779 if 'm' in opts:
777 780 code = 'run_module(modulename, prog_ns)'
778 781 code_ns = {
779 782 'run_module': self.shell.safe_run_module,
780 783 'prog_ns': prog_ns,
781 784 'modulename': modulename,
782 785 }
783 786 else:
784 787 if 'd' in opts:
785 788 # allow exceptions to raise in debug mode
786 789 code = 'execfile(filename, prog_ns, raise_exceptions=True)'
787 790 else:
788 791 code = 'execfile(filename, prog_ns)'
789 792 code_ns = {
790 793 'execfile': self.shell.safe_execfile,
791 794 'prog_ns': prog_ns,
792 795 'filename': get_py_filename(filename),
793 796 }
794 797
795 798 try:
796 799 stats = None
797 800 if 'p' in opts:
798 801 stats = self._run_with_profiler(code, opts, code_ns)
799 802 else:
800 803 if 'd' in opts:
801 804 bp_file, bp_line = parse_breakpoint(
802 805 opts.get('b', ['1'])[0], filename)
803 806 self._run_with_debugger(
804 807 code, code_ns, filename, bp_line, bp_file)
805 808 else:
806 809 if 'm' in opts:
807 810 def run():
808 811 self.shell.safe_run_module(modulename, prog_ns)
809 812 else:
810 813 if runner is None:
811 814 runner = self.default_runner
812 815 if runner is None:
813 816 runner = self.shell.safe_execfile
814 817
815 818 def run():
816 819 runner(filename, prog_ns, prog_ns,
817 820 exit_ignore=exit_ignore)
818 821
819 822 if 't' in opts:
820 823 # timed execution
821 824 try:
822 825 nruns = int(opts['N'][0])
823 826 if nruns < 1:
824 827 error('Number of runs must be >=1')
825 828 return
826 829 except (KeyError):
827 830 nruns = 1
828 831 self._run_with_timing(run, nruns)
829 832 else:
830 833 # regular execution
831 834 run()
832 835
833 836 if 'i' in opts:
834 837 self.shell.user_ns['__name__'] = __name__save
835 838 else:
836 839 # update IPython interactive namespace
837 840
838 841 # Some forms of read errors on the file may mean the
839 842 # __name__ key was never set; using pop we don't have to
840 843 # worry about a possible KeyError.
841 844 prog_ns.pop('__name__', None)
842 845
843 846 with preserve_keys(self.shell.user_ns, '__file__'):
844 847 self.shell.user_ns.update(prog_ns)
845 848 finally:
846 849 # It's a bit of a mystery why, but __builtins__ can change from
847 850 # being a module to becoming a dict missing some key data after
848 851 # %run. As best I can see, this is NOT something IPython is doing
849 852 # at all, and similar problems have been reported before:
850 853 # http://coding.derkeiler.com/Archive/Python/comp.lang.python/2004-10/0188.html
851 854 # Since this seems to be done by the interpreter itself, the best
852 855 # we can do is to at least restore __builtins__ for the user on
853 856 # exit.
854 857 self.shell.user_ns['__builtins__'] = builtin_mod
855 858
856 859 # Ensure key global structures are restored
857 860 sys.argv = save_argv
858 861 if restore_main:
859 862 sys.modules['__main__'] = restore_main
860 863 if '__mp_main__' in sys.modules:
861 864 sys.modules['__mp_main__'] = restore_main
862 865 else:
863 866 # Remove from sys.modules the reference to main_mod we'd
864 867 # added. Otherwise it will trap references to objects
865 868 # contained therein.
866 869 del sys.modules[main_mod_name]
867 870
868 871 return stats
869 872
870 def _run_with_debugger(self, code, code_ns, filename=None,
871 bp_line=None, bp_file=None):
873 def _run_with_debugger(
874 self, code, code_ns, filename=None, bp_line=None, bp_file=None, local_ns=None
875 ):
872 876 """
873 877 Run `code` in debugger with a break point.
874 878
875 879 Parameters
876 880 ----------
877 881 code : str
878 882 Code to execute.
879 883 code_ns : dict
880 884 A namespace in which `code` is executed.
881 885 filename : str
882 886 `code` is ran as if it is in `filename`.
883 887 bp_line : int, optional
884 888 Line number of the break point.
885 889 bp_file : str, optional
886 890 Path to the file in which break point is specified.
887 891 `filename` is used if not given.
892 local_ns : dict, optional
893 A local namespace in which `code` is executed.
888 894
889 895 Raises
890 896 ------
891 897 UsageError
892 898 If the break point given by `bp_line` is not valid.
893 899
894 900 """
895 901 deb = self.shell.InteractiveTB.pdb
896 902 if not deb:
897 903 self.shell.InteractiveTB.pdb = self.shell.InteractiveTB.debugger_cls()
898 904 deb = self.shell.InteractiveTB.pdb
899 905
900 906 # deb.checkline() fails if deb.curframe exists but is None; it can
901 907 # handle it not existing. https://github.com/ipython/ipython/issues/10028
902 908 if hasattr(deb, 'curframe'):
903 909 del deb.curframe
904 910
905 911 # reset Breakpoint state, which is moronically kept
906 912 # in a class
907 913 bdb.Breakpoint.next = 1
908 914 bdb.Breakpoint.bplist = {}
909 915 bdb.Breakpoint.bpbynumber = [None]
910 916 deb.clear_all_breaks()
911 917 if bp_line is not None:
912 918 # Set an initial breakpoint to stop execution
913 919 maxtries = 10
914 920 bp_file = bp_file or filename
915 921 checkline = deb.checkline(bp_file, bp_line)
916 922 if not checkline:
917 923 for bp in range(bp_line + 1, bp_line + maxtries + 1):
918 924 if deb.checkline(bp_file, bp):
919 925 break
920 926 else:
921 927 msg = ("\nI failed to find a valid line to set "
922 928 "a breakpoint\n"
923 929 "after trying up to line: %s.\n"
924 930 "Please set a valid breakpoint manually "
925 931 "with the -b option." % bp)
926 932 raise UsageError(msg)
927 933 # if we find a good linenumber, set the breakpoint
928 934 deb.do_break('%s:%s' % (bp_file, bp_line))
929 935
930 936 if filename:
931 937 # Mimic Pdb._runscript(...)
932 938 deb._wait_for_mainpyfile = True
933 939 deb.mainpyfile = deb.canonic(filename)
934 940
935 941 # Start file run
936 942 print("NOTE: Enter 'c' at the %s prompt to continue execution." % deb.prompt)
937 943 try:
938 944 if filename:
939 945 # save filename so it can be used by methods on the deb object
940 946 deb._exec_filename = filename
941 947 while True:
942 948 try:
943 949 trace = sys.gettrace()
944 deb.run(code, code_ns)
950 deb.run(code, code_ns, local_ns)
945 951 except Restart:
946 952 print("Restarting")
947 953 if filename:
948 954 deb._wait_for_mainpyfile = True
949 955 deb.mainpyfile = deb.canonic(filename)
950 956 continue
951 957 else:
952 958 break
953 959 finally:
954 960 sys.settrace(trace)
955 961
956 962
957 963 except:
958 964 etype, value, tb = sys.exc_info()
959 965 # Skip three frames in the traceback: the %run one,
960 966 # one inside bdb.py, and the command-line typed by the
961 967 # user (run by exec in pdb itself).
962 968 self.shell.InteractiveTB(etype, value, tb, tb_offset=3)
963 969
964 970 @staticmethod
965 971 def _run_with_timing(run, nruns):
966 972 """
967 973 Run function `run` and print timing information.
968 974
969 975 Parameters
970 976 ----------
971 977 run : callable
972 978 Any callable object which takes no argument.
973 979 nruns : int
974 980 Number of times to execute `run`.
975 981
976 982 """
977 983 twall0 = time.perf_counter()
978 984 if nruns == 1:
979 985 t0 = clock2()
980 986 run()
981 987 t1 = clock2()
982 988 t_usr = t1[0] - t0[0]
983 989 t_sys = t1[1] - t0[1]
984 990 print("\nIPython CPU timings (estimated):")
985 991 print(" User : %10.2f s." % t_usr)
986 992 print(" System : %10.2f s." % t_sys)
987 993 else:
988 994 runs = range(nruns)
989 995 t0 = clock2()
990 996 for nr in runs:
991 997 run()
992 998 t1 = clock2()
993 999 t_usr = t1[0] - t0[0]
994 1000 t_sys = t1[1] - t0[1]
995 1001 print("\nIPython CPU timings (estimated):")
996 1002 print("Total runs performed:", nruns)
997 1003 print(" Times : %10s %10s" % ('Total', 'Per run'))
998 1004 print(" User : %10.2f s, %10.2f s." % (t_usr, t_usr / nruns))
999 1005 print(" System : %10.2f s, %10.2f s." % (t_sys, t_sys / nruns))
1000 1006 twall1 = time.perf_counter()
1001 1007 print("Wall time: %10.2f s." % (twall1 - twall0))
1002 1008
1003 1009 @skip_doctest
1004 1010 @no_var_expand
1005 1011 @line_cell_magic
1006 1012 @needs_local_scope
1007 1013 def timeit(self, line='', cell=None, local_ns=None):
1008 1014 """Time execution of a Python statement or expression
1009 1015
1010 1016 Usage, in line mode:
1011 1017 %timeit [-n<N> -r<R> [-t|-c] -q -p<P> -o] statement
1012 1018 or in cell mode:
1013 1019 %%timeit [-n<N> -r<R> [-t|-c] -q -p<P> -o] setup_code
1014 1020 code
1015 1021 code...
1016 1022
1017 1023 Time execution of a Python statement or expression using the timeit
1018 1024 module. This function can be used both as a line and cell magic:
1019 1025
1020 1026 - In line mode you can time a single-line statement (though multiple
1021 1027 ones can be chained with using semicolons).
1022 1028
1023 1029 - In cell mode, the statement in the first line is used as setup code
1024 1030 (executed but not timed) and the body of the cell is timed. The cell
1025 1031 body has access to any variables created in the setup code.
1026 1032
1027 1033 Options:
1028 1034 -n<N>: execute the given statement <N> times in a loop. If <N> is not
1029 1035 provided, <N> is determined so as to get sufficient accuracy.
1030 1036
1031 1037 -r<R>: number of repeats <R>, each consisting of <N> loops, and take the
1032 1038 best result.
1033 1039 Default: 7
1034 1040
1035 1041 -t: use time.time to measure the time, which is the default on Unix.
1036 1042 This function measures wall time.
1037 1043
1038 1044 -c: use time.clock to measure the time, which is the default on
1039 1045 Windows and measures wall time. On Unix, resource.getrusage is used
1040 1046 instead and returns the CPU user time.
1041 1047
1042 1048 -p<P>: use a precision of <P> digits to display the timing result.
1043 1049 Default: 3
1044 1050
1045 1051 -q: Quiet, do not print result.
1046 1052
1047 1053 -o: return a TimeitResult that can be stored in a variable to inspect
1048 1054 the result in more details.
1049 1055
1050 1056 .. versionchanged:: 7.3
1051 1057 User variables are no longer expanded,
1052 1058 the magic line is always left unmodified.
1053 1059
1054 1060 Examples
1055 1061 --------
1056 1062 ::
1057 1063
1058 1064 In [1]: %timeit pass
1059 1065 8.26 ns Β± 0.12 ns per loop (mean Β± std. dev. of 7 runs, 100000000 loops each)
1060 1066
1061 1067 In [2]: u = None
1062 1068
1063 1069 In [3]: %timeit u is None
1064 1070 29.9 ns Β± 0.643 ns per loop (mean Β± std. dev. of 7 runs, 10000000 loops each)
1065 1071
1066 1072 In [4]: %timeit -r 4 u == None
1067 1073
1068 1074 In [5]: import time
1069 1075
1070 1076 In [6]: %timeit -n1 time.sleep(2)
1071 1077
1072 1078 The times reported by %timeit will be slightly higher than those
1073 1079 reported by the timeit.py script when variables are accessed. This is
1074 1080 due to the fact that %timeit executes the statement in the namespace
1075 1081 of the shell, compared with timeit.py, which uses a single setup
1076 1082 statement to import function or create variables. Generally, the bias
1077 1083 does not matter as long as results from timeit.py are not mixed with
1078 1084 those from %timeit."""
1079 1085
1080 1086 opts, stmt = self.parse_options(
1081 1087 line, "n:r:tcp:qo", posix=False, strict=False, preserve_non_opts=True
1082 1088 )
1083 1089 if stmt == "" and cell is None:
1084 1090 return
1085 1091
1086 1092 timefunc = timeit.default_timer
1087 1093 number = int(getattr(opts, "n", 0))
1088 1094 default_repeat = 7 if timeit.default_repeat < 7 else timeit.default_repeat
1089 1095 repeat = int(getattr(opts, "r", default_repeat))
1090 1096 precision = int(getattr(opts, "p", 3))
1091 1097 quiet = 'q' in opts
1092 1098 return_result = 'o' in opts
1093 1099 if hasattr(opts, "t"):
1094 1100 timefunc = time.time
1095 1101 if hasattr(opts, "c"):
1096 1102 timefunc = clock
1097 1103
1098 1104 timer = Timer(timer=timefunc)
1099 1105 # this code has tight coupling to the inner workings of timeit.Timer,
1100 1106 # but is there a better way to achieve that the code stmt has access
1101 1107 # to the shell namespace?
1102 1108 transform = self.shell.transform_cell
1103 1109
1104 1110 if cell is None:
1105 1111 # called as line magic
1106 1112 ast_setup = self.shell.compile.ast_parse("pass")
1107 1113 ast_stmt = self.shell.compile.ast_parse(transform(stmt))
1108 1114 else:
1109 1115 ast_setup = self.shell.compile.ast_parse(transform(stmt))
1110 1116 ast_stmt = self.shell.compile.ast_parse(transform(cell))
1111 1117
1112 1118 ast_setup = self.shell.transform_ast(ast_setup)
1113 1119 ast_stmt = self.shell.transform_ast(ast_stmt)
1114 1120
1115 1121 # Check that these compile to valid Python code *outside* the timer func
1116 1122 # Invalid code may become valid when put inside the function & loop,
1117 1123 # which messes up error messages.
1118 1124 # https://github.com/ipython/ipython/issues/10636
1119 1125 self.shell.compile(ast_setup, "<magic-timeit-setup>", "exec")
1120 1126 self.shell.compile(ast_stmt, "<magic-timeit-stmt>", "exec")
1121 1127
1122 1128 # This codestring is taken from timeit.template - we fill it in as an
1123 1129 # AST, so that we can apply our AST transformations to the user code
1124 1130 # without affecting the timing code.
1125 1131 timeit_ast_template = ast.parse('def inner(_it, _timer):\n'
1126 1132 ' setup\n'
1127 1133 ' _t0 = _timer()\n'
1128 1134 ' for _i in _it:\n'
1129 1135 ' stmt\n'
1130 1136 ' _t1 = _timer()\n'
1131 1137 ' return _t1 - _t0\n')
1132 1138
1133 1139 timeit_ast = TimeitTemplateFiller(ast_setup, ast_stmt).visit(timeit_ast_template)
1134 1140 timeit_ast = ast.fix_missing_locations(timeit_ast)
1135 1141
1136 1142 # Track compilation time so it can be reported if too long
1137 1143 # Minimum time above which compilation time will be reported
1138 1144 tc_min = 0.1
1139 1145
1140 1146 t0 = clock()
1141 1147 code = self.shell.compile(timeit_ast, "<magic-timeit>", "exec")
1142 1148 tc = clock()-t0
1143 1149
1144 1150 ns = {}
1145 1151 glob = self.shell.user_ns
1146 1152 # handles global vars with same name as local vars. We store them in conflict_globs.
1147 1153 conflict_globs = {}
1148 1154 if local_ns and cell is None:
1149 1155 for var_name, var_val in glob.items():
1150 1156 if var_name in local_ns:
1151 1157 conflict_globs[var_name] = var_val
1152 1158 glob.update(local_ns)
1153 1159
1154 1160 exec(code, glob, ns)
1155 1161 timer.inner = ns["inner"]
1156 1162
1157 1163 # This is used to check if there is a huge difference between the
1158 1164 # best and worst timings.
1159 1165 # Issue: https://github.com/ipython/ipython/issues/6471
1160 1166 if number == 0:
1161 1167 # determine number so that 0.2 <= total time < 2.0
1162 1168 for index in range(0, 10):
1163 1169 number = 10 ** index
1164 1170 time_number = timer.timeit(number)
1165 1171 if time_number >= 0.2:
1166 1172 break
1167 1173
1168 1174 all_runs = timer.repeat(repeat, number)
1169 1175 best = min(all_runs) / number
1170 1176 worst = max(all_runs) / number
1171 1177 timeit_result = TimeitResult(number, repeat, best, worst, all_runs, tc, precision)
1172 1178
1173 1179 # Restore global vars from conflict_globs
1174 1180 if conflict_globs:
1175 1181 glob.update(conflict_globs)
1176 1182
1177 1183 if not quiet :
1178 1184 # Check best timing is greater than zero to avoid a
1179 1185 # ZeroDivisionError.
1180 1186 # In cases where the slowest timing is lesser than a microsecond
1181 1187 # we assume that it does not really matter if the fastest
1182 1188 # timing is 4 times faster than the slowest timing or not.
1183 1189 if worst > 4 * best and best > 0 and worst > 1e-6:
1184 1190 print("The slowest run took %0.2f times longer than the "
1185 1191 "fastest. This could mean that an intermediate result "
1186 1192 "is being cached." % (worst / best))
1187 1193
1188 1194 print( timeit_result )
1189 1195
1190 1196 if tc > tc_min:
1191 1197 print("Compiler time: %.2f s" % tc)
1192 1198 if return_result:
1193 1199 return timeit_result
1194 1200
1195 1201 @skip_doctest
1196 1202 @no_var_expand
1197 1203 @needs_local_scope
1198 1204 @line_cell_magic
1199 1205 @output_can_be_silenced
1200 1206 def time(self,line='', cell=None, local_ns=None):
1201 1207 """Time execution of a Python statement or expression.
1202 1208
1203 1209 The CPU and wall clock times are printed, and the value of the
1204 1210 expression (if any) is returned. Note that under Win32, system time
1205 1211 is always reported as 0, since it can not be measured.
1206 1212
1207 1213 This function can be used both as a line and cell magic:
1208 1214
1209 1215 - In line mode you can time a single-line statement (though multiple
1210 1216 ones can be chained with using semicolons).
1211 1217
1212 1218 - In cell mode, you can time the cell body (a directly
1213 1219 following statement raises an error).
1214 1220
1215 1221 This function provides very basic timing functionality. Use the timeit
1216 1222 magic for more control over the measurement.
1217 1223
1218 1224 .. versionchanged:: 7.3
1219 1225 User variables are no longer expanded,
1220 1226 the magic line is always left unmodified.
1221 1227
1222 1228 Examples
1223 1229 --------
1224 1230 ::
1225 1231
1226 1232 In [1]: %time 2**128
1227 1233 CPU times: user 0.00 s, sys: 0.00 s, total: 0.00 s
1228 1234 Wall time: 0.00
1229 1235 Out[1]: 340282366920938463463374607431768211456L
1230 1236
1231 1237 In [2]: n = 1000000
1232 1238
1233 1239 In [3]: %time sum(range(n))
1234 1240 CPU times: user 1.20 s, sys: 0.05 s, total: 1.25 s
1235 1241 Wall time: 1.37
1236 1242 Out[3]: 499999500000L
1237 1243
1238 1244 In [4]: %time print 'hello world'
1239 1245 hello world
1240 1246 CPU times: user 0.00 s, sys: 0.00 s, total: 0.00 s
1241 1247 Wall time: 0.00
1242 1248
1243 1249 .. note::
1244 1250 The time needed by Python to compile the given expression will be
1245 1251 reported if it is more than 0.1s.
1246 1252
1247 1253 In the example below, the actual exponentiation is done by Python
1248 1254 at compilation time, so while the expression can take a noticeable
1249 1255 amount of time to compute, that time is purely due to the
1250 1256 compilation::
1251 1257
1252 1258 In [5]: %time 3**9999;
1253 1259 CPU times: user 0.00 s, sys: 0.00 s, total: 0.00 s
1254 1260 Wall time: 0.00 s
1255 1261
1256 1262 In [6]: %time 3**999999;
1257 1263 CPU times: user 0.00 s, sys: 0.00 s, total: 0.00 s
1258 1264 Wall time: 0.00 s
1259 1265 Compiler : 0.78 s
1260 1266 """
1261 1267 # fail immediately if the given expression can't be compiled
1262 1268
1263 1269 if line and cell:
1264 1270 raise UsageError("Can't use statement directly after '%%time'!")
1265 1271
1266 1272 if cell:
1267 1273 expr = self.shell.transform_cell(cell)
1268 1274 else:
1269 1275 expr = self.shell.transform_cell(line)
1270 1276
1271 1277 # Minimum time above which parse time will be reported
1272 1278 tp_min = 0.1
1273 1279
1274 1280 t0 = clock()
1275 1281 expr_ast = self.shell.compile.ast_parse(expr)
1276 1282 tp = clock()-t0
1277 1283
1278 1284 # Apply AST transformations
1279 1285 expr_ast = self.shell.transform_ast(expr_ast)
1280 1286
1281 1287 # Minimum time above which compilation time will be reported
1282 1288 tc_min = 0.1
1283 1289
1284 1290 expr_val=None
1285 1291 if len(expr_ast.body)==1 and isinstance(expr_ast.body[0], ast.Expr):
1286 1292 mode = 'eval'
1287 1293 source = '<timed eval>'
1288 1294 expr_ast = ast.Expression(expr_ast.body[0].value)
1289 1295 else:
1290 1296 mode = 'exec'
1291 1297 source = '<timed exec>'
1292 1298 # multi-line %%time case
1293 1299 if len(expr_ast.body) > 1 and isinstance(expr_ast.body[-1], ast.Expr):
1294 1300 expr_val= expr_ast.body[-1]
1295 1301 expr_ast = expr_ast.body[:-1]
1296 1302 expr_ast = Module(expr_ast, [])
1297 1303 expr_val = ast.Expression(expr_val.value)
1298 1304
1299 1305 t0 = clock()
1300 1306 code = self.shell.compile(expr_ast, source, mode)
1301 1307 tc = clock()-t0
1302 1308
1303 1309 # skew measurement as little as possible
1304 1310 glob = self.shell.user_ns
1305 1311 wtime = time.time
1306 1312 # time execution
1307 1313 wall_st = wtime()
1308 1314 if mode=='eval':
1309 1315 st = clock2()
1310 1316 try:
1311 1317 out = eval(code, glob, local_ns)
1312 1318 except:
1313 1319 self.shell.showtraceback()
1314 1320 return
1315 1321 end = clock2()
1316 1322 else:
1317 1323 st = clock2()
1318 1324 try:
1319 1325 exec(code, glob, local_ns)
1320 1326 out=None
1321 1327 # multi-line %%time case
1322 1328 if expr_val is not None:
1323 1329 code_2 = self.shell.compile(expr_val, source, 'eval')
1324 1330 out = eval(code_2, glob, local_ns)
1325 1331 except:
1326 1332 self.shell.showtraceback()
1327 1333 return
1328 1334 end = clock2()
1329 1335
1330 1336 wall_end = wtime()
1331 1337 # Compute actual times and report
1332 1338 wall_time = wall_end - wall_st
1333 1339 cpu_user = end[0] - st[0]
1334 1340 cpu_sys = end[1] - st[1]
1335 1341 cpu_tot = cpu_user + cpu_sys
1336 1342 # On windows cpu_sys is always zero, so only total is displayed
1337 1343 if sys.platform != "win32":
1338 1344 print(
1339 1345 f"CPU times: user {_format_time(cpu_user)}, sys: {_format_time(cpu_sys)}, total: {_format_time(cpu_tot)}"
1340 1346 )
1341 1347 else:
1342 1348 print(f"CPU times: total: {_format_time(cpu_tot)}")
1343 1349 print(f"Wall time: {_format_time(wall_time)}")
1344 1350 if tc > tc_min:
1345 1351 print(f"Compiler : {_format_time(tc)}")
1346 1352 if tp > tp_min:
1347 1353 print(f"Parser : {_format_time(tp)}")
1348 1354 return out
1349 1355
1350 1356 @skip_doctest
1351 1357 @line_magic
1352 1358 def macro(self, parameter_s=''):
1353 1359 """Define a macro for future re-execution. It accepts ranges of history,
1354 1360 filenames or string objects.
1355 1361
1356 1362 Usage:\\
1357 1363 %macro [options] name n1-n2 n3-n4 ... n5 .. n6 ...
1358 1364
1359 1365 Options:
1360 1366
1361 1367 -r: use 'raw' input. By default, the 'processed' history is used,
1362 1368 so that magics are loaded in their transformed version to valid
1363 1369 Python. If this option is given, the raw input as typed at the
1364 1370 command line is used instead.
1365 1371
1366 1372 -q: quiet macro definition. By default, a tag line is printed
1367 1373 to indicate the macro has been created, and then the contents of
1368 1374 the macro are printed. If this option is given, then no printout
1369 1375 is produced once the macro is created.
1370 1376
1371 1377 This will define a global variable called `name` which is a string
1372 1378 made of joining the slices and lines you specify (n1,n2,... numbers
1373 1379 above) from your input history into a single string. This variable
1374 1380 acts like an automatic function which re-executes those lines as if
1375 1381 you had typed them. You just type 'name' at the prompt and the code
1376 1382 executes.
1377 1383
1378 1384 The syntax for indicating input ranges is described in %history.
1379 1385
1380 1386 Note: as a 'hidden' feature, you can also use traditional python slice
1381 1387 notation, where N:M means numbers N through M-1.
1382 1388
1383 1389 For example, if your history contains (print using %hist -n )::
1384 1390
1385 1391 44: x=1
1386 1392 45: y=3
1387 1393 46: z=x+y
1388 1394 47: print x
1389 1395 48: a=5
1390 1396 49: print 'x',x,'y',y
1391 1397
1392 1398 you can create a macro with lines 44 through 47 (included) and line 49
1393 1399 called my_macro with::
1394 1400
1395 1401 In [55]: %macro my_macro 44-47 49
1396 1402
1397 1403 Now, typing `my_macro` (without quotes) will re-execute all this code
1398 1404 in one pass.
1399 1405
1400 1406 You don't need to give the line-numbers in order, and any given line
1401 1407 number can appear multiple times. You can assemble macros with any
1402 1408 lines from your input history in any order.
1403 1409
1404 1410 The macro is a simple object which holds its value in an attribute,
1405 1411 but IPython's display system checks for macros and executes them as
1406 1412 code instead of printing them when you type their name.
1407 1413
1408 1414 You can view a macro's contents by explicitly printing it with::
1409 1415
1410 1416 print macro_name
1411 1417
1412 1418 """
1413 1419 opts,args = self.parse_options(parameter_s,'rq',mode='list')
1414 1420 if not args: # List existing macros
1415 1421 return sorted(k for k,v in self.shell.user_ns.items() if isinstance(v, Macro))
1416 1422 if len(args) == 1:
1417 1423 raise UsageError(
1418 1424 "%macro insufficient args; usage '%macro name n1-n2 n3-4...")
1419 1425 name, codefrom = args[0], " ".join(args[1:])
1420 1426
1421 1427 #print 'rng',ranges # dbg
1422 1428 try:
1423 1429 lines = self.shell.find_user_code(codefrom, 'r' in opts)
1424 1430 except (ValueError, TypeError) as e:
1425 1431 print(e.args[0])
1426 1432 return
1427 1433 macro = Macro(lines)
1428 1434 self.shell.define_macro(name, macro)
1429 1435 if not ( 'q' in opts) :
1430 1436 print('Macro `%s` created. To execute, type its name (without quotes).' % name)
1431 1437 print('=== Macro contents: ===')
1432 1438 print(macro, end=' ')
1433 1439
1434 1440 @magic_arguments.magic_arguments()
1435 1441 @magic_arguments.argument('output', type=str, default='', nargs='?',
1436 1442 help="""The name of the variable in which to store output.
1437 1443 This is a utils.io.CapturedIO object with stdout/err attributes
1438 1444 for the text of the captured output.
1439 1445
1440 1446 CapturedOutput also has a show() method for displaying the output,
1441 1447 and __call__ as well, so you can use that to quickly display the
1442 1448 output.
1443 1449
1444 1450 If unspecified, captured output is discarded.
1445 1451 """
1446 1452 )
1447 1453 @magic_arguments.argument('--no-stderr', action="store_true",
1448 1454 help="""Don't capture stderr."""
1449 1455 )
1450 1456 @magic_arguments.argument('--no-stdout', action="store_true",
1451 1457 help="""Don't capture stdout."""
1452 1458 )
1453 1459 @magic_arguments.argument('--no-display', action="store_true",
1454 1460 help="""Don't capture IPython's rich display."""
1455 1461 )
1456 1462 @cell_magic
1457 1463 def capture(self, line, cell):
1458 1464 """run the cell, capturing stdout, stderr, and IPython's rich display() calls."""
1459 1465 args = magic_arguments.parse_argstring(self.capture, line)
1460 1466 out = not args.no_stdout
1461 1467 err = not args.no_stderr
1462 1468 disp = not args.no_display
1463 1469 with capture_output(out, err, disp) as io:
1464 1470 self.shell.run_cell(cell)
1465 1471 if DisplayHook.semicolon_at_end_of_expression(cell):
1466 1472 if args.output in self.shell.user_ns:
1467 1473 del self.shell.user_ns[args.output]
1468 1474 elif args.output:
1469 1475 self.shell.user_ns[args.output] = io
1470 1476
1471 1477 def parse_breakpoint(text, current_file):
1472 1478 '''Returns (file, line) for file:line and (current_file, line) for line'''
1473 1479 colon = text.find(':')
1474 1480 if colon == -1:
1475 1481 return current_file, int(text)
1476 1482 else:
1477 1483 return text[:colon], int(text[colon+1:])
1478 1484
1479 1485 def _format_time(timespan, precision=3):
1480 1486 """Formats the timespan in a human readable form"""
1481 1487
1482 1488 if timespan >= 60.0:
1483 1489 # we have more than a minute, format that in a human readable form
1484 1490 # Idea from http://snipplr.com/view/5713/
1485 1491 parts = [("d", 60*60*24),("h", 60*60),("min", 60), ("s", 1)]
1486 1492 time = []
1487 1493 leftover = timespan
1488 1494 for suffix, length in parts:
1489 1495 value = int(leftover / length)
1490 1496 if value > 0:
1491 1497 leftover = leftover % length
1492 1498 time.append(u'%s%s' % (str(value), suffix))
1493 1499 if leftover < 1:
1494 1500 break
1495 1501 return " ".join(time)
1496 1502
1497 1503
1498 1504 # Unfortunately the unicode 'micro' symbol can cause problems in
1499 1505 # certain terminals.
1500 1506 # See bug: https://bugs.launchpad.net/ipython/+bug/348466
1501 1507 # Try to prevent crashes by being more secure than it needs to
1502 1508 # E.g. eclipse is able to print a Β΅, but has no sys.stdout.encoding set.
1503 1509 units = [u"s", u"ms",u'us',"ns"] # the save value
1504 1510 if hasattr(sys.stdout, 'encoding') and sys.stdout.encoding:
1505 1511 try:
1506 1512 u'\xb5'.encode(sys.stdout.encoding)
1507 1513 units = [u"s", u"ms",u'\xb5s',"ns"]
1508 1514 except:
1509 1515 pass
1510 1516 scaling = [1, 1e3, 1e6, 1e9]
1511 1517
1512 1518 if timespan > 0.0:
1513 1519 order = min(-int(math.floor(math.log10(timespan)) // 3), 3)
1514 1520 else:
1515 1521 order = 3
1516 1522 return u"%.*g %s" % (precision, timespan * scaling[order], units[order])
@@ -1,1531 +1,1548 b''
1 1 # -*- coding: utf-8 -*-
2 2 """Tests for various magic functions."""
3 3
4 4 import gc
5 5 import io
6 6 import os
7 7 import re
8 8 import shlex
9 9 import sys
10 10 import warnings
11 11 from importlib import invalidate_caches
12 12 from io import StringIO
13 13 from pathlib import Path
14 14 from textwrap import dedent
15 15 from unittest import TestCase, mock
16 16
17 17 import pytest
18 18
19 19 from IPython import get_ipython
20 20 from IPython.core import magic
21 21 from IPython.core.error import UsageError
22 22 from IPython.core.magic import (
23 23 Magics,
24 24 cell_magic,
25 25 line_magic,
26 26 magics_class,
27 27 register_cell_magic,
28 28 register_line_magic,
29 29 )
30 30 from IPython.core.magics import code, execution, logging, osm, script
31 31 from IPython.testing import decorators as dec
32 32 from IPython.testing import tools as tt
33 33 from IPython.utils.io import capture_output
34 34 from IPython.utils.process import find_cmd
35 35 from IPython.utils.tempdir import TemporaryDirectory, TemporaryWorkingDirectory
36 36 from IPython.utils.syspathcontext import prepended_to_syspath
37 37
38 38 from .test_debugger import PdbTestInput
39 39
40 40 from tempfile import NamedTemporaryFile
41 41
42 42 @magic.magics_class
43 43 class DummyMagics(magic.Magics): pass
44 44
45 45 def test_extract_code_ranges():
46 46 instr = "1 3 5-6 7-9 10:15 17: :10 10- -13 :"
47 47 expected = [
48 48 (0, 1),
49 49 (2, 3),
50 50 (4, 6),
51 51 (6, 9),
52 52 (9, 14),
53 53 (16, None),
54 54 (None, 9),
55 55 (9, None),
56 56 (None, 13),
57 57 (None, None),
58 58 ]
59 59 actual = list(code.extract_code_ranges(instr))
60 60 assert actual == expected
61 61
62 62 def test_extract_symbols():
63 63 source = """import foo\na = 10\ndef b():\n return 42\n\n\nclass A: pass\n\n\n"""
64 64 symbols_args = ["a", "b", "A", "A,b", "A,a", "z"]
65 65 expected = [([], ['a']),
66 66 (["def b():\n return 42\n"], []),
67 67 (["class A: pass\n"], []),
68 68 (["class A: pass\n", "def b():\n return 42\n"], []),
69 69 (["class A: pass\n"], ['a']),
70 70 ([], ['z'])]
71 71 for symbols, exp in zip(symbols_args, expected):
72 72 assert code.extract_symbols(source, symbols) == exp
73 73
74 74
75 75 def test_extract_symbols_raises_exception_with_non_python_code():
76 76 source = ("=begin A Ruby program :)=end\n"
77 77 "def hello\n"
78 78 "puts 'Hello world'\n"
79 79 "end")
80 80 with pytest.raises(SyntaxError):
81 81 code.extract_symbols(source, "hello")
82 82
83 83
84 84 def test_magic_not_found():
85 85 # magic not found raises UsageError
86 86 with pytest.raises(UsageError):
87 87 _ip.run_line_magic("doesntexist", "")
88 88
89 89 # ensure result isn't success when a magic isn't found
90 90 result = _ip.run_cell('%doesntexist')
91 91 assert isinstance(result.error_in_exec, UsageError)
92 92
93 93
94 94 def test_cell_magic_not_found():
95 95 # magic not found raises UsageError
96 96 with pytest.raises(UsageError):
97 97 _ip.run_cell_magic('doesntexist', 'line', 'cell')
98 98
99 99 # ensure result isn't success when a magic isn't found
100 100 result = _ip.run_cell('%%doesntexist')
101 101 assert isinstance(result.error_in_exec, UsageError)
102 102
103 103
104 104 def test_magic_error_status():
105 105 def fail(shell):
106 106 1/0
107 107 _ip.register_magic_function(fail)
108 108 result = _ip.run_cell('%fail')
109 109 assert isinstance(result.error_in_exec, ZeroDivisionError)
110 110
111 111
112 112 def test_config():
113 113 """ test that config magic does not raise
114 114 can happen if Configurable init is moved too early into
115 115 Magics.__init__ as then a Config object will be registered as a
116 116 magic.
117 117 """
118 118 ## should not raise.
119 119 _ip.run_line_magic("config", "")
120 120
121 121
122 122 def test_config_available_configs():
123 123 """ test that config magic prints available configs in unique and
124 124 sorted order. """
125 125 with capture_output() as captured:
126 126 _ip.run_line_magic("config", "")
127 127
128 128 stdout = captured.stdout
129 129 config_classes = stdout.strip().split('\n')[1:]
130 130 assert config_classes == sorted(set(config_classes))
131 131
132 132 def test_config_print_class():
133 133 """ test that config with a classname prints the class's options. """
134 134 with capture_output() as captured:
135 135 _ip.run_line_magic("config", "TerminalInteractiveShell")
136 136
137 137 stdout = captured.stdout
138 138 assert re.match(
139 139 "TerminalInteractiveShell.* options", stdout.splitlines()[0]
140 140 ), f"{stdout}\n\n1st line of stdout not like 'TerminalInteractiveShell.* options'"
141 141
142 142
143 143 def test_rehashx():
144 144 # clear up everything
145 145 _ip.alias_manager.clear_aliases()
146 146 del _ip.db['syscmdlist']
147 147
148 148 _ip.run_line_magic("rehashx", "")
149 149 # Practically ALL ipython development systems will have more than 10 aliases
150 150
151 151 assert len(_ip.alias_manager.aliases) > 10
152 152 for name, cmd in _ip.alias_manager.aliases:
153 153 # we must strip dots from alias names
154 154 assert "." not in name
155 155
156 156 # rehashx must fill up syscmdlist
157 157 scoms = _ip.db['syscmdlist']
158 158 assert len(scoms) > 10
159 159
160 160
161 161 def test_magic_parse_options():
162 162 """Test that we don't mangle paths when parsing magic options."""
163 163 ip = get_ipython()
164 164 path = 'c:\\x'
165 165 m = DummyMagics(ip)
166 166 opts = m.parse_options('-f %s' % path,'f:')[0]
167 167 # argv splitting is os-dependent
168 168 if os.name == 'posix':
169 169 expected = 'c:x'
170 170 else:
171 171 expected = path
172 172 assert opts["f"] == expected
173 173
174 174
175 175 def test_magic_parse_long_options():
176 176 """Magic.parse_options can handle --foo=bar long options"""
177 177 ip = get_ipython()
178 178 m = DummyMagics(ip)
179 179 opts, _ = m.parse_options("--foo --bar=bubble", "a", "foo", "bar=")
180 180 assert "foo" in opts
181 181 assert "bar" in opts
182 182 assert opts["bar"] == "bubble"
183 183
184 184
185 185 def doctest_hist_f():
186 186 """Test %hist -f with temporary filename.
187 187
188 188 In [9]: import tempfile
189 189
190 190 In [10]: tfile = tempfile.mktemp('.py','tmp-ipython-')
191 191
192 192 In [11]: %hist -nl -f $tfile 3
193 193
194 194 In [13]: import os; os.unlink(tfile)
195 195 """
196 196
197 197
198 198 def doctest_hist_op():
199 199 """Test %hist -op
200 200
201 201 In [1]: class b(float):
202 202 ...: pass
203 203 ...:
204 204
205 205 In [2]: class s(object):
206 206 ...: def __str__(self):
207 207 ...: return 's'
208 208 ...:
209 209
210 210 In [3]:
211 211
212 212 In [4]: class r(b):
213 213 ...: def __repr__(self):
214 214 ...: return 'r'
215 215 ...:
216 216
217 217 In [5]: class sr(s,r): pass
218 218 ...:
219 219
220 220 In [6]:
221 221
222 222 In [7]: bb=b()
223 223
224 224 In [8]: ss=s()
225 225
226 226 In [9]: rr=r()
227 227
228 228 In [10]: ssrr=sr()
229 229
230 230 In [11]: 4.5
231 231 Out[11]: 4.5
232 232
233 233 In [12]: str(ss)
234 234 Out[12]: 's'
235 235
236 236 In [13]:
237 237
238 238 In [14]: %hist -op
239 239 >>> class b:
240 240 ... pass
241 241 ...
242 242 >>> class s(b):
243 243 ... def __str__(self):
244 244 ... return 's'
245 245 ...
246 246 >>>
247 247 >>> class r(b):
248 248 ... def __repr__(self):
249 249 ... return 'r'
250 250 ...
251 251 >>> class sr(s,r): pass
252 252 >>>
253 253 >>> bb=b()
254 254 >>> ss=s()
255 255 >>> rr=r()
256 256 >>> ssrr=sr()
257 257 >>> 4.5
258 258 4.5
259 259 >>> str(ss)
260 260 's'
261 261 >>>
262 262 """
263 263
264 264 def test_hist_pof():
265 265 ip = get_ipython()
266 266 ip.run_cell("1+2", store_history=True)
267 267 #raise Exception(ip.history_manager.session_number)
268 268 #raise Exception(list(ip.history_manager._get_range_session()))
269 269 with TemporaryDirectory() as td:
270 270 tf = os.path.join(td, 'hist.py')
271 271 ip.run_line_magic('history', '-pof %s' % tf)
272 272 assert os.path.isfile(tf)
273 273
274 274
275 275 def test_macro():
276 276 ip = get_ipython()
277 277 ip.history_manager.reset() # Clear any existing history.
278 278 cmds = ["a=1", "def b():\n return a**2", "print(a,b())"]
279 279 for i, cmd in enumerate(cmds, start=1):
280 280 ip.history_manager.store_inputs(i, cmd)
281 281 ip.run_line_magic("macro", "test 1-3")
282 282 assert ip.user_ns["test"].value == "\n".join(cmds) + "\n"
283 283
284 284 # List macros
285 285 assert "test" in ip.run_line_magic("macro", "")
286 286
287 287
288 288 def test_macro_run():
289 289 """Test that we can run a multi-line macro successfully."""
290 290 ip = get_ipython()
291 291 ip.history_manager.reset()
292 292 cmds = ["a=10", "a+=1", "print(a)", "%macro test 2-3"]
293 293 for cmd in cmds:
294 294 ip.run_cell(cmd, store_history=True)
295 295 assert ip.user_ns["test"].value == "a+=1\nprint(a)\n"
296 296 with tt.AssertPrints("12"):
297 297 ip.run_cell("test")
298 298 with tt.AssertPrints("13"):
299 299 ip.run_cell("test")
300 300
301 301
302 302 def test_magic_magic():
303 303 """Test %magic"""
304 304 ip = get_ipython()
305 305 with capture_output() as captured:
306 306 ip.run_line_magic("magic", "")
307 307
308 308 stdout = captured.stdout
309 309 assert "%magic" in stdout
310 310 assert "IPython" in stdout
311 311 assert "Available" in stdout
312 312
313 313
314 314 @dec.skipif_not_numpy
315 315 def test_numpy_reset_array_undec():
316 316 "Test '%reset array' functionality"
317 317 _ip.ex("import numpy as np")
318 318 _ip.ex("a = np.empty(2)")
319 319 assert "a" in _ip.user_ns
320 320 _ip.run_line_magic("reset", "-f array")
321 321 assert "a" not in _ip.user_ns
322 322
323 323
324 324 def test_reset_out():
325 325 "Test '%reset out' magic"
326 326 _ip.run_cell("parrot = 'dead'", store_history=True)
327 327 # test '%reset -f out', make an Out prompt
328 328 _ip.run_cell("parrot", store_history=True)
329 329 assert "dead" in [_ip.user_ns[x] for x in ("_", "__", "___")]
330 330 _ip.run_line_magic("reset", "-f out")
331 331 assert "dead" not in [_ip.user_ns[x] for x in ("_", "__", "___")]
332 332 assert len(_ip.user_ns["Out"]) == 0
333 333
334 334
335 335 def test_reset_in():
336 336 "Test '%reset in' magic"
337 337 # test '%reset -f in'
338 338 _ip.run_cell("parrot", store_history=True)
339 339 assert "parrot" in [_ip.user_ns[x] for x in ("_i", "_ii", "_iii")]
340 340 _ip.run_line_magic("reset", "-f in")
341 341 assert "parrot" not in [_ip.user_ns[x] for x in ("_i", "_ii", "_iii")]
342 342 assert len(set(_ip.user_ns["In"])) == 1
343 343
344 344
345 345 def test_reset_dhist():
346 346 "Test '%reset dhist' magic"
347 347 _ip.run_cell("tmp = [d for d in _dh]") # copy before clearing
348 348 _ip.run_line_magic("cd", os.path.dirname(pytest.__file__))
349 349 _ip.run_line_magic("cd", "-")
350 350 assert len(_ip.user_ns["_dh"]) > 0
351 351 _ip.run_line_magic("reset", "-f dhist")
352 352 assert len(_ip.user_ns["_dh"]) == 0
353 353 _ip.run_cell("_dh = [d for d in tmp]") # restore
354 354
355 355
356 356 def test_reset_in_length():
357 357 "Test that '%reset in' preserves In[] length"
358 358 _ip.run_cell("print 'foo'")
359 359 _ip.run_cell("reset -f in")
360 360 assert len(_ip.user_ns["In"]) == _ip.displayhook.prompt_count + 1
361 361
362 362
363 363 class TestResetErrors(TestCase):
364 364
365 365 def test_reset_redefine(self):
366 366
367 367 @magics_class
368 368 class KernelMagics(Magics):
369 369 @line_magic
370 370 def less(self, shell): pass
371 371
372 372 _ip.register_magics(KernelMagics)
373 373
374 374 with self.assertLogs() as cm:
375 375 # hack, we want to just capture logs, but assertLogs fails if not
376 376 # logs get produce.
377 377 # so log one things we ignore.
378 378 import logging as log_mod
379 379 log = log_mod.getLogger()
380 380 log.info('Nothing')
381 381 # end hack.
382 382 _ip.run_cell("reset -f")
383 383
384 384 assert len(cm.output) == 1
385 385 for out in cm.output:
386 386 assert "Invalid alias" not in out
387 387
388 388 def test_tb_syntaxerror():
389 389 """test %tb after a SyntaxError"""
390 390 ip = get_ipython()
391 391 ip.run_cell("for")
392 392
393 393 # trap and validate stdout
394 394 save_stdout = sys.stdout
395 395 try:
396 396 sys.stdout = StringIO()
397 397 ip.run_cell("%tb")
398 398 out = sys.stdout.getvalue()
399 399 finally:
400 400 sys.stdout = save_stdout
401 401 # trim output, and only check the last line
402 402 last_line = out.rstrip().splitlines()[-1].strip()
403 403 assert last_line == "SyntaxError: invalid syntax"
404 404
405 405
406 406 def test_time():
407 407 ip = get_ipython()
408 408
409 409 with tt.AssertPrints("Wall time: "):
410 410 ip.run_cell("%time None")
411 411
412 412 ip.run_cell("def f(kmjy):\n"
413 413 " %time print (2*kmjy)")
414 414
415 415 with tt.AssertPrints("Wall time: "):
416 416 with tt.AssertPrints("hihi", suppress=False):
417 417 ip.run_cell("f('hi')")
418 418
419 419
420 420 # ';' at the end of %time prevents instruction value to be printed.
421 421 # This tests fix for #13837.
422 422 def test_time_no_output_with_semicolon():
423 423 ip = get_ipython()
424 424
425 425 # Test %time cases
426 426 with tt.AssertPrints(" 123456"):
427 427 with tt.AssertPrints("Wall time: ", suppress=False):
428 428 with tt.AssertPrints("CPU times: ", suppress=False):
429 429 ip.run_cell("%time 123000+456")
430 430
431 431 with tt.AssertNotPrints(" 123456"):
432 432 with tt.AssertPrints("Wall time: ", suppress=False):
433 433 with tt.AssertPrints("CPU times: ", suppress=False):
434 434 ip.run_cell("%time 123000+456;")
435 435
436 436 with tt.AssertPrints(" 123456"):
437 437 with tt.AssertPrints("Wall time: ", suppress=False):
438 438 with tt.AssertPrints("CPU times: ", suppress=False):
439 439 ip.run_cell("%time 123000+456 # Comment")
440 440
441 441 with tt.AssertNotPrints(" 123456"):
442 442 with tt.AssertPrints("Wall time: ", suppress=False):
443 443 with tt.AssertPrints("CPU times: ", suppress=False):
444 444 ip.run_cell("%time 123000+456; # Comment")
445 445
446 446 with tt.AssertPrints(" 123456"):
447 447 with tt.AssertPrints("Wall time: ", suppress=False):
448 448 with tt.AssertPrints("CPU times: ", suppress=False):
449 449 ip.run_cell("%time 123000+456 # ;Comment")
450 450
451 451 # Test %%time cases
452 452 with tt.AssertPrints("123456"):
453 453 with tt.AssertPrints("Wall time: ", suppress=False):
454 454 with tt.AssertPrints("CPU times: ", suppress=False):
455 455 ip.run_cell("%%time\n123000+456\n\n\n")
456 456
457 457 with tt.AssertNotPrints("123456"):
458 458 with tt.AssertPrints("Wall time: ", suppress=False):
459 459 with tt.AssertPrints("CPU times: ", suppress=False):
460 460 ip.run_cell("%%time\n123000+456;\n\n\n")
461 461
462 462 with tt.AssertPrints("123456"):
463 463 with tt.AssertPrints("Wall time: ", suppress=False):
464 464 with tt.AssertPrints("CPU times: ", suppress=False):
465 465 ip.run_cell("%%time\n123000+456 # Comment\n\n\n")
466 466
467 467 with tt.AssertNotPrints("123456"):
468 468 with tt.AssertPrints("Wall time: ", suppress=False):
469 469 with tt.AssertPrints("CPU times: ", suppress=False):
470 470 ip.run_cell("%%time\n123000+456; # Comment\n\n\n")
471 471
472 472 with tt.AssertPrints("123456"):
473 473 with tt.AssertPrints("Wall time: ", suppress=False):
474 474 with tt.AssertPrints("CPU times: ", suppress=False):
475 475 ip.run_cell("%%time\n123000+456 # ;Comment\n\n\n")
476 476
477 477
478 478 def test_time_last_not_expression():
479 479 ip.run_cell("%%time\n"
480 480 "var_1 = 1\n"
481 481 "var_2 = 2\n")
482 482 assert ip.user_ns['var_1'] == 1
483 483 del ip.user_ns['var_1']
484 484 assert ip.user_ns['var_2'] == 2
485 485 del ip.user_ns['var_2']
486 486
487 487
488 488 @dec.skip_win32
489 489 def test_time2():
490 490 ip = get_ipython()
491 491
492 492 with tt.AssertPrints("CPU times: user "):
493 493 ip.run_cell("%time None")
494 494
495 495 def test_time3():
496 496 """Erroneous magic function calls, issue gh-3334"""
497 497 ip = get_ipython()
498 498 ip.user_ns.pop('run', None)
499 499
500 500 with tt.AssertNotPrints("not found", channel='stderr'):
501 501 ip.run_cell("%%time\n"
502 502 "run = 0\n"
503 503 "run += 1")
504 504
505 505 def test_multiline_time():
506 506 """Make sure last statement from time return a value."""
507 507 ip = get_ipython()
508 508 ip.user_ns.pop('run', None)
509 509
510 510 ip.run_cell(
511 511 dedent(
512 512 """\
513 513 %%time
514 514 a = "ho"
515 515 b = "hey"
516 516 a+b
517 517 """
518 518 )
519 519 )
520 520 assert ip.user_ns_hidden["_"] == "hohey"
521 521
522 522
523 523 def test_time_local_ns():
524 524 """
525 525 Test that local_ns is actually global_ns when running a cell magic
526 526 """
527 527 ip = get_ipython()
528 528 ip.run_cell("%%time\n" "myvar = 1")
529 529 assert ip.user_ns["myvar"] == 1
530 530 del ip.user_ns["myvar"]
531 531
532 532
533 533 # Test %%capture magic. Added to test issue #13926
534 534 def test_capture():
535 535 ip = get_ipython()
536 536
537 537 # Test %%capture nominal case
538 538 ip.run_cell("%%capture abc\n1+2")
539 539 with tt.AssertPrints("True", suppress=False):
540 540 ip.run_cell("'abc' in locals()")
541 541 with tt.AssertPrints("True", suppress=False):
542 542 ip.run_cell("'outputs' in dir(abc)")
543 543 with tt.AssertPrints("3", suppress=False):
544 544 ip.run_cell("abc.outputs[0]")
545 545
546 546 # Test %%capture with ';' at end of expression
547 547 ip.run_cell("%%capture abc\n7+8;")
548 548 with tt.AssertPrints("False", suppress=False):
549 549 ip.run_cell("'abc' in locals()")
550 550
551 551
552 552 def test_doctest_mode():
553 553 "Toggle doctest_mode twice, it should be a no-op and run without error"
554 554 _ip.run_line_magic("doctest_mode", "")
555 555 _ip.run_line_magic("doctest_mode", "")
556 556
557 557
558 558 def test_parse_options():
559 559 """Tests for basic options parsing in magics."""
560 560 # These are only the most minimal of tests, more should be added later. At
561 561 # the very least we check that basic text/unicode calls work OK.
562 562 m = DummyMagics(_ip)
563 563 assert m.parse_options("foo", "")[1] == "foo"
564 564 assert m.parse_options("foo", "")[1] == "foo"
565 565
566 566
567 567 def test_parse_options_preserve_non_option_string():
568 568 """Test to assert preservation of non-option part of magic-block, while parsing magic options."""
569 569 m = DummyMagics(_ip)
570 570 opts, stmt = m.parse_options(
571 571 " -n1 -r 13 _ = 314 + foo", "n:r:", preserve_non_opts=True
572 572 )
573 573 assert opts == {"n": "1", "r": "13"}
574 574 assert stmt == "_ = 314 + foo"
575 575
576 576
577 577 def test_run_magic_preserve_code_block():
578 578 """Test to assert preservation of non-option part of magic-block, while running magic."""
579 579 _ip.user_ns["spaces"] = []
580 580 _ip.run_line_magic(
581 581 "timeit", "-n1 -r1 spaces.append([s.count(' ') for s in ['document']])"
582 582 )
583 583 assert _ip.user_ns["spaces"] == [[0]]
584 584
585 585
586 586 def test_dirops():
587 587 """Test various directory handling operations."""
588 588 # curpath = lambda :os.path.splitdrive(os.getcwd())[1].replace('\\','/')
589 589 curpath = os.getcwd
590 590 startdir = os.getcwd()
591 591 ipdir = os.path.realpath(_ip.ipython_dir)
592 592 try:
593 593 _ip.run_line_magic("cd", '"%s"' % ipdir)
594 594 assert curpath() == ipdir
595 595 _ip.run_line_magic("cd", "-")
596 596 assert curpath() == startdir
597 597 _ip.run_line_magic("pushd", '"%s"' % ipdir)
598 598 assert curpath() == ipdir
599 599 _ip.run_line_magic("popd", "")
600 600 assert curpath() == startdir
601 601 finally:
602 602 os.chdir(startdir)
603 603
604 604
605 605 def test_cd_force_quiet():
606 606 """Test OSMagics.cd_force_quiet option"""
607 607 _ip.config.OSMagics.cd_force_quiet = True
608 608 osmagics = osm.OSMagics(shell=_ip)
609 609
610 610 startdir = os.getcwd()
611 611 ipdir = os.path.realpath(_ip.ipython_dir)
612 612
613 613 try:
614 614 with tt.AssertNotPrints(ipdir):
615 615 osmagics.cd('"%s"' % ipdir)
616 616 with tt.AssertNotPrints(startdir):
617 617 osmagics.cd('-')
618 618 finally:
619 619 os.chdir(startdir)
620 620
621 621
622 622 def test_xmode():
623 623 # Calling xmode three times should be a no-op
624 624 xmode = _ip.InteractiveTB.mode
625 625 for i in range(4):
626 626 _ip.run_line_magic("xmode", "")
627 627 assert _ip.InteractiveTB.mode == xmode
628 628
629 629 def test_reset_hard():
630 630 monitor = []
631 631 class A(object):
632 632 def __del__(self):
633 633 monitor.append(1)
634 634 def __repr__(self):
635 635 return "<A instance>"
636 636
637 637 _ip.user_ns["a"] = A()
638 638 _ip.run_cell("a")
639 639
640 640 assert monitor == []
641 641 _ip.run_line_magic("reset", "-f")
642 642 assert monitor == [1]
643 643
644 644 class TestXdel(tt.TempFileMixin):
645 645 def test_xdel(self):
646 646 """Test that references from %run are cleared by xdel."""
647 647 src = ("class A(object):\n"
648 648 " monitor = []\n"
649 649 " def __del__(self):\n"
650 650 " self.monitor.append(1)\n"
651 651 "a = A()\n")
652 652 self.mktmp(src)
653 653 # %run creates some hidden references...
654 654 _ip.run_line_magic("run", "%s" % self.fname)
655 655 # ... as does the displayhook.
656 656 _ip.run_cell("a")
657 657
658 658 monitor = _ip.user_ns["A"].monitor
659 659 assert monitor == []
660 660
661 661 _ip.run_line_magic("xdel", "a")
662 662
663 663 # Check that a's __del__ method has been called.
664 664 gc.collect(0)
665 665 assert monitor == [1]
666 666
667 667 def doctest_who():
668 668 """doctest for %who
669 669
670 670 In [1]: %reset -sf
671 671
672 672 In [2]: alpha = 123
673 673
674 674 In [3]: beta = 'beta'
675 675
676 676 In [4]: %who int
677 677 alpha
678 678
679 679 In [5]: %who str
680 680 beta
681 681
682 682 In [6]: %whos
683 683 Variable Type Data/Info
684 684 ----------------------------
685 685 alpha int 123
686 686 beta str beta
687 687
688 688 In [7]: %who_ls
689 689 Out[7]: ['alpha', 'beta']
690 690 """
691 691
692 692 def test_whos():
693 693 """Check that whos is protected against objects where repr() fails."""
694 694 class A(object):
695 695 def __repr__(self):
696 696 raise Exception()
697 697 _ip.user_ns['a'] = A()
698 698 _ip.run_line_magic("whos", "")
699 699
700 700 def doctest_precision():
701 701 """doctest for %precision
702 702
703 703 In [1]: f = get_ipython().display_formatter.formatters['text/plain']
704 704
705 705 In [2]: %precision 5
706 706 Out[2]: '%.5f'
707 707
708 708 In [3]: f.float_format
709 709 Out[3]: '%.5f'
710 710
711 711 In [4]: %precision %e
712 712 Out[4]: '%e'
713 713
714 714 In [5]: f(3.1415927)
715 715 Out[5]: '3.141593e+00'
716 716 """
717 717
718
718 719 def test_debug_magic():
719 720 """Test debugging a small code with %debug
720 721
721 722 In [1]: with PdbTestInput(['c']):
722 723 ...: %debug print("a b") #doctest: +ELLIPSIS
723 724 ...:
724 725 ...
725 726 ipdb> c
726 727 a b
727 728 In [2]:
728 729 """
729 730
731
732 def test_debug_magic_locals():
733 """Test debugging a small code with %debug with locals
734
735 In [1]: with PdbTestInput(['c']):
736 ...: def fun():
737 ...: res = 1
738 ...: %debug print(res)
739 ...: fun()
740 ...:
741 ...
742 ipdb> c
743 1
744 In [2]:
745 """
746
730 747 def test_psearch():
731 748 with tt.AssertPrints("dict.fromkeys"):
732 749 _ip.run_cell("dict.fr*?")
733 750 with tt.AssertPrints("Ο€.is_integer"):
734 751 _ip.run_cell("Ο€ = 3.14;\nΟ€.is_integ*?")
735 752
736 753 def test_timeit_shlex():
737 754 """test shlex issues with timeit (#1109)"""
738 755 _ip.ex("def f(*a,**kw): pass")
739 756 _ip.run_line_magic("timeit", '-n1 "this is a bug".count(" ")')
740 757 _ip.run_line_magic("timeit", '-r1 -n1 f(" ", 1)')
741 758 _ip.run_line_magic("timeit", '-r1 -n1 f(" ", 1, " ", 2, " ")')
742 759 _ip.run_line_magic("timeit", '-r1 -n1 ("a " + "b")')
743 760 _ip.run_line_magic("timeit", '-r1 -n1 f("a " + "b")')
744 761 _ip.run_line_magic("timeit", '-r1 -n1 f("a " + "b ")')
745 762
746 763
747 764 def test_timeit_special_syntax():
748 765 "Test %%timeit with IPython special syntax"
749 766 @register_line_magic
750 767 def lmagic(line):
751 768 ip = get_ipython()
752 769 ip.user_ns['lmagic_out'] = line
753 770
754 771 # line mode test
755 772 _ip.run_line_magic("timeit", "-n1 -r1 %lmagic my line")
756 773 assert _ip.user_ns["lmagic_out"] == "my line"
757 774 # cell mode test
758 775 _ip.run_cell_magic("timeit", "-n1 -r1", "%lmagic my line2")
759 776 assert _ip.user_ns["lmagic_out"] == "my line2"
760 777
761 778
762 779 def test_timeit_return():
763 780 """
764 781 test whether timeit -o return object
765 782 """
766 783
767 784 res = _ip.run_line_magic('timeit','-n10 -r10 -o 1')
768 785 assert(res is not None)
769 786
770 787 def test_timeit_quiet():
771 788 """
772 789 test quiet option of timeit magic
773 790 """
774 791 with tt.AssertNotPrints("loops"):
775 792 _ip.run_cell("%timeit -n1 -r1 -q 1")
776 793
777 794 def test_timeit_return_quiet():
778 795 with tt.AssertNotPrints("loops"):
779 796 res = _ip.run_line_magic('timeit', '-n1 -r1 -q -o 1')
780 797 assert (res is not None)
781 798
782 799 def test_timeit_invalid_return():
783 800 with pytest.raises(SyntaxError):
784 801 _ip.run_line_magic('timeit', 'return')
785 802
786 803 @dec.skipif(execution.profile is None)
787 804 def test_prun_special_syntax():
788 805 "Test %%prun with IPython special syntax"
789 806 @register_line_magic
790 807 def lmagic(line):
791 808 ip = get_ipython()
792 809 ip.user_ns['lmagic_out'] = line
793 810
794 811 # line mode test
795 812 _ip.run_line_magic("prun", "-q %lmagic my line")
796 813 assert _ip.user_ns["lmagic_out"] == "my line"
797 814 # cell mode test
798 815 _ip.run_cell_magic("prun", "-q", "%lmagic my line2")
799 816 assert _ip.user_ns["lmagic_out"] == "my line2"
800 817
801 818
802 819 @dec.skipif(execution.profile is None)
803 820 def test_prun_quotes():
804 821 "Test that prun does not clobber string escapes (GH #1302)"
805 822 _ip.magic(r"prun -q x = '\t'")
806 823 assert _ip.user_ns["x"] == "\t"
807 824
808 825
809 826 def test_extension():
810 827 # Debugging information for failures of this test
811 828 print('sys.path:')
812 829 for p in sys.path:
813 830 print(' ', p)
814 831 print('CWD', os.getcwd())
815 832
816 833 pytest.raises(ImportError, _ip.magic, "load_ext daft_extension")
817 834 daft_path = os.path.join(os.path.dirname(__file__), "daft_extension")
818 835 sys.path.insert(0, daft_path)
819 836 try:
820 837 _ip.user_ns.pop('arq', None)
821 838 invalidate_caches() # Clear import caches
822 839 _ip.run_line_magic("load_ext", "daft_extension")
823 840 assert _ip.user_ns["arq"] == 185
824 841 _ip.run_line_magic("unload_ext", "daft_extension")
825 842 assert 'arq' not in _ip.user_ns
826 843 finally:
827 844 sys.path.remove(daft_path)
828 845
829 846
830 847 def test_notebook_export_json():
831 848 pytest.importorskip("nbformat")
832 849 _ip = get_ipython()
833 850 _ip.history_manager.reset() # Clear any existing history.
834 851 cmds = ["a=1", "def b():\n return a**2", "print('noΓ«l, Γ©tΓ©', b())"]
835 852 for i, cmd in enumerate(cmds, start=1):
836 853 _ip.history_manager.store_inputs(i, cmd)
837 854 with TemporaryDirectory() as td:
838 855 outfile = os.path.join(td, "nb.ipynb")
839 856 _ip.run_line_magic("notebook", "%s" % outfile)
840 857
841 858
842 859 class TestEnv(TestCase):
843 860
844 861 def test_env(self):
845 862 env = _ip.run_line_magic("env", "")
846 863 self.assertTrue(isinstance(env, dict))
847 864
848 865 def test_env_secret(self):
849 866 env = _ip.run_line_magic("env", "")
850 867 hidden = "<hidden>"
851 868 with mock.patch.dict(
852 869 os.environ,
853 870 {
854 871 "API_KEY": "abc123",
855 872 "SECRET_THING": "ssshhh",
856 873 "JUPYTER_TOKEN": "",
857 874 "VAR": "abc"
858 875 }
859 876 ):
860 877 env = _ip.run_line_magic("env", "")
861 878 assert env["API_KEY"] == hidden
862 879 assert env["SECRET_THING"] == hidden
863 880 assert env["JUPYTER_TOKEN"] == hidden
864 881 assert env["VAR"] == "abc"
865 882
866 883 def test_env_get_set_simple(self):
867 884 env = _ip.run_line_magic("env", "var val1")
868 885 self.assertEqual(env, None)
869 886 self.assertEqual(os.environ["var"], "val1")
870 887 self.assertEqual(_ip.run_line_magic("env", "var"), "val1")
871 888 env = _ip.run_line_magic("env", "var=val2")
872 889 self.assertEqual(env, None)
873 890 self.assertEqual(os.environ['var'], 'val2')
874 891
875 892 def test_env_get_set_complex(self):
876 893 env = _ip.run_line_magic("env", "var 'val1 '' 'val2")
877 894 self.assertEqual(env, None)
878 895 self.assertEqual(os.environ['var'], "'val1 '' 'val2")
879 896 self.assertEqual(_ip.run_line_magic("env", "var"), "'val1 '' 'val2")
880 897 env = _ip.run_line_magic("env", 'var=val2 val3="val4')
881 898 self.assertEqual(env, None)
882 899 self.assertEqual(os.environ['var'], 'val2 val3="val4')
883 900
884 901 def test_env_set_bad_input(self):
885 902 self.assertRaises(UsageError, lambda: _ip.run_line_magic("set_env", "var"))
886 903
887 904 def test_env_set_whitespace(self):
888 905 self.assertRaises(UsageError, lambda: _ip.run_line_magic("env", "var A=B"))
889 906
890 907
891 908 class CellMagicTestCase(TestCase):
892 909
893 910 def check_ident(self, magic):
894 911 # Manually called, we get the result
895 912 out = _ip.run_cell_magic(magic, "a", "b")
896 913 assert out == ("a", "b")
897 914 # Via run_cell, it goes into the user's namespace via displayhook
898 915 _ip.run_cell("%%" + magic + " c\nd\n")
899 916 assert _ip.user_ns["_"] == ("c", "d\n")
900 917
901 918 def test_cell_magic_func_deco(self):
902 919 "Cell magic using simple decorator"
903 920 @register_cell_magic
904 921 def cellm(line, cell):
905 922 return line, cell
906 923
907 924 self.check_ident('cellm')
908 925
909 926 def test_cell_magic_reg(self):
910 927 "Cell magic manually registered"
911 928 def cellm(line, cell):
912 929 return line, cell
913 930
914 931 _ip.register_magic_function(cellm, 'cell', 'cellm2')
915 932 self.check_ident('cellm2')
916 933
917 934 def test_cell_magic_class(self):
918 935 "Cell magics declared via a class"
919 936 @magics_class
920 937 class MyMagics(Magics):
921 938
922 939 @cell_magic
923 940 def cellm3(self, line, cell):
924 941 return line, cell
925 942
926 943 _ip.register_magics(MyMagics)
927 944 self.check_ident('cellm3')
928 945
929 946 def test_cell_magic_class2(self):
930 947 "Cell magics declared via a class, #2"
931 948 @magics_class
932 949 class MyMagics2(Magics):
933 950
934 951 @cell_magic('cellm4')
935 952 def cellm33(self, line, cell):
936 953 return line, cell
937 954
938 955 _ip.register_magics(MyMagics2)
939 956 self.check_ident('cellm4')
940 957 # Check that nothing is registered as 'cellm33'
941 958 c33 = _ip.find_cell_magic('cellm33')
942 959 assert c33 == None
943 960
944 961 def test_file():
945 962 """Basic %%writefile"""
946 963 ip = get_ipython()
947 964 with TemporaryDirectory() as td:
948 965 fname = os.path.join(td, "file1")
949 966 ip.run_cell_magic(
950 967 "writefile",
951 968 fname,
952 969 "\n".join(
953 970 [
954 971 "line1",
955 972 "line2",
956 973 ]
957 974 ),
958 975 )
959 976 s = Path(fname).read_text(encoding="utf-8")
960 977 assert "line1\n" in s
961 978 assert "line2" in s
962 979
963 980
964 981 @dec.skip_win32
965 982 def test_file_single_quote():
966 983 """Basic %%writefile with embedded single quotes"""
967 984 ip = get_ipython()
968 985 with TemporaryDirectory() as td:
969 986 fname = os.path.join(td, "'file1'")
970 987 ip.run_cell_magic(
971 988 "writefile",
972 989 fname,
973 990 "\n".join(
974 991 [
975 992 "line1",
976 993 "line2",
977 994 ]
978 995 ),
979 996 )
980 997 s = Path(fname).read_text(encoding="utf-8")
981 998 assert "line1\n" in s
982 999 assert "line2" in s
983 1000
984 1001
985 1002 @dec.skip_win32
986 1003 def test_file_double_quote():
987 1004 """Basic %%writefile with embedded double quotes"""
988 1005 ip = get_ipython()
989 1006 with TemporaryDirectory() as td:
990 1007 fname = os.path.join(td, '"file1"')
991 1008 ip.run_cell_magic(
992 1009 "writefile",
993 1010 fname,
994 1011 "\n".join(
995 1012 [
996 1013 "line1",
997 1014 "line2",
998 1015 ]
999 1016 ),
1000 1017 )
1001 1018 s = Path(fname).read_text(encoding="utf-8")
1002 1019 assert "line1\n" in s
1003 1020 assert "line2" in s
1004 1021
1005 1022
1006 1023 def test_file_var_expand():
1007 1024 """%%writefile $filename"""
1008 1025 ip = get_ipython()
1009 1026 with TemporaryDirectory() as td:
1010 1027 fname = os.path.join(td, "file1")
1011 1028 ip.user_ns["filename"] = fname
1012 1029 ip.run_cell_magic(
1013 1030 "writefile",
1014 1031 "$filename",
1015 1032 "\n".join(
1016 1033 [
1017 1034 "line1",
1018 1035 "line2",
1019 1036 ]
1020 1037 ),
1021 1038 )
1022 1039 s = Path(fname).read_text(encoding="utf-8")
1023 1040 assert "line1\n" in s
1024 1041 assert "line2" in s
1025 1042
1026 1043
1027 1044 def test_file_unicode():
1028 1045 """%%writefile with unicode cell"""
1029 1046 ip = get_ipython()
1030 1047 with TemporaryDirectory() as td:
1031 1048 fname = os.path.join(td, 'file1')
1032 1049 ip.run_cell_magic("writefile", fname, u'\n'.join([
1033 1050 u'linΓ©1',
1034 1051 u'linΓ©2',
1035 1052 ]))
1036 1053 with io.open(fname, encoding='utf-8') as f:
1037 1054 s = f.read()
1038 1055 assert "linΓ©1\n" in s
1039 1056 assert "linΓ©2" in s
1040 1057
1041 1058
1042 1059 def test_file_amend():
1043 1060 """%%writefile -a amends files"""
1044 1061 ip = get_ipython()
1045 1062 with TemporaryDirectory() as td:
1046 1063 fname = os.path.join(td, "file2")
1047 1064 ip.run_cell_magic(
1048 1065 "writefile",
1049 1066 fname,
1050 1067 "\n".join(
1051 1068 [
1052 1069 "line1",
1053 1070 "line2",
1054 1071 ]
1055 1072 ),
1056 1073 )
1057 1074 ip.run_cell_magic(
1058 1075 "writefile",
1059 1076 "-a %s" % fname,
1060 1077 "\n".join(
1061 1078 [
1062 1079 "line3",
1063 1080 "line4",
1064 1081 ]
1065 1082 ),
1066 1083 )
1067 1084 s = Path(fname).read_text(encoding="utf-8")
1068 1085 assert "line1\n" in s
1069 1086 assert "line3\n" in s
1070 1087
1071 1088
1072 1089 def test_file_spaces():
1073 1090 """%%file with spaces in filename"""
1074 1091 ip = get_ipython()
1075 1092 with TemporaryWorkingDirectory() as td:
1076 1093 fname = "file name"
1077 1094 ip.run_cell_magic(
1078 1095 "file",
1079 1096 '"%s"' % fname,
1080 1097 "\n".join(
1081 1098 [
1082 1099 "line1",
1083 1100 "line2",
1084 1101 ]
1085 1102 ),
1086 1103 )
1087 1104 s = Path(fname).read_text(encoding="utf-8")
1088 1105 assert "line1\n" in s
1089 1106 assert "line2" in s
1090 1107
1091 1108
1092 1109 def test_script_config():
1093 1110 ip = get_ipython()
1094 1111 ip.config.ScriptMagics.script_magics = ['whoda']
1095 1112 sm = script.ScriptMagics(shell=ip)
1096 1113 assert "whoda" in sm.magics["cell"]
1097 1114
1098 1115
1099 1116 def test_script_out():
1100 1117 ip = get_ipython()
1101 1118 ip.run_cell_magic("script", f"--out output {sys.executable}", "print('hi')")
1102 1119 assert ip.user_ns["output"].strip() == "hi"
1103 1120
1104 1121
1105 1122 def test_script_err():
1106 1123 ip = get_ipython()
1107 1124 ip.run_cell_magic(
1108 1125 "script",
1109 1126 f"--err error {sys.executable}",
1110 1127 "import sys; print('hello', file=sys.stderr)",
1111 1128 )
1112 1129 assert ip.user_ns["error"].strip() == "hello"
1113 1130
1114 1131
1115 1132 def test_script_out_err():
1116 1133 ip = get_ipython()
1117 1134 ip.run_cell_magic(
1118 1135 "script",
1119 1136 f"--out output --err error {sys.executable}",
1120 1137 "\n".join(
1121 1138 [
1122 1139 "import sys",
1123 1140 "print('hi')",
1124 1141 "print('hello', file=sys.stderr)",
1125 1142 ]
1126 1143 ),
1127 1144 )
1128 1145 assert ip.user_ns["output"].strip() == "hi"
1129 1146 assert ip.user_ns["error"].strip() == "hello"
1130 1147
1131 1148
1132 1149 async def test_script_bg_out():
1133 1150 ip = get_ipython()
1134 1151 ip.run_cell_magic("script", f"--bg --out output {sys.executable}", "print('hi')")
1135 1152 assert (await ip.user_ns["output"].read()).strip() == b"hi"
1136 1153 assert ip.user_ns["output"].at_eof()
1137 1154
1138 1155
1139 1156 async def test_script_bg_err():
1140 1157 ip = get_ipython()
1141 1158 ip.run_cell_magic(
1142 1159 "script",
1143 1160 f"--bg --err error {sys.executable}",
1144 1161 "import sys; print('hello', file=sys.stderr)",
1145 1162 )
1146 1163 assert (await ip.user_ns["error"].read()).strip() == b"hello"
1147 1164 assert ip.user_ns["error"].at_eof()
1148 1165
1149 1166
1150 1167 async def test_script_bg_out_err():
1151 1168 ip = get_ipython()
1152 1169 ip.run_cell_magic(
1153 1170 "script",
1154 1171 f"--bg --out output --err error {sys.executable}",
1155 1172 "\n".join(
1156 1173 [
1157 1174 "import sys",
1158 1175 "print('hi')",
1159 1176 "print('hello', file=sys.stderr)",
1160 1177 ]
1161 1178 ),
1162 1179 )
1163 1180 assert (await ip.user_ns["output"].read()).strip() == b"hi"
1164 1181 assert (await ip.user_ns["error"].read()).strip() == b"hello"
1165 1182 assert ip.user_ns["output"].at_eof()
1166 1183 assert ip.user_ns["error"].at_eof()
1167 1184
1168 1185
1169 1186 async def test_script_bg_proc():
1170 1187 ip = get_ipython()
1171 1188 ip.run_cell_magic(
1172 1189 "script",
1173 1190 f"--bg --out output --proc p {sys.executable}",
1174 1191 "\n".join(
1175 1192 [
1176 1193 "import sys",
1177 1194 "print('hi')",
1178 1195 "print('hello', file=sys.stderr)",
1179 1196 ]
1180 1197 ),
1181 1198 )
1182 1199 p = ip.user_ns["p"]
1183 1200 await p.wait()
1184 1201 assert p.returncode == 0
1185 1202 assert (await p.stdout.read()).strip() == b"hi"
1186 1203 # not captured, so empty
1187 1204 assert (await p.stderr.read()) == b""
1188 1205 assert p.stdout.at_eof()
1189 1206 assert p.stderr.at_eof()
1190 1207
1191 1208
1192 1209 def test_script_defaults():
1193 1210 ip = get_ipython()
1194 1211 for cmd in ['sh', 'bash', 'perl', 'ruby']:
1195 1212 try:
1196 1213 find_cmd(cmd)
1197 1214 except Exception:
1198 1215 pass
1199 1216 else:
1200 1217 assert cmd in ip.magics_manager.magics["cell"]
1201 1218
1202 1219
1203 1220 @magics_class
1204 1221 class FooFoo(Magics):
1205 1222 """class with both %foo and %%foo magics"""
1206 1223 @line_magic('foo')
1207 1224 def line_foo(self, line):
1208 1225 "I am line foo"
1209 1226 pass
1210 1227
1211 1228 @cell_magic("foo")
1212 1229 def cell_foo(self, line, cell):
1213 1230 "I am cell foo, not line foo"
1214 1231 pass
1215 1232
1216 1233 def test_line_cell_info():
1217 1234 """%%foo and %foo magics are distinguishable to inspect"""
1218 1235 ip = get_ipython()
1219 1236 ip.magics_manager.register(FooFoo)
1220 1237 oinfo = ip.object_inspect("foo")
1221 1238 assert oinfo["found"] is True
1222 1239 assert oinfo["ismagic"] is True
1223 1240
1224 1241 oinfo = ip.object_inspect("%%foo")
1225 1242 assert oinfo["found"] is True
1226 1243 assert oinfo["ismagic"] is True
1227 1244 assert oinfo["docstring"] == FooFoo.cell_foo.__doc__
1228 1245
1229 1246 oinfo = ip.object_inspect("%foo")
1230 1247 assert oinfo["found"] is True
1231 1248 assert oinfo["ismagic"] is True
1232 1249 assert oinfo["docstring"] == FooFoo.line_foo.__doc__
1233 1250
1234 1251
1235 1252 def test_multiple_magics():
1236 1253 ip = get_ipython()
1237 1254 foo1 = FooFoo(ip)
1238 1255 foo2 = FooFoo(ip)
1239 1256 mm = ip.magics_manager
1240 1257 mm.register(foo1)
1241 1258 assert mm.magics["line"]["foo"].__self__ is foo1
1242 1259 mm.register(foo2)
1243 1260 assert mm.magics["line"]["foo"].__self__ is foo2
1244 1261
1245 1262
1246 1263 def test_alias_magic():
1247 1264 """Test %alias_magic."""
1248 1265 ip = get_ipython()
1249 1266 mm = ip.magics_manager
1250 1267
1251 1268 # Basic operation: both cell and line magics are created, if possible.
1252 1269 ip.run_line_magic("alias_magic", "timeit_alias timeit")
1253 1270 assert "timeit_alias" in mm.magics["line"]
1254 1271 assert "timeit_alias" in mm.magics["cell"]
1255 1272
1256 1273 # --cell is specified, line magic not created.
1257 1274 ip.run_line_magic("alias_magic", "--cell timeit_cell_alias timeit")
1258 1275 assert "timeit_cell_alias" not in mm.magics["line"]
1259 1276 assert "timeit_cell_alias" in mm.magics["cell"]
1260 1277
1261 1278 # Test that line alias is created successfully.
1262 1279 ip.run_line_magic("alias_magic", "--line env_alias env")
1263 1280 assert ip.run_line_magic("env", "") == ip.run_line_magic("env_alias", "")
1264 1281
1265 1282 # Test that line alias with parameters passed in is created successfully.
1266 1283 ip.run_line_magic(
1267 1284 "alias_magic", "--line history_alias history --params " + shlex.quote("3")
1268 1285 )
1269 1286 assert "history_alias" in mm.magics["line"]
1270 1287
1271 1288
1272 1289 def test_save():
1273 1290 """Test %save."""
1274 1291 ip = get_ipython()
1275 1292 ip.history_manager.reset() # Clear any existing history.
1276 1293 cmds = ["a=1", "def b():\n return a**2", "print(a, b())"]
1277 1294 for i, cmd in enumerate(cmds, start=1):
1278 1295 ip.history_manager.store_inputs(i, cmd)
1279 1296 with TemporaryDirectory() as tmpdir:
1280 1297 file = os.path.join(tmpdir, "testsave.py")
1281 1298 ip.run_line_magic("save", "%s 1-10" % file)
1282 1299 content = Path(file).read_text(encoding="utf-8")
1283 1300 assert content.count(cmds[0]) == 1
1284 1301 assert "coding: utf-8" in content
1285 1302 ip.run_line_magic("save", "-a %s 1-10" % file)
1286 1303 content = Path(file).read_text(encoding="utf-8")
1287 1304 assert content.count(cmds[0]) == 2
1288 1305 assert "coding: utf-8" in content
1289 1306
1290 1307
1291 1308 def test_save_with_no_args():
1292 1309 ip = get_ipython()
1293 1310 ip.history_manager.reset() # Clear any existing history.
1294 1311 cmds = ["a=1", "def b():\n return a**2", "print(a, b())", "%save"]
1295 1312 for i, cmd in enumerate(cmds, start=1):
1296 1313 ip.history_manager.store_inputs(i, cmd)
1297 1314
1298 1315 with TemporaryDirectory() as tmpdir:
1299 1316 path = os.path.join(tmpdir, "testsave.py")
1300 1317 ip.run_line_magic("save", path)
1301 1318 content = Path(path).read_text(encoding="utf-8")
1302 1319 expected_content = dedent(
1303 1320 """\
1304 1321 # coding: utf-8
1305 1322 a=1
1306 1323 def b():
1307 1324 return a**2
1308 1325 print(a, b())
1309 1326 """
1310 1327 )
1311 1328 assert content == expected_content
1312 1329
1313 1330
1314 1331 def test_store():
1315 1332 """Test %store."""
1316 1333 ip = get_ipython()
1317 1334 ip.run_line_magic('load_ext', 'storemagic')
1318 1335
1319 1336 # make sure the storage is empty
1320 1337 ip.run_line_magic("store", "-z")
1321 1338 ip.user_ns["var"] = 42
1322 1339 ip.run_line_magic("store", "var")
1323 1340 ip.user_ns["var"] = 39
1324 1341 ip.run_line_magic("store", "-r")
1325 1342 assert ip.user_ns["var"] == 42
1326 1343
1327 1344 ip.run_line_magic("store", "-d var")
1328 1345 ip.user_ns["var"] = 39
1329 1346 ip.run_line_magic("store", "-r")
1330 1347 assert ip.user_ns["var"] == 39
1331 1348
1332 1349
1333 1350 def _run_edit_test(arg_s, exp_filename=None,
1334 1351 exp_lineno=-1,
1335 1352 exp_contents=None,
1336 1353 exp_is_temp=None):
1337 1354 ip = get_ipython()
1338 1355 M = code.CodeMagics(ip)
1339 1356 last_call = ['','']
1340 1357 opts,args = M.parse_options(arg_s,'prxn:')
1341 1358 filename, lineno, is_temp = M._find_edit_target(ip, args, opts, last_call)
1342 1359
1343 1360 if exp_filename is not None:
1344 1361 assert exp_filename == filename
1345 1362 if exp_contents is not None:
1346 1363 with io.open(filename, 'r', encoding='utf-8') as f:
1347 1364 contents = f.read()
1348 1365 assert exp_contents == contents
1349 1366 if exp_lineno != -1:
1350 1367 assert exp_lineno == lineno
1351 1368 if exp_is_temp is not None:
1352 1369 assert exp_is_temp == is_temp
1353 1370
1354 1371
1355 1372 def test_edit_interactive():
1356 1373 """%edit on interactively defined objects"""
1357 1374 ip = get_ipython()
1358 1375 n = ip.execution_count
1359 1376 ip.run_cell("def foo(): return 1", store_history=True)
1360 1377
1361 1378 with pytest.raises(code.InteractivelyDefined) as e:
1362 1379 _run_edit_test("foo")
1363 1380 assert e.value.index == n
1364 1381
1365 1382
1366 1383 def test_edit_cell():
1367 1384 """%edit [cell id]"""
1368 1385 ip = get_ipython()
1369 1386
1370 1387 ip.run_cell("def foo(): return 1", store_history=True)
1371 1388
1372 1389 # test
1373 1390 _run_edit_test("1", exp_contents=ip.user_ns['In'][1], exp_is_temp=True)
1374 1391
1375 1392 def test_edit_fname():
1376 1393 """%edit file"""
1377 1394 # test
1378 1395 _run_edit_test("test file.py", exp_filename="test file.py")
1379 1396
1380 1397 def test_bookmark():
1381 1398 ip = get_ipython()
1382 1399 ip.run_line_magic('bookmark', 'bmname')
1383 1400 with tt.AssertPrints('bmname'):
1384 1401 ip.run_line_magic('bookmark', '-l')
1385 1402 ip.run_line_magic('bookmark', '-d bmname')
1386 1403
1387 1404 def test_ls_magic():
1388 1405 ip = get_ipython()
1389 1406 json_formatter = ip.display_formatter.formatters['application/json']
1390 1407 json_formatter.enabled = True
1391 1408 lsmagic = ip.run_line_magic("lsmagic", "")
1392 1409 with warnings.catch_warnings(record=True) as w:
1393 1410 j = json_formatter(lsmagic)
1394 1411 assert sorted(j) == ["cell", "line"]
1395 1412 assert w == [] # no warnings
1396 1413
1397 1414
1398 1415 def test_strip_initial_indent():
1399 1416 def sii(s):
1400 1417 lines = s.splitlines()
1401 1418 return '\n'.join(code.strip_initial_indent(lines))
1402 1419
1403 1420 assert sii(" a = 1\nb = 2") == "a = 1\nb = 2"
1404 1421 assert sii(" a\n b\nc") == "a\n b\nc"
1405 1422 assert sii("a\n b") == "a\n b"
1406 1423
1407 1424 def test_logging_magic_quiet_from_arg():
1408 1425 _ip.config.LoggingMagics.quiet = False
1409 1426 lm = logging.LoggingMagics(shell=_ip)
1410 1427 with TemporaryDirectory() as td:
1411 1428 try:
1412 1429 with tt.AssertNotPrints(re.compile("Activating.*")):
1413 1430 lm.logstart('-q {}'.format(
1414 1431 os.path.join(td, "quiet_from_arg.log")))
1415 1432 finally:
1416 1433 _ip.logger.logstop()
1417 1434
1418 1435 def test_logging_magic_quiet_from_config():
1419 1436 _ip.config.LoggingMagics.quiet = True
1420 1437 lm = logging.LoggingMagics(shell=_ip)
1421 1438 with TemporaryDirectory() as td:
1422 1439 try:
1423 1440 with tt.AssertNotPrints(re.compile("Activating.*")):
1424 1441 lm.logstart(os.path.join(td, "quiet_from_config.log"))
1425 1442 finally:
1426 1443 _ip.logger.logstop()
1427 1444
1428 1445
1429 1446 def test_logging_magic_not_quiet():
1430 1447 _ip.config.LoggingMagics.quiet = False
1431 1448 lm = logging.LoggingMagics(shell=_ip)
1432 1449 with TemporaryDirectory() as td:
1433 1450 try:
1434 1451 with tt.AssertPrints(re.compile("Activating.*")):
1435 1452 lm.logstart(os.path.join(td, "not_quiet.log"))
1436 1453 finally:
1437 1454 _ip.logger.logstop()
1438 1455
1439 1456
1440 1457 def test_time_no_var_expand():
1441 1458 _ip.user_ns["a"] = 5
1442 1459 _ip.user_ns["b"] = []
1443 1460 _ip.run_line_magic("time", 'b.append("{a}")')
1444 1461 assert _ip.user_ns["b"] == ["{a}"]
1445 1462
1446 1463
1447 1464 # this is slow, put at the end for local testing.
1448 1465 def test_timeit_arguments():
1449 1466 "Test valid timeit arguments, should not cause SyntaxError (GH #1269)"
1450 1467 _ip.run_line_magic("timeit", "-n1 -r1 a=('#')")
1451 1468
1452 1469
1453 1470 MINIMAL_LAZY_MAGIC = """
1454 1471 from IPython.core.magic import (
1455 1472 Magics,
1456 1473 magics_class,
1457 1474 line_magic,
1458 1475 cell_magic,
1459 1476 )
1460 1477
1461 1478
1462 1479 @magics_class
1463 1480 class LazyMagics(Magics):
1464 1481 @line_magic
1465 1482 def lazy_line(self, line):
1466 1483 print("Lazy Line")
1467 1484
1468 1485 @cell_magic
1469 1486 def lazy_cell(self, line, cell):
1470 1487 print("Lazy Cell")
1471 1488
1472 1489
1473 1490 def load_ipython_extension(ipython):
1474 1491 ipython.register_magics(LazyMagics)
1475 1492 """
1476 1493
1477 1494
1478 1495 def test_lazy_magics():
1479 1496 with pytest.raises(UsageError):
1480 1497 ip.run_line_magic("lazy_line", "")
1481 1498
1482 1499 startdir = os.getcwd()
1483 1500
1484 1501 with TemporaryDirectory() as tmpdir:
1485 1502 with prepended_to_syspath(tmpdir):
1486 1503 ptempdir = Path(tmpdir)
1487 1504 tf = ptempdir / "lazy_magic_module.py"
1488 1505 tf.write_text(MINIMAL_LAZY_MAGIC)
1489 1506 ip.magics_manager.register_lazy("lazy_line", Path(tf.name).name[:-3])
1490 1507 with tt.AssertPrints("Lazy Line"):
1491 1508 ip.run_line_magic("lazy_line", "")
1492 1509
1493 1510
1494 1511 TEST_MODULE = """
1495 1512 print('Loaded my_tmp')
1496 1513 if __name__ == "__main__":
1497 1514 print('I just ran a script')
1498 1515 """
1499 1516
1500 1517 def test_run_module_from_import_hook():
1501 1518 "Test that a module can be loaded via an import hook"
1502 1519 with TemporaryDirectory() as tmpdir:
1503 1520 fullpath = os.path.join(tmpdir, "my_tmp.py")
1504 1521 Path(fullpath).write_text(TEST_MODULE, encoding="utf-8")
1505 1522
1506 1523 import importlib.abc
1507 1524 import importlib.util
1508 1525
1509 1526 class MyTempImporter(importlib.abc.MetaPathFinder, importlib.abc.SourceLoader):
1510 1527 def find_spec(self, fullname, path, target=None):
1511 1528 if fullname == "my_tmp":
1512 1529 return importlib.util.spec_from_loader(fullname, self)
1513 1530
1514 1531 def get_filename(self, fullname):
1515 1532 assert fullname == "my_tmp"
1516 1533 return fullpath
1517 1534
1518 1535 def get_data(self, path):
1519 1536 assert Path(path).samefile(fullpath)
1520 1537 return Path(fullpath).read_text(encoding="utf-8")
1521 1538
1522 1539 sys.meta_path.insert(0, MyTempImporter())
1523 1540
1524 1541 with capture_output() as captured:
1525 1542 _ip.run_line_magic("run", "-m my_tmp")
1526 1543 _ip.run_cell("import my_tmp")
1527 1544
1528 1545 output = "Loaded my_tmp\nI just ran a script\nLoaded my_tmp\n"
1529 1546 assert output == captured.stdout
1530 1547
1531 1548 sys.meta_path.pop(0)
General Comments 0
You need to be logged in to leave comments. Login now