753ac9b4c4
commit ca3fbe2ff9
Author: Luke Campagnola <luke.campagnola@gmail.com>
Date: Thu Aug 7 08:41:30 2014 -0400
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
107 lines
4.1 KiB
Python
107 lines
4.1 KiB
Python
# -*- coding: utf-8 -*-
|
|
"""This module installs a wrapper around sys.excepthook which allows multiple
|
|
new exception handlers to be registered.
|
|
|
|
Optionally, the wrapper also stops exceptions from causing long-term storage
|
|
of local stack frames. This has two major effects:
|
|
- Unhandled exceptions will no longer cause memory leaks
|
|
(If an exception occurs while a lot of data is present on the stack,
|
|
such as when loading large files, the data would ordinarily be kept
|
|
until the next exception occurs. We would rather release this memory
|
|
as soon as possible.)
|
|
- Some debuggers may have a hard time handling uncaught exceptions
|
|
|
|
The module also provides a callback mechanism allowing others to respond
|
|
to exceptions.
|
|
"""
|
|
|
|
import sys, time
|
|
#from lib.Manager import logMsg
|
|
import traceback
|
|
#from log import *
|
|
|
|
#logging = False
|
|
|
|
callbacks = []
|
|
clear_tracebacks = False
|
|
|
|
def register(fn):
|
|
"""
|
|
Register a callable to be invoked when there is an unhandled exception.
|
|
The callback will be passed the output of sys.exc_info(): (exception type, exception, traceback)
|
|
Multiple callbacks will be invoked in the order they were registered.
|
|
"""
|
|
callbacks.append(fn)
|
|
|
|
def unregister(fn):
|
|
"""Unregister a previously registered callback."""
|
|
callbacks.remove(fn)
|
|
|
|
def setTracebackClearing(clear=True):
|
|
"""
|
|
Enable or disable traceback clearing.
|
|
By default, clearing is disabled and Python will indefinitely store unhandled exception stack traces.
|
|
This function is provided since Python's default behavior can cause unexpected retention of
|
|
large memory-consuming objects.
|
|
"""
|
|
global clear_tracebacks
|
|
clear_tracebacks = clear
|
|
|
|
class ExceptionHandler(object):
|
|
def __call__(self, *args):
|
|
## Start by extending recursion depth just a bit.
|
|
## If the error we are catching is due to recursion, we don't want to generate another one here.
|
|
recursionLimit = sys.getrecursionlimit()
|
|
try:
|
|
sys.setrecursionlimit(recursionLimit+100)
|
|
|
|
|
|
## call original exception handler first (prints exception)
|
|
global original_excepthook, callbacks, clear_tracebacks
|
|
try:
|
|
print("===== %s =====" % str(time.strftime("%Y.%m.%d %H:%m:%S", time.localtime(time.time()))))
|
|
except Exception:
|
|
sys.stderr.write("Warning: stdout is broken! Falling back to stderr.\n")
|
|
sys.stdout = sys.stderr
|
|
|
|
ret = original_excepthook(*args)
|
|
|
|
for cb in callbacks:
|
|
try:
|
|
cb(*args)
|
|
except Exception:
|
|
print(" --------------------------------------------------------------")
|
|
print(" Error occurred during exception callback %s" % str(cb))
|
|
print(" --------------------------------------------------------------")
|
|
traceback.print_exception(*sys.exc_info())
|
|
|
|
|
|
## Clear long-term storage of last traceback to prevent memory-hogging.
|
|
## (If an exception occurs while a lot of data is present on the stack,
|
|
## such as when loading large files, the data would ordinarily be kept
|
|
## until the next exception occurs. We would rather release this memory
|
|
## as soon as possible.)
|
|
if clear_tracebacks is True:
|
|
sys.last_traceback = None
|
|
|
|
finally:
|
|
sys.setrecursionlimit(recursionLimit)
|
|
|
|
|
|
def implements(self, interface=None):
|
|
## this just makes it easy for us to detect whether an ExceptionHook is already installed.
|
|
if interface is None:
|
|
return ['ExceptionHandler']
|
|
else:
|
|
return interface == 'ExceptionHandler'
|
|
|
|
|
|
|
|
## replace built-in excepthook only if this has not already been done
|
|
if not (hasattr(sys.excepthook, 'implements') and sys.excepthook.implements('ExceptionHandler')):
|
|
original_excepthook = sys.excepthook
|
|
sys.excepthook = ExceptionHandler()
|
|
|
|
|
|
|