From 55fcd51539b7efef38c23e2108c315b86dd3ac7e 2011-03-13 12:51:49 From: Thomas Kluyver Date: 2011-03-13 12:51:49 Subject: [PATCH] Simplify magic_history display code, allow get_hist_search to include output in return values, and add some unit tests. --- diff --git a/IPython/core/history.py b/IPython/core/history.py index 5272000..47971dc 100644 --- a/IPython/core/history.py +++ b/IPython/core/history.py @@ -138,7 +138,7 @@ class HistoryManager(Configurable): return ((ses, lin, (inp, out)) for ses, lin, inp, out in hist) return hist - def get_hist_search(self, pattern="*", raw=True): + def get_hist_search(self, pattern="*", raw=True, output=False): """Search the database using unix glob-style matching (wildcards * and ?, escape using \). @@ -147,8 +147,17 @@ class HistoryManager(Configurable): An iterator over tuples: (session, line_number, command) """ toget = "source_raw" if raw else "source" - return self.db.execute("SELECT session, line, " +toget+ \ - " FROM history WHERE " +toget+ " GLOB ?", (pattern,)) + tosearch = toget + sqlfrom = "history" + if output: + sqlfrom = "history LEFT JOIN output_history USING (session, line)" + toget = "history.%s, output_history.output" % toget + tosearch = "history." + tosearch + hist = self.db.execute("SELECT session, line, " +toget+ \ + " FROM "+sqlfrom+" WHERE " +tosearch+ " GLOB ?", (pattern,)) + if output: + return ((ses, lin, (inp, out)) for ses, lin, inp, out in hist) + return hist def _get_hist_session(self, start=1, stop=None, raw=True, output=False): """Get input and output history from the current session. Called by @@ -456,24 +465,11 @@ def magic_history(self, parameter_s = ''): default_length = 40 pattern = None - # Glob search: - if 'g' in opts: + if 'g' in opts: # Glob search pattern = "*" + args + "*" if args else "*" - - # Display: - matches_current_session = [] - for session, line, s in history_manager.get_hist_search(pattern, raw): - if session == history_manager.session_number: - matches_current_session.append((line, s)) - continue - print("%d/%d: %s" %(session, line, s.expandtabs(4)), file=outfile) - if matches_current_session: - print("=== Current session: ===", file=outfile) - for line, s in matches_current_session: - print("%d: %s" %(line, s.expandtabs(4)), file=outfile) - return - - if 'l' in opts: # Get 'tail' + hist = history_manager.get_hist_search(pattern, raw=raw, + output=get_output) + elif 'l' in opts: # Get 'tail' try: n = int(args) except ValueError, IndexError: @@ -484,12 +480,10 @@ def magic_history(self, parameter_s = ''): hist = history_manager.get_hist_from_rangestr(args, raw, get_output) else: # Just get history for the current session hist = history_manager.get_history(raw=raw, output=get_output) - # Pull hist into a list, so we can get the widest number in it. - hist = list(hist) - if not hist: - return - width = max(len(_format_lineno(s, l)) for s, l, _ in hist) + # We could be displaying the entire history, so let's not try to pull it + # into a list in memory. Anything that needs more space will just misalign. + width = 4 for session, lineno, inline in hist: # Print user history with tabs expanded to 4 spaces. The GUI clients @@ -498,12 +492,9 @@ def magic_history(self, parameter_s = ''): if get_output: inline, output = inline inline = inline.expandtabs(4).rstrip() - - if pattern is not None and not fnmatch.fnmatch(inline, pattern): - continue multiline = "\n" in inline - line_sep = '\n' if multiline else '' + line_sep = '\n' if multiline else ' ' if print_nums: print('%s:%s' % (_format_lineno(session, lineno).rjust(width), line_sep), file=outfile, end='') diff --git a/IPython/core/tests/test_history.py b/IPython/core/tests/test_history.py index d471981..c9b8a73 100644 --- a/IPython/core/tests/test_history.py +++ b/IPython/core/tests/test_history.py @@ -35,6 +35,10 @@ def test_history(): for i, h in enumerate(hist, start=1): ip.history_manager.store_inputs(i, h) + ip.history_manager.db_log_output = True + # Doesn't match the input, but we'll just check it's stored. + ip.history_manager.store_output(3, "spam") + nt.assert_equal(ip.history_manager.input_hist_raw, [''] + hist) # Check lines were written to DB @@ -44,7 +48,7 @@ def test_history(): # New session ip.history_manager.reset() newcmds = ["z=5","class X(object):\n pass", "k='p'"] - for i, cmd in enumerate(newcmds): + for i, cmd in enumerate(newcmds, start=1): ip.history_manager.store_inputs(i, cmd) gothist = ip.history_manager.get_history(start=1, stop=4) nt.assert_equal(list(gothist), zip([0,0,0],[1,2,3], newcmds)) @@ -52,6 +56,20 @@ def test_history(): gothist = ip.history_manager.get_history(-1, 1, 4) nt.assert_equal(list(gothist), zip([1,1,1],[1,2,3], hist)) + # Check get_hist_tail + gothist = ip.history_manager.get_hist_tail(4, output=True) + expected = [(1, 3, (hist[-1], "spam")), + (2, 1, (newcmds[0], None)), + (2, 2, (newcmds[1], None)), + (2, 3, (newcmds[2], None)),] + nt.assert_equal(list(gothist), expected) + + # Check get_hist_search + gothist = ip.history_manager.get_hist_search("*test*") + nt.assert_equal(list(gothist), [(1,2,hist[1])] ) + gothist = ip.history_manager.get_hist_search("b*", output=True) + nt.assert_equal(list(gothist), [(1,3,(hist[2],"spam"))] ) + # Cross testing: check that magic %save can get previous session. testfilename = os.path.realpath(os.path.join(tmpdir, "test.py")) ip.magic_save(testfilename + " ~1/1-3")