Add enum fieldtype field

In some case, one field should be limited to some value, like the
cpu architect field.

Make sure that when the value limitation is changed,
the fingerprint will be changed, so that a version bump should happen.

Ported (but changed for consistency) from:
I7848f8b934c169a76b1cfd875f7905273f9f914b

Co-Authored-By: yunhong jiang <yunhong.jiang@intel.com>
Co-Authored-By: Dan Smith <dansmith@redhat.com>
Change-Id: Iac498869d10d2238b3ddf704640cd152cb794099
This commit is contained in:
Davanum Srinivas
2015-03-28 22:16:27 -04:00
committed by Davanum Srinivas (dims)
parent 8f5ca42d51
commit 143c11d5a0
3 changed files with 130 additions and 1 deletions

View File

@@ -164,3 +164,11 @@ class ReadOnlyFieldError(VersionedObjectsException):
class UnsupportedObjectError(VersionedObjectsException):
msg_fmt = _('Unsupported object type %(objtype)s')
class EnumRequiresValidValuesError(VersionedObjectsException):
msg_fmt = _('Enum fields require a list of valid_values')
class EnumValidValuesInvalidError(VersionedObjectsException):
msg_fmt = _('Enum valid values are not valid')

View File

@@ -21,6 +21,7 @@ from oslo_utils import timeutils
import six
from oslo_versionedobjects._i18n import _
from oslo_versionedobjects import exception
class KeyTypeError(TypeError):
@@ -247,6 +248,32 @@ class String(FieldType):
return '\'%s\'' % value
class Enum(String):
def __init__(self, valid_values, **kwargs):
if not valid_values:
raise exception.EnumRequiresValidValuesError()
try:
# Test validity of the values
for value in valid_values:
super(Enum, self).coerce(None, 'init', value)
except (TypeError, ValueError):
raise exception.EnumValidValuesInvalidError()
self._valid_values = valid_values
super(Enum, self).__init__(**kwargs)
def coerce(self, obj, attr, value):
if value not in self._valid_values:
msg = _("Field value %s is invalid") % value
raise ValueError(msg)
return super(Enum, self).coerce(obj, attr, value)
def stringify(self, value):
if value not in self._valid_values:
msg = _("Field value %s is invalid") % value
raise ValueError(msg)
return super(Enum, self).stringify(value)
class UUID(FieldType):
@staticmethod
def coerce(obj, attr, value):
@@ -479,6 +506,23 @@ class StringField(AutoTypedField):
AUTO_TYPE = String()
class EnumField(AutoTypedField):
def __init__(self, valid_values, **kwargs):
self.AUTO_TYPE = Enum(valid_values)
super(EnumField, self).__init__(**kwargs)
def __repr__(self):
valid_values = self._type._valid_values
args = {
'nullable': self._nullable,
'default': self._default,
}
args.update({'valid_values': valid_values})
return '%s(%s)' % (self._type.__class__.__name__,
','.join(['%s=%s' % (k, v)
for k, v in sorted(args.items())]))
class UUIDField(AutoTypedField):
AUTO_TYPE = UUID()
@@ -517,6 +561,23 @@ class ListOfStringsField(AutoTypedField):
AUTO_TYPE = List(String())
class ListOfEnumField(AutoTypedField):
def __init__(self, valid_values, **kwargs):
self.AUTO_TYPE = List(Enum(valid_values))
super(ListOfEnumField, self).__init__(**kwargs)
def __repr__(self):
valid_values = self._type._element_type._type._valid_values
args = {
'nullable': self._nullable,
'default': self._default,
}
args.update({'valid_values': valid_values})
return '%s(%s)' % (self._type.__class__.__name__,
','.join(['%s=%s' % (k, v)
for k, v in sorted(args.items())]))
class SetOfIntegersField(AutoTypedField):
AUTO_TYPE = Set(Integer())

View File

@@ -19,6 +19,7 @@ from oslo_utils import timeutils
import six
from oslo_versionedobjects import base as obj_base
from oslo_versionedobjects import exception
from oslo_versionedobjects import fields
from oslo_versionedobjects import test
@@ -71,7 +72,7 @@ class TestField(test.TestCase):
class TestString(TestField):
def setUp(self):
super(TestField, self).setUp()
super(TestString, self).setUp()
self.field = fields.StringField()
self.coerce_good_values = [
('foo', 'foo'), (1, '1'), (1.0, '1.0'), (True, 'True')]
@@ -85,6 +86,42 @@ class TestString(TestField):
self.assertEqual("'123'", self.field.stringify(123))
class TestEnum(TestField):
def setUp(self):
super(TestEnum, self).setUp()
self.field = fields.EnumField(
valid_values=['foo', 'bar', 1, True])
self.coerce_good_values = [('foo', 'foo'), (1, '1'), (True, 'True')]
self.coerce_bad_values = ['boo', 2, False]
self.to_primitive_values = self.coerce_good_values[0:1]
self.from_primitive_values = self.coerce_good_values[0:1]
def test_stringify(self):
self.assertEqual("'foo'", self.field.stringify('foo'))
def test_stringify_invalid(self):
self.assertRaises(ValueError, self.field.stringify, '123')
def test_fingerprint(self):
# Notes(yjiang5): make sure changing valid_value will be detected
# in test_objects.test_versions
field1 = fields.EnumField(valid_values=['foo', 'bar'])
field2 = fields.EnumField(valid_values=['foo', 'bar1'])
self.assertNotEqual(str(field1), str(field2))
def test_missing_valid_values(self):
self.assertRaises(exception.EnumRequiresValidValuesError,
fields.EnumField, None)
def test_empty_valid_values(self):
self.assertRaises(exception.EnumRequiresValidValuesError,
fields.EnumField, [])
def test_non_iterable_valid_values(self):
self.assertRaises(exception.EnumValidValuesInvalidError,
fields.EnumField, True)
class TestInteger(TestField):
def setUp(self):
super(TestField, self).setUp()
@@ -267,6 +304,29 @@ class TestListOfStrings(TestField):
self.assertEqual("['abc']", self.field.stringify(['abc']))
class TestListOfEnum(TestField):
def setUp(self):
super(TestListOfEnum, self).setUp()
self.field = fields.ListOfEnumField(valid_values=['foo', 'bar'])
self.coerce_good_values = [(['foo', 'bar'], ['foo', 'bar'])]
self.coerce_bad_values = ['foo', ['foo', 'bar1']]
self.to_primitive_values = [(['foo'], ['foo'])]
self.from_primitive_values = [(['foo'], ['foo'])]
def test_stringify(self):
self.assertEqual("['foo']", self.field.stringify(['foo']))
def test_stringify_invalid(self):
self.assertRaises(ValueError, self.field.stringify, '[abc]')
def test_fingerprint(self):
# Notes(yjiang5): make sure changing valid_value will be detected
# in test_objects.test_versions
field1 = fields.ListOfEnumField(valid_values=['foo', 'bar'])
field2 = fields.ListOfEnumField(valid_values=['foo', 'bar1'])
self.assertNotEqual(str(field1), str(field2))
class TestSet(TestField):
def setUp(self):
super(TestSet, self).setUp()