Support Python 3 using six

This commit is contained in:
David Baumgold 2014-08-26 13:25:50 -04:00
commit eedb4c4b73
67 changed files with 455 additions and 255 deletions

View file

@ -34,8 +34,8 @@ class MockAWS(object):
HTTPretty.enable()
for method in HTTPretty.METHODS:
backend = self.backends.values()[0]
for key, value in backend.urls.iteritems():
backend = list(self.backends.values())[0]
for key, value in backend.urls.items():
HTTPretty.register_uri(
method=method,
uri=re.compile(key),
@ -72,7 +72,7 @@ class Model(type):
def __new__(self, clsname, bases, namespace):
cls = super(Model, self).__new__(self, clsname, bases, namespace)
cls.__models__ = {}
for name, value in namespace.iteritems():
for name, value in namespace.items():
model = getattr(value, "__returns_model__", False)
if model is not False:
cls.__models__[model] = name
@ -112,7 +112,7 @@ class BaseBackend(object):
urls = {}
for url_base in url_bases:
for url_path, handler in unformatted_paths.iteritems():
for url_path, handler in unformatted_paths.items():
url = url_path.format(url_base)
urls[url] = handler
@ -127,7 +127,7 @@ class BaseBackend(object):
unformatted_paths = self._url_module.url_paths
paths = {}
for unformatted_path, handler in unformatted_paths.iteritems():
for unformatted_path, handler in unformatted_paths.items():
path = unformatted_path.format("")
paths[path] = handler
@ -146,7 +146,7 @@ class BaseBackend(object):
The url paths that will be used for the flask server
"""
paths = {}
for url_path, handler in self.url_paths.iteritems():
for url_path, handler in self.url_paths.items():
url_path = convert_regex_to_flask_path(url_path)
paths[url_path] = handler

View file

@ -3,12 +3,44 @@ import datetime
import json
import re
from urlparse import parse_qs, urlparse
import six
from six.moves.urllib.parse import parse_qs, urlparse
from werkzeug.exceptions import HTTPException
from moto.core.utils import camelcase_to_underscores, method_names_from_class
def _decode_dict(d):
decoded = {}
for key, value in d.items():
if isinstance(key, six.binary_type):
newkey = key.decode("utf-8")
elif isinstance(key, (list, tuple)):
newkey = []
for k in key:
if isinstance(k, six.binary_type):
newkey.append(k.decode('utf-8'))
else:
newkey.append(k)
else:
newkey = key
if isinstance(value, six.binary_type):
newvalue = value.decode("utf-8")
elif isinstance(value, (list, tuple)):
newvalue = []
for v in value:
if isinstance(v, six.binary_type):
newvalue.append(v.decode('utf-8'))
else:
newvalue.append(v)
else:
newvalue = value
decoded[newkey] = newvalue
return decoded
class BaseResponse(object):
region = 'us-east-1'
@ -28,7 +60,7 @@ class BaseResponse(object):
self.body = request.data
querystring = {}
for key, value in request.form.iteritems():
for key, value in request.form.items():
querystring[key] = [value, ]
if not querystring:
@ -38,6 +70,8 @@ class BaseResponse(object):
if not querystring:
querystring.update(headers)
querystring = _decode_dict(querystring)
self.uri = full_url
self.path = urlparse(full_url).path
self.querystring = querystring
@ -61,7 +95,7 @@ class BaseResponse(object):
response = method()
except HTTPException as http_error:
response = http_error.description, dict(status=http_error.code)
if isinstance(response, basestring):
if isinstance(response, six.string_types):
return 200, headers, response
else:
body, new_headers = response

View file

@ -2,6 +2,7 @@ from __future__ import unicode_literals
import inspect
import random
import re
import six
from flask import request
@ -23,12 +24,20 @@ def camelcase_to_underscores(argument):
def method_names_from_class(clazz):
return [x[0] for x in inspect.getmembers(clazz, predicate=inspect.ismethod)]
# On Python 2, methods are different from functions, and the `inspect`
# predicates distinguish between them. On Python 3, methods are just
# regular functions, and `inspect.ismethod` doesn't work, so we have to
# use `inspect.isfunction` instead
if six.PY2:
predicate = inspect.ismethod
else:
predicate = inspect.isfunction
return [x[0] for x in inspect.getmembers(clazz, predicate=predicate)]
def get_random_hex(length=8):
chars = range(10) + ['a', 'b', 'c', 'd', 'e', 'f']
return ''.join(unicode(random.choice(chars)) for x in range(length))
chars = list(range(10)) + ['a', 'b', 'c', 'd', 'e', 'f']
return ''.join(six.text_type(random.choice(chars)) for x in range(length))
def get_random_message_id():
@ -59,7 +68,7 @@ class convert_flask_to_httpretty_response(object):
# For instance methods, use class and method names. Otherwise
# use module and method name
if inspect.ismethod(self.callback):
outer = self.callback.im_class.__name__
outer = self.callback.__self__.__class__.__name__
else:
outer = self.callback.__module__
return "{0}.{1}".format(outer, self.callback.__name__)