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