4 # Copyright (C) 2010-2018 CEA/DEN
6 # This library is free software; you can redistribute it and/or
7 # modify it under the terms of the GNU Lesser General Public
8 # License as published by the Free Software Foundation; either
9 # version 2.1 of the License.
11 # This library is distributed in the hope that it will be useful,
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 # Lesser General Public License for more details.
16 # You should have received a copy of the GNU Lesser General Public
17 # License along with this library; if not, write to the Free Software
18 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 This file assume DEBUG functionalities use.
22 Print salomeTools debug messages in sys.stderr.
23 Show pretty print debug representation from instances of SAT classes
24 (pretty print src.pyconf.Config)
26 | Warning: supposedly show messages in SAT development phase, not production
29 | >> import debug as DBG
30 | >> DBG.write("aTitle", aVariable) # not shown in production
31 | >> DBG.write("aTitle", aVariable, True) # unconditionaly shown (as show=True)
33 | to set show message as development phase:
34 | >> DBG.push_debug(True)
36 | to set no show message as production phase:
37 | >> DBG.push_debug(False)
39 | to set show message temporary as development phase, only in a method:
40 | >> def aMethodToDebug(...):
41 | >> DBG.push_debug(True) #force show as appended status
42 | >> etc. method code with some DBG.write()
43 | >> DBG.pop_debug() #restore previous status (show or not show)
46 | to set a message for future fix, as temporary problem to not forget:
47 | DBG.tofix("aTitle", aVariable, True/False) #True/False in production shown, or not
49 | in command line interface you could redirect stderr to file 'myDebug.log':
50 | >> sat compile ... 2> myDebug.log # only stderr
51 | >> sat compile ... &> myDebug.log # stdout and stderr
61 # Compatibility python 2/3 for unicode
67 # Compatibility python 2/3 for StringIO
69 from StringIO import StringIO
71 from io import StringIO
73 _debug = [False] #support push/pop for temporary activate debug outputs
78 if you are a developer, sometimes you want verbose traces unconditionally
79 export SAT_DEVELOPER_MODE=1 before launch sat command to do that
81 res = os.getenv("SAT_DEVELOPER_MODE", "0")
82 if res in "YES yes 1 Y y".split():
87 def indent(text, amount=2, ch=' '):
88 """indent multi lines message"""
90 return ''.join(padding + line for line in text.splitlines(True))
92 def isTypeConfig(var):
93 """To know if var is instance from Config/pyconf"""
95 # print "isTypeConfig" ,type, dir(var)
96 if ".pyconf.Config" in typ: return True
97 if ".pyconf.Mapping" in typ: return True
98 if ".pyconf.Sequence" in typ: return True
99 # print "NOT isTypeConfig %s" % typ
102 def write(title, var="", force=None, fmt=" %s:\n%s\n####\n"):
103 """write sys.stderr a message if _debug[-1]==True or optionaly force=True"""
104 if _debug[-1] or force:
105 callerframerecord = inspect.stack()[1] # get info of the caller
106 frame = callerframerecord[0]
107 info = inspect.getframeinfo(frame)
108 sys.stderr.write("\n#### DEBUG - %s:%s (%s) ####\n" % (info.filename, info.lineno, info.function))
111 if isTypeConfig(var):
112 sys.stderr.write(fmt % (title, indent(getStrConfigDbg(var))))
114 if 'UnittestStream' in typ:
115 sys.stderr.write(fmt % (title, indent(var.getLogs())))
117 if tvar is not str and tvar is not unicode:
118 sys.stderr.write(fmt % (title, indent(PP.pformat(var))))
120 sys.stderr.write(fmt % (title, indent(var)))
124 def tofix(title, var="", force=None):
126 write sys.stderr a message if _debug[-1]==True or optionaly force=True
127 use this only if no logger accessible for classic logger.warning(message)
129 if _debug[-1] or isDeveloper():
130 callerframerecord = inspect.stack()[1] # get info of the caller
131 frame = callerframerecord[0]
132 info = inspect.getframeinfo(frame)
133 fmt = "#### TOFIX - " + str(info.filename) + ":" + str(info.lineno) +\
134 " (" + str(info.function) + ") ####\n %s:\n%s\n"
135 write(title, var, force, fmt)
137 def push_debug(aBool):
138 """set debug outputs activated, or not"""
142 """restore previous debug outputs status"""
146 sys.stderr.write("\nERROR: pop_debug: too much pop.")
150 def format_exception(msg, limit=None, trace=None):
152 Format a stack trace and the exception information.
153 as traceback.format_exception(), without color
154 with traceback only if (_debug) or (DBG.isDeveloper())
156 etype, value, tb = sys.exc_info()
159 res += "\nTraceback (most recent call last):\n"
160 res += "".join(traceback.format_tb(tb, limit)) # [:-1])
162 res += "\n".join(traceback.format_exception_only(etype, value))
165 def format_color_exception(msg, limit=None, trace=None):
167 Format a stack trace and the exception information.
168 as traceback.format_exception(), with color
169 with traceback only if _debug or isDeveloper())
171 etype, value, tb = sys.exc_info()
172 if _debug[-1] or isDeveloper():
175 res += "<yellow>\nTraceback (most recent call last):\n"
176 res += "".join(traceback.format_tb(tb, limit)) # [:-1])
178 res += "\n".join(traceback.format_exception_only(etype, value))
179 return res + "<reset>"
181 res = "<red>" + msg # + "<bright>"
182 res += "".join(traceback.format_exception_only(etype, value))
183 return res + "<reset>"
186 ###############################################
187 # utilitaires divers pour debug
188 ###############################################
190 class OutStream(StringIO):
192 utility class for pyconf.Config output iostream
196 because Config.__save__ calls close() stream as file
197 keep value before lost as self.value
199 self.value = self.getvalue()
202 class InStream(StringIO):
203 """utility class for pyconf.Config input iostream"""
207 """get string for environment variables representation"""
209 for i in sorted(os.environ):
210 res += "%s : %s\n" % (i, os.environ[i])
213 # save as initial Config.save() moved as Config.__save__()
214 def saveConfigStd(config, aStream):
215 """returns as file .pyconf"""
217 config.__save__(aStream, indent)
219 def getStrConfigStd(config):
220 """set string as saveConfigStd, as file .pyconf"""
221 outStream = OutStream()
222 saveConfigStd(config, outStream)
223 return outStream.value
225 def getStrConfigDbg(config):
227 set string as saveConfigDbg,
228 as (path expression evaluation) for debug
230 outStream = OutStream()
231 saveConfigDbg(config, outStream)
232 return outStream.value
234 def saveConfigDbg(config, aStream, indent=0, path=""):
235 """pyconf returns multilines (path expression evaluation) for debug"""
236 _saveConfigRecursiveDbg(config, aStream, indent, path, 0)
237 aStream.close() # as config.__save__()
239 def _saveConfigRecursiveDbg(config, aStream, indent, path, nb):
240 """pyconf inspired from Mapping.__save__"""
242 nbp = nb + 1 # depth recursive
248 if nbp > 10: # protection
249 # raise Exception("!!! ERROR: Circular reference after %s" % aStream.getvalue())
250 # raise Exception("!!! ERROR: Circular reference %s" % path)
251 aStream.write("<red>!!! ERROR: Circular reference after %s<reset>\n" % path)
254 indstr = indent * ' ' # '':no indent, ' ':indent
255 strType = str(type(config))
256 if debug: print("saveDbg Type %s %s" % (path, strType))
258 if "Sequence" in strType:
259 for i in range(len(config)):
260 _saveConfigRecursiveDbg(config[i], aStream, indentp, path+"[%i]" % i, nbp)
263 if "Reference" in strType:
265 #evaluate = value.resolve(config)
266 aStream.write("<header>%s%s<reset> : %s <yellow>--> '%s'<reset>\n" % (indstr, path, config, str(config)))
267 except Exception as e:
268 aStream.write("<header>%s%s<reset> : <red>!!! ERROR: %s !!!<reset>\n" % (indstr, path, str(e)))
272 try: #type config, mapping
273 order = object.__getattribute__(config, 'order')
274 data = object.__getattribute__(config, 'data')
276 aStream.write("%s%s : '%s'\n" % (indstr, path, str(config)))
278 for key in sorted(data): #order): # data as sort alphabetical, order as initial order
280 strType = str(type(value))
281 if debug: print('strType %s %s %s' % (path, key, strType))
282 if "Config" in strType:
283 _saveConfigRecursiveDbg(value, aStream, indentp, path+"."+key, nbp)
285 if "Mapping" in strType:
286 _saveConfigRecursiveDbg(value, aStream, indentp, path+"."+key, nbp)
288 if "Sequence" in strType:
289 for i in range(len(value)):
290 _saveConfigRecursiveDbg(value.data[i], aStream, indentp, path+"."+key+"[%i]" % i, nbp)
292 if "Expression" in strType:
294 evaluate = value.evaluate(config)
295 aStream.write("%s%s.%s : %s --> '%s'\n" % (indstr, path, key, str(value), evaluate))
296 except Exception as e:
297 aStream.write("%s%s.%s : !!! ERROR: %s !!!\n" % (indstr, path, key, str(e)))
299 if "Reference" in strType:
301 evaluate = value.resolve(config)
302 aStream.write("%s%s.%s : %s --> '%s'\n" % (indstr, path, key, str(value), evaluate))
303 except Exception as e:
304 aStream.write("%s%s.%s : !!! ERROR: %s !!!\n" % (indstr, path, key, str(e)))
306 if type(value) in [str, bool, int, type(None), unicode]:
307 aStream.write("%s%s.%s : '%s'\n" % (indstr, path, key, str(value)))
310 aStream.write("!!! TODO fix that %s %s%s.%s : %s\n" % (type(value), indstr, path, key, str(value)))
311 except Exception as e:
312 aStream.write("%s%s.%s : !!! %s\n" % (indstr, path, key, str(e)))