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