diff --git a/fastjsonschema/draft04.py b/fastjsonschema/draft04.py index cfc3b7b..25cb374 100644 --- a/fastjsonschema/draft04.py +++ b/fastjsonschema/draft04.py @@ -457,9 +457,10 @@ def generate_required(self): with self.l('if {variable}_is_dict:'): if not isinstance(self._definition['required'], (list, tuple)): raise JsonSchemaDefinitionException('required must be an array') - self.create_variable_with_length() - with self.l('if not all(prop in {variable} for prop in {required}):'): - self.exc('{name} must contain {} properties', self.e(self._definition['required']), rule='required') + self.l('{variable}__missing_keys = set({required}) - {variable}.keys()') + with self.l('if {variable}__missing_keys:'): + dynamic = 'str(sorted({variable}__missing_keys)) + " properties"' + self.exc('{name} must contain ', self.e(self._definition['required']), rule='required', append_to_msg=dynamic) def generate_properties(self): """ diff --git a/tests/test_integration.py b/tests/test_integration.py index d778b63..4ff8ee6 100644 --- a/tests/test_integration.py +++ b/tests/test_integration.py @@ -84,9 +84,13 @@ [9, 'hello', [1, 2, 3], {'a': 'a', 'b': 'b', 'c': 'xy'}, 'str', 5], JsonSchemaValueException('data[2][1] must be string', value=2, name='data[2][1]', definition={'type': 'string'}, rule='type'), ), + ( + [9, 'hello', [1], {'q': 'q', 'x': 'x', 'y': 'y'}, 'str', 5], + JsonSchemaValueException('data[3] must contain [\'a\', \'b\'] properties', value={'q': 'q', 'x': 'x', 'y': 'y'}, name='data[3]', definition=definition['items'][3], rule='required'), + ), ( [9, 'hello', [1], {'a': 'a', 'x': 'x', 'y': 'y'}, 'str', 5], - JsonSchemaValueException('data[3] must contain [\'a\', \'b\'] properties', value={'a': 'a', 'x': 'x', 'y': 'y'}, name='data[3]', definition=definition['items'][3], rule='required'), + JsonSchemaValueException('data[3] must contain [\'b\'] properties', value={'a': 'a', 'x': 'x', 'y': 'y'}, name='data[3]', definition=definition['items'][3], rule='required'), ), ( [9, 'hello', [1], {}, 'str', 5], diff --git a/tests/test_object.py b/tests/test_object.py index 19967a3..228aa9d 100644 --- a/tests/test_object.py +++ b/tests/test_object.py @@ -43,10 +43,11 @@ def test_min_properties(asserter, value, expected): }, value, expected) -exc = JsonSchemaValueException('data must contain [\'a\', \'b\'] properties', value='{data}', name='data', definition='{definition}', rule='required') +def make_exc(missing): + return JsonSchemaValueException('data must contain {} properties'.format(missing), value='{data}', name='data', definition='{definition}', rule='required') @pytest.mark.parametrize('value, expected', [ - ({}, exc), - ({'a': 1}, exc), + ({}, make_exc(['a', 'b'])), + ({'a': 1}, make_exc(['b'])), ({'a': 1, 'b': 2}, {'a': 1, 'b': 2}), ]) def test_required(asserter, value, expected):