##// END OF EJS Templates
Merge branch 'single-output' into takluyver-single-output
Thomas Kluyver -
r3751:bb384816 merge
parent child Browse files
Show More
@@ -282,9 +282,8 b' class DisplayHook(Configurable):'
282 """Log the output."""
282 """Log the output."""
283 if self.shell.logger.log_output:
283 if self.shell.logger.log_output:
284 self.shell.logger.log_write(format_dict['text/plain'], 'output')
284 self.shell.logger.log_write(format_dict['text/plain'], 'output')
285 # This is a defaultdict of lists, so we can always append
285 self.shell.history_manager.output_hist_reprs[self.prompt_count] = \
286 self.shell.history_manager.output_hist_reprs[self.prompt_count]\
286 format_dict['text/plain']
287 .append(format_dict['text/plain'])
288
287
289 def finish_displayhook(self):
288 def finish_displayhook(self):
290 """Finish up all displayhook activities."""
289 """Finish up all displayhook activities."""
@@ -15,14 +15,11 b' from __future__ import print_function'
15 # Stdlib imports
15 # Stdlib imports
16 import atexit
16 import atexit
17 import datetime
17 import datetime
18 import json
19 import os
18 import os
20 import re
19 import re
21 import sqlite3
20 import sqlite3
22 import threading
21 import threading
23
22
24 from collections import defaultdict
25
26 # Our own packages
23 # Our own packages
27 from IPython.config.configurable import Configurable
24 from IPython.config.configurable import Configurable
28 import IPython.utils.io
25 import IPython.utils.io
@@ -56,11 +53,10 b' class HistoryManager(Configurable):'
56 return []
53 return []
57
54
58 # A dict of output history, keyed with ints from the shell's
55 # A dict of output history, keyed with ints from the shell's
59 # execution count. If there are several outputs from one command,
56 # execution count.
60 # only the last one is stored.
61 output_hist = Dict()
57 output_hist = Dict()
62 # Contains all outputs, in lists of reprs.
58 # The text/plain repr of outputs.
63 output_hist_reprs = Instance(defaultdict, args=(list,))
59 output_hist_reprs = Dict()
64
60
65 # String holding the path to the history file
61 # String holding the path to the history file
66 hist_file = Unicode(config=True)
62 hist_file = Unicode(config=True)
@@ -92,11 +88,10 b' class HistoryManager(Configurable):'
92 _ii = Unicode(u'')
88 _ii = Unicode(u'')
93 _iii = Unicode(u'')
89 _iii = Unicode(u'')
94
90
95 # A set with all forms of the exit command, so that we don't store them in
91 # A regex matching all forms of the exit command, so that we don't store
96 # the history (it's annoying to rewind the first entry and land on an exit
92 # them in the history (it's annoying to rewind the first entry and land on
97 # call).
93 # an exit call).
98 _exit_commands = Instance(set, args=(['Quit', 'quit', 'Exit', 'exit',
94 _exit_re = re.compile(r"(exit|quit)(\s*\(.*\))?$")
99 '%Quit', '%quit', '%Exit', '%exit'],))
100
95
101 def __init__(self, shell, config=None, **traits):
96 def __init__(self, shell, config=None, **traits):
102 """Create a new history manager associated with a shell instance.
97 """Create a new history manager associated with a shell instance.
@@ -218,9 +213,7 b' class HistoryManager(Configurable):'
218 cur = self.db.execute("SELECT session, line, %s FROM %s " %\
213 cur = self.db.execute("SELECT session, line, %s FROM %s " %\
219 (toget, sqlfrom) + sql, params)
214 (toget, sqlfrom) + sql, params)
220 if output: # Regroup into 3-tuples, and parse JSON
215 if output: # Regroup into 3-tuples, and parse JSON
221 loads = lambda out: json.loads(out) if out else None
216 return ((ses, lin, (inp, out)) for ses, lin, inp, out in cur)
222 return ((ses, lin, (inp, loads(out))) \
223 for ses, lin, inp, out in cur)
224 return cur
217 return cur
225
218
226
219
@@ -383,7 +376,7 b' class HistoryManager(Configurable):'
383 source_raw = source_raw.rstrip('\n')
376 source_raw = source_raw.rstrip('\n')
384
377
385 # do not store exit/quit commands
378 # do not store exit/quit commands
386 if source_raw.strip() in self._exit_commands:
379 if self._exit_re.match(source_raw.strip()):
387 return
380 return
388
381
389 self.input_hist_parsed.append(source)
382 self.input_hist_parsed.append(source)
@@ -419,9 +412,9 b' class HistoryManager(Configurable):'
419 line_num : int
412 line_num : int
420 The line number from which to save outputs
413 The line number from which to save outputs
421 """
414 """
422 if (not self.db_log_output) or not self.output_hist_reprs[line_num]:
415 if (not self.db_log_output) or (line_num not in self.output_hist_reprs):
423 return
416 return
424 output = json.dumps(self.output_hist_reprs[line_num])
417 output = self.output_hist_reprs[line_num]
425
418
426 with self.db_output_cache_lock:
419 with self.db_output_cache_lock:
427 self.db_output_cache.append((line_num, output))
420 self.db_output_cache.append((line_num, output))
@@ -696,7 +689,7 b" def magic_history(self, parameter_s = ''):"
696 inline = "\n... ".join(inline.splitlines()) + "\n..."
689 inline = "\n... ".join(inline.splitlines()) + "\n..."
697 print(inline, file=outfile)
690 print(inline, file=outfile)
698 if get_output and output:
691 if get_output and output:
699 print("\n".join(output), file=outfile)
692 print(output, file=outfile)
700
693
701 if close_at_end:
694 if close_at_end:
702 outfile.close()
695 outfile.close()
@@ -2150,12 +2150,9 b' class InteractiveShell(Configurable, Magic):'
2150 self.showsyntaxerror()
2150 self.showsyntaxerror()
2151 self.execution_count += 1
2151 self.execution_count += 1
2152 return None
2152 return None
2153
2154 interactivity = 'last' # Last node to be run interactive
2155 if len(cell.splitlines()) == 1:
2156 interactivity = 'all' # Single line; run fully interactive
2157
2153
2158 self.run_ast_nodes(code_ast.body, cell_name, interactivity)
2154 self.run_ast_nodes(code_ast.body, cell_name,
2155 interactivity="last_expr")
2159
2156
2160 # Execute any registered post-execution functions.
2157 # Execute any registered post-execution functions.
2161 for func, status in self._post_execute.iteritems():
2158 for func, status in self._post_execute.iteritems():
@@ -2175,7 +2172,7 b' class InteractiveShell(Configurable, Magic):'
2175 # Each cell is a *single* input, regardless of how many lines it has
2172 # Each cell is a *single* input, regardless of how many lines it has
2176 self.execution_count += 1
2173 self.execution_count += 1
2177
2174
2178 def run_ast_nodes(self, nodelist, cell_name, interactivity='last'):
2175 def run_ast_nodes(self, nodelist, cell_name, interactivity='last_expr'):
2179 """Run a sequence of AST nodes. The execution mode depends on the
2176 """Run a sequence of AST nodes. The execution mode depends on the
2180 interactivity parameter.
2177 interactivity parameter.
2181
2178
@@ -2187,13 +2184,21 b' class InteractiveShell(Configurable, Magic):'
2187 Will be passed to the compiler as the filename of the cell. Typically
2184 Will be passed to the compiler as the filename of the cell. Typically
2188 the value returned by ip.compile.cache(cell).
2185 the value returned by ip.compile.cache(cell).
2189 interactivity : str
2186 interactivity : str
2190 'all', 'last' or 'none', specifying which nodes should be run
2187 'all', 'last', 'last_expr' or 'none', specifying which nodes should be
2191 interactively (displaying output from expressions). Other values for
2188 run interactively (displaying output from expressions). 'last_expr'
2192 this parameter will raise a ValueError.
2189 will run the last node interactively only if it is an expression (i.e.
2190 expressions in loops or other blocks are not displayed. Other values
2191 for this parameter will raise a ValueError.
2193 """
2192 """
2194 if not nodelist:
2193 if not nodelist:
2195 return
2194 return
2196
2195
2196 if interactivity == 'last_expr':
2197 if isinstance(nodelist[-1], ast.Expr):
2198 interactivity = "last"
2199 else:
2200 interactivity = "none"
2201
2197 if interactivity == 'none':
2202 if interactivity == 'none':
2198 to_run_exec, to_run_interactive = nodelist, []
2203 to_run_exec, to_run_interactive = nodelist, []
2199 elif interactivity == 'last':
2204 elif interactivity == 'last':
@@ -33,7 +33,7 b' def test_history():'
33
33
34 ip.history_manager.db_log_output = True
34 ip.history_manager.db_log_output = True
35 # Doesn't match the input, but we'll just check it's stored.
35 # Doesn't match the input, but we'll just check it's stored.
36 ip.history_manager.output_hist_reprs[3].append("spam")
36 ip.history_manager.output_hist_reprs[3] = "spam"
37 ip.history_manager.store_output(3)
37 ip.history_manager.store_output(3)
38
38
39 nt.assert_equal(ip.history_manager.input_hist_raw, [''] + hist)
39 nt.assert_equal(ip.history_manager.input_hist_raw, [''] + hist)
@@ -53,7 +53,7 b' def test_history():'
53 # Check get_hist_tail
53 # Check get_hist_tail
54 gothist = ip.history_manager.get_tail(4, output=True,
54 gothist = ip.history_manager.get_tail(4, output=True,
55 include_latest=True)
55 include_latest=True)
56 expected = [(1, 3, (hist[-1], ["spam"])),
56 expected = [(1, 3, (hist[-1], "spam")),
57 (2, 1, (newcmds[0], None)),
57 (2, 1, (newcmds[0], None)),
58 (2, 2, (newcmds[1], None)),
58 (2, 2, (newcmds[1], None)),
59 (2, 3, (newcmds[2], None)),]
59 (2, 3, (newcmds[2], None)),]
@@ -68,7 +68,7 b' def test_history():'
68 gothist = ip.history_manager.search("*test*")
68 gothist = ip.history_manager.search("*test*")
69 nt.assert_equal(list(gothist), [(1,2,hist[1])] )
69 nt.assert_equal(list(gothist), [(1,2,hist[1])] )
70 gothist = ip.history_manager.search("b*", output=True)
70 gothist = ip.history_manager.search("b*", output=True)
71 nt.assert_equal(list(gothist), [(1,3,(hist[2],["spam"]))] )
71 nt.assert_equal(list(gothist), [(1,3,(hist[2],"spam"))] )
72
72
73 # Cross testing: check that magic %save can get previous session.
73 # Cross testing: check that magic %save can get previous session.
74 testfilename = os.path.realpath(os.path.join(tmpdir, "test.py"))
74 testfilename = os.path.realpath(os.path.join(tmpdir, "test.py"))
General Comments 0
You need to be logged in to leave comments. Login now