1717 SINGLE_ELEMENT ,
1818 CostTableData ,
1919 RelationType ,
20+ activity_based_tables ,
21+ capacity_based_tables ,
22+ commodity_based_tables ,
2023 consolidate_lines ,
2124)
2225from temoa .model_checking .unit_checking .entry_checker import (
@@ -94,8 +97,20 @@ def check_efficiency_table(
9497 continue
9598
9699 # check that our tech matches the units of the connected commodities
97- invalid_input_flag = input_units != comm_units [ic ]
98- invalid_output_flag = output_units != comm_units [oc ]
100+ expected_input = comm_units .get (ic )
101+ expected_output = comm_units .get (oc )
102+ if expected_input is None or expected_output is None :
103+ invalid_rows .append (idx )
104+ logger .warning (
105+ 'Missing commodity units for input_comm=%s or output_comm=%s in efficiency row %d' ,
106+ ic ,
107+ oc ,
108+ idx ,
109+ )
110+ continue
111+
112+ invalid_input_flag = input_units != expected_input
113+ invalid_output_flag = output_units != expected_output
99114 if invalid_input_flag or invalid_output_flag :
100115 logger .warning (
101116 'Efficiency units conflict with associated commodity for Technology %s near row %d' ,
@@ -107,9 +122,9 @@ def check_efficiency_table(
107122 f'{ tech :^20} ----> { f"{ oc } [{ output_units } ]" : ^25} '
108123 )
109124 if invalid_input_flag :
110- msg += f'\n Invalid input units: { comm_units [ ic ] } '
125+ msg += f'\n Invalid input units: { expected_input } '
111126 if invalid_output_flag :
112- msg += f'\n Invalid output units: { comm_units [ oc ] } '
127+ msg += f'\n Invalid output units: { expected_output } '
113128 error_msgs .append (msg )
114129
115130 # check that the output of this technology is consistent in units with
@@ -165,7 +180,12 @@ def check_inter_table_relations(
165180 - Missing tables (e.g., some databases may not have all limit tables)
166181 - Schema variations between v3.1 and v4.0
167182 """
168- grouped_errors = defaultdict (list )
183+ # Validate table_name against known safe tables
184+ valid_tables = activity_based_tables + capacity_based_tables + commodity_based_tables
185+ if table_name not in valid_tables :
186+ raise ValueError (f'Invalid table name: { table_name } ' )
187+
188+ grouped_errors : defaultdict [str , list [int ]] = defaultdict (list )
169189
170190 # Build query based on relation type, with robustness checks
171191 match relation_type :
@@ -206,11 +226,9 @@ def check_inter_table_relations(
206226
207227 try :
208228 rows = conn .execute (query ).fetchall ()
209- except sqlite3 .OperationalError as e :
229+ except sqlite3 .OperationalError as _ :
210230 # Log the error but don't fail the entire check
211- logger .error (
212- 'failed to process query: %s when processing table %s: %s' , query , table_name , e
213- )
231+ logger .exception ('failed to process query: %s when processing table %s' , query , table_name )
214232 msg = (
215233 f'Failed to process table { table_name } due to SQL error. '
216234 f'This may indicate missing columns or incompatible schema. '
@@ -232,7 +250,7 @@ def check_inter_table_relations(
232250 continue
233251 expected_units = io_units .output_units
234252 case RelationType .ACTIVITY :
235- io_units = tech_lut [ tech_or_comm ]
253+ io_units = tech_lut . get ( tech_or_comm )
236254 if not io_units :
237255 grouped_errors [
238256 f'Unprocessed row (missing reference for tech '
@@ -261,25 +279,28 @@ def check_inter_table_relations(
261279 if c2a_units :
262280 c2a_valid , units_data = validate_units_format (c2a_units , SINGLE_ELEMENT )
263281 if c2a_valid and units_data is not None and len (units_data ) >= 1 :
264- # further ensure the conversion is valid and retain the validity
265- c2a_valid , valid_c2a_units = validate_units_expression (units_data [0 ])
282+ # further ensure the conversion is valid and retain the appropriate units object
283+ _ , valid_c2a_units = validate_units_expression (units_data [0 ])
284+ if not valid_c2a_units :
285+ grouped_errors [
286+ f'Invalid units or unit format for c2a table: { c2a_units } '
287+ ].append (idx )
288+ continue
266289 else :
267- valid_c2a_units = None
268- else : # we are in a valid state: no C2A units provided/needed
269- c2a_valid = True
290+ grouped_errors [f'Invalid units or unit format for c2a table: { c2a_units } ' ].append (
291+ idx
292+ )
293+ continue
294+ else :
270295 valid_c2a_units = None
271296
272297 if not valid_table_units :
273- grouped_errors ['Unprocessed row (invalid units--see earlier tests)' ].append (idx )
274- if not c2a_valid :
275- grouped_errors ['Unprocessed row (invalid c2a units--see earlier tests)' ].append (idx )
276- if not valid_table_units or not c2a_valid :
298+ grouped_errors [f'Invalid units or unit format: { table_units } ' ].append (idx )
277299 continue
278300
279301 # if we have valid c2a units, combine them to get the units of activity
280302 if valid_c2a_units :
281303 res_units = valid_table_units * (valid_c2a_units * ureg .year )
282-
283304 else :
284305 res_units = valid_table_units
285306
@@ -356,7 +377,7 @@ def check_cost_tables(
356377 try :
357378 rows = conn .execute (query ).fetchall ()
358379 except sqlite3 .OperationalError :
359- logger .error (
380+ logger .exception (
360381 'failed to process query: %s when processing table %s' , query , ct .table_name
361382 )
362383 msg = f'Failed to process table { ct .table_name } . See log for failed query.'
@@ -385,32 +406,51 @@ def check_cost_tables(
385406 continue
386407
387408 # Test 1: Look for cost commonality
388- if common_cost_unit is None and cost_units is not None :
389- # try to establish it
390- # Check that the units contain currency dimension
391- # Fixed: Changed from .check('[currency]') which only works for pure currency
392- # to checking dimensionality dict which works for composite units
393- # Example: 'Mdollar / (PJ^2/GW)' has currency in dimensionality but fails .check()
394- try :
395- if '[currency]' in cost_units .dimensionality :
396- common_cost_unit = cost_units
397- else :
398- # Units don't contain currency dimension - invalid for cost table
399- error_msgs .append (
400- f'{ ct .table_name } : Unprocessed row '
401- f'(units lack currency dimension): { cost_units } at row: { idx } '
409+ # extract the cost units
410+ if not cost_units :
411+ label = (
412+ f'{ ct .table_name } : Unprocessed row '
413+ f'(missing cost units): { raw_units_expression } '
414+ )
415+ table_grouped_errors [label ].append (idx )
416+ continue
417+
418+ # Get cost unit object
419+ # cost_units is already a pint Unit object from validate_units_expression(elements[0])
420+ cost_unit_obj = cost_units
421+
422+ # Check for currency dimension
423+ if '[currency]' not in cost_unit_obj .dimensionality :
424+ label = (
425+ f'{ ct .table_name } : Cost units must have currency dimension. '
426+ f'Found: { cost_unit_obj } '
427+ )
428+ table_grouped_errors [label ].append (idx )
429+ continue
430+
431+ # Initialize common_cost_unit on first valid row
432+ if common_cost_unit is None :
433+ common_cost_unit = cost_unit_obj
434+ # No need to continue here, as we still need to check measure units
435+ else :
436+ # Validate subsequent rows against the established common unit
437+ if cost_unit_obj != common_cost_unit :
438+ # Try to see if they're equivalent but differently expressed
439+ try :
440+ # Attempt conversion to check if they're compatible
441+ (1.0 * cost_unit_obj ).to (common_cost_unit )
442+ except (ValueError , AttributeError , TypeError ) as e :
443+ # Not compatible - this is an error
444+ label = (
445+ f'{ ct .table_name } : Inconsistent cost units: { cost_unit_obj } '
446+ f'does not match common cost unit { common_cost_unit } . Error: { e } '
402447 )
448+ table_grouped_errors [label ].append (idx )
403449 continue
404- except Exception :
405- error_msgs .append (
406- f'{ ct .table_name } : Could not check cost units: { cost_units } at row: { idx } '
407- )
408- continue
409- if cost_units != common_cost_unit :
450+ # If compatible but not strictly equal, we still flag it as non-standard
410451 label = (
411452 f'{ ct .table_name } : Non-standard cost found '
412453 f'(expected common cost units of { common_cost_unit } ) '
413- f'got: { cost_units } '
414454 )
415455 table_grouped_errors [label ].append (idx )
416456
0 commit comments