How to set up local file references in python-jsonschema document?

Chris W. picture Chris W. · Dec 29, 2018 · Viewed 8.9k times · Source

I have a set of jsonschema compliant documents. Some documents contain references to other documents (via the $ref attribute). I do not wish to host these documents such that they are accessible at an HTTP URI. As such, all references are relative. All documents live in a local folder structure.

How can I make python-jsonschema understand to properly use my local file system to load referenced documents?


For instance, if I have a document with filename defs.json containing some definitions. And I try to load a different document which references it, like:

{
  "allOf": [
    {"$ref":"defs.json#/definitions/basic_event"},
    {
      "type": "object",
      "properties": {
        "action": {
          "type": "string",
          "enum": ["page_load"]
        }
      },
      "required": ["action"]
    }
  ]
}

I get an error RefResolutionError: <urlopen error [Errno 2] No such file or directory: '/defs.json'>

It may be important that I'm on a linux box.


(I'm writing this as a Q&A because I had a hard time figuring this out and observed other folks having trouble too.)

Answer

Daniel Schneider picture Daniel Schneider · May 6, 2020

I had the hardest time figuring out how to do resolve against a set of schemas that $ref each other (I am new to JSON Schemas). It turns out the key is to create the RefResolver with a store that is a dict which maps from url to schema. Building on @devin-p's answer:

import json

from jsonschema import RefResolver, Draft7Validator

base = """
{
  "$id": "base.schema.json",
  "type": "object",
  "properties": {
    "prop": {
      "type": "string"
    }
  },
  "required": ["prop"]
}
"""

extend = """
{  
  "$id": "extend.schema.json",
  "allOf": [
    {"$ref": "base.schema.json#"},
    {
      "properties": {
        "extra": {
          "type": "boolean"
        }
      },
    "required": ["extra"]
    }
  ]
}
"""

extend_extend = """
{
  "$id": "extend_extend.schema.json",
  "allOf": [
    {"$ref": "extend.schema.json#"},
    {
      "properties": {
        "extra2": {
          "type": "boolean"
        }
      },
    "required": ["extra2"]
    }
  ]
}
"""

data = """
{
"prop": "This is the property string",
"extra": true,
"extra2": false
}
"""

schema = json.loads(base)
extendedSchema = json.loads(extend)
extendedExtendSchema = json.loads(extend_extend)
schema_store = {
    schema['$id'] : schema,
    extendedSchema['$id'] : extendedSchema,
    extendedExtendSchema['$id'] : extendedExtendSchema,
}


resolver = RefResolver.from_schema(schema, store=schema_store)
validator = Draft7Validator(extendedExtendSchema, resolver=resolver)

jsonData = json.loads(data)
validator.validate(jsonData)

The above was built with jsonschema==3.2.0.