@@ -119,9 +119,9 @@ def main(args=None) -> tuple[argparse.Namespace, int]:
119119 else :
120120 meta_weights = None
121121
122-
123- player_id = 1
124- player_files = {}
122+ player_id : int = 1
123+ player_files : dict [ int , str ] = {}
124+ player_errors : list [ str ] = []
125125 for file in os .scandir (args .player_files_path ):
126126 fname = file .name
127127 if file .is_file () and not fname .startswith ("." ) and not fname .lower ().endswith (".ini" ) and \
@@ -137,7 +137,11 @@ def main(args=None) -> tuple[argparse.Namespace, int]:
137137 weights_cache [fname ] = tuple (weights_for_file )
138138
139139 except Exception as e :
140- raise ValueError (f"File { fname } is invalid. Please fix your yaml." ) from e
140+ logging .exception (f"Exception reading weights in file { fname } " )
141+ player_errors .append (
142+ f"{ len (player_errors ) + 1 } . "
143+ f"File { fname } is invalid. Please fix your yaml.\n { Utils .get_all_causes (e )} "
144+ )
141145
142146 # sort dict for consistent results across platforms:
143147 weights_cache = {key : value for key , value in sorted (weights_cache .items (), key = lambda k : k [0 ].casefold ())}
@@ -152,6 +156,10 @@ def main(args=None) -> tuple[argparse.Namespace, int]:
152156 args .multi = max (player_id - 1 , args .multi )
153157
154158 if args .multi == 0 :
159+ if player_errors :
160+ errors = "\n \n " .join (player_errors )
161+ raise ValueError (f"Encountered { len (player_errors )} error(s) in player files. "
162+ f"See logs for full tracebacks.\n \n { errors } " )
155163 raise ValueError (
156164 "No individual player files found and number of players is 0. "
157165 "Provide individual player files or specify the number of players via host.yaml or --multi."
@@ -161,6 +169,10 @@ def main(args=None) -> tuple[argparse.Namespace, int]:
161169 f"{ seed_name } Seed { seed } with plando: { args .plando } " )
162170
163171 if not weights_cache :
172+ if player_errors :
173+ errors = "\n \n " .join (player_errors )
174+ raise ValueError (f"Encountered { len (player_errors )} error(s) in player files. "
175+ f"See logs for full tracebacks.\n \n { errors } " )
164176 raise Exception (f"No weights found. "
165177 f"Provide a general weights file ({ args .weights_file_path } ) or individual player files. "
166178 f"A mix is also permitted." )
@@ -171,10 +183,6 @@ def main(args=None) -> tuple[argparse.Namespace, int]:
171183 args .sprite_pool = dict .fromkeys (range (1 , args .multi + 1 ), None )
172184 args .name = {}
173185
174- settings_cache : dict [str , tuple [argparse .Namespace , ...]] = \
175- {fname : (tuple (roll_settings (yaml , args .plando ) for yaml in yamls ) if args .sameoptions else None )
176- for fname , yamls in weights_cache .items ()}
177-
178186 if meta_weights :
179187 for category_name , category_dict in meta_weights .items ():
180188 for key in category_dict :
@@ -197,7 +205,24 @@ def main(args=None) -> tuple[argparse.Namespace, int]:
197205 else :
198206 yaml [category_name ][key ] = option
199207
200- player_path_cache = {}
208+ settings_cache : dict [str , tuple [argparse .Namespace , ...]] = {fname : None for fname in weights_cache }
209+ if args .sameoptions :
210+ for fname , yamls in weights_cache .items ():
211+ try :
212+ settings_cache [fname ] = tuple (roll_settings (yaml , args .plando ) for yaml in yamls )
213+ except Exception as e :
214+ logging .exception (f"Exception reading settings in file { fname } " )
215+ player_errors .append (
216+ f"{ len (player_errors ) + 1 } . "
217+ f"File { fname } is invalid. Please fix your yaml.\n { Utils .get_all_causes (e )} "
218+ )
219+ # Exit early here to avoid throwing the same errors again later
220+ if player_errors :
221+ errors = "\n \n " .join (player_errors )
222+ raise ValueError (f"Encountered { len (player_errors )} error(s) in player files. "
223+ f"See logs for full tracebacks.\n \n { errors } " )
224+
225+ player_path_cache : dict [int , str ] = {}
201226 for player in range (1 , args .multi + 1 ):
202227 player_path_cache [player ] = player_files .get (player , args .weights_file_path )
203228 name_counter = Counter ()
@@ -206,38 +231,62 @@ def main(args=None) -> tuple[argparse.Namespace, int]:
206231 player = 1
207232 while player <= args .multi :
208233 path = player_path_cache [player ]
209- if path :
234+ if not path :
235+ player_errors .append (f'No weights specified for player { player } ' )
236+ player += 1
237+ continue
238+
239+ for doc_index , yaml in enumerate (weights_cache [path ]):
240+ name = yaml .get ("name" )
210241 try :
211- settings : tuple [argparse .Namespace , ...] = settings_cache [path ] if settings_cache [path ] else \
212- tuple (roll_settings (yaml , args .plando ) for yaml in weights_cache [path ])
213- for settingsObject in settings :
214- for k , v in vars (settingsObject ).items ():
215- if v is not None :
216- try :
217- getattr (args , k )[player ] = v
218- except AttributeError :
219- setattr (args , k , {player : v })
220- except Exception as e :
221- raise Exception (f"Error setting { k } to { v } for player { player } " ) from e
222-
223- # name was not specified
224- if player not in args .name :
225- if path == args .weights_file_path :
226- # weights file, so we need to make the name unique
227- args .name [player ] = f"Player{ player } "
228- else :
229- # use the filename
230- args .name [player ] = os .path .splitext (os .path .split (path )[- 1 ])[0 ]
231- args .name [player ] = handle_name (args .name [player ], player , name_counter )
232-
233- player += 1
242+ # Use the cached settings object if it exists, otherwise roll settings within the try-catch
243+ # Invariant: settings_cache[path] and weights_cache[path] have the same length
244+ settingsObject : argparse .Namespace = (
245+ settings_cache [path ][doc_index ]
246+ if settings_cache [path ]
247+ else roll_settings (yaml , args .plando )
248+ )
249+
250+ for k , v in vars (settingsObject ).items ():
251+ if v is not None :
252+ try :
253+ getattr (args , k )[player ] = v
254+ except AttributeError :
255+ setattr (args , k , {player : v })
256+ except Exception as e :
257+ raise Exception (f"Error setting { k } to { v } for player { player } " ) from e
258+
259+ # name was not specified
260+ if player not in args .name :
261+ if path == args .weights_file_path :
262+ # weights file, so we need to make the name unique
263+ args .name [player ] = f"Player{ player } "
264+ else :
265+ # use the filename
266+ args .name [player ] = os .path .splitext (os .path .split (path )[- 1 ])[0 ]
267+ args .name [player ] = handle_name (args .name [player ], player , name_counter )
268+
234269 except Exception as e :
235- raise ValueError (f"File { path } is invalid. Please fix your yaml." ) from e
236- else :
237- raise RuntimeError (f'No weights specified for player { player } ' )
270+ logging .exception (f"Exception reading settings in file { path } document #{ doc_index + 1 } "
271+ f"(name: { args .name .get (player , name )} )" )
272+ player_errors .append (
273+ f"{ len (player_errors ) + 1 } . "
274+ f"File { path } document #{ doc_index + 1 } (name: { args .name .get (player , name )} ) is invalid. "
275+ f"Please fix your yaml.\n { Utils .get_all_causes (e )} " )
276+
277+ # increment for each yaml document in the file
278+ player += 1
238279
239280 if len (set (name .lower () for name in args .name .values ())) != len (args .name ):
240- raise Exception (f"Names have to be unique. Names: { Counter (name .lower () for name in args .name .values ())} " )
281+ player_errors .append (
282+ f"{ len (player_errors ) + 1 } . "
283+ f"Names have to be unique. Names: { Counter (name .lower () for name in args .name .values ())} "
284+ )
285+
286+ if player_errors :
287+ errors = "\n \n " .join (player_errors )
288+ raise ValueError (f"Encountered { len (player_errors )} error(s) in player files. "
289+ f"See logs for full tracebacks.\n \n { errors } " )
241290
242291 return args , seed
243292
0 commit comments