diff --git a/mws/__init__.py b/mws/__init__.py index 51d1c912..2f0b5710 100644 --- a/mws/__init__.py +++ b/mws/__init__.py @@ -1,4 +1,4 @@ # -*- coding: utf-8 -*- -__version__ = '0.6' +from __future__ import absolute_import -from mws import * \ No newline at end of file +from .mws import * diff --git a/mws/mws.py b/mws/mws.py index 2eaacb9e..5a6a975a 100644 --- a/mws/mws.py +++ b/mws/mws.py @@ -1,24 +1,25 @@ -#!/usr/bin/env python # -*- coding: utf-8 -*- -# -# Basic interface to Amazon MWS -# Based on http://code.google.com/p/amazon-mws-python -# +from __future__ import absolute_import -import urllib +import base64 import hashlib import hmac -import base64 -import utils import re +from time import gmtime, strftime + +from requests import request +from requests.exceptions import HTTPError + +from . import utils + +try: + from urllib.parse import quote +except ImportError: + from urllib import quote try: from xml.etree.ElementTree import ParseError as XMLError except ImportError: from xml.parsers.expat import ExpatError as XMLError -from time import strftime, gmtime - -from requests import request -from requests.exceptions import HTTPError __all__ = [ @@ -64,15 +65,19 @@ def calc_md5(string): """ md = hashlib.md5() md.update(string) - return base64.encodestring(md.digest()).strip('\n') + return base64.encodebytes(md.digest()).strip('\n') def remove_empty(d): + """Helper function that removes all keys from a dictionary (d), that have an empty value. + + Args: + d (dict) + + Return: + dict """ - Helper function that removes all keys from a dictionary (d), - that have an empty value. - """ - for key in d.keys(): + for key in set(d.keys()): if not d[key]: del d[key] return d @@ -88,7 +93,7 @@ def __init__(self, xml, rootkey=None): self.original = xml self._rootkey = rootkey self._mydict = utils.xml2dict().fromstring(remove_namespace(xml)) - self._response_dict = self._mydict.get(self._mydict.keys()[0], + self._response_dict = self._mydict.get(list(self._mydict.keys())[0], self._mydict) @property @@ -180,9 +185,9 @@ def make_request(self, extra_data, method="GET", **kwargs): if self.auth_token: params['MWSAuthToken'] = self.auth_token params.update(extra_data) - request_description = '&'.join(['%s=%s' % (k, urllib.quote(params[k], safe='-_.~').encode('utf-8')) for k in sorted(params)]) + request_description = '&'.join(['%s=%s' % (k, quote(params[k], safe='-_.~')) for k in sorted(params)]) signature = self.calc_signature(method, request_description) - url = '%s%s?%s&Signature=%s' % (self.domain, self.uri, request_description, urllib.quote(signature)) + url = '%s%s?%s&Signature=%s' % (self.domain, self.uri, request_description, quote(signature)) headers = {'User-Agent': 'python-amazon-mws/0.0.1 (Language=Python)'} headers.update(kwargs.get('extra_headers', {})) @@ -196,16 +201,18 @@ def make_request(self, extra_data, method="GET", **kwargs): # When retrieving data from the response object, # be aware that response.content returns the content in bytes while response.text calls # response.content and converts it to unicode. - data = response.content + data = response.content # I do not check the headers to decide which content structure to server simply because sometimes # Amazon's MWS API returns XML error responses with "text/plain" as the Content-Type. try: parsed_response = DictWrapper(data, extra_data.get("Action") + "Result") + except TypeError: # raised when using Python 3 and trying to remove_namespace() + parsed_response = DictWrapper(response.text, extra_data.get("Action") + "Result") except XMLError: parsed_response = DataWrapper(data, response.headers) - except HTTPError, e: + except HTTPError as e: error = MWSError(str(e.response.text)) error.response = e.response raise error @@ -224,9 +231,18 @@ def get_service_status(self): def calc_signature(self, method, request_description): """Calculate MWS signature to interface with Amazon + + Args: + method (str) + request_description (str) """ - sig_data = method + '\n' + self.domain.replace('https://', '').lower() + '\n' + self.uri + '\n' + request_description - return base64.b64encode(hmac.new(str(self.secret_key), sig_data, hashlib.sha256).digest()) + sig_data = '\n'.join([ + method, + self.domain.replace('https://', '').lower(), + self.uri, + request_description + ]) + return base64.b64encode(hmac.new(self.secret_key.encode(), sig_data.encode(), hashlib.sha256).digest()) def get_timestamp(self): """ diff --git a/mws/offamazonpayments.py b/mws/offamazonpayments.py index a6b7c7c8..ec146d1c 100644 --- a/mws/offamazonpayments.py +++ b/mws/offamazonpayments.py @@ -1,3 +1,6 @@ +# -*- coding: utf-8 -*- +from __future__ import absolute_import + from .mws import MWS @@ -171,4 +174,3 @@ def close_order_reference(self, order_ref): AmazonOrderReferenceId=order_ref ) ) - diff --git a/mws/utils.py b/mws/utils.py index 8d31c258..dd91af10 100644 --- a/mws/utils.py +++ b/mws/utils.py @@ -6,9 +6,10 @@ @author: pierre """ +from __future__ import absolute_import -import xml.etree.ElementTree as ET import re +import xml.etree.ElementTree as ET class object_dict(dict): diff --git a/setup.py b/setup.py index 16cb9a00..2106699b 100644 --- a/setup.py +++ b/setup.py @@ -25,8 +25,11 @@ 'Topic :: Software Development', 'Topic :: Software Development :: Libraries :: Application Frameworks', 'Programming Language :: Python :: 2', - 'Programming Language :: Python :: 2.6', 'Programming Language :: Python :: 2.7', + 'Programming Language :: Python :: 3', + 'Programming Language :: Python :: 3.3', + 'Programming Language :: Python :: 3.4', + 'Programming Language :: Python :: 3.5', ], platforms=['OS Independent'], license='Unlicense',