Salome HOME
fix archive not found in product
[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 debug messages in sys.stderr for salomeTools
23 - show pretty print debug representation from instances of SAT classes
24   (pretty print src.pyconf.Config), and python dict/list etc. (as 'aVariable')
25
26 WARNING: obviously 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 StringIO as SIO
57 import pprint as PP
58
59 _debug = [False] #support push/pop for temporary activate debug outputs
60
61 def indent(text, amount=2, ch=' '):
62     """indent multi lines message"""
63     padding = amount * ch
64     return ''.join(padding + line for line in text.splitlines(True))
65
66 def write(title, var="", force=None, fmt="\n#### DEBUG: %s:\n%s\n"):
67     """write sys.stderr a message if _debug[-1]==True or optionaly force=True"""
68     if _debug[-1] or force:
69         if 'src.pyconf.' in str(type(var)): 
70             sys.stderr.write(fmt % (title, indent(getStrConfigDbg(var))))
71         elif type(var) is not str:
72             sys.stderr.write(fmt % (title, indent(PP.pformat(var))))
73         else:
74             sys.stderr.write(fmt % (title, indent(var)))
75     return
76
77 def tofix(title, var="", force=None):
78     """
79     write sys.stderr a message if _debug[-1]==True or optionaly force=True
80     use this only if no logger accessible for classic 
81     logger.warning(message) or logger.debug(message)
82     """
83     fmt = "\n#### TOFIX: %s:\n%s\n"
84     write(title, var, force, fmt)
85
86 def push_debug(aBool):
87     """set debug outputs activated, or not"""
88     _debug.append(aBool)
89
90 def pop_debug():
91     """restore previous debug outputs status"""
92     if len(_debug) > 1:
93         return _debug.pop()
94     else:
95         sys.stderr.write("\nERROR: pop_debug: too much pop.")
96         return None
97
98 ###############################################
99 # utilitaires divers pour debug
100 ###############################################
101
102 class OutStream(SIO.StringIO):
103     """utility class for pyconf.Config output iostream"""
104     def close(self):
105       """because Config.__save__ calls close() stream as file
106       keep value before lost as self.value
107       """
108       self.value = self.getvalue()
109       SIO.StringIO.close(self)
110     
111 class InStream(SIO.StringIO):
112     """utility class for pyconf.Config input iostream"""
113     pass
114
115 def getLocalEnv():
116     """get string for environment variables representation"""
117     res = ""
118     for i in sorted(os.environ):
119         res += "%s : %s\n" % (i, os.environ[i])
120     return res
121
122 # save as initial Config.save() moved as Config.__save__() 
123 def saveConfigStd(config, aStream):
124     """returns as file .pyconf"""
125     indent =  0
126     config.__save__(aStream, indent) 
127
128 def getStrConfigStd(config):
129     """set string as saveConfigStd, 
130     as file .pyconf"""
131     outStream = OutStream()
132     saveConfigStd(config, outStream)
133     return outStream.value
134
135 def getStrConfigDbg(config):
136     """set string as saveConfigDbg, 
137     as (path expression evaluation) for debug"""
138     outStream = OutStream()
139     saveConfigDbg(config, outStream)
140     return outStream.value
141
142 def saveConfigDbg(config, aStream, indent=0, path=""):
143     """pyconf returns multilines (path expression evaluation) for debug"""
144     _saveConfigRecursiveDbg(config, aStream, indent, path)
145     aStream.close() # as config.__save__()
146
147 def _saveConfigRecursiveDbg(config, aStream, indent, path):
148     """pyconf inspired from Mapping.__save__"""
149     debug = False
150     if indent <= 0: 
151       indentp = 0
152     else:
153       indentp = indentp + 2
154     indstr = indent * ' ' # '':no indent, ' ':indent
155     strType = str(type(config))
156     if "Sequence" in strType:
157       for i in range(len(config)):
158         _saveConfigRecursiveDbg(config[i], aStream, indentp, path+"[%i]" % i)
159       return
160     try: 
161       order = object.__getattribute__(config, 'order')
162       data = object.__getattribute__(config, 'data')
163     except:
164       aStream.write("%s%s : '%s'\n" % (indstr, path, str(config)))
165       return     
166     for key in sorted(order):
167       value = data[key]
168       strType = str(type(value))
169       if debug: print indstr + 'strType = %s' % strType, key
170       if "Config" in strType:
171         _saveConfigRecursiveDbg(value, aStream, indentp, path+"."+key)
172         continue
173       if "Mapping" in strType:
174         _saveConfigRecursiveDbg(value, aStream, indentp, path+"."+key)
175         continue
176       if "Sequence" in strType:
177         for i in range(len(value)):
178           _saveConfigRecursiveDbg(value[i], aStream, indentp, path+"."+key+"[%i]" % i)
179         continue
180       if "Expression" in strType:
181         try:
182           evaluate = value.evaluate(config)
183           aStream.write("%s%s.%s : %s --> '%s'\n" % (indstr, path, key, str(value), evaluate))
184         except Exception as e:      
185           aStream.write("%s%s.%s : !!! ERROR: %s !!!\n" % (indstr, path, key, e.message))     
186         continue
187       if "Reference" in strType:
188         try:
189           evaluate = value.resolve(config)
190           aStream.write("%s%s.%s : %s --> '%s'\n" % (indstr, path, key, str(value), evaluate))
191         except Exception as e:  
192           aStream.write("%s%s.%s : !!! ERROR: %s !!!\n" % (indstr, path, key, e.message))     
193         continue
194       if type(value) in [str, bool, int, type(None), unicode]:
195         aStream.write("%s%s.%s : '%s'\n" % (indstr, path, key, str(value)))
196         continue
197       try:
198         aStream.write("!!! TODO fix that %s %s%s.%s : %s\n" % (type(value), indstr, path, key, str(value)))
199       except Exception as e:      
200         aStream.write("%s%s.%s : !!! %s\n" % (indstr, path, key, e.message))