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