@@ -187,46 +187,35 @@ class TubStatistics(object):
187187 def __init__ (self ,
188188 tub : Tub ,
189189 config : Optional [Any ] = None ,
190- gyro_z_index : int = 1 ,
191190 sorting_strategy : Optional [SortingStrategy ] = None ,
192191 field_aggregations : Optional [List ] = None ):
193192 """
194193 Construct tub statistics calculator for tub
195194
196195 :param tub: input tub
197196 :param config: Config object (loads FIELD_AGGREGATIONS,
198- LAP_SORTING_CRITERIA)
199- :param gyro_z_index: z coordinate in 3d gyro vector (deprecated,
200- use config)
197+ LAP_SORTING_CRITERIA). Required if
198+ field_aggregations not provided.
201199 :param sorting_strategy: Optional custom sorting strategy
202- (backward compat)
203200 :param field_aggregations: Optional list of FieldAggregationSpec or
204- old-style dicts (backward compat)
201+ dicts. Required if config not provided.
202+ :raises ValueError: If neither config nor field_aggregations
203+ provided.
205204 """
206205 self .tub = tub
207206
208- # Load field aggregations with precedence:
209- # 1. Direct parameter (backward compat)
210- # 2. From config (new preferred method)
211- # 3. Default fallback
207+ # Load field aggregations - require explicit configuration
212208 if field_aggregations is not None :
213- # Handle both old-style dicts and new FieldAggregationSpec
214209 self .field_aggregations = self ._normalize_field_aggregations (
215- field_aggregations , gyro_z_index )
210+ field_aggregations )
216211 elif config :
217212 self .field_aggregations = (
218213 self ._load_field_aggregations_from_config (config ))
219214 else :
220- # Backward compatible defaults
221- self .field_aggregations = [
222- FieldAggregationSpec (
223- field = 'car/gyro' ,
224- output_key = 'gyro_z_agg' ,
225- index = gyro_z_index ,
226- transform = abs ,
227- aggregation = 'avg'
228- )
229- ]
215+ raise ValueError (
216+ 'TubStatistics requires either config or field_aggregations. '
217+ 'No silent defaults are used - configure FIELD_AGGREGATIONS '
218+ 'in config or pass field_aggregations directly.' )
230219
231220 # Load sorting strategy
232221 if sorting_strategy :
@@ -240,58 +229,45 @@ def __init__(self,
240229 logger .info (f'Creating TubStatistics with '
241230 f'{ len (self .field_aggregations )} field aggregations' )
242231
243- def _normalize_field_aggregations (self , field_aggregations : List ,
244- gyro_z_index : int ) -> List [
232+ def _normalize_field_aggregations (self , field_aggregations : List ) -> List [
245233 FieldAggregationSpec ]:
246- """Convert old-style dict specs to FieldAggregationSpec."""
234+ """Convert dict specs to FieldAggregationSpec.
235+
236+ :raises ValueError: If old-style extractor syntax is used.
237+ """
247238 normalized = []
248239 for spec in field_aggregations :
249240 if isinstance (spec , FieldAggregationSpec ):
250241 normalized .append (spec )
251242 elif isinstance (spec , dict ):
252- # Old style dict with 'extractor' and 'transform'
253243 if 'extractor' in spec :
254- # Cannot convert old-style extractor lambdas,
255- # use gyro_z_index default
256- logger .warning ('Old-style field_aggregations dict with '
257- 'extractor not supported. Using defaults.' )
258- normalized .append (FieldAggregationSpec (
259- field = spec ['field' ],
260- output_key = spec ['output_key' ],
261- index = gyro_z_index ,
262- transform = spec .get ('transform' ),
263- aggregation = 'avg'
264- ))
265- else :
266- # New style dict
267- normalized .append (FieldAggregationSpec (
268- field = spec ['field' ],
269- output_key = spec ['output_key' ],
270- index = spec .get ('index' ),
271- transform = spec .get ('transform' ),
272- aggregation = spec .get ('aggregation' , 'avg' )
273- ))
244+ raise ValueError (
245+ f'Old-style field_aggregations with "extractor" '
246+ f'not supported for field { spec .get ("field" , "?" )} . '
247+ f'Use "index" parameter instead.' )
248+ normalized .append (FieldAggregationSpec (
249+ field = spec ['field' ],
250+ output_key = spec ['output_key' ],
251+ index = spec .get ('index' ),
252+ transform = spec .get ('transform' ),
253+ aggregation = spec .get ('aggregation' , 'avg' )
254+ ))
274255 return normalized
275256
276257 def _load_field_aggregations_from_config (self , config ) -> List [
277258 FieldAggregationSpec ]:
278- """Load field aggregation specs from config."""
259+ """Load field aggregation specs from config.
260+
261+ :raises ValueError: If FIELD_AGGREGATIONS not found in config.
262+ """
279263 config_specs = getattr (config , 'FIELD_AGGREGATIONS' , None )
280264
281265 if not config_specs :
282- # Fallback to legacy GYRO_Z_INDEX
283- gyro_z_index = getattr (config , 'GYRO_Z_INDEX' , 1 )
284- logger .info (f'No FIELD_AGGREGATIONS in config, using '
285- f'default gyro aggregation with index { gyro_z_index } ' )
286- return [
287- FieldAggregationSpec (
288- field = 'car/gyro' ,
289- output_key = 'gyro_z_agg' ,
290- index = gyro_z_index ,
291- transform = abs ,
292- aggregation = 'avg'
293- )
294- ]
266+ raise ValueError (
267+ 'FIELD_AGGREGATIONS not found in config. '
268+ 'Please define FIELD_AGGREGATIONS in your config file. '
269+ 'Example: FIELD_AGGREGATIONS = [{"field": "car/gyro", '
270+ '"output_key": "gyro_z_agg", "index": 1, "aggregation": "avg"}]' )
295271
296272 # Convert config dicts to FieldAggregationSpec
297273 specs = []
@@ -317,7 +293,9 @@ def _load_sorting_strategy_from_config(self, config) -> SortingStrategy:
317293 f'{ [c ["key" ] for c in criteria ]} ' )
318294 return SortingStrategy (criteria )
319295 else :
320- logger .info ('No LAP_SORTING_CRITERIA in config, using defaults' )
296+ logger .info ('No LAP_SORTING_CRITERIA in config, using minimal '
297+ 'defaults (time, distance). Configure LAP_SORTING_CRITERIA '
298+ 'in config to include custom fields like gyro_z_agg.' )
321299 return default_lap_sorting_strategy ()
322300
323301 def generate_laptimes_from_records (self , overwrite = False ):
0 commit comments