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