Exemplo n.º 1
0
 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)
Exemplo n.º 2
0
 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)
Exemplo n.º 3
0
 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'),
     ):
         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')
Exemplo n.º 4
0
 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'),
     ):
         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')
Exemplo n.º 5
0
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
        # KLGA220015
        elif ilen == 10 and item[4:].isdigit():
            station, direction, distance = item[:4], item[4:7], item[7:]
    # 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)
Exemplo n.º 6
0
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
        # KLGA220015
        elif ilen == 10 and item[4:].isdigit():
            station, direction, distance = item[:4], item[4:7], item[7:]
    # 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)
Exemplo n.º 7
0
def parse(rmk: str) -> RemarksData:
    """
    Finds temperature and dewpoint decimal values from the remarks
    """
    rmkdata = {}
    for item in rmk.split(' '):
        if len(item) in [5, 9] and item[0] == 'T' and item[1:].isdigit():
            rmkdata['temperature_decimal'] = core.make_number(_tdec(item[1:5], None))
            rmkdata['dewpoint_decimal'] = core.make_number(_tdec(item[5:], None))
    return RemarksData(**rmkdata)
Exemplo n.º 8
0
 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)
Exemplo n.º 9
0
 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)
Exemplo n.º 10
0
 def test_taf(self):
     """
     Tests end-to-end TAF translation
     """
     units = structs.Units(**static.NA_UNITS)
     line_data = {
         'altimeter': core.make_number('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)
Exemplo n.º 11
0
 def test_taf(self):
     """
     Tests end-to-end TAF translation
     """
     units = structs.Units(**static.NA_UNITS)
     line_data = {
         'altimeter': core.make_number('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)
Exemplo n.º 12
0
 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)
Exemplo n.º 13
0
 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)
Exemplo n.º 14
0
 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)
Exemplo n.º 15
0
def _altitude(item: str) -> 'Number|str':
    """
    Convert reporting altitude to a Number or string
    """
    if item.isdigit():
        return core.make_number(item)
    return item
Exemplo n.º 16
0
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
            parsed_line['sanitized'] = prob + ' ' + line if prob else line
            prob = ''
            parsed_lines.append(parsed_line)
        lines.pop(0)
    return parsed_lines
Exemplo n.º 17
0
def _altitude(item: str) -> 'Number|str':
    """
    Convert reporting altitude to a Number or string
    """
    if item.isdigit():
        return core.make_number(item)
    return item
Exemplo n.º 18
0
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
            parsed_line['sanitized'] = prob + ' ' + line if prob else line
            prob = ''
            parsed_lines.append(parsed_line)
        lines.pop(0)
    return parsed_lines
Exemplo n.º 19
0
def parse_in(txt: str) -> (MetarData, Units):
    """
    Parser for the International METAR variant
    """
    units = Units(**IN_UNITS)
    clean = core.sanitize_report_string(txt)
    wxresp = {'raw': txt, 'sanitized': clean}
    wxdata, wxresp['remarks'] = core.get_remarks(clean)
    wxdata, wxresp['runway_visibility'], _ = core.sanitize_report_list(wxdata)
    wxdata, wxresp['station'], wxresp['time'] = core.get_station_and_time(
        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
Exemplo n.º 20
0
 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)
Exemplo n.º 21
0
 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]))
Exemplo n.º 22
0
def _turbulance(item: str) -> Turbulance:
    """
    Convert reported turbulance to a Turbulance object
    """
    items = item.split()
    ret = {'severity': items.pop(0), 'floor': None, 'ceiling': None}
    if items and '-' in items[0]:
        for key, val in zip(('floor', 'ceiling'), items[0].split('-')):
            ret[key] = core.make_number(val)
    return Turbulance(**ret)
Exemplo n.º 23
0
def _turbulance(item: str) -> Turbulance:
    """
    Convert reported turbulance to a Turbulance object
    """
    items = item.split()
    ret = {'severity': items.pop(0), 'floor': None, 'ceiling': None}
    if items and '-' in items[0]:
        for key, val in zip(('floor', 'ceiling'), items[0].split('-')):
            ret[key] = core.make_number(val)
    return Turbulance(**ret)
Exemplo n.º 24
0
 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))
Exemplo n.º 25
0
 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))
Exemplo n.º 26
0
 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]))
Exemplo n.º 27
0
 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)
Exemplo n.º 28
0
 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)
Exemplo n.º 29
0
 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)
Exemplo n.º 30
0
 def test_metar(self):
     """
     Tests end-to-end METAR translation
     """
     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')]
     }
     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)
Exemplo n.º 31
0
def _icing(item: str) -> Icing:
    """
    Convert reported icing to an Icing object
    """
    items = item.split()
    ret = {'severity': items.pop(0), 'type': None, 'floor': None, 'ceiling': None}
    for item in items:
        if '-' in item:
            for key, val in zip(('floor', 'ceiling'), item.split('-')):
                ret[key] = core.make_number(val)
        else:
            ret['type'] = item
    return Icing(**ret)
Exemplo n.º 32
0
 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)
Exemplo n.º 33
0
 def test_altimeter(self):
     """
     Tests converting altimeter reading into a spoken string
     """
     for alt, unit, spoken in (
         ('', 'hPa', 'unknown'),
         ('1020', 'hPa', 'one zero two zero'),
         ('0999', 'hPa', 'zero nine nine nine'),
         ('1012', 'hPa', 'one zero one two'),
         ('3000', 'inHg', 'three zero point zero zero'),
         ('2992', 'inHg', 'two nine point nine two'),
         ('3005', 'inHg', 'three zero point zero five'),
     ):
         self.assertEqual(speech.altimeter(core.make_number(alt), unit), 'Altimeter ' + spoken)
Exemplo n.º 34
0
 def test_altimeter(self):
     """
     Tests converting altimeter reading into a spoken string
     """
     for alt, unit, spoken in (
         ('', 'hPa', 'unknown'),
         ('1020', 'hPa', 'one zero two zero'),
         ('0999', 'hPa', 'zero nine nine nine'),
         ('1012', 'hPa', 'one zero one two'),
         ('3000', 'inHg', 'three zero point zero zero'),
         ('2992', 'inHg', 'two nine point nine two'),
         ('3005', 'inHg', 'three zero point zero five'),
     ):
         self.assertEqual(speech.altimeter(core.make_number(alt), unit), 'Altimeter ' + spoken)
Exemplo n.º 35
0
 def test_altimeter(self):
     """
     Tests altimeter translation and conversion
     """
     for alt, unit, translation in (
         ('', 'hPa', ''),
         ('1020', 'hPa', '1020 hPa (30.12 inHg)'),
         ('0999', 'hPa', '0999 hPa (29.5 inHg)'),
         ('1012', 'hPa', '1012 hPa (29.88 inHg)'),
         ('3000', 'inHg', '30.00 inHg (1016 hPa)'),
         ('2992', 'inHg', '29.92 inHg (1013 hPa)'),
         ('3005', 'inHg', '30.05 inHg (1018 hPa)'),
     ):
         self.assertEqual(translate.altimeter(core.make_number(alt), unit), translation)
Exemplo n.º 36
0
 def test_altimeter(self):
     """
     Tests altimeter translation and conversion
     """
     for alt, unit, translation in (
         ('', 'hPa', ''),
         ('1020', 'hPa', '1020 hPa (30.12 inHg)'),
         ('0999', 'hPa', '0999 hPa (29.5 inHg)'),
         ('1012', 'hPa', '1012 hPa (29.88 inHg)'),
         ('3000', 'inHg', '30.00 inHg (1016 hPa)'),
         ('2992', 'inHg', '29.92 inHg (1013 hPa)'),
         ('3005', 'inHg', '30.05 inHg (1018 hPa)'),
     ):
         self.assertEqual(translate.altimeter(core.make_number(alt), unit),
                          translation)
Exemplo n.º 37
0
 def test_visibility(self):
     """
     Tests converting visibility distance into a spoken string
     """
     for vis, unit, spoken in (
         ('', 'm', 'unknown'),
         ('0000', 'm', 'zero kilometers'),
         ('2000', 'm', 'two kilometers'),
         ('0900', 'm', 'point nine kilometers'),
         ('P6', 'sm', 'greater than six miles'),
         ('M1/4', 'sm', 'less than one quarter of a mile'),
         ('3/4', 'sm', 'three quarters of a mile'),
         ('3/2', 'sm', 'one and one half miles'),
         ('3', 'sm', 'three miles'),
     ):
         self.assertEqual(speech.visibility(core.make_number(vis), unit), 'Visibility ' + spoken)
Exemplo n.º 38
0
 def test_visibility(self):
     """
     Tests visibility translation and conversion
     """
     for vis, unit, translation in (
         ('', 'm', ''),
         ('0000', 'm', '0km (0sm)'),
         ('2000', 'm', '2km (1.2sm)'),
         ('0900', 'm', '0.9km (0.6sm)'),
         ('P6', 'sm', 'Greater than 6sm ( >10km )'),
         ('M1/4', 'sm', 'Less than .25sm ( <0.4km )'),
         ('3/4', 'sm', '0.75sm (1.2km)'),
         ('3/2', 'sm', '1.5sm (2.4km)'),
         ('3', 'sm', '3sm (4.8km)'),
     ):
         self.assertEqual(translate.visibility(core.make_number(vis), unit), translation)
Exemplo n.º 39
0
 def test_visibility(self):
     """
     Tests converting visibility distance into a spoken string
     """
     for vis, unit, spoken in (
         ('', 'm', 'unknown'),
         ('0000', 'm', 'zero kilometers'),
         ('2000', 'm', 'two kilometers'),
         ('0900', 'm', 'point nine kilometers'),
         ('P6', 'sm', 'greater than six miles'),
         ('M1/4', 'sm', 'less than one quarter of a mile'),
         ('3/4', 'sm', 'three quarters of a mile'),
         ('3/2', 'sm', 'one and one half miles'),
         ('3', 'sm', 'three miles'),
     ):
         self.assertEqual(speech.visibility(core.make_number(vis), unit), 'Visibility ' + spoken)
Exemplo n.º 40
0
 def test_visibility(self):
     """
     Tests visibility translation and conversion
     """
     for vis, unit, translation in (
         ('', 'm', ''),
         ('0000', 'm', '0km (0sm)'),
         ('2000', 'm', '2km (1.2sm)'),
         ('0900', 'm', '0.9km (0.6sm)'),
         ('P6', 'sm', 'Greater than 6sm ( >10km )'),
         ('M1/4', 'sm', 'Less than .25sm ( <0.4km )'),
         ('3/4', 'sm', '0.75sm (1.2km)'),
         ('3/2', 'sm', '1.5sm (2.4km)'),
         ('3', 'sm', '3sm (4.8km)'),
     ):
         self.assertEqual(translate.visibility(core.make_number(vis), unit),
                          translation)
Exemplo n.º 41
0
 def test_metar(self):
     """
     Tests end-to-end METAR translation
     """
     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')
         ]
     }
     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)
Exemplo n.º 42
0
def _icing(item: str) -> Icing:
    """
    Convert reported icing to an Icing object
    """
    items = item.split()
    ret = {
        'severity': items.pop(0),
        'type': None,
        'floor': None,
        'ceiling': None
    }
    for item in items:
        if '-' in item:
            for key, val in zip(('floor', 'ceiling'), item.split('-')):
                ret[key] = core.make_number(val)
        else:
            ret['type'] = item
    return Icing(**ret)
Exemplo n.º 43
0
 def test_prob_line(self):
     """
     Even though PROB__ is not in TAF_NEWLINE, it should still separate,
     add a new line, and include the prob value in line.probability
     """
     report = ("TAF AMD CYBC 271356Z 2714/2802 23015G25KT P6SM BKN090 "
               "TEMPO 2714/2718 P6SM -SHRA BKN060 OVC090 "
               "FM271800 22015G25KT P6SM OVC040 "
               "TEMPO 2718/2724 6SM -SHRA "
               "PROB30 2718/2724 VRB25G35KT 1SM +TSRA BR BKN020 OVC040CB "
               "FM280000 23008KT P6SM BKN040 RMK FCST BASED ON AUTO OBS. NXT FCST BY 272000Z")
     taf = Taf('CYBC')
     taf.update(report)
     lines = taf.data.forecast
     self.assertEqual(len(lines), 6)
     self.assertEqual(lines[3].probability, None)
     self.assertEqual(lines[4].probability, core.make_number('30'))
     self.assertTrue(lines[4].raw.startswith('PROB30'))
Exemplo n.º 44
0
 def test_prob_line(self):
     """
     Even though PROB__ is not in TAF_NEWLINE, it should still separate,
     add a new line, and include the prob value in line.probability
     """
     report = ("TAF AMD CYBC 271356Z 2714/2802 23015G25KT P6SM BKN090 "
               "TEMPO 2714/2718 P6SM -SHRA BKN060 OVC090 "
               "FM271800 22015G25KT P6SM OVC040 "
               "TEMPO 2718/2724 6SM -SHRA "
               "PROB30 2718/2724 VRB25G35KT 1SM +TSRA BR BKN020 OVC040CB "
               "FM280000 23008KT P6SM BKN040 RMK FCST BASED ON AUTO OBS. NXT FCST BY 272000Z")
     taf = Taf('CYBC')
     taf.update(report)
     lines = taf.data.forecast
     self.assertEqual(len(lines), 6)
     self.assertEqual(lines[3].probability, None)
     self.assertEqual(lines[4].probability, core.make_number('30'))
     self.assertTrue(lines[4].raw.startswith('PROB30'))
Exemplo n.º 45
0
def min_max_temp(temp: str, unit: str = 'C') -> str:
    """
    Format the Min and Max temp elemets into a readable string

    Ex: Maximum temperature of 23°C (73°F) at 18-15:00Z
    """
    if not temp or len(temp) < 7:
        return ''
    if temp[:2] == 'TX':
        temp_type = 'Maximum'
    elif temp[:2] == 'TN':
        temp_type = 'Minimum'
    else:
        return ''
    temp = temp[2:].replace('M', '-').replace('Z', '').split('/')
    if len(temp[1]) > 2:
        temp[1] = temp[1][:2] + '-' + temp[1][2:]
    temp_value = temperature(core.make_number(temp[0]), unit)
    return f'{temp_type} temperature of {temp_value} at {temp[1]}:00Z'
Exemplo n.º 46
0
 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)
Exemplo n.º 47
0
def parse_in_line(txt: str, units: Units) -> {str: str}:
    """
    Parser for the International TAF forcast varient
    """
    retwx = {}
    wxdata = txt.split(' ')
    wxdata, _, retwx['wind_shear'] = core.sanitize_report_list(wxdata)
    wxdata, retwx['type'], retwx['start_time'], retwx['end_time'] = core.get_type_and_times(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['turbulance'] \
        = core.get_taf_alt_ice_turb(wxdata)
    return retwx
Exemplo n.º 48
0
def parse_in_line(line: str, units: Units) -> {str: str}:
    """
    Parser for the International TAF forcast varient
    """
    retwx = {}
    wxdata = line.split()
    wxdata, _, retwx['wind_shear'] = core.sanitize_report_list(wxdata)
    wxdata, retwx['type'], retwx['start_time'], retwx['end_time'] = core.get_type_and_times(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['turbulance'] \
        = core.get_taf_alt_ice_turb(wxdata)
    return retwx
Exemplo n.º 49
0
 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)
Exemplo n.º 50
0
    def test_get_flight_rules(self):
        """
        Tests that the proper flight rule is calculated for a set visibility and ceiling

        Note: Only 'Broken', 'Overcast', and 'Vertical Visibility' are considdered ceilings
        """
        for vis, ceiling, rule in (
            (None, None, 'IFR'),
            ('10', None, 'VFR'),
            ('P6SM', ['OCV',50], 'VFR'),
            ('6', ['OVC',20], 'MVFR'),
            ('6', ['OVC',7], 'IFR'),
            ('2', ['OVC',20], 'IFR'),
            ('6', ['OVC',4], 'LIFR'),
            ('1/2', ['OVC',30], 'LIFR'),
            ('M1/4', ['OVC',30], 'LIFR'),
        ):
            vis = core.make_number(vis)
            if ceiling:
                ceiling = structs.Cloud(None, *ceiling)
            self.assertEqual(static.FLIGHT_RULES[core.get_flight_rules(vis, ceiling)], rule)
Exemplo n.º 51
0
    def test_get_flight_rules(self):
        """
        Tests that the proper flight rule is calculated for a set visibility and ceiling

        Note: Only 'Broken', 'Overcast', and 'Vertical Visibility' are considdered ceilings
        """
        for vis, ceiling, rule in (
            (None, None, 'IFR'),
            ('10', None, 'VFR'),
            ('P6SM', ['OCV',50], 'VFR'),
            ('6', ['OVC',20], 'MVFR'),
            ('6', ['OVC',7], 'IFR'),
            ('2', ['OVC',20], 'IFR'),
            ('6', ['OVC',4], 'LIFR'),
            ('1/2', ['OVC',30], 'LIFR'),
            ('M1/4', ['OVC',30], 'LIFR'),
        ):
            vis = core.make_number(vis)
            if ceiling:
                ceiling = structs.Cloud(None, *ceiling)
            self.assertEqual(static.FLIGHT_RULES[core.get_flight_rules(vis, ceiling)], rule)
Exemplo n.º 52
0
 def test_taf(self):
     """
     Tests converting a TafData report into a single spoken string
     """
     units = structs.Units(**static.NA_UNITS)
     empty_line = {
         k: None
         for k in structs.TafLineData.__dataclass_fields__.keys()
     }
     forecast = [
         structs.TafLineData(**{
             **empty_line,
             **line
         }) for line in (
             {
                 'type': 'FROM',
                 'start_time': core.make_timestamp('0410Z'),
                 'end_time': core.make_timestamp('0414Z'),
                 'visibility': core.make_number('3'),
                 'wind_direction': core.make_number('360'),
                 'wind_gust': core.make_number('20'),
                 'wind_speed': core.make_number('12'),
             },
             {
                 'type': 'PROB',
                 'probability': core.make_number('45'),
                 'start_time': core.make_timestamp('0412Z'),
                 'end_time': core.make_timestamp('0414Z'),
                 'visibility': core.make_number('M1/4'),
             },
         )
     ]
     taf = structs.TafData(raw=None,
                           remarks=None,
                           station=None,
                           time=None,
                           forecast=forecast,
                           start_time=core.make_timestamp('0410Z'),
                           end_time=core.make_timestamp('0414Z'))
     ret = speech.taf(taf, units)
     spoken = (
         f"Starting on {taf.start_time.dt.strftime('%B')} 4th - From 10 to 14 zulu, "
         "Winds three six zero at 12kt gusting to 20kt. Visibility three miles. "
         r"From 12 to 14 zulu, there's a 45% chance for Visibility "
         "less than one quarter of a mile")
     self.assertIsInstance(ret, str)
     self.assertEqual(ret, spoken)
Exemplo n.º 53
0
 def test_taf(self):
     """
     Tests converting a TafData report into a single spoken string
     """
     units = structs.Units(**static.NA_UNITS)
     empty_line = {k: None for k in structs.TafLineData.__dataclass_fields__.keys()}
     forecast = [structs.TafLineData(**{**empty_line, **line}) for line in (
         {
             'type': 'FROM',
             'start_time': core.make_timestamp('0410Z'),
             'end_time': core.make_timestamp('0414Z'),
             'visibility': core.make_number('3'),
             'wind_direction': core.make_number('360'),
             'wind_gust': core.make_number('20'),
             'wind_speed': core.make_number('12'),
         },
         {
             'type': 'PROB',
             'probability': core.make_number('45'),
             'start_time': core.make_timestamp('0412Z'),
             'end_time': core.make_timestamp('0414Z'),
             'visibility': core.make_number('M1/4'),
         },
     )]
     taf = structs.TafData(
         raw=None, remarks=None, station=None, time=None,
         forecast=forecast,
         start_time=core.make_timestamp('0410Z'),
         end_time=core.make_timestamp('0414Z')
     )
     ret = speech.taf(taf, units)
     spoken = (f"Starting on {taf.start_time.dt.strftime('%B')} 4th - From 10 to 14 zulu, "
               "Winds three six zero at 12kt gusting to 20kt. Visibility three miles. "
               r"From 12 to 14 zulu, there's a 45% chance for Visibility "
               "less than one quarter of a mile")
     self.assertIsInstance(ret, str)
     self.assertEqual(ret, spoken)
Exemplo n.º 54
0
def _number(item: str) -> Number:
    """
    Convert an element to a Number
    """
    return core.make_number(item)
Exemplo n.º 55
0
def _number(item: str) -> Number:
    """
    Convert an element to a Number
    """
    return core.make_number(item)