From 75fd024c98b4552bf3ce8692f2442aff5c012fc6 2021-11-14 18:51:43 From: Nikita Kniazev Date: 2021-11-14 18:51:43 Subject: [PATCH] Fix `history_manager.search(?, unique=True)` returning old entries --- diff --git a/IPython/core/history.py b/IPython/core/history.py index ff931d2..4324806 100644 --- a/IPython/core/history.py +++ b/IPython/core/history.py @@ -265,7 +265,7 @@ class HistoryAccessor(HistoryAccessorBase): ## ------------------------------- ## Methods for retrieving history: ## ------------------------------- - def _run_sql(self, sql, params, raw=True, output=False): + def _run_sql(self, sql, params, raw=True, output=False, latest=False): """Prepares and runs an SQL query for the history database. Parameters @@ -276,6 +276,8 @@ class HistoryAccessor(HistoryAccessorBase): Parameters passed to the SQL query (to replace "?") raw, output : bool See :meth:`get_range` + latest : bool + Select rows with max (session, line) Returns ------- @@ -286,8 +288,12 @@ class HistoryAccessor(HistoryAccessorBase): if output: sqlfrom = "history LEFT JOIN output_history USING (session, line)" toget = "history.%s, output_history.output" % toget + if latest: + toget += ", MAX(session * 128 * 1024 + line)" cur = self.db.execute("SELECT session, line, %s FROM %s " %\ (toget, sqlfrom) + sql, params) + if latest: + cur = (row[:-1] for row in cur) if output: # Regroup into 3-tuples, and parse JSON return ((ses, lin, (inp, out)) for ses, lin, inp, out in cur) return cur @@ -395,7 +401,7 @@ class HistoryAccessor(HistoryAccessorBase): params += (n,) elif unique: sqlform += " ORDER BY session, line" - cur = self._run_sql(sqlform, params, raw=raw, output=output) + cur = self._run_sql(sqlform, params, raw=raw, output=output, latest=unique) if n is not None: return reversed(list(cur)) return cur @@ -817,7 +823,7 @@ class HistorySavingThread(threading.Thread): try: self.db = sqlite3.connect( str(self.history_manager.hist_file), - **self.history_manager.connection_options + **self.history_manager.connection_options, ) while True: self.history_manager.save_flag.wait() diff --git a/IPython/core/tests/test_history.py b/IPython/core/tests/test_history.py index 4cc43ca..6d6a1b1 100644 --- a/IPython/core/tests/test_history.py +++ b/IPython/core/tests/test_history.py @@ -17,12 +17,10 @@ import sqlite3 from traitlets.config.loader import Config from IPython.utils.tempdir import TemporaryDirectory from IPython.core.history import HistoryManager, extract_hist_ranges -from IPython.testing.decorators import skipif def test_proper_default_encoding(): assert sys.getdefaultencoding() == "utf-8" -@skipif(sqlite3.sqlite_version_info > (3,24,0)) def test_history(): ip = get_ipython() with TemporaryDirectory() as tmpdir: @@ -133,6 +131,17 @@ def test_history(): ip.history_manager.store_inputs(1, "rogue") ip.history_manager.writeout_cache() assert ip.history_manager.session_number == 3 + + # Check that session and line values are not just max values + sessid, lineno, entry = newhist[-1] + assert lineno > 1 + ip.history_manager.reset() + lineno = 1 + ip.history_manager.store_inputs(lineno, entry) + gothist = ip.history_manager.search("*=*", unique=True) + hist = list(gothist)[-1] + assert sessid < hist[0] + assert hist[1:] == (lineno, entry) finally: # Ensure saving thread is shut down before we try to clean up the files ip.history_manager.save_thread.stop()