How can I locate where in a JSON file a key is located?

Question:

I’m writing a parser that uses a JSON file for configuration, and if it detects an invalid value, I want to be able to output the location of the problematic data in the form of the line and column number in the source file where the error occurred. I’ve set up all of the tracing and have a path to the problematic data in the form of a list, where each item is either a key to an object or an array index, like ["foo", "bar", 3, "baz"], but can’t figure out how to locate where in the file the path is.

Ideally, the error handling code should be able to print this:

ValidationError: Features require a "feature"
  at .features[0]: "theme.json" line 6, column 13

I found that using a custom JSONDecoder lets you hook into the processing of objects through JSONDecoder.object_hook but the information given to that function is not sufficient and there isn’t any hook for arrays, either.

If needed, this is the error class:

class JSONTraceable(Exception):
    def __init__(
        self,
        message: str,
        json_path: typing.Union[str, typing.List[typing.Union[str, int]]] = "",
    ):
        super().__init__(message)
        if isinstance(json_path, str):
            self.json_path = [json_path]
        elif isinstance(json_path, list):
            self.json_path = json_path
        else:
            raise TypeError(
                f"JSON path should be a string or a list, not {type(json_path).__name__}"
            )

    def extend(self, key: typing.Union[str, int]):
        self.json_path.insert(0, key)
Asked By: PenguinEncounter

||

Answers:

I solved the problem by writing my own JSON parser that keeps track of the location of everything as it runs, following the spec available at json.org. If you want to have a look at the full code for the parser, it’s on GitHub: github permalink

Answered By: PenguinEncounter
Categories: questions Tags: , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.