##// END OF EJS Templates
Merge pull request #12980 from MrMino/rerun_0_lines_msg...
Matthias Bussonnier -
r26551:81609db4 merge
parent child Browse files
Show More
@@ -1,327 +1,335 b''
1 """Implementation of magic functions related to History.
1 """Implementation of magic functions related to History.
2 """
2 """
3 #-----------------------------------------------------------------------------
3 #-----------------------------------------------------------------------------
4 # Copyright (c) 2012, IPython Development Team.
4 # Copyright (c) 2012, 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 os
16 import os
17 import sys
17 import sys
18 from io import open as io_open
18 from io import open as io_open
19 import fnmatch
19 import fnmatch
20
20
21 # Our own packages
21 # Our own packages
22 from IPython.core.error import StdinNotImplementedError
22 from IPython.core.error import StdinNotImplementedError
23 from IPython.core.magic import Magics, magics_class, line_magic
23 from IPython.core.magic import Magics, magics_class, line_magic
24 from IPython.core.magic_arguments import (argument, magic_arguments,
24 from IPython.core.magic_arguments import (argument, magic_arguments,
25 parse_argstring)
25 parse_argstring)
26 from IPython.testing.skipdoctest import skip_doctest
26 from IPython.testing.skipdoctest import skip_doctest
27 from IPython.utils import io
27 from IPython.utils import io
28
28
29 #-----------------------------------------------------------------------------
29 #-----------------------------------------------------------------------------
30 # Magics class implementation
30 # Magics class implementation
31 #-----------------------------------------------------------------------------
31 #-----------------------------------------------------------------------------
32
32
33
33
34 _unspecified = object()
34 _unspecified = object()
35
35
36
36
37 @magics_class
37 @magics_class
38 class HistoryMagics(Magics):
38 class HistoryMagics(Magics):
39
39
40 @magic_arguments()
40 @magic_arguments()
41 @argument(
41 @argument(
42 '-n', dest='print_nums', action='store_true', default=False,
42 '-n', dest='print_nums', action='store_true', default=False,
43 help="""
43 help="""
44 print line numbers for each input.
44 print line numbers for each input.
45 This feature is only available if numbered prompts are in use.
45 This feature is only available if numbered prompts are in use.
46 """)
46 """)
47 @argument(
47 @argument(
48 '-o', dest='get_output', action='store_true', default=False,
48 '-o', dest='get_output', action='store_true', default=False,
49 help="also print outputs for each input.")
49 help="also print outputs for each input.")
50 @argument(
50 @argument(
51 '-p', dest='pyprompts', action='store_true', default=False,
51 '-p', dest='pyprompts', action='store_true', default=False,
52 help="""
52 help="""
53 print classic '>>>' python prompts before each input.
53 print classic '>>>' python prompts before each input.
54 This is useful for making documentation, and in conjunction
54 This is useful for making documentation, and in conjunction
55 with -o, for producing doctest-ready output.
55 with -o, for producing doctest-ready output.
56 """)
56 """)
57 @argument(
57 @argument(
58 '-t', dest='raw', action='store_false', default=True,
58 '-t', dest='raw', action='store_false', default=True,
59 help="""
59 help="""
60 print the 'translated' history, as IPython understands it.
60 print the 'translated' history, as IPython understands it.
61 IPython filters your input and converts it all into valid Python
61 IPython filters your input and converts it all into valid Python
62 source before executing it (things like magics or aliases are turned
62 source before executing it (things like magics or aliases are turned
63 into function calls, for example). With this option, you'll see the
63 into function calls, for example). With this option, you'll see the
64 native history instead of the user-entered version: '%%cd /' will be
64 native history instead of the user-entered version: '%%cd /' will be
65 seen as 'get_ipython().run_line_magic("cd", "/")' instead of '%%cd /'.
65 seen as 'get_ipython().run_line_magic("cd", "/")' instead of '%%cd /'.
66 """)
66 """)
67 @argument(
67 @argument(
68 '-f', dest='filename',
68 '-f', dest='filename',
69 help="""
69 help="""
70 FILENAME: instead of printing the output to the screen, redirect
70 FILENAME: instead of printing the output to the screen, redirect
71 it to the given file. The file is always overwritten, though *when
71 it to the given file. The file is always overwritten, though *when
72 it can*, IPython asks for confirmation first. In particular, running
72 it can*, IPython asks for confirmation first. In particular, running
73 the command 'history -f FILENAME' from the IPython Notebook
73 the command 'history -f FILENAME' from the IPython Notebook
74 interface will replace FILENAME even if it already exists *without*
74 interface will replace FILENAME even if it already exists *without*
75 confirmation.
75 confirmation.
76 """)
76 """)
77 @argument(
77 @argument(
78 '-g', dest='pattern', nargs='*', default=None,
78 '-g', dest='pattern', nargs='*', default=None,
79 help="""
79 help="""
80 treat the arg as a glob pattern to search for in (full) history.
80 treat the arg as a glob pattern to search for in (full) history.
81 This includes the saved history (almost all commands ever written).
81 This includes the saved history (almost all commands ever written).
82 The pattern may contain '?' to match one unknown character and '*'
82 The pattern may contain '?' to match one unknown character and '*'
83 to match any number of unknown characters. Use '%%hist -g' to show
83 to match any number of unknown characters. Use '%%hist -g' to show
84 full saved history (may be very long).
84 full saved history (may be very long).
85 """)
85 """)
86 @argument(
86 @argument(
87 '-l', dest='limit', type=int, nargs='?', default=_unspecified,
87 '-l', dest='limit', type=int, nargs='?', default=_unspecified,
88 help="""
88 help="""
89 get the last n lines from all sessions. Specify n as a single
89 get the last n lines from all sessions. Specify n as a single
90 arg, or the default is the last 10 lines.
90 arg, or the default is the last 10 lines.
91 """)
91 """)
92 @argument(
92 @argument(
93 '-u', dest='unique', action='store_true',
93 '-u', dest='unique', action='store_true',
94 help="""
94 help="""
95 when searching history using `-g`, show only unique history.
95 when searching history using `-g`, show only unique history.
96 """)
96 """)
97 @argument('range', nargs='*')
97 @argument('range', nargs='*')
98 @skip_doctest
98 @skip_doctest
99 @line_magic
99 @line_magic
100 def history(self, parameter_s = ''):
100 def history(self, parameter_s = ''):
101 """Print input history (_i<n> variables), with most recent last.
101 """Print input history (_i<n> variables), with most recent last.
102
102
103 By default, input history is printed without line numbers so it can be
103 By default, input history is printed without line numbers so it can be
104 directly pasted into an editor. Use -n to show them.
104 directly pasted into an editor. Use -n to show them.
105
105
106 By default, all input history from the current session is displayed.
106 By default, all input history from the current session is displayed.
107 Ranges of history can be indicated using the syntax:
107 Ranges of history can be indicated using the syntax:
108
108
109 ``4``
109 ``4``
110 Line 4, current session
110 Line 4, current session
111 ``4-6``
111 ``4-6``
112 Lines 4-6, current session
112 Lines 4-6, current session
113 ``243/1-5``
113 ``243/1-5``
114 Lines 1-5, session 243
114 Lines 1-5, session 243
115 ``~2/7``
115 ``~2/7``
116 Line 7, session 2 before current
116 Line 7, session 2 before current
117 ``~8/1-~6/5``
117 ``~8/1-~6/5``
118 From the first line of 8 sessions ago, to the fifth line of 6
118 From the first line of 8 sessions ago, to the fifth line of 6
119 sessions ago.
119 sessions ago.
120
120
121 Multiple ranges can be entered, separated by spaces
121 Multiple ranges can be entered, separated by spaces
122
122
123 The same syntax is used by %macro, %save, %edit, %rerun
123 The same syntax is used by %macro, %save, %edit, %rerun
124
124
125 Examples
125 Examples
126 --------
126 --------
127 ::
127 ::
128
128
129 In [6]: %history -n 4-6
129 In [6]: %history -n 4-6
130 4:a = 12
130 4:a = 12
131 5:print a**2
131 5:print a**2
132 6:%history -n 4-6
132 6:%history -n 4-6
133
133
134 """
134 """
135
135
136 args = parse_argstring(self.history, parameter_s)
136 args = parse_argstring(self.history, parameter_s)
137
137
138 # For brevity
138 # For brevity
139 history_manager = self.shell.history_manager
139 history_manager = self.shell.history_manager
140
140
141 def _format_lineno(session, line):
141 def _format_lineno(session, line):
142 """Helper function to format line numbers properly."""
142 """Helper function to format line numbers properly."""
143 if session in (0, history_manager.session_number):
143 if session in (0, history_manager.session_number):
144 return str(line)
144 return str(line)
145 return "%s/%s" % (session, line)
145 return "%s/%s" % (session, line)
146
146
147 # Check if output to specific file was requested.
147 # Check if output to specific file was requested.
148 outfname = args.filename
148 outfname = args.filename
149 if not outfname:
149 if not outfname:
150 outfile = sys.stdout # default
150 outfile = sys.stdout # default
151 # We don't want to close stdout at the end!
151 # We don't want to close stdout at the end!
152 close_at_end = False
152 close_at_end = False
153 else:
153 else:
154 if os.path.exists(outfname):
154 if os.path.exists(outfname):
155 try:
155 try:
156 ans = io.ask_yes_no("File %r exists. Overwrite?" % outfname)
156 ans = io.ask_yes_no("File %r exists. Overwrite?" % outfname)
157 except StdinNotImplementedError:
157 except StdinNotImplementedError:
158 ans = True
158 ans = True
159 if not ans:
159 if not ans:
160 print('Aborting.')
160 print('Aborting.')
161 return
161 return
162 print("Overwriting file.")
162 print("Overwriting file.")
163 outfile = io_open(outfname, 'w', encoding='utf-8')
163 outfile = io_open(outfname, 'w', encoding='utf-8')
164 close_at_end = True
164 close_at_end = True
165
165
166 print_nums = args.print_nums
166 print_nums = args.print_nums
167 get_output = args.get_output
167 get_output = args.get_output
168 pyprompts = args.pyprompts
168 pyprompts = args.pyprompts
169 raw = args.raw
169 raw = args.raw
170
170
171 pattern = None
171 pattern = None
172 limit = None if args.limit is _unspecified else args.limit
172 limit = None if args.limit is _unspecified else args.limit
173
173
174 range_pattern = False
174 range_pattern = False
175 if args.pattern is not None and not args.range:
175 if args.pattern is not None and not args.range:
176 if args.pattern:
176 if args.pattern:
177 pattern = "*" + " ".join(args.pattern) + "*"
177 pattern = "*" + " ".join(args.pattern) + "*"
178 else:
178 else:
179 pattern = "*"
179 pattern = "*"
180 hist = history_manager.search(pattern, raw=raw, output=get_output,
180 hist = history_manager.search(pattern, raw=raw, output=get_output,
181 n=limit, unique=args.unique)
181 n=limit, unique=args.unique)
182 print_nums = True
182 print_nums = True
183 elif args.limit is not _unspecified:
183 elif args.limit is not _unspecified:
184 n = 10 if limit is None else limit
184 n = 10 if limit is None else limit
185 hist = history_manager.get_tail(n, raw=raw, output=get_output)
185 hist = history_manager.get_tail(n, raw=raw, output=get_output)
186 else:
186 else:
187 if args.range: # Get history by ranges
187 if args.range: # Get history by ranges
188 if args.pattern:
188 if args.pattern:
189 range_pattern = "*" + " ".join(args.pattern) + "*"
189 range_pattern = "*" + " ".join(args.pattern) + "*"
190 print_nums = True
190 print_nums = True
191 hist = history_manager.get_range_by_str(" ".join(args.range),
191 hist = history_manager.get_range_by_str(" ".join(args.range),
192 raw, get_output)
192 raw, get_output)
193 else: # Just get history for the current session
193 else: # Just get history for the current session
194 hist = history_manager.get_range(raw=raw, output=get_output)
194 hist = history_manager.get_range(raw=raw, output=get_output)
195
195
196 # We could be displaying the entire history, so let's not try to pull
196 # We could be displaying the entire history, so let's not try to pull
197 # it into a list in memory. Anything that needs more space will just
197 # it into a list in memory. Anything that needs more space will just
198 # misalign.
198 # misalign.
199 width = 4
199 width = 4
200
200
201 for session, lineno, inline in hist:
201 for session, lineno, inline in hist:
202 # Print user history with tabs expanded to 4 spaces. The GUI
202 # Print user history with tabs expanded to 4 spaces. The GUI
203 # clients use hard tabs for easier usability in auto-indented code,
203 # clients use hard tabs for easier usability in auto-indented code,
204 # but we want to produce PEP-8 compliant history for safe pasting
204 # but we want to produce PEP-8 compliant history for safe pasting
205 # into an editor.
205 # into an editor.
206 if get_output:
206 if get_output:
207 inline, output = inline
207 inline, output = inline
208 if range_pattern:
208 if range_pattern:
209 if not fnmatch.fnmatch(inline, range_pattern):
209 if not fnmatch.fnmatch(inline, range_pattern):
210 continue
210 continue
211 inline = inline.expandtabs(4).rstrip()
211 inline = inline.expandtabs(4).rstrip()
212
212
213 multiline = "\n" in inline
213 multiline = "\n" in inline
214 line_sep = '\n' if multiline else ' '
214 line_sep = '\n' if multiline else ' '
215 if print_nums:
215 if print_nums:
216 print(u'%s:%s' % (_format_lineno(session, lineno).rjust(width),
216 print(u'%s:%s' % (_format_lineno(session, lineno).rjust(width),
217 line_sep), file=outfile, end=u'')
217 line_sep), file=outfile, end=u'')
218 if pyprompts:
218 if pyprompts:
219 print(u">>> ", end=u"", file=outfile)
219 print(u">>> ", end=u"", file=outfile)
220 if multiline:
220 if multiline:
221 inline = "\n... ".join(inline.splitlines()) + "\n..."
221 inline = "\n... ".join(inline.splitlines()) + "\n..."
222 print(inline, file=outfile)
222 print(inline, file=outfile)
223 if get_output and output:
223 if get_output and output:
224 print(output, file=outfile)
224 print(output, file=outfile)
225
225
226 if close_at_end:
226 if close_at_end:
227 outfile.close()
227 outfile.close()
228
228
229 @line_magic
229 @line_magic
230 def recall(self, arg):
230 def recall(self, arg):
231 r"""Repeat a command, or get command to input line for editing.
231 r"""Repeat a command, or get command to input line for editing.
232
232
233 %recall and %rep are equivalent.
233 %recall and %rep are equivalent.
234
234
235 - %recall (no arguments):
235 - %recall (no arguments):
236
236
237 Place a string version of last computation result (stored in the
237 Place a string version of last computation result (stored in the
238 special '_' variable) to the next input prompt. Allows you to create
238 special '_' variable) to the next input prompt. Allows you to create
239 elaborate command lines without using copy-paste::
239 elaborate command lines without using copy-paste::
240
240
241 In[1]: l = ["hei", "vaan"]
241 In[1]: l = ["hei", "vaan"]
242 In[2]: "".join(l)
242 In[2]: "".join(l)
243 Out[2]: heivaan
243 Out[2]: heivaan
244 In[3]: %recall
244 In[3]: %recall
245 In[4]: heivaan_ <== cursor blinking
245 In[4]: heivaan_ <== cursor blinking
246
246
247 %recall 45
247 %recall 45
248
248
249 Place history line 45 on the next input prompt. Use %hist to find
249 Place history line 45 on the next input prompt. Use %hist to find
250 out the number.
250 out the number.
251
251
252 %recall 1-4
252 %recall 1-4
253
253
254 Combine the specified lines into one cell, and place it on the next
254 Combine the specified lines into one cell, and place it on the next
255 input prompt. See %history for the slice syntax.
255 input prompt. See %history for the slice syntax.
256
256
257 %recall foo+bar
257 %recall foo+bar
258
258
259 If foo+bar can be evaluated in the user namespace, the result is
259 If foo+bar can be evaluated in the user namespace, the result is
260 placed at the next input prompt. Otherwise, the history is searched
260 placed at the next input prompt. Otherwise, the history is searched
261 for lines which contain that substring, and the most recent one is
261 for lines which contain that substring, and the most recent one is
262 placed at the next input prompt.
262 placed at the next input prompt.
263 """
263 """
264 if not arg: # Last output
264 if not arg: # Last output
265 self.shell.set_next_input(str(self.shell.user_ns["_"]))
265 self.shell.set_next_input(str(self.shell.user_ns["_"]))
266 return
266 return
267 # Get history range
267 # Get history range
268 histlines = self.shell.history_manager.get_range_by_str(arg)
268 histlines = self.shell.history_manager.get_range_by_str(arg)
269 cmd = "\n".join(x[2] for x in histlines)
269 cmd = "\n".join(x[2] for x in histlines)
270 if cmd:
270 if cmd:
271 self.shell.set_next_input(cmd.rstrip())
271 self.shell.set_next_input(cmd.rstrip())
272 return
272 return
273
273
274 try: # Variable in user namespace
274 try: # Variable in user namespace
275 cmd = str(eval(arg, self.shell.user_ns))
275 cmd = str(eval(arg, self.shell.user_ns))
276 except Exception: # Search for term in history
276 except Exception: # Search for term in history
277 histlines = self.shell.history_manager.search("*"+arg+"*")
277 histlines = self.shell.history_manager.search("*"+arg+"*")
278 for h in reversed([x[2] for x in histlines]):
278 for h in reversed([x[2] for x in histlines]):
279 if 'recall' in h or 'rep' in h:
279 if 'recall' in h or 'rep' in h:
280 continue
280 continue
281 self.shell.set_next_input(h.rstrip())
281 self.shell.set_next_input(h.rstrip())
282 return
282 return
283 else:
283 else:
284 self.shell.set_next_input(cmd.rstrip())
284 self.shell.set_next_input(cmd.rstrip())
285 return
285 return
286 print("Couldn't evaluate or find in history:", arg)
286 print("Couldn't evaluate or find in history:", arg)
287
287
288 @line_magic
288 @line_magic
289 def rerun(self, parameter_s=''):
289 def rerun(self, parameter_s=''):
290 """Re-run previous input
290 """Re-run previous input
291
291
292 By default, you can specify ranges of input history to be repeated
292 By default, you can specify ranges of input history to be repeated
293 (as with %history). With no arguments, it will repeat the last line.
293 (as with %history). With no arguments, it will repeat the last line.
294
294
295 Options:
295 Options:
296
296
297 -l <n> : Repeat the last n lines of input, not including the
297 -l <n> : Repeat the last n lines of input, not including the
298 current command.
298 current command.
299
299
300 -g foo : Repeat the most recent line which contains foo
300 -g foo : Repeat the most recent line which contains foo
301 """
301 """
302 opts, args = self.parse_options(parameter_s, 'l:g:', mode='string')
302 opts, args = self.parse_options(parameter_s, 'l:g:', mode='string')
303 if "l" in opts: # Last n lines
303 if "l" in opts: # Last n lines
304 n = int(opts['l'])
304 n = int(opts['l'])
305
306 if n == 0:
307 print("Requested 0 last lines - nothing to run")
308 return
309 elif n < 0:
310 print("Number of lines to rerun cannot be negative")
311 return
312
305 hist = self.shell.history_manager.get_tail(n)
313 hist = self.shell.history_manager.get_tail(n)
306 elif "g" in opts: # Search
314 elif "g" in opts: # Search
307 p = "*"+opts['g']+"*"
315 p = "*"+opts['g']+"*"
308 hist = list(self.shell.history_manager.search(p))
316 hist = list(self.shell.history_manager.search(p))
309 for l in reversed(hist):
317 for l in reversed(hist):
310 if "rerun" not in l[2]:
318 if "rerun" not in l[2]:
311 hist = [l] # The last match which isn't a %rerun
319 hist = [l] # The last match which isn't a %rerun
312 break
320 break
313 else:
321 else:
314 hist = [] # No matches except %rerun
322 hist = [] # No matches except %rerun
315 elif args: # Specify history ranges
323 elif args: # Specify history ranges
316 hist = self.shell.history_manager.get_range_by_str(args)
324 hist = self.shell.history_manager.get_range_by_str(args)
317 else: # Last line
325 else: # Last line
318 hist = self.shell.history_manager.get_tail(1)
326 hist = self.shell.history_manager.get_tail(1)
319 hist = [x[2] for x in hist]
327 hist = [x[2] for x in hist]
320 if not hist:
328 if not hist:
321 print("No lines in history match specification")
329 print("No lines in history match specification")
322 return
330 return
323 histlines = "\n".join(hist)
331 histlines = "\n".join(hist)
324 print("=== Executing: ===")
332 print("=== Executing: ===")
325 print(histlines)
333 print(histlines)
326 print("=== Output: ===")
334 print("=== Output: ===")
327 self.shell.run_cell("\n".join(hist), store_history=False)
335 self.shell.run_cell("\n".join(hist), store_history=False)
General Comments 0
You need to be logged in to leave comments. Login now