##// END OF EJS Templates
better comment for the algorithm
Martín Gaitán -
Show More
@@ -1,681 +1,686 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 33 from IPython.utils.warn import warn
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 >>> extract_symbols(code, 'A,b')
99 (["class A: pass", "def b(): return 42"], [])
98 >>> extract_symbols(code, 'A,b,z')
99 (["class A: pass", "def b(): return 42"], ['z'])
100 100 """
101 101 try:
102 102 py_code = ast.parse(code)
103 103 except SyntaxError:
104 104 # ignores non python code
105 105 return []
106 106
107 107 marks = [(getattr(s, 'name', None), s.lineno) for s in py_code.body]
108 108 code = code.split('\n')
109 109
110 # construct a dictionary with elements
111 # {'symbol_name': (start_lineno, end_lineno), ...}
112 end = len(code)
113 110 symbols_lines = {}
111
112 # we already know the start_lineno of each symbol (marks).
113 # To find each end_lineno, we traverse in reverse order until each
114 # non-blank line
115 end = len(code)
114 116 for name, start in reversed(marks):
115 117 while not code[end - 1].strip():
116 118 end -= 1
117 119 if name:
118 120 symbols_lines[name] = (start - 1, end)
119 121 end = start - 1
120 122
121 # fill a list with chunks of codes for each symbol
123 # Now symbols_lines is a map
124 # {'symbol_name': (start_lineno, end_lineno), ...}
125
126 # fill a list with chunks of codes for each requested symbol
122 127 blocks = []
123 128 not_found = []
124 129 for symbol in symbols.split(','):
125 130 if symbol in symbols_lines:
126 131 start, end = symbols_lines[symbol]
127 132 blocks.append('\n'.join(code[start:end]) + '\n')
128 133 else:
129 134 not_found.append(symbol)
130 135
131 136 return blocks, not_found
132 137
133 138
134 139 class InteractivelyDefined(Exception):
135 140 """Exception for interactively defined variable in magic_edit"""
136 141 def __init__(self, index):
137 142 self.index = index
138 143
139 144
140 145 @magics_class
141 146 class CodeMagics(Magics):
142 147 """Magics related to code management (loading, saving, editing, ...)."""
143 148
144 149 @line_magic
145 150 def save(self, parameter_s=''):
146 151 """Save a set of lines or a macro to a given filename.
147 152
148 153 Usage:\\
149 154 %save [options] filename n1-n2 n3-n4 ... n5 .. n6 ...
150 155
151 156 Options:
152 157
153 158 -r: use 'raw' input. By default, the 'processed' history is used,
154 159 so that magics are loaded in their transformed version to valid
155 160 Python. If this option is given, the raw input as typed as the
156 161 command line is used instead.
157 162
158 163 -f: force overwrite. If file exists, %save will prompt for overwrite
159 164 unless -f is given.
160 165
161 166 -a: append to the file instead of overwriting it.
162 167
163 168 This function uses the same syntax as %history for input ranges,
164 169 then saves the lines to the filename you specify.
165 170
166 171 It adds a '.py' extension to the file if you don't do so yourself, and
167 172 it asks for confirmation before overwriting existing files.
168 173
169 174 If `-r` option is used, the default extension is `.ipy`.
170 175 """
171 176
172 177 opts,args = self.parse_options(parameter_s,'fra',mode='list')
173 178 if not args:
174 179 raise UsageError('Missing filename.')
175 180 raw = 'r' in opts
176 181 force = 'f' in opts
177 182 append = 'a' in opts
178 183 mode = 'a' if append else 'w'
179 184 ext = u'.ipy' if raw else u'.py'
180 185 fname, codefrom = unquote_filename(args[0]), " ".join(args[1:])
181 186 if not fname.endswith((u'.py',u'.ipy')):
182 187 fname += ext
183 188 file_exists = os.path.isfile(fname)
184 189 if file_exists and not force and not append:
185 190 try:
186 191 overwrite = self.shell.ask_yes_no('File `%s` exists. Overwrite (y/[N])? ' % fname, default='n')
187 192 except StdinNotImplementedError:
188 193 print "File `%s` exists. Use `%%save -f %s` to force overwrite" % (fname, parameter_s)
189 194 return
190 195 if not overwrite :
191 196 print 'Operation cancelled.'
192 197 return
193 198 try:
194 199 cmds = self.shell.find_user_code(codefrom,raw)
195 200 except (TypeError, ValueError) as e:
196 201 print e.args[0]
197 202 return
198 203 out = py3compat.cast_unicode(cmds)
199 204 with io.open(fname, mode, encoding="utf-8") as f:
200 205 if not file_exists or not append:
201 206 f.write(u"# coding: utf-8\n")
202 207 f.write(out)
203 208 # make sure we end on a newline
204 209 if not out.endswith(u'\n'):
205 210 f.write(u'\n')
206 211 print 'The following commands were written to file `%s`:' % fname
207 212 print cmds
208 213
209 214 @line_magic
210 215 def pastebin(self, parameter_s=''):
211 216 """Upload code to Github's Gist paste bin, returning the URL.
212 217
213 218 Usage:\\
214 219 %pastebin [-d "Custom description"] 1-7
215 220
216 221 The argument can be an input history range, a filename, or the name of a
217 222 string or macro.
218 223
219 224 Options:
220 225
221 226 -d: Pass a custom description for the gist. The default will say
222 227 "Pasted from IPython".
223 228 """
224 229 opts, args = self.parse_options(parameter_s, 'd:')
225 230
226 231 try:
227 232 code = self.shell.find_user_code(args)
228 233 except (ValueError, TypeError) as e:
229 234 print e.args[0]
230 235 return
231 236
232 237 from urllib2 import urlopen # Deferred import
233 238 import json
234 239 post_data = json.dumps({
235 240 "description": opts.get('d', "Pasted from IPython"),
236 241 "public": True,
237 242 "files": {
238 243 "file1.py": {
239 244 "content": code
240 245 }
241 246 }
242 247 }).encode('utf-8')
243 248
244 249 response = urlopen("https://api.github.com/gists", post_data)
245 250 response_data = json.loads(response.read().decode('utf-8'))
246 251 return response_data['html_url']
247 252
248 253 @line_magic
249 254 def loadpy(self, arg_s):
250 255 """Alias of `%load`
251 256
252 257 `%loadpy` has gained some flexibility and dropped the requirement of a `.py`
253 258 extension. So it has been renamed simply into %load. You can look at
254 259 `%load`'s docstring for more info.
255 260 """
256 261 self.load(arg_s)
257 262
258 263 @line_magic
259 264 def load(self, arg_s):
260 265 """Load code into the current frontend.
261 266
262 267 Usage:\\
263 268 %load [options] source
264 269
265 270 where source can be a filename, URL, input history range or macro
266 271
267 272 Options:
268 273 --------
269 274 -r <lines>: Specify lines or ranges of lines to load from the source.
270 275 Ranges could be specified as x-y (x..y) or in python-style x:y
271 276 (x..(y-1)). Both limits x and y can be left blank (meaning the
272 277 beginning and end of the file, respectively).
273 278
274 279 -s <symbols>: Specify function or classes to load from python source.
275 280
276 281 -y : Don't ask confirmation for loading source above 200 000 characters.
277 282
278 283 This magic command can either take a local filename, a URL, an history
279 284 range (see %history) or a macro as argument, it will prompt for
280 285 confirmation before loading source with more than 200 000 characters, unless
281 286 -y flag is passed or if the frontend does not support raw_input::
282 287
283 288 %load myscript.py
284 289 %load 7-27
285 290 %load myMacro
286 291 %load http://www.example.com/myscript.py
287 292 %load -r 5-10 myscript.py
288 293 %load -r 10-20,30,40: foo.py
289 294 %load -s MyClass,wonder_function myscript.py
290 295 """
291 296 opts,args = self.parse_options(arg_s,'ys:r:')
292 297
293 298 if not args:
294 299 raise UsageError('Missing filename, URL, input history range, '
295 300 'or macro.')
296 301
297 302 contents = self.shell.find_user_code(args)
298 303
299 304 if 's' in opts:
300 305 blocks, not_found = extract_symbols(contents, opts['s'])
301 306 if len(not_found) == 1:
302 307 warn('The symbol `%s` was not found' % not_found[0])
303 308 elif len(not_found) > 1:
304 309 warn('The symbols %s were not found' % get_text_list(not_found,
305 310 wrap_item_with='`')
306 311 )
307 312
308 313 contents = '\n'.join(blocks)
309 314
310 315 if 'r' in opts:
311 316 ranges = opts['r'].replace(',', ' ')
312 317 lines = contents.split('\n')
313 318 slices = extract_code_ranges(ranges)
314 319 contents = [lines[slice(*slc)] for slc in slices]
315 320 contents = '\n'.join(chain.from_iterable(contents))
316 321
317 322 l = len(contents)
318 323
319 324 # 200 000 is ~ 2500 full 80 caracter lines
320 325 # so in average, more than 5000 lines
321 326 if l > 200000 and 'y' not in opts:
322 327 try:
323 328 ans = self.shell.ask_yes_no(("The text you're trying to load seems pretty big"\
324 329 " (%d characters). Continue (y/[N]) ?" % l), default='n' )
325 330 except StdinNotImplementedError:
326 331 #asume yes if raw input not implemented
327 332 ans = True
328 333
329 334 if ans is False :
330 335 print 'Operation cancelled.'
331 336 return
332 337
333 338 self.shell.set_next_input(contents)
334 339
335 340 @staticmethod
336 341 def _find_edit_target(shell, args, opts, last_call):
337 342 """Utility method used by magic_edit to find what to edit."""
338 343
339 344 def make_filename(arg):
340 345 "Make a filename from the given args"
341 346 arg = unquote_filename(arg)
342 347 try:
343 348 filename = get_py_filename(arg)
344 349 except IOError:
345 350 # If it ends with .py but doesn't already exist, assume we want
346 351 # a new file.
347 352 if arg.endswith('.py'):
348 353 filename = arg
349 354 else:
350 355 filename = None
351 356 return filename
352 357
353 358 # Set a few locals from the options for convenience:
354 359 opts_prev = 'p' in opts
355 360 opts_raw = 'r' in opts
356 361
357 362 # custom exceptions
358 363 class DataIsObject(Exception): pass
359 364
360 365 # Default line number value
361 366 lineno = opts.get('n',None)
362 367
363 368 if opts_prev:
364 369 args = '_%s' % last_call[0]
365 370 if args not in shell.user_ns:
366 371 args = last_call[1]
367 372
368 373 # by default this is done with temp files, except when the given
369 374 # arg is a filename
370 375 use_temp = True
371 376
372 377 data = ''
373 378
374 379 # First, see if the arguments should be a filename.
375 380 filename = make_filename(args)
376 381 if filename:
377 382 use_temp = False
378 383 elif args:
379 384 # Mode where user specifies ranges of lines, like in %macro.
380 385 data = shell.extract_input_lines(args, opts_raw)
381 386 if not data:
382 387 try:
383 388 # Load the parameter given as a variable. If not a string,
384 389 # process it as an object instead (below)
385 390
386 391 #print '*** args',args,'type',type(args) # dbg
387 392 data = eval(args, shell.user_ns)
388 393 if not isinstance(data, basestring):
389 394 raise DataIsObject
390 395
391 396 except (NameError,SyntaxError):
392 397 # given argument is not a variable, try as a filename
393 398 filename = make_filename(args)
394 399 if filename is None:
395 400 warn("Argument given (%s) can't be found as a variable "
396 401 "or as a filename." % args)
397 402 return (None, None, None)
398 403 use_temp = False
399 404
400 405 except DataIsObject:
401 406 # macros have a special edit function
402 407 if isinstance(data, Macro):
403 408 raise MacroToEdit(data)
404 409
405 410 # For objects, try to edit the file where they are defined
406 411 filename = find_file(data)
407 412 if filename:
408 413 if 'fakemodule' in filename.lower() and \
409 414 inspect.isclass(data):
410 415 # class created by %edit? Try to find source
411 416 # by looking for method definitions instead, the
412 417 # __module__ in those classes is FakeModule.
413 418 attrs = [getattr(data, aname) for aname in dir(data)]
414 419 for attr in attrs:
415 420 if not inspect.ismethod(attr):
416 421 continue
417 422 filename = find_file(attr)
418 423 if filename and \
419 424 'fakemodule' not in filename.lower():
420 425 # change the attribute to be the edit
421 426 # target instead
422 427 data = attr
423 428 break
424 429
425 430 m = ipython_input_pat.match(os.path.basename(filename))
426 431 if m:
427 432 raise InteractivelyDefined(int(m.groups()[0]))
428 433
429 434 datafile = 1
430 435 if filename is None:
431 436 filename = make_filename(args)
432 437 datafile = 1
433 438 if filename is not None:
434 439 # only warn about this if we get a real name
435 440 warn('Could not find file where `%s` is defined.\n'
436 441 'Opening a file named `%s`' % (args, filename))
437 442 # Now, make sure we can actually read the source (if it was
438 443 # in a temp file it's gone by now).
439 444 if datafile:
440 445 if lineno is None:
441 446 lineno = find_source_lines(data)
442 447 if lineno is None:
443 448 filename = make_filename(args)
444 449 if filename is None:
445 450 warn('The file where `%s` was defined '
446 451 'cannot be read or found.' % data)
447 452 return (None, None, None)
448 453 use_temp = False
449 454
450 455 if use_temp:
451 456 filename = shell.mktempfile(data)
452 457 print 'IPython will make a temporary file named:',filename
453 458
454 459 # use last_call to remember the state of the previous call, but don't
455 460 # let it be clobbered by successive '-p' calls.
456 461 try:
457 462 last_call[0] = shell.displayhook.prompt_count
458 463 if not opts_prev:
459 464 last_call[1] = args
460 465 except:
461 466 pass
462 467
463 468
464 469 return filename, lineno, use_temp
465 470
466 471 def _edit_macro(self,mname,macro):
467 472 """open an editor with the macro data in a file"""
468 473 filename = self.shell.mktempfile(macro.value)
469 474 self.shell.hooks.editor(filename)
470 475
471 476 # and make a new macro object, to replace the old one
472 477 mfile = open(filename)
473 478 mvalue = mfile.read()
474 479 mfile.close()
475 480 self.shell.user_ns[mname] = Macro(mvalue)
476 481
477 482 @skip_doctest
478 483 @line_magic
479 484 def edit(self, parameter_s='',last_call=['','']):
480 485 """Bring up an editor and execute the resulting code.
481 486
482 487 Usage:
483 488 %edit [options] [args]
484 489
485 490 %edit runs IPython's editor hook. The default version of this hook is
486 491 set to call the editor specified by your $EDITOR environment variable.
487 492 If this isn't found, it will default to vi under Linux/Unix and to
488 493 notepad under Windows. See the end of this docstring for how to change
489 494 the editor hook.
490 495
491 496 You can also set the value of this editor via the
492 497 ``TerminalInteractiveShell.editor`` option in your configuration file.
493 498 This is useful if you wish to use a different editor from your typical
494 499 default with IPython (and for Windows users who typically don't set
495 500 environment variables).
496 501
497 502 This command allows you to conveniently edit multi-line code right in
498 503 your IPython session.
499 504
500 505 If called without arguments, %edit opens up an empty editor with a
501 506 temporary file and will execute the contents of this file when you
502 507 close it (don't forget to save it!).
503 508
504 509
505 510 Options:
506 511
507 512 -n <number>: open the editor at a specified line number. By default,
508 513 the IPython editor hook uses the unix syntax 'editor +N filename', but
509 514 you can configure this by providing your own modified hook if your
510 515 favorite editor supports line-number specifications with a different
511 516 syntax.
512 517
513 518 -p: this will call the editor with the same data as the previous time
514 519 it was used, regardless of how long ago (in your current session) it
515 520 was.
516 521
517 522 -r: use 'raw' input. This option only applies to input taken from the
518 523 user's history. By default, the 'processed' history is used, so that
519 524 magics are loaded in their transformed version to valid Python. If
520 525 this option is given, the raw input as typed as the command line is
521 526 used instead. When you exit the editor, it will be executed by
522 527 IPython's own processor.
523 528
524 529 -x: do not execute the edited code immediately upon exit. This is
525 530 mainly useful if you are editing programs which need to be called with
526 531 command line arguments, which you can then do using %run.
527 532
528 533
529 534 Arguments:
530 535
531 536 If arguments are given, the following possibilities exist:
532 537
533 538 - If the argument is a filename, IPython will load that into the
534 539 editor. It will execute its contents with execfile() when you exit,
535 540 loading any code in the file into your interactive namespace.
536 541
537 542 - The arguments are ranges of input history, e.g. "7 ~1/4-6".
538 543 The syntax is the same as in the %history magic.
539 544
540 545 - If the argument is a string variable, its contents are loaded
541 546 into the editor. You can thus edit any string which contains
542 547 python code (including the result of previous edits).
543 548
544 549 - If the argument is the name of an object (other than a string),
545 550 IPython will try to locate the file where it was defined and open the
546 551 editor at the point where it is defined. You can use `%edit function`
547 552 to load an editor exactly at the point where 'function' is defined,
548 553 edit it and have the file be executed automatically.
549 554
550 555 - If the object is a macro (see %macro for details), this opens up your
551 556 specified editor with a temporary file containing the macro's data.
552 557 Upon exit, the macro is reloaded with the contents of the file.
553 558
554 559 Note: opening at an exact line is only supported under Unix, and some
555 560 editors (like kedit and gedit up to Gnome 2.8) do not understand the
556 561 '+NUMBER' parameter necessary for this feature. Good editors like
557 562 (X)Emacs, vi, jed, pico and joe all do.
558 563
559 564 After executing your code, %edit will return as output the code you
560 565 typed in the editor (except when it was an existing file). This way
561 566 you can reload the code in further invocations of %edit as a variable,
562 567 via _<NUMBER> or Out[<NUMBER>], where <NUMBER> is the prompt number of
563 568 the output.
564 569
565 570 Note that %edit is also available through the alias %ed.
566 571
567 572 This is an example of creating a simple function inside the editor and
568 573 then modifying it. First, start up the editor::
569 574
570 575 In [1]: edit
571 576 Editing... done. Executing edited code...
572 577 Out[1]: 'def foo():\\n print "foo() was defined in an editing
573 578 session"\\n'
574 579
575 580 We can then call the function foo()::
576 581
577 582 In [2]: foo()
578 583 foo() was defined in an editing session
579 584
580 585 Now we edit foo. IPython automatically loads the editor with the
581 586 (temporary) file where foo() was previously defined::
582 587
583 588 In [3]: edit foo
584 589 Editing... done. Executing edited code...
585 590
586 591 And if we call foo() again we get the modified version::
587 592
588 593 In [4]: foo()
589 594 foo() has now been changed!
590 595
591 596 Here is an example of how to edit a code snippet successive
592 597 times. First we call the editor::
593 598
594 599 In [5]: edit
595 600 Editing... done. Executing edited code...
596 601 hello
597 602 Out[5]: "print 'hello'\\n"
598 603
599 604 Now we call it again with the previous output (stored in _)::
600 605
601 606 In [6]: edit _
602 607 Editing... done. Executing edited code...
603 608 hello world
604 609 Out[6]: "print 'hello world'\\n"
605 610
606 611 Now we call it with the output #8 (stored in _8, also as Out[8])::
607 612
608 613 In [7]: edit _8
609 614 Editing... done. Executing edited code...
610 615 hello again
611 616 Out[7]: "print 'hello again'\\n"
612 617
613 618
614 619 Changing the default editor hook:
615 620
616 621 If you wish to write your own editor hook, you can put it in a
617 622 configuration file which you load at startup time. The default hook
618 623 is defined in the IPython.core.hooks module, and you can use that as a
619 624 starting example for further modifications. That file also has
620 625 general instructions on how to set a new hook for use once you've
621 626 defined it."""
622 627 opts,args = self.parse_options(parameter_s,'prxn:')
623 628
624 629 try:
625 630 filename, lineno, is_temp = self._find_edit_target(self.shell,
626 631 args, opts, last_call)
627 632 except MacroToEdit as e:
628 633 self._edit_macro(args, e.args[0])
629 634 return
630 635 except InteractivelyDefined as e:
631 636 print "Editing In[%i]" % e.index
632 637 args = str(e.index)
633 638 filename, lineno, is_temp = self._find_edit_target(self.shell,
634 639 args, opts, last_call)
635 640 if filename is None:
636 641 # nothing was found, warnings have already been issued,
637 642 # just give up.
638 643 return
639 644
640 645 # do actual editing here
641 646 print 'Editing...',
642 647 sys.stdout.flush()
643 648 try:
644 649 # Quote filenames that may have spaces in them
645 650 if ' ' in filename:
646 651 filename = "'%s'" % filename
647 652 self.shell.hooks.editor(filename,lineno)
648 653 except TryNext:
649 654 warn('Could not open editor')
650 655 return
651 656
652 657 # XXX TODO: should this be generalized for all string vars?
653 658 # For now, this is special-cased to blocks created by cpaste
654 659 if args.strip() == 'pasted_block':
655 660 with open(filename, 'r') as f:
656 661 self.shell.user_ns['pasted_block'] = f.read()
657 662
658 663 if 'x' in opts: # -x prevents actual execution
659 664 print
660 665 else:
661 666 print 'done. Executing edited code...'
662 667 with preserve_keys(self.shell.user_ns, '__file__'):
663 668 if not is_temp:
664 669 self.shell.user_ns['__file__'] = filename
665 670 if 'r' in opts: # Untranslated IPython code
666 671 with open(filename, 'r') as f:
667 672 source = f.read()
668 673 self.shell.run_cell(source, store_history=False)
669 674 else:
670 675 self.shell.safe_execfile(filename, self.shell.user_ns,
671 676 self.shell.user_ns)
672 677
673 678 if is_temp:
674 679 try:
675 680 return open(filename).read()
676 681 except IOError as msg:
677 682 if msg.filename == filename:
678 683 warn('File not found. Did you forget to save?')
679 684 return
680 685 else:
681 686 self.shell.showtraceback()
General Comments 0
You need to be logged in to leave comments. Login now