Skip to content

Commit

Permalink
Better exception inheritance
Browse files Browse the repository at this point in the history
  • Loading branch information
horejsek committed Feb 1, 2021
1 parent b9141ff commit 64a635e
Show file tree
Hide file tree
Showing 22 changed files with 114 additions and 105 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@
* Fix additional property equal to empty object is the same as True
* Fix const with "
* Add const to error message
* Add JsonSchemaValueException (replacement for JsonSchemaException)
* JsonSchemaException is base exception
* JsonSchemaDefinitionException no longer inherits from JsonSchemaValueException


=== 2.14.5 (2020-08-17)
Expand Down
6 changes: 3 additions & 3 deletions fastjsonschema/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -79,11 +79,11 @@
from .draft04 import CodeGeneratorDraft04
from .draft06 import CodeGeneratorDraft06
from .draft07 import CodeGeneratorDraft07
from .exceptions import JsonSchemaException, JsonSchemaDefinitionException
from .exceptions import JsonSchemaException, JsonSchemaValueException, JsonSchemaDefinitionException
from .ref_resolver import RefResolver
from .version import VERSION

__all__ = ('VERSION', 'JsonSchemaException', 'JsonSchemaDefinitionException', 'validate', 'compile', 'compile_to_code')
__all__ = ('VERSION', 'JsonSchemaException', 'JsonSchemaValueException', 'JsonSchemaDefinitionException', 'validate', 'compile', 'compile_to_code')


def validate(definition, data, handlers={}, formats={}):
Expand Down Expand Up @@ -160,7 +160,7 @@ def compile(definition, handlers={}, formats={}):
Exception :any:`JsonSchemaDefinitionException` is raised when generating the
code fails (bad definition).
Exception :any:`JsonSchemaException` is raised from generated funtion when
Exception :any:`JsonSchemaValueException` is raised from generated function when
validation fails (data do not follow the definition).
"""
resolver, code_generator = _factory(definition, handlers, formats)
Expand Down
6 changes: 3 additions & 3 deletions fastjsonschema/draft04.py
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,7 @@ def generate_any_of(self):
with self.l('try:', optimize=False):
self.generate_func_code_block(definition_item, self._variable, self._variable_name, clear_variables=True)
self.l('{variable}_any_of_count += 1')
self.l('except JsonSchemaException: pass')
self.l('except JsonSchemaValueException: pass')

with self.l('if not {variable}_any_of_count:', optimize=False):
self.exc('{name} must be valid by one of anyOf definition', rule='anyOf')
Expand Down Expand Up @@ -179,7 +179,7 @@ def generate_one_of(self):
with self.l('try:', optimize=False):
self.generate_func_code_block(definition_item, self._variable, self._variable_name, clear_variables=True)
self.l('{variable}_one_of_count += 1')
self.l('except JsonSchemaException: pass')
self.l('except JsonSchemaValueException: pass')

with self.l('if {variable}_one_of_count != 1:'):
self.exc('{name} must be valid exactly by one of oneOf definition', rule='oneOf')
Expand Down Expand Up @@ -208,7 +208,7 @@ def generate_not(self):
else:
with self.l('try:', optimize=False):
self.generate_func_code_block(not_definition, self._variable, self._variable_name)
self.l('except JsonSchemaException: pass')
self.l('except JsonSchemaValueException: pass')
with self.l('else:'):
self.exc('{name} must not be valid by not definition', rule='not')

Expand Down
6 changes: 3 additions & 3 deletions fastjsonschema/draft06.py
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ def generate_property_names(self):
self._variable_name,
clear_variables=True,
)
with self.l('except JsonSchemaException:'):
with self.l('except JsonSchemaValueException:'):
self.l('{variable}_property_names = False')
with self.l('if not {variable}_property_names:'):
self.exc('{name} must be named by propertyName definition', rule='propertyNames')
Expand Down Expand Up @@ -161,7 +161,7 @@ def generate_contains(self):
)
self.l('{variable}_contains = True')
self.l('break')
self.l('except JsonSchemaException: pass')
self.l('except JsonSchemaValueException: pass')

with self.l('if not {variable}_contains:'):
self.exc('{name} must contain one of contains definition', rule='contains')
Expand All @@ -180,6 +180,6 @@ def generate_const(self):
"""
const = self._definition['const']
if isinstance(const, str):
const = '"{}"'.format(const.replace('"', '\\"'))
const = '"{}"'.format(self.e(const))
with self.l('if {variable} != {}:', const):
self.exc('{name} must be same as const definition: {definition_rule}', rule='const')
2 changes: 1 addition & 1 deletion fastjsonschema/draft07.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ def generate_if_then_else(self):
self._variable_name,
clear_variables=True
)
with self.l('except JsonSchemaException:'):
with self.l('except JsonSchemaValueException:'):
if 'else' in self._definition:
self.generate_func_code_block(
self._definition['else'],
Expand Down
6 changes: 6 additions & 0 deletions fastjsonschema/exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,12 @@


class JsonSchemaException(ValueError):
"""
Base exception of ``fastjsonschema`` library.
"""


class JsonSchemaValueException(JsonSchemaException):
"""
Exception raised by validation function. Available properties:
Expand Down
18 changes: 9 additions & 9 deletions fastjsonschema/generator.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
from collections import OrderedDict
import re

from .exceptions import JsonSchemaException, JsonSchemaDefinitionException
from .exceptions import JsonSchemaValueException, JsonSchemaDefinitionException
from .indent import indent
from .ref_resolver import RefResolver

Expand Down Expand Up @@ -83,7 +83,7 @@ def global_state(self):
**self._extra_imports_objects,
REGEX_PATTERNS=self._compile_regexps,
re=re,
JsonSchemaException=JsonSchemaException,
JsonSchemaValueException=JsonSchemaValueException,
)

@property
Expand All @@ -96,14 +96,14 @@ def global_state_code(self):

if not self._compile_regexps:
return '\n'.join(self._extra_imports_lines + [
'from fastjsonschema import JsonSchemaException',
'from fastjsonschema import JsonSchemaValueException',
'',
'',
])
regexs = ['"{}": re.compile(r"{}")'.format(key, value.pattern) for key, value in self._compile_regexps.items()]
return '\n'.join(self._extra_imports_lines + [
'import re',
'from fastjsonschema import JsonSchemaException',
'from fastjsonschema import JsonSchemaValueException',
'',
'',
'REGEX_PATTERNS = {',
Expand Down Expand Up @@ -206,14 +206,14 @@ def l(self, line, *args, **kwds):
.. code-block:: python
self.l('if {variable} not in {enum}: raise JsonSchemaException("Wrong!")')
self.l('if {variable} not in {enum}: raise JsonSchemaValueException("Wrong!")')
When you want to indent block, use it as context manager. For example:
.. code-block:: python
with self.l('if {variable} not in {enum}:'):
self.l('raise JsonSchemaException("Wrong!")')
self.l('raise JsonSchemaValueException("Wrong!")')
"""
spaces = ' ' * self.INDENT * self._indent

Expand All @@ -238,15 +238,15 @@ def e(self, string):
.. code-block:: python
self.l('raise JsonSchemaException("Variable: {}")', self.e(variable))
self.l('raise JsonSchemaValueException("Variable: {}")', self.e(variable))
"""
return str(string).replace('"', '\\"')

def exc(self, msg, *args, rule=None):
"""
"""
msg = 'raise JsonSchemaException("'+msg+'", value={variable}, name="{name}", definition={definition}, rule={rule})'
definition_rule = str(self._definition.get(rule) if isinstance(self._definition, dict) else None).replace('"', '\\"')
msg = 'raise JsonSchemaValueException("'+msg+'", value={variable}, name="{name}", definition={definition}, rule={rule})'
definition_rule = self.e(self._definition.get(rule) if isinstance(self._definition, dict) else None)
self.l(msg, *args, definition=repr(self._definition), rule=repr(rule), definition_rule=definition_rule)

def create_variable_with_length(self):
Expand Down
2 changes: 1 addition & 1 deletion tests/benchmarks/test_benchmark.py
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ def test_benchmark_bad_values(benchmark, value):
def f():
try:
fastjsonschema_validate(value)
except fastjsonschema.JsonSchemaException:
except fastjsonschema.JsonSchemaValueException:
pass
else:
pytest.fail('Exception is not raised')
6 changes: 3 additions & 3 deletions tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@

import pytest

from fastjsonschema import JsonSchemaException, compile
from fastjsonschema import JsonSchemaValueException, compile
from fastjsonschema.draft07 import CodeGeneratorDraft07


Expand All @@ -25,8 +25,8 @@ def f(definition, value, expected, formats={}):
definition.setdefault('$schema', 'http://json-schema.org/draft-04/schema')

validator = compile(definition, formats=formats)
if isinstance(expected, JsonSchemaException):
with pytest.raises(JsonSchemaException) as exc:
if isinstance(expected, JsonSchemaValueException):
with pytest.raises(JsonSchemaValueException) as exc:
validator(value)
assert exc.value.message == expected.message
assert exc.value.value == (value if expected.value == '{data}' else expected.value)
Expand Down
4 changes: 2 additions & 2 deletions tests/json_schema/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
import pytest
from urllib.request import urlopen

from fastjsonschema import RefResolver, JsonSchemaException, compile, _get_code_generator_class
from fastjsonschema import RefResolver, JsonSchemaValueException, compile, _get_code_generator_class


REMOTES = {
Expand Down Expand Up @@ -81,7 +81,7 @@ def template_test(schema_version, schema, data, is_valid):
try:
result = validate(data)
print('Validate result:', result)
except JsonSchemaException:
except JsonSchemaValueException:
if is_valid:
raise
else:
Expand Down
26 changes: 13 additions & 13 deletions tests/test_array.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import pytest

from fastjsonschema import JsonSchemaException
from fastjsonschema import JsonSchemaValueException


exc = JsonSchemaException('data must be array', value='{data}', name='data', definition='{definition}', rule='type')
exc = JsonSchemaValueException('data must be array', value='{data}', name='data', definition='{definition}', rule='type')
@pytest.mark.parametrize('value, expected', [
(0, exc),
(None, exc),
Expand All @@ -18,7 +18,7 @@ def test_array(asserter, value, expected):
asserter({'type': 'array'}, value, expected)


exc = JsonSchemaException('data must contain less than or equal to 1 items', value='{data}', name='data', definition='{definition}', rule='maxItems')
exc = JsonSchemaValueException('data must contain less than or equal to 1 items', value='{data}', name='data', definition='{definition}', rule='maxItems')
@pytest.mark.parametrize('value, expected', [
([], []),
([1], [1]),
Expand All @@ -32,7 +32,7 @@ def test_max_items(asserter, value, expected):
}, value, expected)


exc = JsonSchemaException('data must contain at least 2 items', value='{data}', name='data', definition='{definition}', rule='minItems')
exc = JsonSchemaValueException('data must contain at least 2 items', value='{data}', name='data', definition='{definition}', rule='minItems')
@pytest.mark.parametrize('value, expected', [
([], exc),
([1], exc),
Expand All @@ -49,7 +49,7 @@ def test_min_items(asserter, value, expected):
@pytest.mark.parametrize('value, expected', [
([], []),
([1], [1]),
([1, 1], JsonSchemaException('data must contain unique items', value='{data}', name='data', definition='{definition}', rule='uniqueItems')),
([1, 1], JsonSchemaValueException('data must contain unique items', value='{data}', name='data', definition='{definition}', rule='uniqueItems')),
([1, 2, 3], [1, 2, 3]),
])
def test_unique_items(asserter, value, expected):
Expand All @@ -71,7 +71,7 @@ def test_min_and_unique_items(asserter):
@pytest.mark.parametrize('value, expected', [
([], []),
([1], [1]),
([1, 'a'], JsonSchemaException('data[1] must be number', value='a', name='data[1]', definition={'type': 'number'}, rule='type')),
([1, 'a'], JsonSchemaValueException('data[1] must be number', value='a', name='data[1]', definition={'type': 'number'}, rule='type')),
])
def test_items_all_same(asserter, value, expected):
asserter({
Expand All @@ -84,7 +84,7 @@ def test_items_all_same(asserter, value, expected):
([], []),
([1], [1]),
([1, 'a'], [1, 'a']),
([1, 2], JsonSchemaException('data[1] must be string', value=2, name='data[1]', definition={'type': 'string'}, rule='type')),
([1, 2], JsonSchemaValueException('data[1] must be string', value=2, name='data[1]', definition={'type': 'string'}, rule='type')),
([1, 'a', 2], [1, 'a', 2]),
([1, 'a', 'b'], [1, 'a', 'b']),
])
Expand All @@ -102,8 +102,8 @@ def test_different_items(asserter, value, expected):
([], []),
([1], [1]),
([1, 'a'], [1, 'a']),
([1, 2], JsonSchemaException('data[1] must be string', value=2, name='data[1]', definition={'type': 'string'}, rule='type')),
([1, 'a', 2], JsonSchemaException('data[2] must be string', value=2, name='data[2]', definition={'type': 'string'}, rule='type')),
([1, 2], JsonSchemaValueException('data[1] must be string', value=2, name='data[1]', definition={'type': 'string'}, rule='type')),
([1, 'a', 2], JsonSchemaValueException('data[2] must be string', value=2, name='data[2]', definition={'type': 'string'}, rule='type')),
([1, 'a', 'b'], [1, 'a', 'b']),
])
def test_different_items_with_additional_items(asserter, value, expected):
Expand All @@ -121,9 +121,9 @@ def test_different_items_with_additional_items(asserter, value, expected):
([], []),
([1], [1]),
([1, 'a'], [1, 'a']),
([1, 2], JsonSchemaException('data[1] must be string', value=2, name='data[1]', definition={'type': 'string'}, rule='type')),
([1, 'a', 2], JsonSchemaException('data must contain only specified items', value='{data}', name='data', definition='{definition}', rule='items')),
([1, 'a', 'b'], JsonSchemaException('data must contain only specified items', value='{data}', name='data', definition='{definition}', rule='items')),
([1, 2], JsonSchemaValueException('data[1] must be string', value=2, name='data[1]', definition={'type': 'string'}, rule='type')),
([1, 'a', 2], JsonSchemaValueException('data must contain only specified items', value='{data}', name='data', definition='{definition}', rule='items')),
([1, 'a', 'b'], JsonSchemaValueException('data must contain only specified items', value='{data}', name='data', definition='{definition}', rule='items')),
])
def test_different_items_without_additional_items(asserter, value, expected):
asserter({
Expand All @@ -140,7 +140,7 @@ def test_different_items_without_additional_items(asserter, value, expected):
((), ()),
(('a',), ('a',)),
(('a', 'b'), ('a', 'b')),
(('a', 'b', 3), JsonSchemaException('data[2] must be string', value=3, name='data[2]',
(('a', 'b', 3), JsonSchemaValueException('data[2] must be string', value=3, name='data[2]',
definition={'type': 'string'}, rule='type')),
])
def test_tuples_as_arrays(asserter, value, expected):
Expand Down
4 changes: 2 additions & 2 deletions tests/test_boolean.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import pytest

from fastjsonschema import JsonSchemaException
from fastjsonschema import JsonSchemaValueException


exc = JsonSchemaException('data must be boolean', value='{data}', name='data', definition='{definition}', rule='type')
exc = JsonSchemaValueException('data must be boolean', value='{data}', name='data', definition='{definition}', rule='type')
@pytest.mark.parametrize('value, expected', [
(0, exc),
(None, exc),
Expand Down
16 changes: 8 additions & 8 deletions tests/test_common.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import pytest

from fastjsonschema import JsonSchemaException
from fastjsonschema import JsonSchemaValueException


exc = JsonSchemaException('data must be one of [1, 2, \'a\', "b\'c"]', value='{data}', name='data', definition='{definition}', rule='enum')
exc = JsonSchemaValueException('data must be one of [1, 2, \'a\', "b\'c"]', value='{data}', name='data', definition='{definition}', rule='enum')
@pytest.mark.parametrize('value, expected', [
(1, 1),
(2, 2),
Expand All @@ -15,7 +15,7 @@ def test_enum(asserter, value, expected):
asserter({'enum': [1, 2, 'a', "b'c"]}, value, expected)


exc = JsonSchemaException('data must be string or number', value='{data}', name='data', definition='{definition}', rule='type')
exc = JsonSchemaValueException('data must be string or number', value='{data}', name='data', definition='{definition}', rule='type')
@pytest.mark.parametrize('value, expected', [
(0, 0),
(None, exc),
Expand All @@ -30,7 +30,7 @@ def test_types(asserter, value, expected):

@pytest.mark.parametrize('value, expected', [
('qwert', 'qwert'),
('qwertz', JsonSchemaException('data must be shorter than or equal to 5 characters', value='{data}', name='data', definition={'maxLength': 5}, rule='maxLength')),
('qwertz', JsonSchemaValueException('data must be shorter than or equal to 5 characters', value='{data}', name='data', definition={'maxLength': 5}, rule='maxLength')),
])
def test_all_of(asserter, value, expected):
asserter({'allOf': [
Expand All @@ -39,7 +39,7 @@ def test_all_of(asserter, value, expected):
]}, value, expected)


exc = JsonSchemaException('data must be valid by one of anyOf definition', value='{data}', name='data', definition='{definition}', rule='anyOf')
exc = JsonSchemaValueException('data must be valid by one of anyOf definition', value='{data}', name='data', definition='{definition}', rule='anyOf')
@pytest.mark.parametrize('value, expected', [
(0, 0),
(None, exc),
Expand All @@ -55,7 +55,7 @@ def test_any_of(asserter, value, expected):
]}, value, expected)


exc = JsonSchemaException('data must be valid exactly by one of oneOf definition', value='{data}', name='data', definition='{definition}', rule='oneOf')
exc = JsonSchemaValueException('data must be valid exactly by one of oneOf definition', value='{data}', name='data', definition='{definition}', rule='oneOf')
@pytest.mark.parametrize('value, expected', [
(0, exc),
(2, exc),
Expand All @@ -70,7 +70,7 @@ def test_one_of(asserter, value, expected):
]}, value, expected)


exc = JsonSchemaException('data must be valid exactly by one of oneOf definition', value='{data}', name='data', definition='{definition}', rule='oneOf')
exc = JsonSchemaValueException('data must be valid exactly by one of oneOf definition', value='{data}', name='data', definition='{definition}', rule='oneOf')
@pytest.mark.parametrize('value, expected', [
(0, exc),
(2, exc),
Expand All @@ -89,7 +89,7 @@ def test_one_of_factorized(asserter, value, expected):


@pytest.mark.parametrize('value, expected', [
(0, JsonSchemaException('data must not be valid by not definition', value='{data}', name='data', definition='{definition}', rule='not')),
(0, JsonSchemaValueException('data must not be valid by not definition', value='{data}', name='data', definition='{definition}', rule='not')),
(True, True),
('abc', 'abc'),
([], []),
Expand Down
Loading

0 comments on commit 64a635e

Please sign in to comment.