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