-
Notifications
You must be signed in to change notification settings - Fork 26
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
[#3688] Fix some edge cases when parsing JSON Schemas #3937
Conversation
7ff78af
to
975668e
Compare
Codecov ReportAttention: Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## master #3937 +/- ##
==========================================
- Coverage 96.35% 96.07% -0.29%
==========================================
Files 715 715
Lines 22415 22437 +22
Branches 2574 2575 +1
==========================================
- Hits 21599 21556 -43
- Misses 565 626 +61
- Partials 251 255 +4 ☔ View full report in Codecov by Sentry. |
if "object" in type_list and "properties" in json_schema: | ||
required = json_schema.get("required", []) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
the type
can be absent, this is valid:
required:
- foo
properties:
foo:
type: string
and is equivalent to:
required:
- foo
type: object # or ['object']
properties:
foo:
type: string
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure this is the case. If the type
is absent, any data should validate. A thread is available here.
Unfortunately, this isn't explicitly stated in the spec (or I couldn't find it). However, the introduction seems to imply it:
The most basic schema is a blank JSON object, which constrains nothing, allows anything, and describes nothing:
{}
By adding validation keywords to the schema, you can apply constraints to an instance. For example, you can use thetype
keyword to constrain an instance to an object, array, string, number, boolean, or null.
I'm surprised to see the Python jsonschema
library does not respect this, nor does this online validator, but I guess we'll have to comply with how jsonschema
does the validation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hum in fact apparently not: OAI/OpenAPI-Specification#1388 (comment).
So to be precise:
required: - foo properties: foo: type: string
is equivalent to:
required:
- foo
type: ["object", "array", "number", ...]
properties:
foo:
type: string
and depending on the instance being validated, required/properties/minItems/...
constraints apply
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ah yeah, I missed some nuance, TIL!
I was using that same JSON schema validator, so definitely didn't use the spec or a python library to validate my statement.
I think we should take a pragmatic approach here for our practical means. Maybe it's a good idea to create an issue in the object types API to show some warnings if such schemas get uploaded (missing a type
key) because they may unintentionally be too loose.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes I ended up not relying on the type
value, and only assert it is correctly set to object
if provided and properties
is set as a sanity check
case {"type": "object"}: | ||
yield from _iter_json_schema(v, json_path) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
case {"type": "object"}: | |
yield from _iter_json_schema(v, json_path) | |
case {"type": "object"} | {"properties": dict}: | |
yield from _iter_json_schema(v, json_path) | |
case {"type": [*types]} and "object" in types: | |
yield from _iter_json_schema(v, json_path) |
I think?
This would also need the check that object
is in the nested type
array.
The pattern matching itself can probably be done in some clever way, or perhaps you would do the matching only on the properties
key and add an assert
inside the match:
type_ = v.get("type", "object")
assert isinstance(type_, (str, list))
assert type_ == "object" or "object" in type_
Part of #3688
type
can be an arrayobject
sub schema