diff options
author | Julian Berman <Julian+git@GrayVines.com> | 2011-12-30 14:03:01 -0500 |
---|---|---|
committer | Julian Berman <Julian+git@GrayVines.com> | 2011-12-30 14:03:01 -0500 |
commit | 5d68fa84ee198942100579707b9929436475681d (patch) | |
tree | 660415490e9e63f5d0a4e2c46efd250995704412 | |
parent | b18bb96b9bd74a1e52c607bd4ae6dcf924e7caf1 (diff) | |
download | jsonschema-5d68fa84ee198942100579707b9929436475681d.tar.gz |
Py2.5+ Support.
-rw-r--r-- | jsonschema.py | 93 | ||||
-rw-r--r-- | tests.py | 156 |
2 files changed, 144 insertions, 105 deletions
diff --git a/jsonschema.py b/jsonschema.py index 30bde35..980ec63 100644 --- a/jsonschema.py +++ b/jsonschema.py @@ -1,17 +1,31 @@ -from __future__ import division, unicode_literals +from __future__ import division, with_statement -import numbers +import operator import re +import sys import types +# 2.5 support +try: + next +except NameError: + _none = object() + def next(iterator, default=_none): + try: + return iterator.next() + except StopIteration: + if default is not _none: + return default + raise + _PYTYPES = { - "array" : list, "boolean" : bool, "integer" : int, - "null" : types.NoneType, "number" : numbers.Number, - "object" : dict, "string" : basestring + u"array" : list, u"boolean" : bool, u"integer" : int, + u"null" : types.NoneType, u"number" : (int, float), + u"object" : dict, u"string" : basestring, } -_PYTYPES["any"] = tuple(_PYTYPES.values()) +_PYTYPES[u"any"] = tuple(_PYTYPES.values()) class SchemaError(Exception): @@ -26,9 +40,9 @@ class Validator(object): # required and dependencies are handled in validate_properties # exclusive Minium and Maximum are handled in validate_minimum - SKIPPED = { - "dependencies", "required", "exclusiveMinimum", "exclusiveMaximum" - } + SKIPPED = set([ + u"dependencies", u"required", u"exclusiveMinimum", u"exclusiveMaximum" + ]) def _error(self, msg): raise ValidationError(msg) @@ -45,10 +59,12 @@ class Validator(object): if k in self.SKIPPED: continue - validator = getattr(self, "validate_%s" % (k,), None) + validator = getattr(self, u"validate_%s" % (k,), None) if validator is None: - raise SchemaError("'%s' is not a known schema property" % (k,)) + raise SchemaError( + u"'%s' is not a known schema property" % (k,) + ) validator(v, instance, schema) @@ -67,7 +83,7 @@ class Validator(object): type = _PYTYPES.get(type) if type is None: - raise SchemaError("'%s' is not a known type" % (type,)) + raise SchemaError(u"'%s' is not a known type" % (type,)) # isinstance(a_bool, int) will make us even sadder here, so # let's be even dirtier than we would otherwise be. @@ -75,16 +91,16 @@ class Validator(object): elif ( isinstance(instance, type) and (not isinstance(instance, bool) or - type is bool or types == ["any"]) + type is bool or types == [u"any"]) ): return else: - self._error("'%s' is not of type %s" % (instance, types)) + self._error(u"'%s' is not of type %s" % (instance, types)) def validate_properties(self, properties, instance, schema): for property, subschema in properties.iteritems(): if property in instance: - dependencies = _(subschema.get("dependencies", [])) + dependencies = _(subschema.get(u"dependencies", [])) if isinstance(dependencies, dict): self.validate(instance, dependencies) else: @@ -92,12 +108,12 @@ class Validator(object): first = next(missing, None) if first is not None: self._error( - "'%s' is a dependency of '%s'" % (first, property) + u"'%s' is a dependency of '%s'" % (first, property) ) self.validate(instance[property], subschema) - elif subschema.get("required", False): - self._error("'%s' is a required property" % (property,)) + elif subschema.get(u"required", False): + self._error(u"'%s' is a required property" % (property,)) def validate_patternProperties(self, patternProperties, instance, schema): for pattern, subschema in patternProperties.iteritems(): @@ -106,13 +122,14 @@ class Validator(object): self.validate(v, subschema) def validate_additionalProperties(self, aP, instance, schema): - extras = instance.viewkeys() - schema.get("properties", {}).viewkeys() + # no viewkeys in <2.7, and pypy seems to fail on vk - vk anyhow, so... + extras = set(instance) - set(schema.get(u"properties", {})) if isinstance(aP, dict): for extra in extras: self.validate(instance[extra], aP) elif not aP and extras: - self._error("Additional properties are not allowed") + self._error(u"Additional properties are not allowed") def validate_items(self, items, instance, schema): if isinstance(items, dict): @@ -127,53 +144,57 @@ class Validator(object): for item in instance[len(schema):]: self.validate(item, aI) elif not aI and len(instance) > len(schema): - self._error("Additional items are not allowed") + self._error(u"Additional items are not allowed") def validate_minimum(self, minimum, instance, schema): - if schema.get("exclusiveMinimum", False): + if schema.get(u"exclusiveMinimum", False): failed = instance <= minimum - cmp = "less than or equal to" + cmp = u"less than or equal to" else: failed = instance < minimum - cmp = "less than" + cmp = u"less than" if failed: - self._error("%s is %s the minimum (%s)" % (instance, cmp, minimum)) + self._error( + u"%s is %s the minimum of %s" % (instance, cmp, minimum) + ) def validate_maximum(self, maximum, instance, schema): - if schema.get("exclusiveMaximum", False): + if schema.get(u"exclusiveMaximum", False): failed = instance >= maximum - cmp = "greater than or equal to" + cmp = u"greater than or equal to" else: failed = instance > maximum - cmp = "greater than" + cmp = u"greater than" if failed: - self._error("%s is %s the maximum (%s)" % (instance, cmp, maximum)) + self._error( + u"%s is %s the maximum of %s" % (instance, cmp, maximum) + ) def validate_minItems(self, mI, instance, schema): if len(instance) < mI: - self._error("'%s' is too short" % (instance,)) + self._error(u"'%s' is too short" % (instance,)) def validate_maxItems(self, mI, instance, schema): if len(instance) > mI: - self._error("'%s' is too long" % (instance,)) + self._error(u"'%s' is too long" % (instance,)) def validate_pattern(self, pattern, instance, schema): if not re.match(pattern, instance): - self._error("'%s' does not match '%s'" % (instance, pattern)) + self._error(u"'%s' does not match '%s'" % (instance, pattern)) def validate_minLength(self, mL, instance, schema): if len(instance) < mL: - self._error("'%s' is too short" % (instance,)) + self._error(u"'%s' is too short" % (instance,)) def validate_maxLength(self, mL, instance, schema): if len(instance) > mL: - self._error("'%s' is too long" % (instance,)) + self._error(u"'%s' is too long" % (instance,)) def validate_enum(self, enums, instance, schema): if instance not in enums: - self._error("'%s' is not one of %s" % (instance, enums)) + self._error(u"'%s' is not one of %s" % (instance, enums)) def validate_divisibleBy(self, dB, instance, schema): if isinstance(dB, float): @@ -182,7 +203,7 @@ class Validator(object): failed = instance % dB if failed: - self._error("%s is not divisible by %s" % (instance, dB)) + self._error(u"%s is not divisible by %s" % (instance, dB)) def _(thing): @@ -1,6 +1,11 @@ -from __future__ import unicode_literals +from __future__ import with_statement -import unittest +import sys + +if (sys.version_info[0], sys.version_info[1]) < (2, 7): + import unittest2 as unittest +else: + import unittest from jsonschema import ValidationError, validate @@ -18,85 +23,87 @@ class TestValidate(unittest.TestCase): self.validate_test(valids=valids, invalids=invalids, type=type) def test_type_integer(self): - self.type_test("integer", [1], [1.1, "foo", {}, [], True, None]) + self.type_test(u"integer", [1], [1.1, u"foo", {}, [], True, None]) def test_type_number(self): - self.type_test("number", [1, 1.1], ["foo", {}, [], True, None]) + self.type_test(u"number", [1, 1.1], [u"foo", {}, [], True, None]) def test_type_string(self): - self.type_test("string", ["foo", b"foo"], [1, 1.1, {}, [], True, None]) + self.type_test( + u"string", [u"foo", "foo"], [1, 1.1, {}, [], True, None] + ) def test_type_object(self): - self.type_test("object", [{}], [1, 1.1, "foo", [], True, None]) + self.type_test(u"object", [{}], [1, 1.1, u"foo", [], True, None]) def test_type_array(self): - self.type_test("array", [[]], [1, 1.1, "foo", {}, True, None]) + self.type_test(u"array", [[]], [1, 1.1, u"foo", {}, True, None]) def test_type_boolean(self): self.type_test( - "boolean", [True, False], [1, 1.1, "foo", {}, [], None] + u"boolean", [True, False], [1, 1.1, u"foo", {}, [], None] ) def test_type_null(self): - self.type_test("null", [None], [1, 1.1, "foo", {}, [], True]) + self.type_test(u"null", [None], [1, 1.1, u"foo", {}, [], True]) def test_type_any(self): - self.type_test("any", [1, 1.1, "foo", {}, [], True, None], []) + self.type_test(u"any", [1, 1.1, u"foo", {}, [], True, None], []) def test_multiple_types(self): self.type_test( - ["integer", "string"], [1, "foo"], [1.1, {}, [], True, None] + [u"integer", u"string"], [1, u"foo"], [1.1, {}, [], True, None] ) def test_multiple_types_subschema(self): self.type_test( - ["array", {"type" : "object"}], - [[1, 2], {"foo" : "bar"}], + [u"array", {u"type" : u"object"}], + [[1, 2], {u"foo" : u"bar"}], [1.1, True, None] ) self.type_test( - ["integer", {"properties" : {"foo" : {"type" : "null"}}}], - [1, {"foo" : None}], - [{"foo" : 1}, {"foo" : 1.1}], + [u"integer", {u"properties" : {u"foo" : {u"type" : u"null"}}}], + [1, {u"foo" : None}], + [{u"foo" : 1}, {u"foo" : 1.1}], ) def test_properties(self): schema = { "properties" : { - "foo" : {"type" : "number"}, - "bar" : {"type" : "string"}, + u"foo" : {u"type" : u"number"}, + u"bar" : {u"type" : u"string"}, } } valids = [ - {"foo" : 1, "bar" : "baz"}, - {"foo" : 1, "bar" : "baz", "quux" : 42}, + {u"foo" : 1, u"bar" : u"baz"}, + {u"foo" : 1, u"bar" : u"baz", u"quux" : 42}, ] - self.validate_test(valids, [{"foo" : 1, "bar" : []}], **schema) + self.validate_test(valids, [{u"foo" : 1, u"bar" : []}], **schema) def test_patternProperties(self): self.validate_test( - [{"foo" : 1}, {"foo" : 1, "fah" : 2, "bar" : "baz"}], - [{"foo" : "bar"}, {"foo" : 1, "fah" : "bar"}], - patternProperties={"f.*" : {"type" : "integer"}}, + [{u"foo" : 1}, {u"foo" : 1, u"fah" : 2, u"bar" : u"baz"}], + [{u"foo" : u"bar"}, {u"foo" : 1, u"fah" : u"bar"}], + patternProperties={u"f.*" : {u"type" : u"integer"}}, ) def test_multiple_patternProperties(self): - pattern = {"a*" : {"type" : "integer"}, "aaa*" : {"maximum" : 20}} + pattern = {u"a*" : {u"type" : u"integer"}, u"aaa*" : {u"maximum" : 20}} self.validate_test( - [{"a" : 1}, {"a" : 21}, {"aaaa" : 18}], - [{"aaa" : "foo"}, {"aaaa" : 31}], + [{u"a" : 1}, {u"a" : 21}, {u"aaaa" : 18}], + [{u"aaa" : u"foo"}, {u"aaaa" : 31}], patternProperties=pattern, ) def test_additionalProperties(self): - ex = {"foo" : 1, "bar" : "baz", "quux" : False} + ex = {u"foo" : 1, u"bar" : u"baz", u"quux" : False} schema = { "properties" : { - "foo" : {"type" : "number"}, - "bar" : {"type" : "string"}, + u"foo" : {u"type" : u"number"}, + u"bar" : {u"type" : u"string"}, } } @@ -105,81 +112,90 @@ class TestValidate(unittest.TestCase): with self.assertRaises(ValidationError): validate(ex, dict(additionalProperties=False, **schema)) - invalids = [{"foo" : 1, "bar" : "baz", "quux" : "boom"}] - additional = {"type" : "boolean"} + invalids = [{u"foo" : 1, u"bar" : u"baz", u"quux" : u"boom"}] + additional = {u"type" : u"boolean"} self.validate_test( [ex], invalids, additionalProperties=additional, **schema ) def test_items(self): - validate([1, "foo", False], {"type" : "array"}) - self.validate_test([[1, 2, 3]], [[1, "x"]], items={"type" : "integer"}) + validate([1, u"foo", False], {u"type" : u"array"}) + self.validate_test( + [[1, 2, 3]], [[1, u"x"]], items={u"type" : u"integer"} + ) def test_items_tuple_typing(self): - items = [{"type" : "integer"}, {"type" : "string"}] - self.validate_test([[1, "foo"]], [["foo", 1], [1, False]], items=items) + items = [{u"type" : u"integer"}, {u"type" : u"string"}] + self.validate_test( + [[1, u"foo"]], [[u"foo", 1], [1, False]], items=items + ) def test_additionalItems(self): - schema = {"items" : [{"type" : "integer"}, {"type" : "string"}]} + schema = {"items" : [{u"type" : u"integer"}, {u"type" : u"string"}]} - validate([1, "foo", False], schema) + validate([1, u"foo", False], schema) self.validate_test( - [[1, "foo"]], [[1, "foo", False]], additionalItems=False, **schema + [[1, u"foo"]], + [[1, u"foo", False]], + additionalItems=False, + **schema ) self.validate_test( - [[1, "foo", 3]], - [[1, "foo", "bar"]], - additionalItems={"type" : "integer"}, + [[1, u"foo", 3]], + [[1, u"foo", u"bar"]], + additionalItems={u"type" : u"integer"}, **schema ) def test_required(self): schema = { - "properties" : { - "foo" : {"type" : "number"}, - "bar" : {"type" : "string"}, + u"properties" : { + u"foo" : {u"type" : u"number"}, + u"bar" : {u"type" : u"string"}, } } - validate({"foo" : 1}, schema) + validate({u"foo" : 1}, schema) - schema["properties"]["foo"]["required"] = False + schema[u"properties"][u"foo"][u"required"] = False - validate({"foo" : 1}, schema) + validate({u"foo" : 1}, schema) - schema["properties"]["foo"]["required"] = True - schema["properties"]["bar"]["required"] = True + schema[u"properties"][u"foo"][u"required"] = True + schema[u"properties"][u"bar"][u"required"] = True with self.assertRaises(ValidationError): - validate({"foo" : 1}, schema) + validate({u"foo" : 1}, schema) def test_dependencies(self): - schema = {"properties" : {"bar" : {"dependencies" : "foo"}}} + schema = {"properties" : {u"bar" : {u"dependencies" : u"foo"}}} self.validate_test( - [{}, {"foo" : 1}, {"foo" : 1, "bar" : 2}], [{"bar" : 2}], **schema + [{}, {u"foo" : 1}, {u"foo" : 1, u"bar" : 2}], + [{u"bar" : 2}], + **schema ) def test_multiple_dependencies(self): schema = { "properties" : { - "quux" : {"dependencies" : ["foo", "bar"]} + u"quux" : {u"dependencies" : [u"foo", u"bar"]} } } valids = [ {}, - {"foo" : 1}, - {"foo" : 1, "bar" : 2}, - {"foo" : 1, "bar" : 2, "quux" : 3}, + {u"foo" : 1}, + {u"foo" : 1, u"bar" : 2}, + {u"foo" : 1, u"bar" : 2, u"quux" : 3}, ] invalids = [ - {"foo" : 1, "quux" : 2}, - {"bar" : 1, "quux" : 2}, - {"quux" : 1}, + {u"foo" : 1, u"quux" : 2}, + {u"bar" : 1, u"quux" : 2}, + {u"quux" : 1}, ] self.validate_test(valids, invalids, **schema) @@ -187,15 +203,17 @@ class TestValidate(unittest.TestCase): def test_multiple_dependencies_subschema(self): dependencies = { "properties" : { - "foo" : {"type" : "integer"}, - "bar" : {"type" : "integer"}, + u"foo" : {u"type" : u"integer"}, + u"bar" : {u"type" : u"integer"}, } } - schema = {"properties" : {"bar" : {"dependencies" : dependencies}}} + schema = {"properties" : {u"bar" : {u"dependencies" : dependencies}}} self.validate_test( - [{"foo" : 1, "bar" : 2}], [{"foo" : "quux", "bar" : 2}], **schema + [{u"foo" : 1, u"bar" : 2}], + [{u"foo" : u"quux", u"bar" : 2}], + **schema ) def test_minimum(self): @@ -216,20 +234,20 @@ class TestValidate(unittest.TestCase): pass def test_pattern(self): - self.validate_test(["aaa"], ["ab"], pattern="^a*$") + self.validate_test([u"aaa"], [u"ab"], pattern=u"^a*$") def test_minLength(self): - self.validate_test(["foo"], ["f"], minLength=2) + self.validate_test([u"foo"], [u"f"], minLength=2) def test_maxLength(self): - self.validate_test(["f"], ["foo"], maxLength=2) + self.validate_test([u"f"], [u"foo"], maxLength=2) def test_enum(self): self.validate_test([1], [5], enum=[1, 2, 3]) - self.validate_test(["foo"], ["quux"], enum=["foo", "bar"]) + self.validate_test([u"foo"], [u"quux"], enum=[u"foo", u"bar"]) self.validate_test([True], [False], enum=[True]) self.validate_test( - [{"foo" : "bar"}], [{"foo" : "baz"}], enum=[{"foo" : "bar"}] + [{u"foo" : u"bar"}], [{u"foo" : u"baz"}], enum=[{u"foo" : u"bar"}] ) def test_divisibleBy(self): |