Fix additional ASOS parsing issues
This commit is contained in:
parent
04c5692df1
commit
c0257863ee
1 changed files with 75 additions and 59 deletions
|
@ -3,6 +3,8 @@ import enum
|
||||||
import datetime
|
import datetime
|
||||||
import shapely
|
import shapely
|
||||||
|
|
||||||
|
from typing import Self
|
||||||
|
|
||||||
from nexrad.db import DatabaseTable
|
from nexrad.db import DatabaseTable
|
||||||
from nexrad.coord import COORD_SYSTEM
|
from nexrad.coord import COORD_SYSTEM
|
||||||
from nexrad.vtec import VTECEvent
|
from nexrad.vtec import VTECEvent
|
||||||
|
@ -10,13 +12,15 @@ from nexrad.vtec import VTECEvent
|
||||||
RE_ID = re.compile(r'^(\d+)$')
|
RE_ID = re.compile(r'^(\d+)$')
|
||||||
|
|
||||||
RE_ISSUANCE = re.compile(r'''
|
RE_ISSUANCE = re.compile(r'''
|
||||||
^ (WF[A-Z]{2}\d{2})
|
^ (W[A-Z]{3}\d{2})
|
||||||
[ ]{1} (?P<wfo>[A-Z]{4})
|
[ ]{1} (?P<wfo>[A-Z]{4})
|
||||||
[ ]{1} (?P<day>\d{2})
|
[ ]{1} (?P<day>\d{2})
|
||||||
(?P<hour>\d{2}) (?P<minute>\d{2})
|
(?P<hour>\d{2}) (?P<minute>\d{2})
|
||||||
$
|
$
|
||||||
''', re.X)
|
''', re.X)
|
||||||
|
|
||||||
|
RE_PRODUCT = re.compile(r'^(?P<product>[A-Z]{3})(?P<wfo>[A-Z]{3})$')
|
||||||
|
|
||||||
RE_POLY = re.compile(r'^LAT\.\.\.LON (?P<coords>\d+(?: \d+)+)')
|
RE_POLY = re.compile(r'^LAT\.\.\.LON (?P<coords>\d+(?: \d+)+)')
|
||||||
|
|
||||||
RE_MOTION = re.compile(r'''
|
RE_MOTION = re.compile(r'''
|
||||||
|
@ -57,13 +61,10 @@ def parse_shape(text: str):
|
||||||
return shapely.Polygon(points)
|
return shapely.Polygon(points)
|
||||||
|
|
||||||
class AFOSMessageParserState(enum.Enum):
|
class AFOSMessageParserState(enum.Enum):
|
||||||
NONE = 1
|
NONE = 0
|
||||||
HEADER = enum.auto()
|
SERIAL = enum.auto()
|
||||||
ISSUANCE = enum.auto()
|
ISSUANCE = enum.auto()
|
||||||
META = enum.auto()
|
PRODUCT = enum.auto()
|
||||||
TYPEOFFICE = enum.auto()
|
|
||||||
VTEC = enum.auto()
|
|
||||||
BODY_SEP = enum.auto()
|
|
||||||
BODY = enum.auto()
|
BODY = enum.auto()
|
||||||
TAGS = enum.auto()
|
TAGS = enum.auto()
|
||||||
FOOTER = enum.auto()
|
FOOTER = enum.auto()
|
||||||
|
@ -74,8 +75,9 @@ class AFOSMessage(DatabaseTable):
|
||||||
|
|
||||||
__columns__ = (
|
__columns__ = (
|
||||||
'id', 'timestamp_issued', 'timestamp_start', 'timestamp_end',
|
'id', 'timestamp_issued', 'timestamp_start', 'timestamp_end',
|
||||||
'typeof', 'etn', 'actions', 'wfo', 'phenom', 'sig', 'body',
|
'serial', 'product', 'vtec_type', 'etn', 'actions', 'wfo',
|
||||||
'azimuth', 'speed', 'location', 'forecaster', 'poly',
|
'phenom', 'sig', 'text', 'azimuth', 'speed', 'location',
|
||||||
|
'forecaster', 'poly',
|
||||||
)
|
)
|
||||||
|
|
||||||
__columns_read__ = {
|
__columns_read__ = {
|
||||||
|
@ -95,10 +97,14 @@ class AFOSMessage(DatabaseTable):
|
||||||
}
|
}
|
||||||
|
|
||||||
id: int
|
id: int
|
||||||
|
serial: int
|
||||||
|
|
||||||
timestamp_issued: datetime.datetime
|
timestamp_issued: datetime.datetime
|
||||||
timestamp_start: datetime.datetime
|
timestamp_start: datetime.datetime
|
||||||
timestamp_end: datetime.datetime
|
timestamp_end: datetime.datetime
|
||||||
typeof: str
|
|
||||||
|
product: str
|
||||||
|
vtec_type: str
|
||||||
actions: str
|
actions: str
|
||||||
wfo: str
|
wfo: str
|
||||||
phenom: str
|
phenom: str
|
||||||
|
@ -111,56 +117,66 @@ class AFOSMessage(DatabaseTable):
|
||||||
forecaster: str
|
forecaster: str
|
||||||
poly: shapely.Geometry
|
poly: shapely.Geometry
|
||||||
|
|
||||||
@staticmethod
|
def __init__(self):
|
||||||
def parse(text: str):
|
super().__init__()
|
||||||
event = AFOSMessage()
|
self.product = None
|
||||||
state = AFOSMessageParserState.NONE
|
self.vtec_type = None
|
||||||
|
self.actions = None
|
||||||
|
self.wfo = None
|
||||||
|
self.phenom = None
|
||||||
|
self.sig = None
|
||||||
|
self.etn = None
|
||||||
|
self.body = None
|
||||||
|
self.azimuth = None
|
||||||
|
self.speed = None
|
||||||
|
self.location = None
|
||||||
|
self.forecaster = None
|
||||||
|
self.poly = None
|
||||||
|
|
||||||
issuance = None
|
@staticmethod
|
||||||
|
def parse(text: str) -> Self:
|
||||||
|
event = AFOSMessage()
|
||||||
|
state = AFOSMessageParserState.SERIAL
|
||||||
|
|
||||||
for line in text.split('\n'):
|
for line in text.split('\n'):
|
||||||
line = line.rstrip()
|
line = line.rstrip()
|
||||||
|
|
||||||
if state == AFOSMessageParserState.NONE:
|
if state == AFOSMessageParserState.SERIAL:
|
||||||
match = RE_ID.match(line)
|
match = RE_ID.match(line)
|
||||||
|
|
||||||
if match is not None:
|
if match is not None:
|
||||||
event.id = int(match[1])
|
event.serial = int(match[1])
|
||||||
state = AFOSMessageParserState.HEADER
|
state = AFOSMessageParserState.ISSUANCE
|
||||||
elif state == AFOSMessageParserState.HEADER:
|
elif state == AFOSMessageParserState.ISSUANCE:
|
||||||
match = RE_ISSUANCE.match(line)
|
match = RE_ISSUANCE.match(line)
|
||||||
|
|
||||||
if match is not None:
|
if match is not None:
|
||||||
issuance = match
|
state = AFOSMessageParserState.PRODUCT
|
||||||
state = AFOSMessageParserState.ISSUANCE
|
elif state == AFOSMessageParserState.PRODUCT:
|
||||||
elif state == AFOSMessageParserState.ISSUANCE:
|
match = RE_PRODUCT.match(line)
|
||||||
state = AFOSMessageParserState.META
|
|
||||||
elif state == AFOSMessageParserState.META:
|
if match is not None:
|
||||||
|
event.product = match['product']
|
||||||
|
|
||||||
|
state = AFOSMessageParserState.BODY
|
||||||
|
elif state == AFOSMessageParserState.BODY:
|
||||||
|
if line == '':
|
||||||
|
continue
|
||||||
|
elif line[0] == '/':
|
||||||
vtec = VTECEvent.parse(line)
|
vtec = VTECEvent.parse(line)
|
||||||
|
|
||||||
if vtec is not None:
|
if vtec is not None:
|
||||||
event.timestamp_start = vtec.timestamp_start
|
event.timestamp_start = vtec.timestamp_start
|
||||||
event.timestamp_end = vtec.timestamp_end
|
event.timestamp_end = vtec.timestamp_end
|
||||||
|
|
||||||
event.typeof = vtec.typeof
|
event.vtec_type = vtec.typeof
|
||||||
event.actions = vtec.actions
|
event.actions = vtec.actions
|
||||||
event.wfo = vtec.wfo
|
event.wfo = vtec.wfo
|
||||||
event.phenom = vtec.phenom
|
event.phenom = vtec.phenom
|
||||||
event.sig = vtec.sig
|
event.sig = vtec.sig
|
||||||
event.etn = vtec.etn
|
event.etn = vtec.etn
|
||||||
|
elif line == '&&':
|
||||||
state = AFOSMessageParserState.VTEC
|
|
||||||
elif state == AFOSMessageParserState.VTEC:
|
|
||||||
if line == '':
|
|
||||||
state = AFOSMessageParserState.BODY_SEP
|
|
||||||
elif state == AFOSMessageParserState.BODY_SEP:
|
|
||||||
event.body = line
|
|
||||||
state = AFOSMessageParserState.BODY
|
|
||||||
elif state == AFOSMessageParserState.BODY:
|
|
||||||
if line == '&&':
|
|
||||||
state = AFOSMessageParserState.TAGS
|
state = AFOSMessageParserState.TAGS
|
||||||
else:
|
|
||||||
event.body += '\n' + line
|
|
||||||
elif state == AFOSMessageParserState.TAGS:
|
elif state == AFOSMessageParserState.TAGS:
|
||||||
if line == '$$':
|
if line == '$$':
|
||||||
state = AFOSMessageParserState.FOOTER
|
state = AFOSMessageParserState.FOOTER
|
||||||
|
|
Loading…
Add table
Reference in a new issue