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