Spot any errors? let me know, but Unleash your pedant politely please.

Thursday 20 December 2012

Still feeling a bit stupid

I saw yesterday that requests v1.0 was out.  I revisited it in the hope that I wouldn't feel so stupid.

It still doesn't work for me. In a different way.  I tried the three signature types I think are available, but all are rejected by the server.

import requests
from requests_oauthlib import OAuth1

consumer_key        = u"that"
consumer_secret     = u"would"
access_token_key    = u"be"
access_token_secret = u"telling"
                                 
for signature_type in ('auth_header','body','query'):
    auth = OAuth1(client_key            = consumer_key,
                  client_secret         = consumer_secret,
                  resource_owner_key    = access_token_key,
                  resource_owner_secret = access_token_secret,
                  signature_type        = signature_type)
    
    r = requests.get(u'https://api.projectplace.com/1/user/me/profile.json', auth=auth)
    
    print signature_type
    print r.encoding
    print r.text
    print r.json

gives me

auth_header
ISO-8859-1
Could not properly validate "oauth_consumer_key".
>

body
ISO-8859-1
Could not properly validate "oauth_consumer_key".
>

query
ISO-8859-1
Could not properly validate "oauth_consumer_key".
>
administrators-macbook-pro-2:ProjectPlace (requests) bob$ 

Ho hum.
Being a bit lazy, I have some modules that I use that I haven't packaged. I just copy them from project to project.  One is a Java style properties thingamajig. (This is probably unPythonic, there are probably better versions of the same thing out there, but it works for me).  I have a small test in the __main__ that requires a file containing some test data.

Being a bit lazy, I got fed up of copying that test file. It occurred to me today that I should write the test file as part of the test and remove it afterwards.

Why didn't I think of this before?

if __name__ == '__main__':
    
    open('test.properties','w').write("""Param : This is a parameter value
                                          Multi Param  : multi parameter 1
                                         +Multi Param : multi parameter 2
                                         +Multi Param :  multi parameter 3""")
    
    test_properties = Properties('test.properties')
    assert test_properties.property('Param')=='This is a parameter value'
    assert test_properties.propertyAsList('Multi Param')==['multi parameter 1','multi parameter 2','multi parameter 3']
    os.remove('test.properties')


I guess the tests should be put into some kind of unit test framework, but I can't quite yet be arsed to figure that stuff out. If this horrifies you, please do point me in the right direction.

Monday 3 December 2012

Sometimes I feel stupid...

I thought I'd refactor my Python class for accessing Project Place via its REST API using the purportedly more human Requests. A bit of reading and a bit of prodding and poking suggests that when it comes to OAuth, everything sucks, including Requests.

After a bit of faffing with the refactoring, I yanked the bare minimum of code into a single file. No subroutines or classes. Not a single indent:


import requests

consumer_key        = "that"
consumer_secret     = "would"
access_token_key    = "be"
access_token_secret = "telling!"

auth = requests.auth.OAuth1(consumer_key,
                            consumer_secret,
                            access_token_key,
                            access_token_secret,
                            signature_type='auth_header')

r = requests.get('https://api.projectplace.com/1/user/me/profile.json', auth=auth)

For my trouble, I get:

Traceback (most recent call last):
  File "/Users/bob/Dropbox/Coding/Python/ProjectPlace (requests)/requests_test.py", line 19, in
    r = requests.get('https://api.projectplace.com/1/user/me/profile.json', auth=auth)
  File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/requests/api.py", line 65, in get
    return request('get', url, **kwargs)
  File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/requests/safe_mode.py", line 39, in wrapped
    return function(method, url, **kwargs)
  File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/requests/api.py", line 51, in request
    return session.request(method=method, url=url, **kwargs)
  File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/requests/sessions.py", line 241, in request
    r.send(prefetch=prefetch)
  File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/requests/models.py", line 521, in send
    r = self.auth(self)
  File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/requests/auth.py", line 102, in __call__
    unicode(r.full_url), unicode(r.method), r.data, r.headers)
  File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/requests/packages/oauthlib/oauth1/rfc5849/__init__.py", line 213, in sign
    request.oauth_params.append((u'oauth_signature', self.get_oauth_signature(request)))
  File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/requests/packages/oauthlib/oauth1/rfc5849/__init__.py", line 65, in get_oauth_signature
    uri, headers, body = self._render(request)
  File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/requests/packages/oauthlib/oauth1/rfc5849/__init__.py", line 135, in _render
    headers = parameters.prepare_headers(request.oauth_params, request.headers)
  File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/requests/packages/oauthlib/oauth1/rfc5849/utils.py", line 28, in wrapper
    return target(params, *args, **kwargs)
  File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/requests/packages/oauthlib/oauth1/rfc5849/parameters.py", line 55, in prepare_headers
    escaped_value = utils.escape(value)
  File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/requests/packages/oauthlib/oauth1/rfc5849/utils.py", line 52, in escape
    raise ValueError('Only unicode objects are escapable.')
ValueError: Only unicode objects are escapable.

And Googling doesn't really help. I discovered that the OAuth part of Requests is being pulled out into a separate package/project. I tried 'pip'ing it, but it's not available yet.  Sigh.

I should probably mention that:

import requests
print requests.get('https://www.google.com').content

Works perfectly well. It's the OAuth stuff that appears to be FUBAR.