from __future__ import annotations from decimal import Decimal, InvalidOperation, ROUND_HALF_UP FUEL_FACTORS: list[tuple[str, Decimal]] = [ ("HTPB", Decimal("0.00177")), ("Solid", Decimal("0.00178")), ("PBAN", Decimal("0.001772")), ("Kerolox", Decimal("0.0010290673")), ("Hydrolox", Decimal("0.00036235886")), ("Methalox", Decimal("0.000845043157")), ("Hydrazine", Decimal("0.001004")), ("MMH/NTO", Decimal("0.00116557")), ] FUEL_DENSITY_T_PER_LITER = dict(FUEL_FACTORS) VALUE_STEP = Decimal("0.000001") def list_fuel_factors() -> list[dict[str, float | str]]: return [ {"fuel": fuel, "tonnes_per_liter": _to_float(factor)} for fuel, factor in FUEL_FACTORS ] def convert_value(mode: str, raw_value: object) -> dict[str, object]: value = _parse_positive_decimal(raw_value) normalized_mode = mode.strip().lower() if normalized_mode == "volume": results = [ { "fuel": fuel, "value": _to_float(value * factor), "unit": "t", } for fuel, factor in FUEL_FACTORS ] return { "mode": normalized_mode, "input_value": _to_float(value), "input_unit": "L", "results": results, } if normalized_mode == "mass": results = [ { "fuel": fuel, "value": _to_float(value / factor), "unit": "L", } for fuel, factor in FUEL_FACTORS ] return { "mode": normalized_mode, "input_value": _to_float(value), "input_unit": "t", "results": results, } raise ValueError("mode must be either 'volume' or 'mass'") def _parse_positive_decimal(raw_value: object) -> Decimal: try: value = Decimal(str(raw_value)) except (InvalidOperation, ValueError, TypeError) as exc: raise ValueError("value must be numeric") from exc if value <= 0: raise ValueError("value must be greater than zero") return value def _to_float(value: Decimal) -> float: return float(value.quantize(VALUE_STEP, rounding=ROUND_HALF_UP))