diff --git a/CHANGELOG.md b/CHANGELOG.md index 6a7a058..b55f648 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,12 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html). +## [Unreleased] + +### Added + +- Return specific validation errors for `oneOf`, by using `statementType` to pick the correct sub-schema. Only works for BODS. [#16](https://github.com/openownership/cove-bods/issues/16) + ## [0.4.0] - 2019-03-14 ### Changed diff --git a/libcove/lib/common.py b/libcove/lib/common.py index d3fb2f2..d195e88 100644 --- a/libcove/lib/common.py +++ b/libcove/lib/common.py @@ -86,22 +86,56 @@ def oneOf_draft4(validator, oneOf, instance, schema): """ oneOf_draft4 validator from https://github.com/Julian/jsonschema/blob/d16713a4296663f3d62c50b9f9a2893cb380b7af/jsonschema/_validators.py#L337 - patched to sort the instance. + + Modified to: + - sort the instance JSON, so we get a reproducible output that we + can can test more easily + - If `statementType` is available, use that pick the correct + sub-schema, and to yield those ValidationErrors. (Only + applicable for BODS). """ subschemas = enumerate(oneOf) all_errors = [] + validStatementTypes = [] for index, subschema in subschemas: errs = list(validator.descend(instance, subschema, schema_path=index)) if not errs: first_valid = subschema break + properties = subschema.get('properties', {}) + if'statementType' in properties: + if 'statementType' in instance: + try: + validStatementType = properties['statementType'].get('enum', [])[0] + except IndexError: + continue + if instance['statementType'] == validStatementType: + for err in errs: + yield err + return + else: + validStatementTypes.append(validStatementType) + else: + yield ValidationError( + 'statementType', + validator='required', + ) + break all_errors.extend(errs) else: - yield ValidationError( - "%s is not valid under any of the given schemas" % ( - json.dumps(instance, sort_keys=True, default=decimal_default),), - context=all_errors, - ) + if validStatementTypes: + yield ValidationError( + 'Invalid code found in statementType', + instance=instance['statementType'], + path=('statementType',), + validator='enum', + ) + else: + yield ValidationError( + "%s is not valid under any of the given schemas" % ( + json.dumps(instance, sort_keys=True, default=decimal_default),), + context=all_errors, + ) more_valid = [s for i, s in subschemas if validator.is_valid(instance, s)] if more_valid: