2525
2626# Dummy Measure Enum for testing
2727from enum import Enum
28+ from itertools import product
2829from unittest .mock import Mock , PropertyMock , call , patch
2930
3031import numpy as np # For potential NaN/NA comparisons
@@ -267,24 +268,25 @@ def test_generic_metrics_basic_flow(self, mock_npv_transform, mock_risk_periods)
267268 mock_risk_periods .return_value = [mock_calc_period1 , mock_calc_period2 ]
268269
269270 # Mock the metric method on CalcRiskPeriod instances
270- mock_calc_period1 . calc_aai_metric . return_value = pd .DataFrame (
271- {
272- "date" : [ pd .Timestamp ( "2023-01-01" )],
273- "group" : [ "GroupA" ],
274- "measure" : [ "MEAS1" ],
275- "metric" : [ "aai" ],
276- "risk" : [ 100.0 ] ,
277- }
271+ dates1 = [ pd .Timestamp ( "2023-01-01" ), pd . Timestamp ( "2024-01-01" )]
272+ dates2 = [ pd . Timestamp ( "2025-01-01" ), pd . Timestamp ( "2026-01-01" )]
273+ groups = [ "GroupA" , "GroupB" , pd .NA ]
274+ measures = [ "MEAS1" , "MEAS2" ]
275+ metrics = [ "aai" ]
276+ df1 = pd . DataFrame (
277+ product ( dates1 , groups , measures , metrics ) ,
278+ columns = [ "date" , "group" , "measure" , "metric" ],
278279 )
279- mock_calc_period2 .calc_aai_metric .return_value = pd .DataFrame (
280- {
281- "date" : [pd .Timestamp ("2024-01-01" )],
282- "group" : ["GroupB" ],
283- "measure" : ["MEAS2" ],
284- "metric" : ["aai" ],
285- "risk" : [200.0 ],
286- }
280+ df1 ["risk" ] = np .arange (12 ) * 100
281+ df1 ["group" ] = df1 ["group" ].astype ("category" )
282+ df2 = pd .DataFrame (
283+ product (dates2 , groups , measures , metrics ),
284+ columns = ["date" , "group" , "measure" , "metric" ],
287285 )
286+ df2 ["risk" ] = np .arange (12 ) * 100 + 1200
287+ df2 ["group" ] = df2 ["group" ].astype ("category" )
288+ mock_calc_period1 .calc_aai_metric .return_value = df1
289+ mock_calc_period2 .calc_aai_metric .return_value = df2
288290
289291 # Mock npv_transform return value
290292 mock_npv_transform .return_value = "discounted_df"
@@ -300,20 +302,18 @@ def test_generic_metrics_basic_flow(self, mock_npv_transform, mock_risk_periods)
300302
301303 # Check concatenated DataFrame before NPV
302304 # We need to manually recreate the expected intermediate DataFrame before NPV for assertion
303- expected_pre_npv_df = pd .DataFrame (
304- {
305- "date" : [pd .Timestamp ("2023-01-01" ), pd .Timestamp ("2024-01-01" )],
306- "group" : ["GroupA" , "GroupB" ],
307- "measure" : ["MEAS1" , "MEAS2" ],
308- "metric" : ["aai" , "aai" ],
309- "risk" : [100.0 , 200.0 ],
310- }
305+ df3 = pd .DataFrame (
306+ product (dates1 + dates2 , groups , measures , metrics ),
307+ columns = ["date" , "group" , "measure" , "metric" ],
311308 )
312- expected_pre_npv_df ["group" ] = expected_pre_npv_df ["group" ].fillna ("All" )
309+ df3 ["risk" ] = np .arange (24 ) * 100
310+ df3 ["group" ] = df3 ["group" ].astype ("category" )
311+ df3 ["group" ] = df3 ["group" ].cat .add_categories (["All" ])
312+ df3 ["group" ] = df3 ["group" ].fillna ("All" )
313+ expected_pre_npv_df = df3
313314 expected_pre_npv_df = expected_pre_npv_df [
314315 ["group" , "date" , "measure" , "metric" , "risk" ]
315316 ]
316-
317317 # npv_transform should be called with the correctly formatted (concatenated and ordered) DataFrame
318318 # and the risk_disc attribute
319319 mock_npv_transform .assert_called_once ()
@@ -339,31 +339,27 @@ def test_generic_metrics_no_npv(self, mock_npv_transform, mock_risk_periods):
339339 # Mock CalcRiskPeriod instances
340340 mock_calc_period1 = Mock ()
341341 mock_risk_periods .return_value = [mock_calc_period1 ]
342- mock_calc_period1 .calc_aai_metric .return_value = pd .DataFrame (
343- {
344- "date" : [pd .Timestamp ("2023-01-01" )],
345- "group" : ["GroupA" ],
346- "measure" : ["MEAS1" ],
347- "metric" : ["aai" ],
348- "risk" : [100.0 ],
349- }
342+ dates1 = [pd .Timestamp ("2023-01-01" ), pd .Timestamp ("2024-01-01" )]
343+ groups = ["GroupA" , "GroupB" , pd .NA ]
344+ measures = ["MEAS1" , "MEAS2" ]
345+ metrics = ["aai" ]
346+ df1 = pd .DataFrame (
347+ product (groups , dates1 , measures , metrics ),
348+ columns = ["group" , "date" , "measure" , "metric" ],
350349 )
350+ df1 ["risk" ] = np .arange (12 ) * 100
351+ df1 ["group" ] = df1 ["group" ].astype ("category" )
352+ mock_calc_period1 .calc_aai_metric .return_value = df1
351353
352354 result = rt ._generic_metrics (
353355 npv = False , metric_name = "aai" , metric_meth = "calc_aai_metric"
354356 )
355357
356358 # Assertions
357359 mock_npv_transform .assert_not_called ()
358- expected_df = pd .DataFrame (
359- {
360- "group" : ["GroupA" ],
361- "date" : [pd .Timestamp ("2023-01-01" )],
362- "measure" : ["MEAS1" ],
363- "metric" : ["aai" ],
364- "risk" : [100.0 ],
365- }
366- )
360+ expected_df = df1 .copy ()
361+ expected_df ["group" ] = expected_df ["group" ].cat .add_categories (["All" ])
362+ expected_df ["group" ] = expected_df ["group" ].fillna ("All" )
367363 pd .testing .assert_frame_equal (result , expected_df )
368364 pd .testing .assert_frame_equal (getattr (rt , "_aai_metrics" ), expected_df )
369365
@@ -413,7 +409,7 @@ def test_generic_metrics_coord_id_handling(
413409 mock_calc_period .calc_eai_gdf .return_value = pd .DataFrame (
414410 {
415411 "date" : [pd .Timestamp ("2023-01-01" ), pd .Timestamp ("2023-01-01" )],
416- "group" : [ "All" , "All" ] ,
412+ "group" : pd . Categorical ([ pd . NA , pd . NA ]) ,
417413 "measure" : ["MEAS1" , "MEAS1" ],
418414 "metric" : ["eai" , "eai" ],
419415 "coord_id" : [1 , 2 ],
@@ -427,7 +423,7 @@ def test_generic_metrics_coord_id_handling(
427423
428424 expected_df = pd .DataFrame (
429425 {
430- "group" : ["All" , "All" ],
426+ "group" : pd . Categorical ( ["All" , "All" ]) ,
431427 "date" : [pd .Timestamp ("2023-01-01" ), pd .Timestamp ("2023-01-01" )],
432428 "measure" : ["MEAS1" , "MEAS1" ],
433429 "metric" : ["eai" , "eai" ],
0 commit comments