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