Cleanup, better support for tracebacks in DataTreeWidget
This commit is contained in:
parent
8c0064a323
commit
cabd9d6bf2
@ -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)
|
||||
|
@ -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:
|
||||
typeStr = type(data).__name__
|
||||
if typeStr == 'instance':
|
||||
typeStr += ": " + data.__class__.__name__
|
||||
node = QtGui.QTreeWidgetItem([name, typeStr, ""])
|
||||
node = QtGui.QTreeWidgetItem([name, "", ""])
|
||||
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()
|
||||
}
|
||||
|
||||
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))
|
||||
elif isinstance(data, np.ndarray):
|
||||
desc = "<%s shape=%s dtype=%s>" % (data.__class__.__name__, data.shape, data.dtype)
|
||||
node.setText(2, desc)
|
||||
|
||||
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__
|
||||
widget = None
|
||||
desc = ""
|
||||
childs = {}
|
||||
|
||||
# type-specific changes
|
||||
if isinstance(data, dict):
|
||||
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 = "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
|
||||
|
Loading…
Reference in New Issue
Block a user