55from datetime import timedelta
66from pathlib import Path
77from urllib .request import urlopen
8+ from traceback import print_exception
89
910
1011use_ansi = os .name != 'nt' and sys .stdout .isatty ()
@@ -159,16 +160,26 @@ def __str__(self):
159160 return f'{ self .name } : time={ self .time_str ()} result={ self .result } '
160161
161162
163+ def print_error (exc , context ):
164+ exc .add_note (context )
165+ print_exception (exc )
166+
167+
162168class Build :
163169 def __init__ (self , name , builds_dir , misc = None ):
164- if misc is None :
165- misc = {}
166170 self .name = name
167171 self .dir = builds_dir / name
168- self .misc = misc
172+ self .misc = misc or {}
173+ self .basename = self .misc .get ('basename' )
174+ self .props = self .misc .get ('props' , {})
175+ self .tests = {}
169176 self .stats = TestStats ()
170- self .basename = misc ['basename' ]
171- self .props = misc .get ('props' , {})
177+
178+ if misc is None :
179+ return
180+
181+ if self .basename is None :
182+ raise ValueError (f'Build { name !r} is missing a basename, probably a missing latest.txt' )
172183
173184 # Get build.json. It should either exist locally or can be downloaded.
174185 build_json_name = self .basename + '.build.json'
@@ -182,15 +193,20 @@ def __init__(self, name, builds_dir, misc=None):
182193 with urlopen (url ) as f :
183194 data = json .load (f )
184195 else :
185- raise ValueError (f'Can not get { build_json_name } for { name } ' )
196+ raise ValueError (f'Can not get { build_json_name !r } for { name !r } ' )
186197
187- self .tests = {}
188198 for t in data ['tests' ]:
189- test_run = TestRun (t ['name' ], int (t ['result' ]), timedelta (seconds = int (t ['time' ])), t )
190- self .stats .add (test_run .status , test_run .time )
191- if test_run .name in self .tests :
192- raise ValueError (f'Multiple { repr (test_run .name )} in { self .name } !' )
193- self .tests [test_run .name ] = test_run
199+ try :
200+ self .add_test_run (t )
201+ except BaseException as e :
202+ print_error (e , f'Test { name !r} in build { name !r} caused this error' )
203+
204+ def add_test_run (self , t ):
205+ test_run = TestRun (t ['name' ], int (t ['result' ]), timedelta (seconds = int (t ['time' ])), t )
206+ self .stats .add (test_run .status , test_run .time )
207+ if test_run .name in self .tests :
208+ raise ValueError (f'Multiple { repr (test_run .name )} in { self .name } !' )
209+ self .tests [test_run .name ] = test_run
194210
195211 def __iter__ (self ):
196212 return iter (self .tests .values ())
@@ -245,8 +261,8 @@ def __init__(self, builds_dir: Path):
245261 try :
246262 build = Build (name , builds_dir , b )
247263 except BaseException as e :
248- e . add_note ( f'The build that caused an error was { name } ' )
249- raise
264+ print_error ( e , f'The build that caused this error was { name !r } ' )
265+ build = Build ( name , builds_dir )
250266 self .builds [name ] = build
251267
252268 # Collect all the tests
0 commit comments