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