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