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/parallel.py b/ebaysdk/parallel.py index bee0923..e40c769 100644 --- a/ebaysdk/parallel.py +++ b/ebaysdk/parallel.py @@ -6,12 +6,12 @@ Licensed under CDDL 1.0 ''' import sys +from ebaysdk.exception import ConnectionError +import grequests + if sys.version_info[0] >= 3: raise ImportError('grequests does not work with python3+') -import grequests -from ebaysdk.exception import ConnectionError - class Parallel(object): """ diff --git a/ebaysdk/response.py b/ebaysdk/response.py index 79afa2b..b9432d5 100644 --- a/ebaysdk/response.py +++ b/ebaysdk/response.py @@ -45,10 +45,12 @@ def get(self, name, default=None): def _setattr(self, name, value, datetime_nodes): if name.lower() in datetime_nodes: + assert value.endswith('Z') try: - ts = "%s %s" % (value.partition( - 'T')[0], value.partition('T')[2].partition('.')[0]) - value = datetime.datetime.strptime(ts, '%Y-%m-%d %H:%M:%S') + value = datetime.datetime.strptime( + value.replace('Z', 'UTC'), + '%Y-%m-%dT%H:%M:%S.%f%Z' + ).replace(tzinfo=datetime.timezone.utc) except ValueError: pass 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/samples/trading.py b/samples/trading.py index 00bc85b..01e5826 100644 --- a/samples/trading.py +++ b/samples/trading.py @@ -189,6 +189,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: 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..d555f73 100644 --- a/tox.ini +++ b/tox.ini @@ -2,8 +2,12 @@ envlist = py27,py36 [testenv] +setenv = + EBAY_YAML = /etc/ebay.yaml + commands = pep8 --ignore=E202,E501 ebaysdk - pylint -E ebaysdk + pylint -E ebaysdk + python setup.py test whitelist_externals = make deps = pep8 pylint