wordnik / wordnik-python3

wordnik python3 library
73 stars 13 forks source link

401 Unauthorized on Python 3.3 #1

Open jaraco opened 10 years ago

jaraco commented 10 years ago

I tested the library on Python 3.4, and it seems to be working. I then deployed it on a system running Python 3.3 and I get 401 Unauthorized errors. Consider this test script:

import sys
short_ver = '{vi[0]}.{vi[1]}'.format(vi=sys.version_info)

sys.path.insert(0, './wordnik_py3-2.1.2-py{vi}.egg'.format(vi=short_ver))

import wordnik.WordApi
import wordnik.swagger

key = 'elided'
client = wordnik.swagger.ApiClient(key, 'http://api.wordnik.com/v4')
words = wordnik.WordApi.WordApi(client)
words.getDefinitions('dachshund', limit=1)

If I have the wordnik-py3 2.1.2 eggs for Python 3.3 and Python 3.4 in the current directory, I can then run the above script for each. On Python 3.4, it passes without error. On Python 3.3, I get this traceback:

Traceback (most recent call last):
  File ".\test-wn.py", line 12, in <module>
    words.getDefinitions('dachshund', limit=1)
  File "./wordnik_py3-2.1.2-py3.3.egg\wordnik\WordApi.py", line 182, in getDefinitions
    postData, headerParams)
  File "./wordnik_py3-2.1.2-py3.3.egg\wordnik\swagger.py", line 73, in callAPI
    request = urllib.request.urlopen(requestParams)
  File "C:\Program Files\Python33\lib\urllib\request.py", line 156, in urlopen
    return opener.open(url, data, timeout)
  File "C:\Program Files\Python33\lib\urllib\request.py", line 475, in open
    response = meth(req, response)
  File "C:\Program Files\Python33\lib\urllib\request.py", line 587, in http_response
    'http', request, response, code, msg, hdrs)
  File "C:\Program Files\Python33\lib\urllib\request.py", line 513, in error
    return self._call_chain(*args)
  File "C:\Program Files\Python33\lib\urllib\request.py", line 447, in _call_chain
    result = func(*args)
  File "C:\Program Files\Python33\lib\urllib\request.py", line 595, in http_error_default
    raise HTTPError(req.full_url, code, msg, hdrs, fp)
urllib.error.HTTPError: HTTP Error 401: Unauthorized

I'm using the exact same script, so the difference appears to be in how WordNik assembles the HTTP request on Python 3.3, somehow triggering the 401.

jaraco commented 10 years ago

In case it wasn't clear, I'm supplying a valid API key in line 9.

jaraco commented 10 years ago

The issue lies with wordnik.swagger in the MethodRequest class. Only on Python 3.3, for any request where the method isn't specified, get_method returns the empty string. This was a defect I identified in Python 3.3 and which I patched for Python 3.4.

jaraco commented 10 years ago

In jaraco.net, I've developed a more robust MethodRequest that works on multiple Python versions, including 3.3:

class MethodRequest(urllib.request.Request):
    method = None

    def __init__(self, *args, **kwargs):
        """
        Construct a MethodRequest. Usage is the same as for
        `urllib.request.Request` except it also takes an optional `method`
        keyword argument. If supplied, `method` will be used instead of
        the default.
        """
        method = kwargs.pop('method', self.method)
        urllib.request.Request.__init__(self, *args, **kwargs)
        # write the method after __init__ as Python 3.3 overrides the value
        self.method = method

    def get_method(self):
        return getattr(self, 'method') or urllib.request.Request.get_method(self)

Consider using that technique in Wordnik.

jaraco commented 10 years ago

Even that implementation has problems in some cases on some Pythons. I've put together a backports library: backports.method_request which is tested on Python 2.6+. Consider using that library or copying that code into Wordnik3.

jaraco commented 3 years ago

At this point, I'd just recommend dropping support for Python 3.3 and earlier.