From c98a6a651c40decaeea7407d0958b714d84d1d5d Mon Sep 17 00:00:00 2001 From: Mark Oberfield Date: Fri, 10 Sep 2021 12:35:33 -0400 Subject: [PATCH] IWXXM 2021-2 release (#26) * Mostly due to changes of the 2021-2 schema release. TAF.py - minor enhancement to process <12 hr TAFs common/Encoder.py - changes due to processing <12 hr TAFs common/xmlConfig.py - update release variables from 3.0 to 2021-2 swaEncoder.py - insert xsi:nil = true logic tcaEncoder.py - adding TC intensity change element, revised logic for missing forecast maxWindSpeed and position, insert xsi:nil = true logic vaaEncoder.py - insert xsi:nil = true logic * Added new assertions for TCA product. Removed hardwired IWXXM URI in all tests. * Updated README text and demo1.py script to include <12hr TAFs --- README.md | 12 +- demo/demo1.py | 2 +- gifts/TAF.py | 4 +- gifts/common/Encoder.py | 4 +- gifts/common/xmlConfig.py | 6 +- gifts/swaEncoder.py | 2 + gifts/tcaEncoder.py | 47 +++-- gifts/vaaEncoder.py | 18 +- tests/test_metar_encoding.py | 367 ++++++++++++++++++----------------- tests/test_taf_encoding.py | 2 +- tests/test_tca_encoding.py | 16 +- tests/test_vaa_encoding.py | 2 +- 12 files changed, 261 insertions(+), 221 deletions(-) diff --git a/README.md b/README.md index fcb87d2..9c6676b 100644 --- a/README.md +++ b/README.md @@ -8,19 +8,21 @@ This repository is a scientific product and is not official communication of the ------------------------------------------------------------------------------- # Generate IWXXM From TAC -This repository hosts software provided by the United States National Weather Service's [Meteorological Development Laboratory](https://vlab.ncep.noaa.gov/web/mdl) (MDL) that transforms Annex 3 Traditional Alphanumeric Code (TAC) forms into IWXXM v3.0 format. +This repository hosts software provided by the United States National Weather Service's [Meteorological Development Laboratory](https://vlab.ncep.noaa.gov/web/mdl) (MDL) that transforms Annex 3 Traditional Alphanumeric Code (TAC) forms into IWXXM format. The ICAO Meteorological Information Exchange Model (IWXXM) is a format for reporting weather information in eXtensible Markup Language (XML). The IWXXM XML schemas, developed and hosted by the WMO in association with ICAO, are used to encode aviation products described in the Meteorological Service for International Air Navigation, Annex 3 to the Convention on International Civil Aviation. -Version 3.0 of the IWXXM XML schemas encode METAR, SPECI, TAF, SIGMET, AIRMET, Volcanic Ash Advisory, Tropical Cyclone Advisory, and Space Weather Advisory reports. +The IWXXM XML schemas encode METAR, SPECI, TAF, SIGMET, AIRMET, Volcanic Ash Advisory, Tropical Cyclone Advisory, and Space Weather Advisory reports and Significant Weather (SIGWX). -This repository contains software, written exclusively in the Python language, that transforms the current TAC form of these reports into IWXXM XML documents. The advantage of the Python language is its popularity, rich functionality, and wide availability under many different computer operating systems. +This repository contains software, written exclusively in the Python language, that transforms the data in the current TAC form of these reports into IWXXM XML documents. The advantage of the Python language is its popularity, rich functionality, and wide availability under many different computer operating systems. ## Introduction -IWXXM v3.0 will become a WMO standard on 5 November 2020. Met Watch Offices shall disseminate METAR, SPECI, TAF, AIRMET, SIGMET products and Tropical Cyclone, Volcanic Ash and Space Weather Advisories in IWXXM form on that date. +IWXXM became a ICAO standard on 5 November 2020. Various Met Watch Offices shall disseminate METAR, SPECI, TAF, AIRMET, SIGMET products and Tropical Cyclone, Volcanic Ash and Space Weather Advisories in IWXXM form after that date. As XML, and creating XML documents, may be unfamiliar technology to those without an IT background, MDL is providing software to assist those in creating the new XML documents based on IWXXM v3.0 schemas. +It should be understood that the software provided here is a short-term solution as TAC forms of these products will cease to be a standard and no longer disseminated by 2029. + ## Prequisites This software is written entirely in the Python language. Python interpreter version 2.7 or better is required. @@ -90,7 +92,7 @@ The Encoder class requires that the input file contain one WMO AHL line, appropr S(A|P)[A-Z][A-Z]\d\d\s+[A-Z]{4}\s+\d{6}(\s+[ACR]{2}[A-Z])? # for METAR/SPECI FN\w\w\d\d\s+[A-Z]{4}\s+\d{6}(\s+[ACR]{2}[A-Z])? # Space Weather Advisories FK\w\w\d\d\s+[A-Z]{4}\s+\d{6}(\s+[ACR]{2}[A-Z])? # Tropical Cyclone Advisory - FT\w\w\d\d\s+[A-Z]{4}\s+\d{6}(\s+[ACR]{2}[A-Z])? # TAF + F(C|T)\w\w\d\d\s+[A-Z]{4}\s+\d{6}(\s+[ACR]{2}[A-Z])? # TAF FV\w\w\d\d\s+[A-Z]{4}\s+\d{6}(\s+[ACR]{2}[A-Z])? # Volcanic Ash Advisory And for capturing the individual TAC forms: diff --git a/demo/demo1.py b/demo/demo1.py index b1a7d37..1289267 100755 --- a/demo/demo1.py +++ b/demo/demo1.py @@ -103,7 +103,7 @@ def __init__(self): gifts.METAR.Encoder(aerodromes))) self.encoders.append((re.compile(r'^FN[A-Z][A-Z]\d\d\s+[A-Z]{4}\s+\d{6}', re.MULTILINE), gifts.SWA.Encoder())) - self.encoders.append((re.compile(r'^FT[A-Z][A-Z]\d\d\s+[A-Z]{4}\s+\d{6}', re.MULTILINE), + self.encoders.append((re.compile(r'^F(C|T)[A-Z][A-Z]\d\d\s+[A-Z]{4}\s+\d{6}', re.MULTILINE), gifts.TAF.Encoder(aerodromes))) self.encoders.append((re.compile(r'FK\w\w\d\d\s+[A-Z]{4}\s+\d{6}', re.MULTILINE), gifts.TCA.Encoder())) self.encoders.append((re.compile(r'FV\w\w\d\d\s+[A-Z]{4}\s+\d{6}', re.MULTILINE), gifts.VAA.Encoder())) diff --git a/gifts/TAF.py b/gifts/TAF.py index 2cdc35a..892e971 100644 --- a/gifts/TAF.py +++ b/gifts/TAF.py @@ -24,9 +24,9 @@ def __init__(self, geoLocationsDB): super(Encoder, self).__init__() - self.re_AHL = re.compile(r'FT(?P\w\w\d\d)\s+(?P\w{4})\s+(?P\d{6})(\s+(?P[ACR]{2}[A-Z]))?') # noqa:501 + self.re_AHL = re.compile(r'F(?P(C|T)\w\w\d\d)\s+(?P\w{4})\s+(?P\d{6})(\s+(?P[ACR]{2}[A-Z]))?') # noqa:501 self.re_TAC = re.compile(r'^TAF(?:\s+(?:AMD|COR|CC[A-Z]|RTD))?\s+[A-Z]{4}.+?=', (re.MULTILINE | re.DOTALL)) - self.T1T2 = "LT" + self.T1T2 = "L" self._Logger = logging.getLogger(__name__) self.decoder = tafDecoder.Decoder() diff --git a/gifts/common/Encoder.py b/gifts/common/Encoder.py index 544d964..71efb8f 100644 --- a/gifts/common/Encoder.py +++ b/gifts/common/Encoder.py @@ -45,11 +45,11 @@ def encode(self, text, receiptTime=None, **attrs): decodedTAC['translatedBulletinReceptionTime'] = decodedTAC['translationTime'] elif 'err_msg' in decodedTAC: - if self.T1T2 == 'L' or self.T1T2 == 'LT': + if self.T1T2 == 'L': try: self._Logger.warning('Will not create IWXXM document for %s' % decodedTAC['ident']['str']) except KeyError: - self._Logger.warning('Bad observation, could not determine ICAO ID: %s' % tac) + self._Logger.warning('Bad observation or TAF: Could not determine ICAO ID: %s' % tac) else: self._Logger.warning('Will not create IWXXM advisory because of a decoding error.') diff --git a/gifts/common/xmlConfig.py b/gifts/common/xmlConfig.py index 173fc8b..4b1cd45 100644 --- a/gifts/common/xmlConfig.py +++ b/gifts/common/xmlConfig.py @@ -33,11 +33,11 @@ # ----------------------------------------------------------------------------------- # # IWXXM versioning -_iwxxm = '3.0' -_release = '3.0' +_iwxxm = '2021-2' +_release = '2021-2' # IWXXM_URI = 'http://icao.int/iwxxm/%s' % _iwxxm -IWXXM_URL = 'http://schemas.wmo.int/iwxxm/%s/iwxxm.xsd' % _release +IWXXM_URL = 'https://schemas.wmo.int/iwxxm/%s/iwxxm.xsd' % _release # # Path to file containing codes obtained from WMO Code Registry in RDF/XML format. # diff --git a/gifts/swaEncoder.py b/gifts/swaEncoder.py index 8651204..b6bf052 100644 --- a/gifts/swaEncoder.py +++ b/gifts/swaEncoder.py @@ -312,6 +312,8 @@ def postContent(self): indent = ET.SubElement(self.XMLDocument, 'remarks') if self.decodedTAC['remarks'] == 'NIL': indent.set('nilReason', self.codes[des.NIL][des.NA][0]) + indent.set('xsi:nil', 'true') + else: indent.text = self.decodedTAC['remarks'] diff --git a/gifts/tcaEncoder.py b/gifts/tcaEncoder.py index caae66e..ee878f1 100644 --- a/gifts/tcaEncoder.py +++ b/gifts/tcaEncoder.py @@ -164,21 +164,22 @@ def result(self, parent, token, fhr): if fhr == '0': self.doObservedConditions(ET.SubElement(parent, 'observation'), token) else: - indent = ET.SubElement(parent, 'forecast') - if 'windSpeed' in token: - indent1 = ET.Element('TropicalCycloneForecastConditions') - indent1.set('gml:id', deu.getUUID()) - self.itime(indent1, token['dtg']) - self.cyclonePosition(indent1, token) + indent = ET.SubElement(parent, 'forecast') + indent1 = ET.SubElement(indent, 'TropicalCycloneForecastConditions') + indent1.set('gml:id', deu.getUUID()) + self.itime(indent1, token['dtg']) + self.cyclonePosition(indent1, token) + try: indent2 = ET.SubElement(indent1, 'maximumSurfaceWindSpeed') - indent2.set('uom', token['windSpeed']['uom']) indent2.text = token['windSpeed']['value'] - indent.append(indent1) + indent2.set('uom', token['windSpeed']['uom']) - else: - indent.set('nilReason', self.codes[des.NIL][des.NOOPRSIG][0]) + except KeyError: + indent2.set('uom', 'N/A') + indent2.set('nilReason', self.codes[des.NIL][des.NOOPRSIG][0]) + indent2.set('xsi:nil', 'true') def itime(self, parent, dtg): @@ -191,18 +192,19 @@ def itime(self, parent, dtg): def cyclonePosition(self, parent, token): indent = ET.SubElement(parent, 'tropicalCyclonePosition') - if 'position' in token: - - indent1 = ET.SubElement(indent, 'gml:Point') - indent1.set('gml:id', deu.getUUID()) - indent1.set('axisLabels', des.axisLabels) - indent1.set('srsName', des.srsName) - indent1.set('srsDimension', des.srsDimension) - indent2 = ET.SubElement(indent1, 'gml:pos') + indent1 = ET.Element('gml:Point') + indent1.set('gml:id', deu.getUUID()) + indent1.set('axisLabels', des.axisLabels) + indent1.set('srsName', des.srsName) + indent1.set('srsDimension', des.srsDimension) + indent2 = ET.SubElement(indent1, 'gml:pos') + try: indent2.text = token['position'] + indent.append(indent1) - else: - indent.set('nilReason', self.codes[des.NIL][des.MSSG][0]) + except KeyError: + indent.set('nilReason', self.codes[des.NIL][des.NA][0]) + indent.set('xsi:nil', 'true') def doObservedConditions(self, parent, token): @@ -228,6 +230,9 @@ def doObservedConditions(self, parent, token): indent1.text = token['movement']['spd'] indent1.set('uom', token['movement']['uom']) + indent1 = ET.SubElement(indent, 'intensityChange') + indent1.text = {'INTSF': 'INTENSIFY', 'WKN': 'WEAKEN'}.get(self.decodedTAC['intstChange'], 'NO_CHANGE') + indent1 = ET.SubElement(indent, 'centralPressure') indent1.text = self.decodedTAC['minimumPressure']['value'] indent1.set('uom', self.decodedTAC['minimumPressure']['uom']) @@ -307,6 +312,8 @@ def postContent(self): indent = ET.SubElement(self.XMLDocument, 'remarks') if self.decodedTAC['remarks'] == 'NIL': indent.set('nilReason', self.codes[des.NIL][des.NA][0]) + indent.set('xsi:nil', 'true') + else: indent.text = self.decodedTAC['remarks'] diff --git a/gifts/vaaEncoder.py b/gifts/vaaEncoder.py index 3e12899..ae5ceb8 100644 --- a/gifts/vaaEncoder.py +++ b/gifts/vaaEncoder.py @@ -115,8 +115,10 @@ def preamble(self): child = ET.SubElement(self.XMLDocument, 'stateOrRegion') if 'UNKNOWN' not in self.decodedTAC['region']: child.text = self.decodedTAC['region'] + else: child.set('nilReason', self.codes[des.NIL][des.UNKNWN][0]) + child.set('xsi:nil', 'true') child = ET.SubElement(self.XMLDocument, 'summitElevation') if self.decodedTAC['summit']['elevation'].isdigit(): @@ -125,8 +127,10 @@ def preamble(self): elif 'SFC' in self.decodedTAC['summit']['elevation']: child.set('nilReason', self.codes[des.NIL][des.NA][0]) + child.set('xsi:nil', 'true') else: child.set('nilReason', self.codes[des.NIL][des.UNKNWN][0]) + child.set('xsi:nil', 'true') child = ET.SubElement(self.XMLDocument, 'advisoryNumber') child.text = self.decodedTAC['advisoryNumber'] @@ -138,10 +142,16 @@ def preamble(self): child = ET.Element('colourCode') if 'GIVEN' in self.decodedTAC['colourCode']: child.set('nilReason', self.codes[des.NIL][des.WTHLD][0]) + child.set('xsi:nil', 'true') + elif self.decodedTAC['colourCode'] == 'UNKNOWN': child.set('nilReason', self.codes[des.NIL][des.UNKNWN][0]) + child.set('xsi:nil', 'true') + elif self.decodedTAC['colourCode'] == 'NIL': child.set('nilReason', self.codes[des.NIL][des.MSSG][0]) + child.set('xsi:nil', 'true') + else: child.set('xlink:href', self.codes[des.COLOUR_CODES][self.decodedTAC['colourCode']][0]) @@ -153,6 +163,8 @@ def preamble(self): child = ET.SubElement(self.XMLDocument, 'eruptionDetails') if 'UNKNOWN' in self.decodedTAC['details']: child.set('nilReason', self.codes[des.NIL][des.UNKNWN][0]) + child.set('xsi:nil', 'true') + else: child.text = self.decodedTAC['details'] @@ -202,6 +214,8 @@ def volcano(self, parent): indent2 = ET.SubElement(indent1, 'position') if 'UNKNOWN' in self.decodedTAC['volcanoLocation']: indent2.set('nilReason', self.codes[des.NIL][des.UNKNWN][0]) + indent2.set('xsi:nil', 'true') + else: indent3 = ET.SubElement(indent2, 'gml:Point') indent3.set('axisLabels', des.axisLabels) @@ -394,8 +408,10 @@ def airspaceVolume(self, parent, lyr): def postContent(self): indent = ET.SubElement(self.XMLDocument, 'remarks') - if self.decodedTAC['remarks'] == 'NIL': + if self.decodedTAC['remarks'] == 'NIL': indent.set('nilReason', self.codes[des.NIL][des.NA][0]) + indent.set('xsi:nil', 'true') + else: indent.text = self.decodedTAC['remarks'] diff --git a/tests/test_metar_encoding.py b/tests/test_metar_encoding.py index 4f00e1b..904e5c2 100644 --- a/tests/test_metar_encoding.py +++ b/tests/test_metar_encoding.py @@ -13,7 +13,8 @@ codes = deu.parseCodeRegistryTables(des.CodesFilePath, reqCodes) aixm = './/*{http://www.aixm.aero/schema/5.1.1}' -iwxxm = './/*{http://icao.int/iwxxm/3.0}' +iwxxm = '{%s}' % des.IWXXM_URI +find_iwxxm = './/*%s' % iwxxm xhref = '{http://www.w3.org/1999/xlink}href' xtitle = '{http://www.w3.org/1999/xlink}title' @@ -213,7 +214,7 @@ def test_missingMandatories(): # Non-domestic observations are done first for element in ['surfaceWind', 'visibility', 'layer', 'presentWeather', 'airTemperature', 'dewpointTemperature', 'qnh']: - fullname = '%s%s' % (iwxxm, element) + fullname = '%s%s' % (find_iwxxm, element) assert tree.find(fullname).get('nilReason') == notObservable[0] @@ -237,12 +238,12 @@ def test_windComponents(): assert result.get('translationFailedTAC') is None tree = ET.XML(ET.tostring(result)) - assert tree.find('%sAerodromeSurfaceWind' % iwxxm).get('variableWindDirection') == 'false' - assert tree.find('%smeanWindDirection' % iwxxm).get('nilReason') == notObservable[0] - assert tree.find('%smeanWindDirection' % iwxxm).get('uom') == 'N/A' - assert tree.find('%smeanWindSpeed' % iwxxm).text == '10' - assert tree.find('%smeanWindSpeed' % iwxxm).get('uom') == '[kn_i]' - assert tree.find('%swindSpeedGust' % iwxxm) is None + assert tree.find('%sAerodromeSurfaceWind' % find_iwxxm).get('variableWindDirection') == 'false' + assert tree.find('%smeanWindDirection' % find_iwxxm).get('nilReason') == notObservable[0] + assert tree.find('%smeanWindDirection' % find_iwxxm).get('uom') == 'N/A' + assert tree.find('%smeanWindSpeed' % find_iwxxm).text == '10' + assert tree.find('%smeanWindSpeed' % find_iwxxm).get('uom') == '[kn_i]' + assert tree.find('%swindSpeedGust' % find_iwxxm) is None # METAR BIAR 290000Z 260//KT @@ -250,12 +251,12 @@ def test_windComponents(): assert result.get('translationFailedTAC') is None tree = ET.XML(ET.tostring(result)) - assert tree.find('%sAerodromeSurfaceWind' % iwxxm).get('variableWindDirection') == 'false' - assert tree.find('%smeanWindDirection' % iwxxm).text == '260' - assert tree.find('%smeanWindDirection' % iwxxm).get('uom') == 'deg' - assert tree.find('%smeanWindSpeed' % iwxxm).get('nilReason') == notObservable[0] - assert tree.find('%smeanWindSpeed' % iwxxm).get('uom') == 'N/A' - assert tree.find('%swindSpeedGust' % iwxxm) is None + assert tree.find('%sAerodromeSurfaceWind' % find_iwxxm).get('variableWindDirection') == 'false' + assert tree.find('%smeanWindDirection' % find_iwxxm).text == '260' + assert tree.find('%smeanWindDirection' % find_iwxxm).get('uom') == 'deg' + assert tree.find('%smeanWindSpeed' % find_iwxxm).get('nilReason') == notObservable[0] + assert tree.find('%smeanWindSpeed' % find_iwxxm).get('uom') == 'N/A' + assert tree.find('%swindSpeedGust' % find_iwxxm) is None # METAR BIAR 290000Z VRB03KT @@ -263,10 +264,10 @@ def test_windComponents(): assert result.get('translationFailedTAC') is None tree = ET.XML(ET.tostring(result)) - assert tree.find('%sAerodromeSurfaceWind' % iwxxm).get('variableWindDirection') == 'true' - assert tree.find('%smeanWindDirection' % iwxxm) is None - assert tree.find('%smeanWindSpeed' % iwxxm).text == '3' - assert tree.find('%swindSpeedGust' % iwxxm) is None + assert tree.find('%sAerodromeSurfaceWind' % find_iwxxm).get('variableWindDirection') == 'true' + assert tree.find('%smeanWindDirection' % find_iwxxm) is None + assert tree.find('%smeanWindSpeed' % find_iwxxm).text == '3' + assert tree.find('%swindSpeedGust' % find_iwxxm) is None # METAR BIAR 290000Z VRB03G50KT @@ -274,11 +275,11 @@ def test_windComponents(): assert result.get('translationFailedTAC') is None tree = ET.XML(ET.tostring(result)) - assert tree.find('%sAerodromeSurfaceWind' % iwxxm).get('variableWindDirection') == 'true' - assert tree.find('%smeanWindDirection' % iwxxm) is None - assert tree.find('%smeanWindSpeed' % iwxxm).text == '3' - assert tree.find('%swindGustSpeed' % iwxxm).text == '50' - assert tree.find('%swindGustSpeed' % iwxxm).get('uom') == '[kn_i]' + assert tree.find('%sAerodromeSurfaceWind' % find_iwxxm).get('variableWindDirection') == 'true' + assert tree.find('%smeanWindDirection' % find_iwxxm) is None + assert tree.find('%smeanWindSpeed' % find_iwxxm).text == '3' + assert tree.find('%swindGustSpeed' % find_iwxxm).text == '50' + assert tree.find('%swindGustSpeed' % find_iwxxm).get('uom') == '[kn_i]' # METAR BIAR 290000Z 260P10KT @@ -286,10 +287,10 @@ def test_windComponents(): assert result.get('translationFailedTAC') is None tree = ET.XML(ET.tostring(result)) - assert tree.find('%smeanWindDirection' % iwxxm).text == '260' - assert tree.find('%smeanWindSpeed' % iwxxm).text == '10' - assert tree.find('%smeanWindSpeedOperator' % iwxxm).text == 'ABOVE' - assert tree.find('%swindGustSpeed' % iwxxm) is None + assert tree.find('%smeanWindDirection' % find_iwxxm).text == '260' + assert tree.find('%smeanWindSpeed' % find_iwxxm).text == '10' + assert tree.find('%smeanWindSpeedOperator' % find_iwxxm).text == 'ABOVE' + assert tree.find('%swindGustSpeed' % find_iwxxm) is None # METAR BIAR 290000Z 260P10G20KT @@ -297,10 +298,10 @@ def test_windComponents(): assert result.get('translationFailedTAC') is None tree = ET.XML(ET.tostring(result)) - assert tree.find('%smeanWindDirection' % iwxxm).text == '260' - assert tree.find('%smeanWindSpeed' % iwxxm).text == '10' - assert tree.find('%smeanWindSpeedOperator' % iwxxm).text == 'ABOVE' - assert tree.find('%swindGustSpeed' % iwxxm).text == '20' + assert tree.find('%smeanWindDirection' % find_iwxxm).text == '260' + assert tree.find('%smeanWindSpeed' % find_iwxxm).text == '10' + assert tree.find('%smeanWindSpeedOperator' % find_iwxxm).text == 'ABOVE' + assert tree.find('%swindGustSpeed' % find_iwxxm).text == '20' # METAR BIAR 290000Z 26010GP20KT @@ -308,10 +309,10 @@ def test_windComponents(): assert result.get('translationFailedTAC') is None tree = ET.XML(ET.tostring(result)) - assert tree.find('%smeanWindDirection' % iwxxm).text == '260' - assert tree.find('%smeanWindSpeed' % iwxxm).text == '10' - assert tree.find('%swindGustSpeed' % iwxxm).text == '20' - assert tree.find('%swindGustSpeedOperator' % iwxxm).text == 'ABOVE' + assert tree.find('%smeanWindDirection' % find_iwxxm).text == '260' + assert tree.find('%smeanWindSpeed' % find_iwxxm).text == '10' + assert tree.find('%swindGustSpeed' % find_iwxxm).text == '20' + assert tree.find('%swindGustSpeedOperator' % find_iwxxm).text == 'ABOVE' # METAR BIAR 290000Z 26010MPS @@ -319,9 +320,9 @@ def test_windComponents(): assert result.get('translationFailedTAC') is None tree = ET.XML(ET.tostring(result)) - assert tree.find('%smeanWindDirection' % iwxxm).text == '260' - assert tree.find('%smeanWindSpeed' % iwxxm).text == '10' - assert tree.find('%smeanWindSpeed' % iwxxm).get('uom') == 'm/s' + assert tree.find('%smeanWindDirection' % find_iwxxm).text == '260' + assert tree.find('%smeanWindSpeed' % find_iwxxm).text == '10' + assert tree.find('%smeanWindSpeed' % find_iwxxm).get('uom') == 'm/s' # METAR BIAR 290000Z 26010MPS 280V010 @@ -329,8 +330,8 @@ def test_windComponents(): assert result.get('translationFailedTAC') is None tree = ET.XML(ET.tostring(result)) - assert tree.find('%sextremeClockwiseWindDirection' % iwxxm).text == '10' - assert tree.find('%sextremeCounterClockwiseWindDirection' % iwxxm).text == '280' + assert tree.find('%sextremeClockwiseWindDirection' % find_iwxxm).text == '10' + assert tree.find('%sextremeCounterClockwiseWindDirection' % find_iwxxm).text == '280' def test_temperatures(): @@ -348,29 +349,29 @@ def test_temperatures(): assert result.get('translationFailedTAC') is None tree = ET.XML(ET.tostring(result)) - assert tree.find('%sairTemperature' % iwxxm).text == '20' - assert tree.find('%sdewpointTemperature' % iwxxm).text == '20' + assert tree.find('%sairTemperature' % find_iwxxm).text == '20' + assert tree.find('%sdewpointTemperature' % find_iwxxm).text == '20' result = bulletin.pop() assert result.get('translationFailedTAC') is None tree = ET.XML(ET.tostring(result)) - assert tree.find('%sairTemperature' % iwxxm).text == '-20' - assert tree.find('%sdewpointTemperature' % iwxxm).get('nilReason') == notObservable[0] + assert tree.find('%sairTemperature' % find_iwxxm).text == '-20' + assert tree.find('%sdewpointTemperature' % find_iwxxm).get('nilReason') == notObservable[0] result = bulletin.pop() assert result.get('translationFailedTAC') is None tree = ET.XML(ET.tostring(result)) - assert tree.find('%sairTemperature' % iwxxm).get('nilReason') == notObservable[0] - assert tree.find('%sdewpointTemperature' % iwxxm).text == '-20' + assert tree.find('%sairTemperature' % find_iwxxm).get('nilReason') == notObservable[0] + assert tree.find('%sdewpointTemperature' % find_iwxxm).text == '-20' result = bulletin.pop() assert result.get('translationFailedTAC') is None tree = ET.XML(ET.tostring(result)) - assert tree.find('%sairTemperature' % iwxxm).text == '-5' - assert tree.find('%sdewpointTemperature' % iwxxm).text == '-7' + assert tree.find('%sairTemperature' % find_iwxxm).text == '-5' + assert tree.find('%sdewpointTemperature' % find_iwxxm).text == '-7' def test_altimeters(): @@ -388,22 +389,22 @@ def test_altimeters(): assert result.get('translationFailedTAC') is None tree = ET.XML(ET.tostring(result)) - assert tree.find('%sqnh' % iwxxm).text == '1013' - assert tree.find('%sqnh' % iwxxm).get('uom') == 'hPa' + assert tree.find('%sqnh' % find_iwxxm).text == '1013' + assert tree.find('%sqnh' % find_iwxxm).get('uom') == 'hPa' result = bulletin.pop() assert result.get('translationFailedTAC') is None tree = ET.XML(ET.tostring(result)) - assert tree.find('%sqnh' % iwxxm).text == '1013.2' - assert tree.find('%sqnh' % iwxxm).get('uom') == 'hPa' + assert tree.find('%sqnh' % find_iwxxm).text == '1013.2' + assert tree.find('%sqnh' % find_iwxxm).get('uom') == 'hPa' result = bulletin.pop() assert result.get('translationFailedTAC') is None tree = ET.XML(ET.tostring(result)) - assert tree.find('%sqnh' % iwxxm).text == '1013' - assert tree.find('%sqnh' % iwxxm).get('uom') == 'hPa' + assert tree.find('%sqnh' % find_iwxxm).text == '1013' + assert tree.find('%sqnh' % find_iwxxm).get('uom') == 'hPa' result = bulletin.pop() assert result.get('translationFailedTAC') is not None @@ -429,9 +430,9 @@ def test_vsbys(): assert result.get('translationFailedTAC') is None tree = ET.XML(ET.tostring(result)) - assert tree.find('%sprevailingVisibility' % iwxxm).text == '10000' - assert tree.find('%sprevailingVisibility' % iwxxm).get('uom') == 'm' - assert tree.find('%sprevailingVisibilityOperator' % iwxxm).text == 'ABOVE' + assert tree.find('%sprevailingVisibility' % find_iwxxm).text == '10000' + assert tree.find('%sprevailingVisibility' % find_iwxxm).get('uom') == 'm' + assert tree.find('%sprevailingVisibilityOperator' % find_iwxxm).text == 'ABOVE' # METAR BIAR 290000Z /////KT 3000NDV // ////// ///// Q////= @@ -439,8 +440,8 @@ def test_vsbys(): assert result.get('translationFailedTAC') is None tree = ET.XML(ET.tostring(result)) - assert tree.find('%sprevailingVisibility' % iwxxm).text == '3000' - assert tree.find('%sminimumVisibility' % iwxxm) is None + assert tree.find('%sprevailingVisibility' % find_iwxxm).text == '3000' + assert tree.find('%sminimumVisibility' % find_iwxxm) is None # METAR BIAR 290000Z /////KT 4000 0150N // ////// ///// Q////= @@ -448,9 +449,9 @@ def test_vsbys(): assert result.get('translationFailedTAC') is None tree = ET.XML(ET.tostring(result)) - assert tree.find('%sprevailingVisibility' % iwxxm).text == '4000' - assert tree.find('%sminimumVisibility' % iwxxm).text == '150' - assert tree.find('%sminimumVisibilityDirection' % iwxxm).text == '360' + assert tree.find('%sprevailingVisibility' % find_iwxxm).text == '4000' + assert tree.find('%sminimumVisibility' % find_iwxxm).text == '150' + assert tree.find('%sminimumVisibilityDirection' % find_iwxxm).text == '360' # METAR BIAR 290000Z /////KT 0400 0050 // ////// ///// Q////= @@ -458,10 +459,10 @@ def test_vsbys(): assert result.get('translationFailedTAC') is None tree = ET.XML(ET.tostring(result)) - assert tree.find('%sprevailingVisibility' % iwxxm).text == '400' - assert tree.find('%sminimumVisibility' % iwxxm).text == '50' - assert tree.find('%sminimumVisibilityDirection' % iwxxm) is None - assert tree.find('%srvr' % iwxxm).get('nilReason') == missing[0] + assert tree.find('%sprevailingVisibility' % find_iwxxm).text == '400' + assert tree.find('%sminimumVisibility' % find_iwxxm).text == '50' + assert tree.find('%sminimumVisibilityDirection' % find_iwxxm) is None + assert tree.find('%srvr' % find_iwxxm).get('nilReason') == missing[0] # METAR BIAR 290000Z /////KT 1/16SM // ////// ///// Q////= @@ -469,8 +470,8 @@ def test_vsbys(): assert result.get('translationFailedTAC') is None tree = ET.XML(ET.tostring(result)) - assert tree.find('%sprevailingVisibility' % iwxxm).text == '100' - assert tree.find('%sprevailingVisibility' % iwxxm).get('uom') == 'm' + assert tree.find('%sprevailingVisibility' % find_iwxxm).text == '100' + assert tree.find('%sprevailingVisibility' % find_iwxxm).get('uom') == 'm' # METAR BIAR 290000Z /////KT M1/4SM // ////// ///// Q////= @@ -478,8 +479,8 @@ def test_vsbys(): assert result.get('translationFailedTAC') is None tree = ET.XML(ET.tostring(result)) - assert tree.find('%sprevailingVisibility' % iwxxm).text == '400' - assert tree.find('%sprevailingVisibilityOperator' % iwxxm).text == 'BELOW' + assert tree.find('%sprevailingVisibility' % find_iwxxm).text == '400' + assert tree.find('%sprevailingVisibilityOperator' % find_iwxxm).text == 'BELOW' # METAR BIAR 290000Z /////KT 1SM // ////// ///// Q////= @@ -487,8 +488,8 @@ def test_vsbys(): assert result.get('translationFailedTAC') is None tree = ET.XML(ET.tostring(result)) - assert tree.find('%sprevailingVisibility' % iwxxm).text == '1600' - assert tree.find('%sprevailingVisibility' % iwxxm).get('uom') == 'm' + assert tree.find('%sprevailingVisibility' % find_iwxxm).text == '1600' + assert tree.find('%sprevailingVisibility' % find_iwxxm).get('uom') == 'm' # METAR BIAR 290000Z /////KT 1 1/2SM // ////// ///// Q////= @@ -496,7 +497,7 @@ def test_vsbys(): assert result.get('translationFailedTAC') is None tree = ET.XML(ET.tostring(result)) - assert tree.find('%sprevailingVisibility' % iwxxm).text == '2400' + assert tree.find('%sprevailingVisibility' % find_iwxxm).text == '2400' # METAR BIAR 290000Z /////KT 7SM // ////// ///// Q////= @@ -504,8 +505,8 @@ def test_vsbys(): assert result.get('translationFailedTAC') is None tree = ET.XML(ET.tostring(result)) - assert tree.find('%sprevailingVisibility' % iwxxm).text == '10000' - assert tree.find('%sprevailingVisibilityOperator' % iwxxm).text == 'ABOVE' + assert tree.find('%sprevailingVisibility' % find_iwxxm).text == '10000' + assert tree.find('%sprevailingVisibilityOperator' % find_iwxxm).text == 'ABOVE' def test_rvrs(): @@ -533,11 +534,11 @@ def test_rvrs(): assert result.get('translationFailedTAC') is None tree = ET.XML(ET.tostring(result)) - runway = tree.find('%sAerodromeRunwayVisualRange' % iwxxm) + runway = tree.find('%sAerodromeRunwayVisualRange' % find_iwxxm) assert runway.get('pastTendency') == 'MISSING_VALUE' assert runway.find('%sdesignator' % aixm).get('nilReason') == 'missing' - assert tree.find('%smeanRVR' % iwxxm).get('nilReason') == notObservable[0] - assert tree.find('%smeanRVR' % iwxxm).get('uom') == 'N/A' + assert tree.find('%smeanRVR' % find_iwxxm).get('nilReason') == notObservable[0] + assert tree.find('%smeanRVR' % find_iwxxm).get('uom') == 'N/A' # METAR BIAR 290000Z /////KT 1000 R01/////FT ////// ///// Q////= @@ -545,9 +546,9 @@ def test_rvrs(): assert result.get('translationFailedTAC') is None tree = ET.XML(ET.tostring(result)) - runway = tree.find('%sAerodromeRunwayVisualRange' % iwxxm) + runway = tree.find('%sAerodromeRunwayVisualRange' % find_iwxxm) assert runway.find('%sdesignator' % aixm).text == '01' - assert tree.find('%smeanRVR' % iwxxm).get('nilReason') == notObservable[0] + assert tree.find('%smeanRVR' % find_iwxxm).get('nilReason') == notObservable[0] # METAR BIAR 290000Z /////KT 1000 R01C/4000FT ////// ///// Q////= @@ -555,10 +556,10 @@ def test_rvrs(): assert result.get('translationFailedTAC') is None tree = ET.XML(ET.tostring(result)) - runway = tree.find('%sAerodromeRunwayVisualRange' % iwxxm) + runway = tree.find('%sAerodromeRunwayVisualRange' % find_iwxxm) assert runway.find('%sdesignator' % aixm).text == '01C' - assert tree.find('%smeanRVR' % iwxxm).text == '1200' - assert tree.find('%smeanRVR' % iwxxm).get('uom') == 'm' + assert tree.find('%smeanRVR' % find_iwxxm).text == '1200' + assert tree.find('%smeanRVR' % find_iwxxm).get('uom') == 'm' # METAR BIAR 290000Z /////KT 1000 R01L/P4000FT ////// ///// Q////= @@ -566,12 +567,12 @@ def test_rvrs(): assert result.get('translationFailedTAC') is None tree = ET.XML(ET.tostring(result)) - runway = tree.find('%sAerodromeRunwayVisualRange' % iwxxm) + runway = tree.find('%sAerodromeRunwayVisualRange' % find_iwxxm) assert runway.get('pastTendency') == 'MISSING_VALUE' assert runway.find('%sdesignator' % aixm).text == '01L' - assert tree.find('%smeanRVR' % iwxxm).text == '1200' - assert tree.find('%smeanRVR' % iwxxm).get('uom') == 'm' - assert tree.find('%smeanRVROperator' % iwxxm).text == 'ABOVE' + assert tree.find('%smeanRVR' % find_iwxxm).text == '1200' + assert tree.find('%smeanRVR' % find_iwxxm).get('uom') == 'm' + assert tree.find('%smeanRVROperator' % find_iwxxm).text == 'ABOVE' # METAR BIAR 290000Z /////KT 1000 R01R/M0500FT ////// ///// Q////= @@ -579,12 +580,12 @@ def test_rvrs(): assert result.get('translationFailedTAC') is None tree = ET.XML(ET.tostring(result)) - runway = tree.find('%sAerodromeRunwayVisualRange' % iwxxm) + runway = tree.find('%sAerodromeRunwayVisualRange' % find_iwxxm) assert runway.get('pastTendency') == 'MISSING_VALUE' assert runway.find('%sdesignator' % aixm).text == '01R' - assert tree.find('%smeanRVR' % iwxxm).text == '150' - assert tree.find('%smeanRVR' % iwxxm).get('uom') == 'm' - assert tree.find('%smeanRVROperator' % iwxxm).text == 'BELOW' + assert tree.find('%smeanRVR' % find_iwxxm).text == '150' + assert tree.find('%smeanRVR' % find_iwxxm).get('uom') == 'm' + assert tree.find('%smeanRVROperator' % find_iwxxm).text == 'BELOW' # METAR BIAR 290000Z /////KT 1000 R36/1000U ////// ///// Q////= @@ -592,11 +593,11 @@ def test_rvrs(): assert result.get('translationFailedTAC') is None tree = ET.XML(ET.tostring(result)) - runway = tree.find('%sAerodromeRunwayVisualRange' % iwxxm) + runway = tree.find('%sAerodromeRunwayVisualRange' % find_iwxxm) assert runway.get('pastTendency') == 'UPWARD' assert runway.find('%sdesignator' % aixm).text == '36' - assert tree.find('%smeanRVR' % iwxxm).text == '1000' - assert tree.find('%smeanRVR' % iwxxm).get('uom') == 'm' + assert tree.find('%smeanRVR' % find_iwxxm).text == '1000' + assert tree.find('%smeanRVR' % find_iwxxm).get('uom') == 'm' # METAR BIAR 290000Z /////KT 1000 R36L/1000D ////// ///// Q////= @@ -604,7 +605,7 @@ def test_rvrs(): assert result.get('translationFailedTAC') is None tree = ET.XML(ET.tostring(result)) - runway = tree.find('%sAerodromeRunwayVisualRange' % iwxxm) + runway = tree.find('%sAerodromeRunwayVisualRange' % find_iwxxm) assert runway.get('pastTendency') == 'DOWNWARD' assert runway.find('%sdesignator' % aixm).text == '36L' @@ -614,7 +615,7 @@ def test_rvrs(): assert result.get('translationFailedTAC') is None tree = ET.XML(ET.tostring(result)) - runway = tree.find('%sAerodromeRunwayVisualRange' % iwxxm) + runway = tree.find('%sAerodromeRunwayVisualRange' % find_iwxxm) assert runway.get('pastTendency') == 'NO_CHANGE' assert runway.find('%sdesignator' % aixm).text == '36R' @@ -624,7 +625,7 @@ def test_rvrs(): assert result.get('translationFailedTAC') is None tree = ET.XML(ET.tostring(result)) - runway = tree.find('%sAerodromeRunwayVisualRange' % iwxxm) + runway = tree.find('%sAerodromeRunwayVisualRange' % find_iwxxm) assert runway.get('pastTendency') == 'MISSING_VALUE' assert runway.find('%sdesignator' % aixm).text == '36C' @@ -634,7 +635,7 @@ def test_rvrs(): assert result.get('translationFailedTAC') is None tree = ET.XML(ET.tostring(result)) - runway = tree.find('%sAerodromeRunwayVisualRange' % iwxxm) + runway = tree.find('%sAerodromeRunwayVisualRange' % find_iwxxm) assert runway.get('pastTendency') == 'UPWARD' assert runway.find('%sdesignator' % aixm).text == '01C' @@ -644,7 +645,7 @@ def test_rvrs(): assert result.get('translationFailedTAC') is None tree = ET.XML(ET.tostring(result)) - runway = tree.find('%sAerodromeRunwayVisualRange' % iwxxm) + runway = tree.find('%sAerodromeRunwayVisualRange' % find_iwxxm) assert runway.get('pastTendency') == 'DOWNWARD' assert runway.find('%sdesignator' % aixm).text == '01L' @@ -654,7 +655,7 @@ def test_rvrs(): assert result.get('translationFailedTAC') is None tree = ET.XML(ET.tostring(result)) - runway = tree.find('%sAerodromeRunwayVisualRange' % iwxxm) + runway = tree.find('%sAerodromeRunwayVisualRange' % find_iwxxm) assert runway.get('pastTendency') == 'NO_CHANGE' assert runway.find('%sdesignator' % aixm).text == '01R' @@ -667,7 +668,7 @@ def test_rvrs(): tree = ET.XML(ET.tostring(result)) - rvrs = tree.findall('%srvr' % iwxxm) + rvrs = tree.findall('%srvr' % find_iwxxm) assert len(rvrs) == 4 for rvr in rvrs: @@ -683,8 +684,8 @@ def test_rvrs(): else: assert True is False - assert tree.find('%smeanRVR' % iwxxm).text == '1000' - assert tree.find('%smeanRVR' % iwxxm).get('uom') == 'm' + assert tree.find('%smeanRVR' % find_iwxxm).text == '1000' + assert tree.find('%smeanRVR' % find_iwxxm).get('uom') == 'm' def test_wx_phenomena(): @@ -707,7 +708,7 @@ def test_wx_phenomena(): assert result.get('translationFailedTAC') is None tree = ET.XML(ET.tostring(result)) - wx = tree.find('%spresentWeather' % iwxxm) + wx = tree.find('%spresentWeather' % find_iwxxm) url, title = codes[des.WEATHER]['-TSRA'] assert wx.get(xhref) == url assert wx.get(xtitle) == title @@ -716,7 +717,7 @@ def test_wx_phenomena(): assert result.get('translationFailedTAC') is None tree = ET.XML(ET.tostring(result)) - wx = tree.find('%spresentWeather' % iwxxm) + wx = tree.find('%spresentWeather' % find_iwxxm) url, title = codes[des.WEATHER]['VCFG'] assert wx.get(xhref) == url assert wx.get(xtitle) == title @@ -725,7 +726,7 @@ def test_wx_phenomena(): assert result.get('translationFailedTAC') is None tree = ET.XML(ET.tostring(result)) - wx = tree.find('%spresentWeather' % iwxxm) + wx = tree.find('%spresentWeather' % find_iwxxm) url, title = codes[des.WEATHER]['+SS'] assert wx.get(xhref) == url assert wx.get(xtitle) == title @@ -734,7 +735,7 @@ def test_wx_phenomena(): assert result.get('translationFailedTAC') is None tree = ET.XML(ET.tostring(result)) - wx = tree.find('%spresentWeather' % iwxxm) + wx = tree.find('%spresentWeather' % find_iwxxm) url, title = codes[des.WEATHER]['UP'] assert wx.get(xhref) == url assert wx.get(xtitle) == title @@ -743,7 +744,7 @@ def test_wx_phenomena(): assert result.get('translationFailedTAC') is None tree = ET.XML(ET.tostring(result)) - wx = tree.find('%spresentWeather' % iwxxm) + wx = tree.find('%spresentWeather' % find_iwxxm) url, title = codes[des.WEATHER]['+SHUP'] assert wx.get(xhref) == url assert wx.get(xtitle) == title @@ -752,7 +753,7 @@ def test_wx_phenomena(): assert result.get('translationFailedTAC') is None tree = ET.XML(ET.tostring(result)) - wx = tree.find('%spresentWeather' % iwxxm) + wx = tree.find('%spresentWeather' % find_iwxxm) url, title = codes[des.WEATHER]['TS'] assert wx.get(xhref) == url assert wx.get(xtitle) == title @@ -768,7 +769,7 @@ def test_wx_phenomena(): assert result.get('translationFailedTAC') is None tree = ET.XML(ET.tostring(result)) - wxrs = tree.findall('%srecentWeather' % iwxxm) + wxrs = tree.findall('%srecentWeather' % find_iwxxm) assert len(wxrs) == 3 for cnt, wx in enumerate(wxrs): @@ -792,21 +793,21 @@ def test_wx_phenomena(): assert result.get('translationFailedTAC') is None tree = ET.XML(ET.tostring(result)) - assert tree[-1].tag == '{http://icao.int/iwxxm/3.0}trendForecast' + assert tree[-1].tag == '%strendForecast' % iwxxm assert tree[-1].get('nilReason') == noSignificantChange[0] result = bulletin.pop() assert result.get('translationFailedTAC') is None tree = ET.XML(ET.tostring(result)) - element = tree.find('%sMeteorologicalAerodromeTrendForecast' % iwxxm) + element = tree.find('%sMeteorologicalAerodromeTrendForecast' % find_iwxxm) assert element.get('changeIndicator') == 'BECOMING' assert element.get('cloudAndVisibilityOK') == 'true' - assert element[1][0].tag == '{http://icao.int/iwxxm/3.0}AerodromeSurfaceWindTrendForecast' - assert element[1][0][0].tag == '{http://icao.int/iwxxm/3.0}meanWindDirection' + assert element[1][0].tag == '%sAerodromeSurfaceWindTrendForecast' % iwxxm + assert element[1][0][0].tag == '%smeanWindDirection' % iwxxm assert element[1][0][0].text == '210' assert element[1][0][0].get('uom') == 'deg' - assert element[1][0][1].tag == '{http://icao.int/iwxxm/3.0}meanWindSpeed' + assert element[1][0][1].tag == '%smeanWindSpeed' % iwxxm assert element[1][0][1].text == '15' assert element[1][0][1].get('uom') == 'm/s' @@ -814,7 +815,7 @@ def test_wx_phenomena(): assert result.get('translationFailedTAC') is None tree = ET.XML(ET.tostring(result)) - element = tree.find('%sMeteorologicalAerodromeTrendForecast' % iwxxm) + element = tree.find('%sMeteorologicalAerodromeTrendForecast' % find_iwxxm) assert element.get('changeIndicator') == 'TEMPORARY_FLUCTUATIONS' assert element.get('cloudAndVisibilityOK') == 'false' @@ -840,7 +841,7 @@ def test_sky_conditions(): assert result.get('translationFailedTAC') is None tree = ET.XML(ET.tostring(result)) - element = tree.find('%scloud' % iwxxm) + element = tree.find('%scloud' % find_iwxxm) assert element.get('nilReason') == nothingOfOperationalSignificance[0] assert tree.get('automatedStation') == 'false' @@ -850,7 +851,7 @@ def test_sky_conditions(): assert result.get('translationFailedTAC') is None tree = ET.XML(ET.tostring(result)) - element = tree.find('%scloud' % iwxxm) + element = tree.find('%scloud' % find_iwxxm) assert element.get('nilReason') == notDetectedByAutoSystem[0] assert tree.get('automatedStation') == 'true' @@ -860,7 +861,7 @@ def test_sky_conditions(): assert result.get('translationFailedTAC') is None tree = ET.XML(ET.tostring(result)) - element = tree.find('%scloud' % iwxxm) + element = tree.find('%scloud' % find_iwxxm) assert element.get('nilReason') == notDetectedByAutoSystem[0] # METAR BIAR 290000Z /////KT //// ///050 BKN/// //////CB //////TCU ///// Q////= @@ -869,7 +870,7 @@ def test_sky_conditions(): assert result.get('translationFailedTAC') is None tree = ET.XML(ET.tostring(result)) - layers = tree.findall('%sCloudLayer' % iwxxm) + layers = tree.findall('%sCloudLayer' % find_iwxxm) assert len(layers) == 4 for cnt, layer in enumerate(layers): @@ -903,7 +904,7 @@ def test_sky_conditions(): assert result.get('translationFailedTAC') is None tree = ET.XML(ET.tostring(result)) - layer = tree.find('%sverticalVisibility' % iwxxm) + layer = tree.find('%sverticalVisibility' % find_iwxxm) assert layer.get('nilReason') == notObservable[0] assert layer.get('uom') == 'N/A' @@ -913,7 +914,7 @@ def test_sky_conditions(): assert result.get('translationFailedTAC') is None tree = ET.XML(ET.tostring(result)) - layer = tree.find('%sverticalVisibility' % iwxxm) + layer = tree.find('%sverticalVisibility' % find_iwxxm) assert layer.text == '100' assert layer.get('uom') == '[ft_i]' @@ -923,7 +924,7 @@ def test_sky_conditions(): assert result.get('translationFailedTAC') is None tree = ET.XML(ET.tostring(result)) - layers = tree.findall('%sCloudLayer' % iwxxm) + layers = tree.findall('%sCloudLayer' % find_iwxxm) assert len(layers) == 4 for cnt, layer in enumerate(layers): @@ -949,7 +950,7 @@ def test_sky_conditions(): assert layer[0].get(xhref) == codes[des.CLDAMTS]['OVC'][0] assert layer[1].text == '12000' assert layer[1].get('uom') == '[ft_i]' - assert layer[2].tag == '{http://icao.int/iwxxm/3.0}cloudType' + assert layer[2].tag == '%scloudType' % iwxxm assert layer[2].get('nilReason') == notObservable[0] test = """SAXX99 XXXX 151200 @@ -969,7 +970,7 @@ def test_sky_conditions(): tree = ET.XML(ET.tostring(result)) assert tree.get('automatedStation') == 'true' - assert tree.find('%slayer' % iwxxm).get('nilReason') == notDetectedByAutoSystem[0] + assert tree.find('%slayer' % find_iwxxm).get('nilReason') == notDetectedByAutoSystem[0] # METAR BIAR 290000Z AUTO /////KT //// ///050 BKN/// //////CB //////TCU ///// Q////=""" @@ -978,7 +979,7 @@ def test_sky_conditions(): tree = ET.XML(ET.tostring(result)) assert tree.get('automatedStation') == 'true' - layers = tree.findall('%sCloudLayer' % iwxxm) + layers = tree.findall('%sCloudLayer' % find_iwxxm) assert len(layers) == 4 for cnt, layer in enumerate(layers): @@ -1010,7 +1011,7 @@ def test_sky_conditions(): assert result.get('translationFailedTAC') is None tree = ET.XML(ET.tostring(result)) - layers = tree.findall('%sCloudLayer' % iwxxm) + layers = tree.findall('%sCloudLayer' % find_iwxxm) assert len(layers) == 1 for cnt, layer in enumerate(layers): @@ -1036,8 +1037,8 @@ def test_windshears(): assert result.get('translationFailedTAC') is None tree = ET.XML(ET.tostring(result)) - assert len(tree.find('%sAerodromeWindShear' % iwxxm)) == 0 - assert tree.find('%sAerodromeWindShear' % iwxxm).get('allRunways') == 'true' + assert len(tree.find('%sAerodromeWindShear' % find_iwxxm)) == 0 + assert tree.find('%sAerodromeWindShear' % find_iwxxm).get('allRunways') == 'true' # METAR BIAR 290000Z /////KT //// // ////// ///// Q//// WS R01C= @@ -1045,7 +1046,7 @@ def test_windshears(): assert result.get('translationFailedTAC') is None tree = ET.XML(ET.tostring(result)) - ws = tree.find('%sAerodromeWindShear' % iwxxm) + ws = tree.find('%sAerodromeWindShear' % find_iwxxm) assert ws.find('%sdesignator' % aixm).text == '01C' @@ -1065,8 +1066,8 @@ def test_seastates(): assert result.get('translationFailedTAC') is None tree = ET.XML(ET.tostring(result)) - assert tree.find('%sseaSurfaceTemperature' % iwxxm).text == '-2' - ss = tree.find('%sseaState' % iwxxm) + assert tree.find('%sseaSurfaceTemperature' % find_iwxxm).text == '-2' + ss = tree.find('%sseaState' % find_iwxxm) url, title = codes[des.SEACNDS]['2'] assert ss.get(xhref) == url assert ss.get(xtitle) == title @@ -1077,8 +1078,8 @@ def test_seastates(): assert result.get('translationFailedTAC') is None tree = ET.XML(ET.tostring(result)) - assert tree.find('%sseaSurfaceTemperature' % iwxxm).text == '22' - wh = tree.find('%ssignificantWaveHeight' % iwxxm) + assert tree.find('%sseaSurfaceTemperature' % find_iwxxm).text == '22' + wh = tree.find('%ssignificantWaveHeight' % find_iwxxm) assert wh.text == '7.5' assert wh.get('uom') == 'm' @@ -1095,15 +1096,15 @@ def test_seastates(): assert result.get('translationFailedTAC') is None tree = ET.XML(ET.tostring(result)) - assert tree.find('%sseaSurfaceTemperature' % iwxxm).get('nilReason') == notObservable[0] - ss = tree.find('%sseaState' % iwxxm) + assert tree.find('%sseaSurfaceTemperature' % find_iwxxm).get('nilReason') == notObservable[0] + ss = tree.find('%sseaState' % find_iwxxm) assert ss.get('nilReason') == notObservable[0] result = bulletin.pop() assert result.get('translationFailedTAC') is None tree = ET.XML(ET.tostring(result)) - wh = tree.find('%ssignificantWaveHeight' % iwxxm) + wh = tree.find('%ssignificantWaveHeight' % find_iwxxm) assert wh.get('nilReason') == notObservable[0] @@ -1128,7 +1129,7 @@ def test_runwaystates(): assert result.get('translationFailedTAC') is None tree = ET.XML(ET.tostring(result)) - assert tree.find('%srunwayState' % iwxxm).get('nilReason') == des.NIL_SNOCLO_URL + assert tree.find('%srunwayState' % find_iwxxm).get('nilReason') == des.NIL_SNOCLO_URL # METAR BIAR 290000Z /////KT //// // ////// ///// Q//// R/CLRD//= @@ -1136,7 +1137,7 @@ def test_runwaystates(): assert result.get('translationFailedTAC') is None tree = ET.XML(ET.tostring(result)) - rs = tree.find('%srunwayState' % iwxxm) + rs = tree.find('%srunwayState' % find_iwxxm) assert rs[0].get('allRunways') == 'true' assert rs[0].get('cleared') == 'true' @@ -1146,13 +1147,13 @@ def test_runwaystates(): assert result.get('translationFailedTAC') is None tree = ET.XML(ET.tostring(result)) - rs = tree.find('%srunwayState' % iwxxm) + rs = tree.find('%srunwayState' % find_iwxxm) assert rs[0].get('allRunways') == 'false' assert rs.find('%sdesignator' % aixm).text == '01' - assert rs.find('%sdepositType' % iwxxm) is None - assert rs.find('%scontamination' % iwxxm) is None - assert rs.find('%sdepthOfDeposit' % iwxxm).get('nilReason') == nothingOfOperationalSignificance[0] - assert rs.find('%sestimatedSurfaceFrictionOrBrakingAction' % iwxxm) is None + assert rs.find('%sdepositType' % find_iwxxm) is None + assert rs.find('%scontamination' % find_iwxxm) is None + assert rs.find('%sdepthOfDeposit' % find_iwxxm).get('nilReason') == nothingOfOperationalSignificance[0] + assert rs.find('%sestimatedSurfaceFrictionOrBrakingAction' % find_iwxxm) is None # METAR BIAR 290000Z /////KT //// // ////// ///// Q//// R02/999491= @@ -1160,14 +1161,14 @@ def test_runwaystates(): assert result.get('translationFailedTAC') is None tree = ET.XML(ET.tostring(result)) - rs = tree.find('%srunwayState' % iwxxm) + rs = tree.find('%srunwayState' % find_iwxxm) assert rs[0].get('allRunways') == 'false' assert rs.find('%sdesignator' % aixm).text == '02' - assert rs.find('%sdepositType' % iwxxm).get(xhref) == codes[des.RWYDEPST]['9'][0] - assert rs.find('%scontamination' % iwxxm).get(xhref) == codes[des.RWYCNTMS]['9'][0] - assert rs.find('%sdepthOfDeposit' % iwxxm).text == '200' - assert rs.find('%sdepthOfDeposit' % iwxxm).get('uom') == 'mm' - friction = rs.find('%sestimatedSurfaceFrictionOrBrakingAction' % iwxxm) + assert rs.find('%sdepositType' % find_iwxxm).get(xhref) == codes[des.RWYDEPST]['9'][0] + assert rs.find('%scontamination' % find_iwxxm).get(xhref) == codes[des.RWYCNTMS]['9'][0] + assert rs.find('%sdepthOfDeposit' % find_iwxxm).text == '200' + assert rs.find('%sdepthOfDeposit' % find_iwxxm).get('uom') == 'mm' + friction = rs.find('%sestimatedSurfaceFrictionOrBrakingAction' % find_iwxxm) assert friction.get(xhref) == codes[des.RWYFRCTN]['91'][0] # METAR BIAR 290000Z /////KT //// // ////// ///// Q//// R88/CLRD//= @@ -1176,7 +1177,7 @@ def test_runwaystates(): assert result.get('translationFailedTAC') is None tree = ET.XML(ET.tostring(result)) - rs = tree.find('%srunwayState' % iwxxm) + rs = tree.find('%srunwayState' % find_iwxxm) assert rs[0].get('allRunways') == 'true' assert rs[0].get('cleared') == 'true' @@ -1186,7 +1187,7 @@ def test_runwaystates(): assert result.get('translationFailedTAC') is None tree = ET.XML(ET.tostring(result)) - rs = tree.find('%srunwayState' % iwxxm) + rs = tree.find('%srunwayState' % find_iwxxm) assert rs[0].get('fromPreviousReport') == 'true' assert rs[0].get('cleared') == 'true' @@ -1207,17 +1208,17 @@ def test_trendTiming(): assert result.get('translationFailedTAC') is None tree = ET.XML(ET.tostring(result)) - element = tree.find('%sMeteorologicalAerodromeTrendForecast' % iwxxm) + element = tree.find('%sMeteorologicalAerodromeTrendForecast' % find_iwxxm) # METAR BIAR 302351Z /////KT //// ////// ///// Q//// BECMG 9999 NSW= assert element.get('changeIndicator') == 'BECOMING' - assert element[0].tag == '{http://icao.int/iwxxm/3.0}phenomenonTime' + assert element[0].tag == '%sphenomenonTime' % iwxxm assert element[0].get('nilReason') == missing[0] - vis = tree.find('%sprevailingVisibility' % iwxxm) + vis = tree.find('%sprevailingVisibility' % find_iwxxm) assert vis.text == '10000' assert vis.get('uom') == 'm' - oper = tree.find('%sprevailingVisibilityOperator' % iwxxm) + oper = tree.find('%sprevailingVisibilityOperator' % find_iwxxm) oper.text = 'ABOVE' # METAR BIAR 302351Z /////KT //// ////// ///// Q//// BECMG FM0000 TL0030 1/16SM FG= @@ -1226,14 +1227,14 @@ def test_trendTiming(): assert result.get('translationFailedTAC') is None tree = ET.XML(ET.tostring(result)) - vis = tree.find('%sprevailingVisibility' % iwxxm) + vis = tree.find('%sprevailingVisibility' % find_iwxxm) assert vis.text == '100' assert vis.get('uom') == 'm' - element = tree.find('%sMeteorologicalAerodromeTrendForecast' % iwxxm) + element = tree.find('%sMeteorologicalAerodromeTrendForecast' % find_iwxxm) assert element.get('changeIndicator') == 'BECOMING' - assert element[0].tag == '{http://icao.int/iwxxm/3.0}phenomenonTime' - assert element[1].tag == '{http://icao.int/iwxxm/3.0}timeIndicator' + assert element[0].tag == '%sphenomenonTime' % iwxxm + assert element[1].tag == '%stimeIndicator' % iwxxm assert element[1].text == 'FROM_UNTIL' # METAR BIAR 302351Z /////KT //// ////// ///// Q//// BECMG TL0030 CAVOK= @@ -1242,10 +1243,10 @@ def test_trendTiming(): assert result.get('translationFailedTAC') is None tree = ET.XML(ET.tostring(result)) - element = tree.find('%sMeteorologicalAerodromeTrendForecast' % iwxxm) + element = tree.find('%sMeteorologicalAerodromeTrendForecast' % find_iwxxm) assert element.get('changeIndicator') == 'BECOMING' - assert element[0].tag == '{http://icao.int/iwxxm/3.0}phenomenonTime' - assert element[1].tag == '{http://icao.int/iwxxm/3.0}timeIndicator' + assert element[0].tag == '%sphenomenonTime' % iwxxm + assert element[1].tag == '%stimeIndicator' % iwxxm assert element[1].text == 'UNTIL' # METAR BIAR 302351Z /////KT //// ////// ///// Q//// BECMG FM0000 CAVOK= @@ -1254,10 +1255,10 @@ def test_trendTiming(): assert result.get('translationFailedTAC') is None tree = ET.XML(ET.tostring(result)) - element = tree.find('%sMeteorologicalAerodromeTrendForecast' % iwxxm) + element = tree.find('%sMeteorologicalAerodromeTrendForecast' % find_iwxxm) assert element.get('changeIndicator') == 'BECOMING' - assert element[0].tag == '{http://icao.int/iwxxm/3.0}phenomenonTime' - assert element[1].tag == '{http://icao.int/iwxxm/3.0}timeIndicator' + assert element[0].tag == '%sphenomenonTime' % iwxxm + assert element[1].tag == '%stimeIndicator' % iwxxm assert element[1].text == 'FROM' # METAR BIAR 302351Z /////KT //// ////// ///// Q//// BECMG AT0000 CAVOK= @@ -1266,10 +1267,10 @@ def test_trendTiming(): assert result.get('translationFailedTAC') is None tree = ET.XML(ET.tostring(result)) - element = tree.find('%sMeteorologicalAerodromeTrendForecast' % iwxxm) + element = tree.find('%sMeteorologicalAerodromeTrendForecast' % find_iwxxm) assert element.get('changeIndicator') == 'BECOMING' - assert element[0].tag == '{http://icao.int/iwxxm/3.0}phenomenonTime' - assert element[1].tag == '{http://icao.int/iwxxm/3.0}timeIndicator' + assert element[0].tag == '%sphenomenonTime' % iwxxm + assert element[1].tag == '%stimeIndicator' % iwxxm assert element[1].text == 'AT' test = """SAXX99 XXXX 151200 @@ -1288,9 +1289,9 @@ def test_trendTiming(): assert result.get('translationFailedTAC') is None tree = ET.XML(ET.tostring(result)) - element = tree.find('%sMeteorologicalAerodromeTrendForecast' % iwxxm) + element = tree.find('%sMeteorologicalAerodromeTrendForecast' % find_iwxxm) assert element.get('changeIndicator') == 'TEMPORARY_FLUCTUATIONS' - assert element[0].tag == '{http://icao.int/iwxxm/3.0}phenomenonTime' + assert element[0].tag == '%sphenomenonTime' % iwxxm assert element[0].get('nilReason') == missing[0] # METAR BIAR 302351Z /////KT //// ////// ///// Q//// TEMPO FM0000 TL030 +FC= @@ -1299,10 +1300,10 @@ def test_trendTiming(): assert result.get('translationFailedTAC') is None tree = ET.XML(ET.tostring(result)) - element = tree.find('%sMeteorologicalAerodromeTrendForecast' % iwxxm) + element = tree.find('%sMeteorologicalAerodromeTrendForecast' % find_iwxxm) assert element.get('changeIndicator') == 'TEMPORARY_FLUCTUATIONS' - assert element[0].tag == '{http://icao.int/iwxxm/3.0}phenomenonTime' - assert element[1].tag == '{http://icao.int/iwxxm/3.0}timeIndicator' + assert element[0].tag == '%sphenomenonTime' % iwxxm + assert element[1].tag == '%stimeIndicator' % iwxxm assert element[1].text == 'FROM_UNTIL' # METAR BIAR 302351Z /////KT //// ////// ///// Q//// TEMPO TL0030 +FC= @@ -1311,10 +1312,10 @@ def test_trendTiming(): assert result.get('translationFailedTAC') is None tree = ET.XML(ET.tostring(result)) - element = tree.find('%sMeteorologicalAerodromeTrendForecast' % iwxxm) + element = tree.find('%sMeteorologicalAerodromeTrendForecast' % find_iwxxm) assert element.get('changeIndicator') == 'TEMPORARY_FLUCTUATIONS' - assert element[0].tag == '{http://icao.int/iwxxm/3.0}phenomenonTime' - assert element[1].tag == '{http://icao.int/iwxxm/3.0}timeIndicator' + assert element[0].tag == '%sphenomenonTime' % iwxxm + assert element[1].tag == '%stimeIndicator' % iwxxm assert element[1].text == 'UNTIL' # METAR BIAR 302351Z /////KT //// ////// ///// Q//// TEMPO FM0000 +FC= @@ -1323,10 +1324,10 @@ def test_trendTiming(): assert result.get('translationFailedTAC') is None tree = ET.XML(ET.tostring(result)) - element = tree.find('%sMeteorologicalAerodromeTrendForecast' % iwxxm) + element = tree.find('%sMeteorologicalAerodromeTrendForecast' % find_iwxxm) assert element.get('changeIndicator') == 'TEMPORARY_FLUCTUATIONS' - assert element[0].tag == '{http://icao.int/iwxxm/3.0}phenomenonTime' - assert element[1].tag == '{http://icao.int/iwxxm/3.0}timeIndicator' + assert element[0].tag == '%sphenomenonTime' % iwxxm + assert element[1].tag == '%stimeIndicator' % iwxxm assert element[1].text == 'FROM' @@ -1339,7 +1340,7 @@ def test_commonRunway(): assert len(bulletin) == test.count('\n') - 1 tree = ET.XML(ET.tostring(bulletin.pop())) - runways = tree.findall('%srunway' % iwxxm) + runways = tree.findall('%srunway' % find_iwxxm) assert len(runways) == 3 # # First runway shall have the id that is shared with the rest @@ -1369,12 +1370,12 @@ def test_misc(): tree = ET.XML(ET.tostring(bulletin.pop())) assert tree.get('translationFailedTAC') is None - obTime = tree.find('{http://icao.int/iwxxm/3.0}observationTime') + obTime = tree.find('%sobservationTime' % iwxxm) assert obTime.get(xhref) is not None tree = ET.XML(ET.tostring(bulletin.pop())) assert tree.get('translationFailedTAC') is not None - obTime = tree.find('{http://icao.int/iwxxm/3.0}observationTime') + obTime = tree.find('%sobservationTime' % iwxxm) assert obTime.get(xhref) is None diff --git a/tests/test_taf_encoding.py b/tests/test_taf_encoding.py index adac233..71c46a3 100644 --- a/tests/test_taf_encoding.py +++ b/tests/test_taf_encoding.py @@ -9,7 +9,7 @@ reqCodes = [des.WEATHER, des.CLDAMTS, des.CVCTNCLDS] codes = deu.parseCodeRegistryTables(des.CodesFilePath, reqCodes) -iwxxm = '{http://icao.int/iwxxm/3.0}' +iwxxm = '{%s}' % des.IWXXM_URI find_iwxxm = './/*%s' % iwxxm xhref = '{http://www.w3.org/1999/xlink}href' xtitle = '{http://www.w3.org/1999/xlink}title' diff --git a/tests/test_tca_encoding.py b/tests/test_tca_encoding.py index b35503d..abefd19 100644 --- a/tests/test_tca_encoding.py +++ b/tests/test_tca_encoding.py @@ -14,7 +14,7 @@ find_aixm = './/*%s' % aixm gml = '{http://www.opengis.net/gml/3.2}' find_gml = './/*%s' % gml -iwxxm = '{http://icao.int/iwxxm/3.0}' +iwxxm = '{%s}' % des.IWXXM_URI find_iwxxm = './/*%s' % iwxxm xhref = '{http://www.w3.org/1999/xlink}href' xtitle = '{http://www.w3.org/1999/xlink}title' @@ -173,6 +173,8 @@ def test_tcaExercise(): assert movement.text == '270' movement = element.find('%smovementSpeed' % find_iwxxm) assert movement.text == '12' + intensityChg = element.find('%sintensityChange' % find_iwxxm) + assert intensityChg.text == 'INTENSIFY' pressure = element.find('%scentralPressure' % find_iwxxm) assert pressure.text == '905' maxWSpeed = element.find('%smaximumSurfaceWindSpeed' % find_iwxxm) @@ -337,6 +339,8 @@ def test_tcaMetric(): assert movement.text == '270' movement = element.find('%smovementSpeed' % find_iwxxm) assert movement.text == '20' + intensityChg = element.find('%sintensityChange' % find_iwxxm) + assert intensityChg.text == 'NO_CHANGE' pressure = element.find('%scentralPressure' % find_iwxxm) assert pressure.text == '905' maxWSpeed = element.find('%smaximumSurfaceWindSpeed' % find_iwxxm) @@ -448,6 +452,8 @@ def test_developing(): assert movement.text == '225' movement = element.find('%smovementSpeed' % find_iwxxm) assert movement.text == '6' + intensityChg = element.find('%sintensityChange' % find_iwxxm) + assert intensityChg.text == 'WEAKEN' pressure = element.find('%scentralPressure' % find_iwxxm) assert pressure.text == '999' maxWSpeed = element.find('%smaximumSurfaceWindSpeed' % find_iwxxm) @@ -560,6 +566,8 @@ def test_dissipation(): assert movement.text == '22.5' movement = element.find('%smovementSpeed' % find_iwxxm) assert movement.text == '15' + intensityChg = element.find('%sintensityChange' % find_iwxxm) + assert intensityChg.text == 'WEAKEN' pressure = element.find('%scentralPressure' % find_iwxxm) assert pressure.text == '1014' maxWSpeed = element.find('%smaximumSurfaceWindSpeed' % find_iwxxm) @@ -583,8 +591,12 @@ def test_dissipation(): assert time.text == '2019-07-24T09:00:00Z' assert position is None assert maxWSpeed.text == '25' + position = forecast.find('%stropicalCyclonePosition' % find_iwxxm) + assert position.get('nilReason') == codes[des.NIL][des.NA][0] elif fcnt == 3: - assert forecast.get('nilReason') == codes[des.NIL][des.NOOPRSIG][0] + assert time.text == '2019-07-24T15:00:00Z' + assert position.text == '45.500 -55.083' + assert maxWSpeed.get('nilReason') == codes[des.NIL][des.NOOPRSIG][0] elif num == 9: assert len(element.text) > 0 diff --git a/tests/test_vaa_encoding.py b/tests/test_vaa_encoding.py index a754f29..16a1cff 100644 --- a/tests/test_vaa_encoding.py +++ b/tests/test_vaa_encoding.py @@ -14,7 +14,7 @@ find_aixm = './/*%s' % aixm gml = '{http://www.opengis.net/gml/3.2}' find_gml = './/*%s' % gml -iwxxm = '{http://icao.int/iwxxm/3.0}' +iwxxm = '{%s}' % des.IWXXM_URI find_iwxxm = './/*%s' % iwxxm xhref = '{http://www.w3.org/1999/xlink}href'