Ejemplo n.º 1
0
 def test_taf_line(self):
     """Tests converting TAF line data into into a single spoken string"""
     units = structs.Units(**static.core.NA_UNITS)
     line = {
         "altimeter": parse_altimeter("2992"),
         "clouds": [core.make_cloud("BKN015CB")],
         "end_time": core.make_timestamp("1206"),
         "icing": ["611005"],
         "other": [],
         "start_time": core.make_timestamp("1202"),
         "transition_start": None,
         "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"),
         "wx_codes": get_wx_codes(["+RA"])[1],
     }
     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 2000ft 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)
Ejemplo n.º 2
0
 def test_taf(self):
     """
     Tests end-to-end TAF translation
     """
     units = structs.Units(**static.core.NA_UNITS)
     line_data = {
         "altimeter": core.make_number("29.92", "2992"),
         "clouds": [core.make_cloud("BKN015CB")],
         "icing": ["611005"],
         "other": [],
         "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"),
         "wx_codes": get_wx_codes(["+RA"])[1],
     }
     line_data.update({
         k: ""
         for k in (
             "raw",
             "end_time",
             "start_time",
             "transition_start",
             "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",
         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",
         wx_codes="Heavy Rain",
     )
     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.translate_taf(data, units)
     self.assertIsInstance(translated, structs.TafTrans)
     for line in translated.forecast:
         self.assertIsInstance(line, structs.TafLineTrans)
     self.assertEqual(translated, trans)
Ejemplo n.º 3
0
def parse_na(report: str) -> (MetarData, Units):
    """
    Parser for the North American METAR variant
    """
    units = Units(**NA_UNITS)
    wxresp = {"raw": report}
    clean = core.sanitize_report_string(report)
    wxdata, wxresp["remarks"] = 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"] = get_runway_visibility(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"] = get_altimeter(wxdata, units, "NA")
    wxdata, wxresp["visibility"] = core.get_visibility(wxdata, units)
    wxdata, wxresp["temperature"], wxresp["dewpoint"] = get_temp_and_dew(
        wxdata)
    condition = core.get_flight_rules(wxresp["visibility"],
                                      core.get_ceiling(wxresp["clouds"]))
    wxresp["other"], wxresp["wx_codes"] = get_wx_codes(wxdata)
    wxresp["flight_rules"] = FLIGHT_RULES[condition]
    wxresp["remarks_info"] = remarks.parse(wxresp["remarks"])
    wxresp["time"] = core.make_timestamp(wxresp["time"])
    return MetarData(**wxresp), units
Ejemplo n.º 4
0
def parse_in(report: str, issued: date = None) -> (MetarData, Units):
    """
    Parser for the International METAR variant
    """
    units = Units(**IN_UNITS)
    resp = {"raw": report}
    resp["sanitized"], resp["remarks"], data = sanitize(report)
    data, resp["station"], resp["time"] = core.get_station_and_time(data)
    data, resp["runway_visibility"] = get_runway_visibility(data)
    if "CAVOK" not in data:
        data, resp["clouds"] = core.get_clouds(data)
    (
        data,
        resp["wind_direction"],
        resp["wind_speed"],
        resp["wind_gust"],
        resp["wind_variable_direction"],
    ) = core.get_wind(data, units)
    data, resp["altimeter"] = get_altimeter(data, units, "IN")
    if "CAVOK" in data:
        resp["visibility"] = core.make_number("CAVOK")
        resp["clouds"] = []
        data.remove("CAVOK")
    else:
        data, resp["visibility"] = core.get_visibility(data, units)
    data, resp["temperature"], resp["dewpoint"] = get_temp_and_dew(data)
    condition = core.get_flight_rules(resp["visibility"],
                                      core.get_ceiling(resp["clouds"]))
    resp["other"], resp["wx_codes"] = get_wx_codes(data)
    resp["flight_rules"] = FLIGHT_RULES[condition]
    resp["remarks_info"] = remarks.parse(resp["remarks"])
    resp["time"] = core.make_timestamp(resp["time"], target_date=issued)
    return MetarData(**resp), units
Ejemplo n.º 5
0
def parse_na(report: str, issued: date = None) -> Tuple[MetarData, Units]:
    """Parser for the North American METAR variant"""
    units = Units(**NA_UNITS)
    resp = {"raw": report}
    resp["sanitized"], resp["remarks"], data = sanitize(report)
    data, resp["station"], resp["time"] = core.get_station_and_time(data)
    data, resp["runway_visibility"] = get_runway_visibility(data)
    data, resp["clouds"] = core.get_clouds(data)
    (
        data,
        resp["wind_direction"],
        resp["wind_speed"],
        resp["wind_gust"],
        resp["wind_variable_direction"],
    ) = core.get_wind(data, units)
    data, resp["altimeter"] = get_altimeter(data, units, "NA")
    data, resp["visibility"] = core.get_visibility(data, units)
    data, resp["temperature"], resp["dewpoint"] = get_temp_and_dew(data)
    condition = core.get_flight_rules(
        resp["visibility"], core.get_ceiling(resp["clouds"])
    )
    resp["other"], resp["wx_codes"] = get_wx_codes(data)
    resp["flight_rules"] = FLIGHT_RULES[condition]
    resp["remarks_info"] = remarks.parse(resp["remarks"])
    resp["time"] = core.make_timestamp(resp["time"], target_date=issued)
    return MetarData(**resp), units
Ejemplo n.º 6
0
 def test_wx_codes(self):
     """Tests translating a list of weather codes into a single string"""
     for codes, translation in (
         ([], ""),
         (["VCFC", "+RA"], "Vicinity Funnel Cloud, Heavy Rain"),
         (["-SN"], "Light Snow"),
     ):
         codes = get_wx_codes(codes)[1]
         self.assertEqual(translate.base.wx_codes(codes), translation)
Ejemplo n.º 7
0
 def test_metar(self):
     """
     Tests end-to-end METAR translation
     """
     units = structs.Units(**static.core.NA_UNITS)
     data = {
         "altimeter":
         core.make_number("29.92", "2992"),
         "clouds": [core.make_cloud("BKN015CB")],
         "dewpoint":
         core.make_number("M01"),
         "other": [],
         "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"),
         ],
         "wx_codes":
         get_wx_codes(["+RA"])[1],
     }
     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)",
         remarks={},
         temperature="3°C (37°F)",
         visibility="3sm (4.8km)",
         wind="N-360 (variable 340 to 020) at 12kt gusting to 20kt",
         wx_codes="Heavy Rain",
     )
     translated = translate.metar.translate_metar(data, units)
     self.assertIsInstance(translated, structs.MetarTrans)
     self.assertEqual(translated, trans)
Ejemplo n.º 8
0
 def test_metar(self):
     """
     Tests converting METAR data into into a single spoken string
     """
     units = structs.Units(**static.core.NA_UNITS)
     data = {
         "altimeter":
         parse_altimeter("2992"),
         "clouds": [core.make_cloud("BKN015CB")],
         "dewpoint":
         core.make_number("M01"),
         "other": [],
         "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"),
         ],
         "wx_codes":
         get_wx_codes(["+RA"])[1],
     }
     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)
Ejemplo n.º 9
0
 def test_wx_codes(self):
     """Tests converting WX codes into a spoken string"""
     for codes, spoken in (
         ([], ""),
         (
             ["+RATS", "VCFC"],
             "Heavy Rain Thunderstorm. Funnel Cloud in the Vicinity",
         ),
         (
             ["-GR", "FZFG", "BCBLSN"],
             "Light Hail. Freezing Fog. Patchy Blowing Snow",
         ),
     ):
         codes = get_wx_codes(codes)[1]
         self.assertEqual(speech.wx_codes(codes), spoken)
Ejemplo n.º 10
0
 def test_shared(self):
     """Tests availability of shared values between the METAR and TAF translations"""
     units = structs.Units(**static.core.NA_UNITS)
     data = structs.SharedData(
         altimeter=core.make_number("2992"),
         clouds=[core.make_cloud("OVC060")],
         flight_rules="",
         other=[],
         sanitized="",
         visibility=core.make_number("10"),
         wind_direction=core.make_number("0"),
         wind_gust=core.make_number("0"),
         wind_speed=core.make_number("0"),
         wx_codes=get_wx_codes(["RA"])[1],
     )
     trans = translate.base.current_shared(data, units)
     self.assertIsInstance(trans, dict)
     for key in ("altimeter", "clouds", "visibility", "wx_codes"):
         self.assertIn(key, trans)
         self.assertTrue(bool(trans[key]))
Ejemplo n.º 11
0
def parse(station: str, report: str) -> (TafData, Units):
    """
    Returns TafData and Units dataclasses with parsed data and their associated units
    """
    if not report:
        return None, None
    valid_station(station)
    while len(report) > 3 and report[:4] in ("TAF ", "AMD ", "COR "):
        report = report[4:]
    retwx = {
        "end_time": None,
        "raw": report,
        "remarks": None,
        "start_time": None
    }
    report = core.sanitize_report_string(report)
    _, station, time = core.get_station_and_time(report[:20].split())
    retwx["station"] = station
    retwx["time"] = core.make_timestamp(time)
    report = report.replace(station, "")
    if time:
        report = report.replace(time, "").strip()
    if uses_na_format(station):
        use_na = True
        units = Units(**NA_UNITS)
    else:
        use_na = False
        units = Units(**IN_UNITS)
    # Find and remove remarks
    report, retwx["remarks"] = get_taf_remarks(report)
    # Split and parse each line
    lines = split_taf(report)
    parsed_lines = parse_lines(lines, units, use_na)
    # Perform additional info extract and corrections
    if parsed_lines:
        (
            parsed_lines[-1]["other"],
            retwx["max_temp"],
            retwx["min_temp"],
        ) = get_temp_min_and_max(parsed_lines[-1]["other"])
        if not (retwx["max_temp"] or retwx["min_temp"]):
            (
                parsed_lines[0]["other"],
                retwx["max_temp"],
                retwx["min_temp"],
            ) = get_temp_min_and_max(parsed_lines[0]["other"])
        # Set start and end times based on the first line
        start, end = parsed_lines[0]["start_time"], parsed_lines[0]["end_time"]
        parsed_lines[0]["end_time"] = None
        retwx["start_time"], retwx["end_time"] = start, end
        parsed_lines = find_missing_taf_times(parsed_lines, start, end)
        parsed_lines = get_taf_flight_rules(parsed_lines)
    # Extract Oceania-specific data
    if retwx["station"][0] == "A":
        (
            parsed_lines[-1]["other"],
            retwx["alts"],
            retwx["temps"],
        ) = get_oceania_temp_and_alt(parsed_lines[-1]["other"])
    # Convert wx codes
    for i, line in enumerate(parsed_lines):
        parsed_lines[i]["other"], parsed_lines[i]["wx_codes"] = get_wx_codes(
            line["other"])
    # Convert to dataclass
    retwx["forecast"] = [TafLineData(**line) for line in parsed_lines]
    return TafData(**retwx), units