7 from WindowList
import ListedToplevel
9 from ScrolledList
import ScrolledList
14 def __init__(self
, root
, flist
, stack
=None):
15 self
.top
= top
= ListedToplevel(root
)
16 top
.protocol("WM_DELETE_WINDOW", self
.close
)
17 top
.bind("<Key-Escape>", self
.close
)
18 top
.wm_title("Stack viewer")
19 top
.wm_iconname("Stack")
21 self
.helplabel
= Label(top
,
22 text
="Click once to view variables; twice for source",
23 borderwidth
=2, relief
="groove")
24 self
.helplabel
.pack(fill
="x")
26 self
.sv
= StackViewer(top
, flist
, self
)
29 self
.sv
.load_stack(stack
)
31 def close(self
, event
=None):
42 def show_frame(self
, (frame
, lineno
)):
43 if frame
is self
.curframe
:
46 if frame
.f_globals
is not self
.globalsdict
:
47 self
.show_globals(frame
)
48 self
.show_locals(frame
)
51 def show_globals(self
, frame
):
52 title
= "Global Variables"
53 if frame
.f_globals
.has_key("__name__"):
55 name
= str(frame
.f_globals
["__name__"]) + ""
59 title
= title
+ " in module " + name
60 self
.globalsdict
= None
61 if self
.globalsviewer
:
62 self
.globalsviewer
.close()
63 self
.globalsviewer
= None
64 if not self
.globalsframe
:
65 self
.globalsframe
= Frame(self
.top
)
66 self
.globalsdict
= frame
.f_globals
67 self
.globalsviewer
= NamespaceViewer(
71 self
.globalsframe
.pack(fill
="both", side
="bottom")
73 def show_locals(self
, frame
):
74 self
.localsdict
= None
76 self
.localsviewer
.close()
77 self
.localsviewer
= None
78 if frame
.f_locals
is not frame
.f_globals
:
79 title
= "Local Variables"
81 funcname
= code
.co_name
82 if funcname
not in ("?", "", None):
83 title
= title
+ " in " + funcname
84 if not self
.localsframe
:
85 self
.localsframe
= Frame(self
.top
)
86 self
.localsdict
= frame
.f_locals
87 self
.localsviewer
= NamespaceViewer(
91 self
.localsframe
.pack(fill
="both", side
="top")
94 self
.localsframe
.forget()
97 class StackViewer(ScrolledList
):
99 def __init__(self
, master
, flist
, browser
):
100 ScrolledList
.__init
__(self
, master
, width
=80)
102 self
.browser
= browser
105 def load_stack(self
, stack
, index
=None):
108 ## if len(stack) > 10:
110 ## self.topframe.pack(expand=1)
112 ## l["height"] = len(stack)
113 ## self.topframe.pack(expand=0)
114 for i
in range(len(stack
)):
115 frame
, lineno
= stack
[i
]
117 modname
= frame
.f_globals
["__name__"]
121 filename
= code
.co_filename
122 funcname
= code
.co_name
123 sourceline
= linecache
.getline(filename
, lineno
)
124 sourceline
= string
.strip(sourceline
)
125 if funcname
in ("?", "", None):
126 item
= "%s, line %d: %s" % (modname
, lineno
, sourceline
)
128 item
= "%s.%s(), line %d: %s" % (modname
, funcname
,
133 if index
is not None:
136 def popup_event(self
, event
):
138 return ScrolledList
.popup_event(self
, event
)
142 menu
.add_command(label
="Go to source line",
143 command
=self
.goto_source_line
)
144 menu
.add_command(label
="Show stack frame",
145 command
=self
.show_stack_frame
)
147 def on_select(self
, index
):
148 if 0 <= index
< len(self
.stack
):
149 self
.browser
.show_frame(self
.stack
[index
])
151 def on_double(self
, index
):
152 self
.show_source(index
)
154 def goto_source_line(self
):
155 index
= self
.listbox
.index("active")
156 self
.show_source(index
)
158 def show_stack_frame(self
):
159 index
= self
.listbox
.index("active")
160 if 0 <= index
< len(self
.stack
):
161 self
.browser
.show_frame(self
.stack
[index
])
163 def show_source(self
, index
):
164 if not (0 <= index
< len(self
.stack
)):
166 frame
, lineno
= self
.stack
[index
]
168 filename
= code
.co_filename
169 if os
.path
.isfile(filename
):
170 edit
= self
.flist
.open(filename
)
172 edit
.gotoline(lineno
)
175 def get_stack(t
=None, f
=None):
177 t
= sys
.last_traceback
179 if t
and t
.tb_frame
is f
:
182 stack
.append((f
, f
.f_lineno
))
183 if f
is self
.botframe
:
188 stack
.append((t
.tb_frame
, t
.tb_lineno
))
193 def getexception(type=None, value
=None):
196 value
= sys
.last_value
197 if hasattr(type, "__name__"):
200 if value
is not None:
201 s
= s
+ ": " + str(value
)
205 class NamespaceViewer
:
207 def __init__(self
, master
, title
, dict=None):
211 height
= 20*len(dict) # XXX 20 == observed height of Entry widget
215 self
.repr.maxstring
= 60
216 self
.repr.maxother
= 60
217 self
.frame
= frame
= Frame(master
)
218 self
.frame
.pack(expand
=1, fill
="both")
219 self
.label
= Label(frame
, text
=title
, borderwidth
=2, relief
="groove")
220 self
.label
.pack(fill
="x")
221 self
.vbar
= vbar
= Scrollbar(frame
, name
="vbar")
222 vbar
.pack(side
="right", fill
="y")
223 self
.canvas
= canvas
= Canvas(frame
,
224 height
=min(300, max(40, height
)),
225 scrollregion
=(0, 0, width
, height
))
226 canvas
.pack(side
="left", fill
="both", expand
=1)
227 vbar
["command"] = canvas
.yview
228 canvas
["yscrollcommand"] = vbar
.set
229 self
.subframe
= subframe
= Frame(canvas
)
230 self
.sfid
= canvas
.create_window(0, 0, window
=subframe
, anchor
="nw")
235 def load_dict(self
, dict, force
=0):
236 if dict is self
.dict and not force
:
238 subframe
= self
.subframe
240 for c
in subframe
.children
.values():
244 l
= Label(subframe
, text
="None")
245 l
.grid(row
=0, column
=0)
252 svalue
= self
.repr.repr(value
) # repr(value)
253 l
= Label(subframe
, text
=name
)
254 l
.grid(row
=row
, column
=0, sticky
="nw")
255 ## l = Label(subframe, text=svalue, justify="l", wraplength=300)
256 l
= Entry(subframe
, width
=0, borderwidth
=0)
258 ## l["state"] = "disabled"
259 l
.grid(row
=row
, column
=1, sticky
="nw")
262 # XXX Could we use a <Configure> callback for the following?
263 subframe
.update_idletasks() # Alas!
264 width
= subframe
.winfo_reqwidth()
265 height
= subframe
.winfo_reqheight()
267 self
.canvas
["scrollregion"] = (0, 0, width
, height
)
269 canvas
["height"] = 300
272 canvas
["height"] = height