##// END OF EJS Templates
Dedent leading lines on %load -r...
Thomas Kluyver -
Show More
@@ -1,716 +1,746 b''
1 1 """Implementation of code management magic functions.
2 2 """
3 3 from __future__ import print_function
4 4 from __future__ import absolute_import
5 5 #-----------------------------------------------------------------------------
6 6 # Copyright (c) 2012 The IPython Development Team.
7 7 #
8 8 # Distributed under the terms of the Modified BSD License.
9 9 #
10 10 # The full license is in the file COPYING.txt, distributed with this software.
11 11 #-----------------------------------------------------------------------------
12 12
13 13 #-----------------------------------------------------------------------------
14 14 # Imports
15 15 #-----------------------------------------------------------------------------
16 16
17 17 # Stdlib
18 18 import inspect
19 19 import io
20 20 import os
21 21 import re
22 22 import sys
23 23 import ast
24 24 from itertools import chain
25 25
26 26 # Our own packages
27 27 from IPython.core.error import TryNext, StdinNotImplementedError, UsageError
28 28 from IPython.core.macro import Macro
29 29 from IPython.core.magic import Magics, magics_class, line_magic
30 30 from IPython.core.oinspect import find_file, find_source_lines
31 31 from IPython.testing.skipdoctest import skip_doctest
32 32 from IPython.utils import py3compat
33 33 from IPython.utils.py3compat import string_types
34 34 from IPython.utils.contexts import preserve_keys
35 35 from IPython.utils.path import get_py_filename
36 36 from warnings import warn
37 37 from logging import error
38 38 from IPython.utils.text import get_text_list
39 39
40 40 #-----------------------------------------------------------------------------
41 41 # Magic implementation classes
42 42 #-----------------------------------------------------------------------------
43 43
44 44 # Used for exception handling in magic_edit
45 45 class MacroToEdit(ValueError): pass
46 46
47 47 ipython_input_pat = re.compile(r"<ipython\-input\-(\d+)-[a-z\d]+>$")
48 48
49 49 # To match, e.g. 8-10 1:5 :10 3-
50 50 range_re = re.compile(r"""
51 51 (?P<start>\d+)?
52 52 ((?P<sep>[\-:])
53 53 (?P<end>\d+)?)?
54 54 $""", re.VERBOSE)
55 55
56 56
57 57 def extract_code_ranges(ranges_str):
58 58 """Turn a string of range for %%load into 2-tuples of (start, stop)
59 59 ready to use as a slice of the content splitted by lines.
60 60
61 61 Examples
62 62 --------
63 63 list(extract_input_ranges("5-10 2"))
64 64 [(4, 10), (1, 2)]
65 65 """
66 66 for range_str in ranges_str.split():
67 67 rmatch = range_re.match(range_str)
68 68 if not rmatch:
69 69 continue
70 70 sep = rmatch.group("sep")
71 71 start = rmatch.group("start")
72 72 end = rmatch.group("end")
73 73
74 74 if sep == '-':
75 75 start = int(start) - 1 if start else None
76 76 end = int(end) if end else None
77 77 elif sep == ':':
78 78 start = int(start) - 1 if start else None
79 79 end = int(end) - 1 if end else None
80 80 else:
81 81 end = int(start)
82 82 start = int(start) - 1
83 83 yield (start, end)
84 84
85 85
86 86 @skip_doctest
87 87 def extract_symbols(code, symbols):
88 88 """
89 89 Return a tuple (blocks, not_found)
90 90 where ``blocks`` is a list of code fragments
91 91 for each symbol parsed from code, and ``not_found`` are
92 92 symbols not found in the code.
93 93
94 94 For example::
95 95
96 96 >>> code = '''a = 10
97 97
98 98 def b(): return 42
99 99
100 100 class A: pass'''
101 101
102 102 >>> extract_symbols(code, 'A,b,z')
103 103 (["class A: pass", "def b(): return 42"], ['z'])
104 104 """
105 105 symbols = symbols.split(',')
106 106
107 107 # this will raise SyntaxError if code isn't valid Python
108 108 py_code = ast.parse(code)
109 109
110 110 marks = [(getattr(s, 'name', None), s.lineno) for s in py_code.body]
111 111 code = code.split('\n')
112 112
113 113 symbols_lines = {}
114 114
115 115 # we already know the start_lineno of each symbol (marks).
116 116 # To find each end_lineno, we traverse in reverse order until each
117 117 # non-blank line
118 118 end = len(code)
119 119 for name, start in reversed(marks):
120 120 while not code[end - 1].strip():
121 121 end -= 1
122 122 if name:
123 123 symbols_lines[name] = (start - 1, end)
124 124 end = start - 1
125 125
126 126 # Now symbols_lines is a map
127 127 # {'symbol_name': (start_lineno, end_lineno), ...}
128 128
129 129 # fill a list with chunks of codes for each requested symbol
130 130 blocks = []
131 131 not_found = []
132 132 for symbol in symbols:
133 133 if symbol in symbols_lines:
134 134 start, end = symbols_lines[symbol]
135 135 blocks.append('\n'.join(code[start:end]) + '\n')
136 136 else:
137 137 not_found.append(symbol)
138 138
139 139 return blocks, not_found
140 140
141 def strip_initial_indent(lines):
142 """For %load, strip indent from lines until finding an unindented line.
143
144 https://github.com/ipython/ipython/issues/9775
145 """
146 indent_re = re.compile(r'\s+')
147
148 it = iter(lines)
149 first_line = next(it)
150 indent_match = indent_re.match(first_line)
151
152 if indent_match:
153 # First line was indented
154 indent = indent_match.group()
155 yield first_line[len(indent):]
156
157 for line in it:
158 if line.startswith(indent):
159 yield line[len(indent):]
160 else:
161 # Less indented than the first line - stop dedenting
162 yield line
163 break
164 else:
165 yield first_line
166
167 # Pass the remaining lines through without dedenting
168 for line in it:
169 yield line
170
141 171
142 172 class InteractivelyDefined(Exception):
143 173 """Exception for interactively defined variable in magic_edit"""
144 174 def __init__(self, index):
145 175 self.index = index
146 176
147 177
148 178 @magics_class
149 179 class CodeMagics(Magics):
150 180 """Magics related to code management (loading, saving, editing, ...)."""
151 181
152 182 def __init__(self, *args, **kwargs):
153 183 self._knowntemps = set()
154 184 super(CodeMagics, self).__init__(*args, **kwargs)
155 185
156 186 @line_magic
157 187 def save(self, parameter_s=''):
158 188 """Save a set of lines or a macro to a given filename.
159 189
160 190 Usage:\\
161 191 %save [options] filename n1-n2 n3-n4 ... n5 .. n6 ...
162 192
163 193 Options:
164 194
165 195 -r: use 'raw' input. By default, the 'processed' history is used,
166 196 so that magics are loaded in their transformed version to valid
167 197 Python. If this option is given, the raw input as typed as the
168 198 command line is used instead.
169 199
170 200 -f: force overwrite. If file exists, %save will prompt for overwrite
171 201 unless -f is given.
172 202
173 203 -a: append to the file instead of overwriting it.
174 204
175 205 This function uses the same syntax as %history for input ranges,
176 206 then saves the lines to the filename you specify.
177 207
178 208 It adds a '.py' extension to the file if you don't do so yourself, and
179 209 it asks for confirmation before overwriting existing files.
180 210
181 211 If `-r` option is used, the default extension is `.ipy`.
182 212 """
183 213
184 214 opts,args = self.parse_options(parameter_s,'fra',mode='list')
185 215 if not args:
186 216 raise UsageError('Missing filename.')
187 217 raw = 'r' in opts
188 218 force = 'f' in opts
189 219 append = 'a' in opts
190 220 mode = 'a' if append else 'w'
191 221 ext = u'.ipy' if raw else u'.py'
192 222 fname, codefrom = args[0], " ".join(args[1:])
193 223 if not fname.endswith((u'.py',u'.ipy')):
194 224 fname += ext
195 225 file_exists = os.path.isfile(fname)
196 226 if file_exists and not force and not append:
197 227 try:
198 228 overwrite = self.shell.ask_yes_no('File `%s` exists. Overwrite (y/[N])? ' % fname, default='n')
199 229 except StdinNotImplementedError:
200 230 print("File `%s` exists. Use `%%save -f %s` to force overwrite" % (fname, parameter_s))
201 231 return
202 232 if not overwrite :
203 233 print('Operation cancelled.')
204 234 return
205 235 try:
206 236 cmds = self.shell.find_user_code(codefrom,raw)
207 237 except (TypeError, ValueError) as e:
208 238 print(e.args[0])
209 239 return
210 240 out = py3compat.cast_unicode(cmds)
211 241 with io.open(fname, mode, encoding="utf-8") as f:
212 242 if not file_exists or not append:
213 243 f.write(u"# coding: utf-8\n")
214 244 f.write(out)
215 245 # make sure we end on a newline
216 246 if not out.endswith(u'\n'):
217 247 f.write(u'\n')
218 248 print('The following commands were written to file `%s`:' % fname)
219 249 print(cmds)
220 250
221 251 @line_magic
222 252 def pastebin(self, parameter_s=''):
223 253 """Upload code to Github's Gist paste bin, returning the URL.
224 254
225 255 Usage:\\
226 256 %pastebin [-d "Custom description"] 1-7
227 257
228 258 The argument can be an input history range, a filename, or the name of a
229 259 string or macro.
230 260
231 261 Options:
232 262
233 263 -d: Pass a custom description for the gist. The default will say
234 264 "Pasted from IPython".
235 265 """
236 266 opts, args = self.parse_options(parameter_s, 'd:')
237 267
238 268 try:
239 269 code = self.shell.find_user_code(args)
240 270 except (ValueError, TypeError) as e:
241 271 print(e.args[0])
242 272 return
243 273
244 274 # Deferred import
245 275 try:
246 276 from urllib.request import urlopen # Py 3
247 277 except ImportError:
248 278 from urllib2 import urlopen
249 279 import json
250 280 post_data = json.dumps({
251 281 "description": opts.get('d', "Pasted from IPython"),
252 282 "public": True,
253 283 "files": {
254 284 "file1.py": {
255 285 "content": code
256 286 }
257 287 }
258 288 }).encode('utf-8')
259 289
260 290 response = urlopen("https://api.github.com/gists", post_data)
261 291 response_data = json.loads(response.read().decode('utf-8'))
262 292 return response_data['html_url']
263 293
264 294 @line_magic
265 295 def loadpy(self, arg_s):
266 296 """Alias of `%load`
267 297
268 298 `%loadpy` has gained some flexibility and dropped the requirement of a `.py`
269 299 extension. So it has been renamed simply into %load. You can look at
270 300 `%load`'s docstring for more info.
271 301 """
272 302 self.load(arg_s)
273 303
274 304 @line_magic
275 305 def load(self, arg_s):
276 306 """Load code into the current frontend.
277 307
278 308 Usage:\\
279 309 %load [options] source
280 310
281 311 where source can be a filename, URL, input history range, macro, or
282 312 element in the user namespace
283 313
284 314 Options:
285 315
286 316 -r <lines>: Specify lines or ranges of lines to load from the source.
287 317 Ranges could be specified as x-y (x..y) or in python-style x:y
288 318 (x..(y-1)). Both limits x and y can be left blank (meaning the
289 319 beginning and end of the file, respectively).
290 320
291 321 -s <symbols>: Specify function or classes to load from python source.
292 322
293 323 -y : Don't ask confirmation for loading source above 200 000 characters.
294 324
295 325 -n : Include the user's namespace when searching for source code.
296 326
297 327 This magic command can either take a local filename, a URL, an history
298 328 range (see %history) or a macro as argument, it will prompt for
299 329 confirmation before loading source with more than 200 000 characters, unless
300 330 -y flag is passed or if the frontend does not support raw_input::
301 331
302 332 %load myscript.py
303 333 %load 7-27
304 334 %load myMacro
305 335 %load http://www.example.com/myscript.py
306 336 %load -r 5-10 myscript.py
307 337 %load -r 10-20,30,40: foo.py
308 338 %load -s MyClass,wonder_function myscript.py
309 339 %load -n MyClass
310 340 %load -n my_module.wonder_function
311 341 """
312 342 opts,args = self.parse_options(arg_s,'yns:r:')
313 343
314 344 if not args:
315 345 raise UsageError('Missing filename, URL, input history range, '
316 346 'macro, or element in the user namespace.')
317 347
318 348 search_ns = 'n' in opts
319 349
320 350 contents = self.shell.find_user_code(args, search_ns=search_ns)
321 351
322 352 if 's' in opts:
323 353 try:
324 354 blocks, not_found = extract_symbols(contents, opts['s'])
325 355 except SyntaxError:
326 356 # non python code
327 357 error("Unable to parse the input as valid Python code")
328 358 return
329 359
330 360 if len(not_found) == 1:
331 361 warn('The symbol `%s` was not found' % not_found[0])
332 362 elif len(not_found) > 1:
333 363 warn('The symbols %s were not found' % get_text_list(not_found,
334 364 wrap_item_with='`')
335 365 )
336 366
337 367 contents = '\n'.join(blocks)
338 368
339 369 if 'r' in opts:
340 370 ranges = opts['r'].replace(',', ' ')
341 371 lines = contents.split('\n')
342 372 slices = extract_code_ranges(ranges)
343 373 contents = [lines[slice(*slc)] for slc in slices]
344 contents = '\n'.join(chain.from_iterable(contents))
374 contents = '\n'.join(strip_initial_indent(chain.from_iterable(contents)))
345 375
346 376 l = len(contents)
347 377
348 378 # 200 000 is ~ 2500 full 80 caracter lines
349 379 # so in average, more than 5000 lines
350 380 if l > 200000 and 'y' not in opts:
351 381 try:
352 382 ans = self.shell.ask_yes_no(("The text you're trying to load seems pretty big"\
353 383 " (%d characters). Continue (y/[N]) ?" % l), default='n' )
354 384 except StdinNotImplementedError:
355 385 #asume yes if raw input not implemented
356 386 ans = True
357 387
358 388 if ans is False :
359 389 print('Operation cancelled.')
360 390 return
361 391
362 392 contents = "# %load {}\n".format(arg_s) + contents
363 393
364 394 self.shell.set_next_input(contents, replace=True)
365 395
366 396 @staticmethod
367 397 def _find_edit_target(shell, args, opts, last_call):
368 398 """Utility method used by magic_edit to find what to edit."""
369 399
370 400 def make_filename(arg):
371 401 "Make a filename from the given args"
372 402 try:
373 403 filename = get_py_filename(arg)
374 404 except IOError:
375 405 # If it ends with .py but doesn't already exist, assume we want
376 406 # a new file.
377 407 if arg.endswith('.py'):
378 408 filename = arg
379 409 else:
380 410 filename = None
381 411 return filename
382 412
383 413 # Set a few locals from the options for convenience:
384 414 opts_prev = 'p' in opts
385 415 opts_raw = 'r' in opts
386 416
387 417 # custom exceptions
388 418 class DataIsObject(Exception): pass
389 419
390 420 # Default line number value
391 421 lineno = opts.get('n',None)
392 422
393 423 if opts_prev:
394 424 args = '_%s' % last_call[0]
395 425 if args not in shell.user_ns:
396 426 args = last_call[1]
397 427
398 428 # by default this is done with temp files, except when the given
399 429 # arg is a filename
400 430 use_temp = True
401 431
402 432 data = ''
403 433
404 434 # First, see if the arguments should be a filename.
405 435 filename = make_filename(args)
406 436 if filename:
407 437 use_temp = False
408 438 elif args:
409 439 # Mode where user specifies ranges of lines, like in %macro.
410 440 data = shell.extract_input_lines(args, opts_raw)
411 441 if not data:
412 442 try:
413 443 # Load the parameter given as a variable. If not a string,
414 444 # process it as an object instead (below)
415 445
416 446 #print '*** args',args,'type',type(args) # dbg
417 447 data = eval(args, shell.user_ns)
418 448 if not isinstance(data, string_types):
419 449 raise DataIsObject
420 450
421 451 except (NameError,SyntaxError):
422 452 # given argument is not a variable, try as a filename
423 453 filename = make_filename(args)
424 454 if filename is None:
425 455 warn("Argument given (%s) can't be found as a variable "
426 456 "or as a filename." % args)
427 457 return (None, None, None)
428 458 use_temp = False
429 459
430 460 except DataIsObject:
431 461 # macros have a special edit function
432 462 if isinstance(data, Macro):
433 463 raise MacroToEdit(data)
434 464
435 465 # For objects, try to edit the file where they are defined
436 466 filename = find_file(data)
437 467 if filename:
438 468 if 'fakemodule' in filename.lower() and \
439 469 inspect.isclass(data):
440 470 # class created by %edit? Try to find source
441 471 # by looking for method definitions instead, the
442 472 # __module__ in those classes is FakeModule.
443 473 attrs = [getattr(data, aname) for aname in dir(data)]
444 474 for attr in attrs:
445 475 if not inspect.ismethod(attr):
446 476 continue
447 477 filename = find_file(attr)
448 478 if filename and \
449 479 'fakemodule' not in filename.lower():
450 480 # change the attribute to be the edit
451 481 # target instead
452 482 data = attr
453 483 break
454 484
455 485 m = ipython_input_pat.match(os.path.basename(filename))
456 486 if m:
457 487 raise InteractivelyDefined(int(m.groups()[0]))
458 488
459 489 datafile = 1
460 490 if filename is None:
461 491 filename = make_filename(args)
462 492 datafile = 1
463 493 if filename is not None:
464 494 # only warn about this if we get a real name
465 495 warn('Could not find file where `%s` is defined.\n'
466 496 'Opening a file named `%s`' % (args, filename))
467 497 # Now, make sure we can actually read the source (if it was
468 498 # in a temp file it's gone by now).
469 499 if datafile:
470 500 if lineno is None:
471 501 lineno = find_source_lines(data)
472 502 if lineno is None:
473 503 filename = make_filename(args)
474 504 if filename is None:
475 505 warn('The file where `%s` was defined '
476 506 'cannot be read or found.' % data)
477 507 return (None, None, None)
478 508 use_temp = False
479 509
480 510 if use_temp:
481 511 filename = shell.mktempfile(data)
482 512 print('IPython will make a temporary file named:',filename)
483 513
484 514 # use last_call to remember the state of the previous call, but don't
485 515 # let it be clobbered by successive '-p' calls.
486 516 try:
487 517 last_call[0] = shell.displayhook.prompt_count
488 518 if not opts_prev:
489 519 last_call[1] = args
490 520 except:
491 521 pass
492 522
493 523
494 524 return filename, lineno, use_temp
495 525
496 526 def _edit_macro(self,mname,macro):
497 527 """open an editor with the macro data in a file"""
498 528 filename = self.shell.mktempfile(macro.value)
499 529 self.shell.hooks.editor(filename)
500 530
501 531 # and make a new macro object, to replace the old one
502 532 with open(filename) as mfile:
503 533 mvalue = mfile.read()
504 534 self.shell.user_ns[mname] = Macro(mvalue)
505 535
506 536 @skip_doctest
507 537 @line_magic
508 538 def edit(self, parameter_s='',last_call=['','']):
509 539 """Bring up an editor and execute the resulting code.
510 540
511 541 Usage:
512 542 %edit [options] [args]
513 543
514 544 %edit runs IPython's editor hook. The default version of this hook is
515 545 set to call the editor specified by your $EDITOR environment variable.
516 546 If this isn't found, it will default to vi under Linux/Unix and to
517 547 notepad under Windows. See the end of this docstring for how to change
518 548 the editor hook.
519 549
520 550 You can also set the value of this editor via the
521 551 ``TerminalInteractiveShell.editor`` option in your configuration file.
522 552 This is useful if you wish to use a different editor from your typical
523 553 default with IPython (and for Windows users who typically don't set
524 554 environment variables).
525 555
526 556 This command allows you to conveniently edit multi-line code right in
527 557 your IPython session.
528 558
529 559 If called without arguments, %edit opens up an empty editor with a
530 560 temporary file and will execute the contents of this file when you
531 561 close it (don't forget to save it!).
532 562
533 563
534 564 Options:
535 565
536 566 -n <number>: open the editor at a specified line number. By default,
537 567 the IPython editor hook uses the unix syntax 'editor +N filename', but
538 568 you can configure this by providing your own modified hook if your
539 569 favorite editor supports line-number specifications with a different
540 570 syntax.
541 571
542 572 -p: this will call the editor with the same data as the previous time
543 573 it was used, regardless of how long ago (in your current session) it
544 574 was.
545 575
546 576 -r: use 'raw' input. This option only applies to input taken from the
547 577 user's history. By default, the 'processed' history is used, so that
548 578 magics are loaded in their transformed version to valid Python. If
549 579 this option is given, the raw input as typed as the command line is
550 580 used instead. When you exit the editor, it will be executed by
551 581 IPython's own processor.
552 582
553 583 -x: do not execute the edited code immediately upon exit. This is
554 584 mainly useful if you are editing programs which need to be called with
555 585 command line arguments, which you can then do using %run.
556 586
557 587
558 588 Arguments:
559 589
560 590 If arguments are given, the following possibilities exist:
561 591
562 592 - If the argument is a filename, IPython will load that into the
563 593 editor. It will execute its contents with execfile() when you exit,
564 594 loading any code in the file into your interactive namespace.
565 595
566 596 - The arguments are ranges of input history, e.g. "7 ~1/4-6".
567 597 The syntax is the same as in the %history magic.
568 598
569 599 - If the argument is a string variable, its contents are loaded
570 600 into the editor. You can thus edit any string which contains
571 601 python code (including the result of previous edits).
572 602
573 603 - If the argument is the name of an object (other than a string),
574 604 IPython will try to locate the file where it was defined and open the
575 605 editor at the point where it is defined. You can use `%edit function`
576 606 to load an editor exactly at the point where 'function' is defined,
577 607 edit it and have the file be executed automatically.
578 608
579 609 - If the object is a macro (see %macro for details), this opens up your
580 610 specified editor with a temporary file containing the macro's data.
581 611 Upon exit, the macro is reloaded with the contents of the file.
582 612
583 613 Note: opening at an exact line is only supported under Unix, and some
584 614 editors (like kedit and gedit up to Gnome 2.8) do not understand the
585 615 '+NUMBER' parameter necessary for this feature. Good editors like
586 616 (X)Emacs, vi, jed, pico and joe all do.
587 617
588 618 After executing your code, %edit will return as output the code you
589 619 typed in the editor (except when it was an existing file). This way
590 620 you can reload the code in further invocations of %edit as a variable,
591 621 via _<NUMBER> or Out[<NUMBER>], where <NUMBER> is the prompt number of
592 622 the output.
593 623
594 624 Note that %edit is also available through the alias %ed.
595 625
596 626 This is an example of creating a simple function inside the editor and
597 627 then modifying it. First, start up the editor::
598 628
599 629 In [1]: edit
600 630 Editing... done. Executing edited code...
601 631 Out[1]: 'def foo():\\n print "foo() was defined in an editing
602 632 session"\\n'
603 633
604 634 We can then call the function foo()::
605 635
606 636 In [2]: foo()
607 637 foo() was defined in an editing session
608 638
609 639 Now we edit foo. IPython automatically loads the editor with the
610 640 (temporary) file where foo() was previously defined::
611 641
612 642 In [3]: edit foo
613 643 Editing... done. Executing edited code...
614 644
615 645 And if we call foo() again we get the modified version::
616 646
617 647 In [4]: foo()
618 648 foo() has now been changed!
619 649
620 650 Here is an example of how to edit a code snippet successive
621 651 times. First we call the editor::
622 652
623 653 In [5]: edit
624 654 Editing... done. Executing edited code...
625 655 hello
626 656 Out[5]: "print 'hello'\\n"
627 657
628 658 Now we call it again with the previous output (stored in _)::
629 659
630 660 In [6]: edit _
631 661 Editing... done. Executing edited code...
632 662 hello world
633 663 Out[6]: "print 'hello world'\\n"
634 664
635 665 Now we call it with the output #8 (stored in _8, also as Out[8])::
636 666
637 667 In [7]: edit _8
638 668 Editing... done. Executing edited code...
639 669 hello again
640 670 Out[7]: "print 'hello again'\\n"
641 671
642 672
643 673 Changing the default editor hook:
644 674
645 675 If you wish to write your own editor hook, you can put it in a
646 676 configuration file which you load at startup time. The default hook
647 677 is defined in the IPython.core.hooks module, and you can use that as a
648 678 starting example for further modifications. That file also has
649 679 general instructions on how to set a new hook for use once you've
650 680 defined it."""
651 681 opts,args = self.parse_options(parameter_s,'prxn:')
652 682
653 683 try:
654 684 filename, lineno, is_temp = self._find_edit_target(self.shell,
655 685 args, opts, last_call)
656 686 except MacroToEdit as e:
657 687 self._edit_macro(args, e.args[0])
658 688 return
659 689 except InteractivelyDefined as e:
660 690 print("Editing In[%i]" % e.index)
661 691 args = str(e.index)
662 692 filename, lineno, is_temp = self._find_edit_target(self.shell,
663 693 args, opts, last_call)
664 694 if filename is None:
665 695 # nothing was found, warnings have already been issued,
666 696 # just give up.
667 697 return
668 698
669 699 if is_temp:
670 700 self._knowntemps.add(filename)
671 701 elif (filename in self._knowntemps):
672 702 is_temp = True
673 703
674 704
675 705 # do actual editing here
676 706 print('Editing...', end=' ')
677 707 sys.stdout.flush()
678 708 try:
679 709 # Quote filenames that may have spaces in them
680 710 if ' ' in filename:
681 711 filename = "'%s'" % filename
682 712 self.shell.hooks.editor(filename,lineno)
683 713 except TryNext:
684 714 warn('Could not open editor')
685 715 return
686 716
687 717 # XXX TODO: should this be generalized for all string vars?
688 718 # For now, this is special-cased to blocks created by cpaste
689 719 if args.strip() == 'pasted_block':
690 720 with open(filename, 'r') as f:
691 721 self.shell.user_ns['pasted_block'] = f.read()
692 722
693 723 if 'x' in opts: # -x prevents actual execution
694 724 print()
695 725 else:
696 726 print('done. Executing edited code...')
697 727 with preserve_keys(self.shell.user_ns, '__file__'):
698 728 if not is_temp:
699 729 self.shell.user_ns['__file__'] = filename
700 730 if 'r' in opts: # Untranslated IPython code
701 731 with open(filename, 'r') as f:
702 732 source = f.read()
703 733 self.shell.run_cell(source, store_history=False)
704 734 else:
705 735 self.shell.safe_execfile(filename, self.shell.user_ns,
706 736 self.shell.user_ns)
707 737
708 738 if is_temp:
709 739 try:
710 740 return open(filename).read()
711 741 except IOError as msg:
712 742 if msg.filename == filename:
713 743 warn('File not found. Did you forget to save?')
714 744 return
715 745 else:
716 746 self.shell.showtraceback()
@@ -1,1002 +1,1011 b''
1 1 # -*- coding: utf-8 -*-
2 2 """Tests for various magic functions.
3 3
4 4 Needs to be run by nose (to make ipython session available).
5 5 """
6 6 from __future__ import absolute_import
7 7
8 8 import io
9 9 import os
10 10 import sys
11 11 import warnings
12 12 from unittest import TestCase
13 13
14 14 try:
15 15 from importlib import invalidate_caches # Required from Python 3.3
16 16 except ImportError:
17 17 def invalidate_caches():
18 18 pass
19 19
20 20 import nose.tools as nt
21 21
22 22 from IPython import get_ipython
23 23 from IPython.core import magic
24 24 from IPython.core.error import UsageError
25 25 from IPython.core.magic import (Magics, magics_class, line_magic,
26 26 cell_magic,
27 27 register_line_magic, register_cell_magic)
28 28 from IPython.core.magics import execution, script, code
29 29 from IPython.testing import decorators as dec
30 30 from IPython.testing import tools as tt
31 31 from IPython.utils import py3compat
32 32 from IPython.utils.io import capture_output
33 33 from IPython.utils.tempdir import TemporaryDirectory
34 34 from IPython.utils.process import find_cmd
35 35
36 36 if py3compat.PY3:
37 37 from io import StringIO
38 38 else:
39 39 from StringIO import StringIO
40 40
41 41
42 42 _ip = get_ipython()
43 43
44 44 @magic.magics_class
45 45 class DummyMagics(magic.Magics): pass
46 46
47 47 def test_extract_code_ranges():
48 48 instr = "1 3 5-6 7-9 10:15 17: :10 10- -13 :"
49 49 expected = [(0, 1),
50 50 (2, 3),
51 51 (4, 6),
52 52 (6, 9),
53 53 (9, 14),
54 54 (16, None),
55 55 (None, 9),
56 56 (9, None),
57 57 (None, 13),
58 58 (None, None)]
59 59 actual = list(code.extract_code_ranges(instr))
60 60 nt.assert_equal(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 nt.assert_equal(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 nt.assert_raises(SyntaxError):
81 81 code.extract_symbols(source, "hello")
82 82
83 83 def test_config():
84 84 """ test that config magic does not raise
85 85 can happen if Configurable init is moved too early into
86 86 Magics.__init__ as then a Config object will be registerd as a
87 87 magic.
88 88 """
89 89 ## should not raise.
90 90 _ip.magic('config')
91 91
92 92 def test_rehashx():
93 93 # clear up everything
94 94 _ip.alias_manager.clear_aliases()
95 95 del _ip.db['syscmdlist']
96 96
97 97 _ip.magic('rehashx')
98 98 # Practically ALL ipython development systems will have more than 10 aliases
99 99
100 100 nt.assert_true(len(_ip.alias_manager.aliases) > 10)
101 101 for name, cmd in _ip.alias_manager.aliases:
102 102 # we must strip dots from alias names
103 103 nt.assert_not_in('.', name)
104 104
105 105 # rehashx must fill up syscmdlist
106 106 scoms = _ip.db['syscmdlist']
107 107 nt.assert_true(len(scoms) > 10)
108 108
109 109
110 110 def test_magic_parse_options():
111 111 """Test that we don't mangle paths when parsing magic options."""
112 112 ip = get_ipython()
113 113 path = 'c:\\x'
114 114 m = DummyMagics(ip)
115 115 opts = m.parse_options('-f %s' % path,'f:')[0]
116 116 # argv splitting is os-dependent
117 117 if os.name == 'posix':
118 118 expected = 'c:x'
119 119 else:
120 120 expected = path
121 121 nt.assert_equal(opts['f'], expected)
122 122
123 123 def test_magic_parse_long_options():
124 124 """Magic.parse_options can handle --foo=bar long options"""
125 125 ip = get_ipython()
126 126 m = DummyMagics(ip)
127 127 opts, _ = m.parse_options('--foo --bar=bubble', 'a', 'foo', 'bar=')
128 128 nt.assert_in('foo', opts)
129 129 nt.assert_in('bar', opts)
130 130 nt.assert_equal(opts['bar'], "bubble")
131 131
132 132
133 133 @dec.skip_without('sqlite3')
134 134 def doctest_hist_f():
135 135 """Test %hist -f with temporary filename.
136 136
137 137 In [9]: import tempfile
138 138
139 139 In [10]: tfile = tempfile.mktemp('.py','tmp-ipython-')
140 140
141 141 In [11]: %hist -nl -f $tfile 3
142 142
143 143 In [13]: import os; os.unlink(tfile)
144 144 """
145 145
146 146
147 147 @dec.skip_without('sqlite3')
148 148 def doctest_hist_r():
149 149 """Test %hist -r
150 150
151 151 XXX - This test is not recording the output correctly. For some reason, in
152 152 testing mode the raw history isn't getting populated. No idea why.
153 153 Disabling the output checking for now, though at least we do run it.
154 154
155 155 In [1]: 'hist' in _ip.lsmagic()
156 156 Out[1]: True
157 157
158 158 In [2]: x=1
159 159
160 160 In [3]: %hist -rl 2
161 161 x=1 # random
162 162 %hist -r 2
163 163 """
164 164
165 165
166 166 @dec.skip_without('sqlite3')
167 167 def doctest_hist_op():
168 168 """Test %hist -op
169 169
170 170 In [1]: class b(float):
171 171 ...: pass
172 172 ...:
173 173
174 174 In [2]: class s(object):
175 175 ...: def __str__(self):
176 176 ...: return 's'
177 177 ...:
178 178
179 179 In [3]:
180 180
181 181 In [4]: class r(b):
182 182 ...: def __repr__(self):
183 183 ...: return 'r'
184 184 ...:
185 185
186 186 In [5]: class sr(s,r): pass
187 187 ...:
188 188
189 189 In [6]:
190 190
191 191 In [7]: bb=b()
192 192
193 193 In [8]: ss=s()
194 194
195 195 In [9]: rr=r()
196 196
197 197 In [10]: ssrr=sr()
198 198
199 199 In [11]: 4.5
200 200 Out[11]: 4.5
201 201
202 202 In [12]: str(ss)
203 203 Out[12]: 's'
204 204
205 205 In [13]:
206 206
207 207 In [14]: %hist -op
208 208 >>> class b:
209 209 ... pass
210 210 ...
211 211 >>> class s(b):
212 212 ... def __str__(self):
213 213 ... return 's'
214 214 ...
215 215 >>>
216 216 >>> class r(b):
217 217 ... def __repr__(self):
218 218 ... return 'r'
219 219 ...
220 220 >>> class sr(s,r): pass
221 221 >>>
222 222 >>> bb=b()
223 223 >>> ss=s()
224 224 >>> rr=r()
225 225 >>> ssrr=sr()
226 226 >>> 4.5
227 227 4.5
228 228 >>> str(ss)
229 229 's'
230 230 >>>
231 231 """
232 232
233 233 def test_hist_pof():
234 234 ip = get_ipython()
235 235 ip.run_cell(u"1+2", store_history=True)
236 236 #raise Exception(ip.history_manager.session_number)
237 237 #raise Exception(list(ip.history_manager._get_range_session()))
238 238 with TemporaryDirectory() as td:
239 239 tf = os.path.join(td, 'hist.py')
240 240 ip.run_line_magic('history', '-pof %s' % tf)
241 241 assert os.path.isfile(tf)
242 242
243 243
244 244 @dec.skip_without('sqlite3')
245 245 def test_macro():
246 246 ip = get_ipython()
247 247 ip.history_manager.reset() # Clear any existing history.
248 248 cmds = ["a=1", "def b():\n return a**2", "print(a,b())"]
249 249 for i, cmd in enumerate(cmds, start=1):
250 250 ip.history_manager.store_inputs(i, cmd)
251 251 ip.magic("macro test 1-3")
252 252 nt.assert_equal(ip.user_ns["test"].value, "\n".join(cmds)+"\n")
253 253
254 254 # List macros
255 255 nt.assert_in("test", ip.magic("macro"))
256 256
257 257
258 258 @dec.skip_without('sqlite3')
259 259 def test_macro_run():
260 260 """Test that we can run a multi-line macro successfully."""
261 261 ip = get_ipython()
262 262 ip.history_manager.reset()
263 263 cmds = ["a=10", "a+=1", py3compat.doctest_refactor_print("print a"),
264 264 "%macro test 2-3"]
265 265 for cmd in cmds:
266 266 ip.run_cell(cmd, store_history=True)
267 267 nt.assert_equal(ip.user_ns["test"].value,
268 268 py3compat.doctest_refactor_print("a+=1\nprint a\n"))
269 269 with tt.AssertPrints("12"):
270 270 ip.run_cell("test")
271 271 with tt.AssertPrints("13"):
272 272 ip.run_cell("test")
273 273
274 274
275 275 def test_magic_magic():
276 276 """Test %magic"""
277 277 ip = get_ipython()
278 278 with capture_output() as captured:
279 279 ip.magic("magic")
280 280
281 281 stdout = captured.stdout
282 282 nt.assert_in('%magic', stdout)
283 283 nt.assert_in('IPython', stdout)
284 284 nt.assert_in('Available', stdout)
285 285
286 286
287 287 @dec.skipif_not_numpy
288 288 def test_numpy_reset_array_undec():
289 289 "Test '%reset array' functionality"
290 290 _ip.ex('import numpy as np')
291 291 _ip.ex('a = np.empty(2)')
292 292 nt.assert_in('a', _ip.user_ns)
293 293 _ip.magic('reset -f array')
294 294 nt.assert_not_in('a', _ip.user_ns)
295 295
296 296 def test_reset_out():
297 297 "Test '%reset out' magic"
298 298 _ip.run_cell("parrot = 'dead'", store_history=True)
299 299 # test '%reset -f out', make an Out prompt
300 300 _ip.run_cell("parrot", store_history=True)
301 301 nt.assert_true('dead' in [_ip.user_ns[x] for x in ('_','__','___')])
302 302 _ip.magic('reset -f out')
303 303 nt.assert_false('dead' in [_ip.user_ns[x] for x in ('_','__','___')])
304 304 nt.assert_equal(len(_ip.user_ns['Out']), 0)
305 305
306 306 def test_reset_in():
307 307 "Test '%reset in' magic"
308 308 # test '%reset -f in'
309 309 _ip.run_cell("parrot", store_history=True)
310 310 nt.assert_true('parrot' in [_ip.user_ns[x] for x in ('_i','_ii','_iii')])
311 311 _ip.magic('%reset -f in')
312 312 nt.assert_false('parrot' in [_ip.user_ns[x] for x in ('_i','_ii','_iii')])
313 313 nt.assert_equal(len(set(_ip.user_ns['In'])), 1)
314 314
315 315 def test_reset_dhist():
316 316 "Test '%reset dhist' magic"
317 317 _ip.run_cell("tmp = [d for d in _dh]") # copy before clearing
318 318 _ip.magic('cd ' + os.path.dirname(nt.__file__))
319 319 _ip.magic('cd -')
320 320 nt.assert_true(len(_ip.user_ns['_dh']) > 0)
321 321 _ip.magic('reset -f dhist')
322 322 nt.assert_equal(len(_ip.user_ns['_dh']), 0)
323 323 _ip.run_cell("_dh = [d for d in tmp]") #restore
324 324
325 325 def test_reset_in_length():
326 326 "Test that '%reset in' preserves In[] length"
327 327 _ip.run_cell("print 'foo'")
328 328 _ip.run_cell("reset -f in")
329 329 nt.assert_equal(len(_ip.user_ns['In']), _ip.displayhook.prompt_count+1)
330 330
331 331 def test_tb_syntaxerror():
332 332 """test %tb after a SyntaxError"""
333 333 ip = get_ipython()
334 334 ip.run_cell("for")
335 335
336 336 # trap and validate stdout
337 337 save_stdout = sys.stdout
338 338 try:
339 339 sys.stdout = StringIO()
340 340 ip.run_cell("%tb")
341 341 out = sys.stdout.getvalue()
342 342 finally:
343 343 sys.stdout = save_stdout
344 344 # trim output, and only check the last line
345 345 last_line = out.rstrip().splitlines()[-1].strip()
346 346 nt.assert_equal(last_line, "SyntaxError: invalid syntax")
347 347
348 348
349 349 def test_time():
350 350 ip = get_ipython()
351 351
352 352 with tt.AssertPrints("Wall time: "):
353 353 ip.run_cell("%time None")
354 354
355 355 ip.run_cell("def f(kmjy):\n"
356 356 " %time print (2*kmjy)")
357 357
358 358 with tt.AssertPrints("Wall time: "):
359 359 with tt.AssertPrints("hihi", suppress=False):
360 360 ip.run_cell("f('hi')")
361 361
362 362
363 363 @dec.skip_win32
364 364 def test_time2():
365 365 ip = get_ipython()
366 366
367 367 with tt.AssertPrints("CPU times: user "):
368 368 ip.run_cell("%time None")
369 369
370 370 def test_time3():
371 371 """Erroneous magic function calls, issue gh-3334"""
372 372 ip = get_ipython()
373 373 ip.user_ns.pop('run', None)
374 374
375 375 with tt.AssertNotPrints("not found", channel='stderr'):
376 376 ip.run_cell("%%time\n"
377 377 "run = 0\n"
378 378 "run += 1")
379 379
380 380 @dec.skipif(sys.version_info[0] >= 3, "no differences with __future__ in py3")
381 381 def test_time_futures():
382 382 "Test %time with __future__ environments"
383 383 ip = get_ipython()
384 384 ip.autocall = 0
385 385 ip.run_cell("from __future__ import division")
386 386 with tt.AssertPrints('0.25'):
387 387 ip.run_line_magic('time', 'print(1/4)')
388 388 ip.compile.reset_compiler_flags()
389 389 with tt.AssertNotPrints('0.25'):
390 390 ip.run_line_magic('time', 'print(1/4)')
391 391
392 392 def test_doctest_mode():
393 393 "Toggle doctest_mode twice, it should be a no-op and run without error"
394 394 _ip.magic('doctest_mode')
395 395 _ip.magic('doctest_mode')
396 396
397 397
398 398 def test_parse_options():
399 399 """Tests for basic options parsing in magics."""
400 400 # These are only the most minimal of tests, more should be added later. At
401 401 # the very least we check that basic text/unicode calls work OK.
402 402 m = DummyMagics(_ip)
403 403 nt.assert_equal(m.parse_options('foo', '')[1], 'foo')
404 404 nt.assert_equal(m.parse_options(u'foo', '')[1], u'foo')
405 405
406 406
407 407 def test_dirops():
408 408 """Test various directory handling operations."""
409 409 # curpath = lambda :os.path.splitdrive(py3compat.getcwd())[1].replace('\\','/')
410 410 curpath = py3compat.getcwd
411 411 startdir = py3compat.getcwd()
412 412 ipdir = os.path.realpath(_ip.ipython_dir)
413 413 try:
414 414 _ip.magic('cd "%s"' % ipdir)
415 415 nt.assert_equal(curpath(), ipdir)
416 416 _ip.magic('cd -')
417 417 nt.assert_equal(curpath(), startdir)
418 418 _ip.magic('pushd "%s"' % ipdir)
419 419 nt.assert_equal(curpath(), ipdir)
420 420 _ip.magic('popd')
421 421 nt.assert_equal(curpath(), startdir)
422 422 finally:
423 423 os.chdir(startdir)
424 424
425 425
426 426 def test_xmode():
427 427 # Calling xmode three times should be a no-op
428 428 xmode = _ip.InteractiveTB.mode
429 429 for i in range(3):
430 430 _ip.magic("xmode")
431 431 nt.assert_equal(_ip.InteractiveTB.mode, xmode)
432 432
433 433 def test_reset_hard():
434 434 monitor = []
435 435 class A(object):
436 436 def __del__(self):
437 437 monitor.append(1)
438 438 def __repr__(self):
439 439 return "<A instance>"
440 440
441 441 _ip.user_ns["a"] = A()
442 442 _ip.run_cell("a")
443 443
444 444 nt.assert_equal(monitor, [])
445 445 _ip.magic("reset -f")
446 446 nt.assert_equal(monitor, [1])
447 447
448 448 class TestXdel(tt.TempFileMixin):
449 449 def test_xdel(self):
450 450 """Test that references from %run are cleared by xdel."""
451 451 src = ("class A(object):\n"
452 452 " monitor = []\n"
453 453 " def __del__(self):\n"
454 454 " self.monitor.append(1)\n"
455 455 "a = A()\n")
456 456 self.mktmp(src)
457 457 # %run creates some hidden references...
458 458 _ip.magic("run %s" % self.fname)
459 459 # ... as does the displayhook.
460 460 _ip.run_cell("a")
461 461
462 462 monitor = _ip.user_ns["A"].monitor
463 463 nt.assert_equal(monitor, [])
464 464
465 465 _ip.magic("xdel a")
466 466
467 467 # Check that a's __del__ method has been called.
468 468 nt.assert_equal(monitor, [1])
469 469
470 470 def doctest_who():
471 471 """doctest for %who
472 472
473 473 In [1]: %reset -f
474 474
475 475 In [2]: alpha = 123
476 476
477 477 In [3]: beta = 'beta'
478 478
479 479 In [4]: %who int
480 480 alpha
481 481
482 482 In [5]: %who str
483 483 beta
484 484
485 485 In [6]: %whos
486 486 Variable Type Data/Info
487 487 ----------------------------
488 488 alpha int 123
489 489 beta str beta
490 490
491 491 In [7]: %who_ls
492 492 Out[7]: ['alpha', 'beta']
493 493 """
494 494
495 495 def test_whos():
496 496 """Check that whos is protected against objects where repr() fails."""
497 497 class A(object):
498 498 def __repr__(self):
499 499 raise Exception()
500 500 _ip.user_ns['a'] = A()
501 501 _ip.magic("whos")
502 502
503 503 @py3compat.u_format
504 504 def doctest_precision():
505 505 """doctest for %precision
506 506
507 507 In [1]: f = get_ipython().display_formatter.formatters['text/plain']
508 508
509 509 In [2]: %precision 5
510 510 Out[2]: {u}'%.5f'
511 511
512 512 In [3]: f.float_format
513 513 Out[3]: {u}'%.5f'
514 514
515 515 In [4]: %precision %e
516 516 Out[4]: {u}'%e'
517 517
518 518 In [5]: f(3.1415927)
519 519 Out[5]: {u}'3.141593e+00'
520 520 """
521 521
522 522 def test_psearch():
523 523 with tt.AssertPrints("dict.fromkeys"):
524 524 _ip.run_cell("dict.fr*?")
525 525
526 526 def test_timeit_shlex():
527 527 """test shlex issues with timeit (#1109)"""
528 528 _ip.ex("def f(*a,**kw): pass")
529 529 _ip.magic('timeit -n1 "this is a bug".count(" ")')
530 530 _ip.magic('timeit -r1 -n1 f(" ", 1)')
531 531 _ip.magic('timeit -r1 -n1 f(" ", 1, " ", 2, " ")')
532 532 _ip.magic('timeit -r1 -n1 ("a " + "b")')
533 533 _ip.magic('timeit -r1 -n1 f("a " + "b")')
534 534 _ip.magic('timeit -r1 -n1 f("a " + "b ")')
535 535
536 536
537 537 def test_timeit_arguments():
538 538 "Test valid timeit arguments, should not cause SyntaxError (GH #1269)"
539 539 _ip.magic("timeit ('#')")
540 540
541 541
542 542 def test_timeit_special_syntax():
543 543 "Test %%timeit with IPython special syntax"
544 544 @register_line_magic
545 545 def lmagic(line):
546 546 ip = get_ipython()
547 547 ip.user_ns['lmagic_out'] = line
548 548
549 549 # line mode test
550 550 _ip.run_line_magic('timeit', '-n1 -r1 %lmagic my line')
551 551 nt.assert_equal(_ip.user_ns['lmagic_out'], 'my line')
552 552 # cell mode test
553 553 _ip.run_cell_magic('timeit', '-n1 -r1', '%lmagic my line2')
554 554 nt.assert_equal(_ip.user_ns['lmagic_out'], 'my line2')
555 555
556 556 def test_timeit_return():
557 557 """
558 558 test wether timeit -o return object
559 559 """
560 560
561 561 res = _ip.run_line_magic('timeit','-n10 -r10 -o 1')
562 562 assert(res is not None)
563 563
564 564 def test_timeit_quiet():
565 565 """
566 566 test quiet option of timeit magic
567 567 """
568 568 with tt.AssertNotPrints("loops"):
569 569 _ip.run_cell("%timeit -n1 -r1 -q 1")
570 570
571 571 def test_timeit_return_quiet():
572 572 with tt.AssertNotPrints("loops"):
573 573 res = _ip.run_line_magic('timeit', '-n1 -r1 -q -o 1')
574 574 assert (res is not None)
575 575
576 576 @dec.skipif(sys.version_info[0] >= 3, "no differences with __future__ in py3")
577 577 def test_timeit_futures():
578 578 "Test %timeit with __future__ environments"
579 579 ip = get_ipython()
580 580 ip.run_cell("from __future__ import division")
581 581 with tt.AssertPrints('0.25'):
582 582 ip.run_line_magic('timeit', '-n1 -r1 print(1/4)')
583 583 ip.compile.reset_compiler_flags()
584 584 with tt.AssertNotPrints('0.25'):
585 585 ip.run_line_magic('timeit', '-n1 -r1 print(1/4)')
586 586
587 587 @dec.skipif(execution.profile is None)
588 588 def test_prun_special_syntax():
589 589 "Test %%prun with IPython special syntax"
590 590 @register_line_magic
591 591 def lmagic(line):
592 592 ip = get_ipython()
593 593 ip.user_ns['lmagic_out'] = line
594 594
595 595 # line mode test
596 596 _ip.run_line_magic('prun', '-q %lmagic my line')
597 597 nt.assert_equal(_ip.user_ns['lmagic_out'], 'my line')
598 598 # cell mode test
599 599 _ip.run_cell_magic('prun', '-q', '%lmagic my line2')
600 600 nt.assert_equal(_ip.user_ns['lmagic_out'], 'my line2')
601 601
602 602 @dec.skipif(execution.profile is None)
603 603 def test_prun_quotes():
604 604 "Test that prun does not clobber string escapes (GH #1302)"
605 605 _ip.magic(r"prun -q x = '\t'")
606 606 nt.assert_equal(_ip.user_ns['x'], '\t')
607 607
608 608 def test_extension():
609 609 # Debugging information for failures of this test
610 610 print('sys.path:')
611 611 for p in sys.path:
612 612 print(' ', p)
613 613 print('CWD', os.getcwd())
614 614
615 615 nt.assert_raises(ImportError, _ip.magic, "load_ext daft_extension")
616 616 daft_path = os.path.join(os.path.dirname(__file__), "daft_extension")
617 617 sys.path.insert(0, daft_path)
618 618 try:
619 619 _ip.user_ns.pop('arq', None)
620 620 invalidate_caches() # Clear import caches
621 621 _ip.magic("load_ext daft_extension")
622 622 nt.assert_equal(_ip.user_ns['arq'], 185)
623 623 _ip.magic("unload_ext daft_extension")
624 624 assert 'arq' not in _ip.user_ns
625 625 finally:
626 626 sys.path.remove(daft_path)
627 627
628 628
629 629 def test_notebook_export_json():
630 630 _ip = get_ipython()
631 631 _ip.history_manager.reset() # Clear any existing history.
632 632 cmds = [u"a=1", u"def b():\n return a**2", u"print('noΓ«l, Γ©tΓ©', b())"]
633 633 for i, cmd in enumerate(cmds, start=1):
634 634 _ip.history_manager.store_inputs(i, cmd)
635 635 with TemporaryDirectory() as td:
636 636 outfile = os.path.join(td, "nb.ipynb")
637 637 _ip.magic("notebook -e %s" % outfile)
638 638
639 639
640 640 class TestEnv(TestCase):
641 641
642 642 def test_env(self):
643 643 env = _ip.magic("env")
644 644 self.assertTrue(isinstance(env, dict))
645 645
646 646 def test_env_get_set_simple(self):
647 647 env = _ip.magic("env var val1")
648 648 self.assertEqual(env, None)
649 649 self.assertEqual(os.environ['var'], 'val1')
650 650 self.assertEqual(_ip.magic("env var"), 'val1')
651 651 env = _ip.magic("env var=val2")
652 652 self.assertEqual(env, None)
653 653 self.assertEqual(os.environ['var'], 'val2')
654 654
655 655 def test_env_get_set_complex(self):
656 656 env = _ip.magic("env var 'val1 '' 'val2")
657 657 self.assertEqual(env, None)
658 658 self.assertEqual(os.environ['var'], "'val1 '' 'val2")
659 659 self.assertEqual(_ip.magic("env var"), "'val1 '' 'val2")
660 660 env = _ip.magic('env var=val2 val3="val4')
661 661 self.assertEqual(env, None)
662 662 self.assertEqual(os.environ['var'], 'val2 val3="val4')
663 663
664 664 def test_env_set_bad_input(self):
665 665 self.assertRaises(UsageError, lambda: _ip.magic("set_env var"))
666 666
667 667 def test_env_set_whitespace(self):
668 668 self.assertRaises(UsageError, lambda: _ip.magic("env var A=B"))
669 669
670 670
671 671 class CellMagicTestCase(TestCase):
672 672
673 673 def check_ident(self, magic):
674 674 # Manually called, we get the result
675 675 out = _ip.run_cell_magic(magic, 'a', 'b')
676 676 nt.assert_equal(out, ('a','b'))
677 677 # Via run_cell, it goes into the user's namespace via displayhook
678 678 _ip.run_cell('%%' + magic +' c\nd')
679 679 nt.assert_equal(_ip.user_ns['_'], ('c','d'))
680 680
681 681 def test_cell_magic_func_deco(self):
682 682 "Cell magic using simple decorator"
683 683 @register_cell_magic
684 684 def cellm(line, cell):
685 685 return line, cell
686 686
687 687 self.check_ident('cellm')
688 688
689 689 def test_cell_magic_reg(self):
690 690 "Cell magic manually registered"
691 691 def cellm(line, cell):
692 692 return line, cell
693 693
694 694 _ip.register_magic_function(cellm, 'cell', 'cellm2')
695 695 self.check_ident('cellm2')
696 696
697 697 def test_cell_magic_class(self):
698 698 "Cell magics declared via a class"
699 699 @magics_class
700 700 class MyMagics(Magics):
701 701
702 702 @cell_magic
703 703 def cellm3(self, line, cell):
704 704 return line, cell
705 705
706 706 _ip.register_magics(MyMagics)
707 707 self.check_ident('cellm3')
708 708
709 709 def test_cell_magic_class2(self):
710 710 "Cell magics declared via a class, #2"
711 711 @magics_class
712 712 class MyMagics2(Magics):
713 713
714 714 @cell_magic('cellm4')
715 715 def cellm33(self, line, cell):
716 716 return line, cell
717 717
718 718 _ip.register_magics(MyMagics2)
719 719 self.check_ident('cellm4')
720 720 # Check that nothing is registered as 'cellm33'
721 721 c33 = _ip.find_cell_magic('cellm33')
722 722 nt.assert_equal(c33, None)
723 723
724 724 def test_file():
725 725 """Basic %%file"""
726 726 ip = get_ipython()
727 727 with TemporaryDirectory() as td:
728 728 fname = os.path.join(td, 'file1')
729 729 ip.run_cell_magic("file", fname, u'\n'.join([
730 730 'line1',
731 731 'line2',
732 732 ]))
733 733 with open(fname) as f:
734 734 s = f.read()
735 735 nt.assert_in('line1\n', s)
736 736 nt.assert_in('line2', s)
737 737
738 738 def test_file_var_expand():
739 739 """%%file $filename"""
740 740 ip = get_ipython()
741 741 with TemporaryDirectory() as td:
742 742 fname = os.path.join(td, 'file1')
743 743 ip.user_ns['filename'] = fname
744 744 ip.run_cell_magic("file", '$filename', u'\n'.join([
745 745 'line1',
746 746 'line2',
747 747 ]))
748 748 with open(fname) as f:
749 749 s = f.read()
750 750 nt.assert_in('line1\n', s)
751 751 nt.assert_in('line2', s)
752 752
753 753 def test_file_unicode():
754 754 """%%file with unicode cell"""
755 755 ip = get_ipython()
756 756 with TemporaryDirectory() as td:
757 757 fname = os.path.join(td, 'file1')
758 758 ip.run_cell_magic("file", fname, u'\n'.join([
759 759 u'linΓ©1',
760 760 u'linΓ©2',
761 761 ]))
762 762 with io.open(fname, encoding='utf-8') as f:
763 763 s = f.read()
764 764 nt.assert_in(u'linΓ©1\n', s)
765 765 nt.assert_in(u'linΓ©2', s)
766 766
767 767 def test_file_amend():
768 768 """%%file -a amends files"""
769 769 ip = get_ipython()
770 770 with TemporaryDirectory() as td:
771 771 fname = os.path.join(td, 'file2')
772 772 ip.run_cell_magic("file", fname, u'\n'.join([
773 773 'line1',
774 774 'line2',
775 775 ]))
776 776 ip.run_cell_magic("file", "-a %s" % fname, u'\n'.join([
777 777 'line3',
778 778 'line4',
779 779 ]))
780 780 with open(fname) as f:
781 781 s = f.read()
782 782 nt.assert_in('line1\n', s)
783 783 nt.assert_in('line3\n', s)
784 784
785 785
786 786 def test_script_config():
787 787 ip = get_ipython()
788 788 ip.config.ScriptMagics.script_magics = ['whoda']
789 789 sm = script.ScriptMagics(shell=ip)
790 790 nt.assert_in('whoda', sm.magics['cell'])
791 791
792 792 @dec.skip_win32
793 793 def test_script_out():
794 794 ip = get_ipython()
795 795 ip.run_cell_magic("script", "--out output sh", "echo 'hi'")
796 796 nt.assert_equal(ip.user_ns['output'], 'hi\n')
797 797
798 798 @dec.skip_win32
799 799 def test_script_err():
800 800 ip = get_ipython()
801 801 ip.run_cell_magic("script", "--err error sh", "echo 'hello' >&2")
802 802 nt.assert_equal(ip.user_ns['error'], 'hello\n')
803 803
804 804 @dec.skip_win32
805 805 def test_script_out_err():
806 806 ip = get_ipython()
807 807 ip.run_cell_magic("script", "--out output --err error sh", "echo 'hi'\necho 'hello' >&2")
808 808 nt.assert_equal(ip.user_ns['output'], 'hi\n')
809 809 nt.assert_equal(ip.user_ns['error'], 'hello\n')
810 810
811 811 @dec.skip_win32
812 812 def test_script_bg_out():
813 813 ip = get_ipython()
814 814 ip.run_cell_magic("script", "--bg --out output sh", "echo 'hi'")
815 815 nt.assert_equal(ip.user_ns['output'].read(), b'hi\n')
816 816
817 817 @dec.skip_win32
818 818 def test_script_bg_err():
819 819 ip = get_ipython()
820 820 ip.run_cell_magic("script", "--bg --err error sh", "echo 'hello' >&2")
821 821 nt.assert_equal(ip.user_ns['error'].read(), b'hello\n')
822 822
823 823 @dec.skip_win32
824 824 def test_script_bg_out_err():
825 825 ip = get_ipython()
826 826 ip.run_cell_magic("script", "--bg --out output --err error sh", "echo 'hi'\necho 'hello' >&2")
827 827 nt.assert_equal(ip.user_ns['output'].read(), b'hi\n')
828 828 nt.assert_equal(ip.user_ns['error'].read(), b'hello\n')
829 829
830 830 def test_script_defaults():
831 831 ip = get_ipython()
832 832 for cmd in ['sh', 'bash', 'perl', 'ruby']:
833 833 try:
834 834 find_cmd(cmd)
835 835 except Exception:
836 836 pass
837 837 else:
838 838 nt.assert_in(cmd, ip.magics_manager.magics['cell'])
839 839
840 840
841 841 @magics_class
842 842 class FooFoo(Magics):
843 843 """class with both %foo and %%foo magics"""
844 844 @line_magic('foo')
845 845 def line_foo(self, line):
846 846 "I am line foo"
847 847 pass
848 848
849 849 @cell_magic("foo")
850 850 def cell_foo(self, line, cell):
851 851 "I am cell foo, not line foo"
852 852 pass
853 853
854 854 def test_line_cell_info():
855 855 """%%foo and %foo magics are distinguishable to inspect"""
856 856 ip = get_ipython()
857 857 ip.magics_manager.register(FooFoo)
858 858 oinfo = ip.object_inspect('foo')
859 859 nt.assert_true(oinfo['found'])
860 860 nt.assert_true(oinfo['ismagic'])
861 861
862 862 oinfo = ip.object_inspect('%%foo')
863 863 nt.assert_true(oinfo['found'])
864 864 nt.assert_true(oinfo['ismagic'])
865 865 nt.assert_equal(oinfo['docstring'], FooFoo.cell_foo.__doc__)
866 866
867 867 oinfo = ip.object_inspect('%foo')
868 868 nt.assert_true(oinfo['found'])
869 869 nt.assert_true(oinfo['ismagic'])
870 870 nt.assert_equal(oinfo['docstring'], FooFoo.line_foo.__doc__)
871 871
872 872 def test_multiple_magics():
873 873 ip = get_ipython()
874 874 foo1 = FooFoo(ip)
875 875 foo2 = FooFoo(ip)
876 876 mm = ip.magics_manager
877 877 mm.register(foo1)
878 878 nt.assert_true(mm.magics['line']['foo'].__self__ is foo1)
879 879 mm.register(foo2)
880 880 nt.assert_true(mm.magics['line']['foo'].__self__ is foo2)
881 881
882 882 def test_alias_magic():
883 883 """Test %alias_magic."""
884 884 ip = get_ipython()
885 885 mm = ip.magics_manager
886 886
887 887 # Basic operation: both cell and line magics are created, if possible.
888 888 ip.run_line_magic('alias_magic', 'timeit_alias timeit')
889 889 nt.assert_in('timeit_alias', mm.magics['line'])
890 890 nt.assert_in('timeit_alias', mm.magics['cell'])
891 891
892 892 # --cell is specified, line magic not created.
893 893 ip.run_line_magic('alias_magic', '--cell timeit_cell_alias timeit')
894 894 nt.assert_not_in('timeit_cell_alias', mm.magics['line'])
895 895 nt.assert_in('timeit_cell_alias', mm.magics['cell'])
896 896
897 897 # Test that line alias is created successfully.
898 898 ip.run_line_magic('alias_magic', '--line env_alias env')
899 899 nt.assert_equal(ip.run_line_magic('env', ''),
900 900 ip.run_line_magic('env_alias', ''))
901 901
902 902 def test_save():
903 903 """Test %save."""
904 904 ip = get_ipython()
905 905 ip.history_manager.reset() # Clear any existing history.
906 906 cmds = [u"a=1", u"def b():\n return a**2", u"print(a, b())"]
907 907 for i, cmd in enumerate(cmds, start=1):
908 908 ip.history_manager.store_inputs(i, cmd)
909 909 with TemporaryDirectory() as tmpdir:
910 910 file = os.path.join(tmpdir, "testsave.py")
911 911 ip.run_line_magic("save", "%s 1-10" % file)
912 912 with open(file) as f:
913 913 content = f.read()
914 914 nt.assert_equal(content.count(cmds[0]), 1)
915 915 nt.assert_in('coding: utf-8', content)
916 916 ip.run_line_magic("save", "-a %s 1-10" % file)
917 917 with open(file) as f:
918 918 content = f.read()
919 919 nt.assert_equal(content.count(cmds[0]), 2)
920 920 nt.assert_in('coding: utf-8', content)
921 921
922 922
923 923 def test_store():
924 924 """Test %store."""
925 925 ip = get_ipython()
926 926 ip.run_line_magic('load_ext', 'storemagic')
927 927
928 928 # make sure the storage is empty
929 929 ip.run_line_magic('store', '-z')
930 930 ip.user_ns['var'] = 42
931 931 ip.run_line_magic('store', 'var')
932 932 ip.user_ns['var'] = 39
933 933 ip.run_line_magic('store', '-r')
934 934 nt.assert_equal(ip.user_ns['var'], 42)
935 935
936 936 ip.run_line_magic('store', '-d var')
937 937 ip.user_ns['var'] = 39
938 938 ip.run_line_magic('store' , '-r')
939 939 nt.assert_equal(ip.user_ns['var'], 39)
940 940
941 941
942 942 def _run_edit_test(arg_s, exp_filename=None,
943 943 exp_lineno=-1,
944 944 exp_contents=None,
945 945 exp_is_temp=None):
946 946 ip = get_ipython()
947 947 M = code.CodeMagics(ip)
948 948 last_call = ['','']
949 949 opts,args = M.parse_options(arg_s,'prxn:')
950 950 filename, lineno, is_temp = M._find_edit_target(ip, args, opts, last_call)
951 951
952 952 if exp_filename is not None:
953 953 nt.assert_equal(exp_filename, filename)
954 954 if exp_contents is not None:
955 955 with io.open(filename, 'r', encoding='utf-8') as f:
956 956 contents = f.read()
957 957 nt.assert_equal(exp_contents, contents)
958 958 if exp_lineno != -1:
959 959 nt.assert_equal(exp_lineno, lineno)
960 960 if exp_is_temp is not None:
961 961 nt.assert_equal(exp_is_temp, is_temp)
962 962
963 963
964 964 def test_edit_interactive():
965 965 """%edit on interactively defined objects"""
966 966 ip = get_ipython()
967 967 n = ip.execution_count
968 968 ip.run_cell(u"def foo(): return 1", store_history=True)
969 969
970 970 try:
971 971 _run_edit_test("foo")
972 972 except code.InteractivelyDefined as e:
973 973 nt.assert_equal(e.index, n)
974 974 else:
975 975 raise AssertionError("Should have raised InteractivelyDefined")
976 976
977 977
978 978 def test_edit_cell():
979 979 """%edit [cell id]"""
980 980 ip = get_ipython()
981 981
982 982 ip.run_cell(u"def foo(): return 1", store_history=True)
983 983
984 984 # test
985 985 _run_edit_test("1", exp_contents=ip.user_ns['In'][1], exp_is_temp=True)
986 986
987 987 def test_bookmark():
988 988 ip = get_ipython()
989 989 ip.run_line_magic('bookmark', 'bmname')
990 990 with tt.AssertPrints('bmname'):
991 991 ip.run_line_magic('bookmark', '-l')
992 992 ip.run_line_magic('bookmark', '-d bmname')
993 993
994 994 def test_ls_magic():
995 995 ip = get_ipython()
996 996 json_formatter = ip.display_formatter.formatters['application/json']
997 997 json_formatter.enabled = True
998 998 lsmagic = ip.magic('lsmagic')
999 999 with warnings.catch_warnings(record=True) as w:
1000 1000 j = json_formatter(lsmagic)
1001 1001 nt.assert_equal(sorted(j), ['cell', 'line'])
1002 1002 nt.assert_equal(w, []) # no warnings
1003
1004 def test_strip_initial_indent():
1005 def sii(s):
1006 lines = s.splitlines()
1007 return '\n'.join(code.strip_initial_indent(lines))
1008
1009 nt.assert_equal(sii(" a = 1\nb = 2"), "a = 1\nb = 2")
1010 nt.assert_equal(sii(" a\n b\nc"), "a\n b\nc")
1011 nt.assert_equal(sii("a\n b\n"), "a\n b\n")
General Comments 0
You need to be logged in to leave comments. Login now