Skip to content

Instantly share code, notes, and snippets.

@jdevera
Created February 26, 2010 16:24
Show Gist options
  • Save jdevera/315868 to your computer and use it in GitHub Desktop.
Save jdevera/315868 to your computer and use it in GitHub Desktop.
A replacement for pyaws's ecs.py to make it work with signed requests.
# Author: Kun Xi <[email protected]>
# License: Python Software Foundation License
#
# Note: This version, 0.3.1, supports the signed requests required
# by Amazon.
# The changes over 0.3.0 are based on a patch for 0.2.0 found here:
# http://blog.umlungu.co.uk/blog/2009/jul/12/pyaws-adding-request-authentication
# To make it work, just download pyaws from http://trac2.assembla.com/pyaws
# and replace the ecs.py file with this one.
"""
A Python wrapper to access Amazon Web Service(AWS) E-Commerce Serive APIs,
based upon pyamazon (http://www.josephson.org/projects/pyamazon/), enhanced
to meet the latest AWS specification(http://www.amazon.com/webservices).
This module defines the following classes:
- `Bag`, a generic container for the python objects
- `ListIterator`, a forward iterator adapter
- `PaginatedIterator`, a page-based iterator using lazy evaluation
Exception classes:
- `AWSException`
- `NoLicenseKey`
- `NoSecretKey`
- `BadLocale`
- `BadOption`
- `ExactParameterRequirement`
- `ExceededMaximumParameterValues`
- `InsufficientParameterValues`
- `InternalError`
- `InvalidEnumeratedParameter`
- `InvalidISO8601Time`
- `InvalidOperationForMarketplace`
- `InvalidOperationParameter`
- `InvalidParameterCombination`
- `InvalidParameterValue`
- `InvalidResponseGroup`
- `InvalidServiceParameter`
- `InvalidSubscriptionId`
- `InvalidXSLTAddress`
- `MaximumParameterRequirement`
- `MinimumParameterRequirement`
- `MissingOperationParameter`
- `MissingParameterCombination`
- `MissingParameters`
- `MissingParameterValueCombination`
- `MissingServiceParameter`
- `ParameterOutOfRange`
- `ParameterRepeatedInRequest`
- `RestrictedParameterValueCombination`
- `XSLTTransformationError`
Functions:
- `setLocale`
- `getLocale`
- `setLicenseKey`
- `getLicenseKey`
- `setSecretKey`
- `getSecretKey`
- `getVersion`
- `setOptions`
- `getOptions`
- `buildRequest`
- `buildException`
- `query`
- `SimpleObject`
- `Collection`
- `Pagination`
- `unmarshal`
- `ItemLookup`
- `XMLItemLookup`
- `ItemSearch`
- `XMLItemSearch`
- `SimilarityLookup`
- `XMLSimilarityLookup`
- `ListLookup`
- `XMLListLookup`
- `ListSearch`
- `XMLListSearch`
- `CartCreate`
- `XMLCartCreate`
- `CartAdd`
- `XMLCartAdd`
- `CartGet`
- `XMLCartGet`
- `CartModify`
- `XMLCartModify`
- `CartClear`
- `XMLCartClear`
- `SellerLookup`
- `XMLSellerLookup`
- `SellerListingLookup`
- `XMLSellerListingLookup`
- `SellerListingSearch`
- `XMLSellerListingSearch`
- `CustomerContentSearch`
- `XMLCustomerContentSearch`
- `CustomerContentLookup`
- `XMLCustomerContentLookup`
- `BrowseNodeLookup`
- `XMLBrowseNodeLookup`
- `Help`
- `XMLHelp`
- `TransactionLookup`
- `XMLTransactionLookup`
Accroding to the ECS specification, there are two implementation foo and XMLfoo, for example, `ItemLookup` and `XMLItemLookup`. foo returns a Python object, XMLfoo returns the raw XML file.
How To Use This Module
======================
(See the individual classes, methods, and attributes for details.)
1. Apply for a Amazon Web Service API key from Amazon Web Service:
https://aws-portal.amazon.com/gp/aws/developer/registration/index.html
2. Import it: ``import pyaws.ecs``
3. Setup the license key: ``ecs.setLicenseKey('YOUR-KEY-FROM-AWS')``
or you could use the environment variable AWS_LICENSE_KEY
4. Setup your secret key: ``ecs.setSecretKey('YOUR-SECRET-KEY-FROM-AWS')``
or you could use the environment variable AWS_SECRET_KEY
Optional:
a) setup other options, like AssociateTag, MerchantID, Validate
b) export the http_proxy environment variable if you want to use proxy
c) setup the locale if your locale is not ``us``
4. Send query to the AWS, and manupilate the returned python object.
"""
__author__ = "Kun Xi <[email protected]>"
__version__ = "0.3.1"
__license__ = "Python Software Foundation"
__docformat__ = 'restructuredtext'
import os, urllib, string
import hmac, hashlib, base64
from time import strftime, gmtime
from xml.dom import minidom
class Meta:
license_key = None
secret_key = None
locale = "us"
version = "2009-07-01"
options = {}
locales = {
None : "ecs.amazonaws.com",
"us" : "ecs.amazonaws.com",
"uk" : "ecs.amazonaws.co.uk",
"de" : "ecs.amazonaws.co.de",
"jp" : "ecs.amazonaws.co.jp",
"fr" : "ecs.amazonaws.co.fr",
"ca" : "ecs.amazonaws.co.ca",
}
def __buildPlugins():
"""
Build plugins used in unmarshal
Return the dict like:
Operation => { 'isByPassed'=>(...), 'isPivoted'=>(...),
'isCollective'=>(...), 'isCollected'=>(...),
isPaged=> { key1: (...), key2: (...), ... }
"""
"""
ResponseGroups heirachy:
Parent => children,
The benefit of this layer is to reduce the redundency, when
the child ResponseGroup change, it propaged to the parent
automatically
"""
rgh = {
'CustomerFull': ('CustomerInfo', 'CustomerLists', 'CustomerReviews'),
'Large': ('Accessories', 'BrowseNodes', 'ListmaniaLists', 'Medium', 'Offers', 'Reviews', 'Similarities', 'Tracks'),
'ListFull': ('ListInfo', 'ListItems'),
'ListInfo': ('ListMinimum', ),
'ListItems': ('ListMinimum', ),
'Medium': ('EditorialReview', 'Images', 'ItemAttributes', 'OfferSummary', 'Request', 'SalesRank', 'Small'),
'OfferFull': ('Offers',),
'Offers': ('OfferSummary',),
'Variations': ('VariationMinimum', 'VariationSummary')
}
"""
ResponseGroup and corresponding plugins:
ResponseGroup=>(isBypassed, isPivoted, isCollective, isCollected, isPaged)
isPaged is defined as:
{ kwItems : (kwPage, kwTotalResults, pageSize) }
- kwItems: string, the tagname of collection
- kwPage: string, the tagname of page
- kwTotalResults: string, the tagname of length
- pageSize: constant integer, the size of each page
CODE DEBT:
- Do we need to remove the ResponseGroup in rgh.keys()? At least, Medium does not
introduce any new attributes.
"""
rgps = {
'Accessories': ((), (), ('Accessories',), ('Accessory',), {}),
'AlternateVersions': ((), (), (), (), {}),
'BrowseNodeInfo': ((), (), ('Children', 'Ancestors'), ('BrowseNode',), {}),
'BrowseNodes': ((), (), ('Children', 'Ancestors', 'BrowseNodes'), ('BrowseNode',), {}),
'Cart': ((), (), (), (), {}),
'CartNewReleases': ((), (), (), (), {}),
'CartTopSellers': ((), (), (), (), {}),
'CartSimilarities': ((), (), (), (), {}),
'Collections': ((), (), (), (), {}),
'CustomerFull': ((), (), (), (), {}),
'CustomerInfo': ((), (), ('Customers',), ('Customer',), {}),
'CustomerLists': ((), (), ('Customers',), ('Customer',), {}),
'CustomerReviews': ((), (), ('Customers', 'CustomerReviews',),('Customer', 'Review'),{}),
'EditorialReview': ((), (), ('EditorialReviews',), ('EditorialReview',), {}),
'Help': ((), (), ('RequiredParameters', 'AvailableParameters',
'DefaultResponseGroups', 'AvailableResponseGroups'),
('Parameter', 'ResponseGroup'), {}),
'Images': ((), (), ('ImageSets',), ('ImageSet',), {}),
'ItemAttributes': ((), ('ItemAttributes',), (), (), {}),
'ItemIds': ((), (), (), (), {}),
'ItemLookup.Small': ((), ('ItemAttributes',), (), ('Item',),
{'Items': ('OfferPage', 'OfferPages', 10) }),
'ItemSearch.Small': ((), ('ItemAttributes',), (), ('Item',),
{'Items': ('ItemPage', 'TotalPages', 10) }),
'Large': ((), (), (), (), {}),
'ListFull': ((), (), (), ('ListItem', ), {}),
'ListInfo': ((), (), (), (), {}),
'ListItems': ((), (), ('Lists',), ('ListItem', 'List'), {'List': ('ProductPage',
'TotalPages', 10)}),
'ListmaniaLists': ((), (), ('ListmaniaLists', ), ('ListmaniaList',), {}),
'ListMinimum': ((), (), (), (), {}),
'Medium': ((), (), (), (), {}),
'MerchantItemAttributes': ((), (), (), (), {}),
'NewReleases': ((), (), ('NewReleases',), ('NewRelease',), {}),
'OfferFull': ((), (), (), (), {}),
'OfferListings': ((), (), (), (), {}),
'Offers': ((), (), (), ('Offer',), {'Offers': ('OfferPage', 'TotalOfferPages', 10)}),
'OfferSummary': ((), (), (), (), {}),
'Request': (('Request',), (), (), (), {}),
'Reviews': ((), (), ('CustomerReviews', ),('Review',), {}),
'SalesRank': ((), (), (), (), {}),
'SearchBins': ((), (), ('SearchBinSets',), ('SearchBinSet',), {}),
'SimilarityLookup.Small': ((), ('ItemAttributes',), ('Items',), ('Item',), {}),
'Seller': ((), (), (), (), {}),
'SellerListing': ((), (), (), (), {}),
'Similarities': ((), (), ('SimilarProducts',), ('SimilarProduct',), {}),
'Small': ((), (), (), (), {}),
'Subjects': ((), (), ('Subjects',), ('Subject',), {}),
'TopSellers': ((), (), ('TopSellers',), ('TopSeller',), {}),
'Tracks': ((), ('Tracks',), (), (), {}),
'TransactionDetails': ((), (), ('Transactions', 'TransactionItems', 'Shipments'),
('Transaction', 'TransactionItem', 'Shipment'), {}),
'Variations': ((), (), (), (), {}),
'VariationMinimum': ((), (), ('Variations',), ('Variation',), {}),
'VariationImages': ((), (), (), (), {}),
'VariationSummary':((), (), (), (), {})
}
"""
Operation=>ResponseGroups
"""
orgs = {
'BrowseNodeLookup': ('Request', 'BrowseNodeInfo', 'NewReleases', 'TopSellers'),
'CartAdd': ('Cart', 'Request', 'CartSimilarities', 'CartTopSellers', 'NewReleases'),
'CartClear': ('Cart', 'Request'),
'CartCreate': ('Cart', 'Request', 'CartSimilarities', 'CartTopSellers', 'CartNewReleases'),
'CartGet': ('Cart', 'Request', 'CartSimilarities', 'CartTopSellers', 'CartNewReleases'),
'CartModify': ('Cart', 'Request', 'CartSimilarities', 'CartTopSellers', 'CartNewReleases'),
'CustomerContentLookup': ('Request', 'CustomerInfo', 'CustomerReviews', 'CustomerLists', 'CustomerFull'),
'CustomerContentSearch': ('Request', 'CustomerInfo'),
'Help': ('Request', 'Help'),
'ItemLookup': ('Request', 'ItemLookup.Small', 'Accessories', 'BrowseNodes', 'EditorialReview', 'Images', 'ItemAttributes', 'ItemIds', 'Large', 'ListmaniaLists', 'Medium', 'MerchantItemAttributes', 'OfferFull', 'Offers', 'OfferSummary', 'Reviews', 'SalesRank', 'Similarities', 'Subjects', 'Tracks', 'VariationImages', 'VariationMinimum', 'Variations', 'VariationSummary'),
'ItemSearch': ('Request', 'ItemSearch.Small', 'Accessories', 'BrowseNodes', 'EditorialReview', 'ItemAttributes', 'ItemIds', 'Large', 'ListmaniaLists', 'Medium', 'MerchantItemAttributes', 'OfferFull', 'Offers', 'OfferSummary', 'Reviews', 'SalesRank', 'SearchBins', 'Similarities', 'Subjects', 'Tracks', 'VariationMinimum', 'Variations', 'VariationSummary'),
'ListLookup': ('Request', 'ListInfo', 'Accessories', 'BrowseNodes', 'EditorialReview', 'Images', 'ItemAttributes', 'ItemIds', 'Large', 'ListFull', 'ListItems', 'ListmaniaLists', 'Medium', 'Offers', 'OfferSummary', 'Reviews', 'SalesRank', 'Similarities', 'Subjects', 'Tracks', 'VariationMinimum', 'Variations', 'VariationSummary'),
'ListSearch': ('Request', 'ListInfo', 'ListMinimum'),
'SellerListingLookup': ('Request', 'SellerListing'),
'SellerListingSearch': ('Request', 'SellerListing'),
'SellerLookup': ('Request', 'Seller'),
'SimilarityLookup': ('Request', 'SimilarityLookup.Small', 'Accessories', 'BrowseNodes', 'EditorialReview', 'Images', 'ItemAttributes', 'ItemIds', 'Large', 'ListmaniaLists', 'Medium', 'Offers', 'OfferSummary', 'Reviews', 'SalesRank', 'Similarities', 'Tracks', 'VariationMinimum', 'Variations', 'VariationSummary'),
'TransactionLookup':('Request', 'TransactionDetails')
}
def collapse(responseGroups):
l = []
for x in responseGroups:
l.append(x)
if x in rgh.keys():
l.extend( collapse(rgh[x]) )
return l
def mergePlugins(responseGroups, index):
#return reduce(lambda x, y: x.update(set(rgps[y][index])), responseGroups, set())
# this magic reduce does not work, using the primary implementation first.
# CODEDEBT: magic number !
if index == 4:
s = dict()
else:
s = set()
map(lambda x: s.update(rgps[x][index]), responseGroups)
return s
def unionPlugins(responseGroups):
return dict( [ (key, mergePlugins(collapse(responseGroups), index)) for index, key in enumerate(['isBypassed', 'isPivoted', 'isCollective', 'isCollected', 'isPaged']) ])
return dict( [ (k, unionPlugins(v)) for k, v in orgs.items() ] )
__plugins = __buildPlugins()
# Basic class for ECS
class Bag :
"""A generic container for the python objects"""
def __repr__(self):
return '<Bag instance: ' + self.__dict__.__repr__() + '>'
class ListIterator(list):
pass
class PaginatedIterator(ListIterator):
def __init__(self, XMLSearch, arguments, keywords, element, plugins):
"""
Initialize a `PaginatedIterator` object.
Parameters:
- `XMLSearch`: a function, the query to get the DOM
- `arguments`: a dictionary, `XMLSearch`'s arguments
- `keywords`: a tuple, (kwItems, (kwPage, kwTotalPages, pageSize) )
- `element`: a DOM element, the root of the collection
- `plugins`: a dictionary, collection of plugged objects
"""
kwItems, (kwPage, kwTotalPages, pageSize) = keywords
self.search = XMLSearch
self.arguments = arguments
self.plugins = plugins
self.keywords ={'Items':kwItems, 'Page':kwPage}
self.total_page = int(element.getElementsByTagName(kwTotalPages).item(0).firstChild.data)
self.page = 1
self.cache = unmarshal(XMLSearch, arguments, element, plugins, ListIterator())
def __iter__(self):
while True:
for x in self.cache:
yield x
self.page += 1
if self.page > self.total_page:
raise StopIteration
self.arguments[self.keywords['Page']] = self.page
dom = self.search(** self.arguments)
self.cache = unmarshal(self.search, self.arguments, dom.getElementsByTagName(self.keywords['Items']).item(0), self.plugins, ListIterator())
def SimpleObject(XMLSearch, arguments, kwItem, plugins=None):
"""Return simple object from `unmarshal`"""
dom = XMLSearch(** arguments)
return unmarshal(XMLSearch, arguments, dom.getElementsByTagName(kwItem).item(0), plugins)
def Collection(XMLSearch, arguments, kwItems, plugins=None):
"""Return collection of objects from `unmarshal` using ListIterator interface."""
dom = XMLSearch(** arguments)
return unmarshal(XMLSearch, arguments, dom.getElementsByTagName(kwItems).item(0), plugins, ListIterator())
def Pagination(XMLSearch, arguments, keywords, plugins):
return PaginatedIterator(XMLSearch, arguments, keywords,
XMLSearch(** arguments).getElementsByTagName(keywords[0]).item(0),
plugins)
# Exception classes
class AWSException(Exception) : pass
class NoLicenseKey(AWSException) : pass
class NoSecretKey(AWSException) : pass
class BadLocale(AWSException) : pass
class BadOption(AWSException): pass
# Runtime exception
class ExactParameterRequirement(AWSException): pass
class ExceededMaximumParameterValues(AWSException): pass
class InsufficientParameterValues(AWSException): pass
class InternalError(AWSException): pass
class InvalidEnumeratedParameter(AWSException): pass
class InvalidISO8601Time(AWSException): pass
class InvalidOperationForMarketplace(AWSException): pass
class InvalidOperationParameter(AWSException): pass
class InvalidParameterCombination(AWSException): pass
class InvalidParameterValue(AWSException): pass
class InvalidResponseGroup(AWSException): pass
class InvalidServiceParameter(AWSException): pass
class InvalidSubscriptionId(AWSException): pass
class InvalidXSLTAddress(AWSException): pass
class MaximumParameterRequirement(AWSException): pass
class MinimumParameterRequirement(AWSException): pass
class MissingOperationParameter(AWSException): pass
class MissingParameterCombination(AWSException): pass
class MissingParameters(AWSException): pass
class MissingParameterValueCombination(AWSException): pass
class MissingServiceParameter(AWSException): pass
class ParameterOutOfRange(AWSException): pass
class ParameterRepeatedInRequest(AWSException): pass
class RestrictedParameterValueCombination(AWSException): pass
class XSLTTransformationError(AWSException): pass
class ECommerceServiceNoExactMatches(AWSException): pass
def buildRequest(argv):
"""Build the REST request URL from argv."""
url = "https://" + Meta.locales[getLocale()] + "/onca/xml?"
#add Service to url param to argv so it can be sorted:
argv['Service'] = 'AWSECommerceService'
argv['Version'] = Meta.version
# add Timestamp url param to argv, this is required when using a signature
argv['Timestamp'] = strftime("%Y-%m-%dT%H:%M:%SZ", gmtime())
if not argv['AWSAccessKeyId']:
argv['AWSAccessKeyId'] = getLicenseKey()
argv.update(getOptions())
#args must be sorted so both you and amazon generate the same hashed signature
sortedArgv = argv.items()
sortedArgv.sort()
paramsToEncode = '&'.join(['%s=%s' % (k,urllib.quote(str(v),safe='-_.~')) for (k,v) in sortedArgv if v is not None])
stringToSign = "GET" + "\n" + Meta.locales[getLocale()] + "\n" + "/onca/xml" + "\n" + paramsToEncode.encode('utf-8')
signature = base64.b64encode(hmac.new(getSecretKey(), stringToSign, hashlib.sha256).digest())
argv['Signature'] = signature
return url + '&'.join(['%s=%s' % (k,urllib.quote(str(v))) for (k,v) in argv.items() if v is not None])
def buildException(els):
"""Build the exception from the returned DOM node
Note: only the first exception is raised."""
error = els[0]
class_name = error.childNodes[0].firstChild.data[4:].replace(".", "")
msg = error.childNodes[1].firstChild.data
e = globals()[ class_name ](msg)
return e
def query(url):
"""Send the query url and return the DOM
Exception is raised if there are errors"""
u = urllib.FancyURLopener()
usock = u.open(url)
dom = minidom.parse(usock)
usock.close()
errors = dom.getElementsByTagName('Error')
if errors:
e = buildException(errors)
raise e
return dom
def unmarshal(XMLSearch, arguments, element, plugins=None, rc=None):
"""Return the `Bag` / `ListIterator` object with attributes
populated using DOM element.
Parameters:
- `XMLSearch`: callback function, used when construct PaginatedIterator
- `arguments`: arguments of `XMLSearch`
- `element`: DOM object, the DOM element interested in
- `plugins`: a dictionary, collection of plugged objects to fine-tune
the object attributes
- `rc`: Bag object, parent object
This core function is inspired by Mark Pilgrim ([email protected])
with some enhancement. Each node.tagName is evalued by plugins' callback
functions:
- if tagname in plugins['isBypassed']
this elment is ignored
- if tagname in plugins['isPivoted']
this children of this elment is moved to grandparents
this object is ignored.
- if tagname in plugins['isCollective']
this elment is mapped to []
- if tagname in plugins['isCollected']
this children of elment is appended to grandparent
this object is ignored.
- if tagname in plugins['isPaged'].keys():
this PaginatedIterator is constructed for the object
CODE DEBT:
- Use optimal search for optimization if necessary
"""
if(rc == None):
rc = Bag()
childElements = [e for e in element.childNodes if isinstance(e, minidom.Element)]
if childElements:
for child in childElements:
key = child.tagName
if hasattr(rc, key):
attr = getattr(rc, key)
if type(attr) <> type([]):
setattr(rc, key, [attr])
setattr(rc, key, getattr(rc, key) + [unmarshal(XMLSearch, arguments, child, plugins)])
elif isinstance(child, minidom.Element):
if child.tagName in plugins['isPivoted']:
unmarshal(XMLSearch, arguments, child, plugins, rc)
continue
elif child.tagName in plugins['isBypassed']:
continue
if child.tagName in plugins['isCollective']:
value = unmarshal(XMLSearch, arguments, child, plugins, ListIterator())
elif child.tagName in plugins['isPaged'].keys():
value = PaginatedIterator(XMLSearch, arguments, (child.tagName, plugins['isPaged'][child.tagName]), child, plugins)
else :
value = unmarshal(XMLSearch, arguments, child, plugins)
if child.tagName in plugins['isCollected']:
rc.append(value)
else :
setattr(rc, key, value)
else:
rc = "".join([e.data for e in element.childNodes if isinstance(e, minidom.Text)])
return rc
# User interfaces
def ItemLookup(ItemId, IdType=None, SearchIndex=None, MerchantId=None, Condition=None, DeliveryMethod=None, ISPUPostalCode=None, OfferPage=None, ReviewPage=None, ReviewSort=None, VariationPage=None, ResponseGroup=None, AWSAccessKeyId=None):
'''ItemLookup in ECS'''
return SimpleObject(XMLItemLookup, vars(), 'Item', __plugins['ItemLookup'])
def XMLItemLookup(ItemId, IdType=None, SearchIndex=None, MerchantId=None, Condition=None, DeliveryMethod=None, ISPUPostalCode=None, OfferPage=None, ReviewPage=None, ReviewSort=None, VariationPage=None, ResponseGroup=None, AWSAccessKeyId=None):
'''DOM representation of ItemLookup in ECS'''
Operation = "ItemLookup"
return query(buildRequest(vars()))
def ItemSearch(Keywords, SearchIndex="Blended", Availability=None, Title=None, Power=None, BrowseNode=None, Artist=None, Author=None, Actor=None, Director=None, AudienceRating=None, Manufacturer=None, MusicLabel=None, Composer=None, Publisher=None, Brand=None, Conductor=None, Orchestra=None, TextStream=None, ItemPage=None, OfferPage=None, ReviewPage=None, Sort=None, City=None, Cuisine=None, Neighborhood=None, MinimumPrice=None, MaximumPrice=None, MerchantId=None, Condition=None, DeliveryMethod=None, ResponseGroup=None, AWSAccessKeyId=None):
'''ItemSearch in ECS'''
return Pagination(XMLItemSearch, vars(),
('Items', __plugins['ItemSearch']['isPaged']['Items']), __plugins['ItemSearch'])
def XMLItemSearch(Keywords, SearchIndex="Blended", Availability=None, Title=None, Power=None, BrowseNode=None, Artist=None, Author=None, Actor=None, Director=None, AudienceRating=None, Manufacturer=None, MusicLabel=None, Composer=None, Publisher=None, Brand=None, Conductor=None, Orchestra=None, TextStream=None, ItemPage=None, OfferPage=None, ReviewPage=None, Sort=None, City=None, Cuisine=None, Neighborhood=None, MinimumPrice=None, MaximumPrice=None, MerchantId=None, Condition=None, DeliveryMethod=None, ResponseGroup=None, AWSAccessKeyId=None):
'''DOM representation of ItemSearch in ECS'''
Operation = "ItemSearch"
return query(buildRequest(vars()))
def SimilarityLookup(ItemId, SimilarityType=None, MerchantId=None, Condition=None, DeliveryMethod=None, ResponseGroup=None, OfferPage=None, AWSAccessKeyId=None):
'''SimilarityLookup in ECS'''
return Collection(XMLSimilarityLookup, vars(), 'Items', __plugins['SimilarityLookup'])
def XMLSimilarityLookup(ItemId, SimilarityType=None, MerchantId=None, Condition=None, DeliveryMethod=None, ResponseGroup=None, OfferPage=None, AWSAccessKeyId=None):
'''DOM representation of SimilarityLookup in ECS'''
Operation = "SimilarityLookup"
return query(buildRequest(vars()))
# List Operations
def ListLookup(ListType, ListId, ProductPage=None, ProductGroup=None, Sort=None, MerchantId=None, Condition=None, DeliveryMethod=None, ResponseGroup=None, AWSAccessKeyId=None):
'''ListLookup in ECS'''
return Pagination(XMLListLookup, vars(),
('List', __plugins['ListLookup']['isPaged']['List']),
__plugins['ListLookup'])
def XMLListLookup(ListType, ListId, ProductPage=None, ProductGroup=None, Sort=None, MerchantId=None, Condition=None, DeliveryMethod=None, ResponseGroup=None, AWSAccessKeyId=None):
'''DOM representation of ListLookup in ECS'''
Operation = "ListLookup"
return query(buildRequest(vars()))
def ListSearch(ListType, Name=None, FirstName=None, LastName=None, Email=None, City=None, State=None, ListPage=None, ResponseGroup=None, AWSAccessKeyId=None):
'''ListSearch in ECS'''
argv = vars()
plugins = {
'isBypassed': (),
'isPivoted': ('ItemAttributes',),
'isCollective': ('Lists',),
'isCollected': ('List',),
'isPaged' : { 'Lists': ('ListPage', 'TotalResults', 10) }
}
return Pagination(XMLListSearch, argv,
('Lists', plugins['isPaged']['Lists']), plugins)
def XMLListSearch(ListType, Name=None, FirstName=None, LastName=None, Email=None, City=None, State=None, ListPage=None, ResponseGroup=None, AWSAccessKeyId=None):
'''DOM representation of ListSearch in ECS'''
Operation = "ListSearch"
return query(buildRequest(vars()))
#Remote Shopping Cart Operations
def CartCreate(Items, Quantities, ResponseGroup=None, AWSAccessKeyId=None):
'''CartCreate in ECS'''
return __cartOperation(XMLCartCreate, vars())
def XMLCartCreate(Items, Quantities, ResponseGroup=None, AWSAccessKeyId=None):
'''DOM representation of CartCreate in ECS'''
Operation = "CartCreate"
argv = vars()
for x in ('Items', 'Quantities'):
del argv[x]
__fromListToItems(argv, Items, 'ASIN', Quantities)
return query(buildRequest(argv))
def CartAdd(Cart, Items, Quantities, ResponseGroup=None, AWSAccessKeyId=None):
'''CartAdd in ECS'''
return __cartOperation(XMLCartAdd, vars())
def XMLCartAdd(Cart, Items, Quantities, ResponseGroup=None, AWSAccessKeyId=None):
'''DOM representation of CartAdd in ECS'''
Operation = "CartAdd"
CartId = Cart.CartId
HMAC = Cart.HMAC
argv = vars()
for x in ('Items', 'Cart', 'Quantities'):
del argv[x]
__fromListToItems(argv, Items, 'ASIN', Quantities)
return query(buildRequest(argv))
def CartGet(Cart, ResponseGroup=None, AWSAccessKeyId=None):
'''CartGet in ECS'''
return __cartOperation(XMLCartGet, vars())
def XMLCartGet(Cart, ResponseGroup=None, AWSAccessKeyId=None):
'''DOM representation of CartGet in ECS'''
Operation = "CartGet"
CartId = Cart.CartId
HMAC = Cart.HMAC
argv = vars()
del argv['Cart']
return query(buildRequest(argv))
def CartModify(Cart, Items, Actions, ResponseGroup=None, AWSAccessKeyId=None):
'''CartModify in ECS'''
return __cartOperation(XMLCartModify, vars())
def XMLCartModify(Cart, Items, Actions, ResponseGroup=None, AWSAccessKeyId=None):
'''DOM representation of CartModify in ECS'''
Operation = "CartModify"
CartId = Cart.CartId
HMAC = Cart.HMAC
argv = vars()
for x in ('Cart', 'Items', 'Actions'):
del argv[x]
__fromListToItems(argv, Items, 'CartItemId', Actions)
return query(buildRequest(argv))
def CartClear(Cart, ResponseGroup=None, AWSAccessKeyId=None):
'''CartClear in ECS'''
return __cartOperation(XMLCartClear, vars())
def XMLCartClear(Cart, ResponseGroup=None, AWSAccessKeyId=None):
'''DOM representation of CartClear in ECS'''
Operation = "CartClear"
CartId = Cart.CartId
HMAC = Cart.HMAC
argv = vars()
del argv['Cart']
return query(buildRequest(argv))
def __fromListToItems(argv, items, id, actions):
'''Convert list to AWS REST arguments'''
for i in range(len(items)):
argv["Item.%d.%s" % (i+1, id)] = getattr(items[i], id);
action = actions[i]
if isinstance(action, int):
argv["Item.%d.Quantity" % (i+1)] = action
else:
argv["Item.%d.Action" % (i+1)] = action
def __cartOperation(XMLSearch, arguments):
'''Generic cart operation'''
plugins = {
'isBypassed': ('Request',),
'isPivoted': (),
'isCollective': ('CartItems', 'SavedForLaterItems'),
'isCollected': ('CartItem', 'SavedForLaterItem'),
'isPaged': {}
}
return SimpleObject(XMLSearch, arguments, 'Cart', plugins)
# Seller Operation
def SellerLookup(Sellers, FeedbackPage=None, ResponseGroup=None, AWSAccessKeyId=None):
'''SellerLookup in AWS'''
argv = vars()
plugins = {
'isBypassed': ('Request',),
'isPivoted': (),
'isCollective': ('Sellers',),
'isCollected': ('Seller',),
'isPaged': {}
}
return Collection(XMLSellerLookup, argv, 'Sellers', plugins)
def XMLSellerLookup(Sellers, FeedbackPage=None, ResponseGroup=None, AWSAccessKeyId=None):
'''DOM representation of SellerLookup in AWS'''
Operation = "SellerLookup"
SellerId = ",".join(Sellers)
argv = vars()
del argv['Sellers']
return query(buildRequest(argv))
def SellerListingLookup(SellerId, Id, IdType="Listing", ResponseGroup=None, AWSAccessKeyId=None):
'''SellerListingLookup in AWS
Notice: although the repsonse includes TotalPages, TotalResults,
there is no ListingPage in the request, so we have to use Collection
instead of PaginatedIterator. Hope Amazaon would fix this inconsistance'''
argv = vars()
plugins = {
'isBypassed': ('Request',),
'isPivoted': (),
'isCollective': ('SellerListings',),
'isCollected': ('SellerListing',),
'isPaged': {}
}
return Collection(XMLSellerListingLookup, argv, "SellerListings", plugins)
def XMLSellerListingLookup(SellerId, Id, IdType="Listing", ResponseGroup=None, AWSAccessKeyId=None):
'''DOM representation of SellerListingLookup in AWS'''
Operation = "SellerListingLookup"
return query(buildRequest(vars()))
def SellerListingSearch(SellerId, Title=None, Sort=None, ListingPage=None, OfferStatus=None, ResponseGroup=None, AWSAccessKeyId=None):
'''SellerListingSearch in AWS'''
argv = vars()
plugins = {
'isBypassed': ('Request',),
'isPivoted': (),
'isCollective': ('SellerListings',),
'isCollected': ('SellerListing',),
'isPaged' : { 'SellerListings': ('ListingPage', 'TotalResults', 10) }
}
return Pagination(XMLSellerListingSearch, argv,
('SellerListings', plugins['isPaged']['SellerListings']), plugins)
def XMLSellerListingSearch(SellerId, Title=None, Sort=None, ListingPage=None, OfferStatus=None, ResponseGroup=None, AWSAccessKeyId=None):
'''DOM representation of SellerListingSearch in AWS'''
Operation = "SellerListingSearch"
return query(buildRequest(vars()))
def CustomerContentSearch(Name=None, Email=None, CustomerPage=1, ResponseGroup=None, AWSAccessKeyId=None):
'''CustomerContentSearch in AWS'''
return Collection(XMLCustomerContentSearch, vars(), 'Customers', __plugins['CustomerContentSearch'])
def XMLCustomerContentSearch(Name=None, Email=None, CustomerPage=1, ResponseGroup=None, AWSAccessKeyId=None):
'''DOM representation of CustomerContentSearch in AWS'''
Operation = "CustomerContentSearch"
argv = vars()
for x in ('Name', 'Email'):
if not argv[x]:
del argv[x]
return query(buildRequest(argv))
def CustomerContentLookup(CustomerId, ReviewPage=1, ResponseGroup=None, AWSAccessKeyId=None):
'''CustomerContentLookup in AWS'''
argv = vars()
plugins = {
'isBypassed': ('Request',),
'isPivoted': (),
'isCollective': ('Customers',),
'isCollected': ('Customer',),
}
return Collection(XMLCustomerContentLookup, argv, 'Customers', __plugins['CustomerContentLookup'])
def XMLCustomerContentLookup(CustomerId, ReviewPage=1, ResponseGroup=None, AWSAccessKeyId=None):
'''DOM representation of CustomerContentLookup in AWS'''
Operation = "CustomerContentLookup"
return query(buildRequest(vars()))
# BrowseNode
def BrowseNodeLookup(BrowseNodeId, ResponseGroup=None, AWSAccessKeyId=None):
"""
BrowseNodeLookup in AWS
"""
return Collection(XMLBrowseNodeLookup, vars(), 'BrowseNodes', __plugins['BrowseNodeLookup'])
def XMLBrowseNodeLookup(BrowseNodeId, ResponseGroup=None, AWSAccessKeyId=None):
'''DOM representation of BrowseNodeLookup in AWS'''
Operation = "BrowseNodeLookup"
return query(buildRequest(vars()))
# Help
def Help(HelpType, About, ResponseGroup=None, AWSAccessKeyId=None):
'''Help in AWS'''
return SimpleObject(XMLHelp, vars(), 'Information', __plugins['Help'])
def XMLHelp(HelpType, About, ResponseGroup=None, AWSAccessKeyId=None):
'''DOM representation of Help in AWS'''
Operation = "Help"
return query(buildRequest(vars()))
# Transaction
def TransactionLookup(TransactionId, ResponseGroup=None, AWSAccessKeyId=None):
'''TransactionLookup in AWS'''
return Collection(XMLTransactionLookup, vars(), 'Transactions', __plugins['TransactionLookup'])
def XMLTransactionLookup(TransactionId, ResponseGroup=None, AWSAccessKeyId=None):
'''DOM representation of TransactionLookup in AWS'''
Operation = "TransactionLookup"
return query(buildRequest(vars()))
# helper functions
def setLocale(locale):
"""Set the locale
if unsupported locale is set, BadLocale is raised."""
if Meta.locales.has_key(locale):
Meta.locale = locale
else :
raise BadLocale, ("Unsupported locale. Locale must be one of: %s" %
', '.join([x for x in Meta.locales.keys() if x]))
def getLocale():
"""Get the locale"""
return Meta.locale
def setLicenseKey(license_key=None):
"""Set AWS license key.
If license_key is not specified, the license key is set using the
environment variable: AWS_LICENSE_KEY; if no license key is set,
NoLicenseKey exception is raised."""
if license_key:
Meta.license_key = license_key
else :
Meta.license_key = os.environ.get('AWS_LICENSE_KEY', None)
def getLicenseKey():
"""Get AWS license key.
If no license key is specified, NoLicenseKey is raised."""
if Meta.license_key:
return Meta.license_key
else :
raise NoLicenseKey, ("Please get the license key from http://www.amazon.com/webservices")
def setSecretKey(secret_key=None):
"""Set AWS secret key.
If secret_key is not specified, the secret key is set using the
environment variable: AWS_SECRET_KEY; if no secret key is set,
NoSecretKey exception is raised."""
if secret_key:
Meta.secret_key = secret_key
else :
Meta.secret_key = os.environ.get('AWS_SECRET_KEY', None)
def getSecretKey():
"""Get AWS secret key.
If no secret key is specified, NoSecretKey is raised."""
if Meta.secret_key:
return Meta.secret_key
else :
raise NoSecretKey, ("Please get the secret key from http://www.amazon.com/webservices")
def getVersion():
"""Get the version of ECS specification"""
return Meta.version
def setOptions(options):
"""
Set the general optional parameter, available options are:
- AssociateTag
- MerchantID
- Version
- Validate
"""
if set(options.keys()).issubset( set(['AssociateTag', 'MerchantID', 'Validate']) ):
Meta.options.update(options)
else:
raise BadOption, ('Unsupported option')
def getOptions():
"""Get options"""
return Meta.options
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment