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