async def async_fetch(self, station: str = None, lat: float = None, lon: float = None) -> str: """ Asynchronously fetch a report string from the service """ if station: valid_station(station) elif lat is None or lon is None: raise ValueError("No valid fetch parameters") url, params = self._make_url(station, lat, lon) try: async with aiohttp.ClientSession(timeout=_atimeout) as sess: async with getattr(sess, self.method.lower())(url, params=params) as resp: if resp.status != 200: raise SourceError( f"{self.__class__.__name__} server returned {resp.status}" ) text = await resp.text() except aiohttp.ClientConnectionError: raise ConnectionError( f"Unable to connect to {self.__class__.__name__} server") report = self._extract(text, station) # This split join replaces all *whitespace elements with a single space if isinstance(report, list): return dedupe(" ".join(r.split()) for r in report) return " ".join(report.split())
def fetch(self, station: str = None, lat: float = None, lon: float = None) -> str: """ Fetches a report string from the service """ if station: valid_station(station) elif lat is None or lon is None: raise ValueError("No valid fetch parameters") try: url, params = self._make_url(station, lat, lon) url += "?" + urlencode(params) # Non-null data signals a POST request data = {} if self.method == "POST" else None resp = request.urlopen(url, data=data, timeout=10) if resp.status != 200: raise SourceError( f"{self.__class__.__name__} server returned {resp.status}") except URLError: raise ConnectionError( f"Unable to connect to {self.__class__.__name__} server") report = self._extract(resp.read().decode("utf-8"), station) # This split join replaces all *whitespace elements with a single space if isinstance(report, list): return dedupe(" ".join(r.split()) for r in report) return " ".join(report.split())
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 __init__(self, station: str): # Raises a BadStation error if needed valid_station(station) #: Service object used to fetch the report string self.service = service.get_service(station)( self.__class__.__name__.lower()) #: 4-character ICAO station ident code the report was initialized with self.station = station
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, "") if time: 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 test_valid_station(self): """ While not designed to catch all non-existant station idents, valid_station should catch non-ICAO strings and filter based on known prefixes """ # Good stations for station in ('KJFK', 'K123', 'EIGL', 'PHNL', 'MNAH'): _core.valid_station(station) # Bad stations for station in ('12K', 'MAYT'): with self.assertRaises(exceptions.BadStation): _core.valid_station(station)
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 except BadStation: continue # Determine report type if "UA" in items: rtype = "UA" elif "UUA" in items: rtype = "UUA" return {"station": station, "type": rtype}