Salome HOME
add src/versionMinorMajorPatch.py, not used
[tools/sat.git] / src / debug.py
1 #!/usr/bin/env python
2 #-*- coding:utf-8 -*-
3
4 #  Copyright (C) 2010-2018  CEA/DEN
5 #
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.
10 #
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.
15 #
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
19
20 """
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)
25
26 | Warning: supposedly show messages in SAT development phase, not production
27
28 | Usage:
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)
32
33 | to set show message as development phase:
34 | >> DBG.push_debug(True)
35
36 | to set no show message as production phase:
37 | >> DBG.push_debug(False)
38
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)
44 | >>   return
45
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
48
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
52 """
53
54 import os
55 import sys
56 import traceback
57 import StringIO as SIO
58 import pprint as PP
59
60 _debug = [False] #support push/pop for temporary activate debug outputs
61
62 _user = os.environ['USER']
63 # wambeke is christian at home
64 _developers = ["christian", "wambeke", "crouzet"] # crouzet, kloss ...
65
66
67 def isDeveloper():
68     """if you are a developer, sometimes you want verbose traces etc."""
69     res = _user in _developers
70     return res
71
72 def indent(text, amount=2, ch=' '):
73     """indent multi lines message"""
74     padding = amount * ch
75     return ''.join(padding + line for line in text.splitlines(True))
76
77 def isTypeConfig(var):
78     """To know if var is instance from Config/pyconf"""
79     typ = str(type(var))
80     # print "isTypeConfig" ,type, dir(var)
81     if ".pyconf.Config" in typ: return True
82     if ".pyconf.Mapping" in typ: return True
83     if ".pyconf.Sequence" in typ: return True
84     # print "NOT isTypeConfig %s" % typ
85     return False
86     
87 def write(title, var="", force=None, fmt="\n#### DEBUG: %s:\n%s\n"):
88     """write sys.stderr a message if _debug[-1]==True or optionaly force=True"""
89     if _debug[-1] or force:
90       tvar = type(var)
91       typ = str(tvar)
92       if isTypeConfig(var):
93         sys.stderr.write(fmt % (title, indent(getStrConfigDbg(var))))
94         return
95       if 'UnittestStream' in typ:
96         sys.stderr.write(fmt % (title, indent(var.getLogs())))
97         return  
98       if tvar is not str and tvar is not unicode:
99         sys.stderr.write(fmt % (title, indent(PP.pformat(var))))
100         return
101       sys.stderr.write(fmt % (title, indent(var)))
102       return
103     return
104
105 def tofix(title, var="", force=None):
106     """
107     write sys.stderr a message if _debug[-1]==True or optionaly force=True
108     use this only if no logger accessible for classic logger.warning(message)
109     """
110     fmt = "\n#### TOFIX: %s:\n%s\n"
111     write(title, var, force, fmt)
112
113 def push_debug(aBool):
114     """set debug outputs activated, or not"""
115     _debug.append(aBool)
116
117 def pop_debug():
118     """restore previous debug outputs status"""
119     if len(_debug) > 1:
120         return _debug.pop()
121     else:
122         sys.stderr.write("\nERROR: pop_debug: too much pop.")
123         return None
124
125
126 def format_exception(msg, limit=None, trace=None):
127   """
128   Format a stack trace and the exception information.
129   as traceback.format_exception(), without color
130   with traceback only if (_debug) or (DBG._user in DBG._developers)
131   """
132   etype, value, tb = sys.exc_info()
133   if _debug[-1] or isDeveloper():
134     res = msg
135     if tb:
136       res += "\nTraceback (most recent call last):\n"
137       res += "".join(traceback.format_tb(tb, limit))  # [:-1])
138     res += "\n"
139     res += "\n".join(traceback.format_exception_only(etype, value))
140     return res
141   else:
142     res = msg
143     res += "".join(traceback.format_exception_only(etype, value))
144     return res
145
146 def format_color_exception(msg, limit=None, trace=None):
147   """
148   Format a stack trace and the exception information.
149   as traceback.format_exception(), with color
150   with traceback only if _debug or isDeveloper())
151   """
152   etype, value, tb = sys.exc_info()
153   if _debug[-1] or isDeveloper():
154     res = "<red>" + msg
155     if tb:
156       res += "<yellow>\nTraceback (most recent call last):\n"
157       res += "".join(traceback.format_tb(tb, limit))  # [:-1])
158     res += "\n<red>"
159     res += "\n".join(traceback.format_exception_only(etype, value))
160     return res + "<reset>"
161   else:
162     res = "<red>" + msg  # + "<bright>"
163     res += "".join(traceback.format_exception_only(etype, value))
164     return res + "<reset>"
165
166
167 ###############################################
168 # utilitaires divers pour debug
169 ###############################################
170
171 class OutStream(SIO.StringIO):
172     """
173     utility class for pyconf.Config output iostream
174     """
175     def close(self):
176       """
177       because Config.__save__ calls close() stream as file
178       keep value before lost as self.value
179       """
180       self.value = self.getvalue()
181       SIO.StringIO.close(self)
182     
183 class InStream(SIO.StringIO):
184     """utility class for pyconf.Config input iostream"""
185     pass
186
187 def getLocalEnv():
188     """get string for environment variables representation"""
189     res = ""
190     for i in sorted(os.environ):
191         res += "%s : %s\n" % (i, os.environ[i])
192     return res
193
194 # save as initial Config.save() moved as Config.__save__() 
195 def saveConfigStd(config, aStream):
196     """returns as file .pyconf"""
197     indent =  0
198     config.__save__(aStream, indent) 
199
200 def getStrConfigStd(config):
201     """set string as saveConfigStd, as file .pyconf"""
202     outStream = OutStream()
203     saveConfigStd(config, outStream)
204     return outStream.value
205
206 def getStrConfigDbg(config):
207     """
208     set string as saveConfigDbg, 
209     as (path expression evaluation) for debug
210     """
211     outStream = OutStream()
212     saveConfigDbg(config, outStream)
213     return outStream.value
214
215 def saveConfigDbg(config, aStream, indent=0, path=""):
216     """pyconf returns multilines (path expression evaluation) for debug"""
217     _saveConfigRecursiveDbg(config, aStream, indent, path, 0)
218     aStream.close() # as config.__save__()
219
220 def _saveConfigRecursiveDbg(config, aStream, indent, path, nb):
221     """pyconf inspired from Mapping.__save__"""
222     debug = False
223     nbp = nb + 1 # depth recursive
224     if indent <= 0: 
225       indentp = 0
226     else:
227       indentp = indent + 2
228       
229     if nbp > 10: # protection
230       # raise Exception("!!! ERROR: Circular reference after %s" % aStream.getvalue())
231       # raise Exception("!!! ERROR: Circular reference %s" % path)
232       aStream.write("<red>!!! ERROR: Circular reference after %s<reset>\n" % path)
233       return
234     
235     indstr = indent * ' ' # '':no indent, ' ':indent
236     strType = str(type(config))
237     if debug: print("saveDbg Type %s %s" % (path, strType))
238     
239     if "Sequence" in strType:
240       for i in range(len(config)):
241         _saveConfigRecursiveDbg(config[i], aStream, indentp, path+"[%i]" % i, nbp)
242       return
243     '''
244     if "Reference" in strType:
245       try:
246         #evaluate = value.resolve(config)
247         aStream.write("<header>%s%s<reset> : %s <yellow>--> '%s'<reset>\n" % (indstr, path, config, str(config)))
248       except Exception as e:  
249         aStream.write("<header>%s%s<reset> : <red>!!! ERROR: %s !!!<reset>\n" % (indstr, path, e.message))     
250       return
251     '''
252     
253     try: #type config, mapping
254       order = object.__getattribute__(config, 'order')
255       data = object.__getattribute__(config, 'data')
256     except:
257       aStream.write("%s%s : '%s'\n" % (indstr, path, str(config)))
258       return     
259     for key in sorted(data): #order): # data as sort alphabetical, order as initial order
260       value = data[key]
261       strType = str(type(value))
262       if debug: print('strType %s %s %s' % (path, key, strType))
263       if "Config" in strType:
264         _saveConfigRecursiveDbg(value, aStream, indentp, path+"."+key, nbp)
265         continue
266       if "Mapping" in strType:
267         _saveConfigRecursiveDbg(value, aStream, indentp, path+"."+key, nbp)
268         continue
269       if "Sequence" in strType:
270         for i in range(len(value)):
271           _saveConfigRecursiveDbg(value.data[i], aStream, indentp, path+"."+key+"[%i]" % i, nbp)
272         continue
273       if "Expression" in strType:
274         try:
275           evaluate = value.evaluate(config)
276           aStream.write("%s%s.%s : %s --> '%s'\n" % (indstr, path, key, str(value), evaluate))
277         except Exception as e:      
278           aStream.write("%s%s.%s : !!! ERROR: %s !!!\n" % (indstr, path, key, e.message))     
279         continue
280       if "Reference" in strType:
281         try:
282           evaluate = value.resolve(config)
283           aStream.write("%s%s.%s : %s --> '%s'\n" % (indstr, path, key, str(value), evaluate))
284         except Exception as e:  
285           aStream.write("%s%s.%s : !!! ERROR: %s !!!\n" % (indstr, path, key, e.message))     
286         continue
287       if type(value) in [str, bool, int, type(None), unicode]:
288         aStream.write("%s%s.%s : '%s'\n" % (indstr, path, key, str(value)))
289         continue
290       try:
291         aStream.write("!!! TODO fix that %s %s%s.%s : %s\n" % (type(value), indstr, path, key, str(value)))
292       except Exception as e:      
293         aStream.write("%s%s.%s : !!! %s\n" % (indstr, path, key, e.message))