#!/usr/bin/env python
# -*- coding: utf8 -*-
#
# Copyright or © or Copr. Actimar/IFREMER (2010-2015)
#
# This software is a computer program whose purpose is to provide
# utilities for handling oceanographic and atmospheric data,
# with the ultimate goal of validating the MARS model from IFREMER.
#
# This software is governed by the CeCILL license under French law and
# abiding by the rules of distribution of free software. You can use,
# modify and/ or redistribute the software under the terms of the CeCILL
# license as circulated by CEA, CNRS and INRIA at the following URL
# "http://www.cecill.info".
#
# As a counterpart to the access to the source code and rights to copy,
# modify and redistribute granted by the license, users are provided only
# with a limited warranty and the software's author, the holder of the
# economic rights, and the successive licensors have only limited
# liability.
#
# In this respect, the user's attention is drawn to the risks associated
# with loading, using, modifying and/or developing or reproducing the
# software by the user in light of its specific status of free software,
# that may mean that it is complicated to manipulate, and that also
# therefore means that it is reserved for developers and experienced
# professionals having in-depth computer knowledge. Users are therefore
# encouraged to load and test the software's suitability as regards their
# requirements in conditions enabling the security of their systems and/or
# data to be ensured and, more generally, to use and operate it in the
# same conditions as regards security.
#
# The fact that you are presently reading this means that you have had
# knowledge of the CeCILL license and that you accept its terms.
#
__author__ = 'Jonathan Wilkins'
__email__ = 'wilkins@actimar.fr'
__date__ = '2010-11-02'
__doc__ = 'Exceptions utilities'
import sys, traceback, types
[docs]class ExceptionDebugger(object):
'''
Usefull for debugging.
Retreive details about exceptions like locals for each frames.
This provides informations about the program state (variables) for each frame
of the call stack.
'''
def __init__(self, exit=True, nframe=None):
self.exit, self.nframe = exit, nframe
[docs] def getDetailedExceptionInfo(self, etype=None, evalue=None, tb=None):
'''
Print the usual traceback information, followed by a (huge!) listing of all the
local variables in each frame.
**TODO**: use StringIO
'''
ls = u'-'*80
info = ''
try:
if etype is None or evalue is None or tb is None:
fmt_tb = traceback.format_exc()
else:
fmt_tb = u''.join(traceback.format_exception(etype, evalue, tb))
if tb is None:
tb = sys.exc_info()[2]
if tb is None:
return u'(Error while formating exception traceback, sys.exc_info returned no traceback object)'
while 1:
if not tb.tb_next:
break
tb = tb.tb_next
stack = []
f = tb.tb_frame
while f:
stack.append(f)
f = f.f_back
stack.reverse()
info = u'%s\nException details, locals by frame, innermost last'%(ls)
if self.nframe is None:
self.nframe = len(stack)
for frame in stack[-self.nframe:]:
#info = u'%s\n%s\nFrame %s in %s at line %s\n' % (info, ls, frame.f_code.co_name, frame.f_code.co_filename, frame.f_lineno)
info = u'%s\n%s\n%s\n' % (info, ls, ''.join(traceback.format_stack(frame, 1)))
for key in sorted(frame.f_locals.keys()):
value = frame.f_locals[key]
if type(value) == types.ModuleType or type(value) == types.FunctionType:
continue
if key.startswith('__') and key.endswith('__'):
continue
info = u'%s\t%20s '%(info, key)
try:
s = str(value)
if len(s) > 800:
s = s[:800] + ' (...)'
s = s.replace('\n', '\n\t'+' '*22)
s = '%s = %s'%(type(value), s)
info = u'%s%s\n'%(info, s)
except Exception, e:
info = u'%s<ERROR WHILE PRINTING VALUE: %s>\n'%(info, e)
except Exception, e:
info = u'%s<ERROR WHILE PRINTING EXCEPTION DETAILS: %s>\n'%(info, e)
info = u'%s\n%s\n%s\n%s\n'%(info, ls, fmt_tb, ls)
return info
[docs] def exceptHook(self, etype, evalue, tb):
'''Exception hook used when installed by :meth:`bindExceptHook`'''
print>>sys.stderr, self.getDetailedExceptionInfo(etype, evalue, tb)
if self.exit:
sys.exit(1)
[docs] def bindExceptHook(self):
'''Install this classe's exception traceback feature to sys.excepthook.
:meth:`getDetailedExceptionInfo` will then be called when an exception
is not handled by user's code (and then before exiting).
'''
sys.excepthook = self.exceptHook
# Default exception debbuger
_excdbg = ExceptionDebugger()
[docs]def bindExceptHook(*a, **k):
'''See :meth:`ExceptionDebugger.bindExceptHook`'''
_excdbg.bindExceptHook(*a, **k)
[docs]def getDetailedExceptionInfo(*a, **k):
'''See :meth:`ExceptionDebugger.getDetailedExceptionInfo`'''
return _excdbg.getDetailedExceptionInfo(*a, **k)