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