def test_get_location_from_user_timeline_place(self): """Testing getting a location from twitter account's recent tweets using the place bounding box""" fallback_loc = models.WeatherLocation(4, 3, 'test') test_loc = models.WeatherLocation(5.0, 4.0, 'cool place') loc = weatherBot.get_location_from_user_timeline('nocoords', fallback_loc) self.assertTrue(type(loc) is models.WeatherLocation) self.assertEqual(loc, test_loc)
def test_get_location_from_user_timeline_coordinates(self): """Testing getting a location from twitter account's recent tweets using the coordinates property""" fallback_loc = models.WeatherLocation(4, 3, 'test') test_loc = models.WeatherLocation(2, 1, 'test') loc = weatherBot.get_location_from_user_timeline('MorrisMNWeather', fallback_loc) self.assertTrue(type(loc) is models.WeatherLocation) self.assertEqual(loc, test_loc)
def test_get_location_from_user_timeline(self): """Testing getting a location from twitter account's recent tweets""" fallback = models.WeatherLocation(55.76, 12.49, 'Lyngby-Taarbæk, Hovedstaden') morris = models.WeatherLocation(45.58605, -95.91405, 'Morris, MN') loc = weatherBot.get_location_from_user_timeline('MorrisMNWeather', fallback) self.assertTrue(type(loc) is models.WeatherLocation) self.assertEqual(loc, morris) self.assertEqual(weatherBot.get_location_from_user_timeline('twitter', fallback), fallback)
def test_get_location_from_user_timeline_coordinates_no_place_full_name(self): """Testing getting a location from twitter account's recent tweets using the coordinates property when a place does not exist for that location""" fallback_loc = models.WeatherLocation(4, 3, 'test') test_loc = models.WeatherLocation(2.5, 1.5, 'unnamed location') weatherBot.CONFIG['variable_location']['unnamed_location_name'] = 'unnamed location' loc = weatherBot.get_location_from_user_timeline('coordsnoplace', fallback_loc) self.assertTrue(type(loc) is models.WeatherLocation) self.assertEqual(loc, test_loc)
def get_location_from_user_timeline(username, fallback): """ Load the 20 most recent tweets of a given twitter handle and return a models.WeatherLocation object of the most recent location. This function will find a tweet with coordinates or a place, preferring coordinates. If a location is not found in the most recent 20 tweets, the given fallback location will be returned. :type username: str :param username: twitter username to follow :type fallback: models.WeatherLocation :param fallback: a fallback in case no location can be found :return: models.WeatherLocation """ api = get_tweepy_api() # gets the 20 most recent tweets from the given profile try: timeline = api.user_timeline(screen_name=username, include_rts=False, count=20) for tweet in timeline: # if tweet has coordinates (from a smartphone) if tweet.coordinates is not None: lat = tweet.coordinates['coordinates'][1] lng = tweet.coordinates['coordinates'][0] name = CONFIG['variable_location']['unnamed_location_name'] # sometimes a tweet contains a coordinate, but is not in a Twitter place # for example, https://twitter.com/BrianMitchL/status/982664157857271810 has coordinates, but no place if tweet.place is not None: name = tweet.place.full_name logging.debug('Found %s: %f, %f', name, lat, lng) return models.WeatherLocation(lat=lat, lng=lng, name=name) # if the location is a place, not coordinates if tweet.place is not None: point = utils.centerpoint( tweet.place.bounding_box.coordinates[0]) lat = point[0] lng = point[1] name = tweet.place.full_name logging.debug('Found the center of bounding box at %s: %f, %f', name, lat, lng) return models.WeatherLocation(lat=lat, lng=lng, name=name) # fallback to hardcoded location if there is no valid data logging.warning( 'Could not find tweet with location, falling back to hardcoded location' ) return fallback except tweepy.TweepError as err: logging.error(err) logging.warning( 'Could not find tweet with location, falling back to hardcoded location' ) return fallback
def test_get_location_from_user_timeline_empty(self): """Testing getting a location from twitter account's recent tweets when there are none""" fallback_loc = models.WeatherLocation(4, 3, 'test') self.assertEqual( weatherBot.get_location_from_user_timeline('no tweets', fallback_loc), fallback_loc)
def test_alerts(self): """Testing that alerts are loaded correctly into a list""" location = models.WeatherLocation(34.2, -118.36, 'Los Angeles, CA') forecast = forecastio.manual(os.path.join('fixtures', 'us_alert.json')) wd = models.WeatherData(forecast, location) self.assertEqual(wd.alerts[0].title, 'Wind Advisory') self.assertEqual(wd.alerts[1].title, 'Beach Hazards Statement') self.assertEqual(wd.alerts[2].title, 'Red Flag Warning')
def test_alert(self): """Testing that alerts are formatted""" wbs = models.WeatherBotString(self.weatherbot_strings) forecast = forecastio.manual(os.path.join('fixtures', 'ca_alert.json')) location = models.WeatherLocation(50.564167, -111.898889, 'Brooks, Alberta') wd = models.WeatherData(forecast, location) wbs.set_weather(wd) alert = wbs.alert(wd.alerts[0], wd.timezone) self.assertIn('Snowfall Warning', alert) self.assertIn('https://weather.gc.ca/warnings/report_e.html?ab6', alert)
def test_config(self): """Testing config file handling""" equal = { 'basic': { 'dm_errors': False, 'units': 'si', 'tweet_location': False, 'hashtag': '', 'refresh': 300, 'strings': 'fake_path.yml' }, 'scheduled_times': { 'forecast': utils.Time(hour=6, minute=0), 'conditions': [utils.Time(hour=7, minute=0), utils.Time(hour=12, minute=0), utils.Time(hour=15, minute=0), utils.Time(hour=18, minute=0), utils.Time(hour=22, minute=0)] }, 'default_location': models.WeatherLocation(-79.0, 12.0, 'Just a Test'), 'variable_location': { 'enabled': True, 'user': '******', 'unnamed_location_name': 'Somewhere in deep space' }, 'log': { 'enabled': False, 'log_path': '/tmp/weatherBotTest.log' }, 'throttles': { 'default': 24, 'wind-chill': 23, 'medium-wind': 22, 'heavy-wind': 21, 'fog': 20, 'cold': 19, 'hot': 18, 'dry': 17, 'heavy-rain': 16, 'moderate-rain': 15, 'light-rain': 14, 'very-light-rain': 13, 'heavy-snow': 12, 'moderate-snow': 11, 'light-snow': 10, 'very-light-snow': 9, 'heavy-sleet': 8, 'moderate-sleet': 7, 'light-sleet': 6, 'very-light-sleet': 5, 'heavy-hail': 4, 'moderate-hail': 3, 'light-hail': 2, 'very-light-hail': 1 } } conf = configparser.ConfigParser() conf['basic'] = { 'dm_errors': 'off', 'units': 'si', 'tweet_location': 'no', 'hashtag': '', 'refresh': '300', 'strings': 'fake_path.yml' } conf['scheduled times'] = { 'forecast': '6:00', 'conditions': '7:00\n12:00\n15:00\n18:00\n22:00' } conf['default location'] = { 'lat': '-79', 'lng': '12', 'name': 'Just a Test' } conf['variable location'] = { 'enabled': 'yes', 'user': '******', 'unnamed_location_name': 'Somewhere in deep space' } conf['log'] = { 'enabled': '0', 'log_path': '/tmp/weatherBotTest.log' } conf['throttles'] = { 'default': '24', 'wind-chill': '23', 'medium-wind': '22', 'heavy-wind': '21', 'fog': '20', 'cold': '19', 'hot': '18', 'dry': '17', 'heavy-rain': '16', 'moderate-rain': '15', 'light-rain': '14', 'very-light-rain': '13', 'heavy-snow': '12', 'moderate-snow': '11', 'light-snow': '10', 'very-light-snow': '9', 'heavy-sleet': '8', 'moderate-sleet': '7', 'light-sleet': '6', 'very-light-sleet': '5', 'heavy-hail': '4', 'moderate-hail': '3', 'light-hail': '2', 'very-light-hail': '1' } with open(os.getcwd() + '/weatherBotTest.conf', 'w') as configfile: conf.write(configfile) weatherBot.load_config(os.path.abspath('weatherBotTest.conf')) self.assertDictEqual(weatherBot.CONFIG, equal) os.remove(os.path.abspath('weatherBotTest.conf'))
def setUp(self): self.location = models.WeatherLocation(55.76, 12.49, 'Lyngby-Taarbæk, Hovedstaden')
def setUp(self): with open('strings.yml', 'r') as file_stream: self.weatherbot_strings = yaml.safe_load(file_stream) self.location = models.WeatherLocation(55.76, 12.49, 'Lyngby-Taarbæk, Hovedstaden')
def test_equality(self): """Testing equality comparisons""" location_same = models.WeatherLocation(self.lat, self.lng, self.name) self.assertEqual(self.location, location_same) location2 = models.WeatherLocation(20, 16, 'testing') self.assertNotEqual(self.location, location2)
def setUp(self): self.lat = 55.76 self.lng = 12.49 self.name = 'Lyngby-Taarbæk, Hovedstaden' self.location = models.WeatherLocation(self.lat, self.lng, self.name)
def load_config(path): """ Load the configuration file from path and set defaults if not given. The configuration is set to the CONFIG global variable. :type path: str :param path: path to the conf file """ global CONFIG conf = configparser.ConfigParser() conf.read(path) CONFIG = { 'basic': { 'dm_errors': conf['basic'].getboolean('dm_errors', True), 'units': conf['basic'].get('units', 'us'), 'tweet_location': conf['basic'].getboolean('tweet_location', True), 'hashtag': conf['basic'].get('hashtag', '#MorrisWeather'), 'refresh': conf['basic'].getint('refresh', 3), 'strings': conf['basic'].get('strings', 'strings.yml') }, 'scheduled_times': { 'forecast': utils.parse_time_string(conf['scheduled times'].get('forecast', '6:00')), 'conditions': utils.get_times(conf['scheduled times'].get('conditions', '7:00\n12:00\n15:00\n18:00\n22:00')) }, 'default_location': models.WeatherLocation(lat=conf['default location'].getfloat('lat', 45.585), lng=conf['default location'].getfloat('lng', -95.91), name=conf['default location'].get('name', 'Morris, MN')), 'variable_location': { 'enabled': conf['variable location'].getboolean('enabled', False), 'user': conf['variable location'].get('user', 'BrianMitchL') }, 'log': { 'enabled': conf['log'].getboolean('enabled', True), 'log_path': conf['log'].get('log_path', os.path.expanduser('~') + '/weatherBot.log') }, 'throttles': { 'default': conf['throttles'].getint('default', 120), 'wind-chill': conf['throttles'].getint('wind-chill', 120), 'medium-wind': conf['throttles'].getint('medium-wind', 180), 'heavy-wind': conf['throttles'].getint('heavy-wind', 120), 'fog': conf['throttles'].getint('fog', 180), 'cold': conf['throttles'].getint('cold', 120), 'hot': conf['throttles'].getint('hot', 120), 'dry': conf['throttles'].getint('dry', 120), 'heavy-rain': conf['throttles'].getint('heavy-rain', 60), 'moderate-rain': conf['throttles'].getint('moderate-rain', 60), 'light-rain': conf['throttles'].getint('light-rain', 90), 'very-light-rain': conf['throttles'].getint('very-light-rain', 120), 'heavy-snow': conf['throttles'].getint('heavy-snow', 60), 'moderate-snow': conf['throttles'].getint('moderate-snow', 60), 'light-snow': conf['throttles'].getint('light-snow', 90), 'very-light-snow': conf['throttles'].getint('very-light-snow', 120), 'heavy-sleet': conf['throttles'].getint('heavy-sleet', 45), 'moderate-sleet': conf['throttles'].getint('moderate-sleet', 60), 'light-sleet': conf['throttles'].getint('light-sleet', 90), 'very-light-sleet': conf['throttles'].getint('very-light-sleet', 120), 'heavy-hail': conf['throttles'].getint('heavy-hail', 15), 'moderate-hail': conf['throttles'].getint('moderate-hail', 15), 'light-hail': conf['throttles'].getint('light-hail', 20), 'very-light-hail': conf['throttles'].getint('very-light-hail', 30) } }