Skip to content

Commit 9512907

Browse files
committed
greatly simplified the code!
1 parent 993d2c0 commit 9512907

File tree

2 files changed

+46
-99
lines changed

2 files changed

+46
-99
lines changed

v3/js/opt-ipy.js

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -75,11 +75,17 @@ var updater = {
7575
},
7676

7777
showMessage: function(message) {
78+
// empty trace!
79+
if (message.trace.length == 0) {
80+
myVisualizer = null;
81+
$('#vizDiv').empty();
82+
$(document).unbind('keydown');
83+
return;
84+
}
85+
7886
myVisualizer = new ExecutionVisualizer('vizDiv',
7987
message,
80-
{startingInstruction: message.trace.length - 1,
81-
embeddedMode: true,
82-
});
88+
{embeddedMode: true, jumpToEnd: true});
8389

8490
// set keyboard bindings
8591
// VERY IMPORTANT to clear and reset this every time or

v3/opt-ipy.py

Lines changed: 37 additions & 96 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
# Online Python Tutor extension for the IPython shell
22
# http://ipython.org/ipython-doc/stable/config/extensions/index.html
33

4+
# defines a '%clear' magic to clear the user's global environment
5+
46
# Tested on IPython 1.0.dev
57

68
# pgbovine
@@ -35,151 +37,89 @@
3537
# TODO: support incremental pushes to the OPT frontend for efficiency
3638
# and better "snappiness" (although the speed seems fine for now)
3739

38-
# TODO: support line number adjustments for function definitions/calls
39-
# (right now opt-ipy doesn't jump into function calls at all)
40-
41-
# TODO: add an IPython magic to "reset" the trace to start from scratch
42-
# (although the global environment will still not be blank)
43-
4440

4541
class OptHistory(object):
4642
def __init__(self):
4743
self.executed_stmts = []
4844

49-
# first line number of each line in self.executed_stmts
50-
self.first_lineno = []
51-
52-
# each element is a LIST containing an OPT trace
53-
self.output_traces = []
54-
55-
5645
def pop_last(self):
5746
self.executed_stmts.pop()
58-
self.first_lineno.pop()
59-
self.output_traces.pop()
60-
6147

6248
def check_rep(self):
63-
assert len(self.executed_stmts) == len(self.first_lineno) == len(self.output_traces)
64-
49+
pass
6550

6651
def get_code(self):
6752
return '\n'.join(self.executed_stmts)
6853

69-
def get_full_trace(self):
70-
ret = []
71-
for t in self.output_traces:
72-
for e in t:
73-
ret.append(e)
74-
return ret
75-
54+
def run_str(self, stmt_str):
55+
self.executed_stmts.append(stmt_str)
7656

77-
def run_str(self, stmt_str, user_globals):
78-
opt_trace = pg_logger.exec_str_with_user_ns(stmt_str, user_globals, lambda cod, trace: trace)
57+
opt_trace = pg_logger.exec_script_str_local(self.get_code(), [], False, False, lambda cod, trace: trace)
7958

80-
# did it end in disaster?
8159
last_evt = opt_trace[-1]['event']
8260
if last_evt == 'exception':
83-
last_exec_is_exception = True
61+
epic_fail = True
8462
else:
8563
assert last_evt == 'return'
86-
last_exec_is_exception = False
87-
88-
89-
end_of_last_trace = None
90-
91-
# 'clean up' the trace a bit:
92-
if len(self.output_traces):
93-
# for aesthetics, lop off the last element of the previous
94-
# entry since it should match the first element of opt_trace
95-
end_of_last_trace = self.output_traces[-1].pop()
96-
#print 'END:', end_of_last_trace
97-
#print 'CUR:', opt_trace[0]
98-
last_ordered_globals = list(end_of_last_trace['ordered_globals']) # copy just to be paranoid
99-
100-
# patch up ordered_globals with last_ordered_globals to
101-
# maintain continuity, i.e., prevent variable display from "jumping"
102-
for t in opt_trace:
103-
og = t['ordered_globals']
104-
og_set = set(og)
105-
106-
# reorder og to use last_ordered_globals as a prefix to
107-
# maintain order
108-
new_og = [e for e in last_ordered_globals if e in og_set]
109-
new_og_set = set(new_og)
110-
111-
# patch in leftovers
112-
leftovers = [e for e in og if e not in new_og_set]
113-
new_og.extend(leftovers)
114-
115-
assert len(og) == len(new_og)
116-
t['ordered_globals'] = new_og
117-
118-
# patch up stdout to make it cumulative too
119-
last_stdout = end_of_last_trace['stdout']
120-
for t in opt_trace:
121-
t['stdout'] = last_stdout + t['stdout']
122-
123-
124-
# adjust all the line numbers in the trace
125-
if len(self.executed_stmts):
126-
lineno = self.first_lineno[-1] + len(self.executed_stmts[-1].splitlines())
127-
else:
128-
lineno = 1
129-
for elt in opt_trace:
130-
elt['line'] += (lineno - 1)
64+
epic_fail = False
13165

132-
self.executed_stmts.append(stmt_str)
133-
self.first_lineno.append(lineno)
134-
self.output_traces.append(opt_trace)
135-
136-
# now create json_output:
137-
output_dict = dict(code=self.get_code(), trace=self.get_full_trace())
66+
output_dict = dict(code=self.get_code(), trace=opt_trace)
13867
json_output = json.dumps(output_dict, indent=INDENT_LEVEL)
13968

140-
14169
# if this statement ended in an exception, delete it from the
14270
# history and pretend it never happened
143-
if last_exec_is_exception:
71+
if epic_fail:
14472
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-
14973

15074
self.check_rep()
15175
return json_output
15276

15377

154-
15578
# called right before a statement gets executed
15679
def opt_pre_run_code_hook(self):
157-
filtered_ns = {}
158-
for k, v in self.user_ns.iteritems():
159-
if k[0] == '_':
160-
continue
161-
if k in ('In', 'Out', 'help', 'quit', 'exit', 'get_ipython'):
162-
continue
163-
filtered_ns[k] = v
164-
16580
# when you run multiple statements on one line using a semicolon:
16681
# e.g., "print x; print y", this function will fire multiple times.
16782
# we want to avoid duplicates!
16883
last_cmd = self.history_manager.input_hist_parsed[-1]
16984
last_cmd_index = len(self.history_manager.input_hist_parsed) - 1
17085

86+
# also don't intercept special ipython commands
87+
if 'get_ipython().' in last_cmd:
88+
return
89+
17190
if self.meta.last_cmd_index == last_cmd_index:
17291
assert self.meta.last_cmd == last_cmd
17392
return # punt!!!
17493

17594
self.meta.last_cmd = last_cmd
17695
self.meta.last_cmd_index = last_cmd_index
17796

178-
trace_json = self.meta.opt_history.run_str(last_cmd, filtered_ns)
97+
trace_json = self.meta.opt_history.run_str(last_cmd)
17998
#print trace_json
18099
urllib2.urlopen("http://localhost:8888/post", trace_json)
181100

182101

102+
# clear global namespace and reset history
103+
def opt_clear(self, params):
104+
ip = get_ipython()
105+
106+
filtered_user_ns = set()
107+
for k, v in ip.user_ns.iteritems():
108+
if k[0] == '_':
109+
continue
110+
if k in ('In', 'Out', 'help', 'quit', 'exit', 'get_ipython'):
111+
continue
112+
filtered_user_ns.add(k)
113+
114+
for k in filtered_user_ns:
115+
del ip.user_ns[k]
116+
117+
ip.meta.opt_history = OptHistory() # just create a new one!
118+
119+
empty_msg = dict(code='', trace=[])
120+
urllib2.urlopen("http://localhost:8888/post", json.dumps(empty_msg))
121+
122+
183123
def load_ipython_extension(ipython):
184124
# The `ipython` argument is the currently active `InteractiveShell`
185125
# instance, which can be used in any way. This allows you to register
@@ -192,6 +132,7 @@ def load_ipython_extension(ipython):
192132

193133
# NB: spelling might be different in older IPython versions
194134
ipython.set_hook('pre_run_code_hook', opt_pre_run_code_hook)
135+
ipython.define_magic('clear', opt_clear)
195136

196137

197138
def unload_ipython_extension(ipython):

0 commit comments

Comments
 (0)