4141# TODO: add an IPython magic to "reset" the trace to start from scratch
4242# (although the global environment will still not be blank)
4343
44- # TODO: weird shit happens if you write multiple statement on one line
45- # separated by a semicolon. don't do that!
46-
4744
4845class OptHistory (object ):
4946 def __init__ (self ):
@@ -55,9 +52,6 @@ def __init__(self):
5552 # each element is a LIST containing an OPT trace
5653 self .output_traces = []
5754
58- # was the last executed stmt an exception?
59- self .last_exec_is_exception = False
60-
6155
6256 def pop_last (self ):
6357 self .executed_stmts .pop ()
@@ -81,13 +75,23 @@ def get_full_trace(self):
8175
8276
8377 def run_str (self , stmt_str , user_globals ):
84- # now run this string ...
8578 opt_trace = pg_logger .exec_str_with_user_ns (stmt_str , user_globals , lambda cod , trace : trace )
8679
80+ # did it end in disaster?
81+ last_evt = opt_trace [- 1 ]['event' ]
82+ if last_evt == 'exception' :
83+ last_exec_is_exception = True
84+ else :
85+ assert last_evt == 'return'
86+ last_exec_is_exception = False
87+
88+
89+ end_of_last_trace = None
90+
8791 # 'clean up' the trace a bit:
8892 if len (self .output_traces ):
89- # lop off the last element of the previous entry since it should match
90- # the first element of opt_trace
93+ # for aesthetics, lop off the last element of the previous
94+ # entry since it should match the first element of opt_trace
9195 end_of_last_trace = self .output_traces [- 1 ].pop ()
9296 #print 'END:', end_of_last_trace
9397 #print 'CUR:', opt_trace[0]
@@ -117,36 +121,32 @@ def run_str(self, stmt_str, user_globals):
117121 t ['stdout' ] = last_stdout + t ['stdout' ]
118122
119123
120- # destroy the last entry if it was an error
121- # TODO: be careful about where to position this statement
122- if self .last_exec_is_exception :
123- self .pop_last ()
124-
125-
126- # did executing stmt_str end in disaster?
127- last_evt = opt_trace [- 1 ]['event' ]
128- if last_evt == 'exception' :
129- self .last_exec_is_exception = True
130- else :
131- assert last_evt == 'return'
132- self .last_exec_is_exception = False
133-
124+ # adjust all the line numbers in the trace
134125 if len (self .executed_stmts ):
135126 lineno = self .first_lineno [- 1 ] + len (self .executed_stmts [- 1 ].splitlines ())
136127 else :
137128 lineno = 1
138-
139- # adjust all the line numbers in the trace
140129 for elt in opt_trace :
141130 elt ['line' ] += (lineno - 1 )
142131
143132 self .executed_stmts .append (stmt_str )
144133 self .first_lineno .append (lineno )
145134 self .output_traces .append (opt_trace )
146135
136+ # now create json_output:
147137 output_dict = dict (code = self .get_code (), trace = self .get_full_trace ())
148138 json_output = json .dumps (output_dict , indent = INDENT_LEVEL )
149139
140+
141+ # if this statement ended in an exception, delete it from the
142+ # history and pretend it never happened
143+ if last_exec_is_exception :
144+ self .pop_last ()
145+ # SUPER-HACK! patch end_of_last_trace back on
146+ if end_of_last_trace :
147+ self .output_traces [- 1 ].append (end_of_last_trace )
148+
149+
150150 self .check_rep ()
151151 return json_output
152152
@@ -162,7 +162,19 @@ def opt_pre_run_code_hook(self):
162162 continue
163163 filtered_ns [k ] = v
164164
165+ # when you run multiple statements on one line using a semicolon:
166+ # e.g., "print x; print y", this function will fire multiple times.
167+ # we want to avoid duplicates!
165168 last_cmd = self .history_manager .input_hist_parsed [- 1 ]
169+ last_cmd_index = len (self .history_manager .input_hist_parsed ) - 1
170+
171+ if self .meta .last_cmd_index == last_cmd_index :
172+ assert self .meta .last_cmd == last_cmd
173+ return # punt!!!
174+
175+ self .meta .last_cmd = last_cmd
176+ self .meta .last_cmd_index = last_cmd_index
177+
166178 trace_json = self .meta .opt_history .run_str (last_cmd , filtered_ns )
167179 #print trace_json
168180 urllib2 .urlopen ("http://localhost:8888/post" , trace_json )
@@ -175,6 +187,9 @@ def load_ipython_extension(ipython):
175187
176188 ipython .meta .opt_history = OptHistory ()
177189
190+ ipython .meta .last_cmd = None
191+ ipython .meta .last_cmd_index = - 1 # set to an impossible initial value
192+
178193 # NB: spelling might be different in older IPython versions
179194 ipython .set_hook ('pre_run_code_hook' , opt_pre_run_code_hook )
180195
0 commit comments