avwx.forecast.gfs

GFS MOS MAV

The MAV report is a short-range forecast (6-72 hours) based on the Global Forecast System model output and is only valid for ICAO stations in the United States, Puerto Rico, and US Virgin Islands. Reports are published every six hours starting at 0000 UTC.

GFS MOS MEX

The MEX report is an extended-range forecast (24-192 hours) based on the Global Forecast System model output and is only valid for ICAO stations in the United States, Puerto Rico, and US Virgin Islands. Reports are published at 0000 and 1200 UTC.

  1"""
  2# GFS MOS MAV
  3
  4The [MAV report](https://www.nws.noaa.gov/mdl/synop/mavcard.php) is a
  5short-range forecast (6-72 hours) based on the [Global Forecast
  6System](https://www.ncdc.noaa.gov/data-access/model-data/model-datasets/global-forcast-system-gfs)
  7model output and is only valid for ICAO stations in the United States, Puerto
  8Rico, and US Virgin Islands. Reports are published every six hours starting at
  90000 UTC.
 10
 11# GFS MOS MEX
 12
 13The [MEX report](https://www.nws.noaa.gov/mdl/synop/mexcard.php) is an
 14extended-range forecast (24-192 hours) based on the [Global Forecast
 15System](https://www.ncdc.noaa.gov/data-access/model-data/model-datasets/global-forcast-system-gfs)
 16model output and is only valid for ICAO stations in the United States, Puerto
 17Rico, and US Virgin Islands. Reports are published at 0000 and 1200 UTC.
 18"""
 19
 20# stdlib
 21from typing import List, Optional, Tuple
 22
 23# module
 24import avwx.static.gfs as static
 25from avwx.parsing import core
 26from avwx.service import NOAA_GFS
 27from avwx.structs import (
 28    MavData,
 29    MavPeriod,
 30    MexData,
 31    MexPeriod,
 32    Number,
 33    Units,
 34)
 35from .base import (
 36    Forecast,
 37    _code,
 38    _direction,
 39    _find_time_periods,
 40    _init_parse,
 41    _numbers,
 42    _parse_lines,
 43    _split_line,
 44    _trim_lines,
 45)
 46
 47
 48class Mav(Forecast):
 49    '''
 50    The Mav class offers an object-oriented approach to managing MOS MAV data
 51    for a single station.
 52
 53    Below is typical usage for fetching and pulling MAV data for KJFK.
 54
 55    ```python
 56    >>> from avwx import Mav
 57    >>> kjfk = Mav("KJFK")
 58    >>> kjfk.station.name
 59    'John F Kennedy International Airport'
 60    >>> kjfk.update()
 61    True
 62    >>> kjfk.last_updated
 63    datetime.datetime(2020, 4, 20, 1, 7, 7, 393270, tzinfo=datetime.timezone.utc)
 64    >>> print(kjfk.raw)
 65    """
 66    KJFK   GFS MOS GUIDANCE    4/19/2020  1800 UTC
 67    DT /APR  20                  /APR  21                /APR  22
 68    HR   00 03 06 09 12 15 18 21 00 03 06 09 12 15 18 21 00 03 06 12 18
 69    N/X              46          58          44          58       37
 70    TMP  53 52 50 48 48 50 54 56 51 49 47 46 49 53 55 52 47 45 43 41 54
 71    DPT  43 41 37 35 33 30 28 27 28 30 32 34 37 39 37 32 26 23 22 18 14
 72    CLD  OV OV OV OV OV OV OV SC FW CL CL FW BK OV OV OV BK FW CL FW SC
 73    WDR  20 22 26 35 02 03 02 02 34 19 20 18 18 18 18 23 29 30 29 29 28
 74    WSP  20 13 07 08 11 14 14 11 05 03 04 06 11 19 25 21 22 25 20 19 22
 75    P06         0    12     9     1     0     1    29    68     8  2  0
 76    P12              12           9           2          69       15
 77    Q06         0     0     0     0     0     0     0     2     0  0  0
 78    Q12               0           0           0           2        0
 79    T06      0/ 4  1/ 0  1/ 0  0/ 0  0/ 0  0/ 0  5/ 3 13/13  0/ 0  0/ 8
 80    T12                  1/ 2        0/ 0        9/ 6       14/13  1/ 8
 81    POZ   0  1  1  0  0  0  0  0  0  0  0  0  0  0  0  1  0  0  0  0  0
 82    POS   0  0  0  0  0  2  0  6  6  9  9  0 16  8  0  4  4 47 60 67 42
 83    TYP   R  R  R  R  R  R  R  R  R  R  R  R  R  R  R  R  R  R  S  S  R
 84    SNW                                       0                    0
 85    CIG   7  7  7  7  6  6  6  8  8  8  8  8  8  6  6  6  7  8  8  8  8
 86    VIS   7  7  7  7  7  7  7  7  7  7  7  7  7  7  7  6  7  7  7  7  7
 87    OBV   N  N  N  N  N  N  N  N  N  N  N  N  N  N  N  N  N  N  N  N  N
 88    """
 89    >>> len(kjfk.data.forecast)
 90    21
 91    >>> kjfk.data.forecast[0].ceiling
 92    Code(repr='7', value='6600 - 12,000 feet')
 93    ```
 94
 95    The `parse` and `from_report` methods can parse a report string if you want
 96    to override the normal fetching process.
 97    '''
 98
 99    report_type = "mav"
100    _service_class = NOAA_GFS  # type: ignore
101
102    async def _post_update(self) -> None:
103        if self.raw is None:
104            return
105        self.data = parse_mav(self.raw)
106        self.units = Units(**static.UNITS)
107
108    def _post_parse(self) -> None:
109        if self.raw is None:
110            return
111        self.data = parse_mav(self.raw)
112        self.units = Units(**static.UNITS)
113
114
115class Mex(Forecast):
116    '''
117    The Mex class offers an object-oriented approach to managing MOS MEX data
118    for a single station.
119
120    Below is typical usage for fetching and pulling MAV data for KJFK.
121
122    ```python
123    >>> from avwx import Mex
124    >>> kjfk = Mex("KJFK")
125    >>> kjfk.station.name
126    'John F Kennedy International Airport'
127    >>> kjfk.update()
128    True
129    >>> kjfk.last_updated
130    datetime.datetime(2020, 4, 20, 12, 7, 7, 393270, tzinfo=datetime.timezone.utc)
131    >>> print(kjfk.raw)
132    """
133    KJFK   GFSX MOS GUIDANCE   4/20/2020  0000 UTC
134    FHR  24| 36  48| 60  72| 84  96|108 120|132 144|156 168|180 192
135    MON  20| TUE 21| WED 22| THU 23| FRI 24| SAT 25| SUN 26| MON 27 CLIMO
136    X/N  57| 45  59| 37  56| 40  52| 49  58| 46  59| 48  59| 44  58 45 63
137    TMP  50| 49  48| 41  49| 45  48| 52  51| 50  53| 51  52| 48  51
138    DPT  31| 39  26| 17  17| 24  40| 46  43| 40  44| 43  40| 35  31
139    CLD  OV| OV  OV| CL  CL| OV  OV| OV  OV| PC  OV| OV  OV| OV  OV
140    WND  13| 14  26| 26  21| 16  13| 18  15| 16  12| 15  19| 19  11
141    P12   9|  1  73|  7   0|  9  43| 73  63| 27  51| 64  37| 35  32 24 23
142    P24    |     73|      7|     43|     77|     61|     73|     44    36
143    Q12   0|  0   2|  0   0|  0   1|  5   3|  0   2|  5    |
144    Q24    |      1|      0|      0|      5|      2|       |
145    T12   1|  0  12|  1   0|  4   4|  8  11|  3   3| 14   7|  5   9
146    T24    |  1    | 14    |  4    | 12    | 11    | 14    | 11
147    PZP   0|  0   1|  0   2|  4   1|  0   0|  0   0|  0   0|  0   0
148    PSN   0|  0   0| 37  25| 15   4|  0   0|  0   0|  2   0|  3   5
149    PRS   0|  2   1| 32  28| 19   4|  0   1|  1   1|  1   1|  8   9
150    TYP   R|  R   R| RS  RS|  R   R|  R   R|  R   R|  R   R|  R   R
151    SNW    |      0|      0|      0|      0|      0|       |
152    """
153    >>> len(kjfk.data.forecast)
154    15
155    >>> kjfk.data.forecast[2].precip_chance_24
156    Number(repr='73', value=73, spoken='seven three')
157    ```
158
159    The `parse` and `from_report` methods can parse a report string if you want
160    to override the normal fetching process.
161    '''
162
163    report_type = "mex"
164    _service_class = NOAA_GFS  # type: ignore
165
166    async def _post_update(self) -> None:
167        if self.raw is None:
168            return
169        self.data = parse_mex(self.raw)
170        self.units = Units(**static.UNITS)
171
172    def _post_parse(self) -> None:
173        if self.raw is None:
174            return
175        self.data = parse_mex(self.raw)
176        self.units = Units(**static.UNITS)
177
178
179_ThunderList = List[Optional[Tuple[Optional[Number], Optional[Number]]]]
180
181
182def _thunder(line: str, size: int = 3) -> _ThunderList:
183    """Parse thunder line into Number tuples"""
184    ret: _ThunderList = []
185    previous = None
186    for item in _split_line(line, size=size, prefix=5, strip=" /"):
187        if not item:
188            ret.append(None)
189        elif previous:
190            ret.append((previous, core.make_number(item)))
191            previous = None
192        else:
193            ret.append(None)
194            previous = core.make_number(item)
195    return ret
196
197
198# pylint: disable=invalid-name
199_precip_amount = _code(static.PRECIPITATION_AMOUNT)
200
201_HANDLERS = {
202    "X/N": ("temperature_minmax", _numbers),
203    "TMP": ("temperature", _numbers),
204    "DPT": ("dewpoint", _numbers),
205    "CLD": ("cloud", _code(static.CLOUD)),
206    "WDR": ("wind_direction", _direction),
207    "WSP": ("wind_speed", _numbers),
208    "P06": ("precip_chance_6", _numbers),
209    "P12": ("precip_chance_12", _numbers),
210    "P24": ("precip_chance_24", _numbers),
211    "Q06": ("precip_amount_6", _precip_amount),
212    "Q12": ("precip_amount_12", _precip_amount),
213    "Q24": ("precip_amount_24", _precip_amount),
214    "TYP": ("precip_type", _code(static.PRECIPITATION_TYPE)),
215}
216
217
218# Secondary dicts for conflicting handlers
219_MAV_HANDLERS = {
220    **_HANDLERS,
221    "T06": ("thunderstorm_6", "severe_storm_6", _thunder),
222    "T12": ("thunderstorm_12", "severe_storm_12", _thunder),
223    "POZ": ("freezing_precip", _numbers),
224    "POS": ("snow", _numbers),
225    "CIG": ("ceiling", _code(static.CEILING_HEIGHT)),
226    "VIS": ("visibility", _code(static.VISIBILITY)),
227    "OBV": ("vis_obstruction", _code(static.VISIBILITY_OBSTRUCTION)),
228}
229
230_MEX_HANDLERS = {
231    **_HANDLERS,
232    "T12": ("thunderstorm_12", _numbers),
233    "T24": ("thunderstorm_24", _numbers),
234    "PZP": ("freezing_precip", _numbers),
235    "PRS": ("rain_snow_mix", _numbers),
236    "PSN": ("snow", _numbers),
237    "SNW": ("snow_amount_24", _code(static.SNOWFALL_AMOUNT)),
238}
239
240
241def parse_mav(report: str) -> Optional[MavData]:
242    """Parser for GFS MAV reports"""
243    if not report:
244        return None
245    data, lines = _init_parse(report)
246    lines = _trim_lines(lines, 2)
247    period_strings = _split_line(lines[2])
248    timestamp = data.time.dt if data.time else None
249    periods = _find_time_periods(period_strings, timestamp)
250    _parse_lines(periods, lines[3:], _MAV_HANDLERS)
251    return MavData(
252        raw=data.raw,
253        sanitized=data.sanitized,
254        station=data.station,
255        time=data.time,
256        remarks=data.remarks,
257        forecast=[MavPeriod(**p) for p in periods],
258    )
259
260
261def parse_mex(report: str) -> Optional[MexData]:
262    """Parser for GFS MEX reports"""
263    if not report:
264        return None
265    data, lines = _init_parse(report)
266    lines = _trim_lines(lines, 1)
267    period_strings = _split_line(lines[1], size=4, prefix=4)
268    timestamp = data.time.dt if data.time else None
269    periods = _find_time_periods(period_strings, timestamp)
270    _parse_lines(periods, lines[3:], _MEX_HANDLERS, size=4)
271    return MexData(
272        raw=data.raw,
273        sanitized=data.sanitized,
274        station=data.station,
275        time=data.time,
276        remarks=data.remarks,
277        forecast=[MexPeriod(**p) for p in periods],
278    )
class Mav(avwx.forecast.base.Forecast):
 49class Mav(Forecast):
 50    '''
 51    The Mav class offers an object-oriented approach to managing MOS MAV data
 52    for a single station.
 53
 54    Below is typical usage for fetching and pulling MAV data for KJFK.
 55
 56    ```python
 57    >>> from avwx import Mav
 58    >>> kjfk = Mav("KJFK")
 59    >>> kjfk.station.name
 60    'John F Kennedy International Airport'
 61    >>> kjfk.update()
 62    True
 63    >>> kjfk.last_updated
 64    datetime.datetime(2020, 4, 20, 1, 7, 7, 393270, tzinfo=datetime.timezone.utc)
 65    >>> print(kjfk.raw)
 66    """
 67    KJFK   GFS MOS GUIDANCE    4/19/2020  1800 UTC
 68    DT /APR  20                  /APR  21                /APR  22
 69    HR   00 03 06 09 12 15 18 21 00 03 06 09 12 15 18 21 00 03 06 12 18
 70    N/X              46          58          44          58       37
 71    TMP  53 52 50 48 48 50 54 56 51 49 47 46 49 53 55 52 47 45 43 41 54
 72    DPT  43 41 37 35 33 30 28 27 28 30 32 34 37 39 37 32 26 23 22 18 14
 73    CLD  OV OV OV OV OV OV OV SC FW CL CL FW BK OV OV OV BK FW CL FW SC
 74    WDR  20 22 26 35 02 03 02 02 34 19 20 18 18 18 18 23 29 30 29 29 28
 75    WSP  20 13 07 08 11 14 14 11 05 03 04 06 11 19 25 21 22 25 20 19 22
 76    P06         0    12     9     1     0     1    29    68     8  2  0
 77    P12              12           9           2          69       15
 78    Q06         0     0     0     0     0     0     0     2     0  0  0
 79    Q12               0           0           0           2        0
 80    T06      0/ 4  1/ 0  1/ 0  0/ 0  0/ 0  0/ 0  5/ 3 13/13  0/ 0  0/ 8
 81    T12                  1/ 2        0/ 0        9/ 6       14/13  1/ 8
 82    POZ   0  1  1  0  0  0  0  0  0  0  0  0  0  0  0  1  0  0  0  0  0
 83    POS   0  0  0  0  0  2  0  6  6  9  9  0 16  8  0  4  4 47 60 67 42
 84    TYP   R  R  R  R  R  R  R  R  R  R  R  R  R  R  R  R  R  R  S  S  R
 85    SNW                                       0                    0
 86    CIG   7  7  7  7  6  6  6  8  8  8  8  8  8  6  6  6  7  8  8  8  8
 87    VIS   7  7  7  7  7  7  7  7  7  7  7  7  7  7  7  6  7  7  7  7  7
 88    OBV   N  N  N  N  N  N  N  N  N  N  N  N  N  N  N  N  N  N  N  N  N
 89    """
 90    >>> len(kjfk.data.forecast)
 91    21
 92    >>> kjfk.data.forecast[0].ceiling
 93    Code(repr='7', value='6600 - 12,000 feet')
 94    ```
 95
 96    The `parse` and `from_report` methods can parse a report string if you want
 97    to override the normal fetching process.
 98    '''
 99
100    report_type = "mav"
101    _service_class = NOAA_GFS  # type: ignore
102
103    async def _post_update(self) -> None:
104        if self.raw is None:
105            return
106        self.data = parse_mav(self.raw)
107        self.units = Units(**static.UNITS)
108
109    def _post_parse(self) -> None:
110        if self.raw is None:
111            return
112        self.data = parse_mav(self.raw)
113        self.units = Units(**static.UNITS)

The Mav class offers an object-oriented approach to managing MOS MAV data for a single station.

Below is typical usage for fetching and pulling MAV data for KJFK.

>>> from avwx import Mav
>>> kjfk = Mav("KJFK")
>>> kjfk.station.name
'John F Kennedy International Airport'
>>> kjfk.update()
True
>>> kjfk.last_updated
datetime.datetime(2020, 4, 20, 1, 7, 7, 393270, tzinfo=datetime.timezone.utc)
>>> print(kjfk.raw)
"""
KJFK   GFS MOS GUIDANCE    4/19/2020  1800 UTC
DT /APR  20                  /APR  21                /APR  22
HR   00 03 06 09 12 15 18 21 00 03 06 09 12 15 18 21 00 03 06 12 18
N/X              46          58          44          58       37
TMP  53 52 50 48 48 50 54 56 51 49 47 46 49 53 55 52 47 45 43 41 54
DPT  43 41 37 35 33 30 28 27 28 30 32 34 37 39 37 32 26 23 22 18 14
CLD  OV OV OV OV OV OV OV SC FW CL CL FW BK OV OV OV BK FW CL FW SC
WDR  20 22 26 35 02 03 02 02 34 19 20 18 18 18 18 23 29 30 29 29 28
WSP  20 13 07 08 11 14 14 11 05 03 04 06 11 19 25 21 22 25 20 19 22
P06         0    12     9     1     0     1    29    68     8  2  0
P12              12           9           2          69       15
Q06         0     0     0     0     0     0     0     2     0  0  0
Q12               0           0           0           2        0
T06      0/ 4  1/ 0  1/ 0  0/ 0  0/ 0  0/ 0  5/ 3 13/13  0/ 0  0/ 8
T12                  1/ 2        0/ 0        9/ 6       14/13  1/ 8
POZ   0  1  1  0  0  0  0  0  0  0  0  0  0  0  0  1  0  0  0  0  0
POS   0  0  0  0  0  2  0  6  6  9  9  0 16  8  0  4  4 47 60 67 42
TYP   R  R  R  R  R  R  R  R  R  R  R  R  R  R  R  R  R  R  S  S  R
SNW                                       0                    0
CIG   7  7  7  7  6  6  6  8  8  8  8  8  8  6  6  6  7  8  8  8  8
VIS   7  7  7  7  7  7  7  7  7  7  7  7  7  7  7  6  7  7  7  7  7
OBV   N  N  N  N  N  N  N  N  N  N  N  N  N  N  N  N  N  N  N  N  N
"""
>>> len(kjfk.data.forecast)
21
>>> kjfk.data.forecast[0].ceiling
Code(repr='7', value='6600 - 12,000 feet')

The parse and from_report methods can parse a report string if you want to override the normal fetching process.

report_type = 'mav'
class Mex(avwx.forecast.base.Forecast):
116class Mex(Forecast):
117    '''
118    The Mex class offers an object-oriented approach to managing MOS MEX data
119    for a single station.
120
121    Below is typical usage for fetching and pulling MAV data for KJFK.
122
123    ```python
124    >>> from avwx import Mex
125    >>> kjfk = Mex("KJFK")
126    >>> kjfk.station.name
127    'John F Kennedy International Airport'
128    >>> kjfk.update()
129    True
130    >>> kjfk.last_updated
131    datetime.datetime(2020, 4, 20, 12, 7, 7, 393270, tzinfo=datetime.timezone.utc)
132    >>> print(kjfk.raw)
133    """
134    KJFK   GFSX MOS GUIDANCE   4/20/2020  0000 UTC
135    FHR  24| 36  48| 60  72| 84  96|108 120|132 144|156 168|180 192
136    MON  20| TUE 21| WED 22| THU 23| FRI 24| SAT 25| SUN 26| MON 27 CLIMO
137    X/N  57| 45  59| 37  56| 40  52| 49  58| 46  59| 48  59| 44  58 45 63
138    TMP  50| 49  48| 41  49| 45  48| 52  51| 50  53| 51  52| 48  51
139    DPT  31| 39  26| 17  17| 24  40| 46  43| 40  44| 43  40| 35  31
140    CLD  OV| OV  OV| CL  CL| OV  OV| OV  OV| PC  OV| OV  OV| OV  OV
141    WND  13| 14  26| 26  21| 16  13| 18  15| 16  12| 15  19| 19  11
142    P12   9|  1  73|  7   0|  9  43| 73  63| 27  51| 64  37| 35  32 24 23
143    P24    |     73|      7|     43|     77|     61|     73|     44    36
144    Q12   0|  0   2|  0   0|  0   1|  5   3|  0   2|  5    |
145    Q24    |      1|      0|      0|      5|      2|       |
146    T12   1|  0  12|  1   0|  4   4|  8  11|  3   3| 14   7|  5   9
147    T24    |  1    | 14    |  4    | 12    | 11    | 14    | 11
148    PZP   0|  0   1|  0   2|  4   1|  0   0|  0   0|  0   0|  0   0
149    PSN   0|  0   0| 37  25| 15   4|  0   0|  0   0|  2   0|  3   5
150    PRS   0|  2   1| 32  28| 19   4|  0   1|  1   1|  1   1|  8   9
151    TYP   R|  R   R| RS  RS|  R   R|  R   R|  R   R|  R   R|  R   R
152    SNW    |      0|      0|      0|      0|      0|       |
153    """
154    >>> len(kjfk.data.forecast)
155    15
156    >>> kjfk.data.forecast[2].precip_chance_24
157    Number(repr='73', value=73, spoken='seven three')
158    ```
159
160    The `parse` and `from_report` methods can parse a report string if you want
161    to override the normal fetching process.
162    '''
163
164    report_type = "mex"
165    _service_class = NOAA_GFS  # type: ignore
166
167    async def _post_update(self) -> None:
168        if self.raw is None:
169            return
170        self.data = parse_mex(self.raw)
171        self.units = Units(**static.UNITS)
172
173    def _post_parse(self) -> None:
174        if self.raw is None:
175            return
176        self.data = parse_mex(self.raw)
177        self.units = Units(**static.UNITS)

The Mex class offers an object-oriented approach to managing MOS MEX data for a single station.

Below is typical usage for fetching and pulling MAV data for KJFK.

>>> from avwx import Mex
>>> kjfk = Mex("KJFK")
>>> kjfk.station.name
'John F Kennedy International Airport'
>>> kjfk.update()
True
>>> kjfk.last_updated
datetime.datetime(2020, 4, 20, 12, 7, 7, 393270, tzinfo=datetime.timezone.utc)
>>> print(kjfk.raw)
"""
KJFK   GFSX MOS GUIDANCE   4/20/2020  0000 UTC
FHR  24| 36  48| 60  72| 84  96|108 120|132 144|156 168|180 192
MON  20| TUE 21| WED 22| THU 23| FRI 24| SAT 25| SUN 26| MON 27 CLIMO
X/N  57| 45  59| 37  56| 40  52| 49  58| 46  59| 48  59| 44  58 45 63
TMP  50| 49  48| 41  49| 45  48| 52  51| 50  53| 51  52| 48  51
DPT  31| 39  26| 17  17| 24  40| 46  43| 40  44| 43  40| 35  31
CLD  OV| OV  OV| CL  CL| OV  OV| OV  OV| PC  OV| OV  OV| OV  OV
WND  13| 14  26| 26  21| 16  13| 18  15| 16  12| 15  19| 19  11
P12   9|  1  73|  7   0|  9  43| 73  63| 27  51| 64  37| 35  32 24 23
P24    |     73|      7|     43|     77|     61|     73|     44    36
Q12   0|  0   2|  0   0|  0   1|  5   3|  0   2|  5    |
Q24    |      1|      0|      0|      5|      2|       |
T12   1|  0  12|  1   0|  4   4|  8  11|  3   3| 14   7|  5   9
T24    |  1    | 14    |  4    | 12    | 11    | 14    | 11
PZP   0|  0   1|  0   2|  4   1|  0   0|  0   0|  0   0|  0   0
PSN   0|  0   0| 37  25| 15   4|  0   0|  0   0|  2   0|  3   5
PRS   0|  2   1| 32  28| 19   4|  0   1|  1   1|  1   1|  8   9
TYP   R|  R   R| RS  RS|  R   R|  R   R|  R   R|  R   R|  R   R
SNW    |      0|      0|      0|      0|      0|       |
"""
>>> len(kjfk.data.forecast)
15
>>> kjfk.data.forecast[2].precip_chance_24
Number(repr='73', value=73, spoken='seven three')

The parse and from_report methods can parse a report string if you want to override the normal fetching process.

report_type = 'mex'
def parse_mav(report: str) -> Optional[avwx.structs.MavData]:
242def parse_mav(report: str) -> Optional[MavData]:
243    """Parser for GFS MAV reports"""
244    if not report:
245        return None
246    data, lines = _init_parse(report)
247    lines = _trim_lines(lines, 2)
248    period_strings = _split_line(lines[2])
249    timestamp = data.time.dt if data.time else None
250    periods = _find_time_periods(period_strings, timestamp)
251    _parse_lines(periods, lines[3:], _MAV_HANDLERS)
252    return MavData(
253        raw=data.raw,
254        sanitized=data.sanitized,
255        station=data.station,
256        time=data.time,
257        remarks=data.remarks,
258        forecast=[MavPeriod(**p) for p in periods],
259    )

Parser for GFS MAV reports

def parse_mex(report: str) -> Optional[avwx.structs.MexData]:
262def parse_mex(report: str) -> Optional[MexData]:
263    """Parser for GFS MEX reports"""
264    if not report:
265        return None
266    data, lines = _init_parse(report)
267    lines = _trim_lines(lines, 1)
268    period_strings = _split_line(lines[1], size=4, prefix=4)
269    timestamp = data.time.dt if data.time else None
270    periods = _find_time_periods(period_strings, timestamp)
271    _parse_lines(periods, lines[3:], _MEX_HANDLERS, size=4)
272    return MexData(
273        raw=data.raw,
274        sanitized=data.sanitized,
275        station=data.station,
276        time=data.time,
277        remarks=data.remarks,
278        forecast=[MexPeriod(**p) for p in periods],
279    )

Parser for GFS MEX reports