pythontwitterraiserrorraiseerror

raising and catching exceptions in class


The code i struggle with is originally in the mainclass - and works just fine! I got it out of book and used it a couple of times! I tried to change it so that it runs in its own class "twitter_data". But for some reason the function "handle_twitter_http_error" doesnt work as it used to...it just doesnt catch the error anymore...! Im pretty sure it has something to do with the new class structure, of which I have really bad knowledge so far!

Here is the code:

import twitter
import sys
import time
from urllib2 import URLError
from httplib import BadStatusLine
import json
from functools import partial
from sys import maxint
from six import string_types
from datetime import datetime
from datetime import timedelta

class twitter_data:

    def __init__(self):
        self.twitter_api = self.oauth_login()

    def oauth_login(self):
        CONSUMER_KEY = 'KEY'
        CONSUMER_SECRET = 'SECRET'
        OAUTH_TOKEN = 'TOKEN'
        OAUTH_TOKEN_SECRET = 'TOKEN_SECRET'
        auth = twitter.oauth.OAuth(OAUTH_TOKEN,OAUTH_TOKEN_SECRET,CONSUMER_KEY,CONSUMER_SECRET)
        twitter_api=twitter.Twitter(auth=auth)
        return twitter_api

    def handle_twitter_http_error(self,e, wait_period=2, sleep_when_rate_limited=True):
            if wait_period > 3600:
                print >> sys.stderr, 'Too many retries. Quitting'
                raise e

            if e.e.code == 401:
                print >> sys.stderr, 'Encountered 401 Error (Not Authorized)'
                return None

            if e.e.code == 404:
                print >> sys.stderr, 'Encountered 404 Error (Not Found)'
                return None

            elif e.e.code == (429,420):
                print >> sys.stderr, 'Encountered 429/420 Error (Rate Limit Exceeded)',sleep_when_rate_limited
                if sleep_when_rate_limited:
                    print >> sys.stderr, 'Retrying in 15 minutes'
                    sys.stderr.flush()
                    time.sleep(60*15+5)
                    print >>sys.stderr, 'Awake now and retrying'
                    return 2
                else:
                    raise e

            elif e.e.code == (500,502,503,504):
                print >> sys.stderr, 'Encountered %i Error. Retrying in %i seconds' %(e.e.code, wait_period)
                time.sleep(wait_period)
                wait_period *= 1.5
                return wait_period
            else:
                raise e


    def make_twitter_request(self,twitter_api_func,max_errors=10,*args, **kw):
        wait_period = 2
        error_count =0

        while True:
            try:
                return twitter_api_func(*args, **kw)
            except twitter.api.TwitterHTTPError, e:
                error_count = 0
                wait_period = self.handle_twitter_http_error(e,wait_period)
                if wait_period is None:
                    return

            except URLError, e:
                error_count +=1
                print >> sys.stderr, 'URLError encountered. Continuing.'
                if error_count > max_errors:
                    print >> sys.stderr, 'Too many errors...bailing out.'
                    raise

            except BadStatusLine, e:
                error_count +=1
                print >> sys.stderr, 'BadStatusLine encountered. Continuing.'
                if error_count > max_errors:
                    print >> sys.stderr, 'Too many consecutive errors...bailing out.'
                    raise


    def get_friends_followers_ids(self, screen_name=None, user_id=None, friends_limit=maxint, followers_limit=maxint):

        assert (screen_name != None) != (user_id != None), \
        "Must have screen_name or user_id, but not both"

        get_friends_ids = partial(self.make_twitter_request, self.twitter_api.friends.ids, 
                                  count=5000)
        get_followers_ids = partial(self.make_twitter_request, self.twitter_api.followers.ids, 
                                    count=5000)

        friends_ids, followers_ids = [], []

        for twitter_api_func, limit, ids, label in [
                        [get_friends_ids, friends_limit, friends_ids, "friends"], 
                        [get_followers_ids, followers_limit, followers_ids, "followers"]
                    ]:

            if limit == 0: continue

            cursor = -1
            while cursor != 0:


                if screen_name: 
                    response = twitter_api_func(screen_name=screen_name, cursor=cursor)
                else:
                    response = twitter_api_func(user_id=user_id, cursor=cursor)

                if response is not None:
                    ids += response['ids']
                    cursor = response['next_cursor']

                print >> sys.stderr, 'Fetched {0} total {1} ids for {2}'.format(len(ids), 
                                                        label, (user_id or screen_name))

                if len(ids) >= limit or response is None:
                    break
        return friends_ids[:friends_limit], followers_ids[:followers_limit]

Then i use this code to run it:

td = twitter_data()
td.get_friends_followers_ids(screen_name = 'Madonna')

And this is what i get as an error:

---------------------------------------------------------------------------
TwitterHTTPError                          Traceback (most recent call last)
<ipython-input-35-420d4a0a4512> in <module>()
----> 1 td.get_friends_followers_ids(screen_name = 'Madonna')

<ipython-input-29-d4275257b38f> in get_friends_followers_ids(self, screen_name, user_id, friends_limit, followers_limit)
    174 
    175                                 if screen_name:
--> 176                                         response = twitter_api_func(screen_name=screen_name, cursor=cursor)
    177                                 else:
    178                                         response = twitter_api_func(user_id=user_id, cursor=cursor)

<ipython-input-29-d4275257b38f> in make_twitter_request(self, twitter_api_func, max_errors, *args, **kw)
     68                         except twitter.api.TwitterHTTPError, e:
     69                                 error_count = 0
---> 70                                 wait_period = self.handle_twitter_http_error(e,wait_period)
     71                                 if wait_period is None:
     72                                         return

<ipython-input-29-d4275257b38f> in handle_twitter_http_error(self, e, wait_period, sleep_when_rate_limited)
     55                                 return wait_period
     56                         else:
---> 57                                 raise e
     58 
     59 

TwitterHTTPError: Twitter sent status 429 for URL: 1.1/followers/ids.json using parameters: (count=5000&cursor=-1&oauth_consumer_key=o92R2ryg511yw6yK0zXwHBk4Z&oauth_nonce=8966871855796102181&oauth_signature_method=HMAC-SHA1&oauth_timestamp=1440000524&oauth_token=3013233011-jzjcfNa4D5m08k1TbWHeekl9h7Yt9Mu9U6jEPqv&oauth_version=1.0&screen_name=Madonna&oauth_signature=z8mD3kbclM5UOXTbB2E1VguSxHU%3D)
details: {"errors":[{"message":"Rate limit exceeded","code":88}]}

Thanks you all for help on this!

Update:

i did a "print debug" and asked it to "print e.e.code", this is what i got:

td.get_friends_followers_ids(screen_name='Madonna')
429
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "testdriver.py", line 113, in get_friends_followers_ids
    response = twitter_api_func(screen_name=screen_name, cursor=cursor)
  File "testdriver.py", line 70, in make_twitter_request
    wait_period = self.handle_twitter_http_error(e,wait_period)
  File "testdriver.py", line 58, in handle_twitter_http_error
    raise e
twitter.api.TwitterHTTPError: Twitter sent status 429 for URL: 1.1/followers/ids.json using parameters: (count=5000&cursor=1507581380542740144&oauth_consumer_key=o92R2ryg511yw6yK0zXwHBk4Z&oauth_nonce=4075478308692875785&oauth_signature_method=HMAC-SHA1&oauth_timestamp=1440078685&oauth_token=3013233011-jzjcfNa4D5m08k1TbWHeekl9h7Yt9Mu9U6jEPqv&oauth_version=1.0&screen_name=Madonna&oauth_signature=zZRpNFAQGR1IWcVSwK0dAFOJMuk%3D)
details: {"errors":[{"message":"Rate limit exceeded","code":88}]}

So it does contain the information of e.e.code, but does not catch it for some reason!!


Solution

  • I finally figured it out: Thanks Grysik for the idea with the

    e.e.code in (429,420)
    

    Solution totally works! Thanks