Skip to content

complex schema with parent-child-grandchild references in multiple subdirectories aren't resolved correctly #601

@kuba-lilz

Description

@kuba-lilz

There are already quite a few issues related to RefResolver not working correctly for complex schemas, but many of them don't include much code, and none that I saw includes multiple subdirectories.

In this issue I included code that shows that jsonschema doesn't resolve file references correctly for nested references in multiple directories.

System info:
OSX
Python 3.6.8
jsonschema version: '3.0.1'

Project setup:

.
└── my_complex_schemas
   ├── basic_shapes
   │   ├── circle.json
   │   └── rectangle.json
   ├── complex_shapes
   │   └── rectangle_with_hole.json
   └── point.json

my_complex_schemas/point.json

{
  "type": "object",
  "properties": {
    "x": { "type": "number" },
    "y": { "type": "number" }
  },
  "required": ["x", "y"]
}

my_complex_schemas/basic_shapes/circle.json

{
    "type": "object",
    "properties": {
        "center": { "$ref": "point.json" },
        "radius": {"type": "number"}
    },
    "required": ["center", "radius"]
}

my_complex_schemas/basic_shapes/rectangle.json

{
    "type": "object",
    "properties": {
      "top_left": { "$ref": "point.json" },
      "top_right": { "$ref": "point.json" },
      "bottom_left": { "$ref": "point.json" },
      "bottom_right": { "$ref": "point.json" }
    },
    "required": ["top_left", "top_right", "bottom_left", "bottom_right"]
}

my_complex_schemas/complex_shapes/rectangle_with_hole.json

{
    "type": "object",

    "allOf": [
       { "$ref": "basic_shapes/rectangle.json" }
    ],

    "properties": {
      "hole": { "$ref": "basic_shapes/circle.json" }
    },
    "required": ["hole"]
}

With above, when running from directory above my_complex_schemas directory, I can correctly validate circle schema that reference point schema, e.g.:

with open("./my_complex_schemas/basic_shapes/circle.json") as file:
    schema = json.load(file)

base_uri = "file://{}/".format(os.path.abspath("./my_complex_schemas"))
resolver = jsonschema.RefResolver(base_uri=base_uri, referrer=schema)

valid_data = {"center": {"x": 10, "y": 20}, "radius": 2}
jsonschema.validate(valid_data, schema, resolver=resolver)

and similar test passes for rectangle schema.
However, I can't validate rectangle_with_hole schema that references circle and rectangle schemas.

For code

with open("./my_complex_schemas/complex_shapes/rectangle_with_hole.json") as file:
    schema = json.load(file)

base_uri = "file://{}/".format(os.path.abspath("./my_complex_schemas"))
resolver = jsonschema.RefResolver(base_uri=base_uri, referrer=schema)

valid_data = {
    "top_left": {"x": 10, "y": 10},
    "top_right": {"x": 20, "y": 10},
    "bottom_left": {"x": 10, "y": 20},
    "bottom_right": {"x": 20, "y": 20},
    "hole": {"center": {"x": 20, "y": 20}, "radius": 7}
}
jsonschema.validate(valid_data, schema, resolver=resolver)

I get exception

jsonschema.exceptions.RefResolutionError: <urlopen error [Errno 2] No such file or directory: '/Users/kuba/Projects/code/sketchpad/python/python_sketchpad/my_complex_schemas/basic_shapes/point.json'>

That means that when resolver encounters "$ref": "basic_shapes/circle.json" inside my_complex_schemas/complex_shapes/rectangle_with_hole.json, enters basic_shapes/circle.json and encounters "$ref": "point.json", it tries to read it from my_complex_schemas/basic_shapes/point.json instead of my_complex_schemas/point.json, even though base_uri is set to base_uri = "file://{}/".format(os.path.abspath("./my_complex_schemas")).

I can get my_complex_schemas/complex_shapes/rectangle_with_hole.json to validate if I change references in basic_shapes/circle.json and basic_shapes/rectangle.json to "$ref": "../point.json". But if I do that,

with open("./my_complex_schemas/basic_shapes/circle.json") as file:
    schema = json.load(file)

base_uri = "file://{}/".format(os.path.abspath("./my_complex_schemas"))
resolver = jsonschema.RefResolver(base_uri=base_uri, referrer=schema)

valid_data = {"center": {"x": 10, "y": 20}, "radius": 2}
jsonschema.validate(valid_data, schema, resolver=resolver)

fails with

jsonschema.exceptions.RefResolutionError: <urlopen error [Errno 2] No such file or directory: '/Users/kuba/Projects/code/sketchpad/python/python_sketchpad/point.json'>

that is in this case resolves looks for point.json in ./my_complex_schemas/.. instead of ./my_complex_schemas, which is expected.

Hope above will help to make a unit test that fixes resolver.
Or maybe the problem is between the chair and the keyboard, and I missed some important setting?

Metadata

Metadata

Assignees

No one assigned

    Labels

    InvalidNot a bug, PEBKAC, or an unsupported setup

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions