bear / python-twitter

A Python wrapper around the Twitter API.
Apache License 2.0
3.41k stars 954 forks source link

api fails if login credentials are variables #437

Closed neonfuzz closed 7 years ago

neonfuzz commented 7 years ago

Tried to e.g. api.CreateFriendship(screen_name=u'scienmag') or api.CreateFriendship(user_id=2782211491)

and received the following error each time:

---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
<ipython-input-4-4c917bc7ec14> in <module>()
----> 1 api.CreateFriendship(screen_name=u'scienmag')

/usr/lib/python2.7/site-packages/twitter/api.pyc in CreateFriendship(self, user_id, screen_name, follow)
   3099           A twitter.User instance representing the befriended user.
   3100         """
-> 3101         return self._AddOrEditFriendship(user_id=user_id, screen_name=screen_name, follow=follow)
   3102 
   3103     def _AddOrEditFriendship(self, user_id=None, screen_name=None, uri_end='create', follow_key='follow', follow=True):

/usr/lib/python2.7/site-packages/twitter/api.pyc in _AddOrEditFriendship(self, user_id, screen_name, uri_end, follow_key, follow)
   3117         data['{}'.format(follow_key)] = follow_json
   3118 
-> 3119         resp = self._RequestUrl(url, 'POST', data=data)
   3120         data = self._ParseAndCheckTwitter(resp.content.decode('utf-8'))
   3121 

/usr/lib/python2.7/site-packages/twitter/api.pyc in _RequestUrl(self, url, verb, data, json)
   4911 
   4912         if url and self.sleep_on_rate_limit:
-> 4913             limit = self.CheckRateLimit(url)
   4914 
   4915             if limit.remaining == 0:

/usr/lib/python2.7/site-packages/twitter/api.pyc in CheckRateLimit(self, url)
   4766         """
   4767         if not self.rate_limit.__dict__.get('resources', None):
-> 4768             self.InitializeRateLimit()
   4769 
   4770         if url:

/usr/lib/python2.7/site-packages/twitter/api.pyc in InitializeRateLimit(self)
   4748         url = '%s/application/rate_limit_status.json' % self.base_url
   4749 
-> 4750         resp = self._RequestUrl(url, 'GET')  # No-Cache
   4751         data = self._ParseAndCheckTwitter(resp.content.decode('utf-8'))
   4752 

/usr/lib/python2.7/site-packages/twitter/api.pyc in _RequestUrl(self, url, verb, data, json)
   4938             data['tweet_mode'] = self.tweet_mode
   4939             url = self._BuildUrl(url, extra_params=data)
-> 4940             resp = requests.get(url, auth=self.__auth, timeout=self._timeout)
   4941 
   4942         else:

/usr/lib/python2.7/site-packages/requests/api.pyc in get(url, params, **kwargs)
     68 
     69     kwargs.setdefault('allow_redirects', True)
---> 70     return request('get', url, params=params, **kwargs)
     71 
     72 

/usr/lib/python2.7/site-packages/requests/api.pyc in request(method, url, **kwargs)
     54     # cases, and look like a memory leak in others.
     55     with sessions.Session() as session:
---> 56         return session.request(method=method, url=url, **kwargs)
     57 
     58 

/usr/lib/python2.7/site-packages/requests/sessions.pyc in request(self, method, url, params, data, headers, cookies, files, auth, timeout, allow_redirects, proxies, hooks, stream, verify, cert, json)
    472             hooks = hooks,
    473         )
--> 474         prep = self.prepare_request(req)
    475 
    476         proxies = proxies or {}

/usr/lib/python2.7/site-packages/requests/sessions.pyc in prepare_request(self, request)
    405             auth=merge_setting(auth, self.auth),
    406             cookies=merged_cookies,
--> 407             hooks=merge_hooks(request.hooks, self.hooks),
    408         )
    409         return p

/usr/lib/python2.7/site-packages/requests/models.pyc in prepare(self, method, url, headers, files, data, params, auth, cookies, hooks, json)
    304         self.prepare_cookies(cookies)
    305         self.prepare_body(data, files, json)
--> 306         self.prepare_auth(auth, url)
    307 
    308         # Note that prepare_auth must be last to enable authentication schemes

/usr/lib/python2.7/site-packages/requests/models.pyc in prepare_auth(self, auth, url)
    525 
    526             # Allow auth to make its changes.
--> 527             r = auth(self)
    528 
    529             # Update self to reflect the auth changes.

/usr/lib/python2.7/site-packages/requests_oauthlib/oauth1_auth.pyc in __call__(self, r)
     86             # Omit body data in the signing of non form-encoded requests
     87             r.url, headers, _ = self.client.sign(
---> 88                 unicode(r.url), unicode(r.method), None, r.headers)
     89 
     90         r.prepare_headers(headers)

/usr/lib/python2.7/site-packages/oauthlib/oauth1/rfc5849/__init__.pyc in sign(self, uri, http_method, body, headers, realm)
    311         # generate the signature
    312         request.oauth_params.append(
--> 313             ('oauth_signature', self.get_oauth_signature(request)))
    314 
    315         # render the signed request and return it

/usr/lib/python2.7/site-packages/oauthlib/oauth1/rfc5849/__init__.pyc in get_oauth_signature(self, request)
    126                                             self.resource_owner_secret)
    127 
--> 128         uri, headers, body = self._render(request)
    129 
    130         collected_params = signature.collect_parameters(

/usr/lib/python2.7/site-packages/oauthlib/oauth1/rfc5849/__init__.pyc in _render(self, request, formencode, realm)
    208         if self.signature_type == SIGNATURE_TYPE_AUTH_HEADER:
    209             headers = parameters.prepare_headers(
--> 210                 request.oauth_params, request.headers, realm=realm)
    211         elif self.signature_type == SIGNATURE_TYPE_BODY and request.decoded_body is not None:
    212             body = parameters.prepare_form_encoded_body(

/usr/lib/python2.7/site-packages/oauthlib/oauth1/rfc5849/utils.pyc in wrapper(params, *args, **kwargs)
     29     def wrapper(params, *args, **kwargs):
     30         params = filter_oauth_params(params)
---> 31         return target(params, *args, **kwargs)
     32 
     33     wrapper.__doc__ = target.__doc__

/usr/lib/python2.7/site-packages/oauthlib/oauth1/rfc5849/parameters.pyc in prepare_headers(oauth_params, headers, realm)
     55         # .. _`Section 3.6`: http://tools.ietf.org/html/rfc5849#section-3.6
     56         escaped_name = utils.escape(oauth_parameter_name)
---> 57         escaped_value = utils.escape(value)
     58 
     59         # 2.  Each parameter's name is immediately followed by an "=" character

/usr/lib/python2.7/site-packages/oauthlib/oauth1/rfc5849/utils.pyc in escape(u)
     54     if not isinstance(u, unicode_type):
     55         raise ValueError('Only unicode objects are escapable. ' +
---> 56                          'Got %s of type %s.' % (u, type(u)))
     57     # Letters, digits, and the characters '_.-' are already treated as safe
     58     # by urllib.quote(). We need to add '~' to fully support rfc5849.

ValueError: Only unicode objects are escapable. Got <generator object <genexpr> at 0x7f4d9959d730> of type <type 'generator'>.
neonfuzz commented 7 years ago

Update:

I've narrowed this down to how I sign into the api. If I use:

api = twitter.Api(
    consumer_key='XXXXXXXXXXXXXXXXXXXXXXXXX',
    consumer_secret='XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX',
    access_token_key='XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX',
    access_token_secret='XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX')

then the application works fine.

However, if I sign in using:

CONSUMER_KEY='XXXXXXXXXXXXXXXXXXXXXXXXX'
CONSUMER_SECRET='XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'
ACCESS_TOKEN_KEY='XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'
ACCESS_TOKEN_SECRET='XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'

api = twitter.Api(
    consumer_key=CONSUMER_KEY,
    consumer_secret=CONSUMER_SECRET,
    access_token_key=ACCESS_TOKEN_KEY,
    access_token_secret=ACCESS_TOKEN_SECRET)

then any api call I make will fail with the above error.

jeremylow commented 7 years ago

I cannot reproduce. Can you share the exact code that you're using?

neonfuzz commented 7 years ago

Minimum working example that still gives me an error:


import twitter

CONSUMER_KEY='XXXXXXXXXXXXXXXXXXXXXXXXX',
CONSUMER_SECRET='XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX',
ACCESS_TOKEN_KEY='XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX',
ACCESS_TOKEN_SECRET='XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX',

class Scraper(object):
    def __init__(self):
        self.api = twitter.Api(
            consumer_key=CONSUMER_KEY,
            consumer_secret=CONSUMER_SECRET,
            access_token_key=ACCESS_TOKEN_KEY,
            access_token_secret=ACCESS_TOKEN_SECRET,
            sleep_on_rate_limit=True)
        self.followers = None

    def scrape(self):
        self.followers = self.api.GetFollowers()

if __name__ == '__main__':
    scraper = Scraper()
    scraper.scrape()
jeremylow commented 7 years ago

Don't put commas after your variable initialization. 😄

neonfuzz commented 7 years ago

copy/paste fail Thanks for catching my brain fart.

jeremylow commented 7 years ago

No problem; just glad we got it sorted out. Good luck!