Cleanup, better support for tracebacks in DataTreeWidget

This commit is contained in:
Luke Campagnola 2014-09-25 15:21:28 -04:00
parent 8c0064a323
commit cabd9d6bf2
2 changed files with 85 additions and 31 deletions

View File

@ -11,15 +11,29 @@ from pyqtgraph.Qt import QtCore, QtGui
import numpy as np
# for generating a traceback object to display
def some_func1():
return some_func2()
def some_func2():
try:
raise Exception()
except:
import sys
return sys.exc_info()[2]
app = QtGui.QApplication([])
d = {
'list1': [1,2,3,4,5,6, {'nested1': 'aaaaa', 'nested2': 'bbbbb'}, "seven"],
'dict1': {
'a list': [1,2,3,4,5,6, {'nested1': 'aaaaa', 'nested2': 'bbbbb'}, "seven"],
'a dict': {
'x': 1,
'y': 2,
'z': 'three'
},
'array1 (40x10)': np.random.randint(10, size=(40,10))
'an array': np.random.randint(10, size=(40,10)),
'a traceback': some_func1(),
'a function': some_func1,
'a class': pg.DataTreeWidget,
}
tree = pg.DataTreeWidget(data=d)

View File

@ -2,6 +2,7 @@
from ..Qt import QtGui, QtCore
from ..pgcollections import OrderedDict
from .TableWidget import TableWidget
from ..python2_3 import asUnicode
import types, traceback
import numpy as np
@ -18,19 +19,18 @@ class DataTreeWidget(QtGui.QTreeWidget):
Widget for displaying hierarchical python data structures
(eg, nested dicts, lists, and arrays)
"""
def __init__(self, parent=None, data=None):
QtGui.QTreeWidget.__init__(self, parent)
self.setVerticalScrollMode(self.ScrollPerPixel)
self.setData(data)
self.setColumnCount(3)
self.setHeaderLabels(['key / index', 'type', 'value'])
self.setAlternatingRowColors(True)
def setData(self, data, hideRoot=False):
"""data should be a dictionary."""
self.clear()
self.tables = []
self.widgets = []
self.buildTree(data, self.invisibleRootItem(), hideRoot=hideRoot)
self.expandToDepth(3)
self.resizeColumnToContents(0)
@ -39,35 +39,75 @@ class DataTreeWidget(QtGui.QTreeWidget):
if hideRoot:
node = parent
else:
node = QtGui.QTreeWidgetItem([name, "", ""])
parent.addChild(node)
typeStr, desc, childs, widget = self.parse(data)
node.setText(1, typeStr)
node.setText(2, desc)
if widget is not None:
self.widgets.append(widget)
subnode = QtGui.QTreeWidgetItem(["", "", ""])
node.addChild(subnode)
self.setItemWidget(subnode, 0, widget)
self.setFirstItemColumnSpanned(subnode, True)
for name, data in childs.items():
self.buildTree(data, node, asUnicode(name))
def parse(self, data):
"""
Given any python object, return:
* type
* a short string representation
* a dict of sub-objects to be parsed
* optional widget to display as sub-node
"""
# defaults for all objects
typeStr = type(data).__name__
if typeStr == 'instance':
typeStr += ": " + data.__class__.__name__
node = QtGui.QTreeWidgetItem([name, typeStr, ""])
parent.addChild(node)
if isinstance(data, types.TracebackType): ## convert traceback to a list of strings
data = list(map(str.strip, traceback.format_list(traceback.extract_tb(data))))
elif HAVE_METAARRAY and (hasattr(data, 'implements') and data.implements('MetaArray')):
data = {
'data': data.view(np.ndarray),
'meta': data.infoCopy()
}
widget = None
desc = ""
childs = {}
# type-specific changes
if isinstance(data, dict):
for k in data.keys():
self.buildTree(data[k], node, str(k))
elif isinstance(data, list) or isinstance(data, tuple):
for i in range(len(data)):
self.buildTree(data[i], node, str(i))
desc = "length=%d" % len(data)
if isinstance(data, OrderedDict):
childs = data
else:
childs = OrderedDict(sorted(data.items()))
elif isinstance(data, (list, tuple)):
desc = "length=%d" % len(data)
childs = OrderedDict(enumerate(data))
elif HAVE_METAARRAY and (hasattr(data, 'implements') and data.implements('MetaArray')):
childs = OrderedDict([
('data', data.view(np.ndarray)),
('meta', data.infoCopy())
])
elif isinstance(data, np.ndarray):
desc = "<%s shape=%s dtype=%s>" % (data.__class__.__name__, data.shape, data.dtype)
node.setText(2, desc)
subnode = QtGui.QTreeWidgetItem(["", "", ""])
node.addChild(subnode)
desc = "shape=%s dtype=%s" % (data.shape, data.dtype)
table = TableWidget()
table.setData(data)
table.setMaximumHeight(200)
self.setItemWidget(subnode, 2, table)
self.tables.append(table)
widget = table
elif isinstance(data, types.TracebackType): ## convert traceback to a list of strings
frames = list(map(str.strip, traceback.format_list(traceback.extract_tb(data))))
#childs = OrderedDict([
#(i, {'file': child[0], 'line': child[1], 'function': child[2], 'code': child[3]})
#for i, child in enumerate(frames)])
#childs = OrderedDict([(i, ch) for i,ch in enumerate(frames)])
widget = QtGui.QPlainTextEdit(asUnicode('\n'.join(frames)))
widget.setMaximumHeight(200)
widget.setReadOnly(True)
else:
node.setText(2, str(data))
desc = asUnicode(data)
if len(desc) > 100:
desc = desc[:97] + '...'
widget = QtGui.QPlainTextEdit(asUnicode(data))
widget.setMaximumHeight(200)
widget.setReadOnly(True)
return typeStr, desc, childs, widget