def setUp(self): with open('dwml_good.xml') as f: self.good_xml_response = f.read() with open('dwml_dst.xml') as f: self.dst_xml_response = f.read() logger = logging.getLogger(__name__) self.dwml_parser = ForecastDWMLParser(logger)
def setUp(self): with open('dwml_good.xml') as f: self.good_xml_response = f.read() logger = logging.getLogger(__name__) self.dwml_parser = ForecastDWMLParser(logger) root = self.dwml_parser._parse_xml_response_into_doc(self.good_xml_response) layouts = self.dwml_parser._construct_time_layouts(root) rain = self.dwml_parser._get_hourly_precipitation(root, layouts) snow = self.dwml_parser._get_hourly_snow(root, layouts) twelve_hour_pops = self.dwml_parser._get_12hourly_probabilities(root, layouts) six_hour_pops = self.dwml_parser._convert_probabilities_to_6hourly(twelve_hour_pops) self.forecast = DWMLForecast(logger, rain, snow, six_hour_pops)
class TestForecastModel(unittest.TestCase): def setUp(self): with open('dwml_good.xml') as f: self.good_xml_response = f.read() logger = logging.getLogger(__name__) self.dwml_parser = ForecastDWMLParser(logger) root = self.dwml_parser._parse_xml_response_into_doc(self.good_xml_response) layouts = self.dwml_parser._construct_time_layouts(root) rain = self.dwml_parser._get_hourly_precipitation(root, layouts) snow = self.dwml_parser._get_hourly_snow(root, layouts) twelve_hour_pops = self.dwml_parser._get_12hourly_probabilities(root, layouts) six_hour_pops = self.dwml_parser._convert_probabilities_to_6hourly(twelve_hour_pops) self.forecast = DWMLForecast(logger, rain, snow, six_hour_pops) def test_start_end_dates(self): """ Tests to ensure the overall start and end dates for the forcast are calculated correctly """ self.assertEqual(self.forecast.start_date.isoformat(), '2015-09-28T12:00:00-06:00') self.assertEqual(self.forecast.end_date.isoformat(), '2015-09-30T12:00:00-06:00') # Make sure the dates are 48 hours apart delta = self.forecast.end_date - self.forecast.start_date self.assertEqual(delta.total_seconds(), 48 * 60 * 60) def test_total_hours(self): """ Tests to make sure it calculates the number of hours correctly """ self.assertEqual(self.forecast.total_hours, 48) def test_total_inches(self): """ Tests to make sure it sums the snow and rain inches properly """ self.assertEqual(self.forecast.total_rain_inches, 0.36) self.assertEqual(self.forecast.total_snow_inches, 3.6)
class TestXMLForecast(unittest.TestCase): def setUp(self): with open('dwml_good.xml') as f: self.good_xml_response = f.read() with open('dwml_dst.xml') as f: self.dst_xml_response = f.read() logger = logging.getLogger(__name__) self.dwml_parser = ForecastDWMLParser(logger) def test_bad_xml(self): """ Tests that we properly handle invalid XML """ self.assertRaises(ForecastParserException, self.dwml_parser._parse_xml_response_into_doc, 'not xml') def test_layout_keys(self): """ Test the parsing of layout keys into datetimes """ root = self.dwml_parser._parse_xml_response_into_doc(self.good_xml_response) layouts = self.dwml_parser._construct_time_layouts(root) # We should have two layouts self.assertEqual(len(layouts), 2) # We should have known keys self.assertIn('k-p6h-n13-2', layouts.keys()) self.assertIn('k-p12h-n15-1', layouts.keys()) # Check the length of both self.assertEqual(len(layouts['k-p6h-n13-2']), 13) self.assertEqual(len(layouts['k-p12h-n15-1']), 15) # Spot check to ensure we got the right dates d0 = layouts['k-p6h-n13-2'][0][0].isoformat() d1 = layouts['k-p6h-n13-2'][0][1].isoformat() self.assertEqual(d0, '2015-09-28T12:00:00-06:00') self.assertEqual(d1, '2015-09-28T18:00:00-06:00') def test_hourly_precipitations(self): """ Test the parsing of QPF into tuples """ root = self.dwml_parser._parse_xml_response_into_doc(self.good_xml_response) layouts = self.dwml_parser._construct_time_layouts(root) rain = self.dwml_parser._get_hourly_precipitation(root, layouts) # We should have 13 periods self.assertEqual(len(rain), 13) # Check the dates on the first period to make sure they line # up with the time layouts d0 = rain[0][0].isoformat() d1 = rain[0][1].isoformat() self.assertEqual(d0, layouts['k-p6h-n13-2'][0][0].isoformat()) self.assertEqual(d1, layouts['k-p6h-n13-2'][0][1].isoformat()) # Check the amounts are what we expected expected_amts = [0.01, 0.02, 0.03, 0.04, 0.05, 0.06, 0.07, 0.08, 0.09, \ 0.1, 0.11, 0.12, 0.13] amounts = [r[2] for r in rain] self.assertListEqual(amounts, expected_amts) def test_hourly_snow(self): """ Test the parsing of snow amounts into tuples """ root = self.dwml_parser._parse_xml_response_into_doc(self.good_xml_response) layouts = self.dwml_parser._construct_time_layouts(root) snow = self.dwml_parser._get_hourly_snow(root, layouts) # We should have 13 periods self.assertEqual(len(snow), 13) # Check the dates on the first period to make sure they line # up with the time layouts d0 = snow[0][0].isoformat() d1 = snow[0][1].isoformat() self.assertEqual(d0, layouts['k-p6h-n13-2'][0][0].isoformat()) self.assertEqual(d1, layouts['k-p6h-n13-2'][0][1].isoformat()) # Check the amounts are what we expected expected_amts = [0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0, 1.1, 1.2, 1.3] amounts = [s[2] for s in snow] self.assertListEqual(amounts, expected_amts) def test_probabilities(self): """ Test the parsing of precip probabilities into tuples """ root = self.dwml_parser._parse_xml_response_into_doc(self.good_xml_response) layouts = self.dwml_parser._construct_time_layouts(root) twelve_hour_pops = self.dwml_parser._get_12hourly_probabilities(root, layouts) six_hour_pops = self.dwml_parser._convert_probabilities_to_6hourly(twelve_hour_pops) # There should be 15 twelve-hour blocks and 30 six-hour blocks self.assertEqual(len(twelve_hour_pops), 15) self.assertEqual(len(six_hour_pops), 30) # Iterate over each of the twelve-hour pops and check that they have the # correct value expected_pops = [18, 28, 25, 17, 5, 6, 6, 12, 23, 27, 17, 14, 12, 9, 8] for index, pop_tuple in enumerate(twelve_hour_pops): sd = pop_tuple[0].isoformat() ed = pop_tuple[1].isoformat() pct = pop_tuple[2] # Check the start and end dates self.assertEqual(sd, layouts['k-p12h-n15-1'][index][0].isoformat()) self.assertEqual(ed, layouts['k-p12h-n15-1'][index][1].isoformat()) # Check the value is now a decimal instead of an int self.assertEqual(pct, expected_pops[index] / 100.0) # Now we need to check the 6-hourly and make sure they were divided properly for index, pop_tuple in enumerate(six_hour_pops): sd = pop_tuple[0] ed = pop_tuple[1] pct = pop_tuple[2] # Check that the dates are six hour blocks self.assertEqual(ed-sd, datetime.timedelta(0, 21600)) # Make sure each element of the 12-hourly lines up with every *other* # element of the 6-hourly for index, pop_tuple in enumerate(twelve_hour_pops): six_hour_index = index * 2 # Check the percent values self.assertEqual(pop_tuple[2], six_hour_pops[six_hour_index][2]) self.assertEqual(pop_tuple[2], six_hour_pops[six_hour_index+1][2]) # Check the start time self.assertEqual(pop_tuple[0], six_hour_pops[six_hour_index][0]) # Check that the end time is 6 hours difference minus_six_hours = pop_tuple[1] - datetime.timedelta(hours=6) self.assertEqual(six_hour_pops[six_hour_index][1], minus_six_hours) self.assertEqual(six_hour_pops[six_hour_index+1][0], minus_six_hours) def test_daylight_savings(self): """ We can have time periods that don't match up because of daylight savings changes """ root = self.dwml_parser._parse_xml_response_into_doc(self.dst_xml_response) layouts = self.dwml_parser._construct_time_layouts(root) snow = self.dwml_parser._get_hourly_snow(root, layouts) pops = self.dwml_parser._get_12hourly_probabilities(root, layouts) number_items = min(len(snow), len(pops)) # Check the pops and snow elements to see if their start times match. They # won't, so make sure that one is off by an hour for dst for index in range(number_items): try: if not snow[index * 2][0] == pops[index][0]: hours_diff = (pops[index][0] - snow[index * 2][0]).total_seconds() / 60 / 60 self.assertEqual(hours_diff, 1.0) except IndexError: pass
LOGGER.critical('Error! No text forecasts returned.') sys.exit() ### Step 2: Get the forecast data from the NOAA XML API xml_url = "http://graphical.weather.gov/xml/sample_products/" xml_url += "browser_interface/ndfdXMLclient.php?" xml_url += "whichClient=NDFDgen&product=time-series" xml_url += "&lat=%.2f&lon=%.2f" % (LAT, LNG) xml_url += "&Unit=e" xml_url += "&qpf=qpf" xml_url += "&snow=snow" xml_url += "&pop12=pop12" dwml_parser = ForecastDWMLParser(LOGGER) xml_response = dwml_parser.fetch_api_xml(xml_url) try: forecast = dwml_parser.parse_forecast_response(xml_response) LOGGER.debug('XML forecasts were parsed successfully') except ForecastParserException, exception: LOGGER.critical('Error parsing XML: Exception: %s' % exception) sys.exit() ### Part 3: Figure out the answer to 'Will it snow?' # Count how many text forecasts have snow/flurries mentioned in them snow_count = [tf for tf in text_forecasts if tf.has_snow == True]