Skip to content

Commit b21a9c7

Browse files
committed
Preserving full path to a value when following $ref
This is just a "rebased" version of #92, that can be compared and rebased into master. I think this approach is really useful when debugging errors. More than once I found myself trying to understand which property exactly was failing. Preserving the complete path make is less confusing and more straight forward to find the errors. All the work was done by @ZbigniewRA in #92.
1 parent d03f383 commit b21a9c7

File tree

4 files changed

+34
-8
lines changed

4 files changed

+34
-8
lines changed

fastjsonschema/exceptions.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,8 @@ class JsonSchemaValueException(JsonSchemaException):
1616
1717
* ``message`` containing human-readable information what is wrong (e.g. ``data.property[index] must be smaller than or equal to 42``),
1818
* invalid ``value`` (e.g. ``60``),
19-
* ``name`` of a path in the data structure (e.g. ``data.propery[index]``),
20-
* ``path`` as an array in the data structure (e.g. ``['data', 'propery', 'index']``),
19+
* ``name`` of a path in the data structure (e.g. ``data.property[index]``),
20+
* ``path`` as an array in the data structure (e.g. ``['data', 'property', 'index']``),
2121
* the whole ``definition`` which the ``value`` has to fulfil (e.g. ``{'type': 'number', 'maximum': 42}``),
2222
* ``rule`` which the ``value`` is breaking (e.g. ``maximum``)
2323
* and ``rule_definition`` (e.g. ``42``).

fastjsonschema/generator.py

+10-4
Original file line numberDiff line numberDiff line change
@@ -136,7 +136,7 @@ def generate_validation_function(self, uri, name):
136136
self._validation_functions_done.add(uri)
137137
self.l('')
138138
with self._resolver.resolving(uri) as definition:
139-
with self.l('def {}(data, custom_formats={{}}):', name):
139+
with self.l('def {}(data, custom_formats={{}}, name_prefix=None):', name):
140140
self.generate_func_code_block(definition, 'data', 'data', clear_variables=True)
141141
self.l('return data')
142142

@@ -190,7 +190,9 @@ def generate_ref(self):
190190
if uri not in self._validation_functions_done:
191191
self._needed_validation_functions[uri] = name
192192
# call validation function
193-
self.l('{}({variable}, custom_formats)', name)
193+
path = self._variable_name[4:]
194+
name_arg = '(name_prefix or "data") + "{}"'.format(path)
195+
self.l('{}({variable}, custom_formats, {name_arg})', name, name_arg=name_arg)
194196

195197

196198
# pylint: disable=invalid-name
@@ -216,8 +218,12 @@ def l(self, line, *args, **kwds):
216218
spaces = ' ' * self.INDENT * self._indent
217219

218220
name = self._variable_name
219-
if name and '{' in name:
220-
name = '"+"{}".format(**locals())+"'.format(self._variable_name)
221+
if name:
222+
# Add name_prefix to the name when it is being outputted.
223+
assert name.startswith('data')
224+
name = '" + (name_prefix or "data") + "' + name[4:]
225+
if '{' in name:
226+
name = name + '".format(**locals()) + "'
221227

222228
context = dict(
223229
self._definition or {},

tests/test_compile_to_code.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -121,4 +121,4 @@ def test_compile_to_code_custom_format_with_refs():
121121
assert validate({"a": ["identifier"]}, formats) is not None
122122
with pytest.raises(JsonSchemaValueException) as exc:
123123
validate({"a": ["identifier", "not-valid"]}, formats)
124-
assert exc.value.message == "data[1] must be my-format"
124+
assert exc.value.message == "data.a[1] must be my-format"

tests/test_object.py

+21-1
Original file line numberDiff line numberDiff line change
@@ -225,4 +225,24 @@ def test_dependencies(asserter, value, expected):
225225
"dependencies": {
226226
"foo": ["bar"],
227227
},
228-
}, value, expected)
228+
}, value, expected)
229+
230+
231+
@pytest.mark.parametrize('value, expected', [
232+
({"prop1": {"str": 1}}, JsonSchemaValueException('data.prop1.str must be string', value=1, name='data.prop1.str', definition={'type': 'string'}, rule='type')),
233+
])
234+
def test_full_name_after_ref(asserter, value, expected):
235+
asserter({
236+
"definitions": {
237+
"SomeType": {
238+
"type": "object",
239+
"properties": {
240+
"str": {"type": "string"},
241+
},
242+
},
243+
},
244+
"type": "object",
245+
"properties": {
246+
"prop1": {"$ref": "#/definitions/SomeType"},
247+
}
248+
}, value, expected)

0 commit comments

Comments
 (0)