Various changes.
[python_utils.git] / conversion_utils.py
1 #!/usr/bin/env python3
2
3 from numbers import Number
4 from typing import Callable
5
6 import constants
7
8
9 class Converter(object):
10     def __init__(self,
11                  name: str,
12                  category: str,
13                  to_canonical: Callable,
14                  from_canonical: Callable,
15                  unit: str) -> None:
16         self.name = name
17         self.category = category
18         self.to_canonical_f = to_canonical
19         self.from_canonical_f = from_canonical
20         self.unit = unit
21
22     def to_canonical(self, n: Number) -> Number:
23         return self.to_canonical_f(n)
24
25     def from_canonical(self, n: Number) -> Number:
26         return self.from_canonical_f(n)
27
28     def unit_suffix(self) -> str:
29         return self.unit
30
31
32 conversion_catalog = {
33     "Second": Converter("Second",
34                         "time",
35                         lambda s: s,
36                         lambda s: s,
37                         "s"),
38     "Minute": Converter("Minute",
39                         "time",
40                         lambda m: (m * constants.SECONDS_PER_MINUTE),
41                         lambda s: (s / constants.SECONDS_PER_MINUTE),
42                         "m"),
43     "Hour": Converter("Hour",
44                       "time",
45                       lambda h: (h * constants.SECONDS_PER_HOUR),
46                       lambda s: (s / constants.SECONDS_PER_HOUR),
47                       "h"),
48     "Day": Converter("Day",
49                      "time",
50                      lambda d: (d * constants.SECONDS_PER_DAY),
51                      lambda s: (s / constants.SECONDS_PER_DAY),
52                      "d"),
53     "Week": Converter("Week",
54                       "time",
55                       lambda w: (w * constants.SECONDS_PER_WEEK),
56                       lambda s: (s / constants.SECONDS_PER_WEEK),
57                       "w"),
58     "Fahrenheit": Converter("Fahrenheit",
59                             "temperature",
60                             lambda f: (f - 32.0) * 0.55555555,
61                             lambda c: c * 1.8 + 32.0,
62                             "°F"),
63     "Celsius": Converter("Celsius",
64                          "temperature",
65                          lambda c: c,
66                          lambda c: c,
67                          "°C"),
68     "Kelvin": Converter("Kelvin",
69                         "temperature",
70                         lambda k: k - 273.15,
71                         lambda c: c + 273.15,
72                         "°K"),
73 }
74
75
76 def convert(magnitude: Number,
77             from_thing: str,
78             to_thing: str) -> float:
79     src = conversion_catalog.get(from_thing, None)
80     dst = conversion_catalog.get(to_thing, None)
81     if src is None or dst is None:
82         raise ValueError("No known conversion")
83     if src.category != dst.category:
84         raise ValueError("Incompatible conversion")
85     return _convert(magnitude, src, dst)
86
87
88 def _convert(magnitude: Number,
89              from_unit: Converter,
90              to_unit: Converter) -> float:
91     canonical = from_unit.to_canonical(magnitude)
92     converted = to_unit.from_canonical(canonical)
93     return float(converted)
94
95
96 def sec_to_min(s: float) -> float:
97     return convert(s, "Second", "Minute")
98
99
100 def sec_to_hour(s: float) -> float:
101     return convert(s, "Second", "Hour")
102
103
104 def sec_to_day(s: float) -> float:
105     return convert(s, "Second", "Day")
106
107
108 def sec_to_week(s: float) -> float:
109     return convert(s, "Second", "Week")
110
111
112 def min_to_sec(m: float) -> float:
113     return convert(m, "Minute", "Second")
114
115
116 def min_to_hour(m: float) -> float:
117     return convert(m, "Minute", "Hour")
118
119
120 def min_to_day(m: float) -> float:
121     return convert(m, "Minute", "Day")
122
123
124 def min_to_week(m: float) -> float:
125     return convert(m, "Minute", "Week")
126
127
128 def hour_to_sec(h: float) -> float:
129     return convert(h, "Hour", "Second")
130
131
132 def hour_to_min(h: float) -> float:
133     return convert(h, "Hour", "Minute")
134
135
136 def hour_to_day(h: float) -> float:
137     return convert(h, "Hour", "Day")
138
139
140 def hour_to_week(h: float) -> float:
141     return convert(h, "Hour", "Week")
142
143
144 def day_to_sec(d: float) -> float:
145     return convert(d, "Day", "Second")
146
147
148 def day_to_min(d: float) -> float:
149     return convert(d, "Day", "Minute")
150
151
152 def day_to_hour(d: float) -> float:
153     return convert(d, "Day", "Hour")
154
155
156 def day_to_week(d: float) -> float:
157     return convert(d, "Day", "Week")
158
159
160 def week_to_sec(w: float) -> float:
161     return convert(w, "Week", "Second")
162
163
164 def week_to_min(w: float) -> float:
165     return convert(w, "Week", "Minute")
166
167
168 def week_to_hour(w: float) -> float:
169     return convert(w, "Week", "Hour")
170
171
172 def week_to_day(w: float) -> float:
173     return convert(w, "Week", "Day")
174
175
176 def f_to_c(temp_f: float) -> float:
177     """Fahrenheit to Celsius."""
178     return convert(temp_f, "Fahrenheit", "Celsius")
179
180
181 def c_to_f(temp_c: float) -> float:
182     """Celsius to Fahrenheit."""
183     return convert(temp_c, "Celsius", "Fahrenheit")