-
-
Notifications
You must be signed in to change notification settings - Fork 2.4k
Closed
Labels
Description
Bug
Version
Output of python -c "import pydantic.utils; print(pydantic.utils.version_info())":
pydantic version: 1.5.1
pydantic compiled: True
install path: C:\Users\adrian\miniconda3\envs\sangl-butler\Lib\site-packages\pydantic
python version: 3.8.1 (default, Mar 2 2020, 13:06:26) [MSC v.1916 64 bit (AMD64)]
platform: Windows-10-10.0.18362-SP0
optional deps. installed: ['typing-extensions', 'email-validator']
Description
Hi there!
I want to write a generic type, that behaves like the type it extends, but injects fields into the model with __modify_schema__. So my approach was to use a generic class to use it like that:
from pydantic import BaseModel
class MyModel(BaseModel):
my_field: FieldThatModifiesModel[str] = "Default value"The field should completely behave like the type var.
However, when I use a generic type in my model, I can't retrieve the model anymore.
See the code below (taken from the docs):
Example
from pydantic import BaseModel, ValidationError
from pydantic.fields import ModelField
from typing import TypeVar, Generic
AgedType = TypeVar('AgedType')
QualityType = TypeVar('QualityType')
# This is not a pydantic model, it's an arbitrary generic class
class TastingModel(Generic[AgedType, QualityType]):
def __init__(self, name: str, aged: AgedType, quality: QualityType):
self.name = name
self.aged = aged
self.quality = quality
@classmethod
def __get_validators__(cls):
yield cls.validate
@classmethod
# You don't need to add the "ModelField", but it will help your
# editor give you completion and catch errors
def validate(cls, v, field: ModelField):
if not isinstance(v, cls):
# The value is not even a TastingModel
raise TypeError('Invalid value')
if not field.sub_fields:
# Generic parameters were not provided so we don't try to validate
# them and just return the value as is
return v
aged_f = field.sub_fields[0]
quality_f = field.sub_fields[1]
errors = []
# Here we don't need the validated value, but we want the errors
valid_value, error = aged_f.validate(v.aged, {}, loc='aged')
if error:
errors.append(error)
# Here we don't need the validated value, but we want the errors
valid_value, error = quality_f.validate(v.quality, {}, loc='quality')
if error:
errors.append(error)
if errors:
raise ValidationError(errors, cls)
# Validation passed without errors, return the same instance received
return v
class Model(BaseModel):
# for wine, "aged" is an int with years, "quality" is a float
wine: TastingModel[int, float]
# for cheese, "aged" is a bool, "quality" is a str
cheese: TastingModel[bool, str]
# for thing, "aged" is a Any, "quality" is Any
thing: TastingModel
print(Model.schema())
"""
Traceback (most recent call last):
File ".../generic_type.py", line 54, in <module>
print(Model.schema())
File "pydantic\main.py", line 556, in pydantic.main.BaseModel.schema
File "pydantic\schema.py", line 132, in pydantic.schema.model_schema
File "pydantic\schema.py", line 455, in pydantic.schema.model_process_schema
File "pydantic\schema.py", line 491, in pydantic.schema.model_type_schema
File "pydantic\schema.py", line 185, in pydantic.schema.field_schema
File "pydantic\schema.py", line 411, in pydantic.schema.field_type_schema
AssertionError: 10
"""sinoptis, martin1keogh and Mazyod