Permalink
Browse files

Allow history to store multiple outputs for a single input line.

  • Loading branch information...
1 parent 52e9d2a commit 498d9f5596113a9817b9a2fa4a14314c14bb7439 @takluyver committed Mar 14, 2011
Showing with 28 additions and 16 deletions.
  1. +2 −5 IPython/core/displayhook.py
  2. +15 −7 IPython/core/history.py
  3. +7 −1 IPython/core/interactiveshell.py
  4. +4 −3 IPython/core/tests/test_history.py
@@ -275,16 +275,13 @@ def update_user_ns(self, result):
new_result = '_'+`self.prompt_count`
to_main[new_result] = result
self.shell.user_ns.update(to_main)
- self.shell.user_ns['_oh'][self.prompt_count] = result
+ # This is a defaultdict of lists, so we can always append
+ self.shell.user_ns['_oh'][self.prompt_count].append(result)
def log_output(self, format_dict):
"""Log the output."""
if self.shell.logger.log_output:
self.shell.logger.log_write(format_dict['text/plain'], 'output')
- # Write output to the database. Does nothing unless history
- # output logging is enabled.
- self.shell.history_manager.store_output(self.prompt_count,
- format_dict['text/plain'])
def finish_displayhook(self):
"""Finish up all displayhook activities."""
View
@@ -14,10 +14,13 @@
# Stdlib imports
import datetime
+import json
import os
import re
import sqlite3
+from collections import defaultdict
+
# Our own packages
from IPython.config.configurable import Configurable
import IPython.utils.io
@@ -45,7 +48,7 @@ class HistoryManager(Configurable):
# A list of directories visited during session
dir_hist = List()
# A dict of output history, keyed with ints from the shell's execution count
- output_hist = Dict()
+ output_hist = Instance(defaultdict)
# String holding the path to the history file
hist_file = Unicode()
# The SQLite database
@@ -94,6 +97,7 @@ def __init__(self, shell, config=None):
self.new_session()
self._i00, self._i, self._ii, self._iii = '','','',''
+ self.output_hist = defaultdict(list)
self._exit_commands = set(['Quit', 'quit', 'Exit', 'exit', '%Quit',
'%quit', '%Exit', '%exit'])
@@ -179,8 +183,10 @@ def _get_hist_sql(self, sql, params, raw=True, output=False):
toget = "history.%s, output_history.output" % toget
cur = self.db.execute("SELECT session, line, %s FROM %s " %\
(toget, sqlfrom) + sql, params)
- if output: # Regroup into 3-tuples
- return ((ses, lin, (inp, out)) for ses, lin, inp, out in cur)
+ if output: # Regroup into 3-tuples, and parse JSON
+ loads = lambda out: json.loads(out) if out else None
+ return ((ses, lin, (inp, loads(out))) \
+ for ses, lin, inp, out in cur)
return cur
@@ -221,7 +227,8 @@ def _get_hist_session(self, start=1, stop=None, raw=True, output=False):
for i in range(start, stop):
if output:
- line = (input_hist[i], repr(self.output_hist.get(i)))
+ output_item = [repr(x) for x in self.output_hist[i]]
+ line = (input_hist[i], output_item)
else:
line = input_hist[i]
yield (0, i, line)
@@ -324,9 +331,10 @@ def store_inputs(self, line_num, source, source_raw=None):
new_i : self._i00 }
self.shell.user_ns.update(to_main)
- def store_output(self, line_num, output):
- if not self.db_log_output:
+ def store_output(self, line_num):
+ if (not self.db_log_output) or not self.output_hist[line_num]:
return
+ output = json.dumps([repr(x) for x in self.output_hist[line_num]])
db_row = (self.session_number, line_num, output)
if self.db_cache_size > 1:
self.db_output_cache.append(db_row)
@@ -524,7 +532,7 @@ def _format_lineno(session, line):
inline = "\n... ".join(inline.splitlines()) + "\n..."
print(inline, file=outfile)
if get_output and output:
- print(output, file=outfile)
+ print("\n".join(output), file=outfile)
if close_at_end:
outfile.close()
@@ -2119,8 +2119,11 @@ def run_cell(self, cell):
# Single-block input should behave like an interactive prompt
if len(blocks) == 1:
- # since we return here, we need to update the execution count
out = self.run_source(blocks[0])
+ # Write output to the database. Does nothing unless
+ # history output logging is enabled.
+ self.history_manager.store_output(self.execution_count)
+ # since we return here, we need to update the execution count
self.execution_count += 1
return out
@@ -2148,6 +2151,9 @@ def run_cell(self, cell):
# processed input in history
self.run_source(ipy_cell, symbol='exec')
+ # Write output to the database. Does nothing unless
+ # history output logging is enabled.
+ self.history_manager.store_output(self.execution_count)
# Each cell is a *single* input, regardless of how many lines it has
self.execution_count += 1
@@ -38,7 +38,8 @@ def test_history():
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")
+ ip.history_manager.output_hist[3].append("spam")
+ ip.history_manager.store_output(3)
nt.assert_equal(ip.history_manager.input_hist_raw, [''] + hist)
@@ -59,7 +60,7 @@ def test_history():
# Check get_hist_tail
gothist = ip.history_manager.get_hist_tail(4, output=True)
- expected = [(1, 3, (hist[-1], "spam")),
+ expected = [(1, 3, (hist[-1], [repr("spam")])),
(2, 1, (newcmds[0], None)),
(2, 2, (newcmds[1], None)),
(2, 3, (newcmds[2], None)),]
@@ -69,7 +70,7 @@ def test_history():
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"))] )
+ nt.assert_equal(list(gothist), [(1,3,(hist[2],[repr("spam")]))] )
# Cross testing: check that magic %save can get previous session.
testfilename = os.path.realpath(os.path.join(tmpdir, "test.py"))

0 comments on commit 498d9f5

Please sign in to comment.