Commit ca3fbe2f authored by Luke Campagnola's avatar Luke Campagnola
Browse files

Merged numerous updates from acq4:

* Added HDF5 exporter
* CSV exporter gets (x,y,y,y) export mode
* Updates to SVG, Matplotlib exporter
* Console can filter exceptions by string
* Added tick context menu to GradientEditorItem
* Added export feature to imageview
* Parameter trees:
    - Option to save only user-editable values
    - Option to set visible title of parameters separately from name
    - Added experimental ParameterSystem for handling large systems of
        interdependent parameters
    - Auto-select editable portion of spinbox when editing
* Added Vector.__abs__
* Added replacement garbage collector for avoiding crashes on multithreaded Qt
* Fixed "illegal instruction" caused by closing file handle 7 on OSX
* configfile now reloads QtCore objects, Point, ColorMap, numpy arrays
* Avoid triggering recursion issues in exception handler
* Various bugfies and performance enhancements
parent f9c85dae
......@@ -81,5 +81,7 @@ class Vector(QtGui.QVector3D):
# ang *= -1.
return ang * 180. / np.pi
def __abs__(self):
return Vector(abs(self.x()), abs(self.y()), abs(self.z()))
\ No newline at end of file
......@@ -325,8 +325,13 @@ def exit():
atexit._run_exitfuncs()
## close file handles
os.closerange(3, 4096) ## just guessing on the maximum descriptor count..
if sys.platform == 'darwin':
for fd in xrange(3, 4096):
if fd not in [7]: # trying to close 7 produces an illegal instruction on the Mac.
os.close(fd)
else:
os.closerange(3, 4096) ## just guessing on the maximum descriptor count..
os._exit(0)
......
......@@ -67,8 +67,8 @@ class Canvas(QtGui.QWidget):
self.ui.itemList.sigItemMoved.connect(self.treeItemMoved)
self.ui.itemList.itemSelectionChanged.connect(self.treeItemSelected)
self.ui.autoRangeBtn.clicked.connect(self.autoRange)
self.ui.storeSvgBtn.clicked.connect(self.storeSvg)
self.ui.storePngBtn.clicked.connect(self.storePng)
#self.ui.storeSvgBtn.clicked.connect(self.storeSvg)
#self.ui.storePngBtn.clicked.connect(self.storePng)
self.ui.redirectCheck.toggled.connect(self.updateRedirect)
self.ui.redirectCombo.currentIndexChanged.connect(self.updateRedirect)
self.multiSelectBox.sigRegionChanged.connect(self.multiSelectBoxChanged)
......@@ -94,11 +94,13 @@ class Canvas(QtGui.QWidget):
self.ui.itemList.contextMenuEvent = self.itemListContextMenuEvent
def storeSvg(self):
self.ui.view.writeSvg()
#def storeSvg(self):
#from pyqtgraph.GraphicsScene.exportDialog import ExportDialog
#ex = ExportDialog(self.ui.view)
#ex.show()
def storePng(self):
self.ui.view.writeImage()
#def storePng(self):
#self.ui.view.writeImage()
def splitterMoved(self):
self.resizeEvent()
......@@ -571,7 +573,9 @@ class Canvas(QtGui.QWidget):
self.menu.popup(ev.globalPos())
def removeClicked(self):
self.removeItem(self.menuItem)
#self.removeItem(self.menuItem)
for item in self.selectedItems():
self.removeItem(item)
self.menuItem = None
import gc
gc.collect()
......
......@@ -28,21 +28,7 @@
<widget class="GraphicsView" name="view"/>
<widget class="QWidget" name="layoutWidget">
<layout class="QGridLayout" name="gridLayout_2">
<item row="1" column="0">
<widget class="QPushButton" name="storeSvgBtn">
<property name="text">
<string>Store SVG</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QPushButton" name="storePngBtn">
<property name="text">
<string>Store PNG</string>
</property>
</widget>
</item>
<item row="3" column="0" colspan="2">
<item row="2" column="0" colspan="2">
<widget class="QPushButton" name="autoRangeBtn">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
......@@ -55,7 +41,7 @@
</property>
</widget>
</item>
<item row="6" column="0" colspan="2">
<item row="5" column="0" colspan="2">
<layout class="QHBoxLayout" name="horizontalLayout">
<property name="spacing">
<number>0</number>
......@@ -75,7 +61,7 @@
</item>
</layout>
</item>
<item row="7" column="0" colspan="2">
<item row="6" column="0" colspan="2">
<widget class="TreeWidget" name="itemList">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
......@@ -93,28 +79,28 @@
</column>
</widget>
</item>
<item row="11" column="0" colspan="2">
<item row="10" column="0" colspan="2">
<layout class="QGridLayout" name="ctrlLayout">
<property name="spacing">
<number>0</number>
</property>
</layout>
</item>
<item row="8" column="0">
<item row="7" column="0">
<widget class="QPushButton" name="resetTransformsBtn">
<property name="text">
<string>Reset Transforms</string>
</property>
</widget>
</item>
<item row="4" column="0">
<item row="3" column="0">
<widget class="QPushButton" name="mirrorSelectionBtn">
<property name="text">
<string>Mirror Selection</string>
</property>
</widget>
</item>
<item row="4" column="1">
<item row="3" column="1">
<widget class="QPushButton" name="reflectSelectionBtn">
<property name="text">
<string>MirrorXY</string>
......
# -*- coding: utf-8 -*-
# Form implementation generated from reading ui file './pyqtgraph/canvas/CanvasTemplate.ui'
# Form implementation generated from reading ui file 'acq4/pyqtgraph/canvas/CanvasTemplate.ui'
#
# Created: Mon Dec 23 10:10:52 2013
# by: PyQt4 UI code generator 4.10
# Created: Thu Jan 2 11:13:07 2014
# by: PyQt4 UI code generator 4.9
#
# WARNING! All changes made in this file will be lost!
......@@ -12,16 +12,7 @@ from PyQt4 import QtCore, QtGui
try:
_fromUtf8 = QtCore.QString.fromUtf8
except AttributeError:
def _fromUtf8(s):
return s
try:
_encoding = QtGui.QApplication.UnicodeUTF8
def _translate(context, text, disambig):
return QtGui.QApplication.translate(context, text, disambig, _encoding)
except AttributeError:
def _translate(context, text, disambig):
return QtGui.QApplication.translate(context, text, disambig)
_fromUtf8 = lambda s: s
class Ui_Form(object):
def setupUi(self, Form):
......@@ -41,12 +32,6 @@ class Ui_Form(object):
self.gridLayout_2 = QtGui.QGridLayout(self.layoutWidget)
self.gridLayout_2.setMargin(0)
self.gridLayout_2.setObjectName(_fromUtf8("gridLayout_2"))
self.storeSvgBtn = QtGui.QPushButton(self.layoutWidget)
self.storeSvgBtn.setObjectName(_fromUtf8("storeSvgBtn"))
self.gridLayout_2.addWidget(self.storeSvgBtn, 1, 0, 1, 1)
self.storePngBtn = QtGui.QPushButton(self.layoutWidget)
self.storePngBtn.setObjectName(_fromUtf8("storePngBtn"))
self.gridLayout_2.addWidget(self.storePngBtn, 1, 1, 1, 1)
self.autoRangeBtn = QtGui.QPushButton(self.layoutWidget)
sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Minimum, QtGui.QSizePolicy.Fixed)
sizePolicy.setHorizontalStretch(0)
......@@ -54,7 +39,7 @@ class Ui_Form(object):
sizePolicy.setHeightForWidth(self.autoRangeBtn.sizePolicy().hasHeightForWidth())
self.autoRangeBtn.setSizePolicy(sizePolicy)
self.autoRangeBtn.setObjectName(_fromUtf8("autoRangeBtn"))
self.gridLayout_2.addWidget(self.autoRangeBtn, 3, 0, 1, 2)
self.gridLayout_2.addWidget(self.autoRangeBtn, 2, 0, 1, 2)
self.horizontalLayout = QtGui.QHBoxLayout()
self.horizontalLayout.setSpacing(0)
self.horizontalLayout.setObjectName(_fromUtf8("horizontalLayout"))
......@@ -64,7 +49,7 @@ class Ui_Form(object):
self.redirectCombo = CanvasCombo(self.layoutWidget)
self.redirectCombo.setObjectName(_fromUtf8("redirectCombo"))
self.horizontalLayout.addWidget(self.redirectCombo)
self.gridLayout_2.addLayout(self.horizontalLayout, 6, 0, 1, 2)
self.gridLayout_2.addLayout(self.horizontalLayout, 5, 0, 1, 2)
self.itemList = TreeWidget(self.layoutWidget)
sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Expanding)
sizePolicy.setHorizontalStretch(0)
......@@ -74,35 +59,33 @@ class Ui_Form(object):
self.itemList.setHeaderHidden(True)
self.itemList.setObjectName(_fromUtf8("itemList"))
self.itemList.headerItem().setText(0, _fromUtf8("1"))
self.gridLayout_2.addWidget(self.itemList, 7, 0, 1, 2)
self.gridLayout_2.addWidget(self.itemList, 6, 0, 1, 2)
self.ctrlLayout = QtGui.QGridLayout()
self.ctrlLayout.setSpacing(0)
self.ctrlLayout.setObjectName(_fromUtf8("ctrlLayout"))
self.gridLayout_2.addLayout(self.ctrlLayout, 11, 0, 1, 2)
self.gridLayout_2.addLayout(self.ctrlLayout, 10, 0, 1, 2)
self.resetTransformsBtn = QtGui.QPushButton(self.layoutWidget)
self.resetTransformsBtn.setObjectName(_fromUtf8("resetTransformsBtn"))
self.gridLayout_2.addWidget(self.resetTransformsBtn, 8, 0, 1, 1)
self.gridLayout_2.addWidget(self.resetTransformsBtn, 7, 0, 1, 1)
self.mirrorSelectionBtn = QtGui.QPushButton(self.layoutWidget)
self.mirrorSelectionBtn.setObjectName(_fromUtf8("mirrorSelectionBtn"))
self.gridLayout_2.addWidget(self.mirrorSelectionBtn, 4, 0, 1, 1)
self.gridLayout_2.addWidget(self.mirrorSelectionBtn, 3, 0, 1, 1)
self.reflectSelectionBtn = QtGui.QPushButton(self.layoutWidget)
self.reflectSelectionBtn.setObjectName(_fromUtf8("reflectSelectionBtn"))
self.gridLayout_2.addWidget(self.reflectSelectionBtn, 4, 1, 1, 1)
self.gridLayout_2.addWidget(self.reflectSelectionBtn, 3, 1, 1, 1)
self.gridLayout.addWidget(self.splitter, 0, 0, 1, 1)
self.retranslateUi(Form)
QtCore.QMetaObject.connectSlotsByName(Form)
def retranslateUi(self, Form):
Form.setWindowTitle(_translate("Form", "Form", None))
self.storeSvgBtn.setText(_translate("Form", "Store SVG", None))
self.storePngBtn.setText(_translate("Form", "Store PNG", None))
self.autoRangeBtn.setText(_translate("Form", "Auto Range", None))
self.redirectCheck.setToolTip(_translate("Form", "Check to display all local items in a remote canvas.", None))
self.redirectCheck.setText(_translate("Form", "Redirect", None))
self.resetTransformsBtn.setText(_translate("Form", "Reset Transforms", None))
self.mirrorSelectionBtn.setText(_translate("Form", "Mirror Selection", None))
self.reflectSelectionBtn.setText(_translate("Form", "MirrorXY", None))
Form.setWindowTitle(QtGui.QApplication.translate("Form", "Form", None, QtGui.QApplication.UnicodeUTF8))
self.autoRangeBtn.setText(QtGui.QApplication.translate("Form", "Auto Range", None, QtGui.QApplication.UnicodeUTF8))
self.redirectCheck.setToolTip(QtGui.QApplication.translate("Form", "Check to display all local items in a remote canvas.", None, QtGui.QApplication.UnicodeUTF8))
self.redirectCheck.setText(QtGui.QApplication.translate("Form", "Redirect", None, QtGui.QApplication.UnicodeUTF8))
self.resetTransformsBtn.setText(QtGui.QApplication.translate("Form", "Reset Transforms", None, QtGui.QApplication.UnicodeUTF8))
self.mirrorSelectionBtn.setText(QtGui.QApplication.translate("Form", "Mirror Selection", None, QtGui.QApplication.UnicodeUTF8))
self.reflectSelectionBtn.setText(QtGui.QApplication.translate("Form", "MirrorXY", None, QtGui.QApplication.UnicodeUTF8))
from ..widgets.TreeWidget import TreeWidget
from CanvasManager import CanvasCombo
......
......@@ -244,4 +244,7 @@ class ColorMap(object):
else:
return np.all(self.color == np.array([[0,0,0,255], [255,255,255,255]]))
def __repr__(self):
pos = repr(self.pos).replace('\n', '')
color = repr(self.color).replace('\n', '')
return "ColorMap(%s, %s)" % (pos, color)
......@@ -14,6 +14,10 @@ from .pgcollections import OrderedDict
GLOBAL_PATH = None # so not thread safe.
from . import units
from .python2_3 import asUnicode
from .Qt import QtCore
from .Point import Point
from .colormap import ColorMap
import numpy
class ParseError(Exception):
def __init__(self, message, lineNum, line, fileName=None):
......@@ -46,7 +50,7 @@ def readConfigFile(fname):
fname2 = os.path.join(GLOBAL_PATH, fname)
if os.path.exists(fname2):
fname = fname2
GLOBAL_PATH = os.path.dirname(os.path.abspath(fname))
try:
......@@ -135,6 +139,17 @@ def parseString(lines, start=0):
local = units.allUnits.copy()
local['OrderedDict'] = OrderedDict
local['readConfigFile'] = readConfigFile
local['Point'] = Point
local['QtCore'] = QtCore
local['ColorMap'] = ColorMap
# Needed for reconstructing numpy arrays
local['array'] = numpy.array
for dtype in ['int8', 'uint8',
'int16', 'uint16', 'float16',
'int32', 'uint32', 'float32',
'int64', 'uint64', 'float64']:
local[dtype] = getattr(numpy, dtype)
if len(k) < 1:
raise ParseError('Missing name preceding colon', ln+1, l)
if k[0] == '(' and k[-1] == ')': ## If the key looks like a tuple, try evaluating it.
......
......@@ -341,6 +341,17 @@ class ConsoleWidget(QtGui.QWidget):
filename = tb.tb_frame.f_code.co_filename
function = tb.tb_frame.f_code.co_name
filterStr = str(self.ui.filterText.text())
if filterStr != '':
if isinstance(exc, Exception):
msg = exc.message
elif isinstance(exc, basestring):
msg = exc
else:
msg = repr(exc)
match = re.search(filterStr, "%s:%s:%s" % (filename, function, msg))
return match is not None
## Go through a list of common exception points we like to ignore:
if excType is GeneratorExit or excType is StopIteration:
return False
......
......@@ -6,7 +6,7 @@
<rect>
<x>0</x>
<y>0</y>
<width>710</width>
<width>694</width>
<height>497</height>
</rect>
</property>
......@@ -89,6 +89,16 @@
<property name="spacing">
<number>0</number>
</property>
<item row="0" column="6">
<widget class="QPushButton" name="clearExceptionBtn">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>Clear Exception</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QPushButton" name="catchAllExceptionsBtn">
<property name="text">
......@@ -109,7 +119,7 @@
</property>
</widget>
</item>
<item row="0" column="2">
<item row="0" column="4">
<widget class="QCheckBox" name="onlyUncaughtCheck">
<property name="text">
<string>Only Uncaught Exceptions</string>
......@@ -119,14 +129,14 @@
</property>
</widget>
</item>
<item row="2" column="0" colspan="5">
<item row="2" column="0" colspan="7">
<widget class="QListWidget" name="exceptionStackList">
<property name="alternatingRowColors">
<bool>true</bool>
</property>
</widget>
</item>
<item row="3" column="0" colspan="5">
<item row="3" column="0" colspan="7">
<widget class="QCheckBox" name="runSelectedFrameCheck">
<property name="text">
<string>Run commands in selected stack frame</string>
......@@ -136,24 +146,14 @@
</property>
</widget>
</item>
<item row="1" column="0" colspan="5">
<item row="1" column="0" colspan="7">
<widget class="QLabel" name="exceptionInfoLabel">
<property name="text">
<string>Exception Info</string>
</property>
</widget>
</item>
<item row="0" column="4">
<widget class="QPushButton" name="clearExceptionBtn">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>Clear Exception</string>
</property>
</widget>
</item>
<item row="0" column="3">
<item row="0" column="5">
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
......@@ -166,6 +166,16 @@
</property>
</spacer>
</item>
<item row="0" column="2">
<widget class="QLabel" name="label">
<property name="text">
<string>Filter (regex):</string>
</property>
</widget>
</item>
<item row="0" column="3">
<widget class="QLineEdit" name="filterText"/>
</item>
</layout>
</widget>
</widget>
......
# -*- coding: utf-8 -*-
# Form implementation generated from reading ui file './pyqtgraph/console/template.ui'
# Form implementation generated from reading ui file 'template.ui'
#
# Created: Mon Dec 23 10:10:53 2013
# by: PyQt4 UI code generator 4.10
# Created: Fri May 02 18:55:28 2014
# by: PyQt4 UI code generator 4.10.4
#
# WARNING! All changes made in this file will be lost!
......@@ -26,7 +26,7 @@ except AttributeError:
class Ui_Form(object):
def setupUi(self, Form):
Form.setObjectName(_fromUtf8("Form"))
Form.resize(710, 497)
Form.resize(694, 497)
self.gridLayout = QtGui.QGridLayout(Form)
self.gridLayout.setMargin(0)
self.gridLayout.setSpacing(0)
......@@ -71,6 +71,10 @@ class Ui_Form(object):
self.gridLayout_2.setSpacing(0)
self.gridLayout_2.setContentsMargins(-1, 0, -1, 0)
self.gridLayout_2.setObjectName(_fromUtf8("gridLayout_2"))
self.clearExceptionBtn = QtGui.QPushButton(self.exceptionGroup)
self.clearExceptionBtn.setEnabled(False)
self.clearExceptionBtn.setObjectName(_fromUtf8("clearExceptionBtn"))
self.gridLayout_2.addWidget(self.clearExceptionBtn, 0, 6, 1, 1)
self.catchAllExceptionsBtn = QtGui.QPushButton(self.exceptionGroup)
self.catchAllExceptionsBtn.setCheckable(True)
self.catchAllExceptionsBtn.setObjectName(_fromUtf8("catchAllExceptionsBtn"))
......@@ -82,24 +86,26 @@ class Ui_Form(object):
self.onlyUncaughtCheck = QtGui.QCheckBox(self.exceptionGroup)
self.onlyUncaughtCheck.setChecked(True)
self.onlyUncaughtCheck.setObjectName(_fromUtf8("onlyUncaughtCheck"))
self.gridLayout_2.addWidget(self.onlyUncaughtCheck, 0, 2, 1, 1)
self.gridLayout_2.addWidget(self.onlyUncaughtCheck, 0, 4, 1, 1)
self.exceptionStackList = QtGui.QListWidget(self.exceptionGroup)
self.exceptionStackList.setAlternatingRowColors(True)
self.exceptionStackList.setObjectName(_fromUtf8("exceptionStackList"))
self.gridLayout_2.addWidget(self.exceptionStackList, 2, 0, 1, 5)
self.gridLayout_2.addWidget(self.exceptionStackList, 2, 0, 1, 7)
self.runSelectedFrameCheck = QtGui.QCheckBox(self.exceptionGroup)
self.runSelectedFrameCheck.setChecked(True)
self.runSelectedFrameCheck.setObjectName(_fromUtf8("runSelectedFrameCheck"))
self.gridLayout_2.addWidget(self.runSelectedFrameCheck, 3, 0, 1, 5)
self.gridLayout_2.addWidget(self.runSelectedFrameCheck, 3, 0, 1, 7)
self.exceptionInfoLabel = QtGui.QLabel(self.exceptionGroup)
self.exceptionInfoLabel.setObjectName(_fromUtf8("exceptionInfoLabel"))
self.gridLayout_2.addWidget(self.exceptionInfoLabel, 1, 0, 1, 5)
self.clearExceptionBtn = QtGui.QPushButton(self.exceptionGroup)
self.clearExceptionBtn.setEnabled(False)
self.clearExceptionBtn.setObjectName(_fromUtf8("clearExceptionBtn"))
self.gridLayout_2.addWidget(self.clearExceptionBtn, 0, 4, 1, 1)
self.gridLayout_2.addWidget(self.exceptionInfoLabel, 1, 0, 1, 7)
spacerItem = QtGui.QSpacerItem(40, 20, QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Minimum)
self.gridLayout_2.addItem(spacerItem, 0, 3, 1, 1)
self.gridLayout_2.addItem(spacerItem, 0, 5, 1, 1)
self.label = QtGui.QLabel(self.exceptionGroup)
self.label.setObjectName(_fromUtf8("label"))
self.gridLayout_2.addWidget(self.label, 0, 2, 1, 1)
self.filterText = QtGui.QLineEdit(self.exceptionGroup)
self.filterText.setObjectName(_fromUtf8("filterText"))
self.gridLayout_2.addWidget(self.filterText, 0, 3, 1, 1)
self.gridLayout.addWidget(self.splitter, 0, 0, 1, 1)
self.retranslateUi(Form)
......@@ -110,11 +116,12 @@ class Ui_Form(object):
self.historyBtn.setText(_translate("Form", "History..", None))
self.exceptionBtn.setText(_translate("Form", "Exceptions..", None))
self.exceptionGroup.setTitle(_translate("Form", "Exception Handling", None))
self.clearExceptionBtn.setText(_translate("Form", "Clear Exception", None))
self.catchAllExceptionsBtn.setText(_translate("Form", "Show All Exceptions", None))
self.catchNextExceptionBtn.setText(_translate("Form", "Show Next Exception", None))
self.onlyUncaughtCheck.setText(_translate("Form", "Only Uncaught Exceptions", None))
self.runSelectedFrameCheck.setText(_translate("Form", "Run commands in selected stack frame", None))
self.exceptionInfoLabel.setText(_translate("Form", "Exception Info", None))
self.clearExceptionBtn.setText(_translate("Form", "Clear Exception", None))
self.label.setText(_translate("Form", "Filter (regex):", None))
from .CmdInput import CmdInput
......@@ -32,6 +32,57 @@ def ftrace(func):
return rv
return w
class Tracer(object):
"""
Prints every function enter/exit. Useful for debugging crashes / lockups.
"""
def __init__(self):
self.count = 0
self.stack = []
def trace(self, frame, event, arg):
self.count += 1
# If it has been a long time since we saw the top of the stack,
# print a reminder
if self.count % 1000 == 0:
print("----- current stack: -----")
for line in self.stack:
print(line)
if event == 'call':
line = " " * len(self.stack) + ">> " + self.frameInfo(frame)
print(line)
self.stack.append(line)
elif event == 'return':
self.stack.pop()
line = " " * len(self.stack) + "<< " + self.frameInfo(frame)
print(line)
if len(self.stack) == 0:
self.count = 0
return self.trace
def stop(self):
sys.settrace(None)
def start(self):
sys.settrace(self.trace)
def frameInfo(self, fr):
filename = fr.f_code.co_filename
funcname = fr.f_code.co_name
lineno = fr.f_lineno
callfr = sys._getframe(3)
callline = "%s %d" % (callfr.f_code.co_name, callfr.f_lineno)
args, _, _, value_dict = inspect.getargvalues(fr)
if len(args) and args[0] == 'self':
instance = value_dict.get('self', None)
if instance is not None:
cls = getattr(instance, '__class__', None)
if cls is not None:
funcname = cls.__name__ + "." + funcname
return "%s: %s %s: %s" % (callline, filename, lineno, funcname)
def warnOnException(func):
"""Decorator which catches/ignores exceptions and prints a stack trace."""
def w(*args, **kwds):
......@@ -41,17 +92,22 @@ def warnOnException(func):
printExc('Ignored exception:')
return w
def getExc(indent=4, prefix='| '):
tb = traceback.format_exc()
lines = []
for l in tb.split('\n'):
lines.append(" "*indent + prefix + l)
return '\n'.join(lines)
def getExc(indent=4, prefix='| ', skip=1):
lines = (traceback.format_stack()[:-skip]
+ [" ---- exception caught ---->\n"]
+ traceback.format_tb(sys.exc_info()[2])
+ traceback.format_exception_only(*sys.exc_info()[:2]))
lines2 = []
for l in lines:
lines2.extend(l.strip('\n').split('\n'))
lines3 = [" "*indent + prefix + l for l in lines2]
return '\n'.join(lines3)
def printExc(msg='', indent=4, prefix='|'):
"""Print an error message followed by an indented exception backtrace
(This function is intended to be called within except: blocks)"""
exc = getExc(indent, prefix + ' ')
exc = getExc(indent, prefix + ' ', skip=2)
print("[%s] %s\n" % (time.strftime("%H:%M:%S"), msg))
print(" "*indent + prefix + '='*30 + '>>')
print(exc)
......@@ -407,6 +463,7 @@ class Profiler(object):
_depth = 0
_msgs = []
disable = False # set this flag to disable all or individual profilers at runtime
class DisabledProfiler(object):
def __init__(self, *args, **kwds):
......@@ -418,12 +475,11 @@ class Profiler(object):
def mark(self, msg=None):
pass