Esempio n. 1
0
    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)
Esempio n. 2
0
    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)
Esempio n. 3
0
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)
Esempio n. 4
0
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
Esempio n. 5
0
        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]