예제 #1
0
class AmazonScraper(object):
    def __init__(self, access_key, secret_key, associate_tag, *args, **kwargs):
        self.api = AmazonAPI(access_key, secret_key, associate_tag, *args, **kwargs)

    def reviews(self, ItemId=None, URL=None):
        return Reviews(self, ItemId, URL)

    def review(self, Id=None, URL=None):
        return Review(self, Id, URL)

    def lookup(self, URL=None, **kwargs):
        if URL:
            kwargs['ItemId'] = extract_asin(URL)

        result = self.api.lookup(**kwargs)
        if isinstance(result, (list, tuple)):
            result = [Product(p) for p in result]
        else:
            result = Product(result)
        return result

    def similarity_lookup(self, **kwargs):
        for p in self.api.similarity_lookup(**kwargs):
            yield Product(p)

    def browse_node_lookup(self, **kwargs):
        return self.api.browse_node_lookup(**kwargs)

    def search(self, **kwargs):
        for p in self.api.search(**kwargs):
            yield Product(p)

    def search_n(self, n, **kwargs):
        for p in self.api.search_n(n, **kwargs):
            yield Product(p)
예제 #2
0
class AmazonScraper(object):
    def __init__(self, access_key, secret_key, associate_tag, *args, **kwargs):
        self.api = AmazonAPI(access_key, secret_key, associate_tag, *args, **kwargs)

    def reviews(self, ItemId=None, URL=None):
        return Reviews(self, ItemId, URL)

    def review(self, Id=None, URL=None):
        return Review(self, Id, URL)

    def reviewer(self, url):
        return Reviewer(url)

    def lookup(self, URL=None, **kwargs):
        if URL:
            kwargs['ItemId'] = extract_asin(URL)

        result = self.api.lookup(**kwargs)
        if isinstance(result, (list, tuple)):
            result = [Product(p) for p in result]
        else:
            result = Product(result)
        return result

    def similarity_lookup(self, **kwargs):
        for p in self.api.similarity_lookup(**kwargs):
            yield Product(p)

    def browse_node_lookup(self, **kwargs):
        return self.api.browse_node_lookup(**kwargs)

    def search(self, **kwargs):
        for p in self.api.search(**kwargs):
            yield Product(p)

    def search_n(self, n, **kwargs):
        for p in self.api.search_n(n, **kwargs):
            yield Product(p)
예제 #3
0
class TestAmazonApi(TestCase):
    """Test Amazon API

    Test Class for Amazon simple API wrapper.
    """
    def setUp(self):
        """Set Up.

        Initialize the Amazon API wrapper. The following values:

        * AMAZON_ACCESS_KEY
        * AMAZON_SECRET_KEY
        * AMAZON_ASSOC_TAG

        Are imported from a custom file named: 'test_settings.py'
        """
        self.amazon = AmazonAPI(
            AMAZON_ACCESS_KEY, AMAZON_SECRET_KEY, AMAZON_ASSOC_TAG)

    def test_lookup(self):
        """Test Product Lookup.

        Tests that a product lookup for a kindle returns results and that the
        main methods are working.
        """
        product = self.amazon.lookup(ItemId="B007HCCNJU")
        assert_true('Kindle' in product.title)
        assert_equals(product.ean, '0814916017775')
        assert_equals(
            product.large_image_url,
            'http://ecx.images-amazon.com/images/I/41VZlVs8agL.jpg'
        )
        assert_equals(
            product.get_attribute('Publisher'),
            'Amazon'
        )
        assert_equals(product.get_attributes(
            ['ItemDimensions.Width', 'ItemDimensions.Height']),
            {'ItemDimensions.Width': '650', 'ItemDimensions.Height': '130'})
        assert_true(len(product.browse_nodes) > 0)
        assert_true(product.price_and_currency[0] is not None)
        assert_true(product.price_and_currency[1] is not None)
        assert_equals(product.browse_nodes[0].id, 2642129011)
        assert_equals(product.browse_nodes[0].name, 'eBook Readers')

    def test_batch_lookup(self):
        """Test Batch Product Lookup.

        Tests that a batch product lookup request returns multiple results.
        """
        asins = ['B00AWH595M', 'B007HCCNJU', 'B00BWYQ9YE',
                 'B00BWYRF7E', 'B00D2KJDXA']
        products = self.amazon.lookup(ItemId=','.join(asins))
        assert_equals(len(products), 5)
        for i, product in enumerate(products):
            assert_equals(asins[i], product.asin)

    def test_search(self):
        """Test Product Search.

        Tests that a product search is working (by testing that results are
        returned). And that each result has a title attribute. The test
        fails if no results where returned.
        """
        products = self.amazon.search(Keywords='kindle', SearchIndex='All')
        for product in products:
            assert_true(hasattr(product, 'title'))
            break
        else:
            assert_true(False, 'No search results returned.')

    def test_search_n(self):
        """Test Product Search N.

        Tests that a product search n is working by testing that N results are
        returned.
        """
        products = self.amazon.search_n(
            1,
            Keywords='kindle',
            SearchIndex='All'
        )
        assert_equals(len(products), 1)

    def test_amazon_api_defaults_to_US(self):
        """Test Amazon API defaults to the US store."""
        amazon = AmazonAPI(
            AMAZON_ACCESS_KEY,
            AMAZON_SECRET_KEY,
            AMAZON_ASSOC_TAG
        )
        assert_equals(amazon.api.Region, "US")

    def test_search_amazon_uk(self):
        """Test Poduct Search on Amazon UK.

        Tests that a product search on Amazon UK is working and that the
        currency of any of the returned products is GBP. The test fails if no
        results were returned.
        """
        amazon = AmazonAPI(
            AMAZON_ACCESS_KEY,
            AMAZON_SECRET_KEY,
            AMAZON_ASSOC_TAG,
            region="UK"
        )
        assert_equals(amazon.api.Region, "UK", "Region has not been set to UK")

        products = amazon.search(Keywords='Kindle', SearchIndex='All')
        currencies = [product.price_and_currency[1] for product in products]
        assert_true(len(currencies), "No products found")

        is_gbp = 'GBP' in currencies
        assert_true(is_gbp, "Currency is not GBP, cannot be Amazon UK, though")

    def test_similarity_lookup(self):
        """Test Similarity Lookup.

        Tests that a similarity lookup for a kindle returns 10 results.
        """
        products = self.amazon.similarity_lookup(ItemId="B0051QVF7A")
        assert_true(len(products) > 5)

    def test_product_attributes(self):
        """Test Product Attributes.

        Tests that all product that are supposed to be accessible are.
        """
        product = self.amazon.lookup(ItemId="B0051QVF7A")
        for attribute in PRODUCT_ATTRIBUTES:
            getattr(product, attribute)

    def test_browse_node_lookup(self):
        """Test Browse Node Lookup.

        Test that a lookup by Brose Node ID returns appropriate node.
        """
        bnid = 2642129011
        bn = self.amazon.browse_node_lookup(BrowseNodeId=bnid)[0]
        assert_equals(bn.id, bnid)
        assert_equals(bn.name, 'eBook Readers')
        assert_equals(bn.is_category_root, False)

    def test_obscure_date(self):
        """Test Obscure Date Formats

        Test a product with an obscure date format
        """
        product = self.amazon.lookup(ItemId="0933635869")
        assert_equals(product.publication_date.year, 1992)
        assert_equals(product.publication_date.month, 5)
        assert_true(isinstance(product.publication_date, datetime.date))

    def test_single_creator(self):
        """Test a product with a single creator
        """
        product = self.amazon.lookup(ItemId="B00005NZJA")
        creators = dict(product.creators)
        assert_equals(creators[u"Jonathan Davis"], u"Narrator")
        assert_equals(len(creators.values()), 1)

    def test_multiple_creators(self):
        """Test a product with multiple creators
        """
        product = self.amazon.lookup(ItemId="B007V8RQC4")
        creators = dict(product.creators)
        assert_equals(creators[u"John Gregory Betancourt"], u"Editor")
        assert_equals(creators[u"Colin Azariah-Kribbs"], u"Editor")
        assert_equals(len(creators.values()), 2)

    def test_no_creators(self):
        """Test a product with no creators
        """
        product = self.amazon.lookup(ItemId="8420658537")
        assert_false(product.creators)

    def test_single_editorial_review(self):
        product = self.amazon.lookup(ItemId="1930846258")
        expected = u'In the title piece, Alan Turing'
        assert_equals(product.editorial_reviews[0][:len(expected)], expected)
        assert_equals(product.editorial_review, product.editorial_reviews[0])
        assert_equals(len(product.editorial_reviews), 1)

    def test_multiple_editorial_reviews(self):
        product = self.amazon.lookup(ItemId="B000FBJCJE")
        expected = u'Only once in a great'
        assert_equals(product.editorial_reviews[0][:len(expected)], expected)
        expected = u'From the opening line'
        assert_equals(product.editorial_reviews[1][:len(expected)], expected)
        # duplicate data, amazon user data is great...
        expected = u'Only once in a great'
        assert_equals(product.editorial_reviews[2][:len(expected)], expected)

        assert_equals(len(product.editorial_reviews), 3)

    def test_languages_english(self):
        """Test Language Data

        Test an English product
        """
        product = self.amazon.lookup(ItemId="1930846258")
        assert_true('english' in product.languages)
        assert_equals(len(product.languages), 1)

    def test_languages_spanish(self):
        """Test Language Data

        Test an English product
        """
        product = self.amazon.lookup(ItemId="8420658537")
        assert_true('spanish' in product.languages)
        assert_equals(len(product.languages), 1)
class TestAmazonApi(TestCase):
    """Test Amazon API

    Test Class for Amazon simple API wrapper.
    """
    def setUp(self):
        """Set Up.

        Initialize the Amazon API wrapper. The following values:

        * AMAZON_ACCESS_KEY
        * AMAZON_SECRET_KEY
        * AMAZON_ASSOC_TAG

        Are imported from a custom file named: 'test_settings.py'
        """
        self.amazon = AmazonAPI(AMAZON_ACCESS_KEY, AMAZON_SECRET_KEY,
                                AMAZON_ASSOC_TAG)

    def test_lookup(self):
        """Test Product Lookup.

        Tests that a product lookup for a kindle returns results and that the
        main methods are working.
        """
        product = self.amazon.lookup(ItemId="B007HCCNJU")
        assert_true('Kindle' in product.title)
        assert_equals(product.ean, '0814916017775')
        assert_equals(product.large_image_url,
                      'http://ecx.images-amazon.com/images/I/41VZlVs8agL.jpg')
        assert_equals(product.get_attribute('Publisher'), 'Amazon')
        assert_equals(
            product.get_attributes(
                ['ItemDimensions.Width', 'ItemDimensions.Height']), {
                    'ItemDimensions.Width': '650',
                    'ItemDimensions.Height': '130'
                })
        assert_true(len(product.browse_nodes) > 0)
        assert_true(product.price_and_currency[0] is not None)
        assert_true(product.price_and_currency[1] is not None)
        assert_equals(product.browse_nodes[0].id, 2642129011)
        assert_equals(product.browse_nodes[0].name, 'eBook Readers')

    def test_batch_lookup(self):
        """Test Batch Product Lookup.

        Tests that a batch product lookup request returns multiple results.
        """
        asins = [
            'B0051QVESA', 'B005DOK8NW', 'B005890G8Y', 'B0051VVOB2',
            'B005890G8O'
        ]
        products = self.amazon.lookup(ItemId=','.join(asins))
        assert_equals(len(products), 5)
        for i, product in enumerate(products):
            assert_equals(asins[i], product.asin)

    def test_search(self):
        """Test Product Search.

        Tests that a product search is working (by testing that results are
        returned). And that each result has a title attribute. The test
        fails if no results where returned.
        """
        products = self.amazon.search(Keywords='kindle', SearchIndex='All')
        for product in products:
            assert_true(hasattr(product, 'title'))
            break
        else:
            assert_true(False, 'No search results returned.')

    def test_search_n(self):
        """Test Product Search N.

        Tests that a product search n is working by testing that N results are
        returned.
        """
        products = self.amazon.search_n(1,
                                        Keywords='kindle',
                                        SearchIndex='All')
        assert_equals(len(products), 1)

    def test_amazon_api_defaults_to_US(self):
        """Test Amazon API defaults to the US store."""
        amazon = AmazonAPI(AMAZON_ACCESS_KEY, AMAZON_SECRET_KEY,
                           AMAZON_ASSOC_TAG)
        assert_equals(amazon.api.Region, "US")

    def test_search_amazon_uk(self):
        """Test Poduct Search on Amazon UK.

        Tests that a product search on Amazon UK is working and that the
        currency of any of the returned products is GBP. The test fails if no
        results were returned.
        """
        amazon = AmazonAPI(AMAZON_ACCESS_KEY,
                           AMAZON_SECRET_KEY,
                           AMAZON_ASSOC_TAG,
                           region="UK")
        assert_equals(amazon.api.Region, "UK", "Region has not been set to UK")

        products = amazon.search(Keywords='Kindle', SearchIndex='All')
        currencies = [product.price_and_currency[1] for product in products]
        assert_true(len(currencies), "No products found")

        is_gbp = 'GBP' in currencies
        assert_true(is_gbp, "Currency is not GBP, cannot be Amazon UK, though")

    def test_similarity_lookup(self):
        """Test Similarity Lookup.

        Tests that a similarity lookup for a kindle returns 10 results.
        """
        products = self.amazon.similarity_lookup(ItemId="B0051QVF7A")
        assert_equals(len(products), 10)

    def test_product_attributes(self):
        """Test Product Attributes.

        Tests that all product that are supposed to be accessible are.
        """
        product = self.amazon.lookup(ItemId="B0051QVF7A")
        for attribute in PRODUCT_ATTRIBUTES:
            getattr(product, attribute)

    def test_browse_node_lookup(self):
        """Test Browse Node Lookup.

        Test that a lookup by Brose Node ID returns appropriate node.
        """
        bnid = 2642129011
        bn = self.amazon.browse_node_lookup(BrowseNodeId=bnid)[0]
        assert_equals(bn.id, bnid)
        assert_equals(bn.name, 'eBook Readers')
        assert_equals(bn.is_category_root, False)
예제 #5
0
def main():
    #Read setup, Reddit, and Amazon configurations from config.ini
    config = ConfigParser.ConfigParser()
    config.read("config.ini")
    NUM_RETRIEVE = int(
        config.get("setup", "NUM_RETRIEVE")
    )  #Number of submissions to retrieve from "New" in each subreddit
    MIN_CONFIDENCE = int(config.get(
        "setup",
        "MIN_CONFIDENCE"))  #Minimum confidence to reply to keyword call
    SENTENCES_IN_REPLY = int(config.get(
        "setup", "SENTENCES_IN_REPLY"))  #Maximum number of sentences in reply
    SLEEP_TIME = int(config.get("setup",
                                "SLEEP_TIME"))  #Time between pulls, in seconds
    USERNAME = config.get("praw", "USERNAME")
    PASSWORD = config.get("praw", "PASSWORD")
    USER_AGENT = config.get("praw", "USER_AGENT")
    AMAZON_KEY = config.get("amazon", "AMAZON_KEY")
    AMAZON_SECRET = config.get("amazon", "AMAZON_SECRET")
    AMAZON_ASSOCIATE = config.get("amazon", "AMAZON_ASSOCIATE")

    #Initialize variables
    global keywords, c
    alreadyReplied = [
    ]  #Users and submissions that have already been replied to
    keywords = pandas.read_csv(
        'data.csv')  #Items, suggestives, blacklist, subreddits
    conn = sqlite3.connect(
        'templates.db')  #Sentence templates (brand, category, price, link)
    c = conn.cursor()
    subreddits = "+".join(
        [line.strip() for line in keywords['subreddits'].dropna()])

    #Connect to Reddit and Amazon
    r = praw.Reddit(USER_AGENT)
    r.login(USERNAME, PASSWORD, disable_warning=True)
    amazon = AmazonAPI(AMAZON_KEY, AMAZON_SECRET, AMAZON_ASSOCIATE)

    while True:
        submissions = r.get_subreddit(subreddits)
        #Get 'NUM_RETRIEVE' newest submissions from subreddits
        for i in submissions.get_new(limit=NUM_RETRIEVE):
            try:
                if str(i.author) in alreadyReplied:
                    raise ValueError('SKIPPING: ALREADY REPLIED TO AUTHOR')
                if 'reddit.com' not in i.url:
                    raise ValueError('SKIPPING: LINK SUBMISSION')

                #Amazon link in submission (self) text
                str_self = i.selftext.encode('utf-8').lower()
                if ('/dp/' in str_self) or ('/gp/' in str_self):
                    productData = find_in_amazon(
                        amazon, AMAZON_ASSOCIATE,
                        amazon.similarity_lookup(ItemId=get_ASIN(str_self))[0])
                    if type(productData) is dict:
                        print "FOUND", productData['link'], "IN SELF:", i.id
                        alreadyReplied.append(str(
                            i.author))  #Add username to cache
                        print ""
                        print generate_Comment(
                            SENTENCES_IN_REPLY, productData['link'],
                            productData['brand'],
                            str(productData['category']).lower(),
                            productData['price'], productData['features'],
                            productData['reviews'])
                        i.add_comment(
                            generate_Comment(
                                SENTENCES_IN_REPLY, productData['link'],
                                productData['brand'],
                                str(productData['category']).lower(),
                                productData['price'], productData['features'],
                                productData['reviews']))
                        print ""
                        raise ValueError('SKIPPING: DONE REPLYING')
                    elif type(productData) is str:
                        print productData  #Error

                #Amazon link in comment
                for comment in i.comments:
                    str_comment = str(comment).lower()
                    if (str(comment.author) not in alreadyReplied) and (
                        ('/dp/' in str_comment) or ('/gp/' in str_comment)):
                        productData = find_in_amazon(
                            amazon, AMAZON_ASSOCIATE,
                            amazon.similarity_lookup(
                                ItemId=str(get_ASIN(str_comment)))[0])
                        if type(productData) is dict:
                            print "FOUND", productData[
                                'link'], "IN COMMENT", comment.id
                            alreadyReplied.append(str(
                                i.author))  #Add username to cache
                            alreadyReplied.append(str(
                                comment.author))  #Add username to cache
                            print ""
                            print generate_amazonCommentReply(
                                SENTENCES_IN_REPLY, productData['link'],
                                productData['brand'],
                                str(productData['category']).lower(),
                                productData['price'], productData['features'],
                                productData['reviews'])
                            comment.reply(
                                generate_amazonCommentReply(
                                    SENTENCES_IN_REPLY, productData['link'],
                                    productData['brand'],
                                    str(productData['category']).lower(),
                                    productData['price'],
                                    productData['features'],
                                    productData['reviews']))
                            print ""
                            raise ValueError('SKIPPING: DONE REPLYING')
                        elif type(productData) is str:
                            print productData  #Error

                #Item keyword in title
                for word in keywords['items'].dropna(
                ):  #Scan matches between 'items' and title
                    if word.lower() in i.title.encode('utf-8').lower(
                    ):  #Only reply if match found and confidence is high that a suggestion is advised
                        if calculate_confidence(i) >= MIN_CONFIDENCE:
                            productData = find_in_amazon(
                                amazon, AMAZON_ASSOCIATE,
                                amazon.search_n(1,
                                                Keywords=word,
                                                SearchIndex='All')[0])
                            if type(productData) is dict:
                                print "FOUND", word, "IN TITLE", i.id
                                alreadyReplied.append(str(
                                    i.author))  #Add username to cache
                                productData[
                                    'category'] = word  #'word' is more relevant than the default category
                                print ""
                                print generate_Comment(
                                    SENTENCES_IN_REPLY, productData['link'],
                                    productData['brand'],
                                    str(productData['category']).lower(),
                                    productData['price'],
                                    productData['features'],
                                    productData['reviews'])
                                i.add_comment(
                                    generate_Comment(
                                        SENTENCES_IN_REPLY,
                                        productData['link'],
                                        productData['brand'],
                                        str(productData['category']).lower(),
                                        productData['price'],
                                        productData['features'],
                                        productData['reviews']))
                                print ""
                                raise ValueError('SKIPPING: DONE REPLYING')
                            elif type(productData) is str:
                                print productData  #Error
                #Let sprinkle some crack on'em and get outta here
                raise ValueError('SKIPPING: NOTHING FOUND')

            except KeyboardInterrupt:
                raise
            except ValueError as err:
                print err
            except:
                print sys.exc_info()[0]
        print 'SLEEPING FOR', SLEEP_TIME, 'SECONDS...'
        time.sleep(SLEEP_TIME)
class TestAmazonApi(unittest.TestCase):
    """Test Amazon API

    Test Class for Amazon simple API wrapper.
    """

    def setUp(self):
        """Set Up.

        Initialize the Amazon API wrapper. The following values:

        * AMAZON_ACCESS_KEY
        * AMAZON_SECRET_KEY
        * AMAZON_ASSOC_TAG

        Are imported from a custom file named: 'test_settings.py'
        """
        self.amazon = AmazonAPI(
            AMAZON_ACCESS_KEY,
            AMAZON_SECRET_KEY,
            AMAZON_ASSOC_TAG,
            CacheReader=cache_reader,
            CacheWriter=cache_writer,
            MaxQPS=0.5
        )

    def test_lookup(self):
        """Test Product Lookup.

        Tests that a product lookup for a kindle returns results and that the
        main methods are working.
        """
        product = self.amazon.lookup(ItemId="B00I15SB16")
        assert_true('Kindle' in product.title)
        assert_equals(product.ean, '0848719039726')
        assert_equals(
            product.large_image_url,
            'http://ecx.images-amazon.com/images/I/51XGerXeYeL.jpg'
        )
        assert_equals(
            product.get_attribute('Publisher'),
            'Amazon'
        )
        assert_equals(product.get_attributes(
            ['ItemDimensions.Width', 'ItemDimensions.Height']),
            {'ItemDimensions.Width': '469', 'ItemDimensions.Height': '40'})
        assert_true(len(product.browse_nodes) > 0)
        assert_true(product.price_and_currency[0] is not None)
        assert_true(product.price_and_currency[1] is not None)
        assert_equals(product.browse_nodes[0].id, 2642129011)
        assert_equals(product.browse_nodes[0].name, 'eBook Readers')

    def test_lookup_nonexistent_asin(self):
        """Test Product Lookup with a nonexistent ASIN.

        Tests that a product lookup for a nonexistent ASIN raises AsinNotFound.
        """
        assert_raises(AsinNotFound, self.amazon.lookup, ItemId="ABCD1234")

    def test_bulk_lookup(self):
        """Test Baulk Product Lookup.

        Tests that a bulk product lookup request returns multiple results.
        """
        asins = [TEST_ASIN, 'B00BWYQ9YE',
                 'B00BWYRF7E', 'B00D2KJDXA']
        products = self.amazon.lookup(ItemId=','.join(asins))
        assert_equals(len(products), len(asins))
        for i, product in enumerate(products):
            assert_equals(asins[i], product.asin)

    def test_lookup_bulk(self):
        """Test Bulk Product Lookup.

        Tests that a bulk product lookup request returns multiple results.
        """
        asins = [TEST_ASIN, 'B00BWYQ9YE',
                 'B00BWYRF7E', 'B00D2KJDXA']
        products = self.amazon.lookup_bulk(ItemId=','.join(asins))
        assert_equals(len(products), len(asins))
        for i, product in enumerate(products):
            assert_equals(asins[i], product.asin)

    def test_lookup_bulk_empty(self):
        """Test Bulk Product Lookup With No Results.

        Tests that a bulk product lookup request with no results
        returns an empty list.
        """
        asins = ['not-an-asin', 'als-not-an-asin']
        products = self.amazon.lookup_bulk(ItemId=','.join(asins))
        assert_equals(type(products), list)
        assert_equals(len(products), 0)

    def test_search(self):
        """Test Product Search.

        Tests that a product search is working (by testing that results are
        returned). And that each result has a title attribute. The test
        fails if no results where returned.
        """
        products = self.amazon.search(Keywords='kindle', SearchIndex='All')
        for product in products:
            assert_true(hasattr(product, 'title'))
            break
        else:
            assert_true(False, 'No search results returned.')

    def test_search_n(self):
        """Test Product Search N.

        Tests that a product search n is working by testing that N results are
        returned.
        """
        products = self.amazon.search_n(
            1,
            Keywords='kindle',
            SearchIndex='All'
        )
        assert_equals(len(products), 1)

    def test_search_no_results(self):
        """Test Product Search with no results.

        Tests that a product search with that returns no results throws a
        SearchException.
        """
        products = self.amazon.search(Title='no-such-thing-on-amazon',
                                      SearchIndex='Automotive')
        assert_raises(SearchException, (x for x in products).next)

    def test_amazon_api_defaults_to_US(self):
        """Test Amazon API defaults to the US store."""
        amazon = AmazonAPI(
            AMAZON_ACCESS_KEY,
            AMAZON_SECRET_KEY,
            AMAZON_ASSOC_TAG
        )
        assert_equals(amazon.api.Region, "US")

    def test_search_amazon_uk(self):
        """Test Poduct Search on Amazon UK.

        Tests that a product search on Amazon UK is working and that the
        currency of any of the returned products is GBP. The test fails if no
        results were returned.
        """
        amazon = AmazonAPI(
            AMAZON_ACCESS_KEY,
            AMAZON_SECRET_KEY,
            AMAZON_ASSOC_TAG,
            region="UK"
        )
        assert_equals(amazon.api.Region, "UK", "Region has not been set to UK")

        products = amazon.search(Keywords='Kindle', SearchIndex='All')
        currencies = [product.price_and_currency[1] for product in products]
        assert_true(len(currencies), "No products found")

        is_gbp = 'GBP' in currencies
        assert_true(is_gbp, "Currency is not GBP, cannot be Amazon UK, though")

    def test_similarity_lookup(self):
        """Test Similarity Lookup.

        Tests that a similarity lookup for a kindle returns 10 results.
        """
        products = self.amazon.similarity_lookup(ItemId=TEST_ASIN)
        assert_true(len(products) > 5)

    def test_product_attributes(self):
        """Test Product Attributes.

        Tests that all product that are supposed to be accessible are.
        """
        product = self.amazon.lookup(ItemId=TEST_ASIN)
        for attribute in PRODUCT_ATTRIBUTES:
            getattr(product, attribute)

    def test_browse_node_lookup(self):
        """Test Browse Node Lookup.

        Test that a lookup by Brose Node ID returns appropriate node.
        """
        bnid = 2642129011
        bn = self.amazon.browse_node_lookup(BrowseNodeId=bnid)[0]
        assert_equals(bn.id, bnid)
        assert_equals(bn.name, 'eBook Readers')
        assert_equals(bn.is_category_root, False)

    def test_obscure_date(self):
        """Test Obscure Date Formats

        Test a product with an obscure date format
        """
        product = self.amazon.lookup(ItemId="0933635869")
        assert_equals(product.publication_date.year, 1992)
        assert_equals(product.publication_date.month, 5)
        assert_true(isinstance(product.publication_date, datetime.date))

    def test_single_creator(self):
        """Test a product with a single creator
        """
        product = self.amazon.lookup(ItemId="B00005NZJA")
        creators = dict(product.creators)
        assert_equals(creators[u"Jonathan Davis"], u"Narrator")
        assert_equals(len(creators.values()), 2)

    def test_multiple_creators(self):
        """Test a product with multiple creators
        """
        product = self.amazon.lookup(ItemId="B007V8RQC4")
        creators = dict(product.creators)
        assert_equals(creators[u"John Gregory Betancourt"], u"Editor")
        assert_equals(creators[u"Colin Azariah-Kribbs"], u"Editor")
        assert_equals(len(creators.values()), 2)

    def test_no_creators(self):
        """Test a product with no creators
        """
        product = self.amazon.lookup(ItemId="8420658537")
        assert_false(product.creators)

    def test_single_editorial_review(self):
        product = self.amazon.lookup(ItemId="1930846258")
        expected = u'In the title piece, Alan Turing'
        assert_equals(product.editorial_reviews[0][:len(expected)], expected)
        assert_equals(product.editorial_review, product.editorial_reviews[0])
        assert_equals(len(product.editorial_reviews), 1)

    def test_multiple_editorial_reviews(self):
        product = self.amazon.lookup(ItemId="B000FBJCJE")
        expected = u'Only once in a great'
        assert_equals(product.editorial_reviews[0][:len(expected)], expected)
        expected = u'From the opening line'
        assert_equals(product.editorial_reviews[1][:len(expected)], expected)
        # duplicate data, amazon user data is great...
        expected = u'Only once in a great'
        assert_equals(product.editorial_reviews[2][:len(expected)], expected)

        assert_equals(len(product.editorial_reviews), 3)

    def test_languages_english(self):
        """Test Language Data

        Test an English product
        """
        product = self.amazon.lookup(ItemId="1930846258")
        assert_true('english' in product.languages)
        assert_equals(len(product.languages), 1)

    def test_languages_spanish(self):
        """Test Language Data

        Test an English product
        """
        product = self.amazon.lookup(ItemId="8420658537")
        assert_true('spanish' in product.languages)
        assert_equals(len(product.languages), 1)

    def test_region(self):
        amazon = AmazonAPI(AMAZON_ACCESS_KEY, AMAZON_SECRET_KEY,
                           AMAZON_ASSOC_TAG)
        assert_equals(amazon.region, 'US')

        # old 'region' parameter
        amazon = AmazonAPI(AMAZON_ACCESS_KEY, AMAZON_SECRET_KEY,
                           AMAZON_ASSOC_TAG, region='UK')
        assert_equals(amazon.region, 'UK')

        # kwargs method
        amazon = AmazonAPI(AMAZON_ACCESS_KEY, AMAZON_SECRET_KEY,
                           AMAZON_ASSOC_TAG, Region='UK')
        assert_equals(amazon.region, 'UK')

    def test_kwargs(self):
        amazon = AmazonAPI(AMAZON_ACCESS_KEY, AMAZON_SECRET_KEY,
                           AMAZON_ASSOC_TAG, MaxQPS=0.7)

    def test_images(self):
        """Test images property

        Test that the images property has a value when using the
        Images ResponseGroup
        """
        product = self.amazon.lookup(ResponseGroup='Images',
                                     ItemId='B00TSVVNQC')
        assert_equals(type(product.images), list)
        assert_equals(len(product.images), 7)
class TestAmazonApi(unittest.TestCase):
    """Test Amazon API

    Test Class for Amazon simple API wrapper.
    """

    def setUp(self):
        """Set Up.

        Initialize the Amazon API wrapper. The following values:

        * AMAZON_ACCESS_KEY
        * AMAZON_SECRET_KEY
        * AMAZON_ASSOC_TAG

        Are imported from a custom file named: 'test_settings.py'
        """
        self.amazon = AmazonAPI(
            _AMAZON_ACCESS_KEY,
            _AMAZON_SECRET_KEY,
            _AMAZON_ASSOC_TAG,
            CacheReader=cache_reader,
            CacheWriter=cache_writer,
            MaxQPS=0.5
        )

    @flaky(max_runs=3, rerun_filter=delay_rerun)
    def test_lookup(self):
        """Test Product Lookup.

        Tests that a product lookup for a kindle returns results and that the
        main methods are working.
        """
        product = self.amazon.lookup(ItemId="B00ZV9PXP2")
        assert_true('Kindle' in product.title)
        assert_equals(product.ean, '0848719083774')
        assert_equals(
            product.large_image_url,
            'https://images-na.ssl-images-amazon.com/images/I/51hrdzXLUHL.jpg'
        )
        assert_equals(
            product.get_attribute('Publisher'),
            'Amazon'
        )
        assert_equals(product.get_attributes(
            ['ItemDimensions.Width', 'ItemDimensions.Height']),
            {'ItemDimensions.Width': '450', 'ItemDimensions.Height': '36'})
        assert_true(len(product.browse_nodes) > 0)
        assert_true(product.price_and_currency[0] is not None)
        assert_true(product.price_and_currency[1] is not None)
        assert_equals(product.browse_nodes[0].id, 2642129011)
        assert_equals(product.browse_nodes[0].name, 'eBook Readers')

    @flaky(max_runs=3, rerun_filter=delay_rerun)
    def test_lookup_nonexistent_asin(self):
        """Test Product Lookup with a nonexistent ASIN.

        Tests that a product lookup for a nonexistent ASIN raises AsinNotFound.
        """
        assert_raises(AsinNotFound, self.amazon.lookup, ItemId="ABCD1234")

    @flaky(max_runs=3, rerun_filter=delay_rerun)
    def test_bulk_lookup(self):
        """Test Baulk Product Lookup.

        Tests that a bulk product lookup request returns multiple results.
        """
        asins = [TEST_ASIN, 'B00BWYQ9YE',
                 'B00BWYRF7E', 'B00D2KJDXA']
        products = self.amazon.lookup(ItemId=','.join(asins))
        assert_equals(len(products), len(asins))
        for i, product in enumerate(products):
            assert_equals(asins[i], product.asin)

    @flaky(max_runs=3, rerun_filter=delay_rerun)
    def test_lookup_bulk(self):
        """Test Bulk Product Lookup.

        Tests that a bulk product lookup request returns multiple results.
        """
        asins = [TEST_ASIN, 'B00BWYQ9YE',
                 'B00BWYRF7E', 'B00D2KJDXA']
        products = self.amazon.lookup_bulk(ItemId=','.join(asins))
        assert_equals(len(products), len(asins))
        for i, product in enumerate(products):
            assert_equals(asins[i], product.asin)

    @flaky(max_runs=3, rerun_filter=delay_rerun)
    def test_lookup_bulk_empty(self):
        """Test Bulk Product Lookup With No Results.

        Tests that a bulk product lookup request with no results
        returns an empty list.
        """
        asins = ['not-an-asin', 'als-not-an-asin']
        products = self.amazon.lookup_bulk(ItemId=','.join(asins))
        assert_equals(type(products), list)
        assert_equals(len(products), 0)

    @flaky(max_runs=3, rerun_filter=delay_rerun)
    def test_search(self):
        """Test Product Search.

        Tests that a product search is working (by testing that results are
        returned). And that each result has a title attribute. The test
        fails if no results where returned.
        """
        products = self.amazon.search(Keywords='kindle', SearchIndex='All')
        for product in products:
            assert_true(hasattr(product, 'title'))
            break
        else:
            assert_true(False, 'No search results returned.')

    @flaky(max_runs=3, rerun_filter=delay_rerun)
    def test_search_n(self):
        """Test Product Search N.

        Tests that a product search n is working by testing that N results are
        returned.
        """
        products = self.amazon.search_n(
            1,
            Keywords='kindle',
            SearchIndex='All'
        )
        assert_equals(len(products), 1)

    @flaky(max_runs=3, rerun_filter=delay_rerun)
    def test_search_iterate_pages(self):
        products = self.amazon.search(Keywords='internet of things oreilly',
                                      SearchIndex='Books')
        assert_false(products.is_last_page)
        for product in products:
            if products.current_page < 8:
                assert_false(products.is_last_page)
            else:
                assert_true(products.is_last_page)

        assert_true(products.is_last_page)
        assert_true(products.current_page == 8)

    @flaky(max_runs=3, rerun_filter=delay_rerun)
    def test_search_no_results(self):
        """Test Product Search with no results.

        Tests that a product search with that returns no results throws a
        SearchException.
        """
        products = self.amazon.search(Title='no-such-thing-on-amazon',
                                      SearchIndex='Automotive')
        assert_raises(SearchException, next, (x for x in products))

    def test_amazon_api_defaults_to_US(self):
        """Test Amazon API defaults to the US store."""
        amazon = AmazonAPI(
            _AMAZON_ACCESS_KEY,
            _AMAZON_SECRET_KEY,
            _AMAZON_ASSOC_TAG
        )
        assert_equals(amazon.api.Region, "US")

    @flaky(max_runs=3, rerun_filter=delay_rerun)
    def test_search_amazon_uk(self):
        """Test Poduct Search on Amazon UK.

        Tests that a product search on Amazon UK is working and that the
        currency of any of the returned products is GBP. The test fails if no
        results were returned.
        """
        amazon = AmazonAPI(
            _AMAZON_ACCESS_KEY,
            _AMAZON_SECRET_KEY,
            _AMAZON_ASSOC_TAG,
            region="UK"
        )
        assert_equals(amazon.api.Region, "UK", "Region has not been set to UK")

        products = amazon.search(Keywords='Kindle', SearchIndex='All')
        currencies = [product.price_and_currency[1] for product in products]
        assert_true(len(currencies), "No products found")

        is_gbp = 'GBP' in currencies
        assert_true(is_gbp, "Currency is not GBP, cannot be Amazon UK, though")

    @flaky(max_runs=3, rerun_filter=delay_rerun)
    def test_similarity_lookup(self):
        """Test Similarity Lookup.

        Tests that a similarity lookup for a kindle returns 10 results.
        """
        products = self.amazon.similarity_lookup(ItemId=TEST_ASIN)
        assert_true(len(products) > 5)

    @flaky(max_runs=3, rerun_filter=delay_rerun)
    def test_product_attributes(self):
        """Test Product Attributes.

        Tests that all product that are supposed to be accessible are.
        """
        product = self.amazon.lookup(ItemId=TEST_ASIN)
        for attribute in PRODUCT_ATTRIBUTES:
            getattr(product, attribute)

    @flaky(max_runs=3, rerun_filter=delay_rerun)
    def test_browse_node_lookup(self):
        """Test Browse Node Lookup.

        Test that a lookup by Brose Node ID returns appropriate node.
        """
        bnid = 2642129011
        bn = self.amazon.browse_node_lookup(BrowseNodeId=bnid)[0]
        assert_equals(bn.id, bnid)
        assert_equals(bn.name, 'eBook Readers')
        assert_equals(bn.is_category_root, False)

    @flaky(max_runs=3, rerun_filter=delay_rerun)
    def test_obscure_date(self):
        """Test Obscure Date Formats

        Test a product with an obscure date format
        """
        product = self.amazon.lookup(ItemId="0933635869")
        assert_equals(product.publication_date.year, 1992)
        assert_equals(product.publication_date.month, 5)
        assert_true(isinstance(product.publication_date, datetime.date))

    @flaky(max_runs=3, rerun_filter=delay_rerun)
    def test_single_creator(self):
        """Test a product with a single creator
        """
        product = self.amazon.lookup(ItemId="B00005NZJA")
        creators = dict(product.creators)
        assert_equals(creators[u"Jonathan Davis"], u"Narrator")
        assert_equals(len(creators.values()), 2)

    @flaky(max_runs=3, rerun_filter=delay_rerun)
    def test_multiple_creators(self):
        """Test a product with multiple creators
        """
        product = self.amazon.lookup(ItemId="B007V8RQC4")
        creators = dict(product.creators)
        assert_equals(creators[u"John Gregory Betancourt"], u"Editor")
        assert_equals(creators[u"Colin Azariah-Kribbs"], u"Editor")
        assert_equals(len(creators.values()), 2)

    @flaky(max_runs=3, rerun_filter=delay_rerun)
    def test_no_creators(self):
        """Test a product with no creators
        """
        product = self.amazon.lookup(ItemId="8420658537")
        assert_false(product.creators)

    @flaky(max_runs=3, rerun_filter=delay_rerun)
    def test_single_editorial_review(self):
        product = self.amazon.lookup(ItemId="1930846258")
        expected = u'In the title piece, Alan Turing'
        assert_equals(product.editorial_reviews[0][:len(expected)], expected)
        assert_equals(product.editorial_review, product.editorial_reviews[0])
        assert_equals(len(product.editorial_reviews), 1)

    @flaky(max_runs=3, rerun_filter=delay_rerun)
    def test_multiple_editorial_reviews(self):
        product = self.amazon.lookup(ItemId="B01HQA6EOC")
        expected = u'<p>Introducing an instant classic—master storyteller'
        assert_equals(product.editorial_reviews[0][:len(expected)], expected)
        expected = u'<strong>An Amazon Best Book of February 2017:</strong>'
        assert_equals(product.editorial_reviews[1][:len(expected)], expected)
        # duplicate data, amazon user data is great...
        expected = u'<p>Introducing an instant classic—master storyteller'
        assert_equals(product.editorial_reviews[2][:len(expected)], expected)

        assert_equals(len(product.editorial_reviews), 3)

    @flaky(max_runs=3, rerun_filter=delay_rerun)
    def test_languages_english(self):
        """Test Language Data

        Test an English product
        """
        product = self.amazon.lookup(ItemId="1930846258")
        assert_true('english' in product.languages)
        assert_equals(len(product.languages), 1)

    @flaky(max_runs=3, rerun_filter=delay_rerun)
    def test_languages_spanish(self):
        """Test Language Data

        Test an English product
        """
        product = self.amazon.lookup(ItemId="8420658537")
        assert_true('spanish' in product.languages)
        assert_equals(len(product.languages), 1)

    def test_region(self):
        amazon = AmazonAPI(_AMAZON_ACCESS_KEY, _AMAZON_SECRET_KEY,
                           _AMAZON_ASSOC_TAG)
        assert_equals(amazon.region, 'US')

        # old 'region' parameter
        amazon = AmazonAPI(_AMAZON_ACCESS_KEY, _AMAZON_SECRET_KEY,
                           _AMAZON_ASSOC_TAG, region='UK')
        assert_equals(amazon.region, 'UK')

        # kwargs method
        amazon = AmazonAPI(_AMAZON_ACCESS_KEY, _AMAZON_SECRET_KEY,
                           _AMAZON_ASSOC_TAG, Region='UK')
        assert_equals(amazon.region, 'UK')

    @flaky(max_runs=3, rerun_filter=delay_rerun)
    def test_is_adult(self):
        product = self.amazon.lookup(ItemId="B01E7P9LEE")
        assert_true(product.is_adult is not None)

    @flaky(max_runs=3, rerun_filter=delay_rerun)
    def test_product_group(self):
        product = self.amazon.lookup(ItemId="B01LXM0S25")
        assert_equals(product.product_group, 'DVD')

        product = self.amazon.lookup(ItemId="B01NBTSVDN")
        assert_equals(product.product_group, 'Digital Music Album')

    @flaky(max_runs=3, rerun_filter=delay_rerun)
    def test_product_type_name(self):
        product = self.amazon.lookup(ItemId="B01NBTSVDN")
        assert_equals(product.product_type_name, 'DOWNLOADABLE_MUSIC_ALBUM')

    @flaky(max_runs=3, rerun_filter=delay_rerun)
    def test_formatted_price(self):
        product = self.amazon.lookup(ItemId="B01NBTSVDN")
        assert_equals(product.formatted_price, '$12.49')

    @flaky(max_runs=3, rerun_filter=delay_rerun)
    def test_price_and_currency(self):
        product = self.amazon.lookup(ItemId="B01NBTSVDN")
        price, currency = product.price_and_currency
        assert_equals(price, Decimal('12.49'))
        assert_equals(currency, 'USD')

    @flaky(max_runs=3, rerun_filter=delay_rerun)
    def test_list_price(self):
        product = self.amazon.lookup(ItemId="B01NBTSVDN")
        price, currency = product.list_price
        assert_equals(price, Decimal('12.49'))
        assert_equals(currency, 'USD')

    @flaky(max_runs=3, rerun_filter=delay_rerun)
    def test_running_time(self):
        product = self.amazon.lookup(ItemId="B01NBTSVDN")
        assert_equals(product.running_time, '774')

    @flaky(max_runs=3, rerun_filter=delay_rerun)
    def test_studio(self):
        product = self.amazon.lookup(ItemId="B01NBTSVDN")
        assert_equals(product.studio, 'Atlantic Records UK')

    @flaky(max_runs=3, rerun_filter=delay_rerun)
    def test_is_preorder(self):
        product = self.amazon.lookup(ItemId="B01NBTSVDN")
        assert_equals(product.is_preorder, '1')

    @flaky(max_runs=3, rerun_filter=delay_rerun)
    def test_detail_page_url(self):
        product = self.amazon.lookup(ItemId="B01NBTSVDN")
        assert_true(product.detail_page_url.startswith('https://www.amazon.com/%C3%B7-Deluxe-Ed-Sheeran/dp/B01NBTSVDN'))

    @flaky(max_runs=3, rerun_filter=delay_rerun)
    def test_availability(self):
        product = self.amazon.lookup(ItemId="B00ZV9PXP2")
        assert_equals(product.availability, 'Usually ships in 24 hours')

        product = self.amazon.lookup(ItemId="1491914254") # pre-order book
        assert_equals(product.availability, 'Not yet published')

        product = self.amazon.lookup(ItemId="B000SML2BQ") # late availability
        assert_true(product.availability is not None)

        product = self.amazon.lookup(ItemId="B01LTHP2ZK") # unavailable 
        assert_true(product.availability is None)

    @flaky(max_runs=3, rerun_filter=delay_rerun)
    def test_availability_type(self):
        product = self.amazon.lookup(ItemId="B00ZV9PXP2")
        assert_equals(product.availability_type, 'now')

        product = self.amazon.lookup(ItemId="1491914254") # pre-order book
        assert_equals(product.availability_type, 'now')

        product = self.amazon.lookup(ItemId="B00ZV9PXP2") # late availability
        assert_equals(product.availability_type, 'now')

        product = self.amazon.lookup(ItemId="B01LTHP2ZK") # unavailable
        assert_true(product.availability_type is None)

    @flaky(max_runs=3, rerun_filter=delay_rerun)
    def test_availability_min_max_hours(self):
        product = self.amazon.lookup(ItemId="B00ZV9PXP2")
        assert_equals(product.availability_min_hours, '0')
        assert_equals(product.availability_max_hours, '0')


    def test_kwargs(self):
        amazon = AmazonAPI(_AMAZON_ACCESS_KEY, _AMAZON_SECRET_KEY,
                           _AMAZON_ASSOC_TAG, MaxQPS=0.7)

    @flaky(max_runs=3, rerun_filter=delay_rerun)
    def test_images(self):
        """Test images property

        Test that the images property has a value when using the
        Images ResponseGroup
        """
        product = self.amazon.lookup(ResponseGroup='Images',
                                     ItemId='B00TSVVNQC')
        assert_equals(type(product.images), list)
        assert_equals(len(product.images), 7)
class TestAmazonApi(TestCase):
    """Test Amazon API

    Test Class for Amazon simple API wrapper.
    """
    def setUp(self):
        """Set Up.

        Initialize the Amazon API wrapper. The following values:

        * AMAZON_ACCESS_KEY
        * AMAZON_SECRET_KEY
        * AMAZON_ASSOC_TAG

        Are imported from a custom file named: 'test_settings.py'
        """
        self.amazon = AmazonAPI(
            AMAZON_ACCESS_KEY, AMAZON_SECRET_KEY, AMAZON_ASSOC_TAG)

    def test_lookup(self):
        """Test Product Lookup.

        Tests that a product lookup for a kindle returns results and that the
        main methods are working.
        """
        product = self.amazon.lookup(ItemId="B0051QVF7A")
        assert_equals(
            product.title,
            'Kindle, Wi-Fi, 6" E Ink Display - for international shipment'
        )
        assert_equals(product.ean, '0814916014354')
        assert_equals(
            product.large_image_url,
            'http://ecx.images-amazon.com/images/I/411H%2B731ZzL.jpg'
        )
        assert_equals(
            product.get_attribute('Publisher'),
            'Amazon Digital Services, Inc'
        )
        assert_equals(product.get_attributes(
            ['ItemDimensions.Width', 'ItemDimensions.Height']),
            {'ItemDimensions.Width': '450', 'ItemDimensions.Height': '34'})
        assert_true(len(product.browse_nodes) > 0)
        assert_equals(product.browse_nodes[0].id, 2642129011)
        assert_equals(product.browse_nodes[0].name, 'eBook Readers')

    def test_batch_lookup(self):
        """Test Batch Product Lookup.

        Tests that a batch product lookup request returns multiple results.
        """
        asins = ['B0051QVESA', 'B005DOK8NW', 'B005890G8Y',
                 'B0051VVOB2', 'B005890G8O']
        products = self.amazon.lookup(ItemId=','.join(asins))
        assert_equals(len(products), 5)
        for i, product in enumerate(products):
            assert_equals(asins[i], product.asin)

    def test_search(self):
        """Test Product Search.

        Tests that a product search is working (by testing that results are
        returned). And that each result has a title attribute. The test
        fails if no results where returned.
        """
        products = self.amazon.search(Keywords='kindle', SearchIndex='All')
        for product in products:
            assert_true(hasattr(product, 'title'))
            break
        else:
            assert_true(False, 'No search results returned.')

    def test_search_n(self):
        """Test Product Search N.

        Tests that a product search n is working by testing that N results are
        returned.
        """
        products = self.amazon.search_n(
            1,
            Keywords='kindle',
            SearchIndex='All'
        )
        assert_equals(len(products), 1)

    def test_amazon_api_defaults_to_US(self):
        """Test Amazon API defaults to the US store."""
        amazon = AmazonAPI(
            AMAZON_ACCESS_KEY,
            AMAZON_SECRET_KEY,
            AMAZON_ASSOC_TAG
        )
        assert_equals(amazon.api.Region, "US")

    def test_search_amazon_uk(self):
        """Test Poduct Search on Amazon UK.

        Tests that a product search on Amazon UK is working and that the
        currency of any of the returned products is GBP. The test fails if no
        results were returned.
        """
        amazon = AmazonAPI(
            AMAZON_ACCESS_KEY,
            AMAZON_SECRET_KEY,
            AMAZON_ASSOC_TAG,
            region="UK"
        )
        assert_equals(amazon.api.Region, "UK", "Region has not been set to UK")

        products = amazon.search(Keywords='Kindle', SearchIndex='All')
        currencies = [product.price_and_currency[1] for product in products]
        assert_true(len(currencies), "No products found")

        is_gbp = 'GBP' in currencies
        assert_true(is_gbp, "Currency is not GBP, cannot be Amazon UK, though")

    def test_similarity_lookup(self):
        """Test Similarity Lookup.

        Tests that a similarity lookup for a kindle returns 10 results.
        """
        products = self.amazon.similarity_lookup(ItemId="B0051QVF7A")
        assert_equals(len(products), 10)
예제 #9
0
class TestAmazonApi(unittest.TestCase):
    """Test Amazon API

    Test Class for Amazon simple API wrapper.
    """

    def setUp(self):
        """Set Up.

        Initialize the Amazon API wrapper. The following values:

        * AMAZON_ACCESS_KEY
        * AMAZON_SECRET_KEY
        * AMAZON_ASSOC_TAG

        Are imported from a custom file named: 'test_settings.py'
        """
        self.amazon = AmazonAPI(
            AMAZON_ACCESS_KEY,
            AMAZON_SECRET_KEY,
            AMAZON_ASSOC_TAG,
            CacheReader=cache_reader,
            CacheWriter=cache_writer,
            MaxQPS=0.5
        )

    def test_lookup(self):
        """Test Product Lookup.

        Tests that a product lookup for a kindle returns results and that the
        main methods are working.
        """
        product = self.amazon.lookup(ItemId="B00I15SB16")
        assert_true('Kindle' in product.title)
        assert_equals(product.ean, '0848719039726')
        assert_equals(
            product.large_image_url,
            'https://images-na.ssl-images-amazon.com/images/I/51XGerXeYeL.jpg'
        )
        assert_equals(
            product.get_attribute('Publisher'),
            'Amazon'
        )
        assert_equals(product.get_attributes(
            ['ItemDimensions.Width', 'ItemDimensions.Height']),
            {'ItemDimensions.Width': '469', 'ItemDimensions.Height': '40'})
        assert_true(len(product.browse_nodes) > 0)
        assert_true(product.price_and_currency[0] is not None)
        assert_true(product.price_and_currency[1] is not None)
        assert_equals(product.browse_nodes[0].id, 2642129011)
        assert_equals(product.browse_nodes[0].name, 'eBook Readers')

    def test_lookup_nonexistent_asin(self):
        """Test Product Lookup with a nonexistent ASIN.

        Tests that a product lookup for a nonexistent ASIN raises AsinNotFound.
        """
        assert_raises(AsinNotFound, self.amazon.lookup, ItemId="ABCD1234")

    def test_bulk_lookup(self):
        """Test Baulk Product Lookup.

        Tests that a bulk product lookup request returns multiple results.
        """
        asins = [TEST_ASIN, 'B00BWYQ9YE',
                 'B00BWYRF7E', 'B00D2KJDXA']
        products = self.amazon.lookup(ItemId=','.join(asins))
        assert_equals(len(products), len(asins))
        for i, product in enumerate(products):
            assert_equals(asins[i], product.asin)

    def test_lookup_bulk(self):
        """Test Bulk Product Lookup.

        Tests that a bulk product lookup request returns multiple results.
        """
        asins = [TEST_ASIN, 'B00BWYQ9YE',
                 'B00BWYRF7E', 'B00D2KJDXA']
        products = self.amazon.lookup_bulk(ItemId=','.join(asins))
        assert_equals(len(products), len(asins))
        for i, product in enumerate(products):
            assert_equals(asins[i], product.asin)

    def test_lookup_bulk_empty(self):
        """Test Bulk Product Lookup With No Results.

        Tests that a bulk product lookup request with no results
        returns an empty list.
        """
        asins = ['not-an-asin', 'als-not-an-asin']
        products = self.amazon.lookup_bulk(ItemId=','.join(asins))
        assert_equals(type(products), list)
        assert_equals(len(products), 0)

    def test_search(self):
        """Test Product Search.

        Tests that a product search is working (by testing that results are
        returned). And that each result has a title attribute. The test
        fails if no results where returned.
        """
        products = self.amazon.search(Keywords='kindle', SearchIndex='All')
        for product in products:
            assert_true(hasattr(product, 'title'))
            break
        else:
            assert_true(False, 'No search results returned.')

    def test_search_n(self):
        """Test Product Search N.

        Tests that a product search n is working by testing that N results are
        returned.
        """
        products = self.amazon.search_n(
            1,
            Keywords='kindle',
            SearchIndex='All'
        )
        assert_equals(len(products), 1)

    def test_search_no_results(self):
        """Test Product Search with no results.

        Tests that a product search with that returns no results throws a
        SearchException.
        """
        products = self.amazon.search(Title='no-such-thing-on-amazon',
                                      SearchIndex='Automotive')
        assert_raises(SearchException, next, (x for x in products))

    def test_amazon_api_defaults_to_US(self):
        """Test Amazon API defaults to the US store."""
        amazon = AmazonAPI(
            AMAZON_ACCESS_KEY,
            AMAZON_SECRET_KEY,
            AMAZON_ASSOC_TAG
        )
        assert_equals(amazon.api.Region, "US")

    def test_search_amazon_uk(self):
        """Test Poduct Search on Amazon UK.

        Tests that a product search on Amazon UK is working and that the
        currency of any of the returned products is GBP. The test fails if no
        results were returned.
        """
        amazon = AmazonAPI(
            AMAZON_ACCESS_KEY,
            AMAZON_SECRET_KEY,
            AMAZON_ASSOC_TAG,
            region="UK"
        )
        assert_equals(amazon.api.Region, "UK", "Region has not been set to UK")

        products = amazon.search(Keywords='Kindle', SearchIndex='All')
        currencies = [product.price_and_currency[1] for product in products]
        assert_true(len(currencies), "No products found")

        is_gbp = 'GBP' in currencies
        assert_true(is_gbp, "Currency is not GBP, cannot be Amazon UK, though")

    def test_similarity_lookup(self):
        """Test Similarity Lookup.

        Tests that a similarity lookup for a kindle returns 10 results.
        """
        products = self.amazon.similarity_lookup(ItemId=TEST_ASIN)
        assert_true(len(products) > 5)

    def test_product_attributes(self):
        """Test Product Attributes.

        Tests that all product that are supposed to be accessible are.
        """
        product = self.amazon.lookup(ItemId=TEST_ASIN)
        for attribute in PRODUCT_ATTRIBUTES:
            getattr(product, attribute)

    def test_browse_node_lookup(self):
        """Test Browse Node Lookup.

        Test that a lookup by Brose Node ID returns appropriate node.
        """
        bnid = 2642129011
        bn = self.amazon.browse_node_lookup(BrowseNodeId=bnid)[0]
        assert_equals(bn.id, bnid)
        assert_equals(bn.name, 'eBook Readers')
        assert_equals(bn.is_category_root, False)

    def test_obscure_date(self):
        """Test Obscure Date Formats

        Test a product with an obscure date format
        """
        product = self.amazon.lookup(ItemId="0933635869")
        assert_equals(product.publication_date.year, 1992)
        assert_equals(product.publication_date.month, 5)
        assert_true(isinstance(product.publication_date, datetime.date))

    def test_single_creator(self):
        """Test a product with a single creator
        """
        product = self.amazon.lookup(ItemId="B00005NZJA")
        creators = dict(product.creators)
        assert_equals(creators[u"Jonathan Davis"], u"Narrator")
        assert_equals(len(creators.values()), 2)

    def test_multiple_creators(self):
        """Test a product with multiple creators
        """
        product = self.amazon.lookup(ItemId="B007V8RQC4")
        creators = dict(product.creators)
        assert_equals(creators[u"John Gregory Betancourt"], u"Editor")
        assert_equals(creators[u"Colin Azariah-Kribbs"], u"Editor")
        assert_equals(len(creators.values()), 2)

    def test_no_creators(self):
        """Test a product with no creators
        """
        product = self.amazon.lookup(ItemId="8420658537")
        assert_false(product.creators)

    def test_single_editorial_review(self):
        product = self.amazon.lookup(ItemId="1930846258")
        expected = u'In the title piece, Alan Turing'
        assert_equals(product.editorial_reviews[0][:len(expected)], expected)
        assert_equals(product.editorial_review, product.editorial_reviews[0])
        assert_equals(len(product.editorial_reviews), 1)

    def test_multiple_editorial_reviews(self):
        product = self.amazon.lookup(ItemId="B000FBJCJE")
        expected = u'<b>One of <i>Time</i>'
        assert_equals(product.editorial_reviews[0][:len(expected)], expected)
        expected = u'From the opening line'
        assert_equals(product.editorial_reviews[1][:len(expected)], expected)
        # duplicate data, amazon user data is great...
        expected = u'<b>One of <i>Time</i>'
        assert_equals(product.editorial_reviews[2][:len(expected)], expected)

        assert_equals(len(product.editorial_reviews), 3)

    def test_languages_english(self):
        """Test Language Data

        Test an English product
        """
        product = self.amazon.lookup(ItemId="1930846258")
        assert_true('english' in product.languages)
        assert_equals(len(product.languages), 1)

    def test_languages_spanish(self):
        """Test Language Data

        Test an English product
        """
        product = self.amazon.lookup(ItemId="8420658537")
        assert_true('spanish' in product.languages)
        assert_equals(len(product.languages), 1)

    def test_region(self):
        amazon = AmazonAPI(AMAZON_ACCESS_KEY, AMAZON_SECRET_KEY,
                           AMAZON_ASSOC_TAG)
        assert_equals(amazon.region, 'US')

        # old 'region' parameter
        amazon = AmazonAPI(AMAZON_ACCESS_KEY, AMAZON_SECRET_KEY,
                           AMAZON_ASSOC_TAG, region='UK')
        assert_equals(amazon.region, 'UK')

        # kwargs method
        amazon = AmazonAPI(AMAZON_ACCESS_KEY, AMAZON_SECRET_KEY,
                           AMAZON_ASSOC_TAG, Region='UK')
        assert_equals(amazon.region, 'UK')

    def test_kwargs(self):
        amazon = AmazonAPI(AMAZON_ACCESS_KEY, AMAZON_SECRET_KEY,
                           AMAZON_ASSOC_TAG, MaxQPS=0.7)

    def test_images(self):
        """Test images property

        Test that the images property has a value when using the
        Images ResponseGroup
        """
        product = self.amazon.lookup(ResponseGroup='Images',
                                     ItemId='B00TSVVNQC')
        assert_equals(type(product.images), list)
        assert_equals(len(product.images), 7)
class TestAmazonApi(TestCase):
    """Test Amazon API

    Test Class for Amazon simple API wrapper.
    """
    def setUp(self):
        """Set Up.

        Initialize the Amazon API wrapper. The following values:

        * AMAZON_ACCESS_KEY
        * AMAZON_SECRET_KEY
        * AMAZON_ASSOC_TAG

        Are imported from a custom file named: 'test_settings.py'
        """
        self.amazon = AmazonAPI(
            AMAZON_ACCESS_KEY, AMAZON_SECRET_KEY, AMAZON_ASSOC_TAG)

    def test_lookup(self):
        """Test Product Lookup.

        Tests that a product lookup for a kindle returns results and that the
        main methods are working.
        """
        product = self.amazon.lookup(ItemId="B007HCCNJU")
        assert_true('Kindle' in product.title)
        assert_equals(product.ean, '0814916017775')
        assert_equals(
            product.large_image_url,
            'http://ecx.images-amazon.com/images/I/41VZlVs8agL.jpg'
        )
        assert_equals(
            product.get_attribute('Publisher'),
            'Amazon'
        )
        assert_equals(product.get_attributes(
            ['ItemDimensions.Width', 'ItemDimensions.Height']),
            {'ItemDimensions.Width': '650', 'ItemDimensions.Height': '130'})
        assert_true(len(product.browse_nodes) > 0)
        assert_true(product.price_and_currency[0] is not None)
        assert_true(product.price_and_currency[1] is not None)
        assert_equals(product.browse_nodes[0].id, 2642129011)
        assert_equals(product.browse_nodes[0].name, 'eBook Readers')

    def test_batch_lookup(self):
        """Test Batch Product Lookup.

        Tests that a batch product lookup request returns multiple results.
        """
        asins = ['B0051QVESA', 'B005DOK8NW', 'B005890G8Y',
                 'B0051VVOB2', 'B005890G8O']
        products = self.amazon.lookup(ItemId=','.join(asins))
        assert_equals(len(products), 5)
        for i, product in enumerate(products):
            assert_equals(asins[i], product.asin)

    def test_search(self):
        """Test Product Search.

        Tests that a product search is working (by testing that results are
        returned). And that each result has a title attribute. The test
        fails if no results where returned.
        """
        products = self.amazon.search(Keywords='kindle', SearchIndex='All')
        for product in products:
            assert_true(hasattr(product, 'title'))
            break
        else:
            assert_true(False, 'No search results returned.')

    def test_search_n(self):
        """Test Product Search N.

        Tests that a product search n is working by testing that N results are
        returned.
        """
        products = self.amazon.search_n(
            1,
            Keywords='kindle',
            SearchIndex='All'
        )
        assert_equals(len(products), 1)

    def test_amazon_api_defaults_to_US(self):
        """Test Amazon API defaults to the US store."""
        amazon = AmazonAPI(
            AMAZON_ACCESS_KEY,
            AMAZON_SECRET_KEY,
            AMAZON_ASSOC_TAG
        )
        assert_equals(amazon.api.Region, "US")

    def test_search_amazon_uk(self):
        """Test Poduct Search on Amazon UK.

        Tests that a product search on Amazon UK is working and that the
        currency of any of the returned products is GBP. The test fails if no
        results were returned.
        """
        amazon = AmazonAPI(
            AMAZON_ACCESS_KEY,
            AMAZON_SECRET_KEY,
            AMAZON_ASSOC_TAG,
            region="UK"
        )
        assert_equals(amazon.api.Region, "UK", "Region has not been set to UK")

        products = amazon.search(Keywords='Kindle', SearchIndex='All')
        currencies = [product.price_and_currency[1] for product in products]
        assert_true(len(currencies), "No products found")

        is_gbp = 'GBP' in currencies
        assert_true(is_gbp, "Currency is not GBP, cannot be Amazon UK, though")

    def test_similarity_lookup(self):
        """Test Similarity Lookup.

        Tests that a similarity lookup for a kindle returns 10 results.
        """
        products = self.amazon.similarity_lookup(ItemId="B0051QVF7A")
        assert_equals(len(products), 10)

    def test_product_attributes(self):
        """Test Product Attributes.

        Tests that all product that are supposed to be accessible are.
        """
        product = self.amazon.lookup(ItemId="B0051QVF7A")
        for attribute in PRODUCT_ATTRIBUTES:
            getattr(product, attribute)

    def test_browse_node_lookup(self):
        """Test Browse Node Lookup.

        Test that a lookup by Brose Node ID returns appropriate node.
        """
        bnid = 2642129011
        bn = self.amazon.browse_node_lookup(BrowseNodeId=bnid)[0]
        assert_equals(bn.id, bnid)
        assert_equals(bn.name, 'eBook Readers')
        assert_equals(bn.is_category_root, False)
예제 #11
0
from amazon.api import AmazonAPI

amazon = AmazonAPI("AKIAIVHGCP277VB46DMA", "2JYi7rAHq5cGbKN6ISTL96HaPRpqoVODUsUSH93F", "libra0c8-21")
products = amazon.similarity_lookup(ItemId='B0051QVESA,B005DOK8NW')
print products
예제 #12
0
파일: reffit.py 프로젝트: winsonluk/reffit
def main():
    # Configure variables from config.ini.
    config = configparser.ConfigParser()
    config.read('config.ini')
    NUM_RETRIEVE = int(config.get('setup', 'NUM_RETRIEVE'))
    MIN_CONFIDENCE = int(config.get('setup', 'MIN_CONFIDENCE'))
    SENTENCES_IN_REPLY = int(config.get('setup', 'SENTENCES_IN_REPLY'))
    SLEEP_TIME = int(config.get('setup', 'SLEEP_TIME'))
    USER_AGENT = config.get('praw', 'USER_AGENT')
    AMAZON_KEY = config.get('amazon', 'AMAZON_KEY')
    AMAZON_SECRET = config.get('amazon', 'AMAZON_SECRET')
    AMAZON_ASSOCIATE = config.get('amazon', 'AMAZON_ASSOCIATE')

    # Initialize variables.
    global keywords, c
    alreadyReplied = []  # Tracks users whom the bot has replied to.
    keywords = pandas.read_csv('data.csv')
    conn = sqlite3.connect('templates.db')
    c = conn.cursor()
    subreddits = '+'.join([line for line in keywords['subreddits'].dropna()])

    # Connect to Reddit and Amazon.
    r = praw.Reddit(USER_AGENT)
    o = OAuth2Util.OAuth2Util(r)
    amazon = AmazonAPI(AMAZON_KEY, AMAZON_SECRET, AMAZON_ASSOCIATE)

    while True:
        o.refresh()
        submissions = r.get_subreddit(subreddits)
        posts = submissions.get_new(limit=NUM_RETRIEVE)
        for i in posts:
            try:
                if str(i.author) in alreadyReplied:
                    raise ValueError('SKIPPING: ALREADY REPLIED TO AUTHOR')
                if 'reddit.com' not in i.url:
                    raise ValueError('SKIPPING: LINK SUBMISSION')

                # Amazon link is found in submission (self) text.
                selfStr = i.selftext.encode('ascii', 'ignore').lower()
                if ('/dp/' in selfStr) or ('/gp/' in selfStr):
                    productData = find_in_amazon(
                        amazon, AMAZON_ASSOCIATE,
                        amazon.similarity_lookup(ItemId=get_asin(selfStr))[0])
                    if type(productData) is dict:
                        print('FOUND', productData['link'], 'IN SELF:', i.id)
                        alreadyReplied.append(str(i.author))
                        print('')
                        print(
                            generate_comment(
                                SENTENCES_IN_REPLY, productData['link'],
                                productData['brand'],
                                str(productData['category']).lower(),
                                productData['price'], productData['features'],
                                productData['reviews']))
                        #comment.reply(
                        #    generate_comment(
                        #        SENTENCES_IN_REPLY, productData['link'],
                        #        productData['brand'],
                        #        str(productData['category']).lower(),
                        #        productData['price'],
                        #        productData['features'],
                        #        productData['reviews']
                        #        )
                        #    )
                        print('')
                        raise ValueError('SKIPPING: DONE REPLYING')
                    elif type(productData) is str:
                        print(productData)  # Error message

                # Amazon link is found in comment.
                for comment in i.comments:
                    commentStr = str(comment).encode('ascii', 'ignore').lower()
                    if ((str(comment.author) not in alreadyReplied) and
                        (('/dp/' in commentStr) or ('/gp/' in commentStr))):
                        productData = find_in_amazon(
                            amazon, AMAZON_ASSOCIATE,
                            amazon.similarity_lookup(
                                ItemId=str(get_asin(commentStr)))[0])
                        if type(productData) is dict:
                            print(('FOUND', productData['link'], 'IN COMMENT',
                                   comment.id))
                            alreadyReplied.append(str(i.author))
                            alreadyReplied.append(str(comment.author))
                            print('')
                            print(
                                generate_comment_with_reply(
                                    SENTENCES_IN_REPLY, productData['link'],
                                    productData['brand'],
                                    str(productData['category']).lower(),
                                    productData['price'],
                                    productData['features'],
                                    productData['reviews']))
                            #comment.reply(
                            #    generate_comment_with_reply(
                            #        SENTENCES_IN_REPLY, productData['link'],
                            #        productData['brand'],
                            #        str(productData['category']).lower(),
                            #        productData['price'],
                            #        productData['features'],
                            #        productData['reviews']
                            #        )
                            #    )
                            print('')
                            raise ValueError('SKIPPING: DONE REPLYING')
                        elif type(productData) is str:
                            print(productData)  # Error message

                # Item keyword is found in title.
                for word in keywords['items'].dropna():
                    if (word.lower() in i.title.encode('ascii',
                                                       'ignore').lower()):
                        if calculate_confidence(i) >= MIN_CONFIDENCE:
                            productData = find_in_amazon(
                                amazon, AMAZON_ASSOCIATE,
                                amazon.search_n(1,
                                                Keywords=word,
                                                SearchIndex='All')[0])
                            if type(productData) is dict:
                                print('FOUND', word, 'IN TITLE', i.id)
                                alreadyReplied.append(str(i.author))
                                productData['category'] = word
                                print('')
                                print(
                                    generate_comment(
                                        SENTENCES_IN_REPLY,
                                        productData['link'],
                                        productData['brand'],
                                        str(productData['category']).lower(),
                                        productData['price'],
                                        productData['features'],
                                        productData['reviews']))
                                #comment.reply(
                                #    generate_comment(
                                #        SENTENCES_IN_REPLY,
                                #        productData['link'],
                                #        productData['brand'],
                                #        str(productData['category']).lower(),
                                #        productData['price'],
                                #        productData['features'],
                                #        productData['reviews']
                                #        )
                                #    )
                                print('')
                                raise ValueError('SKIPPING: DONE REPLYING')
                            elif type(productData) is str:
                                print(productData)  # Error message

                raise ValueError('SKIPPING: NOTHING FOUND')
            except KeyboardInterrupt:
                raise
            except ValueError as err:
                print(err)
            except:
                print('ERROR: PROBLEM IN MAIN')
                print(sys.exc_info()[0])
        print('SLEEPING FOR', SLEEP_TIME, 'SECONDS...')
        time.sleep(SLEEP_TIME)
예제 #13
0
class TestAmazonApi(TestCase):
    """Test Amazon API

    Test Class for Amazon simple API wrapper.
    """
    def setUp(self):
        """Set Up.

        Initialize the Amazon API wrapper. The following values:

        * AMAZON_ACCESS_KEY
        * AMAZON_SECRET_KEY
        * AMAZON_ASSOC_TAG

        Are imported from a custom file named: 'test_settings.py'
        """
        self.amazon = AmazonAPI(AMAZON_ACCESS_KEY, AMAZON_SECRET_KEY,
                                AMAZON_ASSOC_TAG)

    def test_lookup(self):
        """Test Product Lookup.

        Tests that a product lookup for a kindle returns results and that the
        main methods are working.
        """
        product = self.amazon.lookup(ItemId="B007HCCNJU")
        assert_true('Kindle' in product.title)
        assert_equals(product.ean, '0814916017775')
        assert_equals(product.large_image_url,
                      'http://ecx.images-amazon.com/images/I/41VZlVs8agL.jpg')
        assert_equals(product.get_attribute('Publisher'), 'Amazon')
        assert_equals(
            product.get_attributes(
                ['ItemDimensions.Width', 'ItemDimensions.Height']), {
                    'ItemDimensions.Width': '650',
                    'ItemDimensions.Height': '130'
                })
        assert_true(len(product.browse_nodes) > 0)
        assert_true(product.price_and_currency[0] is not None)
        assert_true(product.price_and_currency[1] is not None)
        assert_equals(product.browse_nodes[0].id, 2642129011)
        assert_equals(product.browse_nodes[0].name, 'eBook Readers')

    def test_batch_lookup(self):
        """Test Batch Product Lookup.

        Tests that a batch product lookup request returns multiple results.
        """
        asins = [
            'B00AWH595M', 'B007HCCNJU', 'B00BWYQ9YE', 'B00BWYRF7E',
            'B00D2KJDXA'
        ]
        products = self.amazon.lookup(ItemId=','.join(asins))
        assert_equals(len(products), 5)
        for i, product in enumerate(products):
            assert_equals(asins[i], product.asin)

    def test_search(self):
        """Test Product Search.

        Tests that a product search is working (by testing that results are
        returned). And that each result has a title attribute. The test
        fails if no results where returned.
        """
        products = self.amazon.search(Keywords='kindle', SearchIndex='All')
        for product in products:
            assert_true(hasattr(product, 'title'))
            break
        else:
            assert_true(False, 'No search results returned.')

    def test_search_n(self):
        """Test Product Search N.

        Tests that a product search n is working by testing that N results are
        returned.
        """
        products = self.amazon.search_n(1,
                                        Keywords='kindle',
                                        SearchIndex='All')
        assert_equals(len(products), 1)

    def test_amazon_api_defaults_to_US(self):
        """Test Amazon API defaults to the US store."""
        amazon = AmazonAPI(AMAZON_ACCESS_KEY, AMAZON_SECRET_KEY,
                           AMAZON_ASSOC_TAG)
        assert_equals(amazon.api.Region, "US")

    def test_search_amazon_uk(self):
        """Test Poduct Search on Amazon UK.

        Tests that a product search on Amazon UK is working and that the
        currency of any of the returned products is GBP. The test fails if no
        results were returned.
        """
        amazon = AmazonAPI(AMAZON_ACCESS_KEY,
                           AMAZON_SECRET_KEY,
                           AMAZON_ASSOC_TAG,
                           region="UK")
        assert_equals(amazon.api.Region, "UK", "Region has not been set to UK")

        products = amazon.search(Keywords='Kindle', SearchIndex='All')
        currencies = [product.price_and_currency[1] for product in products]
        assert_true(len(currencies), "No products found")

        is_gbp = 'GBP' in currencies
        assert_true(is_gbp, "Currency is not GBP, cannot be Amazon UK, though")

    def test_similarity_lookup(self):
        """Test Similarity Lookup.

        Tests that a similarity lookup for a kindle returns 10 results.
        """
        products = self.amazon.similarity_lookup(ItemId="B0051QVF7A")
        assert_true(len(products) > 5)

    def test_product_attributes(self):
        """Test Product Attributes.

        Tests that all product that are supposed to be accessible are.
        """
        product = self.amazon.lookup(ItemId="B0051QVF7A")
        for attribute in PRODUCT_ATTRIBUTES:
            getattr(product, attribute)

    def test_browse_node_lookup(self):
        """Test Browse Node Lookup.

        Test that a lookup by Brose Node ID returns appropriate node.
        """
        bnid = 2642129011
        bn = self.amazon.browse_node_lookup(BrowseNodeId=bnid)[0]
        assert_equals(bn.id, bnid)
        assert_equals(bn.name, 'eBook Readers')
        assert_equals(bn.is_category_root, False)

    def test_obscure_date(self):
        """Test Obscure Date Formats

        Test a product with an obscure date format
        """
        product = self.amazon.lookup(ItemId="0933635869")
        assert_equals(product.publication_date.year, 1992)
        assert_equals(product.publication_date.month, 5)
        assert_true(isinstance(product.publication_date, datetime.date))

    def test_single_creator(self):
        """Test a product with a single creator
        """
        product = self.amazon.lookup(ItemId="B00005NZJA")
        creators = dict(product.creators)
        assert_equals(creators[u"Jonathan Davis"], u"Narrator")
        assert_equals(len(creators.values()), 1)

    def test_multiple_creators(self):
        """Test a product with multiple creators
        """
        product = self.amazon.lookup(ItemId="B007V8RQC4")
        creators = dict(product.creators)
        assert_equals(creators[u"John Gregory Betancourt"], u"Editor")
        assert_equals(creators[u"Colin Azariah-Kribbs"], u"Editor")
        assert_equals(len(creators.values()), 2)

    def test_no_creators(self):
        """Test a product with no creators
        """
        product = self.amazon.lookup(ItemId="8420658537")
        assert_false(product.creators)

    def test_single_editorial_review(self):
        product = self.amazon.lookup(ItemId="1930846258")
        expected = u'In the title piece, Alan Turing'
        assert_equals(product.editorial_reviews[0][:len(expected)], expected)
        assert_equals(product.editorial_review, product.editorial_reviews[0])
        assert_equals(len(product.editorial_reviews), 1)

    def test_multiple_editorial_reviews(self):
        product = self.amazon.lookup(ItemId="B000FBJCJE")
        expected = u'Only once in a great'
        assert_equals(product.editorial_reviews[0][:len(expected)], expected)
        expected = u'From the opening line'
        assert_equals(product.editorial_reviews[1][:len(expected)], expected)
        # duplicate data, amazon user data is great...
        expected = u'Only once in a great'
        assert_equals(product.editorial_reviews[2][:len(expected)], expected)

        assert_equals(len(product.editorial_reviews), 3)

    def test_languages_english(self):
        """Test Language Data

        Test an English product
        """
        product = self.amazon.lookup(ItemId="1930846258")
        assert_true('english' in product.languages)
        assert_equals(len(product.languages), 1)

    def test_languages_spanish(self):
        """Test Language Data

        Test an English product
        """
        product = self.amazon.lookup(ItemId="8420658537")
        assert_true('spanish' in product.languages)
        assert_equals(len(product.languages), 1)
class TestAmazonApi(TestCase):
    """Test Amazon API

    Test Class for Amazon simple API wrapper.
    """

    def setUp(self):
        """Set Up.

        Initialize the Amazon API wrapper. The following values:

        * AMAZON_ACCESS_KEY
        * AMAZON_SECRET_KEY
        * AMAZON_ASSOC_TAG

        Are imported from a custom file named: 'test_settings.py'
        """
        self.amazon = AmazonAPI(AMAZON_ACCESS_KEY, AMAZON_SECRET_KEY, AMAZON_ASSOC_TAG)

    def test_lookup(self):
        """Test Product Lookup.

        Tests that a product lookup for a kindle returns results and that the
        main methods are working.
        """
        product = self.amazon.lookup(ItemId="B0051QVF7A")
        assert_equals(product.title, 'Kindle, Wi-Fi, 6" E Ink Display - for international shipment')
        assert_equals(product.ean, "0814916014354")
        assert_equals(product.large_image_url, "http://ecx.images-amazon.com/images/I/411H%2B731ZzL.jpg")
        assert_equals(product.get_attribute("Publisher"), "Amazon Digital Services, Inc")
        assert_equals(
            product.get_attributes(["ItemDimensions.Width", "ItemDimensions.Height"]),
            {"ItemDimensions.Width": "450", "ItemDimensions.Height": "34"},
        )
        assert_true(len(product.browse_nodes) > 0)
        assert_equals(product.browse_nodes[0].id, 2642129011)
        assert_equals(product.browse_nodes[0].name, "eBook Readers")

    def test_batch_lookup(self):
        """Test Batch Product Lookup.

        Tests that a batch product lookup request returns multiple results.
        """
        asins = ["B0051QVESA", "B005DOK8NW", "B005890G8Y", "B0051VVOB2", "B005890G8O"]
        products = self.amazon.lookup(ItemId=",".join(asins))
        assert_equals(len(products), 5)
        for i, product in enumerate(products):
            assert_equals(asins[i], product.asin)

    def test_search(self):
        """Test Product Search.

        Tests that a product search is working (by testing that results are
        returned). And that each result has a title attribute. The test
        fails if no results where returned.
        """
        products = self.amazon.search(Keywords="kindle", SearchIndex="All")
        for product in products:
            assert_true(hasattr(product, "title"))
            break
        else:
            assert_true(False, "No search results returned.")

    def test_search_n(self):
        """Test Product Search N.

        Tests that a product search n is working by testing that N results are
        returned.
        """
        products = self.amazon.search_n(1, Keywords="kindle", SearchIndex="All")
        assert_equals(len(products), 1)

    def test_amazon_api_defaults_to_US(self):
        """Test Amazon API defaults to the US store."""
        amazon = AmazonAPI(AMAZON_ACCESS_KEY, AMAZON_SECRET_KEY, AMAZON_ASSOC_TAG)
        assert_equals(amazon.api.Region, "US")

    def test_search_amazon_uk(self):
        """Test Poduct Search on Amazon UK.

        Tests that a product search on Amazon UK is working and that the
        currency of any of the returned products is GBP. The test fails if no
        results were returned.
        """
        amazon = AmazonAPI(AMAZON_ACCESS_KEY, AMAZON_SECRET_KEY, AMAZON_ASSOC_TAG, region="UK")
        assert_equals(amazon.api.Region, "UK", "Region has not been set to UK")

        products = amazon.search(Keywords="Kindle", SearchIndex="All")
        currencies = [product.price_and_currency[1] for product in products]
        assert_true(len(currencies), "No products found")

        is_gbp = "GBP" in currencies
        assert_true(is_gbp, "Currency is not GBP, cannot be Amazon UK, though")

    def test_similarity_lookup(self):
        """Test Similarity Lookup.

        Tests that a similarity lookup for a kindle returns 10 results.
        """
        products = self.amazon.similarity_lookup(ItemId="B0051QVF7A")
        assert_equals(len(products), 10)

    def test_product_attributes(self):
        """Test Product Attributes.

        Tests that all product that are supposed to be accessible are.
        """
        product = self.amazon.lookup(ItemId="B0051QVF7A")
        for attribute in PRODUCT_ATTRIBUTES:
            getattr(product, attribute)

    def test_browse_node_lookup(self):
        """Test Browse Node Lookup.

        Test that a lookup by Brose Node ID returns appropriate node.
        """
        bnid = 2642129011
        bn = self.amazon.browse_node_lookup(BrowseNodeId=bnid)[0]
        assert_equals(bn.id, bnid)
        assert_equals(bn.name, "eBook Readers")
        assert_equals(bn.is_category_root, False)
class TestAmazonApi(unittest.TestCase):
    """Test Amazon API

    Test Class for Amazon simple API wrapper.
    """

    def setUp(self):
        """Set Up.

        Initialize the Amazon API wrapper. The following values:

        * AMAZON_ACCESS_KEY
        * AMAZON_SECRET_KEY
        * AMAZON_ASSOC_TAG

        Are imported from a custom file named: 'test_settings.py'
        """
        self.amazon = AmazonAPI(
            _AMAZON_ACCESS_KEY,
            _AMAZON_SECRET_KEY,
            _AMAZON_ASSOC_TAG,
            CacheReader=cache_reader,
            CacheWriter=cache_writer,
            MaxQPS=0.5
        )

    @flaky(max_runs=3, rerun_filter=delay_rerun)
    def test_lookup(self):
        """Test Product Lookup.

        Tests that a product lookup for a kindle returns results and that the
        main methods are working.
        """
        product = self.amazon.lookup(ItemId="B00ZV9PXP2")
        assert_true('Kindle' in product.title)
        assert_equals(product.ean, '0848719083774')
        assert_equals(
            product.large_image_url,
            'https://images-na.ssl-images-amazon.com/images/I/51hrdzXLUHL.jpg'
        )
        assert_equals(
            product.get_attribute('Publisher'),
            'Amazon'
        )
        assert_equals(product.get_attributes(
            ['ItemDimensions.Width', 'ItemDimensions.Height']),
            {'ItemDimensions.Width': '450', 'ItemDimensions.Height': '36'})
        assert_true(len(product.browse_nodes) > 0)
        assert_true(product.price_and_currency[0] is not None)
        assert_true(product.price_and_currency[1] is not None)
        assert_equals(product.browse_nodes[0].id, 2642129011)
        assert_equals(product.browse_nodes[0].name, 'eBook Readers')

    @flaky(max_runs=3, rerun_filter=delay_rerun)
    def test_lookup_nonexistent_asin(self):
        """Test Product Lookup with a nonexistent ASIN.

        Tests that a product lookup for a nonexistent ASIN raises AsinNotFound.
        """
        assert_raises(AsinNotFound, self.amazon.lookup, ItemId="ABCD1234")

    @flaky(max_runs=3, rerun_filter=delay_rerun)
    def test_bulk_lookup(self):
        """Test Baulk Product Lookup.

        Tests that a bulk product lookup request returns multiple results.
        """
        asins = [TEST_ASIN, 'B00BWYQ9YE',
                 'B00BWYRF7E', 'B00D2KJDXA']
        products = self.amazon.lookup(ItemId=','.join(asins))
        assert_equals(len(products), len(asins))
        for i, product in enumerate(products):
            assert_equals(asins[i], product.asin)

    @flaky(max_runs=3, rerun_filter=delay_rerun)
    def test_lookup_bulk(self):
        """Test Bulk Product Lookup.

        Tests that a bulk product lookup request returns multiple results.
        """
        asins = [TEST_ASIN, 'B00BWYQ9YE',
                 'B00BWYRF7E', 'B00D2KJDXA']
        products = self.amazon.lookup_bulk(ItemId=','.join(asins))
        assert_equals(len(products), len(asins))
        for i, product in enumerate(products):
            assert_equals(asins[i], product.asin)

    @flaky(max_runs=3, rerun_filter=delay_rerun)
    def test_lookup_bulk_empty(self):
        """Test Bulk Product Lookup With No Results.

        Tests that a bulk product lookup request with no results
        returns an empty list.
        """
        asins = ['not-an-asin', 'als-not-an-asin']
        products = self.amazon.lookup_bulk(ItemId=','.join(asins))
        assert_equals(type(products), list)
        assert_equals(len(products), 0)

    @flaky(max_runs=3, rerun_filter=delay_rerun)
    def test_search(self):
        """Test Product Search.

        Tests that a product search is working (by testing that results are
        returned). And that each result has a title attribute. The test
        fails if no results where returned.
        """
        products = self.amazon.search(Keywords='kindle', SearchIndex='All')
        for product in products:
            assert_true(hasattr(product, 'title'))
            break
        else:
            assert_true(False, 'No search results returned.')

    @flaky(max_runs=3, rerun_filter=delay_rerun)
    def test_search_n(self):
        """Test Product Search N.

        Tests that a product search n is working by testing that N results are
        returned.
        """
        products = self.amazon.search_n(
            1,
            Keywords='kindle',
            SearchIndex='All'
        )
        assert_equals(len(products), 1)

    @flaky(max_runs=3, rerun_filter=delay_rerun)
    def test_search_iterate_pages(self):
        products = self.amazon.search(Keywords='internet of things oreilly',
                                      SearchIndex='Books')
        assert_false(products.is_last_page)
        for product in products:
            pass
        assert_true(products.is_last_page)


    @flaky(max_runs=3, rerun_filter=delay_rerun)
    def test_search_no_results(self):
        """Test Product Search with no results.

        Tests that a product search with that returns no results throws a
        SearchException.
        """
        products = self.amazon.search(Title='no-such-thing-on-amazon',
                                      SearchIndex='Automotive')
        assert_raises(SearchException, next, (x for x in products))

    def test_amazon_api_defaults_to_US(self):
        """Test Amazon API defaults to the US store."""
        amazon = AmazonAPI(
            _AMAZON_ACCESS_KEY,
            _AMAZON_SECRET_KEY,
            _AMAZON_ASSOC_TAG
        )
        assert_equals(amazon.api.Region, "US")

    @flaky(max_runs=3, rerun_filter=delay_rerun)
    def test_search_amazon_uk(self):
        """Test Poduct Search on Amazon UK.

        Tests that a product search on Amazon UK is working and that the
        currency of any of the returned products is GBP. The test fails if no
        results were returned.
        """
        amazon = AmazonAPI(
            _AMAZON_ACCESS_KEY,
            _AMAZON_SECRET_KEY,
            _AMAZON_ASSOC_TAG,
            region="UK"
        )
        assert_equals(amazon.api.Region, "UK", "Region has not been set to UK")

        products = amazon.search(Keywords='Kindle', SearchIndex='All')
        currencies = [product.price_and_currency[1] for product in products]
        assert_true(len(currencies), "No products found")

        is_gbp = 'GBP' in currencies
        assert_true(is_gbp, "Currency is not GBP, cannot be Amazon UK, though")

    @flaky(max_runs=3, rerun_filter=delay_rerun)
    def test_similarity_lookup(self):
        """Test Similarity Lookup.

        Tests that a similarity lookup for a kindle returns 10 results.
        """
        products = self.amazon.similarity_lookup(ItemId=TEST_ASIN)
        assert_true(len(products) > 5)

    @flaky(max_runs=3, rerun_filter=delay_rerun)
    def test_product_attributes(self):
        """Test Product Attributes.

        Tests that all product that are supposed to be accessible are.
        """
        product = self.amazon.lookup(ItemId=TEST_ASIN)
        for attribute in PRODUCT_ATTRIBUTES:
            getattr(product, attribute)

    @flaky(max_runs=3, rerun_filter=delay_rerun)
    def test_browse_node_lookup(self):
        """Test Browse Node Lookup.

        Test that a lookup by Brose Node ID returns appropriate node.
        """
        bnid = 2642129011
        bn = self.amazon.browse_node_lookup(BrowseNodeId=bnid)[0]
        assert_equals(bn.id, bnid)
        assert_equals(bn.name, 'eBook Readers')
        assert_equals(bn.is_category_root, False)

    @flaky(max_runs=3, rerun_filter=delay_rerun)
    def test_obscure_date(self):
        """Test Obscure Date Formats

        Test a product with an obscure date format
        """
        product = self.amazon.lookup(ItemId="0933635869")
        assert_equals(product.publication_date.year, 1992)
        assert_equals(product.publication_date.month, 5)
        assert_true(isinstance(product.publication_date, datetime.date))

    @flaky(max_runs=3, rerun_filter=delay_rerun)
    def test_single_creator(self):
        """Test a product with a single creator
        """
        product = self.amazon.lookup(ItemId="B00005NZJA")
        creators = dict(product.creators)
        assert_equals(creators[u"Jonathan Davis"], u"Narrator")
        assert_equals(len(creators.values()), 2)

    @flaky(max_runs=3, rerun_filter=delay_rerun)
    def test_multiple_creators(self):
        """Test a product with multiple creators
        """
        product = self.amazon.lookup(ItemId="B007V8RQC4")
        creators = dict(product.creators)
        assert_equals(creators[u"John Gregory Betancourt"], u"Editor")
        assert_equals(creators[u"Colin Azariah-Kribbs"], u"Editor")
        assert_equals(len(creators.values()), 2)

    @flaky(max_runs=3, rerun_filter=delay_rerun)
    def test_no_creators(self):
        """Test a product with no creators
        """
        product = self.amazon.lookup(ItemId="8420658537")
        assert_false(product.creators)

    @flaky(max_runs=3, rerun_filter=delay_rerun)
    def test_single_editorial_review(self):
        product = self.amazon.lookup(ItemId="1930846258")
        expected = u'In the title piece, Alan Turing'
        assert_equals(product.editorial_reviews[0][:len(expected)], expected)
        assert_equals(product.editorial_review, product.editorial_reviews[0])
        assert_equals(len(product.editorial_reviews), 1)

    @flaky(max_runs=3, rerun_filter=delay_rerun)
    def test_multiple_editorial_reviews(self):
        product = self.amazon.lookup(ItemId="B01HQA6EOC")
        expected = u'<p>Introducing an instant classic—master storyteller'
        assert_equals(product.editorial_reviews[0][:len(expected)], expected)
        expected = u'<strong>An Amazon Best Book of February 2017:</strong>'
        assert_equals(product.editorial_reviews[1][:len(expected)], expected)
        # duplicate data, amazon user data is great...
        expected = u'<p>Introducing an instant classic—master storyteller'
        assert_equals(product.editorial_reviews[2][:len(expected)], expected)

        assert_equals(len(product.editorial_reviews), 3)

    @flaky(max_runs=3, rerun_filter=delay_rerun)
    def test_languages_english(self):
        """Test Language Data

        Test an English product
        """
        product = self.amazon.lookup(ItemId="1930846258")
        assert_true('english' in product.languages)
        assert_equals(len(product.languages), 1)

    @flaky(max_runs=3, rerun_filter=delay_rerun)
    def test_languages_spanish(self):
        """Test Language Data

        Test an English product
        """
        product = self.amazon.lookup(ItemId="8420658537")
        assert_true('spanish' in product.languages)
        assert_equals(len(product.languages), 1)

    def test_region(self):
        amazon = AmazonAPI(_AMAZON_ACCESS_KEY, _AMAZON_SECRET_KEY,
                           _AMAZON_ASSOC_TAG)
        assert_equals(amazon.region, 'US')

        # old 'region' parameter
        amazon = AmazonAPI(_AMAZON_ACCESS_KEY, _AMAZON_SECRET_KEY,
                           _AMAZON_ASSOC_TAG, region='UK')
        assert_equals(amazon.region, 'UK')

        # kwargs method
        amazon = AmazonAPI(_AMAZON_ACCESS_KEY, _AMAZON_SECRET_KEY,
                           _AMAZON_ASSOC_TAG, Region='UK')
        assert_equals(amazon.region, 'UK')

    @flaky(max_runs=3, rerun_filter=delay_rerun)
    def test_is_adult(self):
        product = self.amazon.lookup(ItemId="B01E7P9LEE")
        assert_true(product.is_adult is not None)

    @flaky(max_runs=3, rerun_filter=delay_rerun)
    def test_product_group(self):
        product = self.amazon.lookup(ItemId="B01LXM0S25")
        assert_equals(product.product_group, 'DVD')

        product = self.amazon.lookup(ItemId="B01NBTSVDN")
        assert_equals(product.product_group, 'Digital Music Album')

    @flaky(max_runs=3, rerun_filter=delay_rerun)
    def test_product_type_name(self):
        product = self.amazon.lookup(ItemId="B01NBTSVDN")
        assert_equals(product.product_type_name, 'DOWNLOADABLE_MUSIC_ALBUM')

    @flaky(max_runs=3, rerun_filter=delay_rerun)
    def test_formatted_price(self):
        product = self.amazon.lookup(ItemId="B01NBTSVDN")
        assert_equals(product.formatted_price, '$12.49')

    @flaky(max_runs=3, rerun_filter=delay_rerun)
    def test_price_and_currency(self):
        product = self.amazon.lookup(ItemId="B01NBTSVDN")
        price, currency = product.price_and_currency
        assert_equals(price, Decimal('12.49'))
        assert_equals(currency, 'USD')

    @flaky(max_runs=3, rerun_filter=delay_rerun)
    def test_list_price(self):
        product = self.amazon.lookup(ItemId="B01NBTSVDN")
        price, currency = product.list_price
        assert_equals(price, Decimal('12.49'))
        assert_equals(currency, 'USD')

    @flaky(max_runs=3, rerun_filter=delay_rerun)
    def test_running_time(self):
        product = self.amazon.lookup(ItemId="B01NBTSVDN")
        assert_equals(product.running_time, '3567')

    @flaky(max_runs=3, rerun_filter=delay_rerun)
    def test_studio(self):
        product = self.amazon.lookup(ItemId="B01NBTSVDN")
        assert_equals(product.studio, 'Atlantic Records UK')

    @flaky(max_runs=3, rerun_filter=delay_rerun)
    def test_is_preorder(self):
        product = self.amazon.lookup(ItemId="B01NBTSVDN")
        assert_equals(product.is_preorder , None)

    @flaky(max_runs=3, rerun_filter=delay_rerun)
    def test_detail_page_url(self):
        product = self.amazon.lookup(ItemId="B01NBTSVDN")
        assert_true(product.detail_page_url.startswith('https://www.amazon.com/%C3%B7-Deluxe-Ed-Sheeran/dp/B01NBTSVDN'))

    @flaky(max_runs=3, rerun_filter=delay_rerun)
    def test_availability(self):
        product = self.amazon.lookup(ItemId="B00ZV9PXP2")
        assert_equals(product.availability, 'Usually ships in 24 hours')

        product = self.amazon.lookup(ItemId="1491914254") # pre-order book
        assert_equals(product.availability, 'Not yet published')

    @flaky(max_runs=3, rerun_filter=delay_rerun)
    def test_availability_type(self):
        product = self.amazon.lookup(ItemId="B00ZV9PXP2")
        assert_equals(product.availability_type, 'now')

        product = self.amazon.lookup(ItemId="1491914254") # pre-order book
        assert_equals(product.availability_type, 'now')

        product = self.amazon.lookup(ItemId="B00ZV9PXP2") # late availability
        assert_equals(product.availability_type, 'now')

    @flaky(max_runs=3, rerun_filter=delay_rerun)
    def test_availability_min_max_hours(self):
        product = self.amazon.lookup(ItemId="B00ZV9PXP2")
        assert_equals(product.availability_min_hours, '0')
        assert_equals(product.availability_max_hours, '0')


    def test_kwargs(self):
        amazon = AmazonAPI(_AMAZON_ACCESS_KEY, _AMAZON_SECRET_KEY,
                           _AMAZON_ASSOC_TAG, MaxQPS=0.7)

    @flaky(max_runs=3, rerun_filter=delay_rerun)
    def test_images(self):
        """Test images property

        Test that the images property has a value when using the
        Images ResponseGroup
        """
        product = self.amazon.lookup(ResponseGroup='Images',
                                     ItemId='B00TSVVNQC')
        assert_equals(type(product.images), list)
        assert_equals(len(product.images), 7)
class TestAmazonApi(TestCase):
    """Test Amazon API

    Test Class for Amazon simple API wrapper.
    """
    def setUp(self):
        """Set Up.

        Initialize the Amazon API wrapper. The following values:

        * AMAZON_ACCESS_KEY
        * AMAZON_SECRET_KEY
        * AMAZON_ASSOC_TAG

        Are imported from a custom file named: 'test_settings.py'
        """
        self.amazon = AmazonAPI(AMAZON_ACCESS_KEY, AMAZON_SECRET_KEY,
                                AMAZON_ASSOC_TAG)

    def test_lookup(self):
        """Test Product Lookup.

        Tests that a product lookup for a kindle returns results and that the
        main methods are working.
        """
        product = self.amazon.lookup(ItemId="B0051QVF7A")
        assert_equals(
            product.title,
            'Kindle, Wi-Fi, 6" E Ink Display - for international shipment')
        assert_equals(product.ean, '0814916014354')
        assert_equals(
            product.large_image_url,
            'http://ecx.images-amazon.com/images/I/411H%2B731ZzL.jpg')
        assert_equals(product.get_attribute('Publisher'),
                      'Amazon Digital Services, Inc')
        assert_equals(
            product.get_attributes(
                ['ItemDimensions.Width', 'ItemDimensions.Height']), {
                    'ItemDimensions.Width': '450',
                    'ItemDimensions.Height': '34'
                })

    def test_batch_lookup(self):
        """Test Batch Product Lookup.

        Tests that a batch product lookup request returns multiple results.
        """
        asins = [
            'B0051QVESA', 'B005DOK8NW', 'B005890G8Y', 'B0051VVOB2',
            'B005890G8O'
        ]
        products = self.amazon.lookup(ItemId=','.join(asins))
        assert_equals(len(products), 5)
        for i, product in enumerate(products):
            assert_equals(asins[i], product.asin)

    def test_search(self):
        """Test Product Search.

        Tests that a product search is working (by testing that results are
        returned). And that each result has a title attribute. The test
        fails if no results where returned.
        """
        products = self.amazon.search(Keywords='kindle', SearchIndex='All')
        for product in products:
            assert_true(hasattr(product, 'title'))
            break
        else:
            assert_true(False, 'No search results returned.')

    def test_search_n(self):
        """Test Product Search N.

        Tests that a product search n is working by testing that N results are
        returned.
        """
        products = self.amazon.search_n(1,
                                        Keywords='kindle',
                                        SearchIndex='All')
        assert_equals(len(products), 1)

    def test_amazon_api_defaults_to_US(self):
        """Test Amazon API defaults to the US store."""
        amazon = AmazonAPI(AMAZON_ACCESS_KEY, AMAZON_SECRET_KEY,
                           AMAZON_ASSOC_TAG)
        assert_equals(amazon.api.Region, "US")

    def test_search_amazon_uk(self):
        """Test Poduct Search on Amazon UK.

        Tests that a product search on Amazon UK is working and that the
        currency of any of the returned products is GBP. The test fails if no
        results were returned.
        """
        amazon = AmazonAPI(AMAZON_ACCESS_KEY,
                           AMAZON_SECRET_KEY,
                           AMAZON_ASSOC_TAG,
                           region="UK")
        assert_equals(amazon.api.Region, "UK", "Region has not been set to UK")

        products = amazon.search(Keywords='Kindle', SearchIndex='All')
        currencies = [product.price_and_currency[1] for product in products]
        assert_true(len(currencies), "No products found")

        is_gbp = 'GBP' in currencies
        assert_true(is_gbp, "Currency is not GBP, cannot be Amazon UK, though")

    def test_similarity_lookup(self):
        """Test Similarity Lookup.

        Tests that a similarity lookup for a kindle returns 10 results.
        """
        products = self.amazon.similarity_lookup(ItemId="B0051QVF7A")
        assert_equals(len(products), 10)