X-Git-Url: http://git.salome-platform.org/gitweb/?a=blobdiff_plain;f=src%2Fdebug.py;h=330fb6df37c33468237c5c49f03f4e04528161b4;hb=abdba0a000f0e0436aa604ecae09224b4a63d178;hp=e1ab251b1a0af00cd5a48eec7feda9b88660a1fa;hpb=788a01b4bddd79de8067345a99b6ce0da3605503;p=tools%2Fsat.git diff --git a/src/debug.py b/src/debug.py old mode 100644 new mode 100755 index e1ab251..330fb6d --- a/src/debug.py +++ b/src/debug.py @@ -18,66 +18,121 @@ # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA """ -This file assume DEBUG functionalities use -- print debug messages in sys.stderr for salomeTools -- show pretty print debug representation from instances of SAT classes - (pretty print src.pyconf.Config), and python dict/list etc. (as 'aVariable') +This file assume DEBUG functionalities use. +Print salomeTools debug messages in sys.stderr. +Show pretty print debug representation from instances of SAT classes +(pretty print src.pyconf.Config) -WARNING: obviously supposedly show messages in SAT development phase, not production - -usage: ->> import debug as DBG ->> DBG.write("aTitle", aVariable) # not shown in production ->> DBG.write("aTitle", aVariable, True) # unconditionaly shown (as show=True) - -to set show message as development phase: ->> DBG.push_debug(True) - -to set no show message as production phase: ->> DBG.push_debug(False) - -to set show message temporary as development phase, only in a method: ->> def aMethodToDebug(...): ->> DBG.push_debug(True) #force show as appended status ->> etc. method code with some DBG.write() ->> DBG.pop_debug() #restore previous status (show or not show) ->> return - -to set a message for future fix, as temporary problem to not forget: -DBG.tofix("aTitle", aVariable, True/False) #True/False in production shown, or not +| Warning: supposedly show messages in SAT development phase, not production +| +| Usage: +| >> import debug as DBG +| >> DBG.write("aTitle", aVariable) # not shown in production +| >> DBG.write("aTitle", aVariable, True) # unconditionaly shown (as show=True) +| +| to set show message as development phase: +| >> DBG.push_debug(True) +| +| to set no show message as production phase: +| >> DBG.push_debug(False) +| +| to set show message temporary as development phase, only in a method: +| >> def aMethodToDebug(...): +| >> DBG.push_debug(True) #force show as appended status +| >> etc. method code with some DBG.write() +| >> DBG.pop_debug() #restore previous status (show or not show) +| >> return +| +| to set a message for future fix, as temporary problem to not forget: +| DBG.tofix("aTitle", aVariable, True/False) #True/False in production shown, or not +| +| in command line interface you could redirect stderr to file 'myDebug.log': +| >> sat compile ... 2> myDebug.log # only stderr +| >> sat compile ... &> myDebug.log # stdout and stderr """ import os import sys -import StringIO as SIO +import traceback import pprint as PP +import inspect +import src + +# Compatibility python 2/3 for unicode +try: + _test = unicode +except: + unicode = str + +# Compatibility python 2/3 for StringIO +try: + from StringIO import StringIO +except ImportError: + from io import StringIO _debug = [False] #support push/pop for temporary activate debug outputs + +def isDeveloper(): + """ + if you are a developer, sometimes you want verbose traces unconditionally + export SAT_DEVELOPER_MODE=1 before launch sat command to do that + """ + res = os.getenv("SAT_DEVELOPER_MODE", "0") + if res in "YES yes 1 Y y".split(): + return True + else: + return False + def indent(text, amount=2, ch=' '): """indent multi lines message""" padding = amount * ch return ''.join(padding + line for line in text.splitlines(True)) -def write(title, var="", force=None, fmt="\n#### DEBUG: %s:\n%s\n"): +def isTypeConfig(var): + """To know if var is instance from Config/pyconf""" + typ = str(type(var)) + # print "isTypeConfig" ,type, dir(var) + if ".pyconf.Config" in typ: return True + if ".pyconf.Mapping" in typ: return True + if ".pyconf.Sequence" in typ: return True + # print "NOT isTypeConfig %s" % typ + return False + +def write(title, var="", force=None, fmt=" %s:\n%s\n####\n"): """write sys.stderr a message if _debug[-1]==True or optionaly force=True""" if _debug[-1] or force: - if 'src.pyconf.' in str(type(var)): - sys.stderr.write(fmt % (title, indent(getStrConfigDbg(var)))) - elif type(var) is not str: - sys.stderr.write(fmt % (title, indent(PP.pformat(var)))) - else: - sys.stderr.write(fmt % (title, indent(var))) + callerframerecord = inspect.stack()[1] # get info of the caller + frame = callerframerecord[0] + info = inspect.getframeinfo(frame) + sys.stderr.write("\n#### DEBUG - %s:%s (%s) ####\n" % (info.filename, info.lineno, info.function)) + tvar = type(var) + typ = str(tvar) + if isTypeConfig(var): + sys.stderr.write(fmt % (title, indent(getStrConfigDbg(var)))) + return + if 'UnittestStream' in typ: + sys.stderr.write(fmt % (title, indent(var.getLogs()))) + return + if tvar is not str and tvar is not unicode: + sys.stderr.write(fmt % (title, indent(PP.pformat(var)))) + return + sys.stderr.write(fmt % (title, indent(var))) + return return def tofix(title, var="", force=None): """ write sys.stderr a message if _debug[-1]==True or optionaly force=True - use this only if no logger accessible for classic - logger.warning(message) or logger.debug(message) + use this only if no logger accessible for classic logger.warning(message) """ - fmt = "\n#### TOFIX: %s:\n%s\n" - write(title, var, force, fmt) + if _debug[-1] or isDeveloper(): + callerframerecord = inspect.stack()[1] # get info of the caller + frame = callerframerecord[0] + info = inspect.getframeinfo(frame) + fmt = "#### TOFIX - " + str(info.filename) + ":" + str(info.lineno) +\ + " (" + str(info.function) + ") ####\n %s:\n%s\n" + write(title, var, force, fmt) def push_debug(aBool): """set debug outputs activated, or not""" @@ -91,20 +146,60 @@ def pop_debug(): sys.stderr.write("\nERROR: pop_debug: too much pop.") return None + +def format_exception(msg, limit=None, trace=None): + """ + Format a stack trace and the exception information. + as traceback.format_exception(), without color + with traceback only if (_debug) or (DBG.isDeveloper()) + """ + etype, value, tb = sys.exc_info() + res = msg + if tb: + res += "\nTraceback (most recent call last):\n" + res += "".join(traceback.format_tb(tb, limit)) # [:-1]) + res += "\n" + res += "\n".join(traceback.format_exception_only(etype, value)) + return res + +def format_color_exception(msg, limit=None, trace=None): + """ + Format a stack trace and the exception information. + as traceback.format_exception(), with color + with traceback only if _debug or isDeveloper()) + """ + etype, value, tb = sys.exc_info() + if _debug[-1] or isDeveloper(): + res = "" + msg + if tb: + res += "\nTraceback (most recent call last):\n" + res += "".join(traceback.format_tb(tb, limit)) # [:-1]) + res += "\n" + res += "\n".join(traceback.format_exception_only(etype, value)) + return res + "" + else: + res = "" + msg # + "" + res += "".join(traceback.format_exception_only(etype, value)) + return res + "" + + ############################################### # utilitaires divers pour debug ############################################### -class OutStream(SIO.StringIO): - """utility class for pyconf.Config output iostream""" +class OutStream(StringIO): + """ + utility class for pyconf.Config output iostream + """ def close(self): - """because Config.__save__ calls close() stream as file + """ + because Config.__save__ calls close() stream as file keep value before lost as self.value """ self.value = self.getvalue() - SIO.StringIO.close(self) + StringIO.close(self) -class InStream(SIO.StringIO): +class InStream(StringIO): """utility class for pyconf.Config input iostream""" pass @@ -122,70 +217,91 @@ def saveConfigStd(config, aStream): config.__save__(aStream, indent) def getStrConfigStd(config): - """set string as saveConfigStd, - as file .pyconf""" + """set string as saveConfigStd, as file .pyconf""" outStream = OutStream() saveConfigStd(config, outStream) return outStream.value def getStrConfigDbg(config): - """set string as saveConfigDbg, - as (path expression evaluation) for debug""" + """ + set string as saveConfigDbg, + as (path expression evaluation) for debug + """ outStream = OutStream() saveConfigDbg(config, outStream) return outStream.value def saveConfigDbg(config, aStream, indent=0, path=""): """pyconf returns multilines (path expression evaluation) for debug""" - _saveConfigRecursiveDbg(config, aStream, indent, path) + _saveConfigRecursiveDbg(config, aStream, indent, path, 0) aStream.close() # as config.__save__() -def _saveConfigRecursiveDbg(config, aStream, indent, path): +def _saveConfigRecursiveDbg(config, aStream, indent, path, nb): """pyconf inspired from Mapping.__save__""" debug = False + nbp = nb + 1 # depth recursive if indent <= 0: indentp = 0 else: - indentp = indentp + 2 + indentp = indent + 2 + + if nbp > 10: # protection + # raise Exception("!!! ERROR: Circular reference after %s" % aStream.getvalue()) + # raise Exception("!!! ERROR: Circular reference %s" % path) + aStream.write("!!! ERROR: Circular reference after %s\n" % path) + return + indstr = indent * ' ' # '':no indent, ' ':indent strType = str(type(config)) + if debug: print("saveDbg Type %s %s" % (path, strType)) + if "Sequence" in strType: for i in range(len(config)): - _saveConfigRecursiveDbg(config[i], aStream, indentp, path+"[%i]" % i) + _saveConfigRecursiveDbg(config[i], aStream, indentp, path+"[%i]" % i, nbp) return - try: + ''' + if "Reference" in strType: + try: + #evaluate = value.resolve(config) + aStream.write("
%s%s : %s --> '%s'\n" % (indstr, path, config, str(config))) + except Exception as e: + aStream.write("
%s%s : !!! ERROR: %s !!!\n" % (indstr, path, str(e))) + return + ''' + + try: #type config, mapping order = object.__getattribute__(config, 'order') data = object.__getattribute__(config, 'data') except: aStream.write("%s%s : '%s'\n" % (indstr, path, str(config))) return - for key in sorted(order): + for key in sorted(data): #order): # data as sort alphabetical, order as initial order value = data[key] strType = str(type(value)) - if debug: print indstr + 'strType = %s' % strType, key + if debug: print('strType %s %s %s' % (path, key, strType)) if "Config" in strType: - _saveConfigRecursiveDbg(value, aStream, indentp, path+"."+key) + _saveConfigRecursiveDbg(value, aStream, indentp, path+"."+key, nbp) continue if "Mapping" in strType: - _saveConfigRecursiveDbg(value, aStream, indentp, path+"."+key) + _saveConfigRecursiveDbg(value, aStream, indentp, path+"."+key, nbp) continue if "Sequence" in strType: for i in range(len(value)): - _saveConfigRecursiveDbg(value[i], aStream, indentp, path+"."+key+"[%i]" % i) + _saveConfigRecursiveDbg(value.data[i], aStream, indentp, path+"."+key+"[%i]" % i, nbp) continue if "Expression" in strType: try: evaluate = value.evaluate(config) aStream.write("%s%s.%s : %s --> '%s'\n" % (indstr, path, key, str(value), evaluate)) except Exception as e: - aStream.write("%s%s.%s : !!! ERROR: %s !!!\n" % (indstr, path, key, e.message)) + aStream.write("%s%s.%s : !!! ERROR: %s !!!\n" % (indstr, path, key, str(e))) continue if "Reference" in strType: try: evaluate = value.resolve(config) aStream.write("%s%s.%s : %s --> '%s'\n" % (indstr, path, key, str(value), evaluate)) except Exception as e: - aStream.write("%s%s.%s : !!! ERROR: %s !!!\n" % (indstr, path, key, e.message)) + aStream.write("%s%s.%s : !!! ERROR: %s !!!\n" % (indstr, path, key, str(e))) continue if type(value) in [str, bool, int, type(None), unicode]: aStream.write("%s%s.%s : '%s'\n" % (indstr, path, key, str(value))) @@ -193,4 +309,4 @@ def _saveConfigRecursiveDbg(config, aStream, indent, path): try: aStream.write("!!! TODO fix that %s %s%s.%s : %s\n" % (type(value), indstr, path, key, str(value))) except Exception as e: - aStream.write("%s%s.%s : !!! %s\n" % (indstr, path, key, e.message)) + aStream.write("%s%s.%s : !!! %s\n" % (indstr, path, key, str(e)))