Hi Ian, all, If you run the attached script with 'python pudb.py pudb.py' and hit 'h', you'll see a help screen that's supposed to be scrollable. For me, it scrolls just a little bit, but doesn't show all the text it's supposed to show.
Looks like a ListBox bug... Andreas PS: I'm attaching a bunch of fixes I've made against the hg version. This includes the prior patch.
#! /usr/bin/env python
# -*- coding: utf-8 -*-
import urwid.raw_display
import urwid
import bdb
# TODO: Breakpoint setting and deleting
# TODO: Breakpoint listing
# TODO: File open
# TODO: Stack display
# TODO: Stack browsing
# TODO: Show stuff when exception happens
# TODO: Postmortem
# TODO: set_trace
# TODO: help dialog working
HELP_TEXT = """\
Welcome to PuDB, the Python Urwid debugger.
-------------------------------------------
Keys:
n - next
s - step
c - continue
f - finish
v - view output
b - breakpoint
j/k - up/down
g/G - start/end
License:
--------
PuDB is licensed to you under the MIT/X Consortium license:
Copyright (c) 2008 Andreas Klöckner
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use,
copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following
conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.
"""
# debugger interface ----------------------------------------------------------
class Debugger(bdb.Bdb):
def __init__(self):
bdb.Bdb.__init__(self)
self.ui = DebuggerUI(self)
self.mainpyfile = ''
self._wait_for_mainpyfile = False
def reset(self):
bdb.Bdb.reset(self)
self.forget()
def forget(self):
self.curframe = None
def interaction(self, frame, traceback):
self.stack, self.curindex = self.get_stack(frame, traceback)
self.curframe = self.stack[self.curindex][0]
self.ui.set_current_line(
self.curframe.f_code.co_filename,
self.curframe.f_lineno)
self.ui.set_locals(self.curframe.f_locals)
self.ui.call_with_ui(self.ui.event_loop)
def user_call(self, frame, argument_list):
"""This method is called when there is the remote possibility
that we ever need to stop in this function."""
if self._wait_for_mainpyfile:
return
if self.stop_here(frame):
#print '--Call--'
self.interaction(frame, None)
def user_line(self, frame):
"""This function is called when we stop or break at this line."""
if self._wait_for_mainpyfile:
if (self.mainpyfile != self.canonic(frame.f_code.co_filename)
or frame.f_lineno<= 0):
return
self._wait_for_mainpyfile = False
self.interaction(frame, None)
def user_return(self, frame, return_value):
"""This function is called when a return trap is set here."""
frame.f_locals['__return__'] = return_value
#print '--Return--'
self.interaction(frame, None)
def user_exception(self, frame, (exc_type, exc_value, exc_traceback)):
"""This function is called if an exception occurs,
but only if we are to stop at or just below this level."""
frame.f_locals['__exception__'] = exc_type, exc_value
if type(exc_type) == type(''):
exc_type_name = exc_type
else:
exc_type_name = exc_type.__name__
#print exc_type_name + ':', _saferepr(exc_value)
self.interaction(frame, exc_traceback)
def _runscript(self, filename):
# Start with fresh empty copy of globals and locals and tell the script
# that it's being run as __main__ to avoid scripts being able to access
# the debugger's namespace.
globals_ = {"__name__" : "__main__"}
locals_ = globals_
# When bdb sets tracing, a number of call and line events happens
# BEFORE debugger even reaches user's code (and the exact sequence of
# events depends on python version). So we take special measures to
# avoid stopping before we reach the main script (see user_line and
# user_call for details).
self._wait_for_mainpyfile = 1
self.mainpyfile = self.canonic(filename)
statement = 'execfile( "%s")' % filename
self.run(statement, globals=globals_, locals=locals_)
# UI stuff --------------------------------------------------------------------
class SelectableText(urwid.Text):
def selectable(self):
return True
def keypress(self, size, key):
return key
class SignalWrap(urwid.WidgetWrap):
def __init__(self, w):
urwid.WidgetWrap.__init__(self, w)
self.event_listeners = []
def listen(self, mask, handler):
self.event_listeners.append((mask, handler))
def keypress(self, size, key):
for mask, handler in self.event_listeners:
if mask is None or mask == key:
return handler(self, size, key)
return self._w.keypress(size, key)
class SourceLine(urwid.FlowWidget):
def __init__(self, text):
self.text = text
self.has_breakpoint = False
self.is_current = False
def selectable(self):
return True
def set_current(self, is_current):
self.is_current = is_current
self._invalidate()
def set_breakpoint(self, has_breakpoint):
self.has_breakpoint = has_breakpoint
self._invalidate()
def rows(self, (maxcol,), focus=False):
return 1
def render(self, (maxcol,), focus=False):
attrs = []
if self.is_current:
crnt = ">"
attrs.append("current")
else:
crnt = " "
if self.has_breakpoint:
bp = "*"
attrs.append("breakpoint")
else:
bp = " "
line = crnt+bp+self.text
if focus:
attrs.append("focused")
return urwid.TextCanvas(
[line],
attr=[[(" ".join(attrs+["source"]), maxcol)]],
maxcol=maxcol)
def keypress(self, size, key):
return key
class DebuggerUI(object):
def __init__(self, dbg):
self.debugger = dbg
Attr = urwid.AttrWrap
self.source = urwid.SimpleListWalker([])
self.source_list = urwid.ListBox(self.source)
self.locals = urwid.SimpleListWalker([])
self.var_list = urwid.ListBox(self.locals)
self.stack_walker = urwid.SimpleListWalker(
[Attr(SelectableText(fname),
None, "focused frame")
for fname in []])
self.stack_list = urwid.ListBox(self.stack_walker)
self.bp_walker = urwid.SimpleListWalker(
[Attr(SelectableText(fname),
None, "focused breakpoint")
for fname in []])
self.bp_list = urwid.ListBox(self.bp_walker)
rhs_col = urwid.Pile([
Attr(urwid.Pile([
("flow", urwid.Text("Locals:")),
Attr(self.var_list, "variables"),
]), None, "focused sidebar"),
Attr(urwid.Pile([
("flow", urwid.Text("Stack:")),
Attr(self.stack_list, "stack"),
]), None, "focused sidebar"),
Attr(urwid.Pile([
("flow", urwid.Text("Breakpoints:")),
Attr(self.bp_list, "breakpoints"),
]), None, "focused sidebar"),
])
columns = urwid.AttrWrap(
urwid.Columns(
[
("weight", 3,
urwid.AttrWrap(self.source_list, "source")),
("weight", 1, rhs_col),
],
dividechars=1),
"background")
instruct = urwid.Text(u"PuDB - The Python Urwid debugger - F1 for help"
u" - © Andreas Klöckner 2008")
header = urwid.AttrWrap(instruct, "header")
self.top = SignalWrap(urwid.Frame(columns, header))
# listeners -----------------------------------------------------------
def end():
self.quit_event_loop = True
def next(w, size, key):
self.debugger.set_next(self.debugger.curframe)
end()
def step(w, size, key):
self.debugger.set_step()
end()
def view(w, size, key):
self.screen.stop()
raw_input("Hit Enter to return:")
self.screen.start()
def finish(w, size, key):
self.debugger.set_return(self.debugger.curframe)
end()
def cont(w, size, key):
self.debugger.set_continue()
end()
def move_home(w, size, key):
self.source.set_focus(0)
def move_end(w, size, key):
self.source.set_focus(len(self.source))
def move_down(w, size, key):
w.keypress(size, "down")
def move_up(w, size, key):
w.keypress(size, "up")
def breakpoint(w, size, key):
if self.shown_file:
sline, pos = self.source.get_focus()
err = self.debugger.set_break(self.shown_file, pos+1,
temporary=False, cond=None, funcname=None)
sline.set_breakpoint(True)
self.update_breakpoints()
else:
raise RuntimeError, "no valid current file"
def quit(w, size, key):
self.debugger.set_quit()
end()
def help(w, size, key):
l = urwid.ListBox([urwid.Text(HELP_TEXT)])
ok = Attr(urwid.Button("OK", lambda btn: end()), "button")
w = urwid.Columns([
l,
("fixed", 10, urwid.ListBox([ok])),
])
#w = urwid.Padding(w, ('fixed left', 1), ('fixed right', 0))
w = urwid.LineBox(w)
w = urwid.Overlay(w, self.top,
align="center",
valign="middle",
width=('relative', 50),
height=('relative', 50),
)
w = Attr(w, "background")
self.event_loop(w)
self.top.listen("n", next)
self.top.listen("s", step)
self.top.listen("v", view)
self.top.listen("f", finish)
self.top.listen("c", cont)
self.top.listen("j", move_down)
self.top.listen("k", move_up)
self.top.listen("home", move_home)
self.top.listen("end", move_end)
self.top.listen("g", move_home)
self.top.listen("G", move_end)
self.top.listen("b", breakpoint)
self.top.listen("q", quit)
self.top.listen("h", help)
self.top.listen("f1", help)
# setup ---------------------------------------------------------------
self.screen = urwid.raw_display.Screen()
self.setup_palette(self.screen)
self.show_count = 0
self.shown_file = None
self.current_line = None
self.quit_event_loop = False
@staticmethod
def setup_palette(screen):
screen.register_palette([
("header", "black", "dark cyan", "standout"),
("source", "yellow", "dark blue", "standout"),
("focused source", "black", "dark green"),
("current source", "black", "dark cyan"),
("current focused source", "white", "dark cyan"),
("breakpoint source", "yellow", "dark red", "standout"),
("breakpoint focused source", "black", "dark red"),
("current breakpoint source", "black", "dark red"),
("current breakpoint focused source", "white", "dark red"),
("variables", "black", "dark cyan", "standout"),
("focused variable", "black", "dark green", "standout"),
("stack", "black", "dark cyan", "standout"),
("focused frame", "black", "dark green", "standout"),
("breakpoints", "black", "dark cyan", "standout"),
("focused breakpoints", "black", "dark green", "standout"),
("button", "white", "dark blue", "standout"),
("background", "black", "light gray", "standout"),
("focused sidebar", "yellow", "light gray", "standout"),
])
# UI enter/exit -----------------------------------------------------------
def show(self):
if self.show_count == 0:
self.screen.start()
self.show_count += 1
def hide(self):
self.show_count -= 1
if self.show_count == 0:
self.screen.stop()
def call_with_ui(self, f, *args, **kwargs):
self.show()
try:
f(*args, **kwargs)
finally:
self.hide()
# interaction -------------------------------------------------------------
def event_loop(self, toplevel=None):
prev_quit_loop = self.quit_event_loop
try:
if toplevel is None:
toplevel = self.top
self.size = self.screen.get_cols_rows()
self.quit_event_loop = False
while not self.quit_event_loop:
canvas = toplevel.render(self.size, focus=True)
self.screen.draw_screen(self.size, canvas)
keys = self.screen.get_input()
for k in keys:
if k == "window resize":
self.size = self.screen.get_cols_rows()
else:
toplevel.keypress(self.size, k)
finally:
self.quit_event_loop = prev_quit_loop
# debugger-facing interface -----------------------------------------------
def set_current_file(self, fname):
if self.shown_file != fname:
try:
inf = open(fname)
except IOError:
self.source[:] = [SourceLine(fname)]
else:
self.source[:] = [
SourceLine(line.rstrip("\n"))
for line in inf.readlines()]
self.shown_file = fname
self.current_line = None
def set_current_line(self, fname, line):
self.set_current_file(fname)
line = line-1
if self.current_line is not None:
self.current_line.set_current(False)
if line >= 0 and line < len(self.source):
self.current_line = self.source[line]
self.current_line.set_current(True)
self.source.set_focus(line)
#self.source_list.shi('middle')
def set_locals(self, locals):
vars = locals.keys()
vars.sort()
self.locals[:] = [
urwid.AttrWrap(
SelectableText("%s: %s" % (var, locals[var])),
None, "focused variable")
for var in vars
if not var.startswith("_")]
def update_breakpoints(self):
# FIXME
pass
def main():
import sys
if not sys.argv[1:]:
print "usage: %s scriptfile [arg] ..." % sys.argv[0]
sys.exit(2)
mainpyfile = sys.argv[1]
from os.path import exists, dirname
if not exists(mainpyfile):
print 'Error:', mainpyfile, 'does not exist'
sys.exit(1)
# Hide "pdb.py" from argument list
del sys.argv[0]
# Replace pdb's dir with script's dir in front of module search path.
sys.path[0] = dirname(mainpyfile)
# Note on saving/restoring sys.argv: it's a good idea when sys.argv was
# modified by the script being debugged. It's a bad idea when it was
# changed by the user from the command line. The best approach would be to
# have a "restart" command which would allow explicit specification of
# command line arguments.
dbg = Debugger()
dbg._runscript(mainpyfile)
if __name__=='__main__':
main()
diff -r e8c070db8be7 graph.py
--- a/graph.py Sun Nov 09 20:29:36 2008 -0500
+++ b/graph.py Sat Nov 29 16:50:09 2008 -0500
@@ -195,7 +195,7 @@
def on_unicode_checkbox(self, w, state):
self.graph = self.bar_graph( state )
- self.graph_wrap.w = self.graph
+ self.graph_wrap._w = self.graph
self.animate_progress = self.progress_bar( state )
self.animate_progress_wrap.w = self.animate_progress
diff -r e8c070db8be7 setup.py
--- a/setup.py Sun Nov 09 20:29:36 2008 -0500
+++ b/setup.py Sat Nov 29 16:50:09 2008 -0500
@@ -21,8 +21,10 @@
try:
from setuptools import setup, Extension
+ have_setuptools = True
except ImportError:
from distutils.core import setup, Extension
+ have_setuptools = False
import os
@@ -83,6 +85,10 @@
'packages':['urwid'],
}
+if have_setuptools:
+ setup_d['zip_safe'] = False
+
+
try:
True
except:
diff -r e8c070db8be7 urwid/container.py
--- a/urwid/container.py Sun Nov 09 20:29:36 2008 -0500
+++ b/urwid/container.py Sat Nov 29 16:50:09 2008 -0500
@@ -143,7 +143,7 @@
"""Set the focus to the item in focus in the display widget."""
if isinstance(w, Padding):
# unwrap padding
- w = w.w
+ w = w._original_widget
w = w.get_focus()
if w in self.cells:
self.set_focus(w)
@@ -329,7 +329,7 @@
bottom = maxrow-top-height
elif self.height_type is None:
# top_w is a flow widget
- height = self.body.rows((maxcol,),focus=focus)
+ height = self.top_w.rows((maxcol,),focus=focus)
top, bottom = calculate_filler( self.valign_type,
self.valign_amount, 'fixed', height,
None, maxrow )
diff -r e8c070db8be7 urwid/decoration.py
--- a/urwid/decoration.py Sun Nov 09 20:29:36 2008 -0500
+++ b/urwid/decoration.py Sat Nov 29 16:50:09 2008 -0500
@@ -412,31 +412,31 @@
return self._original_widget.rows((maxcol-left-right,), focus=focus)
def keypress(self, size, key):
- """Pass keypress to self.w."""
+ """Pass keypress to self._original_widget."""
maxcol = size[0]
left, right = self.padding_values(size, True)
maxvals = (maxcol-left-right,)+size[1:]
- return self.w.keypress(maxvals, key)
+ return self._original_widget.keypress(maxvals, key)
def get_cursor_coords(self,size):
- """Return the (x,y) coordinates of cursor within self.w."""
- if not hasattr(self.w,'get_cursor_coords'):
+ """Return the (x,y) coordinates of cursor within self._original_widget."""
+ if not hasattr(self._original_widget,'get_cursor_coords'):
return None
left, right = self.padding_values(size, True)
maxcol = size[0]
maxvals = (maxcol-left-right,)+size[1:]
- coords = self.w.get_cursor_coords(maxvals)
+ coords = self._original_widget.get_cursor_coords(maxvals)
if coords is None:
return None
x, y = coords
return x+left, y
def move_cursor_to_coords(self, size, x, y):
- """Set the cursor position with (x,y) coordinates of self.w.
+ """Set the cursor position with (x,y) coordinates of self._original_widget.
Returns True if move succeeded, False otherwise.
"""
- if not hasattr(self.w,'move_cursor_to_coords'):
+ if not hasattr(self._original_widget,'move_cursor_to_coords'):
return True
left, right = self.padding_values(size, True)
maxcol = size[0]
@@ -447,29 +447,29 @@
elif x >= maxcol-right:
x = maxcol-right-1
x -= left
- return self.w.move_cursor_to_coords(maxvals, x, y)
+ return self._original_widget.move_cursor_to_coords(maxvals, x, y)
def mouse_event(self, size, event, button, x, y, focus):
- """Send mouse event if position is within self.w."""
- if not hasattr(self.w,'mouse_event'):
+ """Send mouse event if position is within self._original_widget."""
+ if not hasattr(self._original_widget,'mouse_event'):
return False
left, right = self.padding_values(size, focus)
maxcol = size[0]
if x < left or x >= maxcol-right:
return False
maxvals = (maxcol-left-right,)+size[1:]
- return self.w.mouse_event(maxvals, event, button, x-left, y,
+ return self._original_widget.mouse_event(maxvals, event, button, x-left, y,
focus)
def get_pref_col(self, size):
- """Return the preferred column from self.w, or None."""
- if not hasattr(self.w,'get_pref_col'):
+ """Return the preferred column from self._original_widget, or None."""
+ if not hasattr(self._original_widget,'get_pref_col'):
return None
left, right = self.padding_values(size, True)
maxcol = size[0]
maxvals = (maxcol-left-right,)+size[1:]
- x = self.w.get_pref_col(maxvals)
+ x = self._original_widget.get_pref_col(maxvals)
if type(x) == type(0):
return x+left
return x
diff -r e8c070db8be7 urwid/display_common.py
--- a/urwid/display_common.py Sun Nov 09 20:29:36 2008 -0500
+++ b/urwid/display_common.py Sat Nov 29 16:50:09 2008 -0500
@@ -478,7 +478,7 @@
if self.colours > colours:
raise AttrSpecError(('foreground/background (%s/%s) require ' +
'more colours than have been specified (%d).') %
- (repr(foreground), repr(background), colours))
+ (repr(fg), repr(bg), colours))
foreground_basic = property(lambda s: s._value & _FG_BASIC_COLOUR != 0)
foreground_high = property(lambda s: s._value & _FG_HIGH_COLOUR != 0)
diff -r e8c070db8be7 urwid/listbox.py
--- a/urwid/listbox.py Sun Nov 09 20:29:36 2008 -0500
+++ b/urwid/listbox.py Sat Nov 29 16:50:09 2008 -0500
@@ -385,6 +385,7 @@
('fixed bottom', rows)
('relative', percentage 0=top 100=bottom)
"""
+ from urwid.decoration import decompose_valign_height
vt,va,ht,ha=decompose_valign_height(valign,None,ListBoxError)
self.set_focus_valign_pending = vt,va
signature.asc
Description: This is a digitally signed message part.
_______________________________________________ Urwid mailing list [email protected] http://lists.excess.org/mailman/listinfo/urwid
