views:

44

answers:

4

I'm writing an API wrapper to a couple of different web services.

I have a method that has an article url, and I want to extract text from it using alchemyapi.

def extractText(self):
    #All Extract Text Methods ---------------------------------------------------------//
    #Extract page text from a web URL (ignoring navigation links, ads, etc.).
    if self.alchemyapi == True:
        self.full_text = self.alchemyObj.URLGetText(self.article_link)

which goes to the following code in the python wrapper

def URLGetText(self, url, textParams=None):
    self.CheckURL(url)
    if textParams == None:
      textParams = AlchemyAPI_TextParams()
    textParams.setUrl(url)
    return self.GetRequest("URLGetText", "url", textParams)

def GetRequest(self, apiCall, apiPrefix, paramObject):
    endpoint = 'http://' + self._hostPrefix + '.alchemyapi.com/calls/' + apiPrefix + '/' + apiCall
    endpoint += '?apikey=' + self._apiKey + paramObject.getParameterString()
    handle = urllib.urlopen(endpoint)
    result = handle.read()
    handle.close()
    xpathQuery = '/results/status'
    nodes = etree.fromstring(result).xpath(xpathQuery)
    if nodes[0].text != "OK":
      raise 'Error making API call.'
    return result

However I get this error ---

  Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "text_proc.py", line 97, in __init__
    self.alchemyObj.loadAPIKey("api_key.txt");    
  File "text_proc.py", line 115, in extractText
    if self.alchemyapi == True:
  File "/Users/Diesel/Desktop/AlchemyAPI.py", line 502, in URLGetText
    return self.GetRequest("URLGetText", "url", textParams)
  File "/Users/Diesel/Desktop/AlchemyAPI.py", line 618, in GetRequest
    raise 'Error making API call.'

I know I'm somehow passing the url string to the api wrapper in a faulty format, but I can't figure out how to fix it.

+2  A: 

You should raise Exception or a subclass thereof, instead of a string.

knutin
A: 

You're getting the error because your function GetRequest() raising a string as an exception:

if nodes[0].text != "OK":
  raise 'Error making API call.'

If that's not what you want, you have two options:

  1. You can have the function return the string or None, or
  2. You can pass the error message to a real subclass of Exception (as suggested by knutin)

In either case, if you are assigning that return value to a variable, you can handle it accordingly. Here is an example:

Option 1 Let's assume you decide to have GetRequest() return None:

def URLGetText(self, url, textParams=None):
    self.CheckURL(url)
    if textParams == None:
        textParams = AlchemyAPI_TextParams()
    textParams.setUrl(url)

    # Capture the value of GetRequest() before returning it
    retval = self.GetRequest("URLGetText", "url", textParams)
    if retval is None:
        print 'Error making API call.' # print the error but still return 

    return retval 

def GetRequest(self, apiCall, apiPrefix, paramObject):
    # ...
    if nodes[0].text != "OK":
      return None
    return result

This option is a little ambiguous. How do you know that it was really an error, or the return value truly was None?

Option 2 This is probably the better way to do it:

First create an subclass of Exception:

class GetRequestError(Exception):
    """Error returned from GetRequest()"""
    pass

Then raise it in GetRequest()`:

def URLGetText(self, url, textParams=None):
    self.CheckURL(url)
    if textParams == None:
      textParams = AlchemyAPI_TextParams()
    textParams.setUrl(url)

    # Attempt to get a legit return value & handle errors
    try:
        retval = self.GetRequest(apiCall, apiPrefix, paramObject)
    except GetRequestError as err:
        print err # prints 'Error making API call.'
        # handle the error here
        retval = None

    return retval

def GetRequest(self, apiCall, apiPrefix, paramObject):
    # ...
    if nodes[0].text != "OK":
      raise GetRequestError('Error making API call.')
    return result

This way you're raising a legitimate error when GetRequest() doesn't return the desired result, and then you can handle the error using a try..except block and optionally print the error, stop the program there, or keep going (which is what I think you want to do based on your question).

jathanism
I'm afraid that's not his code, but part of the official Alchemy "SDK"...
Jim Brissom
Well I'll be damned. Undo! Undo!
jathanism
LOL -- Thanks for the design pattern help ! I'm going to take Jim's advice and just make a small wrapper class for my module.
Hey all I've scrapped using AlchemyAPI's API and just wrote my own ... no problems now ... go figure...
+2  A: 

The information provided is not actually very helpful to diagnose or solve the problem. Have you considered taking a look at the response from the server? You might inspect a complete traffic log using Fiddler.

Additionally, the SDK provided by Alchemy doesn't seem to be of - cough, cough - the greatest quality. Since it really consists only of around 600 lines of source code, I'd consider writing a shorter, more robust / pythonic / whatever SDK.

I might also add that right now, even the on-site demo at the Alchemy web site is failing, so maybe your problem is related to that. I really suggest taking a look at the traffic.

Jim Brissom