Repository: horejsek/python-fastjsonschema

Issue:
Keep the variable name and path through references
> for me the most important feature is to keep track of the context/scope of where the validation process is at when the exception is thrown. so given: a schema:

article.json
```{
  "$schema": "http://json-schema.org/draft-07/schema#",
  "type" : "object",
  "additionalProperties": false,
  "properties": {
    "teaser" : { "$ref": "intro.json" },
    "prolog" : { "$ref": "intro.json" }
  }
}
```
when the error occurs during the prolog validation, the exception contains an attribute with value `article.prolog.....`  about where it happened (like the jsonschema library does).

_Originally posted by @isomogyi in https://github.com/horejsek/python-fastjsonschema/pull/61_

Discussion:

Patch:
diff --git a/fastjsonschema/exceptions.py b/fastjsonschema/exceptions.py
index 63d9819..d2dddd6 100644
--- a/fastjsonschema/exceptions.py
+++ b/fastjsonschema/exceptions.py
@@ -16,8 +16,8 @@ class JsonSchemaValueException(JsonSchemaException):
 
      * ``message`` containing human-readable information what is wrong (e.g. ``data.property[index] must be smaller than or equal to 42``),
      * invalid ``value`` (e.g. ``60``),
-     * ``name`` of a path in the data structure (e.g. ``data.propery[index]``),
-     * ``path`` as an array in the data structure (e.g. ``['data', 'propery', 'index']``),
+     * ``name`` of a path in the data structure (e.g. ``data.property[index]``),
+     * ``path`` as an array in the data structure (e.g. ``['data', 'property', 'index']``),
      * the whole ``definition`` which the ``value`` has to fulfil (e.g. ``{'type': 'number', 'maximum': 42}``),
      * ``rule`` which the ``value`` is breaking (e.g. ``maximum``)
      * and ``rule_definition`` (e.g. ``42``).
diff --git a/fastjsonschema/generator.py b/fastjsonschema/generator.py
index 57b65a6..cebf302 100644
--- a/fastjsonschema/generator.py
+++ b/fastjsonschema/generator.py
@@ -136,7 +136,7 @@ class CodeGenerator:
         self._validation_functions_done.add(uri)
         self.l('')
         with self._resolver.resolving(uri) as definition:
-            with self.l('def {}(data, custom_formats={{}}):', name):
+            with self.l('def {}(data, custom_formats={{}}, name_prefix=None):', name):
                 self.generate_func_code_block(definition, 'data', 'data', clear_variables=True)
                 self.l('return data')
 
@@ -190,7 +190,10 @@ class CodeGenerator:
             if uri not in self._validation_functions_done:
                 self._needed_validation_functions[uri] = name
             # call validation function
-            self.l('{}({variable}, custom_formats)', name)
+            assert self._variable_name.startswith("data")
+            path = self._variable_name[4:]
+            name_arg = '(name_prefix or "data") + "{}"'.format(path)
+            self.l('{}({variable}, custom_formats, {name_arg})', name, name_arg=name_arg)
 
 
     # pylint: disable=invalid-name
@@ -216,8 +219,12 @@ class CodeGenerator:
         spaces = ' ' * self.INDENT * self._indent
 
         name = self._variable_name
-        if name and '{' in name:
-            name = '"+"{}".format(**locals())+"'.format(self._variable_name)
+        if name:
+            # Add name_prefix to the name when it is being outputted.
+            assert name.startswith('data')
+            name = '" + (name_prefix or "data") + "' + name[4:]
+            if '{' in name:
+                name = name + '".format(**locals()) + "'
 
         context = dict(
             self._definition or {},


Test patch:
diff --git a/tests/test_compile_to_code.py b/tests/test_compile_to_code.py
index 84bc981..8e40db5 100644
--- a/tests/test_compile_to_code.py
+++ b/tests/test_compile_to_code.py
@@ -121,4 +121,4 @@ def test_compile_to_code_custom_format_with_refs():
     assert validate({"a": ["identifier"]}, formats) is not None
     with pytest.raises(JsonSchemaValueException) as exc:
         validate({"a": ["identifier", "not-valid"]}, formats)
-    assert exc.value.message == "data[1] must be my-format"
\ No newline at end of file
+    assert exc.value.message == "data.a[1] must be my-format"
diff --git a/tests/test_object.py b/tests/test_object.py
index d880dc4..19967a3 100644
--- a/tests/test_object.py
+++ b/tests/test_object.py
@@ -225,4 +225,24 @@ def test_dependencies(asserter, value, expected):
         "dependencies": {
             "foo": ["bar"],
         },
-    }, value, expected)
\ No newline at end of file
+    }, value, expected)
+
+
+@pytest.mark.parametrize('value, expected', [
+    ({"prop1": {"str": 1}}, JsonSchemaValueException('data.prop1.str must be string', value=1, name='data.prop1.str', definition={'type': 'string'}, rule='type')),
+])
+def test_full_name_after_ref(asserter, value, expected):
+    asserter({
+        "definitions": {
+            "SomeType": {
+                "type": "object",
+                "properties": {
+                    "str": {"type": "string"},
+                },
+            },
+        },
+        "type": "object",
+        "properties": {
+            "prop1": {"$ref": "#/definitions/SomeType"},
+        }
+    }, value, expected)