def _location(item: str) -> Location: """ Convert a location element to a Location object """ items = item.split() if not items: return station, direction, distance = None, None, None if len(items) == 1: ilen = len(item) # MLB if ilen < 5: station = item # MKK360002 or KLGA220015 elif ilen in (9, 10) and item[-6:].isdigit(): station, direction, distance = item[:-6], item[-6:-3], item[-3:] # 10 WGON elif items[0].isdigit(): station, direction, distance = items[1][-3:], items[1][:-3], items[0] # GON 270010 elif items[1].isdigit(): station, direction, distance = items[0], items[1][:3], items[1][3:] # Convert non-null elements if direction: direction = _core.make_number(direction) if distance: distance = _core.make_number(distance) return Location(item, station, direction, distance)
def test_wind(self): """ Tests converting wind data into a spoken string """ for *wind, vardir, spoken in ( ("", "", "", None, "unknown"), ( "360", "12", "20", ["340", "020"], "three six zero (variable three four zero to zero two zero) at 12kt gusting to 20kt", ), ("000", "00", "", None, "Calm"), ("VRB", "5", "12", None, "Variable at 5kt gusting to 12kt"), ( "270", "10", "", ["240", "300"], "two seven zero (variable two four zero to three zero zero) at 10kt", ), ): wind = [_core.make_number(i) for i in wind] if vardir: vardir = [_core.make_number(i, speak=i) for i in vardir] self.assertEqual(speech.wind(*wind, vardir), "Winds " + spoken)
def test_make_number(self): """ Tests Number dataclass generation from a number string """ self.assertIsNone(_core.make_number('')) for num, value, spoken in ( ('1', 1, 'one'), ('1.5', 1.5, 'one point five'), ('060', 60, 'six zero'), ('M10', -10, 'minus one zero'), ('P6SM', None, 'greater than six'), ('M1/4', None, 'less than one quarter'), ): number = _core.make_number(num) self.assertEqual(number.repr, num) self.assertEqual(number.value, value) self.assertEqual(number.spoken, spoken) for num, value, spoken, nmr, dnm, norm in ( ('1/4', 0.25, 'one quarter', 1, 4, '1/4'), ('5/2', 2.5, 'two and one half', 5, 2, '2 1/2'), ('3/4', 0.75, 'three quarters', 3, 4, '3/4'), ('5/4', 1.25, 'one and one quarter', 5, 4, '1 1/4'), ('11/4', 1.25, 'one and one quarter', 5, 4, '1 1/4'), ): number = _core.make_number(num) self.assertEqual(number.value, value) self.assertEqual(number.spoken, spoken) self.assertEqual(number.numerator, nmr) self.assertEqual(number.denominator, dnm) self.assertEqual(number.normalized, norm) self.assertEqual(_core.make_number('1234', 'A1234').repr, 'A1234') number = _core.make_number('040', speak='040') self.assertEqual(number.value, 40) self.assertEqual(number.spoken, 'zero four zero')
def test_make_number(self): """ Tests Number dataclass generation from a number string """ self.assertIsNone(_core.make_number("")) for num, value, spoken in ( ("1", 1, "one"), ("1.5", 1.5, "one point five"), ("060", 60, "six zero"), ("M10", -10, "minus one zero"), ("P6SM", None, "greater than six"), ("M1/4", None, "less than one quarter"), ): number = _core.make_number(num) self.assertEqual(number.repr, num) self.assertEqual(number.value, value) self.assertEqual(number.spoken, spoken) for num, value, spoken, nmr, dnm, norm in ( ("1/4", 0.25, "one quarter", 1, 4, "1/4"), ("5/2", 2.5, "two and one half", 5, 2, "2 1/2"), ("3/4", 0.75, "three quarters", 3, 4, "3/4"), ("5/4", 1.25, "one and one quarter", 5, 4, "1 1/4"), ("11/4", 1.25, "one and one quarter", 5, 4, "1 1/4"), ): number = _core.make_number(num) self.assertEqual(number.value, value) self.assertEqual(number.spoken, spoken) self.assertEqual(number.numerator, nmr) self.assertEqual(number.denominator, dnm) self.assertEqual(number.normalized, norm) self.assertEqual(_core.make_number("1234", "A1234").repr, "A1234") number = _core.make_number("040", speak="040") self.assertEqual(number.value, 40) self.assertEqual(number.spoken, "zero four zero")
def test_taf_line(self): """ Tests converting TAF line data into into a single spoken string """ units = structs.Units(**static.NA_UNITS) line = { 'altimeter': _core.make_number('2992'), 'clouds': [_core.make_cloud('BKN015CB')], 'end_time': _core.make_timestamp('1206'), 'icing': ['611005'], 'other': ['+RA'], 'start_time': _core.make_timestamp('1202'), 'turbulance': ['540553'], 'type': 'FROM', 'visibility': _core.make_number('3'), 'wind_direction': _core.make_number('360'), 'wind_gust': _core.make_number('20'), 'wind_shear': 'WS020/07040KT', 'wind_speed': _core.make_number('12'), } line.update({ k: None for k in ('flight_rules', 'probability', 'raw', 'sanitized') }) line = structs.TafLineData(**line) spoken = ( 'From 2 to 6 zulu, Winds three six zero at 12kt gusting to 20kt. ' 'Wind shear 2000inHg from zero seven zero at 40kt. Visibility three miles. ' 'Altimeter two nine point nine two. Heavy Rain. ' 'Broken layer at 1500ft (Cumulonimbus). ' 'Occasional moderate turbulence in clouds from 5500ft to 8500ft. ' 'Light icing from 10000ft to 15000ft') ret = speech.taf_line(line, units) self.assertIsInstance(ret, str) self.assertEqual(ret, spoken)
def test_taf_line(self): """ Tests converting TAF line data into into a single spoken string """ units = structs.Units(**static.NA_UNITS) line = { "altimeter": _core.make_number("2992"), "clouds": [_core.make_cloud("BKN015CB")], "end_time": _core.make_timestamp("1206"), "icing": ["611005"], "other": ["+RA"], "start_time": _core.make_timestamp("1202"), "turbulence": ["540553"], "type": "FROM", "visibility": _core.make_number("3"), "wind_direction": _core.make_number("360"), "wind_gust": _core.make_number("20"), "wind_shear": "WS020/07040KT", "wind_speed": _core.make_number("12"), } line.update( {k: None for k in ("flight_rules", "probability", "raw", "sanitized")} ) line = structs.TafLineData(**line) spoken = ( "From 2 to 6 zulu, Winds three six zero at 12kt gusting to 20kt. " "Wind shear 2000inHg from zero seven zero at 40kt. Visibility three miles. " "Altimeter two nine point nine two. Heavy Rain. " "Broken layer at 1500ft (Cumulonimbus). " "Occasional moderate turbulence in clouds from 5500ft to 8500ft. " "Light icing from 10000ft to 15000ft" ) ret = speech.taf_line(line, units) self.assertIsInstance(ret, str) self.assertEqual(ret, spoken)
def test_taf(self): """ Tests end-to-end TAF translation """ units = structs.Units(**static.NA_UNITS) line_data = { "altimeter": _core.make_number("29.92", "2992"), "clouds": [_core.make_cloud("BKN015CB")], "icing": ["611005"], "other": ["+RA"], "turbulence": ["540553"], "visibility": _core.make_number("3"), "wind_direction": _core.make_number("360"), "wind_gust": _core.make_number("20"), "wind_shear": "WS020/07040KT", "wind_speed": _core.make_number("12"), } line_data.update({ k: "" for k in ( "raw", "end_time", "start_time", "probability", "type", "flight_rules", "sanitized", ) }) data = {"max_temp": "TX20/1518Z", "min_temp": "TN00/00", "remarks": ""} data.update({ k: "" for k in ("raw", "station", "time", "start_time", "end_time") }) data = structs.TafData(forecast=[structs.TafLineData(**line_data)], **data) line_trans = structs.TafLineTrans( altimeter="29.92 inHg (1013 hPa)", clouds="Broken layer at 1500ft (Cumulonimbus) - Reported AGL", icing="Light icing from 10000ft to 15000ft", other="Heavy Rain", turbulence= "Occasional moderate turbulence in clouds from 5500ft to 8500ft", visibility="3sm (4.8km)", wind_shear="Wind shear 2000ft from 070 at 40kt", wind="N-360 at 12kt gusting to 20kt", ) trans = structs.TafTrans( forecast=[line_trans], max_temp="Maximum temperature of 20°C (68°F) at 15-18:00Z", min_temp="Minimum temperature of 0°C (32°F) at 00:00Z", remarks={}, ) translated = translate.taf(data, units) self.assertIsInstance(translated, structs.TafTrans) for line in translated.forecast: self.assertIsInstance(line, structs.TafLineTrans) self.assertEqual(translated, trans)
def test_taf(self): """ Tests end-to-end TAF translation """ units = structs.Units(**static.NA_UNITS) line_data = { 'altimeter': _core.make_number('29.92', '2992'), 'clouds': [_core.make_cloud('BKN015CB')], 'icing': ['611005'], 'other': ['+RA'], 'turbulance': ['540553'], 'visibility': _core.make_number('3'), 'wind_direction': _core.make_number('360'), 'wind_gust': _core.make_number('20'), 'wind_shear': 'WS020/07040KT', 'wind_speed': _core.make_number('12') } line_data.update({ k: '' for k in ('raw', 'end_time', 'start_time', 'probability', 'type', 'flight_rules', 'sanitized') }) data = {'max_temp': 'TX20/1518Z', 'min_temp': 'TN00/00', 'remarks': ''} data.update({ k: '' for k in ('raw', 'station', 'time', 'start_time', 'end_time') }) data = structs.TafData(forecast=[structs.TafLineData(**line_data)], **data) line_trans = structs.TafLineTrans( altimeter='29.92 inHg (1013 hPa)', clouds='Broken layer at 1500ft (Cumulonimbus) - Reported AGL', icing='Light icing from 10000ft to 15000ft', other='Heavy Rain', turbulance= 'Occasional moderate turbulence in clouds from 5500ft to 8500ft', visibility='3sm (4.8km)', wind_shear='Wind shear 2000ft from 070 at 40kt', wind='N-360 at 12kt gusting to 20kt') trans = structs.TafTrans( forecast=[line_trans], max_temp='Maximum temperature of 20°C (68°F) at 15-18:00Z', min_temp='Minimum temperature of 0°C (32°F) at 00:00Z', remarks={}) translated = translate.taf(data, units) self.assertIsInstance(translated, structs.TafTrans) for line in translated.forecast: self.assertIsInstance(line, structs.TafLineTrans) self.assertEqual(translated, trans)
def test_metar(self): """ Tests end-to-end METAR translation """ units = structs.Units(**static.NA_UNITS) data = { "altimeter": _core.make_number("29.92", "2992"), "clouds": [_core.make_cloud("BKN015CB")], "dewpoint": _core.make_number("M01"), "other": ["+RA"], "temperature": _core.make_number("03"), "visibility": _core.make_number("3"), "wind_direction": _core.make_number("360"), "wind_gust": _core.make_number("20"), "wind_speed": _core.make_number("12"), "wind_variable_direction": [ _core.make_number("340"), _core.make_number("020"), ], } data.update({ k: "" for k in ( "raw", "remarks", "station", "time", "flight_rules", "remarks_info", "runway_visibility", "sanitized", ) }) data = structs.MetarData(**data) trans = structs.MetarTrans( altimeter="29.92 inHg (1013 hPa)", clouds="Broken layer at 1500ft (Cumulonimbus) - Reported AGL", dewpoint="-1°C (30°F)", other="Heavy Rain", remarks={}, temperature="3°C (37°F)", visibility="3sm (4.8km)", wind="N-360 (variable 340 to 020) at 12kt gusting to 20kt", ) translated = translate.metar(data, units) self.assertIsInstance(translated, structs.MetarTrans) self.assertEqual(translated, trans)
def parse_in_line(line: str, units: Units) -> {str: str}: """ Parser for the International TAF forcast variant """ wxdata = _core.dedupe(line.split()) wxdata = _core.sanitize_report_list(wxdata) retwx = {"sanitized": " ".join(wxdata)} ( wxdata, retwx["type"], retwx["start_time"], retwx["end_time"], ) = _core.get_type_and_times(wxdata) wxdata, retwx["wind_shear"] = _core.get_wind_shear(wxdata) ( wxdata, retwx["wind_direction"], retwx["wind_speed"], retwx["wind_gust"], _, ) = _core.get_wind(wxdata, units) if "CAVOK" in wxdata: retwx["visibility"] = _core.make_number("CAVOK") retwx["clouds"] = [] wxdata.pop(wxdata.index("CAVOK")) else: wxdata, retwx["visibility"] = _core.get_visibility(wxdata, units) wxdata, retwx["clouds"] = _core.get_clouds(wxdata) ( retwx["other"], retwx["altimeter"], retwx["icing"], retwx["turbulence"], ) = _core.get_taf_alt_ice_turb(wxdata) return retwx
def parse_lines(lines: [str], units: Units, use_na: bool = True) -> [dict]: """ Returns a list of parsed line dictionaries """ parsed_lines = [] prob = "" while lines: raw_line = lines[0].strip() line = _core.sanitize_line(raw_line) # Remove prob from the beginning of a line if line.startswith("PROB"): # Add standalone prob to next line if len(line) == 6: prob = line line = "" # Add to current line elif len(line) > 6: prob = line[:6] line = line[6:].strip() if line: parsed_line = (parse_na_line if use_na else parse_in_line)(line, units) for key in ("start_time", "end_time"): parsed_line[key] = _core.make_timestamp(parsed_line[key]) parsed_line["probability"] = _core.make_number(prob[4:]) parsed_line["raw"] = raw_line if prob: parsed_line[ "sanitized"] = prob + " " + parsed_line["sanitized"] prob = "" parsed_lines.append(parsed_line) lines.pop(0) return parsed_lines
def parse_in(report: str) -> (MetarData, Units): """ Parser for the International METAR variant """ units = Units(**IN_UNITS) wxresp = {"raw": report} clean = _core.sanitize_report_string(report) wxdata, wxresp["remarks"] = _core.get_remarks(clean) wxdata = _core.dedupe(wxdata) wxdata = _core.sanitize_report_list(wxdata) wxresp["sanitized"] = " ".join(wxdata + [wxresp["remarks"]]) wxdata, wxresp["station"], wxresp["time"] = _core.get_station_and_time(wxdata) wxdata, wxresp["runway_visibility"] = _core.get_runway_visibility(wxdata) if "CAVOK" not in wxdata: wxdata, wxresp["clouds"] = _core.get_clouds(wxdata) wxdata, wxresp["wind_direction"], wxresp["wind_speed"], wxresp["wind_gust"], wxresp[ "wind_variable_direction" ] = _core.get_wind(wxdata, units) wxdata, wxresp["altimeter"] = _core.get_altimeter(wxdata, units, "IN") if "CAVOK" in wxdata: wxresp["visibility"] = _core.make_number("CAVOK") wxresp["clouds"] = [] wxdata.remove("CAVOK") else: wxdata, wxresp["visibility"] = _core.get_visibility(wxdata, units) wxresp["other"], wxresp["temperature"], wxresp["dewpoint"] = _core.get_temp_and_dew( wxdata ) condition = _core.get_flight_rules( wxresp["visibility"], _core.get_ceiling(wxresp["clouds"]) ) wxresp["flight_rules"] = FLIGHT_RULES[condition] wxresp["remarks_info"] = remarks.parse(wxresp["remarks"]) wxresp["time"] = _core.make_timestamp(wxresp["time"]) return MetarData(**wxresp), units
def test_type_and_times(self): """ Tests line start from type, time, and probability values """ for type, *times, prob, spoken in ( (None, None, None, None, ""), ("FROM", "2808", "2815", None, "From 8 to 15 zulu,"), ("FROM", "2822", "2903", None, "From 22 to 3 zulu,"), ("BECMG", "3010", None, None, "At 10 zulu becoming"), ( "PROB", "1303", "1305", "30", r"From 3 to 5 zulu, there's a 30% chance for", ), ( "INTER", "1303", "1305", "45", r"From 3 to 5 zulu, there's a 45% chance for intermittent", ), ("INTER", "2423", "2500", None, "From 23 to midnight zulu, intermittent"), ("TEMPO", "0102", "0103", None, "From 2 to 3 zulu, temporary"), ): times = [_core.make_timestamp(time) for time in times] if prob is not None: prob = _core.make_number(prob) ret = speech.type_and_times(type, *times, prob) self.assertIsInstance(ret, str) self.assertEqual(ret, spoken)
def _altitude(item: str) -> "Number|str": """ Convert reporting altitude to a Number or string """ if item.isdigit(): return _core.make_number(item) return item
def test_wind(self): """ Tests that wind values are translating into a single string """ for *wind, vardir, translation in ( ('', '', '', None, ''), ('360', '12', '20', ['340', '020'], 'N-360 (variable 340 to 020) at 12kt gusting to 20kt'), ('000', '00', '', None, 'Calm'), ('VRB', '5', '12', None, 'Variable at 5kt gusting to 12kt'), ('270', '10', '', ['240', '300'], 'W-270 (variable 240 to 300) at 10kt'), ): wind = [_core.make_number(i) for i in wind] if vardir: vardir = [_core.make_number(i) for i in vardir] self.assertEqual(translate.wind(*wind, vardir), translation)
def test_metar(self): """ Tests converting METAR data into into a single spoken string """ units = structs.Units(**static.NA_UNITS) data = { "altimeter": _core.make_number("2992"), "clouds": [_core.make_cloud("BKN015CB")], "dewpoint": _core.make_number("M01"), "other": ["+RA"], "temperature": _core.make_number("03"), "visibility": _core.make_number("3"), "wind_direction": _core.make_number("360"), "wind_gust": _core.make_number("20"), "wind_speed": _core.make_number("12"), "wind_variable_direction": [ _core.make_number("340"), _core.make_number("020", speak="020"), ], } data.update({ k: None for k in ( "raw", "remarks", "station", "time", "flight_rules", "remarks_info", "runway_visibility", "sanitized", ) }) data = structs.MetarData(**data) spoken = ( "Winds three six zero (variable three four zero to zero two zero) " "at 12kt gusting to 20kt. Visibility three miles. " "Temperature three degrees Celsius. Dew point minus one degree Celsius. " "Altimeter two nine point nine two. Heavy Rain. " "Broken layer at 1500ft (Cumulonimbus)") ret = speech.metar(data, units) self.assertIsInstance(ret, str) self.assertEqual(ret, spoken)
def test_get_taf_alt_ice_turb(self): """ Tests that report global altimeter, icing, and turbulance get removed """ for wx, *data in ((['1'], '', [], []), (['1', '512345', '612345'], '', ['612345'], ['512345']), (['QNH1234', '1', '612345'], _core.make_number('1234'), ['612345'], [])): self.assertEqual(_core.get_taf_alt_ice_turb(wx), (['1'], *data))
def test_wind(self): """ Tests converting wind data into a spoken string """ for *wind, vardir, spoken in ( ('', '', '', None, 'unknown'), ('360', '12', '20', ['340', '020'], 'three six zero (variable three four zero to zero two zero) at 12kt gusting to 20kt' ), ('000', '00', '', None, 'Calm'), ('VRB', '5', '12', None, 'Variable at 5kt gusting to 12kt'), ('270', '10', '', ['240', '300'], 'two seven zero (variable two four zero to three zero zero) at 10kt' ), ): wind = [_core.make_number(i) for i in wind] if vardir: vardir = [_core.make_number(i, speak=i) for i in vardir] self.assertEqual(speech.wind(*wind, vardir), 'Winds ' + spoken)
def test_shared(self): """ Tests availibility of shared values between the METAR and TAF translations """ units = structs.Units(**static.NA_UNITS) data = structs.SharedData(altimeter=_core.make_number('2992'), clouds=[_core.make_cloud('OVC060')], flight_rules='', other=['RA'], sanitized='', visibility=_core.make_number('10'), wind_direction=_core.make_number('0'), wind_gust=_core.make_number('0'), wind_speed=_core.make_number('0')) trans = translate.shared(data, units) self.assertIsInstance(trans, dict) for key in ('altimeter', 'clouds', 'other', 'visibility'): self.assertIn(key, trans) self.assertTrue(bool(trans[key]))
def test_parse(self): """ Tests generating RemarksData from a remarks string """ for rmk, data in ( ('', (None, None)), ('T09870123', ('12.3', '98.7')), ('RMK AO2 SLP141 T02670189 $', ('18.9', '26.7')), ): data = [_core.make_number(d) for d in data] self.assertEqual(remarks.parse(rmk), structs.RemarksData(*data))
def test_get_taf_alt_ice_turb(self): """ Tests that report global altimeter, icing, and turbulance get removed """ for wx, *data in ( (["1"], "", [], []), (["1", "512345", "612345"], "", ["612345"], ["512345"]), (["QNH1234", "1", "612345"], _core.make_number("1234"), ["612345"], []), ): self.assertEqual(_core.get_taf_alt_ice_turb(wx), (["1"], *data))
def test_parse(self): """ Tests generating RemarksData from a remarks string """ for rmk, data in ( ("", (None, None)), ("T09870123", ("12.3", "98.7")), ("RMK AO2 SLP141 T02670189 $", ("18.9", "26.7")), ): data = [_core.make_number(d) for d in data] self.assertEqual(remarks.parse(rmk), structs.RemarksData(*data))
def test_shared(self): """ Tests availability of shared values between the METAR and TAF translations """ units = structs.Units(**static.NA_UNITS) data = structs.SharedData( altimeter=_core.make_number("2992"), clouds=[_core.make_cloud("OVC060")], flight_rules="", other=["RA"], sanitized="", visibility=_core.make_number("10"), wind_direction=_core.make_number("0"), wind_gust=_core.make_number("0"), wind_speed=_core.make_number("0"), ) trans = translate.shared(data, units) self.assertIsInstance(trans, dict) for key in ("altimeter", "clouds", "other", "visibility"): self.assertIn(key, trans) self.assertTrue(bool(trans[key]))
def test_metar(self): """ Tests end-to-end METAR translation """ units = structs.Units(**static.NA_UNITS) data = { 'altimeter': _core.make_number('29.92', '2992'), 'clouds': [_core.make_cloud('BKN015CB')], 'dewpoint': _core.make_number('M01'), 'other': ['+RA'], 'temperature': _core.make_number('03'), 'visibility': _core.make_number('3'), 'wind_direction': _core.make_number('360'), 'wind_gust': _core.make_number('20'), 'wind_speed': _core.make_number('12'), 'wind_variable_direction': [_core.make_number('340'), _core.make_number('020')] } data.update({ k: '' for k in ('raw', 'remarks', 'station', 'time', 'flight_rules', 'remarks_info', 'runway_visibility', 'sanitized') }) data = structs.MetarData(**data) trans = structs.MetarTrans( altimeter='29.92 inHg (1013 hPa)', clouds='Broken layer at 1500ft (Cumulonimbus) - Reported AGL', dewpoint='-1°C (30°F)', other='Heavy Rain', remarks={}, temperature='3°C (37°F)', visibility='3sm (4.8km)', wind='N-360 (variable 340 to 020) at 12kt gusting to 20kt') translated = translate.metar(data, units) self.assertIsInstance(translated, structs.MetarTrans) self.assertEqual(translated, trans)
def test_wind(self): """ Tests that wind values are translating into a single string """ for *wind, vardir, translation in ( ("", "", "", None, ""), ( "360", "12", "20", ["340", "020"], "N-360 (variable 340 to 020) at 12kt gusting to 20kt", ), ("000", "00", "", None, "Calm"), ("VRB", "5", "12", None, "Variable at 5kt gusting to 12kt"), ("270", "10", "", ["240", "300"], "W-270 (variable 240 to 300) at 10kt"), ): wind = [_core.make_number(i) for i in wind] if vardir: vardir = [_core.make_number(i) for i in vardir] self.assertEqual(translate.wind(*wind, vardir), translation)
def test_temperature(self): """ Tests temperature translation and conversion """ for temp, unit, translation in ( ('20', 'F', '20°F (-7°C)'), ('M20', 'F', '-20°F (-29°C)'), ('20', 'C', '20°C (68°F)'), ('M20', 'C', '-20°C (-4°F)'), ('', 'F', ''), ): self.assertEqual( translate.temperature(_core.make_number(temp), unit), translation)
def test_temperature(self): """ Tests temperature translation and conversion """ for temp, unit, translation in ( ("20", "F", "20°F (-7°C)"), ("M20", "F", "-20°F (-29°C)"), ("20", "C", "20°C (68°F)"), ("M20", "C", "-20°C (-4°F)"), ("", "F", ""), ): self.assertEqual( translate.temperature(_core.make_number(temp), unit), translation)
def _find_floor_ceiling(items: [str]) -> ([str], dict): """ Extracts the floor and ceiling from item list """ ret = {"floor": None, "ceiling": None} for i, item in enumerate(items): hloc = item.find("-") # TRACE RIME 070-090 if hloc > -1 and item[:hloc].isdigit() and item[hloc + 1:].isdigit(): for key, val in zip(("floor", "ceiling"), items.pop(i).split("-")): ret[key] = _core.make_number(val) break # CONT LGT CHOP BLO 250 elif item in _DIR_SIG: ret[_DIR_SIG[item]] = _core.make_number(items[i + 1]) items = items[:i] break # LGT RIME 025 elif item.isdigit(): num = _core.make_number(item) ret["floor"], ret["ceiling"] = num, num break return items, ret
def test_temperature(self): """ Tests converting a temperature into a spoken string """ for temp, unit, spoken in ( ('', 'F', 'unknown'), ('20', 'F', 'two zero degrees Fahrenheit'), ('M20', 'F', 'minus two zero degrees Fahrenheit'), ('20', 'C', 'two zero degrees Celsius'), ('1', 'C', 'one degree Celsius'), ): self.assertEqual( speech.temperature('Temp', _core.make_number(temp), unit), 'Temp ' + spoken)
def _turbulance(item: str) -> Turbulance: """ Convert reported turbulance to a Turbulance object """ items = item.split() ret = {"severity": None, "floor": None, "ceiling": None} for i, item in enumerate(items): hloc = item.find("-") if hloc > -1 and item[:hloc].isdigit() and item[hloc + 1:].isdigit(): for key, val in zip(("floor", "ceiling"), items.pop(i).split("-")): ret[key] = _core.make_number(val) break ret["severity"] = " ".join(items) return Turbulance(**ret)