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