##// END OF EJS Templates
Remove superfluous import.
Thomas Kluyver -
Show More
@@ -1,806 +1,805 b''
1 1 """ History related magics and functionality """
2 2 #-----------------------------------------------------------------------------
3 3 # Copyright (C) 2010 The IPython Development Team.
4 4 #
5 5 # Distributed under the terms of the BSD License.
6 6 #
7 7 # The full license is in the file COPYING.txt, distributed with this software.
8 8 #-----------------------------------------------------------------------------
9 9
10 10 #-----------------------------------------------------------------------------
11 11 # Imports
12 12 #-----------------------------------------------------------------------------
13 13 from __future__ import print_function
14 14
15 15 # Stdlib imports
16 16 import atexit
17 17 import datetime
18 18 import json
19 19 import os
20 20 import re
21 21 import sqlite3
22 22 import threading
23 23
24 24 from collections import defaultdict
25 from contextlib import nested
26 25
27 26 # Our own packages
28 27 from IPython.config.configurable import Configurable
29 28 import IPython.utils.io
30 29
31 30 from IPython.testing import decorators as testdec
32 31 from IPython.utils.io import ask_yes_no
33 32 from IPython.utils.traitlets import Bool, Dict, Instance, Int, List, Unicode
34 33 from IPython.utils.warn import warn
35 34
36 35 #-----------------------------------------------------------------------------
37 36 # Classes and functions
38 37 #-----------------------------------------------------------------------------
39 38
40 39 class HistoryManager(Configurable):
41 40 """A class to organize all history-related functionality in one place.
42 41 """
43 42 # Public interface
44 43
45 44 # An instance of the IPython shell we are attached to
46 45 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC')
47 46 # Lists to hold processed and raw history. These start with a blank entry
48 47 # so that we can index them starting from 1
49 48 input_hist_parsed = List([""])
50 49 input_hist_raw = List([""])
51 50 # A list of directories visited during session
52 51 dir_hist = List()
53 52 def _dir_hist_default(self):
54 53 try:
55 54 return [os.getcwd()]
56 55 except OSError:
57 56 return []
58 57
59 58 # A dict of output history, keyed with ints from the shell's
60 59 # execution count. If there are several outputs from one command,
61 60 # only the last one is stored.
62 61 output_hist = Dict()
63 62 # Contains all outputs, in lists of reprs.
64 63 output_hist_reprs = Instance(defaultdict, args=(list,))
65 64
66 65 # String holding the path to the history file
67 66 hist_file = Unicode(config=True)
68 67
69 68 # The SQLite database
70 69 db = Instance(sqlite3.Connection)
71 70 # The number of the current session in the history database
72 71 session_number = Int()
73 72 # Should we log output to the database? (default no)
74 73 db_log_output = Bool(False, config=True)
75 74 # Write to database every x commands (higher values save disk access & power)
76 75 # Values of 1 or less effectively disable caching.
77 76 db_cache_size = Int(0, config=True)
78 77 # The input and output caches
79 78 db_input_cache = List()
80 79 db_output_cache = List()
81 80
82 81 # History saving in separate thread
83 82 save_thread = Instance('IPython.core.history.HistorySavingThread')
84 83 save_flag = Instance(threading._Event)
85 84
86 85 # Private interface
87 86 # Variables used to store the three last inputs from the user. On each new
88 87 # history update, we populate the user's namespace with these, shifted as
89 88 # necessary.
90 89 _i00 = Unicode(u'')
91 90 _i = Unicode(u'')
92 91 _ii = Unicode(u'')
93 92 _iii = Unicode(u'')
94 93
95 94 # A set with all forms of the exit command, so that we don't store them in
96 95 # the history (it's annoying to rewind the first entry and land on an exit
97 96 # call).
98 97 _exit_commands = Instance(set, args=(['Quit', 'quit', 'Exit', 'exit',
99 98 '%Quit', '%quit', '%Exit', '%exit'],))
100 99
101 100 def __init__(self, shell, config=None, **traits):
102 101 """Create a new history manager associated with a shell instance.
103 102 """
104 103 # We need a pointer back to the shell for various tasks.
105 104 super(HistoryManager, self).__init__(shell=shell, config=config,
106 105 **traits)
107 106
108 107 if self.hist_file == u'':
109 108 # No one has set the hist_file, yet.
110 109 if shell.profile:
111 110 histfname = 'history-%s' % shell.profile
112 111 else:
113 112 histfname = 'history'
114 113 self.hist_file = os.path.join(shell.ipython_dir, histfname + '.sqlite')
115 114
116 115 try:
117 116 self.init_db()
118 117 except sqlite3.DatabaseError:
119 118 if os.path.isfile(self.hist_file):
120 119 # Try to move the file out of the way.
121 120 newpath = os.path.join(self.shell.ipython_dir, "hist-corrupt.sqlite")
122 121 os.rename(self.hist_file, newpath)
123 122 print("ERROR! History file wasn't a valid SQLite database.",
124 123 "It was moved to %s" % newpath, "and a new file created.")
125 124 self.init_db()
126 125 else:
127 126 # The hist_file is probably :memory: or something else.
128 127 raise
129 128
130 129 self.save_flag = threading.Event()
131 130 self.db_input_cache_lock = threading.Lock()
132 131 self.db_output_cache_lock = threading.Lock()
133 132 self.save_thread = HistorySavingThread(self)
134 133 self.save_thread.start()
135 134
136 135 self.new_session()
137 136
138 137
139 138 def init_db(self):
140 139 """Connect to the database, and create tables if necessary."""
141 140 self.db = sqlite3.connect(self.hist_file)
142 141 self.db.execute("""CREATE TABLE IF NOT EXISTS sessions (session integer
143 142 primary key autoincrement, start timestamp,
144 143 end timestamp, num_cmds integer, remark text)""")
145 144 self.db.execute("""CREATE TABLE IF NOT EXISTS history
146 145 (session integer, line integer, source text, source_raw text,
147 146 PRIMARY KEY (session, line))""")
148 147 # Output history is optional, but ensure the table's there so it can be
149 148 # enabled later.
150 149 self.db.execute("""CREATE TABLE IF NOT EXISTS output_history
151 150 (session integer, line integer, output text,
152 151 PRIMARY KEY (session, line))""")
153 152 self.db.commit()
154 153
155 154 def new_session(self, conn=None):
156 155 """Get a new session number."""
157 156 if conn is None:
158 157 conn = self.db
159 158
160 159 with conn:
161 160 cur = conn.execute("""INSERT INTO sessions VALUES (NULL, ?, NULL,
162 161 NULL, "") """, (datetime.datetime.now(),))
163 162 self.session_number = cur.lastrowid
164 163
165 164 def end_session(self):
166 165 """Close the database session, filling in the end time and line count."""
167 166 self.writeout_cache()
168 167 with self.db:
169 168 self.db.execute("""UPDATE sessions SET end=?, num_cmds=? WHERE
170 169 session==?""", (datetime.datetime.now(),
171 170 len(self.input_hist_parsed)-1, self.session_number))
172 171 self.session_number = 0
173 172
174 173 def name_session(self, name):
175 174 """Give the current session a name in the history database."""
176 175 with self.db:
177 176 self.db.execute("UPDATE sessions SET remark=? WHERE session==?",
178 177 (name, self.session_number))
179 178
180 179 def reset(self, new_session=True):
181 180 """Clear the session history, releasing all object references, and
182 181 optionally open a new session."""
183 182 self.output_hist.clear()
184 183 # The directory history can't be completely empty
185 184 self.dir_hist[:] = [os.getcwd()]
186 185
187 186 if new_session:
188 187 if self.session_number:
189 188 self.end_session()
190 189 self.input_hist_parsed[:] = [""]
191 190 self.input_hist_raw[:] = [""]
192 191 self.new_session()
193 192
194 193 ## -------------------------------
195 194 ## Methods for retrieving history:
196 195 ## -------------------------------
197 196 def _run_sql(self, sql, params, raw=True, output=False):
198 197 """Prepares and runs an SQL query for the history database.
199 198
200 199 Parameters
201 200 ----------
202 201 sql : str
203 202 Any filtering expressions to go after SELECT ... FROM ...
204 203 params : tuple
205 204 Parameters passed to the SQL query (to replace "?")
206 205 raw, output : bool
207 206 See :meth:`get_range`
208 207
209 208 Returns
210 209 -------
211 210 Tuples as :meth:`get_range`
212 211 """
213 212 toget = 'source_raw' if raw else 'source'
214 213 sqlfrom = "history"
215 214 if output:
216 215 sqlfrom = "history LEFT JOIN output_history USING (session, line)"
217 216 toget = "history.%s, output_history.output" % toget
218 217 cur = self.db.execute("SELECT session, line, %s FROM %s " %\
219 218 (toget, sqlfrom) + sql, params)
220 219 if output: # Regroup into 3-tuples, and parse JSON
221 220 loads = lambda out: json.loads(out) if out else None
222 221 return ((ses, lin, (inp, loads(out))) \
223 222 for ses, lin, inp, out in cur)
224 223 return cur
225 224
226 225
227 226 def get_tail(self, n=10, raw=True, output=False, include_latest=False):
228 227 """Get the last n lines from the history database.
229 228
230 229 Parameters
231 230 ----------
232 231 n : int
233 232 The number of lines to get
234 233 raw, output : bool
235 234 See :meth:`get_range`
236 235 include_latest : bool
237 236 If False (default), n+1 lines are fetched, and the latest one
238 237 is discarded. This is intended to be used where the function
239 238 is called by a user command, which it should not return.
240 239
241 240 Returns
242 241 -------
243 242 Tuples as :meth:`get_range`
244 243 """
245 244 self.writeout_cache()
246 245 if not include_latest:
247 246 n += 1
248 247 cur = self._run_sql("ORDER BY session DESC, line DESC LIMIT ?",
249 248 (n,), raw=raw, output=output)
250 249 if not include_latest:
251 250 return reversed(list(cur)[1:])
252 251 return reversed(list(cur))
253 252
254 253 def search(self, pattern="*", raw=True, search_raw=True,
255 254 output=False):
256 255 """Search the database using unix glob-style matching (wildcards
257 256 * and ?).
258 257
259 258 Parameters
260 259 ----------
261 260 pattern : str
262 261 The wildcarded pattern to match when searching
263 262 search_raw : bool
264 263 If True, search the raw input, otherwise, the parsed input
265 264 raw, output : bool
266 265 See :meth:`get_range`
267 266
268 267 Returns
269 268 -------
270 269 Tuples as :meth:`get_range`
271 270 """
272 271 tosearch = "source_raw" if search_raw else "source"
273 272 if output:
274 273 tosearch = "history." + tosearch
275 274 self.writeout_cache()
276 275 return self._run_sql("WHERE %s GLOB ?" % tosearch, (pattern,),
277 276 raw=raw, output=output)
278 277
279 278 def _get_range_session(self, start=1, stop=None, raw=True, output=False):
280 279 """Get input and output history from the current session. Called by
281 280 get_range, and takes similar parameters."""
282 281 input_hist = self.input_hist_raw if raw else self.input_hist_parsed
283 282
284 283 n = len(input_hist)
285 284 if start < 0:
286 285 start += n
287 286 if not stop:
288 287 stop = n
289 288 elif stop < 0:
290 289 stop += n
291 290
292 291 for i in range(start, stop):
293 292 if output:
294 293 line = (input_hist[i], self.output_hist_reprs.get(i))
295 294 else:
296 295 line = input_hist[i]
297 296 yield (0, i, line)
298 297
299 298 def get_range(self, session=0, start=1, stop=None, raw=True,output=False):
300 299 """Retrieve input by session.
301 300
302 301 Parameters
303 302 ----------
304 303 session : int
305 304 Session number to retrieve. The current session is 0, and negative
306 305 numbers count back from current session, so -1 is previous session.
307 306 start : int
308 307 First line to retrieve.
309 308 stop : int
310 309 End of line range (excluded from output itself). If None, retrieve
311 310 to the end of the session.
312 311 raw : bool
313 312 If True, return untranslated input
314 313 output : bool
315 314 If True, attempt to include output. This will be 'real' Python
316 315 objects for the current session, or text reprs from previous
317 316 sessions if db_log_output was enabled at the time. Where no output
318 317 is found, None is used.
319 318
320 319 Returns
321 320 -------
322 321 An iterator over the desired lines. Each line is a 3-tuple, either
323 322 (session, line, input) if output is False, or
324 323 (session, line, (input, output)) if output is True.
325 324 """
326 325 if session == 0 or session==self.session_number: # Current session
327 326 return self._get_range_session(start, stop, raw, output)
328 327 if session < 0:
329 328 session += self.session_number
330 329
331 330 if stop:
332 331 lineclause = "line >= ? AND line < ?"
333 332 params = (session, start, stop)
334 333 else:
335 334 lineclause = "line>=?"
336 335 params = (session, start)
337 336
338 337 return self._run_sql("WHERE session==? AND %s""" % lineclause,
339 338 params, raw=raw, output=output)
340 339
341 340 def get_range_by_str(self, rangestr, raw=True, output=False):
342 341 """Get lines of history from a string of ranges, as used by magic
343 342 commands %hist, %save, %macro, etc.
344 343
345 344 Parameters
346 345 ----------
347 346 rangestr : str
348 347 A string specifying ranges, e.g. "5 ~2/1-4". See
349 348 :func:`magic_history` for full details.
350 349 raw, output : bool
351 350 As :meth:`get_range`
352 351
353 352 Returns
354 353 -------
355 354 Tuples as :meth:`get_range`
356 355 """
357 356 for sess, s, e in extract_hist_ranges(rangestr):
358 357 for line in self.get_range(sess, s, e, raw=raw, output=output):
359 358 yield line
360 359
361 360 ## ----------------------------
362 361 ## Methods for storing history:
363 362 ## ----------------------------
364 363 def store_inputs(self, line_num, source, source_raw=None):
365 364 """Store source and raw input in history and create input cache
366 365 variables _i*.
367 366
368 367 Parameters
369 368 ----------
370 369 line_num : int
371 370 The prompt number of this input.
372 371
373 372 source : str
374 373 Python input.
375 374
376 375 source_raw : str, optional
377 376 If given, this is the raw input without any IPython transformations
378 377 applied to it. If not given, ``source`` is used.
379 378 """
380 379 if source_raw is None:
381 380 source_raw = source
382 381 source = source.rstrip('\n')
383 382 source_raw = source_raw.rstrip('\n')
384 383
385 384 # do not store exit/quit commands
386 385 if source_raw.strip() in self._exit_commands:
387 386 return
388 387
389 388 self.input_hist_parsed.append(source)
390 389 self.input_hist_raw.append(source_raw)
391 390
392 391 with self.db_input_cache_lock:
393 392 self.db_input_cache.append((line_num, source, source_raw))
394 393 # Trigger to flush cache and write to DB.
395 394 if len(self.db_input_cache) >= self.db_cache_size:
396 395 self.save_flag.set()
397 396
398 397 # update the auto _i variables
399 398 self._iii = self._ii
400 399 self._ii = self._i
401 400 self._i = self._i00
402 401 self._i00 = source_raw
403 402
404 403 # hackish access to user namespace to create _i1,_i2... dynamically
405 404 new_i = '_i%s' % line_num
406 405 to_main = {'_i': self._i,
407 406 '_ii': self._ii,
408 407 '_iii': self._iii,
409 408 new_i : self._i00 }
410 409 self.shell.user_ns.update(to_main)
411 410
412 411 def store_output(self, line_num):
413 412 """If database output logging is enabled, this saves all the
414 413 outputs from the indicated prompt number to the database. It's
415 414 called by run_cell after code has been executed.
416 415
417 416 Parameters
418 417 ----------
419 418 line_num : int
420 419 The line number from which to save outputs
421 420 """
422 421 if (not self.db_log_output) or not self.output_hist_reprs[line_num]:
423 422 return
424 423 output = json.dumps(self.output_hist_reprs[line_num])
425 424
426 425 with self.db_output_cache_lock:
427 426 self.db_output_cache.append((line_num, output))
428 427 if self.db_cache_size <= 1:
429 428 self.save_flag.set()
430 429
431 430 def _writeout_input_cache(self, conn):
432 431 with conn:
433 432 for line in self.db_input_cache:
434 433 conn.execute("INSERT INTO history VALUES (?, ?, ?, ?)",
435 434 (self.session_number,)+line)
436 435
437 436 def _writeout_output_cache(self, conn):
438 437 with conn:
439 438 for line in self.db_output_cache:
440 439 conn.execute("INSERT INTO output_history VALUES (?, ?, ?)",
441 440 (self.session_number,)+line)
442 441
443 442 def writeout_cache(self, conn=None):
444 443 """Write any entries in the cache to the database."""
445 444 if conn is None:
446 445 conn = self.db
447 446
448 447 with self.db_input_cache_lock:
449 448 try:
450 449 self._writeout_input_cache(conn)
451 450 except sqlite3.IntegrityError:
452 451 self.new_session(conn)
453 452 print("ERROR! Session/line number was not unique in",
454 453 "database. History logging moved to new session",
455 454 self.session_number)
456 455 try: # Try writing to the new session. If this fails, don't recurse
457 456 self._writeout_input_cache(conn)
458 457 except sqlite3.IntegrityError:
459 458 pass
460 459 finally:
461 460 self.db_input_cache = []
462 461
463 462 with self.db_output_cache_lock:
464 463 try:
465 464 self._writeout_output_cache(conn)
466 465 except sqlite3.IntegrityError:
467 466 print("!! Session/line number for output was not unique",
468 467 "in database. Output will not be stored.")
469 468 finally:
470 469 self.db_output_cache = []
471 470
472 471
473 472 class HistorySavingThread(threading.Thread):
474 473 """This thread takes care of writing history to the database, so that
475 474 the UI isn't held up while that happens.
476 475
477 476 It waits for the HistoryManager's save_flag to be set, then writes out
478 477 the history cache. The main thread is responsible for setting the flag when
479 478 the cache size reaches a defined threshold."""
480 479 daemon = True
481 480 stop_now = False
482 481 def __init__(self, history_manager):
483 482 super(HistorySavingThread, self).__init__()
484 483 self.history_manager = history_manager
485 484 atexit.register(self.stop)
486 485
487 486 def run(self):
488 487 # We need a separate db connection per thread:
489 488 self.db = sqlite3.connect(self.history_manager.hist_file)
490 489 while True:
491 490 self.history_manager.save_flag.wait()
492 491 if self.stop_now:
493 492 return
494 493 self.history_manager.save_flag.clear()
495 494 self.history_manager.writeout_cache(self.db)
496 495
497 496 def stop(self):
498 497 """This can be called from the main thread to safely stop this thread.
499 498
500 499 Note that it does not attempt to write out remaining history before
501 500 exiting. That should be done by calling the HistoryManager's
502 501 end_session method."""
503 502 self.stop_now = True
504 503 self.history_manager.save_flag.set()
505 504 self.join()
506 505
507 506
508 507 # To match, e.g. ~5/8-~2/3
509 508 range_re = re.compile(r"""
510 509 ((?P<startsess>~?\d+)/)?
511 510 (?P<start>\d+) # Only the start line num is compulsory
512 511 ((?P<sep>[\-:])
513 512 ((?P<endsess>~?\d+)/)?
514 513 (?P<end>\d+))?
515 514 $""", re.VERBOSE)
516 515
517 516 def extract_hist_ranges(ranges_str):
518 517 """Turn a string of history ranges into 3-tuples of (session, start, stop).
519 518
520 519 Examples
521 520 --------
522 521 list(extract_input_ranges("~8/5-~7/4 2"))
523 522 [(-8, 5, None), (-7, 1, 4), (0, 2, 3)]
524 523 """
525 524 for range_str in ranges_str.split():
526 525 rmatch = range_re.match(range_str)
527 526 if not rmatch:
528 527 continue
529 528 start = int(rmatch.group("start"))
530 529 end = rmatch.group("end")
531 530 end = int(end) if end else start+1 # If no end specified, get (a, a+1)
532 531 if rmatch.group("sep") == "-": # 1-3 == 1:4 --> [1, 2, 3]
533 532 end += 1
534 533 startsess = rmatch.group("startsess") or "0"
535 534 endsess = rmatch.group("endsess") or startsess
536 535 startsess = int(startsess.replace("~","-"))
537 536 endsess = int(endsess.replace("~","-"))
538 537 assert endsess >= startsess
539 538
540 539 if endsess == startsess:
541 540 yield (startsess, start, end)
542 541 continue
543 542 # Multiple sessions in one range:
544 543 yield (startsess, start, None)
545 544 for sess in range(startsess+1, endsess):
546 545 yield (sess, 1, None)
547 546 yield (endsess, 1, end)
548 547
549 548 def _format_lineno(session, line):
550 549 """Helper function to format line numbers properly."""
551 550 if session == 0:
552 551 return str(line)
553 552 return "%s#%s" % (session, line)
554 553
555 554 @testdec.skip_doctest
556 555 def magic_history(self, parameter_s = ''):
557 556 """Print input history (_i<n> variables), with most recent last.
558 557
559 558 %history -> print at most 40 inputs (some may be multi-line)\\
560 559 %history n -> print at most n inputs\\
561 560 %history n1 n2 -> print inputs between n1 and n2 (n2 not included)\\
562 561
563 562 By default, input history is printed without line numbers so it can be
564 563 directly pasted into an editor. Use -n to show them.
565 564
566 565 Ranges of history can be indicated using the syntax:
567 566 4 : Line 4, current session
568 567 4-6 : Lines 4-6, current session
569 568 243/1-5: Lines 1-5, session 243
570 569 ~2/7 : Line 7, session 2 before current
571 570 ~8/1-~6/5 : From the first line of 8 sessions ago, to the fifth line
572 571 of 6 sessions ago.
573 572 Multiple ranges can be entered, separated by spaces
574 573
575 574 The same syntax is used by %macro, %save, %edit, %rerun
576 575
577 576 Options:
578 577
579 578 -n: print line numbers for each input.
580 579 This feature is only available if numbered prompts are in use.
581 580
582 581 -o: also print outputs for each input.
583 582
584 583 -p: print classic '>>>' python prompts before each input. This is useful
585 584 for making documentation, and in conjunction with -o, for producing
586 585 doctest-ready output.
587 586
588 587 -r: (default) print the 'raw' history, i.e. the actual commands you typed.
589 588
590 589 -t: print the 'translated' history, as IPython understands it. IPython
591 590 filters your input and converts it all into valid Python source before
592 591 executing it (things like magics or aliases are turned into function
593 592 calls, for example). With this option, you'll see the native history
594 593 instead of the user-entered version: '%cd /' will be seen as
595 594 'get_ipython().magic("%cd /")' instead of '%cd /'.
596 595
597 596 -g: treat the arg as a pattern to grep for in (full) history.
598 597 This includes the saved history (almost all commands ever written).
599 598 Use '%hist -g' to show full saved history (may be very long).
600 599
601 600 -l: get the last n lines from all sessions. Specify n as a single arg, or
602 601 the default is the last 10 lines.
603 602
604 603 -f FILENAME: instead of printing the output to the screen, redirect it to
605 604 the given file. The file is always overwritten, though IPython asks for
606 605 confirmation first if it already exists.
607 606
608 607 Examples
609 608 --------
610 609 ::
611 610
612 611 In [6]: %hist -n 4 6
613 612 4:a = 12
614 613 5:print a**2
615 614
616 615 """
617 616
618 617 if not self.shell.displayhook.do_full_cache:
619 618 print('This feature is only available if numbered prompts are in use.')
620 619 return
621 620 opts,args = self.parse_options(parameter_s,'noprtglf:',mode='string')
622 621
623 622 # For brevity
624 623 history_manager = self.shell.history_manager
625 624
626 625 def _format_lineno(session, line):
627 626 """Helper function to format line numbers properly."""
628 627 if session in (0, history_manager.session_number):
629 628 return str(line)
630 629 return "%s/%s" % (session, line)
631 630
632 631 # Check if output to specific file was requested.
633 632 try:
634 633 outfname = opts['f']
635 634 except KeyError:
636 635 outfile = IPython.utils.io.Term.cout # default
637 636 # We don't want to close stdout at the end!
638 637 close_at_end = False
639 638 else:
640 639 if os.path.exists(outfname):
641 640 if not ask_yes_no("File %r exists. Overwrite?" % outfname):
642 641 print('Aborting.')
643 642 return
644 643
645 644 outfile = open(outfname,'w')
646 645 close_at_end = True
647 646
648 647 print_nums = 'n' in opts
649 648 get_output = 'o' in opts
650 649 pyprompts = 'p' in opts
651 650 # Raw history is the default
652 651 raw = not('t' in opts)
653 652
654 653 default_length = 40
655 654 pattern = None
656 655
657 656 if 'g' in opts: # Glob search
658 657 pattern = "*" + args + "*" if args else "*"
659 658 hist = history_manager.search(pattern, raw=raw, output=get_output)
660 659 elif 'l' in opts: # Get 'tail'
661 660 try:
662 661 n = int(args)
663 662 except ValueError, IndexError:
664 663 n = 10
665 664 hist = history_manager.get_tail(n, raw=raw, output=get_output)
666 665 else:
667 666 if args: # Get history by ranges
668 667 hist = history_manager.get_range_by_str(args, raw, get_output)
669 668 else: # Just get history for the current session
670 669 hist = history_manager.get_range(raw=raw, output=get_output)
671 670
672 671 # We could be displaying the entire history, so let's not try to pull it
673 672 # into a list in memory. Anything that needs more space will just misalign.
674 673 width = 4
675 674
676 675 for session, lineno, inline in hist:
677 676 # Print user history with tabs expanded to 4 spaces. The GUI clients
678 677 # use hard tabs for easier usability in auto-indented code, but we want
679 678 # to produce PEP-8 compliant history for safe pasting into an editor.
680 679 if get_output:
681 680 inline, output = inline
682 681 inline = inline.expandtabs(4).rstrip()
683 682
684 683 multiline = "\n" in inline
685 684 line_sep = '\n' if multiline else ' '
686 685 if print_nums:
687 686 print('%s:%s' % (_format_lineno(session, lineno).rjust(width),
688 687 line_sep), file=outfile, end='')
689 688 if pyprompts:
690 689 print(">>> ", end="", file=outfile)
691 690 if multiline:
692 691 inline = "\n... ".join(inline.splitlines()) + "\n..."
693 692 print(inline, file=outfile)
694 693 if get_output and output:
695 694 print("\n".join(output), file=outfile)
696 695
697 696 if close_at_end:
698 697 outfile.close()
699 698
700 699
701 700 def magic_rep(self, arg):
702 701 r""" Repeat a command, or get command to input line for editing
703 702
704 703 - %rep (no arguments):
705 704
706 705 Place a string version of last computation result (stored in the special '_'
707 706 variable) to the next input prompt. Allows you to create elaborate command
708 707 lines without using copy-paste::
709 708
710 709 In[1]: l = ["hei", "vaan"]
711 710 In[2]: "".join(l)
712 711 Out[2]: heivaan
713 712 In[3]: %rep
714 713 In[4]: heivaan_ <== cursor blinking
715 714
716 715 %rep 45
717 716
718 717 Place history line 45 on the next input prompt. Use %hist to find
719 718 out the number.
720 719
721 720 %rep 1-4
722 721
723 722 Combine the specified lines into one cell, and place it on the next
724 723 input prompt. See %history for the slice syntax.
725 724
726 725 %rep foo+bar
727 726
728 727 If foo+bar can be evaluated in the user namespace, the result is
729 728 placed at the next input prompt. Otherwise, the history is searched
730 729 for lines which contain that substring, and the most recent one is
731 730 placed at the next input prompt.
732 731 """
733 732 if not arg: # Last output
734 733 self.set_next_input(str(self.shell.user_ns["_"]))
735 734 return
736 735 # Get history range
737 736 histlines = self.history_manager.get_range_by_str(arg)
738 737 cmd = "\n".join(x[2] for x in histlines)
739 738 if cmd:
740 739 self.set_next_input(cmd.rstrip())
741 740 return
742 741
743 742 try: # Variable in user namespace
744 743 cmd = str(eval(arg, self.shell.user_ns))
745 744 except Exception: # Search for term in history
746 745 histlines = self.history_manager.search("*"+arg+"*")
747 746 for h in reversed([x[2] for x in histlines]):
748 747 if 'rep' in h:
749 748 continue
750 749 self.set_next_input(h.rstrip())
751 750 return
752 751 else:
753 752 self.set_next_input(cmd.rstrip())
754 753 print("Couldn't evaluate or find in history:", arg)
755 754
756 755 def magic_rerun(self, parameter_s=''):
757 756 """Re-run previous input
758 757
759 758 By default, you can specify ranges of input history to be repeated
760 759 (as with %history). With no arguments, it will repeat the last line.
761 760
762 761 Options:
763 762
764 763 -l <n> : Repeat the last n lines of input, not including the
765 764 current command.
766 765
767 766 -g foo : Repeat the most recent line which contains foo
768 767 """
769 768 opts, args = self.parse_options(parameter_s, 'l:g:', mode='string')
770 769 if "l" in opts: # Last n lines
771 770 n = int(opts['l'])
772 771 hist = self.history_manager.get_tail(n)
773 772 elif "g" in opts: # Search
774 773 p = "*"+opts['g']+"*"
775 774 hist = list(self.history_manager.search(p))
776 775 for l in reversed(hist):
777 776 if "rerun" not in l[2]:
778 777 hist = [l] # The last match which isn't a %rerun
779 778 break
780 779 else:
781 780 hist = [] # No matches except %rerun
782 781 elif args: # Specify history ranges
783 782 hist = self.history_manager.get_range_by_str(args)
784 783 else: # Last line
785 784 hist = self.history_manager.get_tail(1)
786 785 hist = [x[2] for x in hist]
787 786 if not hist:
788 787 print("No lines in history match specification")
789 788 return
790 789 histlines = "\n".join(hist)
791 790 print("=== Executing: ===")
792 791 print(histlines)
793 792 print("=== Output: ===")
794 793 self.run_cell("\n".join(hist), store_history=False)
795 794
796 795
797 796 def init_ipython(ip):
798 797 ip.define_magic("rep", magic_rep)
799 798 ip.define_magic("recall", magic_rep)
800 799 ip.define_magic("rerun", magic_rerun)
801 800 ip.define_magic("hist",magic_history) # Alternative name
802 801 ip.define_magic("history",magic_history)
803 802
804 803 # XXX - ipy_completers are in quarantine, need to be updated to new apis
805 804 #import ipy_completers
806 805 #ipy_completers.quick_completer('%hist' ,'-g -t -r -n')
General Comments 0
You need to be logged in to leave comments. Login now