Do not compute JSON Schema default when plain serializers are used with when_used set to 'json-unless-none' and the default value is None#10121
Conversation
Deploying pydantic-docs with
|
| Latest commit: |
eb1570b
|
| Status: | ✅ Deploy successful! |
| Preview URL: | https://41c39d23.pydantic-docs.pages.dev |
| Branch Preview URL: | https://10118-plain-json-schema.pydantic-docs.pages.dev |
CodSpeed Performance ReportMerging #10121 will not alter performanceComparing Summary
|
| assert Model.model_json_schema(mode='serialization') == { | ||
| 'properties': {'custom_decimal': {'default': None, 'title': 'Custom Decimal', 'type': 'number'}}, | ||
| 'title': 'Model', | ||
| 'type': 'object', | ||
| } |
There was a problem hiding this comment.
This revealed another issue with the JSON Schema: type should be 'anyOf': [{'type': 'number'}, {'type': 'null'}]}.
When the JSON Schema for our field is created, schema is of type default, and schema['schema'] is of type nullable:
pydantic/pydantic/json_schema.py
Lines 1022 to 1031 in 0c97049
However, self.generate_inner(schema['schema']) will not go through nullable_schema as we would expect. As there's a serialization key, ser_schema is being used:
pydantic/pydantic/json_schema.py
Lines 492 to 494 in 0c97049
This makes sense, however, the issue is ser_schema kind of assumes when_used is always. I'll see if I can fix this in a follow up PR.
| and (ser_schema := schema['schema'].get('serialization')) | ||
| and (ser_func := ser_schema.get('function')) | ||
| and ser_schema.get('type') == 'function-plain' | ||
| and not ser_schema.get('info_arg') |
There was a problem hiding this comment.
Switching from and ser_schema.get('info_arg') is False releaved an issue in the tests, that I fixed in 0eed384.
…th `when_used` set to `'json-unless-none'` and the default value is `None`
acef83b to
4396bb3
Compare
Coverage reportClick to see where and how coverage changed
This report was generated by python-coverage-comment-action |
||||||||||||||||||||||||||||||||||||||||||||||||
sydney-runkle
left a comment
There was a problem hiding this comment.
This patch looks alright to me - I've left one comment that I think might simplify things!
| # It might be that the provided default needs to be validated first | ||
| # (assuming `validate_default` is enabled). However, we can't perform | ||
| # such validation during JSON Schema generation so we don't support | ||
| # this pattern for now. | ||
| # (One example is when using `foo: ByteSize = '1MB'`, which validates and | ||
| # serializes as an int. In this case, `ser_func` is `int` and `int('1MB')` fails). | ||
| self.emit_warning( | ||
| 'non-serializable-default', | ||
| f'Unable to serialize value {default!r} with the plain serializer; excluding default from JSON schema', | ||
| ) | ||
| return json_schema |
There was a problem hiding this comment.
Could we do something like this?
pydantic/pydantic/json_schema.py
Lines 2017 to 2044 in 0c97049
I feel like we shouldn't be skipping that logic here, we could maybe call that function?
There was a problem hiding this comment.
I don't think it makes sense to do so, or we may end up with a wrong default value in the JSON Schema (in the related test fixed, '1MB' was set as the default value in the JSON Schema, but this isn't true as the default is 1000000). In my opinion, it's better to have no value than a wrong one.
However, we emit a warning here, so I'm ok to call encode_default.
There was a problem hiding this comment.
That's fair - I wonder if we could use a similar pattern though + attempt to validate the default + include that in the JSON schema. Feels messy to do validation here, I admit.
I'm not opposed to the warning you have in place, I think that's good!
There was a problem hiding this comment.
That's fair - I wonder if we could use a similar pattern though + attempt to validate the default + include that in the JSON schema. Feels messy to do validation here, I admit.
I think we can do this in a separate PR, if someone asks for it. I'm not keen to go ahead and do this now.
Change looks good to me, thanks for including the helpful warning.
0eed384 to
eb1570b
Compare
sydney-runkle
left a comment
There was a problem hiding this comment.
Looks good @Viicos, nice work
| # serializes as an int. In this case, `ser_func` is `int` and `int('1MB')` fails). | ||
| self.emit_warning( | ||
| 'non-serializable-default', | ||
| f'Unable to serialize value {default!r} with the plain serializer; excluding default from JSON schema', |
There was a problem hiding this comment.
One nit, this isn't always a user defined plain serializer, which might be confusing. We could change the wording of this a bit, but I'm not super worried about it, so will go ahead and merge this.
Fixes #10118
Change Summary
Related issue number
Checklist