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