ebay / ebay / api.py

import sys
import urllib
import time
import warnings
from ebay import transport
from ebay.etree import ET
from ebay.exc import EbayAPIError, EbayInvalidItemID, EbayHTTPError

class XMLNamespace(object):
    
    def __init__(self, namespace):
        self.namespace = namespace
    
    def __call__(self, path_parts):
        """out of path parts return a namespaced path."""
        ns_sep = "{%s}" % self.namespace
        path = ns_sep + ("/" + ns_sep).join(path_parts)
        return path

NS = XMLNamespace('urn:ebay:apis:eBLBaseComponents')

__all__ = ['ShoppingAPI']

class EbayAPI(object):
    """Base class for objects that connects to the Ebay API.
    
    See http://developer.ebay.com/
    """
    
    # this can be set to "latest" if you are fearless
    api_version = '607'
    
    def __init__(self, appid, failed_req_sleep_time=1.0, sandbox=False, api_version=None):
        if api_version:
            if api_version != self.api_version:
                warnings.warn("Only tested with API version %s (might not work with %s)" % (
                                                                self.api_version, api_version))
            self.api_version = api_version
        if appid is None:
            raise TypeError("appid cannot be None")
        self.api_hits = 0
        self.appid = appid
        self.failed_req_sleep_time = failed_req_sleep_time
        # is this host just for the shopping API?
        if sandbox:
            self.host = "open.api.sandbox.ebay.com"
        else:
            self.host = "open.api.ebay.com"
        self.protocol = "http"
    
    def _object_from_response(self, response, ResponseClass):
        tree = ET.parse(response)
        return ResponseClass(response=response, tree=tree)
        
    def request(self, resource, ResponseClass=None, **params):
        """Make an HTTP GET request to the Ebay API.
                
        Per the `Compatibility Checklist`_, this will retry errors a
        maximum of two times. 
        
        :returns: file-like object (response) *or* a response wrapped in ResponseClass if not None.
    
        .. _Compatibility Checklist: http://developer.ebay.com/support/certification/Default.aspx
        """
        if resource[0] == "/":
            resource = resource[1:]
        # todo: switch to non-leaky urllib2 (for older Pythons)
        url = "%s://%s/%s?%s" % (self.protocol, self.host, resource, urllib.urlencode(params))
        
        def try_request():
            response = transport.urlopen(url)
            # only count successful hits because that's probably 
            # how ebay quota works.
            self.api_hits += 1
            if ResponseClass:
                return self._object_from_response(response, ResponseClass)
            else:
                return response
        
        res = None
        exc = None
        
        try:
            res = try_request()
        except Exception, exc:
            # todo: log this?  do we care?
            pass
        else:
            return res
        
        # second try:
        time.sleep(self.failed_req_sleep_time)
                
        try:
            res = try_request()
        except EbayAPIError:
            raise
        except Exception, exc:
            etype, val, tb = sys.exc_info()
            raise EbayHTTPError("%s: %s" % (exc.__class__.__name__, exc)), None, tb
        else:
            return res
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.