1292 lines
47 KiB
Python
1292 lines
47 KiB
Python
|
|
||
|
# This software is in the public domain, furnished "as is", without technical
|
||
|
# support, and with no warranty, express or implied, as to its usefulness for
|
||
|
# any purpose.
|
||
|
#
|
||
|
# TropicalHazards
|
||
|
#
|
||
|
# Author: Matthew H. Belk WFO BOX
|
||
|
# ----------------------------------------------------------------------------
|
||
|
#
|
||
|
# SOFTWARE HISTORY
|
||
|
#
|
||
|
# Date Ticket# Engineer Description
|
||
|
# ------------- -------- --------- --------------------------------------------
|
||
|
# Jun 22, 2013 mbelk Initial creation
|
||
|
# Jul 14, 2016 mbelk Changes for 2017 season
|
||
|
# Sep 19, 2016 19293 randerso Initial baseline check in
|
||
|
# May 22, 2019 21290 mbelk/ryu Fix error with importing TCVNHC formatters
|
||
|
#
|
||
|
########################################################################
|
||
|
|
||
|
##
|
||
|
# This is an absolute override file, indicating that a higher priority version
|
||
|
# of the file will completely replace a lower priority version of the file.
|
||
|
##
|
||
|
|
||
|
import os
|
||
|
import re
|
||
|
import errno
|
||
|
import functools
|
||
|
|
||
|
import JsonSupport, LocalizationSupport
|
||
|
import LogStream
|
||
|
import ModuleAccessor
|
||
|
import pprint as pp
|
||
|
|
||
|
|
||
|
class TropicalHazards:
|
||
|
|
||
|
def __init__(self):
|
||
|
|
||
|
#-----------------------------------------------------------------------
|
||
|
# Make a link to the TropicalAreaDictionary
|
||
|
|
||
|
# Access the information for the breakpoint area(s) if available
|
||
|
self._tropicalAreaDict = \
|
||
|
ModuleAccessor.ModuleAccessor().variable("AreaDictionary",
|
||
|
"AreaDictionary")
|
||
|
|
||
|
# Then make a cache of sorted hash keys to this dictionary
|
||
|
self._tropicalAreaDictKeys = sorted(self._tropicalAreaDict.keys())
|
||
|
|
||
|
|
||
|
################################################################################
|
||
|
# New common utility methods for tropical hazard formatters
|
||
|
################################################################################
|
||
|
|
||
|
def allowedHazards(self):
|
||
|
"""TropicalHazards version of GenericHazards.allowedHazards.
|
||
|
|
||
|
This method defines the allowed hazards for tropical hazard products.
|
||
|
"""
|
||
|
tropicalActions = ["NEW", "EXA", "CAN", "CON"]
|
||
|
return [
|
||
|
('HU.W',tropicalActions,'Hurricane'),
|
||
|
('HU.A',tropicalActions,'Hurricane'),
|
||
|
('SS.W',tropicalActions,'Surge'),
|
||
|
('SS.A',tropicalActions,'Surge'),
|
||
|
('TR.W',tropicalActions,'Tropical'),
|
||
|
('TR.A',tropicalActions,'Tropical'),
|
||
|
]
|
||
|
|
||
|
|
||
|
################################################################################
|
||
|
# New common utility methods for tropical hazard formatters
|
||
|
################################################################################
|
||
|
|
||
|
#===========================================================================
|
||
|
# Define a method to determine which WFOs are impacted based on a list of
|
||
|
# affected edit area ID's
|
||
|
|
||
|
def _getAffectedWFOs(self, idList):
|
||
|
"""TropicalHazards addition of _getAffectedWFOs.
|
||
|
|
||
|
This method will produce a list of NWS WFOs impacted by tropical
|
||
|
hazards with the specified identifiers.
|
||
|
|
||
|
Arguments:
|
||
|
idList -> list TropicalAreaDictionary keys
|
||
|
"""
|
||
|
|
||
|
# Look at each breakpoint segment in this list
|
||
|
for id in idList:
|
||
|
|
||
|
# Get the AreaDictionary entry for this segment
|
||
|
if id in self._tropicalAreaDict:
|
||
|
entry = self._tropicalAreaDict[id]
|
||
|
else:
|
||
|
LogStream.logProblem(\
|
||
|
"AreaDictionary missing definition for [" + id + "].")
|
||
|
continue
|
||
|
|
||
|
# Get the WFO responsible for this segment - always use the WFO of the
|
||
|
# starting point to avoid including WFOs unnecessarily
|
||
|
if 'wfo' in entry:
|
||
|
wfo = entry['wfo'].strip()
|
||
|
else:
|
||
|
LogStream.logProblem(\
|
||
|
"AreaDictionary missing WFO definition for [" + id + "].")
|
||
|
continue
|
||
|
|
||
|
# If we have a valid WFO identifier, and it is not already noted in the
|
||
|
# impacted WFO list
|
||
|
if len(wfo) > 0 and wfo not in self._wfoList:
|
||
|
|
||
|
# Add this WFO to the list of impacted WFOs
|
||
|
self._wfoList.append(wfo)
|
||
|
|
||
|
|
||
|
#===========================================================================
|
||
|
# Define a method to format a breakpoint text line within a TCV segment
|
||
|
|
||
|
def _formatTCVline(self, entry, type="start"):
|
||
|
"""TropicalHazards addition of _formatTCVline.
|
||
|
|
||
|
This method will produce a list of NWS WFOs impacted by tropical
|
||
|
hazards with the specified identifiers.
|
||
|
|
||
|
Arguments:
|
||
|
entry -> TropicalAreaDictionary entry for an edit area
|
||
|
type -> type of breakpoint to produce (optional, defaults to start)
|
||
|
"""
|
||
|
|
||
|
# If this is not an ending point
|
||
|
if type != "end":
|
||
|
|
||
|
# Get the information we need
|
||
|
point = entry["startBreakpoint"].strip()
|
||
|
lat = entry["startLat"].strip()
|
||
|
lon = entry["startLon"].strip()
|
||
|
state = entry["startState"].strip()
|
||
|
|
||
|
# Otherwise - get the end point info for this segment
|
||
|
else:
|
||
|
|
||
|
# Get the information we need
|
||
|
point = entry["endBreakpoint"].strip()
|
||
|
lat = entry["endLat"].strip()
|
||
|
lon = entry["endLon"].strip()
|
||
|
state = entry["endState"].strip()
|
||
|
|
||
|
|
||
|
# Clean up the state so there are no spaces or dashes
|
||
|
state = re.sub("[ _-]+", "", state)
|
||
|
|
||
|
#-----------------------------------------------------------------------
|
||
|
# If this is not the border of a state or country
|
||
|
|
||
|
if re.search("(?i)border", point) is None:
|
||
|
|
||
|
# Add the state/country
|
||
|
point += "-" + state
|
||
|
|
||
|
#-----------------------------------------------------------------------
|
||
|
# Append the appropriate hemisphere of the latitude
|
||
|
|
||
|
if lat.find("-") != -1:
|
||
|
lat += "S"
|
||
|
lat = lat.replace("-", "")
|
||
|
else:
|
||
|
lat += "N"
|
||
|
|
||
|
#-----------------------------------------------------------------------
|
||
|
# Append the appropriate hemisphere of the longitude
|
||
|
|
||
|
if lon.find("-") != -1:
|
||
|
lon += "W"
|
||
|
lon = lon.replace("-", "")
|
||
|
else:
|
||
|
lon += "E"
|
||
|
|
||
|
#-----------------------------------------------------------------------
|
||
|
# Now construct the final formatted line
|
||
|
|
||
|
text = "%-36s%6s%7s\n" % (re.sub("[ _]+", "-", point) + " ", lat, lon)
|
||
|
|
||
|
# Return the text
|
||
|
return text
|
||
|
|
||
|
|
||
|
#===========================================================================
|
||
|
# Define a method to sort breakpoint record keys
|
||
|
|
||
|
@property
|
||
|
def _sortBreakpoints(self):
|
||
|
"""TropicalHazards addition of _sortBreakpoints.
|
||
|
|
||
|
This method will produce a sorted list of breakpoint segments. This
|
||
|
ensures the order of contiguous breakpoint segments
|
||
|
"""
|
||
|
def cmpfunc(a, b):
|
||
|
# Make a list of valid string identifier parts
|
||
|
validTypes = [
|
||
|
"LN", # mainland segments - any country
|
||
|
"KEY", # Florida Keys
|
||
|
"ISL", # islands
|
||
|
"CUBA", # Cuba
|
||
|
"HISP", # Hispaniola
|
||
|
"NAI", # North Atlantic islands
|
||
|
"WTDE", # Deleware Bay
|
||
|
"WTTP", # Tidal Potomac
|
||
|
"WTCP", # Chesapeake Bay
|
||
|
"WTPT", # Generic water points
|
||
|
|
||
|
# Zones used by VTEC
|
||
|
"GYC", # Guyana
|
||
|
"VEC", # Venezuela
|
||
|
"COC", # Colombia
|
||
|
"PAC", # Panama
|
||
|
"CRC", # Costa Rica
|
||
|
"NIC", # Nicaragua
|
||
|
"HNC", # Honduras
|
||
|
"GTC", # Guatemala
|
||
|
"BZC", # Belize
|
||
|
"MXC", # Mexico
|
||
|
"USC", # United States
|
||
|
"CNC", # Canada
|
||
|
"KEC", # Dry Tortugas
|
||
|
"AWC", # Aruba
|
||
|
"CWC", # Curacao
|
||
|
"TTC", # Trinidad and Tobago
|
||
|
"BBC", # Barbados
|
||
|
"LCC", # St. Lucia
|
||
|
"MQC", # France - Caribbean
|
||
|
"AGC", # Antigua and Barbuda
|
||
|
"BSC", # Bahamas
|
||
|
"BMC", # Bermuda
|
||
|
"JMC", # Jamaica
|
||
|
"KYC", # Cayman Islands
|
||
|
"CUC", # Cuba
|
||
|
"DOC", # Dominican Republic
|
||
|
"HTC", # Haiti
|
||
|
"PMC", # France - North Atlantic
|
||
|
"LOC", # Lake_Okeechobee
|
||
|
"FBC", # Florida Bay
|
||
|
"PSC", # Pamlico Sound
|
||
|
"ASC", # Albemarle Sound
|
||
|
"TXZ", # Texas
|
||
|
"LAZ", # Louisiana
|
||
|
"MSZ", # Mississippi
|
||
|
"ALZ", # Alabama
|
||
|
"FLZ", # Florida
|
||
|
"GAZ", # Georgia
|
||
|
"SCZ", # South Carolina
|
||
|
"NCZ", # North Carolina
|
||
|
"VAZ", # Virginia
|
||
|
"MDZ", # Maryland
|
||
|
"DCZ", # District of Columbia
|
||
|
"DEZ", # Deleware
|
||
|
"NJZ", # New Jersey
|
||
|
"NYZ", # New York
|
||
|
"CTZ", # Connecticut
|
||
|
"RIZ", # Rhode Island
|
||
|
"MAZ", # Massachusetts
|
||
|
"NHZ", # New Hampshire
|
||
|
"MEZ", # Maine
|
||
|
"NMZ", # New Mexico
|
||
|
"ARZ", # Arkansas
|
||
|
"OKZ", # Oklahoma
|
||
|
"MOZ", # Missouri
|
||
|
"TNZ", # Tennessee
|
||
|
"WVZ", # West Virginia
|
||
|
"PAZ", # Pennsylvania
|
||
|
"VTZ", # Vermont
|
||
|
"PRZ", # Puerto Rico
|
||
|
"VIZ", # U.S. Virgin Islands
|
||
|
"RE", # General edit area collection
|
||
|
]
|
||
|
|
||
|
# Get the first part of each identifier
|
||
|
aSeg = a.split("_")[0]
|
||
|
bSeg = b.split("_")[0]
|
||
|
|
||
|
# Get ready to split these identifiers into alpha and numeric parts
|
||
|
aSegType = ""
|
||
|
bSegType = ""
|
||
|
aSegNum = ""
|
||
|
bSegNum = ""
|
||
|
|
||
|
# Start with the alpha components
|
||
|
for c in aSeg:
|
||
|
if c.isalpha():
|
||
|
aSegType += c
|
||
|
|
||
|
for c in bSeg:
|
||
|
if c.isalpha():
|
||
|
bSegType += c
|
||
|
|
||
|
# Now get the numeric components
|
||
|
for c in aSeg:
|
||
|
if c.isnumeric():
|
||
|
aSegNum += c
|
||
|
|
||
|
for c in bSeg:
|
||
|
if c.isnumeric():
|
||
|
bSegNum += c
|
||
|
|
||
|
# Determine the order of these areas based on segment type first
|
||
|
aTypeIndex = validTypes.index(aSegType)
|
||
|
try:
|
||
|
bTypeIndex = validTypes.index(bSegType)
|
||
|
except:
|
||
|
bTypeIndex = aTypeIndex
|
||
|
bSegNum = aSegNum
|
||
|
|
||
|
# Try to determine order based on segment type
|
||
|
if aTypeIndex < bTypeIndex:
|
||
|
return -1
|
||
|
elif bTypeIndex < aTypeIndex:
|
||
|
return 1
|
||
|
|
||
|
# If the segment types are the same, use the numeric component last
|
||
|
if int(aSegNum) < int(bSegNum):
|
||
|
return -1
|
||
|
elif int(bSegNum) < int(aSegNum):
|
||
|
return 1
|
||
|
else:
|
||
|
# # print "ERROR!!!!!!! Segment names are equal!!!!!!!"
|
||
|
return 0
|
||
|
|
||
|
return functools.cmp_to_key(cmpfunc)
|
||
|
|
||
|
#===========================================================================
|
||
|
# Define a method to organize breakpoint segment zones by government
|
||
|
|
||
|
def _organizeZonesByGovt(self):
|
||
|
"""TropicalHazards addition of _organizeZonesByGovt.
|
||
|
|
||
|
This method will produce a dictionary of sorted lists where each list
|
||
|
contains all the zone identifiers for which that government is the
|
||
|
responsible entity.
|
||
|
"""
|
||
|
|
||
|
# Create a dictionary to hold all zones managed by a government
|
||
|
zoneDict = {}
|
||
|
|
||
|
# Also make a list to hold governments in the order we find them
|
||
|
govtList = []
|
||
|
|
||
|
# Initialize some lists for handling zone codes
|
||
|
ugcList = []
|
||
|
ugcListUsa = []
|
||
|
|
||
|
#-----------------------------------------------------------------------
|
||
|
# Look at each edit area we have
|
||
|
|
||
|
for key in self._tropicalAreaDictKeys:
|
||
|
|
||
|
# Get the type of this zone
|
||
|
zoneId = key.split("_")[0]
|
||
|
|
||
|
zoneType = ""
|
||
|
|
||
|
# Get all the letters from this zone ID
|
||
|
for c in zoneId:
|
||
|
if not c.isdigit():
|
||
|
zoneType += c
|
||
|
|
||
|
# If this is primary representation of segment zones
|
||
|
# (this is to avoid duplication with the individual zones)
|
||
|
# Make an exception for US zones though
|
||
|
if zoneType in ["LN", "KEY", "CUBA", "HISP", "ISL", "NAI", "WTDE",
|
||
|
"WTTP", "WTCP", "WTPT", "USC"]:
|
||
|
|
||
|
# Get the government responsible for this zone
|
||
|
zoneGovt = self._tropicalAreaDict[key]["hazardIssuer"].strip()
|
||
|
|
||
|
# Handle the case of the USA, which receives no attribution
|
||
|
if zoneGovt.strip() == "":
|
||
|
zoneGovt = "US"
|
||
|
|
||
|
# If we do not already know about this government
|
||
|
if zoneGovt not in govtList:
|
||
|
|
||
|
# Add it now
|
||
|
govtList.append(zoneGovt)
|
||
|
|
||
|
#---------------------------------------------------------------
|
||
|
# Get the impacted zones for this segment
|
||
|
|
||
|
ugcCode = self._tropicalAreaDict[key]["ugcCode"].strip()
|
||
|
|
||
|
#---------------------------------------------------------------
|
||
|
# Expand UGC code if there is more than one zone represented
|
||
|
|
||
|
if len(ugcCode.split("-")) > 1 or ugcCode.find(">") != -1:
|
||
|
ugcList = self.expandComplexUgc(ugcCode)
|
||
|
|
||
|
# Otherwise, just use this single zone
|
||
|
else:
|
||
|
ugcList = [ugcCode]
|
||
|
|
||
|
#---------------------------------------------------------------
|
||
|
# Expand UGC code if there is more than one zone represented
|
||
|
|
||
|
try:
|
||
|
ugcCodeUsa = self._tropicalAreaDict[key]["ugcCodeUsa"].strip()
|
||
|
|
||
|
if len(ugcCodeUsa.split("-")) > 1 or ugcCodeUsa.find(">") != -1:
|
||
|
ugcListUsa = self.expandComplexUgc(ugcCodeUsa)
|
||
|
|
||
|
# Otherwise, just use this single zone
|
||
|
else:
|
||
|
ugcListUsa = [ugcCodeUsa]
|
||
|
|
||
|
except:
|
||
|
ugcListUsa = []
|
||
|
|
||
|
#---------------------------------------------------------------
|
||
|
# If we already have an entry for this government
|
||
|
|
||
|
if zoneGovt in zoneDict:
|
||
|
|
||
|
# Get the zones already associated
|
||
|
curZoneList = zoneDict[zoneGovt]
|
||
|
|
||
|
# Otherwise make a new list for this governement
|
||
|
else:
|
||
|
curZoneList = []
|
||
|
|
||
|
#---------------------------------------------------------------
|
||
|
# Now add all the new zones
|
||
|
|
||
|
for ugc in ugcList + ugcListUsa:
|
||
|
|
||
|
# If we don't already have this ugc
|
||
|
if ugc not in curZoneList and len(ugc.strip()) > 0:
|
||
|
|
||
|
# Add it
|
||
|
curZoneList.append(ugc)
|
||
|
|
||
|
## print curZoneList
|
||
|
|
||
|
# Sort the UGC list
|
||
|
curZoneList.sort()
|
||
|
|
||
|
# Store the list of zones for this government
|
||
|
zoneDict[zoneGovt] = curZoneList
|
||
|
|
||
|
# Always ensure the USA comes first
|
||
|
if "US" in govtList:
|
||
|
govtList.remove("US")
|
||
|
finalGovtList = ["US"] + govtList
|
||
|
|
||
|
# Return the completed dictionary
|
||
|
return zoneDict, finalGovtList
|
||
|
|
||
|
|
||
|
#===========================================================================
|
||
|
# Define a method to filter a segment list by government
|
||
|
|
||
|
def _filterAreaListByGovernment(self, govtList, areaList):
|
||
|
"""TropicalHazards addition of _filterAreaListByGovernment.
|
||
|
|
||
|
This method will produce a list of all zones managed by a particular
|
||
|
government contained within the specified area list.
|
||
|
|
||
|
Arguments:
|
||
|
govtList -> list of identifiers managed by a government
|
||
|
areaList -> list of edit area identifiers to process
|
||
|
"""
|
||
|
|
||
|
# Initialize a new list
|
||
|
newList = []
|
||
|
|
||
|
# Look through each edit area
|
||
|
for area in areaList:
|
||
|
|
||
|
# If this edit area is managed by this government
|
||
|
if area in govtList:
|
||
|
|
||
|
# Add it to the filtered list
|
||
|
newList.append(area)
|
||
|
|
||
|
# Return the filtered list
|
||
|
return newList
|
||
|
|
||
|
|
||
|
#===========================================================================
|
||
|
# Define a method to filter a segment list by government
|
||
|
|
||
|
def _organizeAreasByType(self, areaList):
|
||
|
"""TropicalHazards addition of _organizeAreasByType.
|
||
|
|
||
|
This method will separate a list of areas into one of four types:
|
||
|
mainland segments, UGC zones, zones and islands. These will be stored
|
||
|
in the processed hazard dictionary for easier access later.
|
||
|
|
||
|
Arguments:
|
||
|
areaList -> list of edit area identifiers to process
|
||
|
"""
|
||
|
|
||
|
# Initialize both lists
|
||
|
segmentList = []
|
||
|
ugcZoneList = []
|
||
|
zoneList = []
|
||
|
islandList = []
|
||
|
waterList = []
|
||
|
|
||
|
# Look through each edit area
|
||
|
for area in areaList:
|
||
|
|
||
|
# Assume this is a "land" area
|
||
|
areaType = "land"
|
||
|
|
||
|
# If the TropicalAreaDictionary has a record for this area
|
||
|
if area in self._tropicalAreaDict:
|
||
|
|
||
|
# Get the type of this area - if we can
|
||
|
if "segmentType" in self._tropicalAreaDict[area]:
|
||
|
areaType = self._tropicalAreaDict[area]["segmentType"]
|
||
|
|
||
|
# Get the type of this area
|
||
|
try:
|
||
|
usaZoneList = self.expandComplexUgc(
|
||
|
self._tropicalAreaDict[area]["ugcCodeUsa"])
|
||
|
except:
|
||
|
usaZoneList = []
|
||
|
|
||
|
|
||
|
#---------------------------------------------------------------
|
||
|
# If this is an island
|
||
|
|
||
|
if areaType == "island":
|
||
|
|
||
|
# If we do not already have a record for this area
|
||
|
if area not in islandList:
|
||
|
|
||
|
# Add it to the list of islands
|
||
|
islandList.append(area)
|
||
|
|
||
|
#---------------------------------------------------------------
|
||
|
# Otherwise, if this is a water area
|
||
|
|
||
|
elif areaType == "water":
|
||
|
|
||
|
# If we do not already have a record for this area
|
||
|
if area not in waterList:
|
||
|
|
||
|
# Add it to the list of islands
|
||
|
waterList.append(area)
|
||
|
|
||
|
#---------------------------------------------------------------
|
||
|
# Otherwise, organize the land-based areas
|
||
|
|
||
|
else:
|
||
|
|
||
|
# If this is a zone-based identifier
|
||
|
if len(area) == 6 and area[2] in ["Z", "C"]:
|
||
|
|
||
|
# Place this zone into the proper list
|
||
|
if area[2] == "Z":
|
||
|
|
||
|
# If this area has not already been recorded
|
||
|
if area not in ugcZoneList:
|
||
|
|
||
|
# Add it to the UGC zone list
|
||
|
ugcZoneList.append(area)
|
||
|
else:
|
||
|
|
||
|
# If this area has not already been recorded
|
||
|
if area not in zoneList:
|
||
|
|
||
|
# Add it to the zone list
|
||
|
zoneList.append(area)
|
||
|
|
||
|
# If there any zones associated with this segment
|
||
|
if len(usaZoneList) > 0:
|
||
|
|
||
|
for usZone in usaZoneList:
|
||
|
|
||
|
if usZone not in ugcZoneList:
|
||
|
|
||
|
# Add it to the UGC zone list
|
||
|
ugcZoneList.append(usZone)
|
||
|
|
||
|
# Otherwise, this is a breakpoint segment
|
||
|
elif area not in segmentList:
|
||
|
segmentList.append(area)
|
||
|
|
||
|
# Get any UGC codes associated with this segment
|
||
|
areaUgc = self._tropicalAreaDict[area]["ugcCode"]
|
||
|
|
||
|
# If there is more than 1 zone associated with segment
|
||
|
if len(areaUgc) > 7:
|
||
|
|
||
|
# Expand the UGC codes
|
||
|
ugcList = self.expandComplexUgc(areaUgc)
|
||
|
|
||
|
# Otherwise, make a simpler list so we can proceed
|
||
|
else:
|
||
|
ugcList = [areaUgc]
|
||
|
|
||
|
#-------------------------------------------------------
|
||
|
# Add each zone code into the list as needed
|
||
|
|
||
|
for ugcCode in ugcList:
|
||
|
|
||
|
# Clean up any extra characters
|
||
|
ugcCode = ugcCode.replace("-", "")
|
||
|
|
||
|
# If this is a zone-based identifier
|
||
|
if len(ugcCode) >= 6 and ugcCode[2] in ["Z", "C"]:
|
||
|
|
||
|
# Place this zone into the proper list
|
||
|
if ugcCode[2] == "Z":
|
||
|
|
||
|
# If this area has not already been recorded
|
||
|
if ugcCode not in ugcZoneList:
|
||
|
|
||
|
# Add it to the UGC zone list
|
||
|
ugcZoneList.append(ugcCode)
|
||
|
else:
|
||
|
|
||
|
# If this area has not already been recorded
|
||
|
if ugcCode not in zoneList:
|
||
|
|
||
|
# Add it to the zone list
|
||
|
zoneList.append(ugcCode)
|
||
|
|
||
|
|
||
|
#-----------------------------------------------------------------------
|
||
|
# Sort all lists to keep them ordered - as needed
|
||
|
|
||
|
if len(segmentList) > 1:
|
||
|
segmentList.sort(key=self._sortBreakpoints)
|
||
|
|
||
|
if len(ugcZoneList) > 1:
|
||
|
ugcZoneList.sort(key=self._sortBreakpoints)
|
||
|
|
||
|
if len(zoneList) > 1:
|
||
|
zoneList.sort(key=self._sortBreakpoints)
|
||
|
|
||
|
if len(islandList) > 1:
|
||
|
islandList.sort(key=self._sortBreakpoints)
|
||
|
|
||
|
if len(waterList) > 1:
|
||
|
waterList.sort(key=self._sortBreakpoints)
|
||
|
|
||
|
# Return the compiled lists
|
||
|
return (segmentList, ugcZoneList, zoneList, islandList, waterList)
|
||
|
|
||
|
|
||
|
#===========================================================================
|
||
|
# Define a method to construct a processed hazard dictionary
|
||
|
|
||
|
def _constructHazardDict(self, hazardPhenSig, filterEtn):
|
||
|
"""TropicalHazards addition of _constructHazardDict.
|
||
|
|
||
|
This method will produce a processed dictionary of tropical hazards
|
||
|
for easier use later on.
|
||
|
|
||
|
Arguments:
|
||
|
hazardPhenSig -> dictionary of hazards keyed by phenomenon and
|
||
|
significance. Values are a list of all hazards
|
||
|
which share that same phenomenon and significance.
|
||
|
filterEtn -> Event Tracking Number of interest which will be used
|
||
|
to filter hazards for a particular product.
|
||
|
"""
|
||
|
|
||
|
#-----------------------------------------------------------------------
|
||
|
# Get ready to populate the hazard dictionary for this storm
|
||
|
|
||
|
hazardAreaDict = {}
|
||
|
hazardAreaDictKeyList = []
|
||
|
|
||
|
# Assume this is going to be the last product we issue for this storm
|
||
|
self._allCAN = True
|
||
|
|
||
|
#=======================================================================
|
||
|
# Look for each of the tropical hazards in order
|
||
|
|
||
|
for phenSig in [("SS","W"), ("HU","W"), ("SS","A"), ("HU","A"),
|
||
|
("TR","W"), ("TR","A")]:
|
||
|
|
||
|
if phenSig in hazardPhenSig:
|
||
|
print("="*90)
|
||
|
print("\n\tConstructing -> %s" % (repr(phenSig)))
|
||
|
print(len(hazardPhenSig[phenSig]), hazardPhenSig[phenSig])
|
||
|
|
||
|
# Look through all the sampled hazards
|
||
|
for phen in hazardPhenSig[phenSig]:
|
||
|
print("-"*90)
|
||
|
print("phen = %s" % (phen))
|
||
|
|
||
|
# Set aside the headline for each action in this area
|
||
|
NEW = []
|
||
|
CAN = []
|
||
|
UPG = []
|
||
|
EXA = []
|
||
|
CON = []
|
||
|
|
||
|
#-----------------------------------------------------------
|
||
|
# If we have items for this particular phen.sig
|
||
|
# combination, and this is the storm we are after
|
||
|
|
||
|
if phen["etn"] != filterEtn:
|
||
|
|
||
|
print("\tWrong storm!", phen)
|
||
|
|
||
|
# Move on to the next one
|
||
|
continue
|
||
|
|
||
|
|
||
|
# Get the full VTEC code for this phenomena
|
||
|
# curHazardKey = (phen["act"], phen["key"])
|
||
|
curHazardKey = (phen["act"], phen["phensig"])
|
||
|
print("+++++ %s" % (repr(curHazardKey)))
|
||
|
|
||
|
# If this action is anything other than "CAN", indicate it
|
||
|
# so we don't delete the JSON file for this storm at end
|
||
|
if phen["act"] != "CAN":
|
||
|
self._allCAN = False
|
||
|
|
||
|
# If we do not have the ETN of this hazard
|
||
|
if re.search(":\d{4}$", curHazardKey[1]) is None:
|
||
|
|
||
|
newHazardType = curHazardKey[1] + ":%d" % \
|
||
|
(phen["etn"])
|
||
|
else:
|
||
|
newHazardType = ""
|
||
|
|
||
|
# If we need to adjust the hazard key
|
||
|
if len(newHazardType) > 0:
|
||
|
|
||
|
# Make the changes
|
||
|
newCurHazardKey = (curHazardKey[0], newHazardType)
|
||
|
curHazardKey = newCurHazardKey
|
||
|
|
||
|
# See if there are upgrades or replacements for this area
|
||
|
areaHazardList = self._hazards.getHazardList(phen["id"])
|
||
|
|
||
|
#-----------------------------------------------------------
|
||
|
# Construct a hazard key which incorporates all hazards
|
||
|
# and actions for this area
|
||
|
|
||
|
tempHazardList = [curHazardKey]
|
||
|
for areaHazard in areaHazardList:
|
||
|
|
||
|
#-------------------------------------------------------
|
||
|
# Record headline for each action we find
|
||
|
|
||
|
if areaHazard["act"] == "NEW" and \
|
||
|
areaHazard["hdln"] not in NEW:
|
||
|
NEW.append(areaHazard["hdln"])
|
||
|
|
||
|
elif areaHazard["act"] == "CAN" and \
|
||
|
areaHazard["hdln"] not in CAN:
|
||
|
CAN.append(areaHazard["hdln"])
|
||
|
|
||
|
elif areaHazard["act"] == "UPG" and \
|
||
|
areaHazard["hdln"] not in UPG:
|
||
|
UPG.append(areaHazard["hdln"])
|
||
|
|
||
|
elif areaHazard["act"] == "CON" and \
|
||
|
areaHazard["hdln"] not in CON:
|
||
|
CON.append(areaHazard["hdln"])
|
||
|
|
||
|
elif areaHazard["act"] == "EXA" and \
|
||
|
areaHazard["hdln"] not in EXA:
|
||
|
EXA.append(areaHazard["hdln"])
|
||
|
|
||
|
#-------------------------------------------------------
|
||
|
# Make a key for this particular hazard/action combo
|
||
|
|
||
|
tempHazardKey = (areaHazard["act"], areaHazard["phensig"])
|
||
|
|
||
|
# If we do not have the ETN of this hazard
|
||
|
if re.search(":\d{4}$", tempHazardKey[1]) is None:
|
||
|
|
||
|
newHazardType = tempHazardKey[1] + ":%d" % \
|
||
|
(areaHazard["etn"])
|
||
|
else:
|
||
|
newHazardType = ""
|
||
|
|
||
|
# If we need to adjust the hazard key
|
||
|
if len(newHazardType) > 0:
|
||
|
|
||
|
# Make the changes
|
||
|
newTempHazardKey = (tempHazardKey[0], newHazardType)
|
||
|
tempHazardKey = newTempHazardKey
|
||
|
|
||
|
# If this is not already part of the hazard key
|
||
|
if tempHazardKey != curHazardKey:
|
||
|
|
||
|
# Add this hazard/action combo to the list
|
||
|
tempHazardList.append(tempHazardKey)
|
||
|
|
||
|
# Sort the keys so we have some consistency in ordering
|
||
|
tempHazardList.sort()
|
||
|
|
||
|
# Convert the list of hazards for this area into a tuple
|
||
|
# so we can use it as a dictionary key
|
||
|
hazardKey = tuple(tempHazardList)
|
||
|
|
||
|
#-----------------------------------------------------------
|
||
|
# Ensure we only group areas associated with same storm
|
||
|
# and hazard/action combos
|
||
|
|
||
|
# If we already have an entry for this storm and hazard
|
||
|
if hazardKey in hazardAreaDict:
|
||
|
|
||
|
# Add to what is already there
|
||
|
tempList = hazardAreaDict[hazardKey]["AREAS"]
|
||
|
tempList.append(phen["id"])
|
||
|
hazardAreaDict[hazardKey]["AREAS"] = tempList
|
||
|
|
||
|
# Otherwise, make a new entry
|
||
|
else:
|
||
|
## "AREAS":[phen["id"]], "HDLN":phen["hdln"],
|
||
|
hazardAreaDict[hazardKey] = {
|
||
|
"AREAS":[phen["id"]], "NEW":NEW, "CAN":CAN,
|
||
|
"CON":CON, "EXA":EXA, "UPG":UPG
|
||
|
}
|
||
|
|
||
|
# Add this key the list
|
||
|
if hazardKey not in hazardAreaDictKeyList:
|
||
|
hazardAreaDictKeyList.append(hazardKey)
|
||
|
|
||
|
print("\n\n", "+"*100)
|
||
|
print("in the middle")
|
||
|
print(pp.pformat(hazardAreaDictKeyList), "\n")
|
||
|
print(pp.pformat(hazardAreaDict))
|
||
|
|
||
|
#-----------------------------------------------------------------------
|
||
|
# Keep track of segments and zones. We will need segments to
|
||
|
# ensure proper grouping and breakpoints. We will need UGC zones
|
||
|
# to get the proper VTEC action
|
||
|
|
||
|
segments = []
|
||
|
ugcZones = []
|
||
|
zones = []
|
||
|
islands = []
|
||
|
water = []
|
||
|
|
||
|
#=======================================================================
|
||
|
# Organize all the impacted areas by type
|
||
|
|
||
|
for key in hazardAreaDictKeyList:
|
||
|
|
||
|
#-------------------------------------------------------------------
|
||
|
# Organize various areas associated with this hazard by type
|
||
|
|
||
|
(segments, ugcZones, zones, islands, water) = \
|
||
|
self._organizeAreasByType(hazardAreaDict[key]["AREAS"])
|
||
|
|
||
|
# Add these organized zones to the dictionary for this hazard
|
||
|
hazardAreaDict[key]["SEGMENTS"] = segments
|
||
|
hazardAreaDict[key]["UGCZONES"] = ugcZones
|
||
|
hazardAreaDict[key]["ZONES"] = zones
|
||
|
hazardAreaDict[key]["ISLANDS"] = islands
|
||
|
hazardAreaDict[key]["WATER"] = water
|
||
|
|
||
|
print("+"*90 + "\nFinally!")
|
||
|
print("found -> %s" % (repr(hazardAreaDictKeyList)))
|
||
|
print("allCAN = %s" % (self._allCAN))
|
||
|
for key in hazardAreaDictKeyList:
|
||
|
print("-"*60)
|
||
|
print("%s\n\t%s" % (key, pp.pformat(hazardAreaDict[key])))
|
||
|
|
||
|
# Return the completed hazard dictionary and sorted keys
|
||
|
return (hazardAreaDict, hazardAreaDictKeyList)
|
||
|
|
||
|
|
||
|
#===========================================================================
|
||
|
# Process the shortcut hazard dictionary and organize a list of segments
|
||
|
# which are organized by similar type.
|
||
|
|
||
|
def _constructSegmentList(self, hazardAreaDict, hazardAreaDictKeyList,
|
||
|
UStcv=0):
|
||
|
"""TropicalHazards addition of _constructSegmentList.
|
||
|
|
||
|
This method will produce create all the appropriate segments which
|
||
|
should go into a tropical hazard product, particularly a TCV.
|
||
|
|
||
|
Arguments:
|
||
|
hazardAreaDict -> processed dictionary of hazards
|
||
|
hazardAreaDictKeyList -> list of keys of active hazards to process.
|
||
|
UStcv -> (optional) toggle to group islands within a single segment
|
||
|
{1 = Yes (default - USA TCV) / 0 = No}
|
||
|
"""
|
||
|
|
||
|
# Initialize a list to hold the final group of segments
|
||
|
finalSegmentList = []
|
||
|
|
||
|
segmentDict = {"CUC": [], "HTC":[], "DOC":[], "USC":[]}
|
||
|
|
||
|
#-----------------------------------------------------------------------
|
||
|
# Look at every hazard we found
|
||
|
|
||
|
for hazardKey in hazardAreaDictKeyList:
|
||
|
|
||
|
segmentList = []
|
||
|
zoneList = []
|
||
|
|
||
|
#-------------------------------------------------------------------
|
||
|
# Double check to be sure Cuba and Hispaniola are not part of
|
||
|
# the mainland segment lists
|
||
|
|
||
|
for curId in hazardAreaDict[hazardKey]["SEGMENTS"]:
|
||
|
|
||
|
# If this is a Cuba or Hispaniola code
|
||
|
if curId[:3] in segmentDict:
|
||
|
|
||
|
## print "Found segment -> curId =", curId
|
||
|
# Add this identifier to the dictionary
|
||
|
tempList = segmentDict[curId[:3]]
|
||
|
|
||
|
# If this identifier is not already in the list
|
||
|
if curId not in tempList:
|
||
|
tempList.append(curId)
|
||
|
|
||
|
# Store the updated list
|
||
|
segmentDict[curId[:3]] = tempList
|
||
|
|
||
|
# Otherwise,
|
||
|
elif curId not in segmentList:
|
||
|
|
||
|
segmentList.append(curId)
|
||
|
|
||
|
#-------------------------------------------------------------------
|
||
|
# Double check to be sure Cuba and Hispaniola are not part of
|
||
|
# the mainland zone lists
|
||
|
|
||
|
for curId in hazardAreaDict[hazardKey]["ZONES"]:
|
||
|
|
||
|
# If this is a Cuba or Hispaniola code
|
||
|
if curId[:3] in segmentDict:
|
||
|
|
||
|
## print "Found zone -> curId =", curId
|
||
|
# Add this identifier to the dictionary
|
||
|
tempList = segmentDict[curId[:3]]
|
||
|
|
||
|
# If this identifier is not already in the list
|
||
|
if curId not in tempList:
|
||
|
tempList.append(curId)
|
||
|
|
||
|
# Store the updated list
|
||
|
segmentDict[curId[:3]] = tempList
|
||
|
|
||
|
# Otherwise,
|
||
|
elif curId not in segmentList:
|
||
|
|
||
|
zoneList.append(curId)
|
||
|
|
||
|
#-------------------------------------------------------------------
|
||
|
# Make a separate segment for Cuba
|
||
|
|
||
|
if len(segmentDict["CUC"]) > 0:
|
||
|
|
||
|
sortedZones = segmentDict["CUC"]
|
||
|
sortedZones.sort()
|
||
|
|
||
|
record = ([], # Segments
|
||
|
[], # UGC zones
|
||
|
sortedZones, # Zones
|
||
|
[], # Islands
|
||
|
[]) # Water
|
||
|
|
||
|
# If we do not already have a record for these particular zones
|
||
|
if record not in finalSegmentList:
|
||
|
|
||
|
print("\n\nCuba record", record)
|
||
|
|
||
|
# Add it now
|
||
|
finalSegmentList.append(record)
|
||
|
|
||
|
#-------------------------------------------------------------------
|
||
|
# Make a separate segment for Hispaniola
|
||
|
|
||
|
if len(segmentDict["HTC"]) > 0 or len(segmentDict["DOC"]) > 0:
|
||
|
|
||
|
# Get a compined list of zones
|
||
|
combinedZones = segmentDict["HTC"] + segmentDict["DOC"]
|
||
|
|
||
|
# Sort these zones
|
||
|
combinedZones.sort(key=self._sortBreakpoints)
|
||
|
|
||
|
record = ([], # Segments
|
||
|
[], # UGC zones
|
||
|
combinedZones, # Zones
|
||
|
[], # Islands
|
||
|
[]) # Water
|
||
|
|
||
|
# If we do not already have a record for these particular zones
|
||
|
if record not in finalSegmentList:
|
||
|
|
||
|
print("\n\nHispaniola record", record)
|
||
|
|
||
|
# Add it now
|
||
|
finalSegmentList.append(record)
|
||
|
|
||
|
## #-------------------------------------------------------------------
|
||
|
## # Make a separate segment for the United States
|
||
|
##
|
||
|
## if len(segmentDict["USC"]) > 0:
|
||
|
##
|
||
|
## sortedZones = segmentDict["USC"]
|
||
|
## sortedZones.sort()
|
||
|
##
|
||
|
## record = ([], # Segments
|
||
|
## [], # UGC zones
|
||
|
## sortedZones, # Zones
|
||
|
## [], # Islands
|
||
|
## []) # Water
|
||
|
##
|
||
|
## # If we do not already have a record for these particular zones
|
||
|
## if record not in finalSegmentList:
|
||
|
##
|
||
|
## print "\n\nCuba record", record
|
||
|
##
|
||
|
## # Add it now
|
||
|
## finalSegmentList.append(record)
|
||
|
|
||
|
#-------------------------------------------------------------------
|
||
|
# If we have filtered segments or zones
|
||
|
|
||
|
if len(segmentList) != 0 and \
|
||
|
len(segmentList) != len(hazardAreaDict[hazardKey]["SEGMENTS"]):
|
||
|
|
||
|
# Update the record for this segment
|
||
|
curSegments = segmentList
|
||
|
|
||
|
# Otherwise, keep segments we already have
|
||
|
else:
|
||
|
curSegments = hazardAreaDict[hazardKey]["SEGMENTS"]
|
||
|
|
||
|
if len(zoneList) != 0 and \
|
||
|
len(zoneList) != len(hazardAreaDict[hazardKey]["ZONES"]):
|
||
|
|
||
|
# Update the record for this segment
|
||
|
curZones = zoneList
|
||
|
|
||
|
# Otherwise, keep segments we already have
|
||
|
else:
|
||
|
curZones = hazardAreaDict[hazardKey]["ZONES"]
|
||
|
|
||
|
|
||
|
#-------------------------------------------------------------------
|
||
|
# Create a new segment for each island which was found - if we
|
||
|
# need to
|
||
|
|
||
|
islandList = []
|
||
|
|
||
|
# USA TCV
|
||
|
if UStcv:
|
||
|
|
||
|
# Make a new record for this island
|
||
|
record = ([], # Segments
|
||
|
[hazardAreaDict[hazardKey]["ISLANDS"]], # UGC zones
|
||
|
[], # Zones
|
||
|
[hazardAreaDict[hazardKey]["ISLANDS"]], # Islands
|
||
|
[]) # Water
|
||
|
|
||
|
# If we do not already have a record for this island
|
||
|
if record not in finalSegmentList:
|
||
|
|
||
|
print("\n\nUSA Island record -> %s" % (record))
|
||
|
|
||
|
# Add it now
|
||
|
finalSegmentList.append(record)
|
||
|
|
||
|
# International TCV
|
||
|
else:
|
||
|
|
||
|
for island in hazardAreaDict[hazardKey]["ISLANDS"]:
|
||
|
|
||
|
# Make a new record for this island
|
||
|
record = ([], # Segments
|
||
|
[], # UGC zones
|
||
|
[island], # Zones
|
||
|
[island], # Islands
|
||
|
[]) # Water
|
||
|
|
||
|
# If we do not already have a record for this island
|
||
|
if record not in finalSegmentList:
|
||
|
|
||
|
# print "\n\nIntl Island record -> %s" % (record)
|
||
|
|
||
|
# Add it now
|
||
|
finalSegmentList.append(record)
|
||
|
|
||
|
#===================================================================
|
||
|
# Make a record to group all the various areas associated with a
|
||
|
# particular hazard
|
||
|
|
||
|
record = (curSegments,
|
||
|
hazardAreaDict[hazardKey]["UGCZONES"],
|
||
|
curZones,
|
||
|
hazardAreaDict[hazardKey]["ISLANDS"],
|
||
|
hazardAreaDict[hazardKey]["WATER"])
|
||
|
|
||
|
# If we do not already have a record for these particular zones
|
||
|
if record not in finalSegmentList:
|
||
|
|
||
|
# Add it now
|
||
|
finalSegmentList.append(record)
|
||
|
|
||
|
print("\n\n", "*"*90)
|
||
|
print("finalSegmentList =", pp.pformat(finalSegmentList))
|
||
|
|
||
|
# Return the final organized list
|
||
|
return finalSegmentList
|
||
|
|
||
|
|
||
|
#===========================================================================
|
||
|
# Define a method to find missing zone codes for breakpoint segments,
|
||
|
# islands and water.
|
||
|
|
||
|
def _findZoneCodes(self, areaList):
|
||
|
|
||
|
# Get ready to find the zone codes
|
||
|
ugcZones = []
|
||
|
zones = []
|
||
|
|
||
|
# Look at each area in the list
|
||
|
for areaId in areaList:
|
||
|
|
||
|
# If there is an entry in the TropicalAreaDictionary for this area
|
||
|
if areaId in self._tropicalAreaDict:
|
||
|
|
||
|
# Get the 'ugcCode' for this area
|
||
|
ugcCode = self._tropicalAreaDict[areaId]["ugcCode"]
|
||
|
|
||
|
# If this is a generic zone code
|
||
|
if len(ugcCode) > 3 and ugcCode[2] == "C":
|
||
|
|
||
|
# If we do not already have it in the zone list
|
||
|
if ugcCode not in zones:
|
||
|
|
||
|
# Add it now
|
||
|
zones.append(ugcCode)
|
||
|
|
||
|
# Otherwise, this must be a UGC code
|
||
|
else:
|
||
|
|
||
|
# See if we need to expand it
|
||
|
if len(ugcCode) > 7:
|
||
|
|
||
|
# Expand the UGC code into individual zones
|
||
|
expandUgcList = self.expandComplexUgc(ugcCode)
|
||
|
|
||
|
# Add each UGC code to the list - if not already there
|
||
|
for ugc in expandUgcList:
|
||
|
|
||
|
if ugc not in ugcZones:
|
||
|
ugcZones.append(ugc)
|
||
|
|
||
|
# Otherwise, just add this UGC zone if it is not already there
|
||
|
elif ugcCode not in ugcZones:
|
||
|
ugcZones.append(ugc)
|
||
|
|
||
|
# Sort these lists as needed
|
||
|
if len(ugcZones) > 1:
|
||
|
ugcZones.sort(key=self._sortBreakpoints)
|
||
|
|
||
|
if len(zones) > 1:
|
||
|
zones.sort(key=self._sortBreakpoints)
|
||
|
|
||
|
if len(ugcZones) == 0:
|
||
|
return "There are no areas in this TCV"
|
||
|
|
||
|
# Return the zones we found
|
||
|
return (ugcZones, zones)
|
||
|
|
||
|
|
||
|
#===============================================================================
|
||
|
# Code to process StormInfo files -
|
||
|
|
||
|
# same as HLSTCV_Common
|
||
|
def _synchronizeAdvisories(self):
|
||
|
# Retrieving a directory causes synching to occur.
|
||
|
# This code can throw an exception but don't catch it
|
||
|
# so that forecasters can be made aware of the issue.
|
||
|
file = LocalizationSupport.getLocalizationFile(
|
||
|
LocalizationSupport.CAVE_STATIC,
|
||
|
LocalizationSupport.SITE, self._site,
|
||
|
self._getAdvisoryPath()).getFile()
|
||
|
|
||
|
return file
|
||
|
|
||
|
# same as HLSTCV_Common
|
||
|
def _getLocalAdvisoryDirectoryPath(self):
|
||
|
file = self._synchronizeAdvisories()
|
||
|
path = file.getPath()
|
||
|
print("\n\nLooking for JSON files in '%s'" % (path))
|
||
|
|
||
|
try:
|
||
|
os.makedirs(path)
|
||
|
except OSError as exception:
|
||
|
if exception.errno != errno.EEXIST:
|
||
|
raise
|
||
|
|
||
|
return path
|
||
|
|
||
|
def _getStormAdvisoryNames(self):
|
||
|
advisoryDirectoryPath = self._getLocalAdvisoryDirectoryPath()
|
||
|
filenames = os.listdir(advisoryDirectoryPath)
|
||
|
allAdvisories = [filename for filename in filenames if filename[-5:] == ".json"]
|
||
|
|
||
|
stormAdvisories = [filename for filename in allAdvisories if filename[:2] == "AT"]
|
||
|
|
||
|
return stormAdvisories
|
||
|
|
||
|
def _loadAdvisory(self, advisoryName):
|
||
|
self._synchronizeAdvisories()
|
||
|
fileName = self._getAdvisoryFilename(advisoryName)
|
||
|
|
||
|
try:
|
||
|
pythonDict = JsonSupport.loadFromJson(LocalizationSupport.CAVE_STATIC,
|
||
|
self._site, fileName)
|
||
|
|
||
|
statFileName = os.path.join(os.environ["HOME"], "caveData", "etc",
|
||
|
"site", self._site, fileName)
|
||
|
lastModified = os.stat(statFileName).st_mtime
|
||
|
pythonDict["lastModified"] = lastModified
|
||
|
|
||
|
print("File contents for %s:" % (fileName))
|
||
|
print(pp.pformat(pythonDict))
|
||
|
|
||
|
return pythonDict
|
||
|
|
||
|
except Exception as e:
|
||
|
print("Load Exception for %s : %s" % (fileName, e))
|
||
|
return None
|
||
|
|
||
|
def _saveAdvisory(self, advisoryName, advisoryDict):
|
||
|
self._synchronizeAdvisories()
|
||
|
fileName = self._getAdvisoryFilename(advisoryName)
|
||
|
|
||
|
print("Saving %s to %s" % (advisoryName, fileName))
|
||
|
print("advisoryDict: %s" % (pp.pformat(advisoryDict)))
|
||
|
|
||
|
try:
|
||
|
JsonSupport.saveToJson(LocalizationSupport.CAVE_STATIC,
|
||
|
self._site, fileName, advisoryDict)
|
||
|
# os.system('chmod 664 %s' % (fileName))
|
||
|
except Exception as e:
|
||
|
print("Save Exception for %s : %s" % (fileName, e))
|
||
|
else: # No exceptions occurred
|
||
|
print("Wrote file contents for: %s" % (fileName))
|
||
|
|
||
|
# Purposely allow this to throw
|
||
|
self._synchronizeAdvisories()
|
||
|
|
||
|
def _deleteAdvisory(self):
|
||
|
|
||
|
# Sync the CAVE localization store
|
||
|
self._synchronizeAdvisories()
|
||
|
fileName = self._getAdvisoryFilename(self._advisoryFileName)
|
||
|
|
||
|
print("\n\nDeleting -> " + fileName)
|
||
|
|
||
|
try:
|
||
|
LocalizationSupport.deleteFile(LocalizationSupport.CAVE_STATIC,
|
||
|
LocalizationSupport.SITE, self._site,
|
||
|
fileName)
|
||
|
|
||
|
except Exception as e:
|
||
|
print("Delete Exception for %s : %s" % (fileName, e))
|
||
|
return None
|
||
|
|
||
|
|
||
|
# same as HLSTCV_Common
|
||
|
def _getAdvisoryPath(self):
|
||
|
dataMgr = self._argDict["dataMgr"]
|
||
|
gfeMode = dataMgr.getOpMode().name()
|
||
|
|
||
|
if gfeMode == "PRACTICE":
|
||
|
return os.path.join("gfe", "tcvAdvisories", "practice")
|
||
|
else:
|
||
|
return os.path.join("gfe", "tcvAdvisories")
|
||
|
|
||
|
|
||
|
def _getAdvisoryFilename(self, advisoryName):
|
||
|
advisoryFilename = os.path.join(self._getAdvisoryPath(), advisoryName)
|
||
|
|
||
|
if not advisoryFilename.endswith(".json"):
|
||
|
advisoryFilename += ".json"
|
||
|
|
||
|
return advisoryFilename
|