Skip to content

Commit

Permalink
Rewrote all SchemaConflict exceptions to be more human readable.
Browse files Browse the repository at this point in the history
  • Loading branch information
Grokzen committed Aug 4, 2015
1 parent 1c7471c commit afa9ab7
Show file tree
Hide file tree
Showing 4 changed files with 75 additions and 18 deletions.
1 change: 1 addition & 0 deletions ReleaseNotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ Release Notes
- Reworked all RuleError exceptions to now have better exception messages.
- RuleError exceptions now have a unique 'error_key' that can make it easier to identify what error it is.
- Paths for RuleErrors have been moved inside the exception as a variable.
- Rewrote all SchemaConflict exceptions to be more human readable.


1.3.0
Expand Down
4 changes: 4 additions & 0 deletions docs/Upgrade Instructions.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,10 @@ Python 3.2 support have been dropped. It was going to be dropped when python 3.5

All logging and exception messages have been fixed to work with unicode characters in schema and data files. If you use this in lib mode then you should test your code to ensure it is still compatible.

If you use `RuleError` in your code, you must update to use the new `msg` and `error_key` variables.

If you use `SchemaConflict` in your code, you must update to use the new `msg` and `error_key` variables.


## 1.2.0 --> 1.3.0

Expand Down
67 changes: 57 additions & 10 deletions pykwalify/rule.py
Original file line number Diff line number Diff line change
Expand Up @@ -628,25 +628,72 @@ def check_conflicts(self, schema, rule, path):

if self._type == "seq":
if all([sa not in schema for sa in sequence_aliases]):
raise SchemaConflict(u"seq.nosequence")
raise SchemaConflict(
msg="Type is sequence but no sequence alias found on same level",
error_key=u"seq.no_sequence",
path=path,
)

if self._enum is not None:
raise SchemaConflict(u"seq.conflict :: enum: {}".format(path))
raise SchemaConflict(
msg="Sequence and enum can't be on the same level in the schema",
error_key=u"seq.conflict.enum",
path=path,
)

if self._pattern is not None:
raise SchemaConflict(u"seq.conflict :: pattern: {}".format(path))
raise SchemaConflict(
msg="Sequence and pattern can't be on the same level in the schema",
error_key=u"seq.conflict.pattern",
path=path,
)

if self._mapping is not None:
raise SchemaConflict(u"seq.conflict :: mapping: {}".format(path))
raise SchemaConflict(
msg="Sequence and mapping can't be on the same level in the schema",
error_key=u"seq.conflict.mapping",
path=path,
)
elif self._type == "map":
if all([ma not in schema for ma in mapping_aliases]) and not self._allowempty_map:
raise SchemaConflict(u"map.nomapping")
raise SchemaConflict(
msg="Type is mapping but no mapping alias found on same level",
error_key=u"map.no_mapping",
path=path,
)

if self._enum is not None:
raise SchemaConflict(u"map.conflict :: enum:")
raise SchemaConflict(
msg="Mapping and enum can't be on the same level in the schema",
error_key=u"map.conflict.enum",
path=path,
)

if self._sequence is not None:
raise SchemaConflict(u"map.conflict :: mapping: {}".format(path))
raise SchemaConflict(
msg="Mapping and sequence can't be on the same level in the schema",
error_key=u"map.conflict.sequence",
path=path,
)
else:
if self._sequence is not None:
raise SchemaConflict(u"scalar.conflict :: sequence: {}".format(path))
raise SchemaConflict(
msg="Scalar and sequence can't be on the same level in the schema",
error_key=u"scalar.conflict.sequence",
path=path,
)

if self._mapping is not None:
raise SchemaConflict(u"scalar.conflict :: mapping: {}".format(path))
raise SchemaConflict(
msg="Scalar and mapping can't be on the same level in the schema",
error_key=u"scalar.conflict.mapping",
path=path,
)

if self._enum is not None:
if self._range is not None:
raise SchemaConflict(u"enum.conflict :: range: {}".format(path))
raise SchemaConflict(
msg="Enum and range can't be on the same level in the schema",
error_key=u"enum.conflict.range",
path=path,
)
21 changes: 13 additions & 8 deletions tests/test_rule.py
Original file line number Diff line number Diff line change
Expand Up @@ -231,12 +231,12 @@ def test_sequence(self):
# Test error is raised when sequence key is missing
with pytest.raises(SchemaConflict) as ex:
Rule(schema={"type": "seq"})
assert ex.value.msg.startswith("seq.nosequence"), "Wrong exception was raised"
assert str(ex.value) == "<SchemaConflict: error code 5: Type is sequence but no sequence alias found on same level: Path: '/'>"

# sequence and pattern can't be used at same time
with pytest.raises(SchemaConflict) as ex:
Rule(schema={"type": "seq", "sequence": [{"type": "str"}], "pattern": "..."})
assert ex.value.msg.startswith("seq.conflict :: pattern"), "Wrong exception was raised"
assert str(ex.value) == "<SchemaConflict: error code 5: Sequence and pattern can't be on the same level in the schema: Path: '/'>"

def test_build_sequence_multiple_values(self):
"""
Expand Down Expand Up @@ -276,7 +276,7 @@ def test_mapping(self):
# when type is specefied, 'mapping' key must be present
with pytest.raises(SchemaConflict) as ex:
Rule(schema={"type": "map"})
assert ex.value.msg.startswith("map.nomapping"), "Wrong exception was raised"
assert str(ex.value) == "<SchemaConflict: error code 5: Type is mapping but no mapping alias found on same level: Path: '/'>"

# 'map' and 'enum' can't be used at same time
# TODO: This do not work because it currently raises RuleError: <RuleError: error code 4: enum.notscalar>
Expand All @@ -295,24 +295,29 @@ def test_check_conflicts(self):
# Test sequence and mapping can't be used at same level
with pytest.raises(SchemaConflict) as ex:
Rule(schema={"type": "seq", "sequence": [{"type": "str"}], "mapping": {"name": {"type": "str", "pattern": ".+@.+"}}})
assert ex.value.msg.startswith("seq.conflict :: mapping"), "Wrong exception was raised"
assert str(ex.value) == "<SchemaConflict: error code 5: Sequence and mapping can't be on the same level in the schema: Path: '/'>"
assert ex.value.error_key == 'seq.conflict.mapping'

# Mapping and sequence can't used at same time
with pytest.raises(SchemaConflict) as ex:
Rule(schema={"type": "map", "mapping": {"foo": {"type": "str"}}, "sequence": [{"type": "str"}]})
assert ex.value.msg.startswith("map.conflict :: mapping"), "Wrong exception was raised"
assert str(ex.value) == "<SchemaConflict: error code 5: Mapping and sequence can't be on the same level in the schema: Path: '/'>"
assert ex.value.error_key == 'map.conflict.sequence'

# scalar type and sequence can't be used at same time
with pytest.raises(SchemaConflict) as ex:
Rule(schema={"type": "int", "sequence": [{"type": "str"}]})
assert ex.value.msg.startswith("scalar.conflict :: sequence"), "Wrong exception was raised"
assert str(ex.value) == "<SchemaConflict: error code 5: Scalar and sequence can't be on the same level in the schema: Path: '/'>"
assert ex.value.error_key == 'scalar.conflict.sequence'

# scalar type and mapping can't be used at same time
with pytest.raises(SchemaConflict) as ex:
Rule(schema={"type": "int", "mapping": {"foo": {"type": "str"}}})
assert ex.value.msg.startswith("scalar.conflict :: mapping"), "Wrong exception was raised"
assert str(ex.value) == "<SchemaConflict: error code 5: Scalar and mapping can't be on the same level in the schema: Path: '/'>"
assert ex.value.error_key == 'scalar.conflict.mapping'

# scalar type and enum can't be used at same time
with pytest.raises(SchemaConflict) as ex:
Rule(schema={"type": "int", "enum": [1, 2, 3], "range": {"max": 10, "min": 1}})
assert ex.value.msg.startswith("enum.conflict :: range"), "Wrong exception was raised"
assert str(ex.value) == "<SchemaConflict: error code 5: Enum and range can't be on the same level in the schema: Path: '/'>"
assert ex.value.error_key == 'enum.conflict.range'

0 comments on commit afa9ab7

Please sign in to comment.