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