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