history.py 32 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911
  1. """ History related magics and functionality """
  2. # Copyright (c) IPython Development Team.
  3. # Distributed under the terms of the Modified BSD License.
  4. from __future__ import print_function
  5. import atexit
  6. import datetime
  7. import os
  8. import re
  9. try:
  10. import sqlite3
  11. except ImportError:
  12. try:
  13. from pysqlite2 import dbapi2 as sqlite3
  14. except ImportError:
  15. sqlite3 = None
  16. import threading
  17. from traitlets.config.configurable import LoggingConfigurable
  18. from decorator import decorator
  19. from IPython.utils.decorators import undoc
  20. from IPython.utils.path import locate_profile
  21. from IPython.utils import py3compat
  22. from traitlets import (
  23. Any, Bool, Dict, Instance, Integer, List, Unicode, TraitError,
  24. default, observe,
  25. )
  26. from warnings import warn
  27. #-----------------------------------------------------------------------------
  28. # Classes and functions
  29. #-----------------------------------------------------------------------------
  30. @undoc
  31. class DummyDB(object):
  32. """Dummy DB that will act as a black hole for history.
  33. Only used in the absence of sqlite"""
  34. def execute(*args, **kwargs):
  35. return []
  36. def commit(self, *args, **kwargs):
  37. pass
  38. def __enter__(self, *args, **kwargs):
  39. pass
  40. def __exit__(self, *args, **kwargs):
  41. pass
  42. @decorator
  43. def needs_sqlite(f, self, *a, **kw):
  44. """Decorator: return an empty list in the absence of sqlite."""
  45. if sqlite3 is None or not self.enabled:
  46. return []
  47. else:
  48. return f(self, *a, **kw)
  49. if sqlite3 is not None:
  50. DatabaseError = sqlite3.DatabaseError
  51. OperationalError = sqlite3.OperationalError
  52. else:
  53. @undoc
  54. class DatabaseError(Exception):
  55. "Dummy exception when sqlite could not be imported. Should never occur."
  56. @undoc
  57. class OperationalError(Exception):
  58. "Dummy exception when sqlite could not be imported. Should never occur."
  59. # use 16kB as threshold for whether a corrupt history db should be saved
  60. # that should be at least 100 entries or so
  61. _SAVE_DB_SIZE = 16384
  62. @decorator
  63. def catch_corrupt_db(f, self, *a, **kw):
  64. """A decorator which wraps HistoryAccessor method calls to catch errors from
  65. a corrupt SQLite database, move the old database out of the way, and create
  66. a new one.
  67. We avoid clobbering larger databases because this may be triggered due to filesystem issues,
  68. not just a corrupt file.
  69. """
  70. try:
  71. return f(self, *a, **kw)
  72. except (DatabaseError, OperationalError) as e:
  73. self._corrupt_db_counter += 1
  74. self.log.error("Failed to open SQLite history %s (%s).", self.hist_file, e)
  75. if self.hist_file != ':memory:':
  76. if self._corrupt_db_counter > self._corrupt_db_limit:
  77. self.hist_file = ':memory:'
  78. self.log.error("Failed to load history too many times, history will not be saved.")
  79. elif os.path.isfile(self.hist_file):
  80. # move the file out of the way
  81. base, ext = os.path.splitext(self.hist_file)
  82. size = os.stat(self.hist_file).st_size
  83. if size >= _SAVE_DB_SIZE:
  84. # if there's significant content, avoid clobbering
  85. now = datetime.datetime.now().isoformat().replace(':', '.')
  86. newpath = base + '-corrupt-' + now + ext
  87. # don't clobber previous corrupt backups
  88. for i in range(100):
  89. if not os.path.isfile(newpath):
  90. break
  91. else:
  92. newpath = base + '-corrupt-' + now + (u'-%i' % i) + ext
  93. else:
  94. # not much content, possibly empty; don't worry about clobbering
  95. # maybe we should just delete it?
  96. newpath = base + '-corrupt' + ext
  97. os.rename(self.hist_file, newpath)
  98. self.log.error("History file was moved to %s and a new file created.", newpath)
  99. self.init_db()
  100. return []
  101. else:
  102. # Failed with :memory:, something serious is wrong
  103. raise
  104. class HistoryAccessorBase(LoggingConfigurable):
  105. """An abstract class for History Accessors """
  106. def get_tail(self, n=10, raw=True, output=False, include_latest=False):
  107. raise NotImplementedError
  108. def search(self, pattern="*", raw=True, search_raw=True,
  109. output=False, n=None, unique=False):
  110. raise NotImplementedError
  111. def get_range(self, session, start=1, stop=None, raw=True,output=False):
  112. raise NotImplementedError
  113. def get_range_by_str(self, rangestr, raw=True, output=False):
  114. raise NotImplementedError
  115. class HistoryAccessor(HistoryAccessorBase):
  116. """Access the history database without adding to it.
  117. This is intended for use by standalone history tools. IPython shells use
  118. HistoryManager, below, which is a subclass of this."""
  119. # counter for init_db retries, so we don't keep trying over and over
  120. _corrupt_db_counter = 0
  121. # after two failures, fallback on :memory:
  122. _corrupt_db_limit = 2
  123. # String holding the path to the history file
  124. hist_file = Unicode(
  125. help="""Path to file to use for SQLite history database.
  126. By default, IPython will put the history database in the IPython
  127. profile directory. If you would rather share one history among
  128. profiles, you can set this value in each, so that they are consistent.
  129. Due to an issue with fcntl, SQLite is known to misbehave on some NFS
  130. mounts. If you see IPython hanging, try setting this to something on a
  131. local disk, e.g::
  132. ipython --HistoryManager.hist_file=/tmp/ipython_hist.sqlite
  133. you can also use the specific value `:memory:` (including the colon
  134. at both end but not the back ticks), to avoid creating an history file.
  135. """).tag(config=True)
  136. enabled = Bool(True,
  137. help="""enable the SQLite history
  138. set enabled=False to disable the SQLite history,
  139. in which case there will be no stored history, no SQLite connection,
  140. and no background saving thread. This may be necessary in some
  141. threaded environments where IPython is embedded.
  142. """
  143. ).tag(config=True)
  144. connection_options = Dict(
  145. help="""Options for configuring the SQLite connection
  146. These options are passed as keyword args to sqlite3.connect
  147. when establishing database conenctions.
  148. """
  149. ).tag(config=True)
  150. # The SQLite database
  151. db = Any()
  152. @observe('db')
  153. def _db_changed(self, change):
  154. """validate the db, since it can be an Instance of two different types"""
  155. new = change['new']
  156. connection_types = (DummyDB,)
  157. if sqlite3 is not None:
  158. connection_types = (DummyDB, sqlite3.Connection)
  159. if not isinstance(new, connection_types):
  160. msg = "%s.db must be sqlite3 Connection or DummyDB, not %r" % \
  161. (self.__class__.__name__, new)
  162. raise TraitError(msg)
  163. def __init__(self, profile='default', hist_file=u'', **traits):
  164. """Create a new history accessor.
  165. Parameters
  166. ----------
  167. profile : str
  168. The name of the profile from which to open history.
  169. hist_file : str
  170. Path to an SQLite history database stored by IPython. If specified,
  171. hist_file overrides profile.
  172. config : :class:`~traitlets.config.loader.Config`
  173. Config object. hist_file can also be set through this.
  174. """
  175. # We need a pointer back to the shell for various tasks.
  176. super(HistoryAccessor, self).__init__(**traits)
  177. # defer setting hist_file from kwarg until after init,
  178. # otherwise the default kwarg value would clobber any value
  179. # set by config
  180. if hist_file:
  181. self.hist_file = hist_file
  182. if self.hist_file == u'':
  183. # No one has set the hist_file, yet.
  184. self.hist_file = self._get_hist_file_name(profile)
  185. if sqlite3 is None and self.enabled:
  186. warn("IPython History requires SQLite, your history will not be saved")
  187. self.enabled = False
  188. self.init_db()
  189. def _get_hist_file_name(self, profile='default'):
  190. """Find the history file for the given profile name.
  191. This is overridden by the HistoryManager subclass, to use the shell's
  192. active profile.
  193. Parameters
  194. ----------
  195. profile : str
  196. The name of a profile which has a history file.
  197. """
  198. return os.path.join(locate_profile(profile), 'history.sqlite')
  199. @catch_corrupt_db
  200. def init_db(self):
  201. """Connect to the database, and create tables if necessary."""
  202. if not self.enabled:
  203. self.db = DummyDB()
  204. return
  205. # use detect_types so that timestamps return datetime objects
  206. kwargs = dict(detect_types=sqlite3.PARSE_DECLTYPES|sqlite3.PARSE_COLNAMES)
  207. kwargs.update(self.connection_options)
  208. self.db = sqlite3.connect(self.hist_file, **kwargs)
  209. self.db.execute("""CREATE TABLE IF NOT EXISTS sessions (session integer
  210. primary key autoincrement, start timestamp,
  211. end timestamp, num_cmds integer, remark text)""")
  212. self.db.execute("""CREATE TABLE IF NOT EXISTS history
  213. (session integer, line integer, source text, source_raw text,
  214. PRIMARY KEY (session, line))""")
  215. # Output history is optional, but ensure the table's there so it can be
  216. # enabled later.
  217. self.db.execute("""CREATE TABLE IF NOT EXISTS output_history
  218. (session integer, line integer, output text,
  219. PRIMARY KEY (session, line))""")
  220. self.db.commit()
  221. # success! reset corrupt db count
  222. self._corrupt_db_counter = 0
  223. def writeout_cache(self):
  224. """Overridden by HistoryManager to dump the cache before certain
  225. database lookups."""
  226. pass
  227. ## -------------------------------
  228. ## Methods for retrieving history:
  229. ## -------------------------------
  230. def _run_sql(self, sql, params, raw=True, output=False):
  231. """Prepares and runs an SQL query for the history database.
  232. Parameters
  233. ----------
  234. sql : str
  235. Any filtering expressions to go after SELECT ... FROM ...
  236. params : tuple
  237. Parameters passed to the SQL query (to replace "?")
  238. raw, output : bool
  239. See :meth:`get_range`
  240. Returns
  241. -------
  242. Tuples as :meth:`get_range`
  243. """
  244. toget = 'source_raw' if raw else 'source'
  245. sqlfrom = "history"
  246. if output:
  247. sqlfrom = "history LEFT JOIN output_history USING (session, line)"
  248. toget = "history.%s, output_history.output" % toget
  249. cur = self.db.execute("SELECT session, line, %s FROM %s " %\
  250. (toget, sqlfrom) + sql, params)
  251. if output: # Regroup into 3-tuples, and parse JSON
  252. return ((ses, lin, (inp, out)) for ses, lin, inp, out in cur)
  253. return cur
  254. @needs_sqlite
  255. @catch_corrupt_db
  256. def get_session_info(self, session):
  257. """Get info about a session.
  258. Parameters
  259. ----------
  260. session : int
  261. Session number to retrieve.
  262. Returns
  263. -------
  264. session_id : int
  265. Session ID number
  266. start : datetime
  267. Timestamp for the start of the session.
  268. end : datetime
  269. Timestamp for the end of the session, or None if IPython crashed.
  270. num_cmds : int
  271. Number of commands run, or None if IPython crashed.
  272. remark : unicode
  273. A manually set description.
  274. """
  275. query = "SELECT * from sessions where session == ?"
  276. return self.db.execute(query, (session,)).fetchone()
  277. @catch_corrupt_db
  278. def get_last_session_id(self):
  279. """Get the last session ID currently in the database.
  280. Within IPython, this should be the same as the value stored in
  281. :attr:`HistoryManager.session_number`.
  282. """
  283. for record in self.get_tail(n=1, include_latest=True):
  284. return record[0]
  285. @catch_corrupt_db
  286. def get_tail(self, n=10, raw=True, output=False, include_latest=False):
  287. """Get the last n lines from the history database.
  288. Parameters
  289. ----------
  290. n : int
  291. The number of lines to get
  292. raw, output : bool
  293. See :meth:`get_range`
  294. include_latest : bool
  295. If False (default), n+1 lines are fetched, and the latest one
  296. is discarded. This is intended to be used where the function
  297. is called by a user command, which it should not return.
  298. Returns
  299. -------
  300. Tuples as :meth:`get_range`
  301. """
  302. self.writeout_cache()
  303. if not include_latest:
  304. n += 1
  305. cur = self._run_sql("ORDER BY session DESC, line DESC LIMIT ?",
  306. (n,), raw=raw, output=output)
  307. if not include_latest:
  308. return reversed(list(cur)[1:])
  309. return reversed(list(cur))
  310. @catch_corrupt_db
  311. def search(self, pattern="*", raw=True, search_raw=True,
  312. output=False, n=None, unique=False):
  313. """Search the database using unix glob-style matching (wildcards
  314. * and ?).
  315. Parameters
  316. ----------
  317. pattern : str
  318. The wildcarded pattern to match when searching
  319. search_raw : bool
  320. If True, search the raw input, otherwise, the parsed input
  321. raw, output : bool
  322. See :meth:`get_range`
  323. n : None or int
  324. If an integer is given, it defines the limit of
  325. returned entries.
  326. unique : bool
  327. When it is true, return only unique entries.
  328. Returns
  329. -------
  330. Tuples as :meth:`get_range`
  331. """
  332. tosearch = "source_raw" if search_raw else "source"
  333. if output:
  334. tosearch = "history." + tosearch
  335. self.writeout_cache()
  336. sqlform = "WHERE %s GLOB ?" % tosearch
  337. params = (pattern,)
  338. if unique:
  339. sqlform += ' GROUP BY {0}'.format(tosearch)
  340. if n is not None:
  341. sqlform += " ORDER BY session DESC, line DESC LIMIT ?"
  342. params += (n,)
  343. elif unique:
  344. sqlform += " ORDER BY session, line"
  345. cur = self._run_sql(sqlform, params, raw=raw, output=output)
  346. if n is not None:
  347. return reversed(list(cur))
  348. return cur
  349. @catch_corrupt_db
  350. def get_range(self, session, start=1, stop=None, raw=True,output=False):
  351. """Retrieve input by session.
  352. Parameters
  353. ----------
  354. session : int
  355. Session number to retrieve.
  356. start : int
  357. First line to retrieve.
  358. stop : int
  359. End of line range (excluded from output itself). If None, retrieve
  360. to the end of the session.
  361. raw : bool
  362. If True, return untranslated input
  363. output : bool
  364. If True, attempt to include output. This will be 'real' Python
  365. objects for the current session, or text reprs from previous
  366. sessions if db_log_output was enabled at the time. Where no output
  367. is found, None is used.
  368. Returns
  369. -------
  370. entries
  371. An iterator over the desired lines. Each line is a 3-tuple, either
  372. (session, line, input) if output is False, or
  373. (session, line, (input, output)) if output is True.
  374. """
  375. if stop:
  376. lineclause = "line >= ? AND line < ?"
  377. params = (session, start, stop)
  378. else:
  379. lineclause = "line>=?"
  380. params = (session, start)
  381. return self._run_sql("WHERE session==? AND %s" % lineclause,
  382. params, raw=raw, output=output)
  383. def get_range_by_str(self, rangestr, raw=True, output=False):
  384. """Get lines of history from a string of ranges, as used by magic
  385. commands %hist, %save, %macro, etc.
  386. Parameters
  387. ----------
  388. rangestr : str
  389. A string specifying ranges, e.g. "5 ~2/1-4". See
  390. :func:`magic_history` for full details.
  391. raw, output : bool
  392. As :meth:`get_range`
  393. Returns
  394. -------
  395. Tuples as :meth:`get_range`
  396. """
  397. for sess, s, e in extract_hist_ranges(rangestr):
  398. for line in self.get_range(sess, s, e, raw=raw, output=output):
  399. yield line
  400. class HistoryManager(HistoryAccessor):
  401. """A class to organize all history-related functionality in one place.
  402. """
  403. # Public interface
  404. # An instance of the IPython shell we are attached to
  405. shell = Instance('IPython.core.interactiveshell.InteractiveShellABC',
  406. allow_none=True)
  407. # Lists to hold processed and raw history. These start with a blank entry
  408. # so that we can index them starting from 1
  409. input_hist_parsed = List([""])
  410. input_hist_raw = List([""])
  411. # A list of directories visited during session
  412. dir_hist = List()
  413. @default('dir_hist')
  414. def _dir_hist_default(self):
  415. try:
  416. return [py3compat.getcwd()]
  417. except OSError:
  418. return []
  419. # A dict of output history, keyed with ints from the shell's
  420. # execution count.
  421. output_hist = Dict()
  422. # The text/plain repr of outputs.
  423. output_hist_reprs = Dict()
  424. # The number of the current session in the history database
  425. session_number = Integer()
  426. db_log_output = Bool(False,
  427. help="Should the history database include output? (default: no)"
  428. ).tag(config=True)
  429. db_cache_size = Integer(0,
  430. help="Write to database every x commands (higher values save disk access & power).\n"
  431. "Values of 1 or less effectively disable caching."
  432. ).tag(config=True)
  433. # The input and output caches
  434. db_input_cache = List()
  435. db_output_cache = List()
  436. # History saving in separate thread
  437. save_thread = Instance('IPython.core.history.HistorySavingThread',
  438. allow_none=True)
  439. try: # Event is a function returning an instance of _Event...
  440. save_flag = Instance(threading._Event, allow_none=True)
  441. except AttributeError: # ...until Python 3.3, when it's a class.
  442. save_flag = Instance(threading.Event, allow_none=True)
  443. # Private interface
  444. # Variables used to store the three last inputs from the user. On each new
  445. # history update, we populate the user's namespace with these, shifted as
  446. # necessary.
  447. _i00 = Unicode(u'')
  448. _i = Unicode(u'')
  449. _ii = Unicode(u'')
  450. _iii = Unicode(u'')
  451. # A regex matching all forms of the exit command, so that we don't store
  452. # them in the history (it's annoying to rewind the first entry and land on
  453. # an exit call).
  454. _exit_re = re.compile(r"(exit|quit)(\s*\(.*\))?$")
  455. def __init__(self, shell=None, config=None, **traits):
  456. """Create a new history manager associated with a shell instance.
  457. """
  458. # We need a pointer back to the shell for various tasks.
  459. super(HistoryManager, self).__init__(shell=shell, config=config,
  460. **traits)
  461. self.save_flag = threading.Event()
  462. self.db_input_cache_lock = threading.Lock()
  463. self.db_output_cache_lock = threading.Lock()
  464. try:
  465. self.new_session()
  466. except OperationalError:
  467. self.log.error("Failed to create history session in %s. History will not be saved.",
  468. self.hist_file, exc_info=True)
  469. self.hist_file = ':memory:'
  470. if self.enabled and self.hist_file != ':memory:':
  471. self.save_thread = HistorySavingThread(self)
  472. self.save_thread.start()
  473. def _get_hist_file_name(self, profile=None):
  474. """Get default history file name based on the Shell's profile.
  475. The profile parameter is ignored, but must exist for compatibility with
  476. the parent class."""
  477. profile_dir = self.shell.profile_dir.location
  478. return os.path.join(profile_dir, 'history.sqlite')
  479. @needs_sqlite
  480. def new_session(self, conn=None):
  481. """Get a new session number."""
  482. if conn is None:
  483. conn = self.db
  484. with conn:
  485. cur = conn.execute("""INSERT INTO sessions VALUES (NULL, ?, NULL,
  486. NULL, "") """, (datetime.datetime.now(),))
  487. self.session_number = cur.lastrowid
  488. def end_session(self):
  489. """Close the database session, filling in the end time and line count."""
  490. self.writeout_cache()
  491. with self.db:
  492. self.db.execute("""UPDATE sessions SET end=?, num_cmds=? WHERE
  493. session==?""", (datetime.datetime.now(),
  494. len(self.input_hist_parsed)-1, self.session_number))
  495. self.session_number = 0
  496. def name_session(self, name):
  497. """Give the current session a name in the history database."""
  498. with self.db:
  499. self.db.execute("UPDATE sessions SET remark=? WHERE session==?",
  500. (name, self.session_number))
  501. def reset(self, new_session=True):
  502. """Clear the session history, releasing all object references, and
  503. optionally open a new session."""
  504. self.output_hist.clear()
  505. # The directory history can't be completely empty
  506. self.dir_hist[:] = [py3compat.getcwd()]
  507. if new_session:
  508. if self.session_number:
  509. self.end_session()
  510. self.input_hist_parsed[:] = [""]
  511. self.input_hist_raw[:] = [""]
  512. self.new_session()
  513. # ------------------------------
  514. # Methods for retrieving history
  515. # ------------------------------
  516. def get_session_info(self, session=0):
  517. """Get info about a session.
  518. Parameters
  519. ----------
  520. session : int
  521. Session number to retrieve. The current session is 0, and negative
  522. numbers count back from current session, so -1 is the previous session.
  523. Returns
  524. -------
  525. session_id : int
  526. Session ID number
  527. start : datetime
  528. Timestamp for the start of the session.
  529. end : datetime
  530. Timestamp for the end of the session, or None if IPython crashed.
  531. num_cmds : int
  532. Number of commands run, or None if IPython crashed.
  533. remark : unicode
  534. A manually set description.
  535. """
  536. if session <= 0:
  537. session += self.session_number
  538. return super(HistoryManager, self).get_session_info(session=session)
  539. def _get_range_session(self, start=1, stop=None, raw=True, output=False):
  540. """Get input and output history from the current session. Called by
  541. get_range, and takes similar parameters."""
  542. input_hist = self.input_hist_raw if raw else self.input_hist_parsed
  543. n = len(input_hist)
  544. if start < 0:
  545. start += n
  546. if not stop or (stop > n):
  547. stop = n
  548. elif stop < 0:
  549. stop += n
  550. for i in range(start, stop):
  551. if output:
  552. line = (input_hist[i], self.output_hist_reprs.get(i))
  553. else:
  554. line = input_hist[i]
  555. yield (0, i, line)
  556. def get_range(self, session=0, start=1, stop=None, raw=True,output=False):
  557. """Retrieve input by session.
  558. Parameters
  559. ----------
  560. session : int
  561. Session number to retrieve. The current session is 0, and negative
  562. numbers count back from current session, so -1 is previous session.
  563. start : int
  564. First line to retrieve.
  565. stop : int
  566. End of line range (excluded from output itself). If None, retrieve
  567. to the end of the session.
  568. raw : bool
  569. If True, return untranslated input
  570. output : bool
  571. If True, attempt to include output. This will be 'real' Python
  572. objects for the current session, or text reprs from previous
  573. sessions if db_log_output was enabled at the time. Where no output
  574. is found, None is used.
  575. Returns
  576. -------
  577. entries
  578. An iterator over the desired lines. Each line is a 3-tuple, either
  579. (session, line, input) if output is False, or
  580. (session, line, (input, output)) if output is True.
  581. """
  582. if session <= 0:
  583. session += self.session_number
  584. if session==self.session_number: # Current session
  585. return self._get_range_session(start, stop, raw, output)
  586. return super(HistoryManager, self).get_range(session, start, stop, raw,
  587. output)
  588. ## ----------------------------
  589. ## Methods for storing history:
  590. ## ----------------------------
  591. def store_inputs(self, line_num, source, source_raw=None):
  592. """Store source and raw input in history and create input cache
  593. variables ``_i*``.
  594. Parameters
  595. ----------
  596. line_num : int
  597. The prompt number of this input.
  598. source : str
  599. Python input.
  600. source_raw : str, optional
  601. If given, this is the raw input without any IPython transformations
  602. applied to it. If not given, ``source`` is used.
  603. """
  604. if source_raw is None:
  605. source_raw = source
  606. source = source.rstrip('\n')
  607. source_raw = source_raw.rstrip('\n')
  608. # do not store exit/quit commands
  609. if self._exit_re.match(source_raw.strip()):
  610. return
  611. self.input_hist_parsed.append(source)
  612. self.input_hist_raw.append(source_raw)
  613. with self.db_input_cache_lock:
  614. self.db_input_cache.append((line_num, source, source_raw))
  615. # Trigger to flush cache and write to DB.
  616. if len(self.db_input_cache) >= self.db_cache_size:
  617. self.save_flag.set()
  618. # update the auto _i variables
  619. self._iii = self._ii
  620. self._ii = self._i
  621. self._i = self._i00
  622. self._i00 = source_raw
  623. # hackish access to user namespace to create _i1,_i2... dynamically
  624. new_i = '_i%s' % line_num
  625. to_main = {'_i': self._i,
  626. '_ii': self._ii,
  627. '_iii': self._iii,
  628. new_i : self._i00 }
  629. if self.shell is not None:
  630. self.shell.push(to_main, interactive=False)
  631. def store_output(self, line_num):
  632. """If database output logging is enabled, this saves all the
  633. outputs from the indicated prompt number to the database. It's
  634. called by run_cell after code has been executed.
  635. Parameters
  636. ----------
  637. line_num : int
  638. The line number from which to save outputs
  639. """
  640. if (not self.db_log_output) or (line_num not in self.output_hist_reprs):
  641. return
  642. output = self.output_hist_reprs[line_num]
  643. with self.db_output_cache_lock:
  644. self.db_output_cache.append((line_num, output))
  645. if self.db_cache_size <= 1:
  646. self.save_flag.set()
  647. def _writeout_input_cache(self, conn):
  648. with conn:
  649. for line in self.db_input_cache:
  650. conn.execute("INSERT INTO history VALUES (?, ?, ?, ?)",
  651. (self.session_number,)+line)
  652. def _writeout_output_cache(self, conn):
  653. with conn:
  654. for line in self.db_output_cache:
  655. conn.execute("INSERT INTO output_history VALUES (?, ?, ?)",
  656. (self.session_number,)+line)
  657. @needs_sqlite
  658. def writeout_cache(self, conn=None):
  659. """Write any entries in the cache to the database."""
  660. if conn is None:
  661. conn = self.db
  662. with self.db_input_cache_lock:
  663. try:
  664. self._writeout_input_cache(conn)
  665. except sqlite3.IntegrityError:
  666. self.new_session(conn)
  667. print("ERROR! Session/line number was not unique in",
  668. "database. History logging moved to new session",
  669. self.session_number)
  670. try:
  671. # Try writing to the new session. If this fails, don't
  672. # recurse
  673. self._writeout_input_cache(conn)
  674. except sqlite3.IntegrityError:
  675. pass
  676. finally:
  677. self.db_input_cache = []
  678. with self.db_output_cache_lock:
  679. try:
  680. self._writeout_output_cache(conn)
  681. except sqlite3.IntegrityError:
  682. print("!! Session/line number for output was not unique",
  683. "in database. Output will not be stored.")
  684. finally:
  685. self.db_output_cache = []
  686. class HistorySavingThread(threading.Thread):
  687. """This thread takes care of writing history to the database, so that
  688. the UI isn't held up while that happens.
  689. It waits for the HistoryManager's save_flag to be set, then writes out
  690. the history cache. The main thread is responsible for setting the flag when
  691. the cache size reaches a defined threshold."""
  692. daemon = True
  693. stop_now = False
  694. enabled = True
  695. def __init__(self, history_manager):
  696. super(HistorySavingThread, self).__init__(name="IPythonHistorySavingThread")
  697. self.history_manager = history_manager
  698. self.enabled = history_manager.enabled
  699. atexit.register(self.stop)
  700. @needs_sqlite
  701. def run(self):
  702. # We need a separate db connection per thread:
  703. try:
  704. self.db = sqlite3.connect(self.history_manager.hist_file,
  705. **self.history_manager.connection_options
  706. )
  707. while True:
  708. self.history_manager.save_flag.wait()
  709. if self.stop_now:
  710. self.db.close()
  711. return
  712. self.history_manager.save_flag.clear()
  713. self.history_manager.writeout_cache(self.db)
  714. except Exception as e:
  715. print(("The history saving thread hit an unexpected error (%s)."
  716. "History will not be written to the database.") % repr(e))
  717. def stop(self):
  718. """This can be called from the main thread to safely stop this thread.
  719. Note that it does not attempt to write out remaining history before
  720. exiting. That should be done by calling the HistoryManager's
  721. end_session method."""
  722. self.stop_now = True
  723. self.history_manager.save_flag.set()
  724. self.join()
  725. # To match, e.g. ~5/8-~2/3
  726. range_re = re.compile(r"""
  727. ((?P<startsess>~?\d+)/)?
  728. (?P<start>\d+)?
  729. ((?P<sep>[\-:])
  730. ((?P<endsess>~?\d+)/)?
  731. (?P<end>\d+))?
  732. $""", re.VERBOSE)
  733. def extract_hist_ranges(ranges_str):
  734. """Turn a string of history ranges into 3-tuples of (session, start, stop).
  735. Examples
  736. --------
  737. >>> list(extract_hist_ranges("~8/5-~7/4 2"))
  738. [(-8, 5, None), (-7, 1, 5), (0, 2, 3)]
  739. """
  740. for range_str in ranges_str.split():
  741. rmatch = range_re.match(range_str)
  742. if not rmatch:
  743. continue
  744. start = rmatch.group("start")
  745. if start:
  746. start = int(start)
  747. end = rmatch.group("end")
  748. # If no end specified, get (a, a + 1)
  749. end = int(end) if end else start + 1
  750. else: # start not specified
  751. if not rmatch.group('startsess'): # no startsess
  752. continue
  753. start = 1
  754. end = None # provide the entire session hist
  755. if rmatch.group("sep") == "-": # 1-3 == 1:4 --> [1, 2, 3]
  756. end += 1
  757. startsess = rmatch.group("startsess") or "0"
  758. endsess = rmatch.group("endsess") or startsess
  759. startsess = int(startsess.replace("~","-"))
  760. endsess = int(endsess.replace("~","-"))
  761. assert endsess >= startsess, "start session must be earlier than end session"
  762. if endsess == startsess:
  763. yield (startsess, start, end)
  764. continue
  765. # Multiple sessions in one range:
  766. yield (startsess, start, None)
  767. for sess in range(startsess+1, endsess):
  768. yield (sess, 1, None)
  769. yield (endsess, 1, end)
  770. def _format_lineno(session, line):
  771. """Helper function to format line numbers properly."""
  772. if session == 0:
  773. return str(line)
  774. return "%s#%s" % (session, line)