import os
from typing import Callable, Optional, TypeVar
INVALID_UNIT_ERR = ValueError("Invalid unit. Must be 'C', 'F', or 'K'.")
# python generics my beloved
T = TypeVar("T")
def prompt(
msg: str,
transform: Optional[Callable[[str], T]] = None,
err_msg="Invalid response, please try again.",
) -> T:
transform_fn = (lambda x: x) if transform is None else transform
while True:
try:
return transform_fn(input(msg).strip())
except Exception:
# windows (command prompt only) doesn't have `clear` command
os.system("cls" if os.name == "nt" else "clear")
print(err_msg)
def parse_unit(unit: str) -> str:
if unit.lower() not in ["c", "f", "k"]:
raise INVALID_UNIT_ERR
return unit.lower()
def calculate_temperatures(temperature: float, unit: str) -> dict[str, float]:
conversions = {
"c": temperature,
"f": (temperature - 32) * 5 / 9,
"k": temperature - 273.15,
}
celsius = conversions[unit]
return {
"celsius": celsius,
"fahrenheit": celsius * 9 / 5 + 32,
"kelvin": celsius + 273.15,
}
def temperature_table(temperatures: dict[str, float]) -> str:
headers = ["Unit", "Temperature"]
rows = [(unit.title(), f"{temp:.2f}") for unit, temp in temperatures.items()]
max_unit_w = max(len(headers[0]), max(len(row[0]) for row in rows))
max_temp_w = max(len(headers[1]), max(len(row[1]) for row in rows))
row_template = f"â {{:<{max_unit_w}}} â {{:>{max_temp_w}}} â"
border = f"â{'â' * (max_unit_w + 2)}âŽ{'â' * (max_temp_w + 2)}âŪ"
separator = f"â{'â' * (max_unit_w + 2)}âž{'â' * (max_temp_w + 2)}âĪ"
footer = f"â°{'â' * (max_unit_w + 2)}âī{'â' * (max_temp_w + 2)}âŊ"
table = [border, row_template.format(*headers), separator]
table.extend(row_template.format(unit, temp) for unit, temp in rows)
table.append(footer)
return "\n".join(table)
def main() -> None:
temperature = prompt(
"Enter a temperature: ", float, "Please enter a valid number."
)
unit = prompt(
"Enter the unit of the temperature (C/F/K): ",
parse_unit,
"Please enter 'C', 'F', or 'K'.",
)
temperatures = calculate_temperatures(temperature, unit)
print(f"Based on {temperature:.2f}°{unit.upper()}:")
print(temperature_table(temperatures))
if __name__ == "__main__":
main()