diff --git a/.gitignore b/.gitignore index b401fe8..0a764d8 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ +ebay.yaml timebay.yaml build/ dist/ @@ -12,3 +13,4 @@ ebaysdk.egg-info/ \.tox venv/ venv* +\.virtualenvs diff --git a/ebay.yaml b/ebay.yaml new file mode 100644 index 0000000..fc170b6 --- /dev/null +++ b/ebay.yaml @@ -0,0 +1,27 @@ +name: ebay_api_config + +# Trading API Sandbox - https://www.x.com/developers/ebay/products/trading-api +api.sandbox.ebay.com: + compatability: 719 + appid: ENTER_YOUR_APPID_HERE + certid: ENTER_YOUR_CERTID_HERE + devid: ENTER_YOUR_DEVID_HERE + token: ENTER_YOUR_TOKEN_HERE + +# Trading API - https://www.x.com/developers/ebay/products/trading-api +api.ebay.com: + compatability: 719 + appid: ENTER_YOUR_APPID_HERE + certid: ENTER_YOUR_CERTID_HERE + devid: ENTER_YOUR_DEVID_HERE + token: ENTER_YOUR_TOKEN_HERE + +# Finding API - https://www.x.com/developers/ebay/products/finding-api +svcs.ebay.com: + appid: ENTER_YOUR_APPID_HERE + version: 1.0.0 + +# Shopping API - https://www.x.com/developers/ebay/products/shopping-api +open.api.ebay.com: + appid: ENTER_YOUR_APPID_HERE + version: 671 diff --git a/ebaysdk/__init__.py b/ebaysdk/__init__.py index cf8ab9b..79b6c1a 100644 --- a/ebaysdk/__init__.py +++ b/ebaysdk/__init__.py @@ -9,8 +9,8 @@ import platform import logging -__version__ = '2.1.4' -Version = __version__ # for backware compatibility +__version__ = '2.1.5' +Version = __version__ # for backward compatibility try: from logging import NullHandler diff --git a/ebaysdk/config.py b/ebaysdk/config.py index 1766496..ed857af 100644 --- a/ebaysdk/config.py +++ b/ebaysdk/config.py @@ -17,8 +17,6 @@ class Config(object): """Config Class for all APIs connections >>> c = Config(domain='api.ebay.com') - >>> print(c.file()) - ebay.yaml >>> c.set('fname', 'tim') >>> c.get('fname') 'tim' diff --git a/ebaysdk/connection.py b/ebaysdk/connection.py index 77d5f8f..6948cef 100644 --- a/ebaysdk/connection.py +++ b/ebaysdk/connection.py @@ -30,6 +30,12 @@ True: 'https', } +# Added compatibility for Python 3 +try: + basestring +except NameError: + basestring = str + class BaseConnection(object): """Base Connection Class.""" diff --git a/ebaysdk/finding/__init__.py b/ebaysdk/finding/__init__.py index fb0ba25..468930a 100644 --- a/ebaysdk/finding/__init__.py +++ b/ebaysdk/finding/__init__.py @@ -28,7 +28,7 @@ class Connection(BaseConnection): Doctests: >>> f = Connection(config_file=os.environ.get('EBAY_YAML'), debug=False) - >>> retval = f.execute('findItemsAdvanced', {'keywords': u'niño'}) + >>> retval = f.execute('findItemsAdvanced', {'keywords': u'El Niño'}) >>> error = f.error() >>> print(error) None @@ -99,6 +99,7 @@ def __init__(self, **kwargs): 'finditemsbykeywordsresponse.categoryhistogramcontainer.categoryhistogram', 'finditemsbyproductresponse.categoryhistogramcontainer.categoryhistogram', 'finditemsinebaystoresresponse.categoryhistogramcontainer.categoryhistogram', + 'finditemsinebaystoresresponse.categoryhistogramcontainer.categoryhistogram.childcategoryhistogram', 'findcompleteditemsresponse.aspecthistogramcontainer.aspect', 'finditemsadvancedresponse.aspecthistogramcontainer.aspect', 'finditemsbycategoryresponse.aspecthistogramcontainer.aspect', diff --git a/ebaysdk/parallel.py b/ebaysdk/parallel.py index bee0923..bc311e5 100644 --- a/ebaysdk/parallel.py +++ b/ebaysdk/parallel.py @@ -6,11 +6,14 @@ Licensed under CDDL 1.0 ''' import sys -if sys.version_info[0] >= 3: - raise ImportError('grequests does not work with python3+') +from ebaysdk.exception import ConnectionError +# pylint: disable=import-error import grequests -from ebaysdk.exception import ConnectionError +# pylint: enable=import-error + +if sys.version_info[0] >= 3: + raise ImportError('grequests does not work with python3+') class Parallel(object): diff --git a/ebaysdk/shopping/__init__.py b/ebaysdk/shopping/__init__.py index ceec437..a34b92e 100644 --- a/ebaysdk/shopping/__init__.py +++ b/ebaysdk/shopping/__init__.py @@ -46,7 +46,7 @@ def __init__(self, **kwargs): uri -- API endpoint uri (default: /shopping) appid -- eBay application id siteid -- eBay country site id (default: 0 (US)) - compatibility -- version number (default: 799) + version -- version number (default: 799) https -- execute of https (default: True) proxy_host -- proxy hostname proxy_port -- proxy port number diff --git a/ebaysdk/soa/__init__.py b/ebaysdk/soa/__init__.py index 25193ab..67f003b 100644 --- a/ebaysdk/soa/__init__.py +++ b/ebaysdk/soa/__init__.py @@ -55,24 +55,6 @@ def load_from_app_config(self, app_config): def response_dict(self): return self.response.dict() - ''' - if self._response_dict: - return self._response_dict - - if self._response_content: - - mydict = self.response.dict() - - try: - verb = self.verb + 'Response' - self._response_dict = mydict['Envelope']['Body'][verb] - - except KeyError: - self._response_dict = mydict.get(self.verb + 'Response', mydict) - - return self._response_dict - ''' - def build_request_headers(self, verb): return { 'Content-Type': self.config.get('content_type'), diff --git a/ebaysdk/trading/__init__.py b/ebaysdk/trading/__init__.py index 183db30..1349c19 100644 --- a/ebaysdk/trading/__init__.py +++ b/ebaysdk/trading/__init__.py @@ -681,7 +681,7 @@ def build_request_headers(self, verb): "X-EBAY-API-DEV-NAME": self.config.get('devid', ''), "X-EBAY-API-APP-NAME": self.config.get('appid', ''), "X-EBAY-API-CERT-NAME": self.config.get('certid', ''), - "X-EBAY-API-SITEID": self.config.get('siteid', ''), + "X-EBAY-API-SITEID": str(self.config.get('siteid', '')), "X-EBAY-API-CALL-NAME": self.verb, "Content-Type": "text/xml" } @@ -785,7 +785,7 @@ def _get_resp_body_errors(self): .format(eClass=eClass, severity=eSeverity, code=eCode, shortMsg=eShortMsg, longMsg=eLongMsg) - #from IPython import embed; embed() + # from IPython import embed; embed() if eSeverity == 'Warning': warnings.append(msg) diff --git a/ebaysdk/utils.py b/ebaysdk/utils.py index 64ac996..94cdd26 100644 --- a/ebaysdk/utils.py +++ b/ebaysdk/utils.py @@ -96,7 +96,8 @@ def smart_encode_request_data(value): try: if sys.version_info[0] < 3: return value - + if type(value) == dict: # Added compatibility for Python 3 + return {k: v.encode('utf-8') for (k, v) in value.items()} return value.encode('utf-8') except UnicodeDecodeError: @@ -344,8 +345,8 @@ def perftest_dict2xml(): xml = dict2xml(sample_dict) -if __name__ == '__main__': +if __name__ == '__main__': import timeit print("perftest_dict2xml() %s" % timeit.timeit("perftest_dict2xml()", number=50000, diff --git a/samples/finding.py b/samples/finding.py index 674c6f8..bb45bf5 100644 --- a/samples/finding.py +++ b/samples/finding.py @@ -31,6 +31,9 @@ def init_options(): parser.add_option("-a", "--appid", dest="appid", default=None, help="Specifies the eBay application id to use.") + parser.add_option("-n", "--domain", + dest="domain", default='svcs.ebay.com', + help="Specifies the eBay domain to use (e.g. svcs.sandbox.ebay.com).") (opts, args) = parser.parse_args() return opts, args @@ -39,7 +42,7 @@ def init_options(): def run(opts): try: - api = finding(debug=opts.debug, appid=opts.appid, + api = finding(debug=opts.debug, appid=opts.appid, domain=opts.domain, config_file=opts.yaml, warnings=True) api_request = { @@ -66,7 +69,7 @@ def run(opts): def run_unicode(opts): try: - api = finding(debug=opts.debug, appid=opts.appid, + api = finding(debug=opts.debug, appid=opts.appid, domain=opts.domain, config_file=opts.yaml, warnings=True) api_request = { @@ -88,7 +91,7 @@ def run_unicode(opts): def run2(opts): try: - api = finding(debug=opts.debug, appid=opts.appid, + api = finding(debug=opts.debug, appid=opts.appid, domain=opts.domain, config_file=opts.yaml) response = api.execute('findItemsByProduct', @@ -103,7 +106,7 @@ def run2(opts): def run_motors(opts): api = finding(siteid='EBAY-MOTOR', debug=opts.debug, appid=opts.appid, config_file=opts.yaml, - warnings=True) + domain=opts.domain, warnings=True) api.execute('findItemsAdvanced', { 'keywords': 'tesla', diff --git a/samples/storeMeta.py b/samples/storeMeta.py new file mode 100644 index 0000000..9098e53 --- /dev/null +++ b/samples/storeMeta.py @@ -0,0 +1,282 @@ +# -*- coding: utf-8 -*- +''' +© 2012-2013 eBay Software Foundation +Authored by: Tim Keefer +Licensed under CDDL 1.0 +''' + +import os +import sys +from optparse import OptionParser +import csv +import json +import requests + +sys.path.insert(0, '%s/../' % os.path.dirname(__file__)) + +from common import dump + +import ebaysdk +from ebaysdk.finding import Connection as finding +from ebaysdk.exception import ConnectionError, RequestPaginationError, PaginationLimit + + +def init_options(): + usage = "usage: %prog [options]" + parser = OptionParser(usage=usage) + + parser.add_option("-d", "--debug", + action="store_true", dest="debug", default=False, + help="Enabled debugging [default: %default]") + parser.add_option("-y", "--yaml", + dest="yaml", default='ebay.yaml', + help="Specifies the name of the YAML defaults file. [default: %default]") + parser.add_option("-a", "--appid", + dest="appid", default=None, + help="Specifies the eBay application id to use.") + parser.add_option("-s", "--store_name", + dest="store_name", default=None, + help="Store name") + parser.add_option("-f", "--file", + dest="input_file", default=None, + help="Input file containing store names.") + parser.add_option("-o", "--offset", + dest="offset", default=0, + help="Input file line offset.") + parser.add_option("-e", "--line_end", + dest="line_end", default=None, + help="Input file lines.") + + (opts, args) = parser.parse_args() + return opts, args + + +def run(opts): + + data = None + if opts.store_name: + data = get_store_meta(opts.store_name) + print(data) + + if opts.input_file: + lines = [] + with open(opts.input_file, newline='') as csvfile: + for row1 in csv.reader(csvfile, delimiter=',', quotechar='"'): + name = row1[1] + desc = row1[2].replace('\n', '') + logo = row1[3] + sub = row1[4] + lines.append([name, desc, logo, sub]) + + for row in lines[int(opts.offset):(int(opts.offset)+1000)]: + print("(%s)" % row) + + if row[3] == 'http://': + row[3] = None + + if row[0] and row[2] and row[3]: + if record_exists(row[0]): + print("skipping %s" % row[0]) + continue + + try: + data = get_store_meta(row[0]) + except Exception as e: + print("Exception %s" % e) + + if not data: + continue + + data['store_logo'] = row[2] + data['store_name'] = row[0] + data['store_description'] = row[1] + data['subscription_level'] = row[3] + + req = requests.post( + 'http://elastic-1-2467465.lvs02.dev.ebayc3.com:9200/stores/storeMeta', + data=json.dumps(data, sort_keys=True) + ) + print(req.text) + + else: + pass + + +def record_exists(store_name): + query = { + "query": { + "match": { + "store_name": { + "query": store_name, + "type": "phrase" + } + } + } + } + + query_req = requests.get('http://elastic-1-2467465.lvs02.dev.ebayc3.com:9200/stores/storeMeta/_search', + data=json.dumps(query, sort_keys=True)) + + try: + record_id = query_req.json()['hits']['hits'][0]['_id'] + except Exception as e: + record_id = None + + return record_id + + +def get_store_meta(store_name): + + try: + api = finding(debug=opts.debug, appid=opts.appid, + config_file=opts.yaml) + + response = api.execute('findItemsIneBayStores', { + 'storeName': store_name, + 'outputSelector': [ + 'CategoryHistogram', + 'AspectHistogram', + 'SellerInfo', + 'StoreInfo', + ]} + ) + + if response.reply.ack != 'Success': + return {} + + if int(response.reply.paginationOutput.totalEntries) <= 0: + return {} + + data = { + 'followers': 0, + 'item_count': response.reply.paginationOutput.totalEntries, + 'seller_name': response.reply.searchResult.item[0].sellerInfo.sellerUserName, + 'store_url': response.reply.searchResult.item[0].storeInfo.storeURL, + 'feedback_score': response.reply.searchResult.item[0].sellerInfo.feedbackScore, + 'positive_feedback_percent': response.reply.searchResult.item[0].sellerInfo.positiveFeedbackPercent, + 'top_rated_seller': response.reply.searchResult.item[0].sellerInfo.topRatedSeller, + 'country_code': response.reply.searchResult.item[0].country, + } + + agg_data = { + 'cat_asp': {}, + 'watch_count': 0, + 'L0': [], + 'L1': [], + } + + dominate_l0_cat_count = 0 + dominate_l1_cat_count = 0 + + for lev0 in response.reply.categoryHistogramContainer.categoryHistogram: + agg_data['L0'].append({ + 'category_id': lev0.categoryId, + 'category_name': lev0.categoryName, + 'item_count': lev0.count + }) + + if int(lev0.count) > dominate_l0_cat_count: + dominate_l0_cat_count = int(lev0.count) + agg_data['dominate_l0_category_id'] = lev0.categoryId + agg_data['dominate_l0_category_name'] = lev0.categoryName + + for lev1 in lev0.childCategoryHistogram: + agg_data['L1'].append({ + 'category_id': lev1.categoryId, + 'category_name': lev1.categoryName, + 'item_count': lev1.count + }) + + if int(lev1.count) > dominate_l1_cat_count: + dominate_l1_cat_count = int(lev1.count) + agg_data['dominate_l1_category_id'] = lev1.categoryId + agg_data['dominate_l1_category_name'] = lev1.categoryName + + + + for category_node in agg_data['L1']: + category_id = category_node['category_id'] + + category_call = api.execute('findItemsIneBayStores', { + 'storeName': store_name, + 'categoryId': category_id, + 'outputSelector': [ + 'CategoryHistogram', + 'AspectHistogram', + 'SellerInfo', + 'StoreInfo', + ]} + ) + + if category_call.reply.ack != 'Success': + return {} + + if int(category_call.reply.paginationOutput.totalEntries) <= 0: + return {} + + analyze_items(category_call.reply.searchResult.item, category_id, agg_data) + + try: + while True: + category_call2 = api.next_page() + analyze_items(category_call2.reply.searchResult.item, category_id, agg_data) + + except PaginationLimit as e: + pass + + dom_l1_asp = average_asp( + agg_data['cat_asp'][agg_data['dominate_l1_category_id']] + ) + + for category_node in agg_data['L1']: + asp = average_asp(agg_data['cat_asp'][category_node['category_id']]) + category_node.update({'asp': asp}) + + data.update({ + 'L0': agg_data['L0'], + 'L1': agg_data['L1'], + 'watch_count': agg_data['watch_count'], + 'postal_code': agg_data.get('postal_code', None), + 'dominate_category_id': agg_data['dominate_l0_category_id'], + 'dominate_category_name': agg_data['dominate_l0_category_name'], + 'dominate_l1_category_id': agg_data['dominate_l1_category_id'], + 'dominate_l1_category_name': agg_data['dominate_l1_category_name'], + 'dominate_l1_category_asp': dom_l1_asp, + }) + + #from IPython import embed; + #embed() + + return data + + except ConnectionError as e: + print(e) + + +def average_asp(prices): + total = sum(prices) + if total > 0: + return total / len(prices) + else: + return 0 + + +def analyze_items(items, category_id, agg_data): + + for item in items: + if not agg_data['cat_asp'].get(category_id, None): + agg_data['cat_asp'][category_id] = [] + + agg_data['cat_asp'][category_id].append(float(item.sellingStatus.currentPrice.value)) + if getattr(item.listingInfo, 'watchCount', None): + agg_data['watch_count'] += int(item.listingInfo.watchCount) + + if getattr(item, 'postalCode', None): + agg_data['postal_code'] = item.postalCode + + +if __name__ == "__main__": + print("Finding samples for SDK version %s" % ebaysdk.get_version()) + (opts, args) = init_options() + + run(opts) diff --git a/samples/trading.py b/samples/trading.py index 00bc85b..06e2b1b 100644 --- a/samples/trading.py +++ b/samples/trading.py @@ -104,7 +104,8 @@ def verifyAddItem(opts): "Title": "Harry Potter and the Philosopher's Stone", "Description": "This is the first book in the Harry Potter series. In excellent condition!", "PrimaryCategory": {"CategoryID": "377"}, - "StartPrice": "1.0", + "StartPrice": "10.0", + "BuyItNowPrice": "15.0", "CategoryMappingAllowed": "true", "Country": "US", "ConditionID": "3000", @@ -124,12 +125,29 @@ def verifyAddItem(opts): "Description": "If you are not satisfied, return the book for refund.", "ShippingCostPaidByOption": "Buyer" }, + "SellerProfiles": { + "SellerPaymentProfile": { + "PaymentProfileName": "PayPal:Immediate pay", + }, + "SellerReturnProfile": { + "ReturnProfileName": "30 Day Return Policy", + }, + "SellerShippingProfile": { + "ShippingProfileName": "USPS First Class, Priority, Priority Express Flat Rate Envelope", + } + }, "ShippingDetails": { - "ShippingType": "Flat", + "ShippingType": "Calculated", "ShippingServiceOptions": { "ShippingServicePriority": "1", - "ShippingService": "USPSMedia", - "ShippingServiceCost": "2.50" + "ShippingService": "USPSMedia" + }, + "CalculatedShippingRate": { + "OriginatingPostalCode": "95125", + "PackagingHandlingCosts": "0.0", + "ShippingPackage": "PackageThickEnvelope", + "WeightMajor": "1", + "WeightMinor": "0" } }, "Site": "US" @@ -189,6 +207,25 @@ def verifyAddItemErrorCodes(opts): } } + motors_item = { + 'Item': { + 'Category': '101', + 'Title': 'My Title', + 'ItemCompatibilityList': { + 'Compatibility': [ + { + 'CompatibilityNotes': 'Fits for all trims and engines.', + 'NameValueList': [ + {'Name': 'Year', 'Value': '2001'}, + {'Name': 'Make', 'Value': 'Honda'}, + {'Name': 'Model', 'Value': 'Accord'} + ] + }, + ] + } + } + } + api.execute('VerifyAddItem', myitem) except ConnectionError as e: @@ -317,7 +354,7 @@ def categories(opts): try: api = Trading(debug=opts.debug, config_file=opts.yaml, appid=opts.appid, - certid=opts.certid, devid=opts.devid, warnings=True, timeout=20, siteid='101') + certid=opts.certid, devid=opts.devid, warnings=True, timeout=20, siteid='0') callData = { 'DetailLevel': 'ReturnAll', @@ -346,7 +383,6 @@ def categories(opts): print("Trading API Samples for version %s" % ebaysdk.get_version()) - """ run(opts) feedback(opts) verifyAddItem(opts) @@ -356,6 +392,6 @@ def categories(opts): uploadPictureFromFilesystem(opts, ("%s/test_image.jpg" % os.path.dirname(__file__))) memberMessages(opts) categories(opts) - """ - getUser(opts) + + # getUser(opts) # getOrders(opts) diff --git a/setup.py b/setup.py index dc3395e..fc03578 100644 --- a/setup.py +++ b/setup.py @@ -20,11 +20,7 @@ PKG = 'ebaysdk' -# Get the version -VERSIONFILE = os.path.join(PKG, "__init__.py") -version = re.search(r"^__version__ = ['\"]([^'\"]*)['\"]", - open(VERSIONFILE, "rt").read(), re.M).group(1) - +version = __import__(PKG).get_version() long_desc = """This SDK is a programatic inteface into the eBay APIs. It simplifies development and cuts development time by standerizing diff --git a/tests/__init__.py b/tests/__init__.py index 7e93eb8..8b13789 100644 --- a/tests/__init__.py +++ b/tests/__init__.py @@ -1,58 +1 @@ -# -*- coding: utf-8 -*- -''' -© 2012-2013 eBay Software Foundation -Authored by: Tim Keefer -Licensed under CDDL 1.0 -''' - -import sys -import unittest -import doctest -import ebaysdk.utils -import ebaysdk.config -import ebaysdk.response -import ebaysdk.connection -import ebaysdk.http -import ebaysdk.shopping -import ebaysdk.trading -import ebaysdk.merchandising -import ebaysdk.soa.finditem -import ebaysdk.finding -import ebaysdk.poller.orders -import ebaysdk.inventorymanagement - -# does not pass with python3.3 -try: - import ebaysdk.parallel -except ImportError: - pass - - -def getTestSuite(): - suite = unittest.TestSuite() - - suite.addTest(doctest.DocTestSuite(ebaysdk.poller.orders)) - suite.addTest(doctest.DocTestSuite(ebaysdk.utils)) - suite.addTest(doctest.DocTestSuite(ebaysdk.config)) - suite.addTest(doctest.DocTestSuite(ebaysdk.response)) - suite.addTest(doctest.DocTestSuite(ebaysdk.connection)) - # suite.addTest(doctest.DocTestSuite(ebaysdk.http)) - suite.addTest(doctest.DocTestSuite(ebaysdk.shopping)) - suite.addTest(doctest.DocTestSuite(ebaysdk.trading)) - suite.addTest(doctest.DocTestSuite(ebaysdk.merchandising)) - suite.addTest(doctest.DocTestSuite(ebaysdk.finding)) - suite.addTest(doctest.DocTestSuite(ebaysdk.inventorymanagement)) - - if not sys.version_info[0] >= 3 \ - and sys.modules.has_key('grequests') is True: - # suite.addTest(doctest.DocTestSuite(ebaysdk.parallel)) - pass - - # inside only - # suite.addTest(doctest.DocTestSuite(ebaysdk.soa.finditem)) - - return suite - -runner = unittest.TextTestRunner() -runner.run(getTestSuite()) diff --git a/tests/test_base.py b/tests/test_base.py new file mode 100644 index 0000000..c27431d --- /dev/null +++ b/tests/test_base.py @@ -0,0 +1,85 @@ +# -*- coding: utf-8 -*- + +''' +© 2012-2013 eBay Software Foundation +Authored by: Tim Keefer +Licensed under CDDL 1.0 +''' + +from __future__ import absolute_import +import os +import sys +import unittest +import doctest +import ebaysdk.utils +import ebaysdk.config +import ebaysdk.response +import ebaysdk.connection +import ebaysdk.http +import ebaysdk.shopping +import ebaysdk.trading +import ebaysdk.merchandising +import ebaysdk.soa.finditem +import ebaysdk.finding +import ebaysdk.poller.orders +import ebaysdk.inventorymanagement + +# does not pass with python3.3 +try: + import ebaysdk.parallel +except ImportError: + pass + +# os.environ.setdefault("EBAY_YAML", "ebay.yaml") + + +class TestBase(unittest.TestCase): + + def doctest(self, module): + doctest.testmod(module, raise_on_error=True, verbose=False) + + def test_run_doctest_poller(self): + self.doctest(ebaysdk.poller.orders) + + def test_run_doctest_utils(self): + self.doctest(ebaysdk.utils) + + def test_run_doctest_config(self): + self.doctest(ebaysdk.config) + + def test_run_doctest_response(self): + self.doctest(ebaysdk.response) + + def test_run_doctest_connection(self): + self.doctest(ebaysdk.connection) + + def test_run_doctest_shopping(self): + s = ebaysdk.shopping.Connection(config_file=os.environ.get('EBAY_YAML')) + resp = s.execute('GetCategoryInfo', + {'CategoryID': '-1', + 'IncludeSelector': ['ChildCategories']}) + self.assertEqual(s.response.reply.Ack, 'Success') + self.assertEqual(s.error(), None) + #self.doctest(ebaysdk.shopping) + + def test_run_doctest_trading(self): + self.doctest(ebaysdk.trading) + + def test_run_doctest_merchandising(self): + self.doctest(ebaysdk.merchandising) + + def test_run_doctest_finding(self): + self.doctest(ebaysdk.finding) + + def test_run_doctest_inventorymanagement(self): + self.doctest(ebaysdk.inventorymanagement) + + def test_grequests(self): + if not sys.version_info[0] >= 3 \ + and sys.modules.has_key('grequests') is True: + + # self.doctest(ebaysdk.parallel) + pass + +if __name__ == '__main__': + unittest.main() diff --git a/tests/test_errors.py b/tests/test_errors.py new file mode 100644 index 0000000..2d4a8ae --- /dev/null +++ b/tests/test_errors.py @@ -0,0 +1,72 @@ +# -*- coding: utf-8 -*- + +''' +© 2012-2013 eBay Software Foundation +Authored by: Tim Keefer +Licensed under CDDL 1.0 +''' + +from __future__ import absolute_import +import os +import unittest +import ebaysdk.shopping +import lxml + +os.environ.setdefault("EBAY_YAML", "ebay.yaml") + +class TestErrors(unittest.TestCase): + + def DISABLE_test_single_item(self): + connection = ebaysdk.shopping.Connection(version='799', config_file=os.environ.get('EBAY_YAML')) + + for i in range(20): + connection.execute('GetSingleItem', { + 'ItemID': '262809803926', + 'version': '981', + 'IncludeSelector': ['Variations'] + }) + self.assertEqual(connection.response.status_code, 200) + self.assertEqual(type(connection.response.dom()), lxml.etree._Element) + +if __name__ == '__main__': + unittest.main() + +""" +Variations262809803926981 +2017-02-28 06:18:42,156 ebaysdk [DEBUG]:total time=0.478377819061 +2017-02-28 06:18:42,156 ebaysdk [DEBUG]:execute: verb=GetSingleItem data={'ItemID': '262809803926', 'version': 981, 'IncludeSelector': 'Variations'} +2017-02-28 06:18:42,157 ebaysdk [DEBUG]:REQUEST (3ff5f071-04c3-40c0-a4f0-57f04a9e9972): POST http://open.api.ebay.com/shopping +2017-02-28 06:18:42,157 ebaysdk [DEBUG]:headers={'Content-Length': '219', 'X-EBAY-API-REQUEST-ENCODING': 'XML', 'X-EBAY-API-VERSION': '799', 'User-Agent': 'eBaySDK/2.1.4 Pytho +n/2.7.6 Linux/3.13.0-91-generic', 'X-EBAY-SDK-REQUEST-ID': '3ff5f071-04c3-40c0-a4f0-57f04a9e9972', 'X-EBAY-API-SITE-ID': '0', 'X-EBAY-API-CALL-NAME': 'GetSingleItem', 'Content +-Type': 'text/xml', 'X-EBAY-API-APP-ID': 'LogoGrab-logograb-PRD-42f530923-a70f22b2'} +2017-02-28 06:18:42,157 ebaysdk [DEBUG]:body=Variations262809803926981 +2017-02-28 06:18:42,511 ebaysdk [DEBUG]:RESPONSE (3ff5f071-04c3-40c0-a4f0-57f04a9e9972): +2017-02-28 06:18:42,511 ebaysdk [DEBUG]:elapsed time=0:00:00.354254 +2017-02-28 06:18:42,511 ebaysdk [DEBUG]:status code=500 +2017-02-28 06:18:42,511 ebaysdk [DEBUG]:headers={'breadcrumbid': 'ID-slc4b03c-6483-stratus-slc-ebay-com-53764-1487075486325-0-1105919761', 'content-length': '25', 'accept-enco +ding': 'identity', 'x-ebay-api-request-encoding': 'XML', 'x-ebay-api-version': '799', 'user-agent': 'eBaySDK/2.1.4 Python/2.7.6 Linux/3.13.0-91-generic', 'connection': 'keep-a +live', 'x-ebay-sdk-request-id': '3ff5f071-04c3-40c0-a4f0-57f04a9e9972', 'x-ebay-api-site-id': '0', 'x-ebay-api-call-name': 'GetSingleItem', 'content-type': 'text/plain;charset +=utf-8', 'x-forwarded-for': '52.19.146.95', 'x-ebay-api-app-id': 'LogoGrab-logograb-PRD-42f530923-a70f22b2'} +2017-02-28 06:18:42,511 ebaysdk [DEBUG]:content=an internal error occured +2017-02-28 06:18:42,512 ebaysdk [DEBUG]:response parse failed: Start tag expected, '<' not found, line 1, column 1 +ERROR - 2017-02-28 06:18:42,512 - utils.firehose_util - MainProcess - MainThread: Shopping Call error: {"ItemID": "262809803926", "version": 981, "IncludeSelector": "Variation +s"} +Traceback (most recent call last): + File "/home/ubuntu/logograb2-detection-server/utils/firehose_util.py", line 235, in make_ebay_request + r = Shopping(appid=app_id, config_file=None, debug=True).execute('GetSingleItem', api_pars) + File "/usr/local/lib/python2.7/dist-packages/ebaysdk/connection.py", line 124, in execute + self.error_check() + File "/usr/local/lib/python2.7/dist-packages/ebaysdk/connection.py", line 209, in error_check + estr = self.error() + File "/usr/local/lib/python2.7/dist-packages/ebaysdk/connection.py", line 321, in error + error_array.extend(self._get_resp_body_errors()) + File "/usr/local/lib/python2.7/dist-packages/ebaysdk/shopping/__init__.py", line 188, in _get_resp_body_errors + dom = self.response.dom() + File "/usr/local/lib/python2.7/dist-packages/ebaysdk/response.py", line 233, in dom + return self._dom + File "/usr/local/lib/python2.7/dist-packages/ebaysdk/response.py", line 220, in __getattr__ + return getattr(self._obj, name) +AttributeError: 'Response' object has no attribute '_dom' +""" diff --git a/tests/test_request.py b/tests/test_request.py new file mode 100644 index 0000000..1f60954 --- /dev/null +++ b/tests/test_request.py @@ -0,0 +1,67 @@ +# -*- coding: utf-8 -*- + +''' +© 2012-2013 eBay Software Foundation +Authored by: Tim Keefer +Licensed under CDDL 1.0 +''' + +from __future__ import absolute_import +import os +import unittest +import re +from ebaysdk.utils import dict2xml + +os.environ.setdefault("EBAY_YAML", "ebay.yaml") + + +class TestBase(unittest.TestCase): + + def test_motors_compat_request_xml(self): + motors_dict = { + 'Item': { + 'Category': '101', + 'Title': 'My Title', + 'ItemCompatibilityList': { + 'Compatibility': [ + { + 'CompatibilityNotes': 'Fits for all trims and engines.', + 'NameValueList': [ + {'Name': 'Year', 'Value': '2001'}, + {'Name': 'Make', 'Value': 'Honda'}, + {'Name': 'Model', 'Value': 'Accord'} + ] + }, + ] + } + } + } + + motors_xml = """ + 101 + + + Fits for all trims and engines. + + Year2001 + + + MakeHonda + + + ModelAccord + + + + My Title + + """ + + motors_xml = re.sub(r'>\s+<', '><', motors_xml) + motors_xml = re.sub(r'\s+$', '', motors_xml) + + self.assertEqual(dict2xml(motors_dict), motors_xml) + + +if __name__ == '__main__': + unittest.main() diff --git a/tox.ini b/tox.ini index 0809def..406235c 100644 --- a/tox.ini +++ b/tox.ini @@ -2,10 +2,14 @@ envlist = py27,py36 [testenv] -commands = pep8 --ignore=E202,E501 ebaysdk - pylint -E ebaysdk +setenv = + EBAY_YAML = /etc/ebay.yaml + +commands = pycodestyle --ignore=E202,E501 ebaysdk + pylint -E ebaysdk + python setup.py test whitelist_externals = make -deps = pep8 +deps = pycodestyle pylint pytest