def test_uses_na_format(self): """ METAR and TAF reports come in two flavors: North American and International uses_na_format should determine the format based on the station ident using prefixes """ # NA stations for station in ('KJFK', 'PHNL', 'TNCM', 'MYNN'): self.assertTrue(core.uses_na_format(station)) # IN stations for station in ('EGLL', 'MNAH', 'MUHA'): self.assertFalse(core.uses_na_format(station)) # Bad stations for station in ('12K', 'MAYT'): with self.assertRaises(exceptions.BadStation): core.uses_na_format(station)
def parse(station: str, report: str) -> (MetarData, Units): """ Returns MetarData and Units dataclasses with parsed data and their associated units """ core.valid_station(station) if not report: return None, None return parse_na(report) if core.uses_na_format( station[:2]) else parse_in(report)
def parse(station: str, txt: str) -> {str: object}: """Returns a dictionary of parsed METAR data Keys: Station, Time, Wind-Direction, Wind-Speed, Wind-Gust, Wind-Variable-Dir, Visibility, Runway-Vis-List, Altimeter, Temperature, Dewpoint, Cloud-List, Other-List, Remarks, Units Units is dict of identified units of measurement for each field """ core.valid_station(station) return parse_na(txt) if core.uses_na_format(station[:2]) else parse_in(txt)
def parse(station: str, report: str) -> TafData: """ Returns TafData and Units dataclasses with parsed data and their associated units """ if not report: return None, None core.valid_station(station) while len(report) > 3 and report[:4] in ('TAF ', 'AMD ', 'COR '): report = report[4:] _, station, time = core.get_station_and_time(report[:20].split()) retwx = { 'end_time': None, 'raw': report, 'remarks': None, 'start_time': None, 'station': station, 'time': core.make_timestamp(time) } report = report.replace(station, '') report = report.replace(time, '').strip() if core.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'] = core.get_taf_remarks(report) # Split and parse each line lines = core.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'] \ = core.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'] \ = core.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 = core.find_missing_taf_times(parsed_lines, start, end) parsed_lines = core.get_taf_flight_rules(parsed_lines) # Extract Oceania-specific data if retwx['station'][0] == 'A': parsed_lines[-1]['other'], retwx['alts'], retwx['temps'] \ = core.get_oceania_temp_and_alt(parsed_lines[-1]['other']) # Convert to dataclass retwx['forecast'] = [TafLineData(**line) for line in parsed_lines] return TafData(**retwx), units
def parse(station: str, txt: str) -> (MetarData, Units): """ Returns MetarData and Units dataclasses with parsed data and their associated units """ core.valid_station(station) return parse_na(txt) if core.uses_na_format(station[:2]) else parse_in(txt)
def parse(station: str, txt: str, delim: str = '<br/> ') -> { str: object }: """ Returns a dictionary of parsed TAF data 'delim' is the divider between forecast lines. Ex: aviationweather.gov uses '<br/> ' Keys: Station, Time, Forecast, Remarks, Min-Temp, Max-Temp, Units Oceania stations also have the following keys: Temp-List, Alt-List Forecast is list of report dicts in order of time with the following keys: Type, Start-Time, End-Time, Flight-Rules, Wind-Direction, Wind-Speed, Wind-Gust, Wind-Shear, Visibility, Altimeter, Cloud-List, Icing-List, Turb-List, Other-List, Probability, Raw-Line Units is dict of identified units of measurement for each field """ core.valid_station(station) retwx = {} while len(txt) > 3 and txt[:4] in ['TAF ', 'AMD ', 'COR ']: txt = txt[4:] _, retwx['Station'], retwx['Time'] = core.get_station_and_time( txt[:20].split(' ')) txt = txt.replace(retwx['Station'], '') txt = txt.replace(retwx['Time'], '') if core.uses_na_format(retwx['Station']): is_international = False units = copy(NA_UNITS) else: is_international = True units = copy(IN_UNITS) retwx['Remarks'] = '' parsed_lines = [] prob = '' lines = txt.strip(' ').split(delim) while lines: line = lines[0].strip(' ') line = core.sanitize_line(line) #Remove Remarks from line index = core.find_first_in_list(line, TAF_RMK) if index != -1: retwx['Remarks'] = line[index:] line = line[:index].strip(' ') #Separate new lines fixed by sanitizeLine index = core.find_first_in_list(line, TAF_NEWLINE) if index != -1: lines.insert(1, line[index + 1:]) line = line[:index] # 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: # Separate full prob forecast into its own line if ' PROB' in line: probindex = line.index(' PROB') lines.insert(1, line[probindex + 1:]) line = line[:probindex] raw_line = prob + ' ' + line if prob else line parsed_line, units = parse_in_line(line, units) if is_international \ else parse_na_line(line, units) parsed_line['Probability'] = prob[4:] parsed_line['Raw-Line'] = raw_line prob = '' parsed_lines.append(parsed_line) lines.pop(0) if parsed_lines: parsed_lines[len(parsed_lines) - 1]['Other-List'], retwx['Max-Temp'], retwx['Min-Temp'] \ = core.get_temp_min_and_max(parsed_lines[len(parsed_lines) - 1]['Other-List']) if not (retwx['Max-Temp'] or retwx['Min-Temp']): parsed_lines[0]['Other-List'], retwx['Max-Temp'], retwx['Min-Temp'] \ = core.get_temp_min_and_max(parsed_lines[0]['Other-List']) parsed_lines = core.find_missing_taf_times(parsed_lines) parsed_lines = core.get_taf_flight_rules(parsed_lines) else: retwx['Min-Temp'] = ['', ''] retwx['Max-Temp'] = ['', ''] if retwx['Station'][0] == 'A': parsed_lines[len(parsed_lines) - 1]['Other-List'], retwx['Alt-List'], retwx['Temp-List'] \ = core.get_oceania_temp_and_alt(parsed_lines[len(parsed_lines) - 1]['Other-List']) retwx['Forecast'] = parsed_lines retwx['Units'] = units return retwx