def validate_tweet(self, tweet): """ Check to see if a Tweet is valid (i.e. we want to reply to it), and returns True if so Tweets from ourselves, and mentions that are not directly addressed to us, returns False """ message = tweet.text # Bit of logging, plus we always return True for DMs if is_direct_message(tweet): logging.info("Have a DM from %s: %s", tweet.sender.screen_name, message) return True else: username = tweet.user.screen_name logging.info("Have an @ reply from %s: %s", username, message) # Don't start talking to yourself if username == self.username: logging.debug("Not talking to myself, that way madness lies") return False # Ignore mentions that are not direct replies if not message.lower().startswith('@%s' % self.username.lower()): logging.debug("Not a proper @ reply, skipping") return False return True
def alert_admin_about_exception(self, tweet, exception_name): """ Alert the administrator about a non-WhensMyTransportException encountered when processing a Tweet """ if is_direct_message(tweet): tweet_time = tweet.created_at.strftime('%d-%m-%y %H:%M:%S') error_message = "Hey! A DM from @%s at %s GMT caused me to crash with a %s" % (tweet.sender.screen_name, tweet_time, exception_name) else: twitter_permalink = "https://twitter.com/#!/%s/status/%s" % (tweet.user.screen_name, tweet.id) error_message = "Hey! A tweet from @%s caused me to crash with a %s: %s" % (tweet.user.screen_name, exception_name, twitter_permalink) self.twitter_client.send_reply_back(error_message, self.admin_name, True)
def check_tweets(self): """ Check incoming Tweets, and reply to them """ tweets = self.twitter_client.fetch_tweets() logging.debug("%s Tweets to process", len(tweets)) for tweet in tweets: # If the Tweet is not valid (e.g. not directly addressed, from ourselves) then skip it if not self.validate_tweet(tweet): continue # Try processing the Tweet. This may fail with a WhensMyTransportException for a number of reasons, in which # case we catch the exception and process an apology accordingly. Other Python Exceptions may occur too - we handle # these by DMing the admin with an alert try: replies = self.process_tweet(tweet) except WhensMyTransportException as exc: replies = (exc.get_user_message(),) except Exception as exc: logging.error("Exception encountered: %s", exc.__class__.__name__) logging.error("Traceback:\r\n%s" % traceback.format_exc()) self.alert_admin_about_exception(tweet, exc.__class__.__name__) replies = (WhensMyTransportException('unknown_error').get_user_message(),) # If the reply is blank, probably didn't contain a bus number or Tube line, so check to see if there was a thank-you if not replies: replies = self.check_politeness(tweet) # Send a reply back, if we have one. DMs and @ replies have different structures and different handlers for reply in replies: if is_direct_message(tweet): self.twitter_client.send_reply_back(reply, tweet.sender.screen_name, True, tweet.id) else: self.twitter_client.send_reply_back(reply, tweet.user.screen_name, False, tweet.id) self.twitter_client.check_followers()