summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJulian Berman <Julian+git@GrayVines.com>2012-01-15 20:42:51 -0500
committerJulian Berman <Julian+git@GrayVines.com>2012-01-15 20:42:51 -0500
commitce63985a3d854c016985923d55e8716d5aa579c5 (patch)
tree82cd40d51a610383703f00b07ca70fd0f2292bd2
parent0500c5069db7e997bb71cdab497e6b8e8a17d5b2 (diff)
downloadjsonschema-ce63985a3d854c016985923d55e8716d5aa579c5.tar.gz
Make {max,min}{Items,Length} stricter, and 'clean up' type checking.
-rw-r--r--jsonschema.py86
-rw-r--r--tests.py5
2 files changed, 58 insertions, 33 deletions
diff --git a/jsonschema.py b/jsonschema.py
index 2c3b3db..014bb6b 100644
--- a/jsonschema.py
+++ b/jsonschema.py
@@ -113,6 +113,35 @@ class Validator(object):
)
self._types[u"any"] = tuple(self._types.values())
+ def _is_type(self, instance, type):
+ """
+ Check if an ``instance`` is of the provided ``type``.
+
+ """
+
+ py_type = self._types.get(type)
+
+ if py_type is None:
+ return self._schema_error(
+ self._unknown_type, u"%r is not a known type" % (type,)
+ )
+
+ # the only thing we're careful about here is evading bool inheriting
+ # from int, so let's be even dirtier than usual
+
+ elif (
+ # it's not a bool, so no worries
+ not isinstance(instance, bool) or
+
+ # it is a bool, but we're checking for a bool, so no worries
+ (
+ py_type is bool or
+ isinstance(py_type, tuple) and bool in py_type
+ )
+
+ ):
+ return isinstance(instance, py_type)
+
def _error(self, msg):
"""
Something failed to validate. ``msg`` will have details.
@@ -191,31 +220,22 @@ class Validator(object):
types = _list(types)
for type in types:
- if (
- isinstance(type, dict) and
- isinstance(instance, dict) and
+ # Ouch. Brain hurts. Two paths here, either we have a schema, then
+ # check if the instance is valid under it
+ if ((
+ self._is_type(type, "object") and
+ self._is_type(instance, "object") and
self.is_valid(instance, type)
- ):
- return
-
- elif isinstance(type, basestring):
- py_type = self._types.get(type)
- if py_type is None:
- self._schema_error(
- self._unknown_type, u"%r is not a known type" % (type,)
- )
- return
+ # Or we have a type as a string, just check if the instance is that
+ # type. Also, HACK: we can reach the `or` here if skip_types is
+ # something other than error. If so, bail out.
- # isinstance(a_bool, int) will make us even sadder here, so
- # let's be even dirtier than we would otherwise be.
-
- elif (
- isinstance(instance, py_type) and
- (not isinstance(instance, bool) or
- py_type is bool or types == [u"any"])
- ):
- return
+ ) or (
+ self._is_type(type, "string") and
+ (self._is_type(instance, type) or type not in self._types)
+ )):
+ return
else:
self._error(u"%r is not of type %s" % (instance, _delist(types)))
@@ -223,7 +243,7 @@ class Validator(object):
for property, subschema in properties.iteritems():
if property in instance:
dependencies = _list(subschema.get(u"dependencies", []))
- if isinstance(dependencies, dict):
+ if self._is_type(dependencies, "object"):
self._validate(instance, dependencies)
else:
missing = (d for d in dependencies if d not in instance)
@@ -247,14 +267,14 @@ class Validator(object):
# 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):
+ if self._is_type(aP, "object"):
for extra in extras:
self._validate(instance[extra], aP)
elif not aP and extras:
self._error(u"Additional properties are not allowed")
def validate_items(self, items, instance, schema):
- if isinstance(items, dict):
+ if self._is_type(items, "object"):
for item in instance:
self._validate(item, items)
else:
@@ -262,7 +282,7 @@ class Validator(object):
self._validate(item, subschema)
def validate_additionalItems(self, aI, instance, schema):
- if isinstance(aI, dict):
+ if self._is_type(aI, "object"):
for item in instance[len(schema):]:
self._validate(item, aI)
elif not aI and len(instance) > len(schema):
@@ -295,23 +315,23 @@ class Validator(object):
)
def validate_minItems(self, mI, instance, schema):
- if len(instance) < mI:
+ if self._is_type(instance, "array") and len(instance) < mI:
self._error(u"%r is too short" % (instance,))
def validate_maxItems(self, mI, instance, schema):
- if len(instance) > mI:
+ if self._is_type(instance, "array") and len(instance) > mI:
self._error(u"%r is too long" % (instance,))
- def validate_pattern(self, pattern, instance, schema):
- if not re.match(pattern, instance):
- self._error(u"%r does not match %r" % (instance, pattern))
+ def validate_pattern(self, patrn, instance, schema):
+ if self._is_type(instance, "string") and not re.match(patrn, instance):
+ self._error(u"%r does not match %r" % (instance, patrn))
def validate_minLength(self, mL, instance, schema):
- if len(instance) < mL:
+ if self._is_type(instance, "string") and len(instance) < mL:
self._error(u"%r is too short" % (instance,))
def validate_maxLength(self, mL, instance, schema):
- if len(instance) > mL:
+ if self._is_type(instance, "string") and len(instance) > mL:
self._error(u"%r is too long" % (instance,))
def validate_enum(self, enums, instance, schema):
diff --git a/tests.py b/tests.py
index c604953..bda2a62 100644
--- a/tests.py
+++ b/tests.py
@@ -360,6 +360,7 @@ class TestValidate(unittest.TestCase):
("exact", "valid", [1]),
("longer", "valid", [1, 2]),
("too_short", "invalid", []),
+ ("ignores_strings", "valid", "a"),
)(validation_test(minItems=1))
maxItems = parametrized(
@@ -367,21 +368,25 @@ class TestValidate(unittest.TestCase):
("shorter", "valid", [1]),
("empty", "valid", []),
("too_long", "invalid", [1, 2, 3]),
+ ("ignores_strings", "valid", "aaaa"),
)(validation_test(maxItems=2))
pattern = parametrized(
("match", "valid", u"aaa"),
("mismatch", "invalid", u"ab"),
+ ("ignores_other_stuff", "valid", True),
)(validation_test(pattern=u"^a*$"))
minLength = parametrized(
("", "valid", u"foo"),
("too_short", "invalid", u"f"),
+ ("ignores_arrays", "valid", [1]),
)(validation_test(minLength=2))
maxLength = parametrized(
("", "valid", u"f"),
("too_long", "invalid", u"foo"),
+ ("ignores_arrays", "valid", [1, 2, 3]),
)(validation_test(maxLength=2))
@parametrized(