def main(path): """ Main function called when starting weatherBot. The path is to the configuration file. :type path: str :param path: path to configuration file """ # pylint: disable=broad-except,no-member global CACHE load_config(os.path.abspath(path)) initialize_logger(CONFIG['log']['enabled'], CONFIG['log']['log_path']) logging.debug(CONFIG) keys.set_twitter_env_vars() keys.set_darksky_env_vars() CACHE['throttles']['default'] = pytz.utc.localize(datetime.utcnow()).astimezone(pytz.utc) with open(CONFIG['basic']['strings'], 'r') as file_stream: try: weatherbot_strings = yaml.safe_load(file_stream) logging.debug(weatherbot_strings) wb_string = models.WeatherBotString(weatherbot_strings) except yaml.YAMLError as err: logging.error(err, exc_info=True) logging.error('Could not read YAML file, please correct, run yamllint, and try again.') exit() location = CONFIG['default_location'] updated_time = utils.datetime_to_utc('UTC', datetime.utcnow()) - timedelta(minutes=30) try: while True: # check for new location every 30 minutes now_utc = utils.datetime_to_utc('UTC', datetime.utcnow()) if CONFIG['variable_location']['enabled'] and updated_time + timedelta(minutes=30) < now_utc: location = get_location_from_user_timeline(CONFIG['variable_location']['user'], location) updated_time = now_utc forecast = get_forecast_object(location.lat, location.lng, CONFIG['basic']['units'], wb_string.language) if forecast is not None: weather_data = models.WeatherData(forecast, location) if weather_data.valid: CACHE = get_cache() tweet_logic(weather_data, wb_string) CACHE['throttles'] = cleanse_throttles(CACHE['throttles'], now_utc) set_cache(CACHE) time.sleep(CONFIG['basic']['refresh'] * 60) else: time.sleep(60) except Exception as err: logging.error(err) logging.error('We got an exception!', exc_info=True) if CONFIG['basic']['dm_errors']: api = get_tweepy_api() api.send_direct_message(screen_name=api.me().screen_name, text=str(random.randint(0, 9999)) + traceback.format_exc())
def test_datetime_to_utc(self): """Testing localize a normal datetime object to timezone id, then convert to UTC""" dt = datetime.datetime.fromtimestamp(1461738535) # datetime.datetime(2016, 4, 27, 1, 28, 55) timezone_id = 'Europe/Copenhagen' utc_dt = utils.datetime_to_utc(timezone_id, dt) correct_dt = pytz.timezone('Europe/Copenhagen').localize(dt).astimezone(pytz.utc) self.assertEqual(utc_dt, correct_dt)
def tweet_logic(weather_data, wb_string): """ Core logic for tweets once initialization and configuration has been set and weather data fetched. :type weather_data: models.WeatherData :type wb_string: models.WeatherBotString """ # pylint: disable=global-variable-not-assigned # CACHE is being modified here, pylint doesn't see that global CACHE wb_string.set_weather(weather_data) special = wb_string.special() normal_text = wb_string.normal() now = datetime.utcnow() now_utc = utils.datetime_to_utc('UTC', now) now_local = utils.localize_utc_datetime(weather_data.timezone, now) # weather alerts for alert in weather_data.alerts: if alert.sha() not in CACHE['throttles'] and not alert.expired(now_utc): try: CACHE['throttles'][alert.sha()] = alert.expires except AttributeError: # most alerts are probably done after 3 days CACHE['throttles'][alert.sha()] = alert.time + timedelta(days=3) do_tweet(wb_string.alert(alert, weather_data.timezone), weather_data.location, CONFIG['basic']['tweet_location'], CONFIG['variable_location']['enabled'], hashtag=CONFIG['basic']['hashtag']) # forecast forecast_dt = now_local.replace(hour=CONFIG['scheduled_times']['forecast'].hour, minute=CONFIG['scheduled_times']['forecast'].minute, second=0, microsecond=0).astimezone(pytz.utc) timed_tweet(forecast_dt, now_utc, wb_string.forecast(), weather_data.location) # scheduled tweet for scheduled_time in CONFIG['scheduled_times']['conditions']: scheduled_dt = now_local.replace(hour=scheduled_time.hour, minute=scheduled_time.minute, second=0, microsecond=0).astimezone(pytz.utc) timed_tweet(scheduled_dt, now_utc, normal_text, weather_data.location) # special condition if special.type != 'normal': logging.debug('Special event') try: next_allowed = CACHE['throttles'][special.type] except KeyError: next_allowed = CACHE['throttles']['default'] if now_utc >= next_allowed: try: minutes = CONFIG['throttles'][special.type] except KeyError: minutes = CONFIG['throttles']['default'] do_tweet(special.text, weather_data.location, CONFIG['basic']['tweet_location'], CONFIG['variable_location']['enabled'], hashtag=CONFIG['basic']['hashtag']) CACHE['throttles'][special.type] = now_utc + timedelta(minutes=minutes) logging.debug(CACHE)
def tweet_logic(weather_data, wb_string): """ Core logic for tweets once initialization and configuration has been set and weather data fetched. :type weather_data: models.WeatherData :type wb_string: models.WeatherBotString """ # pylint: disable=global-variable-not-assigned # CACHE is being modified here, pylint doesn't see that global CACHE wb_string.set_weather(weather_data) logging.debug(wb_string.__dict__()) special = wb_string.special() normal_text = wb_string.normal() now = datetime.utcnow() now_utc = utils.datetime_to_utc('UTC', now) now_local = utils.localize_utc_datetime(weather_data.timezone, now) # weather alerts for alert in weather_data.alerts: if alert.sha() not in CACHE['throttles'] and not alert.expired(now_utc): local_expires_time = alert.expires.astimezone(pytz.timezone(weather_data.timezone)) CACHE['throttles'][alert.sha()] = alert.expires do_tweet(wb_string.alert(alert.title, local_expires_time, alert.uri), weather_data.location, CONFIG['basic']['tweet_location'], CONFIG['variable_location']['enabled'], hashtag=CONFIG['basic']['hashtag']) # forecast forecast_dt = now_local.replace(hour=CONFIG['scheduled_times']['forecast'].hour, minute=CONFIG['scheduled_times']['forecast'].minute, second=0, microsecond=0).astimezone(pytz.utc) timed_tweet(forecast_dt, now_utc, wb_string.forecast(), weather_data.location) # scheduled tweet for scheduled_time in CONFIG['scheduled_times']['conditions']: scheduled_dt = now_local.replace(hour=scheduled_time.hour, minute=scheduled_time.minute, second=0, microsecond=0).astimezone(pytz.utc) timed_tweet(scheduled_dt, now_utc, normal_text, weather_data.location) # special condition if special.type != 'normal': logging.debug('Special event') try: next_allowed = CACHE['throttles'][special.type] except KeyError: next_allowed = CACHE['throttles']['default'] if now_utc >= next_allowed: try: minutes = CONFIG['throttles'][special.type] except KeyError: minutes = CONFIG['throttles']['default'] do_tweet(special.text, weather_data.location, CONFIG['basic']['tweet_location'], CONFIG['variable_location']['enabled'], hashtag=CONFIG['basic']['hashtag']) CACHE['throttles'][special.type] = now_utc + timedelta(minutes=minutes) logging.debug(CACHE)