Compatibility with Python 3
Make the tests run under Python 3.4. Tests now work with random hash seed. Change-Id: I5f9f57e0bef2c015ab2ff4b5732ccdade5d3bfbe Closes-Bug: 1417279 Closes-Bug: 1417285
This commit is contained in:
parent
c330f938c8
commit
1b8336fbe8
@ -59,7 +59,7 @@ def make_class_properties(cls):
|
||||
for name, field in supercls.fields.items():
|
||||
if name not in cls.fields:
|
||||
cls.fields[name] = field
|
||||
for name, field in cls.fields.iteritems():
|
||||
for name, field in six.iteritems(cls.fields):
|
||||
if not isinstance(field, fields.Field):
|
||||
raise exception.ObjectFieldInvalid(
|
||||
field=name, objname=cls.obj_name())
|
||||
@ -558,7 +558,7 @@ class VersionedObject(object):
|
||||
|
||||
@property
|
||||
def obj_fields(self):
|
||||
return self.fields.keys() + self.obj_extra_fields
|
||||
return list(self.fields.keys()) + self.obj_extra_fields
|
||||
|
||||
|
||||
class VersionedObjectDictCompat(object):
|
||||
@ -721,8 +721,8 @@ class ObjectListBase(object):
|
||||
"""List index of value."""
|
||||
return self.objects.index(value)
|
||||
|
||||
def sort(self, cmp=None, key=None, reverse=False):
|
||||
self.objects.sort(cmp=cmp, key=key, reverse=reverse)
|
||||
def sort(self, key=None, reverse=False):
|
||||
self.objects.sort(key=key, reverse=reverse)
|
||||
|
||||
def obj_make_compatible(self, primitive, target_version):
|
||||
primitives = primitive['objects']
|
||||
|
@ -28,6 +28,7 @@ import sys
|
||||
|
||||
from oslo_config import cfg
|
||||
from oslo_utils import excutils
|
||||
import six
|
||||
import webob.exc
|
||||
|
||||
from oslo_versionedobjects._i18n import _, _LE
|
||||
@ -126,7 +127,7 @@ class VersionedObjectsException(Exception):
|
||||
LOG.error("%s: %s" % (name, value)) # noqa
|
||||
|
||||
if CONF.fatal_exception_format_errors:
|
||||
raise exc_info[0], exc_info[1], exc_info[2]
|
||||
raise six.reraise(*exc_info)
|
||||
else:
|
||||
# at least get the core message out if something happened
|
||||
message = self.msg_fmt
|
||||
|
@ -132,13 +132,8 @@ class Field(object):
|
||||
self._read_only = read_only
|
||||
|
||||
def __repr__(self):
|
||||
args = {
|
||||
'nullable': self._nullable,
|
||||
'default': self._default,
|
||||
}
|
||||
return '%s(%s)' % (self._type.__class__.__name__,
|
||||
','.join(['%s=%s' % (k, v)
|
||||
for k, v in args.items()]))
|
||||
return '%s(default=%s,nullable=%s)' % (self._type.__class__.__name__,
|
||||
self._default, self._nullable)
|
||||
|
||||
@property
|
||||
def nullable(self):
|
||||
@ -238,9 +233,10 @@ class String(FieldType):
|
||||
@staticmethod
|
||||
def coerce(obj, attr, value):
|
||||
# FIXME(danms): We should really try to avoid the need to do this
|
||||
if isinstance(value, (six.string_types, int, long, float,
|
||||
datetime.datetime)):
|
||||
return unicode(value)
|
||||
accepted_types = six.integer_types + (float, six.string_types,
|
||||
datetime.datetime)
|
||||
if isinstance(value, accepted_types):
|
||||
return six.text_type(value)
|
||||
else:
|
||||
raise ValueError(_('A string is required here, not %s') %
|
||||
value.__class__.__name__)
|
||||
|
@ -16,6 +16,7 @@ import datetime
|
||||
|
||||
import iso8601
|
||||
from oslo_utils import timeutils
|
||||
import six
|
||||
|
||||
from oslo_versionedobjects import base as obj_base
|
||||
from oslo_versionedobjects import fields
|
||||
@ -72,8 +73,10 @@ class TestString(TestField):
|
||||
def setUp(self):
|
||||
super(TestField, self).setUp()
|
||||
self.field = fields.StringField()
|
||||
self.coerce_good_values = [('foo', 'foo'), (1, '1'), (1L, '1'),
|
||||
(True, 'True')]
|
||||
self.coerce_good_values = [
|
||||
('foo', 'foo'), (1, '1'), (1.0, '1.0'), (True, 'True')]
|
||||
if six.PY2:
|
||||
self.coerce_good_values += [(long(1), '1')]
|
||||
self.coerce_bad_values = [None]
|
||||
self.to_primitive_values = self.coerce_good_values[0:1]
|
||||
self.from_primitive_values = self.coerce_good_values[0:1]
|
||||
|
@ -20,6 +20,7 @@ import inspect
|
||||
import logging
|
||||
import os
|
||||
import pprint
|
||||
import six
|
||||
|
||||
import mock
|
||||
from oslo_context import context
|
||||
@ -569,14 +570,13 @@ class _TestObject(object):
|
||||
'foo', '1.0')
|
||||
|
||||
def test_obj_class_from_name_supported_version(self):
|
||||
error = None
|
||||
self.assertRaises(exception.IncompatibleObjectVersion,
|
||||
base.VersionedObject.obj_class_from_name,
|
||||
'MyObj', '1.25')
|
||||
try:
|
||||
base.VersionedObject.obj_class_from_name('MyObj', '1.25')
|
||||
except exception.IncompatibleObjectVersion as error:
|
||||
pass
|
||||
|
||||
self.assertIsNotNone(error)
|
||||
self.assertEqual('1.6', error.kwargs['supported'])
|
||||
self.assertEqual('1.6', error.kwargs['supported'])
|
||||
|
||||
def test_orphaned_object(self):
|
||||
obj = MyObj.query(self.context)
|
||||
@ -665,7 +665,7 @@ class _TestObject(object):
|
||||
'versioned_object.namespace': 'versionedobjects',
|
||||
'versioned_object.version': '1.6',
|
||||
'versioned_object.changes': [
|
||||
'deleted', 'created_at', 'deleted_at', 'updated_at',
|
||||
'created_at', 'deleted', 'deleted_at', 'updated_at',
|
||||
],
|
||||
'versioned_object.data': {
|
||||
'created_at': timeutils.isotime(dt),
|
||||
@ -674,7 +674,10 @@ class _TestObject(object):
|
||||
'deleted': False,
|
||||
},
|
||||
}
|
||||
self.assertEqual(obj.obj_to_primitive(), expected)
|
||||
|
||||
got = obj.obj_to_primitive()
|
||||
got['versioned_object.changes'].sort()
|
||||
self.assertEqual(got, expected)
|
||||
|
||||
def test_contains(self):
|
||||
obj = MyObj()
|
||||
@ -707,7 +710,7 @@ class _TestObject(object):
|
||||
self.assertRaises(AttributeError, obj.get, 'nothing', 3)
|
||||
|
||||
def test_object_inheritance(self):
|
||||
base_fields = base.VersionedPersistentObject.fields.keys()
|
||||
base_fields = list(base.VersionedPersistentObject.fields.keys())
|
||||
myobj_fields = (['foo', 'bar', 'missing',
|
||||
'readonly', 'rel_object', 'rel_objects'] +
|
||||
base_fields)
|
||||
@ -1119,11 +1122,11 @@ class TestObjectSerializer(_BaseTestCase):
|
||||
thing = {'key': obj}
|
||||
primitive = ser.serialize_entity(self.context, thing)
|
||||
self.assertEqual(1, len(primitive))
|
||||
for item in primitive.itervalues():
|
||||
for item in six.itervalues(primitive):
|
||||
self.assertNotIsInstance(item, base.VersionedObject)
|
||||
thing2 = ser.deserialize_entity(self.context, primitive)
|
||||
self.assertEqual(1, len(thing2))
|
||||
for item in thing2.itervalues():
|
||||
for item in six.itervalues(thing2):
|
||||
self.assertIsInstance(item, MyObj)
|
||||
|
||||
# object-action updates dict case
|
||||
@ -1172,7 +1175,8 @@ class TestObjectVersions(test.TestCase):
|
||||
"""Follow a chain of remotable things down to the original function."""
|
||||
if isinstance(thing, classmethod):
|
||||
return self._find_remotable_method(cls, thing.__get__(None, cls))
|
||||
elif inspect.ismethod(thing) and hasattr(thing, 'remotable'):
|
||||
elif (inspect.ismethod(thing)
|
||||
or inspect.isfunction(thing)) and hasattr(thing, 'remotable'):
|
||||
return self._find_remotable_method(cls, thing.original_fn,
|
||||
parent_was_remotable=True)
|
||||
elif parent_was_remotable:
|
||||
@ -1185,12 +1189,13 @@ class TestObjectVersions(test.TestCase):
|
||||
|
||||
def _get_fingerprint(self, obj_name):
|
||||
obj_class = base.VersionedObjectRegistry.obj_classes()[obj_name][0]
|
||||
fields = obj_class.fields.items()
|
||||
fields = list(obj_class.fields.items())
|
||||
fields.sort()
|
||||
methods = []
|
||||
for name in dir(obj_class):
|
||||
thing = getattr(obj_class, name)
|
||||
if inspect.ismethod(thing) or isinstance(thing, classmethod):
|
||||
if inspect.ismethod(thing) or inspect.isfunction(thing) \
|
||||
or isinstance(thing, classmethod):
|
||||
method = self._find_remotable_method(obj_class, thing)
|
||||
if method:
|
||||
methods.append((name, inspect.getargspec(method)))
|
||||
@ -1204,13 +1209,13 @@ class TestObjectVersions(test.TestCase):
|
||||
relevant_data = (fields, methods, obj_class.child_versions)
|
||||
else:
|
||||
relevant_data = (fields, methods)
|
||||
fingerprint = '%s-%s' % (obj_class.VERSION,
|
||||
hashlib.md5(str(relevant_data)).hexdigest())
|
||||
fingerprint = '%s-%s' % (obj_class.VERSION, hashlib.md5(
|
||||
six.binary_type(repr(relevant_data).encode())).hexdigest())
|
||||
return fingerprint
|
||||
|
||||
def test_versions(self):
|
||||
fingerprints = {}
|
||||
for obj_name in base.VersionedObjectRegistry.obj_classes():
|
||||
for obj_name in sorted(base.VersionedObjectRegistry.obj_classes()):
|
||||
obj_classes = base.VersionedObjectRegistry._registry._obj_classes
|
||||
obj_cls = obj_classes[obj_name][0]
|
||||
if is_test_object(obj_cls):
|
||||
@ -1218,8 +1223,8 @@ class TestObjectVersions(test.TestCase):
|
||||
fingerprints[obj_name] = self._get_fingerprint(obj_name)
|
||||
|
||||
if os.getenv('GENERATE_HASHES'):
|
||||
file('object_hashes.txt', 'w').write(
|
||||
pprint.pformat(fingerprints))
|
||||
with open('object_hashes.txt', 'w') as fp:
|
||||
fp.write(pprint.pformat(fingerprints))
|
||||
raise test.TestingException(
|
||||
'Generated hashes in object_hashes.txt')
|
||||
|
||||
|
@ -17,6 +17,7 @@
|
||||
|
||||
"""Utilities and helper functions."""
|
||||
|
||||
import functools
|
||||
import logging
|
||||
|
||||
import six
|
||||
@ -32,7 +33,7 @@ def convert_version_to_int(version):
|
||||
if isinstance(version, six.string_types):
|
||||
version = convert_version_to_tuple(version)
|
||||
if isinstance(version, tuple):
|
||||
return reduce(lambda x, y: (x * 1000) + y, version)
|
||||
return functools.reduce(lambda x, y: (x * 1000) + y, version)
|
||||
except Exception:
|
||||
msg = _("Hypervisor version %s is invalid.") % version
|
||||
raise exception.VersionedObjectsException(msg)
|
||||
@ -44,9 +45,9 @@ def convert_version_to_str(version_int):
|
||||
while version_int != 0:
|
||||
version_number = version_int - (version_int // factor * factor)
|
||||
version_numbers.insert(0, str(version_number))
|
||||
version_int = version_int / factor
|
||||
version_int = version_int // factor
|
||||
|
||||
return reduce(lambda x, y: "%s.%s" % (x, y), version_numbers)
|
||||
return '.'.join(map(str, version_numbers))
|
||||
|
||||
|
||||
def convert_version_to_tuple(version_str):
|
||||
|
12
requirements-py3.txt
Normal file
12
requirements-py3.txt
Normal file
@ -0,0 +1,12 @@
|
||||
eventlet>=0.16.1
|
||||
six>=1.7.0
|
||||
Babel>=1.3
|
||||
netaddr>=0.7.12
|
||||
oslo.concurrency>=1.4.1 # Apache-2.0
|
||||
oslo.context>=0.1.0 # Apache-2.0
|
||||
oslo.messaging>=1.4.0,!=1.5.0
|
||||
oslo.serialization>=1.2.0 # Apache-2.0
|
||||
oslo.utils>=1.2.0 # Apache-2.0
|
||||
iso8601>=0.1.9
|
||||
oslo.log>=0.1.0
|
||||
oslo.i18n>=1.3.0 # Apache-2.0
|
5
tox.ini
5
tox.ini
@ -14,7 +14,6 @@ install_command = pip install -U {opts} {packages}
|
||||
# fails with a random hash seed, so set PYTHONHASHSEED.
|
||||
setenv =
|
||||
VIRTUAL_ENV={envdir}
|
||||
PYTHONHASHSEED=0
|
||||
deps = -r{toxinidir}/requirements.txt
|
||||
-r{toxinidir}/test-requirements.txt
|
||||
commands = python setup.py testr --slowest --testr-args='{posargs}'
|
||||
@ -22,6 +21,10 @@ commands = python setup.py testr --slowest --testr-args='{posargs}'
|
||||
[testenv:pep8]
|
||||
commands = flake8
|
||||
|
||||
[testenv:py34]
|
||||
deps = -r{toxinidir}/requirements-py3.txt
|
||||
-r{toxinidir}/test-requirements.txt
|
||||
|
||||
[testenv:venv]
|
||||
commands = {posargs}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user