FIX: Python exception handling across different versions
[freefoam.git] / tutorials / Allrun.py.in
blobdb8ba59cc6b8ed239be706939b484e1f55365911
1 #!@PYTHON_EXECUTABLE@
3 import sys
4 import os
5 import os.path
6 import imp
7 import inspect
8 import re
9 sys.path.insert(0, '@FOAM_PYTHON_DIR@')
10 from FreeFOAM.compat import *
11 import FreeFOAM.tutorial
12 import FreeFOAM.util
14 class LogParserError(Exception):
15 """Thrown when parsing of the log file failed."""
16 def __init__(self, msg):
17 Exception.__init__(self, msg)
18 def __str__(self):
19 return self.args[0]
22 class AllTutorialsRunner(FreeFOAM.tutorial.TutorialRunner):
23 def __init__(self):
24 FreeFOAM.tutorial.TutorialRunner.__init__(self)
25 self.tutorials_dir = os.path.abspath(os.path.dirname(sys.argv[0]))
27 def main(self):
28 # prevent python from creating byte-compiled files (python >= 2.6)
29 try:
30 sys.dont_write_bytecode = True
31 except:
32 pass
33 # Recursively run all tutorials
34 pwd = os.getcwd()
35 i = 0
36 for parent, dirs, files in os.walk(self.tutorials_dir):
37 if parent == self.tutorials_dir:
38 continue
39 if 'Allrun' in files:
40 # don't recurse
41 del dirs[:]
42 i += 1
43 os.chdir(parent)
44 f = open('Allrun', 'rt')
45 try:
46 m = imp.load_module('Allrun'+str(i), f, f.name,
47 (os.path.splitext(f.name)[1], 'r', imp.PY_SOURCE))
48 if hasattr(m, 'register_cases') and inspect.isfunction(
49 m.register_cases):
50 m.register_cases(self)
51 else:
52 for d in dir(m):
53 a = getattr(m, d)
54 if inspect.isclass(a) and (
55 FreeFOAM.tutorial.CaseRunner in inspect.getmro(a)):
56 self.add_case(a())
57 except Exception:
58 e = sys.exc_info()[1]
59 FreeFOAM.util.cecho(
60 '${RED}*** Error ***${NORMAL} In '+os.path.abspath(f.name))
61 raise
62 os.chdir(pwd)
64 ret = FreeFOAM.tutorial.TutorialRunner.main(self)
66 if not self.did_run:
67 return ret
69 # Analyse all log files
70 testReport = open(
71 os.path.join(self.tutorials_dir, 'testLoopReport'), 'wt')
72 logs = open(os.path.join(self.tutorials_dir, 'logs'), 'wt')
73 for parent, dirs, files in os.walk(self.tutorials_dir):
74 for f in files:
75 if f[0:4] == 'log.':
76 # skip test directories if not in test_mode and vice versa
77 if bool(parent[-5:] == '-test') ^ bool(self.test_mode):
78 continue
79 l = os.path.join(parent, f)
80 logs.writelines(open(l, 'rt').readlines())
81 logs.write('\n\n')
82 self._logReport(l, testReport)
83 logs.close()
84 testReport.close()
86 if self.test_mode:
87 self._testReport()
89 def _logReport(self, logName, reportFile):
90 """Extracts useful info from log file `logName` and writes it to file
91 object `reportFile`."""
92 case = None
93 app = None
94 fatalError = False
95 singularity = False
96 completed = False
97 success = False
98 time = ''
99 for l in open(logName, 'rt'):
100 m = re.match(
101 r'(?:APPLICATION:\s+(?P<app>\S+)|CASE:\s+(?P<case>\S+))', l)
102 if m:
103 d = m.groupdict()
104 if d['app']:
105 app = d['app']
106 elif d['case']:
107 case = d['case']
108 if re.search('FOAM FATAL', l):
109 fatalError = True
110 elif re.search(r'U[xyz](:|\s)*solution singularity', l):
111 singularity = True
112 elif re.match(r'^\s*[Ee]nd\s*\.?\s*$', l):
113 completed = True
114 elif re.match(r'^REPORT:\s+SUCCESS', l):
115 success = True
116 else:
117 m = re.search(r'Execution\S+\s+=\s+(?P<time>\S+\s+\S+)', l)
118 if m:
119 time = m.group('time')
121 if bool(case) != bool(app):
122 raise LogParserError('Failed to parse "%s"'%logName)
123 elif not case and not app:
124 # skip this
125 return
127 appAndCase = "Application %s - case %s"%(app,
128 os.path.relpath(case, self.tutorials_dir))
130 if fatalError:
131 reportFile.write('%s: ** FOAM FATAL ERROR **\n'%appAndCase)
132 elif singularity:
133 reportFile.write('%s: ** Solution singularity **\n'%appAndCase)
134 elif completed and success:
135 reportFile.write('%s: completed'%appAndCase)
136 if len(time) > 0:
137 reportFile.write(' in %s\n'%time)
138 else:
139 reportFile.write('\n')
140 else:
141 reportFile.write('%s: unconfirmed completion\n'%appAndCase)
143 def _testReport(self):
144 fv_schemes = (
145 'gradScheme',
146 'divScheme',
147 'laplacianScheme',
148 'interpolationScheme',
149 'snGradScheme',
150 'fluxRequired',
152 solvers_tmp = {}
153 schemes_tmp = {}
154 # traverse tree
155 for parent, dirs, files in os.walk(self.tutorials_dir):
156 # skip test directories if not in test_mode and vice versa
157 if bool(parent[-5:] == '-test') ^ bool(self.test_mode):
158 continue
159 # loop over files
160 for f in files:
161 if f[0:4] == 'log.':
162 # scan log for APPLICATION and then for schemes and solver
163 # information
164 log = open(os.path.join(parent, f), 'rt')
165 app = None
166 for l in log:
167 if app == None:
168 m = re.match(r'APPLICATION:\s*(?P<app>\S+)', l)
169 if m:
170 app = os.path.basename(m.group('app'))
171 if app not in solvers_tmp:
172 solvers_tmp[app] = set()
173 schemes_tmp[app] = {}
174 else:
175 for st in fv_schemes:
176 if re.search(st, l):
177 if st not in schemes_tmp[app]:
178 schemes_tmp[app][st] = set()
179 schemes_tmp[app][st].add(l.split()[-1])
180 m = re.match(r'(\S+):\s+Solving for', l)
181 if m:
182 solvers_tmp[app].add(m.group(1))
183 # write schemes and solvers information per application
184 SC = open(os.path.join(self.tutorials_dir, 'FvSchemes'), 'wt')
185 SO = open(os.path.join(self.tutorials_dir, 'FvSolution'), 'wt')
186 applications = solvers_tmp.keys()
187 applications.sort()
188 for app in applications:
189 SC.write('%s\n'%app)
190 SO.write('%s\n'%app)
191 for st in fv_schemes:
192 SC.write(' %s\n'%st)
193 if st in schemes_tmp[app] and len(schemes_tmp[app][st]) > 0:
194 tmp = list(schemes_tmp[app][st])
195 tmp.sort()
196 SC.write(' '+'\n '.join(tmp)+'\n')
197 if len(solvers_tmp[app]) > 0:
198 tmp = list(solvers_tmp[app])
199 tmp.sort()
200 SO.write(' '+'\n '.join(tmp)+'\n')
201 SO.close()
202 SC.close()
204 if __name__ == '__main__':
205 os.chdir(os.path.abspath(os.path.dirname(sys.argv[0])))
206 sys.argv[0] = os.path.basename(sys.argv[0])
207 sys.exit(AllTutorialsRunner().main())
209 # ------------------- vim: set sw=3 sts=3 ft=python et: ------------ end-of-file