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