From b23ad5d6a393a229b26e5172f7ca9626849340c0 Mon Sep 17 00:00:00 2001 From: Anthony Sottile Date: Mon, 31 Mar 2014 22:49:24 -0700 Subject: [PATCH] Add jsonschema extension to populate defaults. --- pre_commit/jsonschema_extensions.py | 32 ++++++++++++++++++ tests/jsonschema_extensions_test.py | 51 +++++++++++++++++++++++++++++ 2 files changed, 83 insertions(+) create mode 100644 pre_commit/jsonschema_extensions.py create mode 100644 tests/jsonschema_extensions_test.py diff --git a/pre_commit/jsonschema_extensions.py b/pre_commit/jsonschema_extensions.py new file mode 100644 index 00000000..938303c9 --- /dev/null +++ b/pre_commit/jsonschema_extensions.py @@ -0,0 +1,32 @@ + +import copy +import jsonschema +import jsonschema.validators + + +# From https://github.com/Julian/jsonschema/blob/master/docs/faq.rst +def extend_with_default(validator_class): + validate_properties = validator_class.VALIDATORS["properties"] + + def set_defaults(validator, properties, instance, schema): + for error in validate_properties( + validator, properties, instance, schema, + ): + yield error + + for property, subschema in properties.iteritems(): + if "default" in subschema: + instance.setdefault(property, subschema["default"]) + + return jsonschema.validators.extend( + validator_class, {"properties" : set_defaults}, + ) + + +DefaultingValidator = extend_with_default(jsonschema.Draft4Validator) + + +def apply_defaults(obj, schema): + obj = copy.deepcopy(obj) + DefaultingValidator(schema).validate(obj) + return obj diff --git a/tests/jsonschema_extensions_test.py b/tests/jsonschema_extensions_test.py new file mode 100644 index 00000000..4ea2686c --- /dev/null +++ b/tests/jsonschema_extensions_test.py @@ -0,0 +1,51 @@ + +from pre_commit.jsonschema_extensions import apply_defaults + + +def test_apply_defaults_copies_object(): + input = {} + ret = apply_defaults(input, {}) + assert ret is not input + + +def test_apply_default_does_not_touch_schema_without_defaults(): + ret = apply_defaults( + {'foo': 'bar'}, + {'type': 'object', 'properties': {'foo': {}, 'baz': {}}}, + ) + assert ret == {'foo': 'bar'} + + +def test_apply_defaults_applies_defaults(): + ret = apply_defaults( + {'foo': 'bar'}, + { + 'type': 'object', + 'properties': { + 'foo': {'default': 'biz'}, + 'baz': {'default': 'herp'}, + } + } + ) + assert ret == {'foo': 'bar', 'baz': 'herp'} + + +def test_apply_defaults_deep(): + ret = apply_defaults( + {'foo': {'bar': {}}}, + { + 'type': 'object', + 'properties': { + 'foo': { + 'type': 'object', + 'properties': { + 'bar': { + 'type': 'object', + 'properties': {'baz': {'default': 'herp'}}, + }, + }, + }, + }, + }, + ) + assert ret == {'foo': {'bar': {'baz': 'herp'}}}