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"] = _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, 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_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
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 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
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
def parse_na(report: str) -> (MetarData, Units): """ Parser for the North American METAR variant """ units = Units(**NA_UNITS) clean = core.sanitize_report_string(report) wxresp = {'raw': report, 'sanitized': clean} wxdata, wxresp['remarks'] = core.get_remarks(clean) wxdata = core.dedupe(wxdata) wxdata, wxresp['runway_visibility'], _ = core.sanitize_report_list(wxdata) wxdata, wxresp['station'], wxresp['time'] = core.get_station_and_time( 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, 'NA') 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 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
from avwx.current.base import Reports from avwx.parsing import core, sanitization from avwx.static.core import NA_UNITS from avwx.structs import ( Aircraft, Cloud, Icing, Location, Number, PirepData, Timestamp, Turbulence, Units, ) _UNITS = Units(**NA_UNITS) def _root(item: str) -> dict: """ Parses report root data including station and report type """ # pylint: disable=redefined-argument-from-local report_type = None station = None for item in item.split(): if item in ("UA", "UUA"): report_type = item elif not station: station = item return {"station": station, "type": report_type}
from avwx import _core, static, structs from avwx.exceptions import BadStation from avwx.structs import ( Aircraft, Cloud, Icing, Location, Number, PirepData, Timestamp, Turbulance, Units, ) _units = Units(**static.NA_UNITS) def _root(item: str) -> dict: """ Parses report root data including station and report type """ items = item.split() rtype = None station = None # Find valid station for item in items: try: _core.valid_station(item) station = item break
class Reports(AVWXBase): """ Base class containing multiple reports """ raw: [str] = None data: [ReportData] = None units: Units = Units(**NA_UNITS) def __init__(self, icao: str = None, lat: float = None, lon: float = None): if icao: super().__init__(icao) lat = self.station.latitude lon = self.station.longitude elif lat is None or lon is None: raise ValueError("No station or valid coordinates given") self.lat = lat self.lon = lon self.service = NOAA_ADDS("aircraftreport") def __repr__(self) -> str: return f"<avwx.{self.__class__.__name__} lat={self.lat} lon={self.lon}>" @staticmethod def _report_filter(reports: [str]) -> [str]: """ Applies any report filtering before updating raw_reports """ return reports def update( self, reports: [str] = None, issued: date = None, timeout: int = 10, disable_post: bool = False, ) -> bool: """ Updates raw and data by fetch recent aircraft reports Can accept a list report strings to parse instead Returns True if new reports are available, else False """ if not reports: reports = self.service.fetch(lat=self.lat, lon=self.lon, timeout=timeout) if not reports: return False issued = None if isinstance(reports, str): reports = [reports] if reports == self.raw: return False self.raw = self._report_filter(reports) self.issued = issued if not disable_post: self._post_update() self._set_meta() return True async def async_update(self, timeout: int = 10, disable_post: bool = False) -> bool: """ Async version of update """ reports = await self.service.async_fetch(lat=self.lat, lon=self.lon, timeout=timeout) if not reports or reports == self.raw: return False self.raw = reports self.issued = None if not disable_post: self._post_update() self._set_meta() return True
class Reports(AVWXBase): """ Base class containing multiple reports """ raw: Optional[List[str]] = None data: Optional[List[ReportData]] = None units: Units = Units(**NA_UNITS) def __init__(self, icao: str = None, lat: float = None, lon: float = None): if icao: super().__init__(icao) lat = self.station.latitude lon = self.station.longitude elif lat is None or lon is None: raise ValueError("No station or valid coordinates given") self.lat = lat self.lon = lon self.service = NOAA_ADDS("aircraftreport") def __repr__(self) -> str: return f"<avwx.{self.__class__.__name__} lat={self.lat} lon={self.lon}>" @staticmethod def _report_filter(reports: List[str]) -> List[str]: """Applies any report filtering before updating raw_reports""" return reports def _update( self, reports: List[str], issued: Optional[date], disable_post: bool ) -> bool: if not reports: return False reports = self._report_filter(reports) return super()._update(reports, issued, disable_post) def parse(self, reports: Union[str, List[str]], issued: Optional[date] = None): """Updates report data by parsing a given report Can accept a report issue date if not a recent report string """ if isinstance(reports, str): reports = [reports] return self._update(reports, issued, False) def update( self, timeout: int = 10, disable_post: bool = False, ) -> bool: """Updates report data by fetching and parsing the report Returns True if new reports are available, else False """ reports = self.service.fetch(lat=self.lat, lon=self.lon, timeout=timeout) return self._update(reports, None, disable_post) async def async_update(self, timeout: int = 10, disable_post: bool = False) -> bool: """Async updates report data by fetching and parsing the report""" reports = await self.service.async_fetch( lat=self.lat, lon=self.lon, timeout=timeout ) return self._update(reports, None, disable_post)
def _post_update(self): self.data = parse_mex(self.raw) self.units = Units(**static.UNITS)
from avwx.current.base import Reports from avwx.parsing import core from avwx.static.core import NA_UNITS from avwx.structs import ( Aircraft, Cloud, Icing, Location, Number, PirepData, Timestamp, Turbulence, Units, ) _units = Units(**NA_UNITS) def _root(item: str) -> dict: """ Parses report root data including station and report type """ report_type = None station = None for item in item.split(): if item in ("UA", "UUA"): report_type = item elif not station: station = item return {"station": station, "type": report_type}