Skip to content

Unable to resolve local subschemas through "$defs" #947

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
MatthewNielsen27 opened this issue May 13, 2022 · 9 comments
Closed

Unable to resolve local subschemas through "$defs" #947

MatthewNielsen27 opened this issue May 13, 2022 · 9 comments

Comments

@MatthewNielsen27
Copy link

MatthewNielsen27 commented May 13, 2022

The issue

The json-schema specification outlines the ability to reference local subschemas that are defined in $defs. Currently, a RefResolutionError is raised when attempting to validate an instance of a schema that references local subschemas with $defs.

How to replicate

Running the following python code will raise a RefResolutionError.

import jsonschema

# note: the $id uses a "namespace" for the project instead of a protocol, which is still valid.
schema = {
    "$schema": "https://json-schema.org/draft-07/schema",
    "$id": "project://test.schema.json",
    "type": "object",
    "properties": {
        "foo": {"$ref": "#/$defs/bar"}
    },
    "$defs": {
        "bar": {"type": "integer"}
    }
}

# In reality there is a dependency between multiple schemas in the same directory or namespace.
# I understand that we can pre-populate a RefResolver with a store of schemas.
store = {"project://test.schema.json": schema}
resolver = jsonschema.RefResolver.from_schema(schema, store=store)

instance = {"foo": 12}
jsonschema.Draft7Validator(schema=schema, resolver=resolver).validate(instance)

What I think is going wrong

Subschema references are resolved using the _find_in_subschemas(...) function which calls the following function:

    def _get_subschemas_cache(self):
        cache = {key: [] for key in _SUBSCHEMAS_KEYWORDS}
        for keyword, subschema in _search_schema(
            self.referrer, _match_subschema_keywords,
        ):
            cache[keyword].append(subschema)
        return cache

The issue is that _SUBSCHEMAS_KEYWORDS doesn't contain "$defs" (currently it is only comprised of ("$id", "id", "$anchor", "$dynamicAnchor"))

Proposed fix

Add "$defs" to _SUBSCHEMAS_KEYWORDS.

@karenetheridge

This comment was marked as off-topic.

@Julian

This comment was marked as off-topic.

@Julian
Copy link
Member

Julian commented May 13, 2022

@MatthewNielsen27 thanks, will have a look.

@karenetheridge

This comment was marked as off-topic.

@Julian
Copy link
Member

Julian commented May 20, 2022

I didn't fully look at this yet, but just glancing at it again briefly, I don't think this has anything to do with $def; does the issue go away if you use a different scheme? If so it's probably another instance of #544.

@MatthewNielsen27
Copy link
Author

MatthewNielsen27 commented May 20, 2022

I'm suspicious because "$defs" doesn't appear anywhere in the python code. Since "$defs" isn't included in _SUBSCHEMA_KEYWORDS, it isn't considered in subschema resolution.

When the search for the id in the schema_store and subschemas fails, it then tries to pull it from the web. Which is the failure condition seen here and in #544. (in these cases since its a URN, the url is parsed as '').

To put it plainly, the subschema resolution only considers a subset of valid subschema tags.

@Julian
Copy link
Member

Julian commented May 20, 2022

$defs shouldn't appear in _SUBSCHEMA_KEYWORDS. That constant has to do with which keywords are anchor-like and affect the URI that's being resolved. $defs doesn't, it's just a normal addressible location.

(EDIT: Which isn't to say I know what the solution is yet, but yeah I'm reasonably sure that's not it).

@MatthewNielsen27
Copy link
Author

Ok, thanks for clearing that up. I think we can mark this as a duplicate of #544.

@Julian
Copy link
Member

Julian commented May 20, 2022

Sounds good, will do, appreciate the report!

@Julian Julian closed this as completed May 20, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants