#!/usr/bin/env python
#-*- coding:utf-8 -*-
# Copyright (C) 2010-2018 CEA/DEN
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
"""
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: 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 traceback
import StringIO as SIO
import pprint as PP
_debug = [False] #support push/pop for temporary activate debug outputs
_user = os.environ['USER']
# wambeke is christian at home
_developpers = ["christian", "wambeke", "crouzet"] # crouzet, kloss ...
[docs]def indent(text, amount=2, ch=' '):
"""indent multi lines message"""
padding = amount * ch
return ''.join(padding + line for line in text.splitlines(True))
[docs]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
[docs]def write(title, var="", force=None, fmt="\n#### DEBUG: %s:\n%s\n"):
"""write sys.stderr a message if _debug[-1]==True or optionaly force=True"""
if _debug[-1] or force:
tvar = type(var)
typ = str(tvar)
if isTypeConfig(var):
sys.stderr.write(fmt % (title, indent(COLS.toColor(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
[docs]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)
"""
fmt = "\n#### TOFIX: %s:\n%s\n"
write(title, var, force, fmt)
[docs]def push_debug(aBool):
"""set debug outputs activated, or not"""
_debug.append(aBool)
[docs]def pop_debug():
"""restore previous debug outputs status"""
if len(_debug) > 1:
return _debug.pop()
else:
sys.stderr.write("\nERROR: pop_debug: too much pop.")
return None
###############################################
# utilitaires divers pour debug
###############################################
[docs]class OutStream(SIO.StringIO):
"""
utility class for pyconf.Config output iostream
"""
[docs] def close(self):
"""
because Config.__save__ calls close() stream as file
keep value before lost as self.value
"""
self.value = self.getvalue()
SIO.StringIO.close(self)
[docs]class InStream(SIO.StringIO):
"""utility class for pyconf.Config input iostream"""
pass
[docs]def getLocalEnv():
"""get string for environment variables representation"""
res = ""
for i in sorted(os.environ):
res += "%s : %s\n" % (i, os.environ[i])
return res
# save as initial Config.save() moved as Config.__save__()
[docs]def saveConfigStd(config, aStream):
"""returns as file .pyconf"""
indent = 0
config.__save__(aStream, indent)
[docs]def getStrConfigStd(config):
"""set string as saveConfigStd, as file .pyconf"""
outStream = OutStream()
saveConfigStd(config, outStream)
return outStream.value
[docs]def getStrConfigDbg(config):
"""
set string as saveConfigDbg,
as (path expression evaluation) for debug
"""
outStream = OutStream()
saveConfigDbg(config, outStream)
return outStream.value
[docs]def saveConfigDbg(config, aStream, indent=0, path=""):
"""pyconf returns multilines (path expression evaluation) for debug"""
_saveConfigRecursiveDbg(config, aStream, indent, path, 0)
aStream.close() # as config.__save__()
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 = indent + 2
if nbp > 10: # protection
# raise Exception("!!! ERROR: Circular reference after %s" % aStream.getvalue())
# raise Exception("!!! ERROR: Circular reference %s" % path)
aStream.write("<red>!!! ERROR: Circular reference after %s<reset>\n" % path)
return
indstr = indent * ' ' # '':no indent, ' ':indent
strType = str(type(config))
if debug: print "saveDbg Type", path, strType
if "Sequence" in strType:
for i in range(len(config)):
_saveConfigRecursiveDbg(config[i], aStream, indentp, path+"[%i]" % i, nbp)
return
'''
if "Reference" in strType:
try:
#evaluate = value.resolve(config)
aStream.write("<header>%s%s<reset> : %s <yellow>--> '%s'<reset>\n" % (indstr, path, config, str(config)))
except Exception as e:
aStream.write("<header>%s%s<reset> : <red>!!! ERROR: %s !!!<reset>\n" % (indstr, path, e.message))
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(data): #order): # data as sort alphabetical, order as initial order
value = data[key]
strType = str(type(value))
if debug: print 'strType', path, key, strType
if "Config" in strType:
_saveConfigRecursiveDbg(value, aStream, indentp, path+"."+key, nbp)
continue
if "Mapping" in strType:
_saveConfigRecursiveDbg(value, aStream, indentp, path+"."+key, nbp)
continue
if "Sequence" in strType:
for i in range(len(value)):
_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))
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))
continue
if type(value) in [str, bool, int, type(None), unicode]:
aStream.write("%s%s.%s : '%s'\n" % (indstr, path, key, str(value)))
continue
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))