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