From e80ab966e042682fad3da1fcb9e4cd00957f9c38 Mon Sep 17 00:00:00 2001 From: Julian Sy Date: Fri, 10 Jun 2016 15:41:03 +0000 Subject: [PATCH] JSON schema get_schema implementation for common fields This implements the get_schema method of common Field and FieldType classes. This method will be used by the to_json_schema method in Versioned objects to partially generate the schema of the object's fields. Fields implemented in this patch: string, enum, integer, float, boolean, list This also fixes check for default value for Field. Implements blueprint json-schema-for-versioned-object Change-Id: Ibd84cb4e33c375044611c6ffa137ee67d21a93e5 --- oslo_versionedobjects/fields.py | 20 ++++++++- oslo_versionedobjects/tests/test_fields.py | 47 ++++++++++++++++++++++ 2 files changed, 66 insertions(+), 1 deletion(-) diff --git a/oslo_versionedobjects/fields.py b/oslo_versionedobjects/fields.py index 0d9d7ce1..8c904f81 100644 --- a/oslo_versionedobjects/fields.py +++ b/oslo_versionedobjects/fields.py @@ -246,7 +246,7 @@ class Field(object): if self.nullable: schema['type'].append('null') default = self.default - if not isinstance(default, UnspecifiedDefault): + if default != UnspecifiedDefault: schema.update({'default': default}) return schema @@ -268,6 +268,9 @@ class String(FieldType): def stringify(value): return '\'%s\'' % value + def get_schema(self): + return {'type': ['string']} + class SensitiveString(String): """A string field type that may contain sensitive (password) information. @@ -320,6 +323,9 @@ class Enum(String): raise ValueError(msg) return super(Enum, self).stringify(value) + def get_schema(self): + return {'enum': self._valid_values} + class UUID(FieldType): @staticmethod @@ -375,17 +381,26 @@ class Integer(FieldType): def coerce(obj, attr, value): return int(value) + def get_schema(self): + return {'type': ['integer']} + class Float(FieldType): def coerce(self, obj, attr, value): return float(value) + def get_schema(self): + return {'type': ['number']} + class Boolean(FieldType): @staticmethod def coerce(obj, attr, value): return bool(value) + def get_schema(self): + return {'type': ['boolean']} + class FlexibleBoolean(Boolean): @staticmethod @@ -520,6 +535,9 @@ class List(CompoundFieldType): return '[%s]' % ( ','.join([self._element_type.stringify(x) for x in value])) + def get_schema(self): + return {'type': ['array'], 'items': self._element_type.get_schema()} + class Dict(CompoundFieldType): def coerce(self, obj, attr, value): diff --git a/oslo_versionedobjects/tests/test_fields.py b/oslo_versionedobjects/tests/test_fields.py index d708ba3a..e9eed260 100644 --- a/oslo_versionedobjects/tests/test_fields.py +++ b/oslo_versionedobjects/tests/test_fields.py @@ -166,6 +166,13 @@ class TestString(TestField): def test_stringify(self): self.assertEqual("'123'", self.field.stringify(123)) + def test_fieldtype_get_schema(self): + self.assertEqual({'type': ['string']}, self.field._type.get_schema()) + + def test_get_schema(self): + self.assertEqual({'type': ['string'], 'readonly': False}, + self.field.get_schema()) + class TestSensitiveString(TestString): def setUp(self): @@ -318,6 +325,14 @@ class TestEnum(TestField): def test_stringify_invalid(self): self.assertRaises(ValueError, self.field.stringify, '123') + def test_fieldtype_get_schema(self): + self.assertEqual({'enum': ["foo", "bar", 1, True]}, + self.field._type.get_schema()) + + def test_get_schema(self): + self.assertEqual({'enum': ["foo", "bar", 1, True], + 'readonly': False}, self.field.get_schema()) + def test_fingerprint(self): # Notes(yjiang5): make sure changing valid_value will be detected # in test_objects.test_versions @@ -421,6 +436,13 @@ class TestInteger(TestField): self.to_primitive_values = self.coerce_good_values[0:1] self.from_primitive_values = self.coerce_good_values[0:1] + def test_fieldtype_get_schema(self): + self.assertEqual({'type': ['integer']}, self.field._type.get_schema()) + + def test_get_schema(self): + self.assertEqual({'type': ['integer'], 'readonly': False}, + self.field.get_schema()) + class TestFloat(TestField): def setUp(self): @@ -431,6 +453,13 @@ class TestFloat(TestField): self.to_primitive_values = self.coerce_good_values[0:1] self.from_primitive_values = self.coerce_good_values[0:1] + def test_fieldtype_get_schema(self): + self.assertEqual({'type': ['number']}, self.field._type.get_schema()) + + def test_get_schema(self): + self.assertEqual({'type': ['number'], 'readonly': False}, + self.field.get_schema()) + class TestBoolean(TestField): def setUp(self): @@ -442,6 +471,13 @@ class TestBoolean(TestField): self.to_primitive_values = self.coerce_good_values[0:2] self.from_primitive_values = self.coerce_good_values[0:2] + def test_fieldtype_get_schema(self): + self.assertEqual({'type': ['boolean']}, self.field._type.get_schema()) + + def test_get_schema(self): + self.assertEqual({'type': ['boolean'], 'readonly': False}, + self.field.get_schema()) + class TestFlexibleBoolean(TestField): def setUp(self): @@ -597,6 +633,17 @@ class TestList(TestField): def test_stringify(self): self.assertEqual('[123]', self.field.stringify([123])) + def test_fieldtype_get_schema(self): + self.assertEqual({'type': ['array'], + 'items': {'type': ['foo'], 'readonly': False}}, + self.field._type.get_schema()) + + def test_get_schema(self): + self.assertEqual({'type': ['array'], + 'items': {'type': ['foo'], 'readonly': False}, + 'readonly': False}, + self.field.get_schema()) + class TestListOfStrings(TestField): def setUp(self):