8000 BaseModel.schema() fails when using generic types · Issue #1578 · pydantic/pydantic · GitHub
[go: up one dir, main page]

Skip to content

BaseModel.schema() fails when using generic types #1578

@adrianschneider94

Description

@adrianschneider94

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
"""

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions

      0