So we're using pydantic and python-jsonschema to validate user input. Pydantic for internal validation, and python-jsonschema for validation on the portal. And I've come across an interesting issue, and I can't wrap my head around it.
Example code:
from pydantic import BaseModel
import typing as tp
import jsonschema
class Pet(BaseModel):
pet_type: tp.Optional[tp.Literal['cat', 'dog']]
params = {'pet_type': None}
myPet = Pet(**params)
print(myPet.pet_type)
try:
jsonschema.validate(instance=params, schema=Pet.schema())
print('Passed validaton on None')
except Exception as e:
print('Failed validation on None')
So, according to Pydantic documentation, tp.Optional is a shorthand for tp.Union. Which means that the code above should be read as tp.Union[tp.Literal['cat', 'dog'], None]. Meaning that animal type can be 'cat', 'dog' or None, right?
Well, schema seems to confirm that, with Pet.schema() output being the following, and no 'required' as pet_type:
{
'title': 'Pet',
'type': 'object',
'properties': {
'pet_type': {
'title': 'Pet Type',
'enum': ['cat', 'dog'],
'type': 'string'
}
}
}
However, if the code is run it fails at jsonschema validation with message:
ValidationError: None is not one of ['cat', 'dog']
Failed validating 'enum' in schema['properties']['pet_type']:
{'enum': ['cat', 'dog'], 'title': 'Pet Type', 'type': 'string'}
On instance['pet_type']:
None
So even though pydantic specifies that attribute can be 'cat', 'dog' or None, jsonschema still fails.
Is that a problem with pydantic code, python-jsonschema code or our use of pydantic?
EDIT: To try to further narrow down the cause, I've tried creating a schema manually and validating it through jsonschema. Manual passes, pydantic one doesn't:
schema_manual = {
'title': 'Pet',
'type': 'object',
'properties': {
'pet_type': {
'title': 'Pet Type',
'oneOf': [
{'type': 'string', 'enum': ['cat', 'dog']},
{'type': 'null'}
]
}
}
}
validate(instance=params, schema=schema_manual)
validate(instance=params, schema=Pet.schema())