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
75 # wambeke is christian at home
76 _developers = ["xchristian", "xwambeke"]
80 """if you are a developer, sometimes you want verbose traces etc."""
81 res = src.architecture.get_user() in _developers
84 def indent(text, amount=2, ch=' '):
85 """indent multi lines message"""
87 return ''.join(padding + line for line in text.splitlines(True))
89 def isTypeConfig(var):
90 """To know if var is instance from Config/pyconf"""
92 # print "isTypeConfig" ,type, dir(var)
93 if ".pyconf.Config" in typ: return True
94 if ".pyconf.Mapping" in typ: return True
95 if ".pyconf.Sequence" in typ: return True
96 # print "NOT isTypeConfig %s" % typ
99 def write(title, var="", force=None, fmt=" %s:\n%s\n####\n"):
100 """write sys.stderr a message if _debug[-1]==True or optionaly force=True"""
101 if _debug[-1] or force:
102 callerframerecord = inspect.stack()[1] # get info of the caller
103 frame = callerframerecord[0]
104 info = inspect.getframeinfo(frame)
105 sys.stderr.write("\n#### DEBUG - %s:%s (%s) ####\n" % (info.filename, info.lineno, info.function))
108 if isTypeConfig(var):
109 sys.stderr.write(fmt % (title, indent(getStrConfigDbg(var))))
111 if 'UnittestStream' in typ:
112 sys.stderr.write(fmt % (title, indent(var.getLogs())))
114 if tvar is not str and tvar is not unicode:
115 sys.stderr.write(fmt % (title, indent(PP.pformat(var))))
117 sys.stderr.write(fmt % (title, indent(var)))
121 def tofix(title, var="", force=None):
123 write sys.stderr a message if _debug[-1]==True or optionaly force=True
124 use this only if no logger accessible for classic logger.warning(message)
126 if _debug[-1] or isDeveloper():
127 callerframerecord = inspect.stack()[1] # get info of the caller
128 frame = callerframerecord[0]
129 info = inspect.getframeinfo(frame)
130 fmt = "#### TOFIX - " + str(info.filename) + ":" + str(info.lineno) +\
131 " (" + str(info.function) + ") ####\n %s:\n%s\n"
132 write(title, var, force, fmt)
134 def push_debug(aBool):
135 """set debug outputs activated, or not"""
139 """restore previous debug outputs status"""
143 sys.stderr.write("\nERROR: pop_debug: too much pop.")
147 def format_exception(msg, limit=None, trace=None):
149 Format a stack trace and the exception information.
150 as traceback.format_exception(), without color
151 with traceback only if (_debug) or (DBG._user in DBG._developers)
153 etype, value, tb = sys.exc_info()
156 res += "\nTraceback (most recent call last):\n"
157 res += "".join(traceback.format_tb(tb, limit)) # [:-1])
159 res += "\n".join(traceback.format_exception_only(etype, value))
162 def format_color_exception(msg, limit=None, trace=None):
164 Format a stack trace and the exception information.
165 as traceback.format_exception(), with color
166 with traceback only if _debug or isDeveloper())
168 etype, value, tb = sys.exc_info()
169 if _debug[-1] or isDeveloper():
172 res += "<yellow>\nTraceback (most recent call last):\n"
173 res += "".join(traceback.format_tb(tb, limit)) # [:-1])
175 res += "\n".join(traceback.format_exception_only(etype, value))
176 return res + "<reset>"
178 res = "<red>" + msg # + "<bright>"
179 res += "".join(traceback.format_exception_only(etype, value))
180 return res + "<reset>"
183 ###############################################
184 # utilitaires divers pour debug
185 ###############################################
187 class OutStream(StringIO):
189 utility class for pyconf.Config output iostream
193 because Config.__save__ calls close() stream as file
194 keep value before lost as self.value
196 self.value = self.getvalue()
199 class InStream(StringIO):
200 """utility class for pyconf.Config input iostream"""
204 """get string for environment variables representation"""
206 for i in sorted(os.environ):
207 res += "%s : %s\n" % (i, os.environ[i])
210 # save as initial Config.save() moved as Config.__save__()
211 def saveConfigStd(config, aStream):
212 """returns as file .pyconf"""
214 config.__save__(aStream, indent)
216 def getStrConfigStd(config):
217 """set string as saveConfigStd, as file .pyconf"""
218 outStream = OutStream()
219 saveConfigStd(config, outStream)
220 return outStream.value
222 def getStrConfigDbg(config):
224 set string as saveConfigDbg,
225 as (path expression evaluation) for debug
227 outStream = OutStream()
228 saveConfigDbg(config, outStream)
229 return outStream.value
231 def saveConfigDbg(config, aStream, indent=0, path=""):
232 """pyconf returns multilines (path expression evaluation) for debug"""
233 _saveConfigRecursiveDbg(config, aStream, indent, path, 0)
234 aStream.close() # as config.__save__()
236 def _saveConfigRecursiveDbg(config, aStream, indent, path, nb):
237 """pyconf inspired from Mapping.__save__"""
239 nbp = nb + 1 # depth recursive
245 if nbp > 10: # protection
246 # raise Exception("!!! ERROR: Circular reference after %s" % aStream.getvalue())
247 # raise Exception("!!! ERROR: Circular reference %s" % path)
248 aStream.write("<red>!!! ERROR: Circular reference after %s<reset>\n" % path)
251 indstr = indent * ' ' # '':no indent, ' ':indent
252 strType = str(type(config))
253 if debug: print("saveDbg Type %s %s" % (path, strType))
255 if "Sequence" in strType:
256 for i in range(len(config)):
257 _saveConfigRecursiveDbg(config[i], aStream, indentp, path+"[%i]" % i, nbp)
260 if "Reference" in strType:
262 #evaluate = value.resolve(config)
263 aStream.write("<header>%s%s<reset> : %s <yellow>--> '%s'<reset>\n" % (indstr, path, config, str(config)))
264 except Exception as e:
265 aStream.write("<header>%s%s<reset> : <red>!!! ERROR: %s !!!<reset>\n" % (indstr, path, str(e)))
269 try: #type config, mapping
270 order = object.__getattribute__(config, 'order')
271 data = object.__getattribute__(config, 'data')
273 aStream.write("%s%s : '%s'\n" % (indstr, path, str(config)))
275 for key in sorted(data): #order): # data as sort alphabetical, order as initial order
277 strType = str(type(value))
278 if debug: print('strType %s %s %s' % (path, key, strType))
279 if "Config" in strType:
280 _saveConfigRecursiveDbg(value, aStream, indentp, path+"."+key, nbp)
282 if "Mapping" in strType:
283 _saveConfigRecursiveDbg(value, aStream, indentp, path+"."+key, nbp)
285 if "Sequence" in strType:
286 for i in range(len(value)):
287 _saveConfigRecursiveDbg(value.data[i], aStream, indentp, path+"."+key+"[%i]" % i, nbp)
289 if "Expression" in strType:
291 evaluate = value.evaluate(config)
292 aStream.write("%s%s.%s : %s --> '%s'\n" % (indstr, path, key, str(value), evaluate))
293 except Exception as e:
294 aStream.write("%s%s.%s : !!! ERROR: %s !!!\n" % (indstr, path, key, str(e)))
296 if "Reference" in strType:
298 evaluate = value.resolve(config)
299 aStream.write("%s%s.%s : %s --> '%s'\n" % (indstr, path, key, str(value), evaluate))
300 except Exception as e:
301 aStream.write("%s%s.%s : !!! ERROR: %s !!!\n" % (indstr, path, key, str(e)))
303 if type(value) in [str, bool, int, type(None), unicode]:
304 aStream.write("%s%s.%s : '%s'\n" % (indstr, path, key, str(value)))
307 aStream.write("!!! TODO fix that %s %s%s.%s : %s\n" % (type(value), indstr, path, key, str(value)))
308 except Exception as e:
309 aStream.write("%s%s.%s : !!! %s\n" % (indstr, path, key, str(e)))