Finished flushing out Amazon's use of the web services. Added actual tests to

the test suite and updated pyamazon from 0.4 to 0.61
This commit is contained in:
James Vega 2003-12-04 01:56:50 +00:00
parent a74d1d5aef
commit fa1c70b137
3 changed files with 531 additions and 289 deletions

View File

@ -1,275 +1,301 @@
"""Python wrapper for Amazon web APIs """Python wrapper
This module allows you to access Amazon's web APIs,
to do things like search Amazon and get the results programmatically. for Amazon web APIs
Described here:
http://www.amazon.com/webservices This module allows you to access Amazon's web APIs,
to do things like search Amazon and get the results programmatically.
You need a Amazon-provided license key to use these services. Described here:
Follow the link above to get one. These functions will look in http://www.amazon.com/webservices
several places (in this order) for the license key:
- the "license_key" argument of each function You need a Amazon-provided license key to use these services.
- the module-level LICENSE_KEY variable (call setLicense once to set it) Follow the link above to get one. These functions will look in
- an environment variable called AMAZON_LICENSE_KEY several places (in this order) for the license key:
- a file called ".amazonkey" in the current directory - the "license_key" argument of each function
- a file called "amazonkey.txt" in the current directory - the module-level LICENSE_KEY variable (call setLicense once to set it)
- a file called ".amazonkey" in your home directory - an environment variable called AMAZON_LICENSE_KEY
- a file called "amazonkey.txt" in your home directory - a file called ".amazonkey" in the current directory
- a file called ".amazonkey" in the same directory as amazon.py - a file called "amazonkey.txt" in the current directory
- a file called "amazonkey.txt" in the same directory as amazon.py - a file called ".amazonkey" in your home directory
- a file called "amazonkey.txt" in your home directory
Sample usage: - a file called ".amazonkey" in the same directory as amazon.py
>>> import amazon - a file called "amazonkey.txt" in the same directory as amazon.py
>>> amazon.setLicense('...') # must get your own key!
>>> pythonBooks = amazon.searchByKeyword('Python') Sample usage:
>>> pythonBooks[0].ProductName >>> import amazon
u'Learning Python (Help for Programmers)' >>> amazon.setLicense('...') # must get your own key!
>>> pythonBooks[0].URL >>> pythonBooks = amazon.searchByKeyword('Python')
... >>> pythonBooks[0].ProductName
>>> pythonBooks[0].OurPrice u'Learning Python (Help for Programmers)'
... >>> pythonBooks[0].URL
...
Other available functions: >>> pythonBooks[0].OurPrice
- browseBestSellers ...
- searchByASIN
- searchByUPC Other available functions:
- searchByAuthor - browseBestSellers
- searchByArtist - searchByASIN
- searchByActor - searchByUPC
- searchByDirector - searchByAuthor
- searchByManufacturer - searchByArtist
- searchByListMania - searchByActor
- searchSimilar - searchByDirector
- searchByManufacturer
Other usage notes: - searchByListMania
- Most functions can take product_line as well, see source for possible values - searchSimilar
- All functions can take type="lite" to get less detail in results - searchByWishlist
- All functions can take page=N to get second, third, fourth page of results
- All functions can take license_key="XYZ", instead of setting it globally Other usage notes:
- All functions can take http_proxy="http://x/y/z" which overrides your system setting - Most functions can take product_line as well, see source for possible values
""" - All functions can take type="lite" to get less detail in results
- All functions can take page=N to get second, third, fourth page of results
__author__ = "Mark Pilgrim (f8dy@diveintomark.org)" - All functions can take license_key="XYZ", instead of setting it globally
__version__ = "0.4" - All functions can take http_proxy="http://x/y/z" which overrides your system setting
__cvsversion__ = "$Revision$"[11:-2] """
__date__ = "$Date$"[7:-2]
__copyright__ = "Copyright (c) 2002 Mark Pilgrim" __author__ = "Mark Pilgrim (f8dy@diveintomark.org)"
__license__ = "Python" __version__ = "0.61"
__cvsversion__ = "$Revision$"[11:-2]
from xml.dom import minidom __date__ = "$Date$"[7:-2]
import os, sys, getopt, cgi, urllib __copyright__ = "Copyright (c) 2002 Mark Pilgrim"
try: __license__ = "Python"
import timeoutsocket # http://www.timo-tasi.org/python/timeoutsocket.py # Powersearch and return object type fix by Joseph Reagle <geek@goatee.net>
timeoutsocket.setDefaultSocketTimeout(10)
except ImportError: from xml.dom import minidom
pass import os, sys, getopt, cgi, urllib
try:
LICENSE_KEY = None import timeoutsocket # http://www.timo-tasi.org/python/timeoutsocket.py
HTTP_PROXY = None timeoutsocket.setDefaultSocketTimeout(10)
except ImportError:
# don't touch the rest of these constants pass
class AmazonError(Exception): pass
class NoLicenseKey(Exception): pass LICENSE_KEY = None
_amazonfile1 = ".amazonkey" HTTP_PROXY = None
_amazonfile2 = "amazonkey.txt"
_licenseLocations = ( # don't touch the rest of these constants
(lambda key: key, 'passed to the function in license_key variable'), class AmazonError(Exception): pass
(lambda key: LICENSE_KEY, 'module-level LICENSE_KEY variable (call setLicense to set it)'), class NoLicenseKey(Exception): pass
(lambda key: os.environ.get('AMAZON_LICENSE_KEY', None), 'an environment variable called AMAZON_LICENSE_KEY'), _amazonfile1 = ".amazonkey"
(lambda key: _contentsOf(os.getcwd(), _amazonfile1), '%s in the current directory' % _amazonfile1), _amazonfile2 = "amazonkey.txt"
(lambda key: _contentsOf(os.getcwd(), _amazonfile2), '%s in the current directory' % _amazonfile2), _licenseLocations = (
(lambda key: _contentsOf(os.environ.get('HOME', ''), _amazonfile1), '%s in your home directory' % _amazonfile1), (lambda key: key, 'passed to the function in license_key variable'),
(lambda key: _contentsOf(os.environ.get('HOME', ''), _amazonfile2), '%s in your home directory' % _amazonfile2), (lambda key: LICENSE_KEY, 'module-level LICENSE_KEY variable (call setLicense to set it)'),
(lambda key: _contentsOf(_getScriptDir(), _amazonfile1), '%s in the amazon.py directory' % _amazonfile1), (lambda key: os.environ.get('AMAZON_LICENSE_KEY', None), 'an environment variable called AMAZON_LICENSE_KEY'),
(lambda key: _contentsOf(_getScriptDir(), _amazonfile2), '%s in the amazon.py directory' % _amazonfile2) (lambda key: _contentsOf(os.getcwd(), _amazonfile1), '%s in the current directory' % _amazonfile1),
) (lambda key: _contentsOf(os.getcwd(), _amazonfile2), '%s in the current directory' % _amazonfile2),
(lambda key: _contentsOf(os.environ.get('HOME', ''), _amazonfile1), '%s in your home directory' % _amazonfile1),
## administrative functions (lambda key: _contentsOf(os.environ.get('HOME', ''), _amazonfile2), '%s in your home directory' % _amazonfile2),
def version(): (lambda key: _contentsOf(_getScriptDir(), _amazonfile1), '%s in the amazon.py directory' % _amazonfile1),
print """PyAmazon %(__version__)s (lambda key: _contentsOf(_getScriptDir(), _amazonfile2), '%s in the amazon.py directory' % _amazonfile2)
%(__copyright__)s )
released %(__date__)s
""" % globals() ## administrative functions
def version():
## utility functions print """PyAmazon %(__version__)s
def setLicense(license_key): %(__copyright__)s
"""set license key""" released %(__date__)s
global LICENSE_KEY """ % globals()
LICENSE_KEY = license_key
## utility functions
def getLicense(license_key = None): def setLicense(license_key):
"""get license key """set license key"""
global LICENSE_KEY
license key can come from any number of locations; LICENSE_KEY = license_key
see module docs for search order"""
for get, location in _licenseLocations: def getLicense(license_key = None):
rc = get(license_key) """get license key
if rc: return rc
raise NoLicenseKey, 'get a license key at http://www.amazon.com/webservices' license key can come from any number of locations;
see module docs for search order"""
def setProxy(http_proxy): for get, location in _licenseLocations:
"""set HTTP proxy""" rc = get(license_key)
global HTTP_PROXY if rc: return rc
HTTP_PROXY = http_proxy raise NoLicenseKey, 'get a license key at http://www.amazon.com/webservices'
def getProxy(http_proxy = None): def setProxy(http_proxy):
"""get HTTP proxy""" """set HTTP proxy"""
return http_proxy or HTTP_PROXY global HTTP_PROXY
HTTP_PROXY = http_proxy
def getProxies(http_proxy = None):
http_proxy = getProxy(http_proxy) def getProxy(http_proxy = None):
if http_proxy: """get HTTP proxy"""
proxies = {"http": http_proxy} return http_proxy or HTTP_PROXY
else:
proxies = None def getProxies(http_proxy = None):
return proxies http_proxy = getProxy(http_proxy)
if http_proxy:
def _contentsOf(dirname, filename): proxies = {"http": http_proxy}
filename = os.path.join(dirname, filename) else:
if not os.path.exists(filename): return None proxies = None
fsock = open(filename) return proxies
contents = fsock.read()
fsock.close() def _contentsOf(dirname, filename):
return contents filename = os.path.join(dirname, filename)
if not os.path.exists(filename): return None
def _getScriptDir(): fsock = open(filename)
if __name__ == '__main__': contents = fsock.read()
return os.path.abspath(os.path.dirname(sys.argv[0])) fsock.close()
else: return contents
return os.path.abspath(os.path.dirname(sys.modules[__name__].__file__))
def _getScriptDir():
class Bag: pass if __name__ == '__main__':
return os.path.abspath(os.path.dirname(sys.argv[0]))
def unmarshal(element): else:
rc = Bag() return os.path.abspath(os.path.dirname(sys.modules[__name__].__file__))
if isinstance(element, minidom.Element) and (element.tagName == 'Details'):
rc.URL = element.attributes["url"].value class Bag: pass
childElements = [e for e in element.childNodes if isinstance(e, minidom.Element)]
if childElements: def unmarshal(element):
for child in childElements: rc = Bag()
key = child.tagName if isinstance(element, minidom.Element) and (element.tagName == 'Details'):
if hasattr(rc, key): rc.URL = element.attributes["url"].value
if type(getattr(rc, key)) <> type([]): childElements = [e for e in element.childNodes if isinstance(e, minidom.Element)]
setattr(rc, key, [getattr(rc, key)]) if childElements:
setattr(rc, key, getattr(rc, key) + [unmarshal(child)]) for child in childElements:
else: key = child.tagName
setattr(rc, key, unmarshal(child)) if hasattr(rc, key):
else: if type(getattr(rc, key)) <> type([]):
rc = "".join([e.data for e in element.childNodes if isinstance(e, minidom.Text)]) setattr(rc, key, [getattr(rc, key)])
if element.tagName == 'SalesRank': setattr(rc, key, getattr(rc, key) + [unmarshal(child)])
rc = int(rc.replace(',', '')) elif isinstance(child, minidom.Element) and (child.tagName == 'Details'):
return rc # make the first Details element a key
setattr(rc,key,[unmarshal(child)])
def buildURL(search_type, keyword, product_line, type, page, license_key): #dbg: because otherwise 'hasattr' only tests
url = "http://xml.amazon.com/onca/xml3?v=1.0&f=xml&t=webservices-20" #dbg: on the second occurence: if there's a
url += "&dev-t=%s" % license_key.strip() #dbg: single return to a query, it's not a
url += "&type=%s" % type #dbg: list. This module should always
if page: #dbg: return a list of Details objects.
url += "&page=%s" % page else:
if product_line: setattr(rc, key, unmarshal(child))
url += "&mode=%s" % product_line else:
url += "&%s=%s" % (search_type, urllib.quote(keyword)) rc = "".join([e.data for e in element.childNodes if isinstance(e, minidom.Text)])
# print url if element.tagName == 'SalesRank':
return url rc = int(rc.replace(',', ''))
return rc
## main functions
def search(search_type, keyword, product_line, type="heavy", page=None, def buildURL(search_type, keyword, product_line, type, page, license_key):
license_key = None, http_proxy = None): url = "http://xml.amazon.com/onca/xml?v=1.0&f=xml&t=webservices-20"
"""search Amazon url += "&dev-t=%s" % license_key.strip()
url += "&type=%s" % type
You need a license key to call this function; see if page:
http://www.amazon.com/webservices url += "&page=%s" % page
to get one. Then you can either pass it to if product_line:
this function every time, or set it globally; see the module docs for details. url += "&mode=%s" % product_line
url += "&%s=%s" % (search_type, urllib.quote(keyword))
Parameters: return url
keyword - keyword to search
search_type - in (KeywordSearch, BrowseNodeSearch, AsinSearch, UpcSearch, AuthorSearch, ArtistSearch, ActorSearch, DirectorSearch, ManufacturerSearch, ListManiaSearch, SimilaritySearch)
product_line - type of product to search for. restrictions based on search_type ## main functions
UpcSearch - in (music, classical)
AuthorSearch - must be "books"
ArtistSearch - in (music, classical) def search(search_type, keyword, product_line, type="heavy", page=None,
ActorSearch - in (dvd, vhs, video) license_key = None, http_proxy = None):
DirectorSearch - in (dvd, vhs, video) """search Amazon
ManufacturerSearch - in (electronics, kitchen, videogames, software, photo, pc-hardware)
http_proxy (optional) - address of HTTP proxy to use for sending and receiving SOAP messages You need a license key to call this function; see
http://www.amazon.com/webservices
Returns: list of Bags, each Bag may contain the following attributes: to get one. Then you can either pass it to
Asin - Amazon ID ("ASIN" number) of this item this function every time, or set it globally; see the module docs for details.
Authors - list of authors
Availability - "available", etc. Parameters:
BrowseList - list of related categories keyword - keyword to search
Catalog - catalog type ("Book", etc) search_type - in (KeywordSearch, BrowseNodeSearch, AsinSearch, UpcSearch, AuthorSearch, ArtistSearch, ActorSearch, DirectorSearch, ManufacturerSearch, ListManiaSearch, SimilaritySearch)
CollectiblePrice - ?, format "$34.95" product_line - type of product to search for. restrictions based on search_type
ImageUrlLarge - URL of large image of this item UpcSearch - in (music, classical)
ImageUrlMedium - URL of medium image of this item AuthorSearch - must be "books"
ImageUrlSmall - URL of small image of this item ArtistSearch - in (music, classical)
Isbn - ISBN number ActorSearch - in (dvd, vhs, video)
ListPrice - list price, format "$34.95" DirectorSearch - in (dvd, vhs, video)
Lists - list of ListMania lists that include this item ManufacturerSearch - in (electronics, kitchen, videogames, software, photo, pc-hardware)
Manufacturer - manufacturer http_proxy (optional) - address of HTTP proxy to use for sending and receiving SOAP messages
Media - media ("Paperback", "Audio CD", etc)
NumMedia - number of different media types in which this item is available Returns: list of Bags, each Bag may contain the following attributes:
OurPrice - Amazon price, format "$24.47" Asin - Amazon ID ("ASIN" number) of this item
ProductName - name of this item Authors - list of authors
ReleaseDate - release date, format "09 April, 1999" Availability - "available", etc.
Reviews - reviews (AvgCustomerRating, plus list of CustomerReview with Rating, Summary, Content) BrowseList - list of related categories
SalesRank - sales rank (integer) Catalog - catalog type ("Book", etc)
SimilarProducts - list of Product, which is ASIN number CollectiblePrice - ?, format "$34.95"
ThirdPartyNewPrice - ?, format "$34.95" ImageUrlLarge - URL of large image of this item
URL - URL of this item ImageUrlMedium - URL of medium image of this item
""" ImageUrlSmall - URL of small image of this item
license_key = getLicense(license_key) Isbn - ISBN number
url = buildURL(search_type, keyword, product_line, type, page, license_key) ListPrice - list price, format "$34.95"
proxies = getProxies(http_proxy) Lists - list of ListMania lists that include this item
u = urllib.FancyURLopener(proxies) Manufacturer - manufacturer
usock = u.open(url) Media - media ("Paperback", "Audio CD", etc)
xmldoc = minidom.parse(usock) NumMedia - number of different media types in which this item is available
usock.close() OurPrice - Amazon price, format "$24.47"
data = unmarshal(xmldoc).ProductInfo ProductName - name of this item
if hasattr(data, 'ErrorMsg'): ReleaseDate - release date, format "09 April, 1999"
raise AmazonError, data.ErrorMsg Reviews - reviews (AvgCustomerRating, plus list of CustomerReview with Rating, Summary, Content)
else: SalesRank - sales rank (integer)
return data.Details SimilarProducts - list of Product, which is ASIN number
ThirdPartyNewPrice - ?, format "$34.95"
def searchByKeyword(keyword, product_line="books", type="heavy", page=1, license_key=None, http_proxy=None): URL - URL of this item
return search("KeywordSearch", keyword, product_line, type, page, license_key, http_proxy) """
license_key = getLicense(license_key)
def browseBestSellers(browse_node, product_line="books", type="heavy", page=1, license_key=None, http_proxy=None): url = buildURL(search_type, keyword, product_line, type, page, license_key)
return search("BrowseNodeSearch", browse_node, product_line, type, page, license_key, http_proxy) proxies = getProxies(http_proxy)
u = urllib.FancyURLopener(proxies)
def searchByASIN(ASIN, type="heavy", license_key=None, http_proxy=None): usock = u.open(url)
return search("AsinSearch", ASIN, None, type, None, license_key, http_proxy) xmldoc = minidom.parse(usock)
def searchByUPC(UPC, type="heavy", license_key=None, http_proxy=None): # from xml.dom.ext import PrettyPrint
return search("UpcSearch", UPC, None, type, None, license_key, http_proxy) # PrettyPrint(xmldoc)
def searchByAuthor(author, type="heavy", page=1, license_key=None, http_proxy=None): usock.close()
return search("AuthorSearch", author, "books", type, page, license_key, http_proxy) data = unmarshal(xmldoc).ProductInfo
if hasattr(data, 'ErrorMsg'):
def searchByArtist(artist, product_line="music", type="heavy", page=1, license_key=None, http_proxy=None): raise AmazonError, data.ErrorMsg
if product_line not in ("music", "classical"): else:
raise AmazonError, "product_line must be in ('music', 'classical')" return data.Details
return search("ArtistSearch", artist, product_line, type, page, license_key, http_proxy)
def searchByKeyword(keyword, product_line="books", type="heavy", page=1, license_key=None, http_proxy=None):
def searchByActor(actor, product_line="dvd", type="heavy", page=1, license_key=None, http_proxy=None): return search("KeywordSearch", keyword, product_line, type, page, license_key, http_proxy)
if product_line not in ("dvd", "vhs", "video"):
raise AmazonError, "product_line must be in ('dvd', 'vhs', 'video')" def browseBestSellers(browse_node, product_line="books", type="heavy", page=1, license_key=None, http_proxy=None):
return search("ActorSearch", actor, product_line, type, page, license_key, http_proxy) return search("BrowseNodeSearch", browse_node, product_line, type, page, license_key, http_proxy)
def searchByDirector(director, product_line="dvd", type="heavy", page=1, license_key=None, http_proxy=None): def searchByASIN(ASIN, type="heavy", license_key=None, http_proxy=None):
if product_line not in ("dvd", "vhs", "video"): return search("AsinSearch", ASIN, None, type, None, license_key, http_proxy)
raise AmazonError, "product_line must be in ('dvd', 'vhs', 'video')"
return search("DirectorSearch", director, product_line, type, page, license_key, http_proxy) def searchByUPC(UPC, type="heavy", license_key=None, http_proxy=None):
return search("UpcSearch", UPC, None, type, None, license_key, http_proxy)
def searchByManufacturer(manufacturer, product_line="pc-hardware", type="heavy", page=1, license_key=None, http_proxy=None):
if product_line not in ("electronics", "kitchen", "videogames", "software", "photo", "pc-hardware"): def searchByAuthor(author, type="heavy", page=1, license_key=None, http_proxy=None):
raise AmazonError, "product_line must be in ('electronics', 'kitchen', 'videogames', 'software', 'photo', 'pc-hardware')" return search("AuthorSearch", author, "books", type, page, license_key, http_proxy)
return search("ManufacturerSearch", manufacturer, product_line, type, page, license_key, http_proxy)
def searchByArtist(artist, product_line="music", type="heavy", page=1, license_key=None, http_proxy=None):
def searchByListMania(listManiaID, type="heavy", page=1, license_key=None, http_proxy=None): if product_line not in ("music", "classical"):
return search("ListManiaSearch", listManiaID, None, type, page, license_key, http_proxy) raise AmazonError, "product_line must be in ('music', 'classical')"
return search("ArtistSearch", artist, product_line, type, page, license_key, http_proxy)
def searchSimilar(ASIN, type="heavy", page=1, license_key=None, http_proxy=None):
return search("SimilaritySearch", ASIN, None, type, page, license_key, http_proxy) def searchByActor(actor, product_line="dvd", type="heavy", page=1, license_key=None, http_proxy=None):
# vim:set shiftwidth=4 tabstop=8 expandtab textwidth=78: if product_line not in ("dvd", "vhs", "video"):
raise AmazonError, "product_line must be in ('dvd', 'vhs', 'video')"
return search("ActorSearch", actor, product_line, type, page, license_key, http_proxy)
def searchByDirector(director, product_line="dvd", type="heavy", page=1, license_key=None, http_proxy=None):
if product_line not in ("dvd", "vhs", "video"):
raise AmazonError, "product_line must be in ('dvd', 'vhs', 'video')"
return search("DirectorSearch", director, product_line, type, page, license_key, http_proxy)
def searchByManufacturer(manufacturer, product_line="pc-hardware", type="heavy", page=1, license_key=None, http_proxy=None):
if product_line not in ("electronics", "kitchen", "videogames", "software", "photo", "pc-hardware"):
raise AmazonError, "product_line must be in ('electronics', 'kitchen', 'videogames', 'software', 'photo', 'pc-hardware')"
return search("ManufacturerSearch", manufacturer, product_line, type, page, license_key, http_proxy)
def searchByListMania(listManiaID, type="heavy", page=1, license_key=None, http_proxy=None):
return search("ListManiaSearch", listManiaID, None, type, page, license_key, http_proxy)
def searchSimilar(ASIN, type="heavy", page=1, license_key=None, http_proxy=None):
return search("SimilaritySearch", ASIN, None, type, page, license_key, http_proxy)
def searchByWishlist(wishlistID, type="heavy", page=1, license_key=None, http_proxy=None):
return search("WishlistSearch", wishlistID, None, type, page, license_key, http_proxy)
def searchByPower(keyword, product_line="books", type="heavy", page=1, license_key=None, http_proxy=None):
return search("PowerSearch", keyword, product_line, type, page, license_key, http_proxy)
# >>> RecentKing = amazon.searchByPower('author:Stephen King and pubdate:2003')
# >>> SnowCrash = amazon.searchByPower('title:Snow Crash')

View File

@ -69,6 +69,8 @@ class Amazon(callbacks.Privmsg):
def _genResults(self, reply, attribs, items, url): def _genResults(self, reply, attribs, items, url):
results = {} results = {}
res = [] res = []
if isinstance(items, amazon.Bag):
items = [items]
for item in items: for item in items:
try: try:
for k,v in attribs.iteritems(): for k,v in attribs.iteritems():
@ -86,6 +88,8 @@ class Amazon(callbacks.Privmsg):
res.append(str(s)) res.append(str(s))
except amazon.AmazonError, e: except amazon.AmazonError, e:
self.log.warning(str(e)) self.log.warning(str(e))
except UnicodeEncodeError, e:
self.log.warning(str(e))
return res return res
def licensekey(self, irc, msg, args): def licensekey(self, irc, msg, args):
@ -121,7 +125,7 @@ class Amazon(callbacks.Privmsg):
'URL' : 'url' 'URL' : 'url'
} }
s = '"%(title)s", written by %(author)s; published by '\ s = '"%(title)s", written by %(author)s; published by '\
'%(publisher)s.%(url)s' '%(publisher)s%(url)s'
try: try:
book = amazon.searchByKeyword(isbn) book = amazon.searchByKeyword(isbn)
res = self._genResults(s, attribs, book, url) res = self._genResults(s, attribs, book, url)
@ -130,7 +134,70 @@ class Amazon(callbacks.Privmsg):
return return
except amazon.AmazonError, e: except amazon.AmazonError, e:
pass pass
irc.reply(msg, 'No book was found with that ISBN.') irc.error(msg, 'No book was found with that ISBN.')
def asin(self, irc, msg, args):
"""[--url] <asin>
Returns the item matching the given ASIN number. If --url is
specified, a link to amazon.com's page for the item will also be
returned.
"""
opts = ['url']
(optlist, rest) = getopt.getopt(args, '', opts)
url = False
for (option, argument) in optlist:
option = option.lstrip('-')
if option == 'url':
url = True
asin = privmsgs.getArgs(rest)
asin = asin.replace('-', '').replace(' ', '')
attribs = {'ProductName' : 'title',
'URL' : 'url'
}
s = '"%(title)s"%(url)s'
try:
item = amazon.searchByASIN(asin)
res = self._genResults(s, attribs, item, url)
if res:
irc.reply(msg, utils.commaAndify(res))
return
except amazon.AmazonError, e:
pass
irc.error(msg, 'No item was found with that ASIN.')
def upc(self, irc, msg, args):
"""[--url] <upc>
Returns the item matching the given UPC number. If --url is
specified, a link to amazon.com's page for the item will also be
returned. Only items in the following categories may be found via upc
search: music, classical, software, dvd, video, vhs, electronics,
pc-hardware, and photo.
"""
opts = ['url']
(optlist, rest) = getopt.getopt(args, '', opts)
url = False
for (option, argument) in optlist:
option = option.lstrip('-')
if option == 'url':
url = True
upc = privmsgs.getArgs(rest)
upc = upc.replace('-', '').replace(' ', '')
attribs = {'ProductName' : 'title',
'Manufacturer' : 'manufacturer',
'URL' : 'url'
}
s = '"%(title)s" %(manufacturer)s%(url)s'
try:
item = amazon.searchByUPC(upc)
res = self._genResults(s, attribs, item, url)
if res:
irc.reply(msg, utils.commaAndify(res))
return
except amazon.AmazonError, e:
pass
irc.error(msg, 'No item was found with that UPC.')
def author(self, irc, msg, args): def author(self, irc, msg, args):
"""[--url] <author> """[--url] <author>
@ -147,14 +214,13 @@ class Amazon(callbacks.Privmsg):
if option == 'url': if option == 'url':
url = True url = True
author = privmsgs.getArgs(rest) author = privmsgs.getArgs(rest)
self.log.info(author)
attribs = {'ProductName' : 'title', attribs = {'ProductName' : 'title',
'Manufacturer' : 'publisher', 'Manufacturer' : 'publisher',
'Authors' : 'author', 'Authors' : 'author',
'URL' : 'url' 'URL' : 'url'
} }
s = '"%(title)s", written by %(author)s; published by '\ s = '"%(title)s", written by %(author)s; published by '\
'%(publisher)s.%(url)s' '%(publisher)s%(url)s'
try: try:
books = amazon.searchByAuthor(author) books = amazon.searchByAuthor(author)
res = self._genResults(s, attribs, books, url) res = self._genResults(s, attribs, books, url)
@ -163,7 +229,66 @@ class Amazon(callbacks.Privmsg):
return return
except amazon.AmazonError, e: except amazon.AmazonError, e:
pass pass
irc.reply(msg, 'No books were found by that author.') irc.error(msg, 'No books were found by that author.')
# FIXME: Until I get a *good* list of categories (ones that actually work),
# these commands will remain unavailable
'''
_textToNode = {'dvds':'130', 'magazines':'599872', 'music':'301668',
'software':'491286', 'vhs':'404272', 'kitchen':'491864',
'video games':'471280', 'toys':'491290', 'camera':'502394',
'outdoor':'468250', 'computers':'565118', 'tools':'468240',
'electronics':'172282'
}
def categories(self, irc, msg, args):
"""takes no arguments
Returns a list of valid categories to use with the bestsellers
commands.
"""
cats = self._textToNode.keys()
cats.sort()
irc.reply(msg, utils.commaAndify(cats))
def bestsellers(self, irc, msg, args):
"""[--url] <category>
Returns a list of best selling items in <category>. The 'categories'
command will return a list of the available categores. If --url
is specified, a link to amazon.com's page for the item will also be
returned.
"""
opts = ['url']
(optlist, rest) = getopt.getopt(args, '', opts)
url = False
for (option, argument) in optlist:
option = option.lstrip('-')
if option == 'url':
url = True
category = privmsgs.getArgs(rest).lower()
if category not in self._textToNode:
irc.error(msg, 'An invalid category was specified. The categories'
' command will return a list of valid categories')
return
category = self._textToNode[category]
attribs = {'ProductName' : 'title',
'Manufacturer' : 'publisher',
'URL' : 'url'
}
s = '"%(title)s", from %(publisher)s.%(url)s'
try:
self.log.warning(category)
items = amazon.browseBestSellers(category)
self.log.warning(items)
res = self._genResults(s, attribs, items, url)
if res:
irc.reply(msg, utils.commaAndify(res))
return
except amazon.AmazonError, e:
pass
irc.error(msg, 'No items were found on that best seller list.')
'''
def artist(self, irc, msg, args): def artist(self, irc, msg, args):
"""[--url] [--{music,classical}] <artist> """[--url] [--{music,classical}] <artist>
@ -192,7 +317,7 @@ class Amazon(callbacks.Privmsg):
'URL' : 'url' 'URL' : 'url'
} }
s = '"%(title)s" (%(media)s), by %(artist)s; published by '\ s = '"%(title)s" (%(media)s), by %(artist)s; published by '\
'%(publisher)s.%(url)s' '%(publisher)s%(url)s'
try: try:
items = amazon.searchByArtist(artist, product_line=product) items = amazon.searchByArtist(artist, product_line=product)
res = self._genResults(s, attribs, items, url) res = self._genResults(s, attribs, items, url)
@ -201,7 +326,7 @@ class Amazon(callbacks.Privmsg):
return return
except amazon.AmazonError, e: except amazon.AmazonError, e:
pass pass
irc.reply(msg, 'No items were found by that artist.') irc.error(msg, 'No items were found by that artist.')
def actor(self, irc, msg, args): def actor(self, irc, msg, args):
"""[--url] [--{dvd,vhs,video}] <actor> """[--url] [--{dvd,vhs,video}] <actor>
@ -231,7 +356,7 @@ class Amazon(callbacks.Privmsg):
'URL' : 'url' 'URL' : 'url'
} }
s = '"%(title)s" (%(media)s), rated %(mpaa)s; released '\ s = '"%(title)s" (%(media)s), rated %(mpaa)s; released '\
'%(date)s; published by %(publisher)s.%(url)s' '%(date)s; published by %(publisher)s%(url)s'
try: try:
items = amazon.searchByActor(actor, product_line=product) items = amazon.searchByActor(actor, product_line=product)
res = self._genResults(s, attribs, items, url) res = self._genResults(s, attribs, items, url)
@ -240,7 +365,46 @@ class Amazon(callbacks.Privmsg):
return return
except amazon.AmazonError, e: except amazon.AmazonError, e:
pass pass
irc.reply(msg, 'No items were found starring that actor.') irc.error(msg, 'No items were found starring that actor.')
def director(self, irc, msg, args):
"""[--url] [--{dvd,vhs,video}] <director>
Returns a list of items by the given director. If --url is
specified, a link to amazon.com's page for the match will also be
returned. The search defaults to using --dvd.
"""
products = ['dvd', 'video', 'vhs']
opts = ['url']
(optlist, rest) = getopt.getopt(args, '', products + opts)
url = False
product = ''
for (option, argument) in optlist:
option = option.lstrip('-')
if option == 'url':
url = True
if option in products:
product = option
product = product or 'dvd'
director = privmsgs.getArgs(rest)
attribs = {'ProductName' : 'title',
'Manufacturer' : 'publisher',
'MpaaRating' : 'mpaa',
'Media' : 'media',
'ReleaseDate' : 'date',
'URL' : 'url'
}
s = '"%(title)s" (%(media)s), rated %(mpaa)s; released '\
'%(date)s; published by %(publisher)s%(url)s'
try:
items = amazon.searchByDirector(director, product_line=product)
res = self._genResults(s, attribs, items, url)
if res:
irc.reply(msg, utils.commaAndify(res))
return
except amazon.AmazonError, e:
pass
irc.error(msg, 'No items were found by that director.')
def manufacturer(self, irc, msg, args): def manufacturer(self, irc, msg, args):
""" [--url] \ """ [--url] \
@ -255,7 +419,6 @@ class Amazon(callbacks.Privmsg):
'photo', 'pc-hardware'] 'photo', 'pc-hardware']
opts = ['url'] opts = ['url']
(optlist, rest) = getopt.getopt(args, '', products + opts) (optlist, rest) = getopt.getopt(args, '', products + opts)
self.log.info(rest)
url = False url = False
product = '' product = ''
for (option, argument) in optlist: for (option, argument) in optlist:
@ -267,11 +430,9 @@ class Amazon(callbacks.Privmsg):
product = product or 'pc-hardware' product = product or 'pc-hardware'
manufacturer = privmsgs.getArgs(rest) manufacturer = privmsgs.getArgs(rest)
attribs = {'ProductName' : 'title', attribs = {'ProductName' : 'title',
'Catalog' : 'catalog',
'Manufacturer' : 'manufacturer',
'URL' : 'url' 'URL' : 'url'
} }
s = '"%(title)s" (%(catalog)s), by %(manufacturer)s.%(url)s' s = '"%(title)s"%(url)s'
try: try:
items = amazon.searchByManufacturer(manufacturer, items = amazon.searchByManufacturer(manufacturer,
product_line=product) product_line=product)
@ -281,7 +442,7 @@ class Amazon(callbacks.Privmsg):
return return
except amazon.AmazonError, e: except amazon.AmazonError, e:
pass pass
irc.reply(msg, 'No items were found by that manufacturer.') irc.error(msg, 'No items were found by that manufacturer.')
Class = Amazon Class = Amazon

View File

@ -33,7 +33,62 @@ from testsupport import *
class AmazonTestCase(PluginTestCase, PluginDocumentation): class AmazonTestCase(PluginTestCase, PluginDocumentation):
plugins = ('Amazon',) plugins = ('Amazon',)
def setUp(self):
PluginTestCase.setUp(self)
self.assertNotError('licensekey test')
def testIsbn(self):
self.assertHelp('isbn')
self.assertRegexp('isbn 0738203793', r'Buckminster Fuller\'s Universe')
self.assertRegexp('isbn --url 0738203793', r'Buck.*/exec/obidos/ASIN')
def testAsin(self):
self.assertHelp('asin')
self.assertRegexp('asin B00005JM5E', r'Pirates of the Caribbean')
self.assertRegexp('asin --url B00005JM5E', r'Pirate.*ASIN/B00005JM5E')
def testUpc(self):
self.assertHelp('upc')
self.assertRegexp('upc 093624586425', r'Short Bus')
self.assertRegexp('upc --url 093624586425', r'Short Bus.*/exec/obidos')
def testAuthor(self):
self.assertHelp('author')
self.assertRegexp('author torvalds', r'Just for Fun')
self.assertRegexp('author --url torvalds', r'Linus.*/exec/obidos')
def testArtist(self):
self.assertHelp('artist')
self.assertRegexp('artist rahzel', r'Audio CD')
self.assertRegexp('artist --url rahzel', r'Audio CD.*/exec/obidos')
self.assertRegexp('artist --classical rahzel', r'No items were found')
self.assertRegexp('artist --classical vivaldi', r'Audio CD')
def testActor(self):
self.assertHelp('actor')
self.assertRegexp('actor bruce lee', r'DVD')
self.assertRegexp('actor --url bruce lee', r'DVD.*/exec/obidos/')
self.assertRegexp('actor --vhs bruce lee', r'VHS Tape')
self.assertRegexp('actor --video bruce lee', r'DVD|VHS Tape')
def testDirector(self):
self.assertHelp('director')
self.assertRegexp('director gore verbinski', r'DVD')
self.assertRegexp('director --url gore verbinski',
r'DVD.*/exec/obidos/')
self.assertRegexp('director --vhs gore verbinski', r'VHS Tape')
self.assertRegexp('director --video gore verbinski', r'DVD|VHS Tape')
def testManufacturer(self):
self.assertHelp('manufacturer')
self.assertRegexp('manufacturer iomega', r'Iomega')
self.assertRegexp('manufacturer --url iomega',
r'Iomega.*/exec/obidos/')
self.assertRegexp('manufacturer --electronics plextor', r'Plextor')
self.assertRegexp('manufacturer --kitchen henckels', r'Henckels')
self.assertRegexp('manufacturer --videogames ea', r'Madden')
self.assertRegexp('manufacturer --software adobe', r'Photoshop')
self.assertRegexp('manufacturer --photo kodak', r'Kodak')
# vim:set shiftwidth=4 tabstop=8 expandtab textwidth=78: # vim:set shiftwidth=4 tabstop=8 expandtab textwidth=78: