Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve validation error messages for oneOf #12

Merged
merged 10 commits into from
Mar 25, 2019
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
46 changes: 40 additions & 6 deletions libcove/lib/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down