def test_query_string_parse(self): """ Test parsing query strings, as used by the supybot plugin and (for city parsing) the command-line interface. """ result = climate.parse_text_query("Toronto march".split()) self.assertEqual(result["cities"], ["Toronto"]) self.assertEqual(result["months"][2], True) self.assertEqual(result["months"][1], False) result = climate.parse_text_query("mar high r-low".split()) self.assertEqual(result["categories"]["high C"], True) self.assertEqual(result["categories"]["record low C"], True) self.assertEqual(result["months"][2], True) self.assertEqual(result["cities"], []) result = climate.parse_text_query("low seattle hamilton New Zealand portland, or mar".split()) self.assertEqual(result["categories"]["low C"], True) self.assertEqual(result["months"][2], True) self.assertEqual(result["cities"], ["Seattle", "Hamilton, New Zealand", "Portland, Or"]) result = climate.parse_text_query( ("washington dc march albuquerque new mexico " + "high low seattle washington").split() ) self.assertEqual(result["categories"]["high C"], True) self.assertEqual(result["categories"]["low C"], True) self.assertEqual(result["months"][2], True) self.assertEqual(result["cities"], ["Washington Dc", "Albuquerque", "Seattle"])
def test_space_in_query_string(self): """ Test that localities with spaces, possibly multiple spaces, in the name are handled correctly. Examples: Washington, DC; Albuquerque, New Mexico; Hamilton, New Zealand """ result = climate.parse_text_query("Washington D.C. Toronto Elmira, Ontario Seattle".split()) self.assertEqual(result["cities"], ["Washington D.C.", "Toronto", "Seattle"]) result = climate.parse_text_query("Hamilton, New Zealand".split()) self.assertEqual(result["cities"], ["Hamilton, New Zealand"]) result = climate.parse_text_query("Washington, District of Columbia Toronto Ontario".split()) self.assertEqual(result["cities"], ["Washington, District Of Columbia", "Toronto"]) result = climate.parse_text_query("Washington, D.C. Toronto Hamilton New Zealand Seattle Washington".split()) self.assertEqual(result["cities"], ["Washington, D.C.", "Toronto", "Hamilton, New Zealand", "Seattle"]) result = climate.parse_text_query("Washington, D.C. Toronto Elmira, New Zealand Seattle Washington".split()) self.assertEqual(result["cities"], ["Washington, D.C.", "Toronto", "Seattle"])
def get(self, irc, msg, args, strings): """ <text> (including <places>, <months>, <categories>) Gets climate data for <places> during <months> for <categories>. Normally at least one each of place and month are required, except script will pick most contrasting month if two cities are given. Category will default to average high temperature if not specified. Get the list of recognized <categories> with `@climate categories`. Places, months, and categories can be mixed within <text> in any order. Unrecognized words will be silently ignored (this means you can write e.g. "Toronto and Sydney high for December"). """ import climate query = climate.parse_text_query(strings) cities = query['cities'] months = query['months'] categories = query['categories'] has_category = False has_month = False for month in months: has_month = has_month or month for category in categories: has_category = has_category or categories[category] if has_category is False: # default to showing high temperature if no category is specified categories['high C'] = True has_category = True if has_month is True: data = climate.get_comparison_data(cities, months, categories) elif len(cities) == 2: # get data for all, and pick most interesting one automagically # criterion is biggest difference between the numerical values # among chosen categories for the chosen cities # for now only two cities are supported # TODO: expand to arbitrary amount - will need to round-robin # the calculations or something for i in range(len(months)): months[i] = True data = climate.get_comparison_data(cities, months, categories) # get cities' names directly from data - they are likely # different than in request (capitalization, redirects, etc) data_cities = data[data.keys()[0]].keys() comparisons = {} sums = {} for i in range(len(data_cities)): city = data_cities[i] for category,category_include in categories.items(): if not category_include: continue if category == 'location': # only non-numerical 'category' so far. cannot # be compared. detect this case more robustly if we # get more non-numerical categories continue if category not in comparisons: comparisons[category] = {} sums[category] = [] for month,month_include in enumerate(months): if not month_include: continue if not month in comparisons[category]: comparisons[category][month] = {} comparisons[category][month][city] = \ data[month][city][category] if i > 0: for m,dummy_var in enumerate(months): # calculate difference between the two cities for # each month # order within sums[category] list will be created # automagically sums[category].append(abs( \ comparisons[category][m][data_cities[i-1]] - \ comparisons[category][m][data_cities[i]])) max_month = -1 max_value = float('-inf') for category in categories: if category in sums: category_max = max(sums[category]) category_index = sums[category].index(category_max) if category_max > max_value: max_value = category_max max_month = category_index filtered_data = {} if max_month > -1: filtered_data[max_month] = data[max_month] data = filtered_data else: # not supported, return empty data = {} # output format is roughly: """October: Toronto high 10, Melbourne high 20; April: Toronto high 10, Melbourne high 15 October: Toronto high 10, low 5, Melbourne high 20, low 12; April: Toronto high 10, low 3, Melbourne high 15, low 8""" # so each month first, then each city with its categories grouped output = [] for month,month_data in data.items(): month_line = calendar.month_name[month+1] + ': ' city_lines = [] for city,city_data in month_data.items(): city_line = city + ' ' category_lines = [] for category,category_data in city_data.items(): if category in climate.PRINTED_ROW_TITLES: category_lines.append( climate.PRINTED_ROW_TITLES[category] + ' ' + str(int(round(category_data, 0)))) city_line += ', '.join(category_lines) city_lines.append(city_line) month_line += ', '.join(city_lines) output.append(month_line) output = '; '.join(output) response = '' if len(output) > 0: response = output elif len(cities) == 1 and 'location' in categories \ and categories['location'] == True: data = climate.get_climate_data(cities[0]) if 'location' in data and len(data['location']) > 0: response = data['title'] + ': ' + data['location'] if len(response) == 0: response = 'No data found or invalid query. Try @help climate get.' irc.reply(response.encode('utf-8'), prefixNick = False)