Coverage for backend/django/Economics/results/unit_options.py: 86%

43 statements  

« prev     ^ index     » next       coverage.py v7.10.7, created at 2026-06-23 21:51 +0000

1from decimal import Decimal, ROUND_HALF_UP 

2 

3from core.auxiliary.enums.unitsOfMeasure import UnitOfMeasure 

4from Economics.shared.unit_conversion import convert_quantity 

5from Economics.shared.unit_options import ( 

6 UnitOption, 

7 dedupe_unit_options, 

8 infer_physical_unit_type, 

9 price_denominator_options, 

10 price_denominator_units, 

11 registry_unit_options, 

12 strip_time_denominator, 

13 with_current_unit, 

14) 

15 

16 

17RESULT_QUANTITY_QUANTUM = Decimal("0.00000001") 

18 

19 

20def annual_result_basis_unit_options(current_unit: str) -> list[UnitOption]: 

21 current = _annual_result_unit(current_unit) 

22 unit_type = _annual_result_basis_unit_type(current) 

23 if not unit_type: 23 ↛ 24line 23 didn't jump to line 24 because the condition on line 23 was never true

24 return with_current_unit([], current) 

25 

26 base_options = _annual_result_basis_base_options(unit_type) 

27 options = [ 

28 {"value": f"{option['value']}/year", "label": f"{option['label']}/year"} 

29 for option in base_options 

30 if _annual_result_units_compatible(current, f"{option['value']}/year") 

31 ] 

32 return with_current_unit(options, current) 

33 

34 

35def annual_result_basis_quantities_by_unit( 

36 *, 

37 quantity: Decimal | None, 

38 current_unit: str, 

39) -> dict[str, str]: 

40 if quantity is None: 

41 return {} 

42 source_unit = _annual_result_unit(current_unit) 

43 converted: dict[str, str] = {} 

44 for option in annual_result_basis_unit_options(current_unit): 

45 target_unit = option["value"] 

46 target_quantity = convert_quantity( 

47 value=quantity, 

48 source_unit=source_unit, 

49 target_unit=target_unit, 

50 ) 

51 if target_quantity is None: 51 ↛ 52line 51 didn't jump to line 52 because the condition on line 51 was never true

52 continue 

53 converted[target_unit] = str( 

54 target_quantity.quantize( 

55 RESULT_QUANTITY_QUANTUM, 

56 rounding=ROUND_HALF_UP, 

57 ) 

58 ) 

59 return converted 

60 

61 

62def _annual_result_basis_unit_type(unit: str) -> str: 

63 base_unit = strip_time_denominator(unit) 

64 if base_unit in price_denominator_units(UnitOfMeasure.powerPrice): 

65 return str(UnitOfMeasure.energy) 

66 return infer_physical_unit_type(base_unit) 

67 

68 

69def _annual_result_basis_base_options(unit_type: str) -> list[UnitOption]: 

70 if unit_type == UnitOfMeasure.energy: 

71 return dedupe_unit_options( 

72 [ 

73 *registry_unit_options(UnitOfMeasure.energy), 

74 *price_denominator_options(UnitOfMeasure.powerPrice), 

75 ] 

76 ) 

77 return registry_unit_options(unit_type) 

78 

79 

80def _annual_result_units_compatible(source_unit: str, target_unit: str) -> bool: 

81 return convert_quantity( 

82 value=Decimal("1"), 

83 source_unit=source_unit, 

84 target_unit=target_unit, 

85 ) is not None 

86 

87 

88def _annual_result_unit(unit: str) -> str: 

89 current = (unit or "").strip() 

90 if not current: 90 ↛ 91line 90 didn't jump to line 91 because the condition on line 90 was never true

91 return "" 

92 if "/" in current and current.rsplit("/", 1)[1].strip() in {"y", "yr", "year", "years"}: 92 ↛ 93line 92 didn't jump to line 93 because the condition on line 92 was never true

93 return current 

94 return f"{current}/year"