Exemple #1
0
 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())
Exemple #2
0
 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())
Exemple #3
0
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)
Exemple #4
0
    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
Exemple #5
0
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
Exemple #6
0
 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)
Exemple #7
0
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}