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
|
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([])
|
app = QtGui.QApplication([])
|
||||||
d = {
|
d = {
|
||||||
'list1': [1,2,3,4,5,6, {'nested1': 'aaaaa', 'nested2': 'bbbbb'}, "seven"],
|
'a list': [1,2,3,4,5,6, {'nested1': 'aaaaa', 'nested2': 'bbbbb'}, "seven"],
|
||||||
'dict1': {
|
'a dict': {
|
||||||
'x': 1,
|
'x': 1,
|
||||||
'y': 2,
|
'y': 2,
|
||||||
'z': 'three'
|
'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)
|
tree = pg.DataTreeWidget(data=d)
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
from ..Qt import QtGui, QtCore
|
from ..Qt import QtGui, QtCore
|
||||||
from ..pgcollections import OrderedDict
|
from ..pgcollections import OrderedDict
|
||||||
from .TableWidget import TableWidget
|
from .TableWidget import TableWidget
|
||||||
|
from ..python2_3 import asUnicode
|
||||||
import types, traceback
|
import types, traceback
|
||||||
import numpy as np
|
import numpy as np
|
||||||
|
|
||||||
@ -18,19 +19,18 @@ class DataTreeWidget(QtGui.QTreeWidget):
|
|||||||
Widget for displaying hierarchical python data structures
|
Widget for displaying hierarchical python data structures
|
||||||
(eg, nested dicts, lists, and arrays)
|
(eg, nested dicts, lists, and arrays)
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
def __init__(self, parent=None, data=None):
|
def __init__(self, parent=None, data=None):
|
||||||
QtGui.QTreeWidget.__init__(self, parent)
|
QtGui.QTreeWidget.__init__(self, parent)
|
||||||
self.setVerticalScrollMode(self.ScrollPerPixel)
|
self.setVerticalScrollMode(self.ScrollPerPixel)
|
||||||
self.setData(data)
|
self.setData(data)
|
||||||
self.setColumnCount(3)
|
self.setColumnCount(3)
|
||||||
self.setHeaderLabels(['key / index', 'type', 'value'])
|
self.setHeaderLabels(['key / index', 'type', 'value'])
|
||||||
|
self.setAlternatingRowColors(True)
|
||||||
|
|
||||||
def setData(self, data, hideRoot=False):
|
def setData(self, data, hideRoot=False):
|
||||||
"""data should be a dictionary."""
|
"""data should be a dictionary."""
|
||||||
self.clear()
|
self.clear()
|
||||||
self.tables = []
|
self.widgets = []
|
||||||
self.buildTree(data, self.invisibleRootItem(), hideRoot=hideRoot)
|
self.buildTree(data, self.invisibleRootItem(), hideRoot=hideRoot)
|
||||||
self.expandToDepth(3)
|
self.expandToDepth(3)
|
||||||
self.resizeColumnToContents(0)
|
self.resizeColumnToContents(0)
|
||||||
@ -39,35 +39,75 @@ class DataTreeWidget(QtGui.QTreeWidget):
|
|||||||
if hideRoot:
|
if hideRoot:
|
||||||
node = parent
|
node = parent
|
||||||
else:
|
else:
|
||||||
typeStr = type(data).__name__
|
node = QtGui.QTreeWidgetItem([name, "", ""])
|
||||||
if typeStr == 'instance':
|
|
||||||
typeStr += ": " + data.__class__.__name__
|
|
||||||
node = QtGui.QTreeWidgetItem([name, typeStr, ""])
|
|
||||||
parent.addChild(node)
|
parent.addChild(node)
|
||||||
|
|
||||||
if isinstance(data, types.TracebackType): ## convert traceback to a list of strings
|
typeStr, desc, childs, widget = self.parse(data)
|
||||||
data = list(map(str.strip, traceback.format_list(traceback.extract_tb(data))))
|
node.setText(1, typeStr)
|
||||||
elif HAVE_METAARRAY and (hasattr(data, 'implements') and data.implements('MetaArray')):
|
node.setText(2, desc)
|
||||||
data = {
|
if widget is not None:
|
||||||
'data': data.view(np.ndarray),
|
self.widgets.append(widget)
|
||||||
'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)
|
|
||||||
subnode = QtGui.QTreeWidgetItem(["", "", ""])
|
subnode = QtGui.QTreeWidgetItem(["", "", ""])
|
||||||
node.addChild(subnode)
|
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 = TableWidget()
|
||||||
table.setData(data)
|
table.setData(data)
|
||||||
table.setMaximumHeight(200)
|
table.setMaximumHeight(200)
|
||||||
self.setItemWidget(subnode, 2, table)
|
widget = table
|
||||||
self.tables.append(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:
|
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