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
« prev ^ index » next coverage.py v7.10.7, created at 2026-06-23 21:51 +0000
1from decimal import Decimal, ROUND_HALF_UP
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)
17RESULT_QUANTITY_QUANTUM = Decimal("0.00000001")
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)
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)
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
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)
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)
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
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"