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