pythontypestype-hintingpydanticpython-dataclasses

Why can't I specify multiple types in a List in pydantic


class Embedded(BaseModel):
    path: str
    items: list[Union[ResourceItemDir, ResourceItemFile]] # here
    limit: int
    offset: int
    sort: str
    total: int

class ResourceItemFile(BaseModel):
    name: str
    path: str
    size: int
    file: str

    resource_id: str
    created: datetime.datetime
    modified: datetime.datetime
    media_type: str
    antivirus_status: str
    comment_ids: dict
    exif: dict
    md5: str
    mime_type: str
    preview: str
    revision: int
    sha256: str
    share: dict
    type: Literal["file"]

class ResourceItemDir(BaseModel):
    name: str
    path: str

    comment_ids: dict
    created: datetime.datetime
    exif: dict
    modified: datetime.datetime
    public_key: str
    public_url: str
    resource_id: str
    revision: int
    share: dict
    type: Literal["dir"]

Why can't I specify multiple types in a List in pydantic? How else can I specify that the items field accepts two data types? If there are ideas how differently I should implement it?

Now such a mistake:

  File "pydantic\main.py", line 331, in pydantic.main.BaseModel.__init__
pydantic.error_wrappers.ValidationError: 99 validation errors for Resource
embedded -> items -> 2 -> public_key
  field required (type=value_error.missing)
embedded -> items -> 2 -> public_url
  field required (type=value_error.missing)
embedded -> items -> 2 -> size
  field required (type=value_error.missing)
embedded -> items -> 2 -> file
  field required (type=value_error.missing)
embedded -> items -> 2 -> media_type
  field required (type=value_error.missing)
embedded -> items -> 2 -> antivirus_status
  field required (type=value_error.missing)
embedded -> items -> 2 -> md5
  field required (type=value_error.missing)
embedded -> items -> 2 -> mime_type
  field required (type=value_error.missing)
embedded -> items -> 2 -> preview
  field required (type=value_error.missing)
embedded -> items -> 2 -> sha256
  field required (type=value_error.missing)
embedded -> items -> 2 -> type
  unexpected value; permitted: 'file' (type=value_error.const; given=dir; permitted=('file',))

Solution

  • I think I found a solution using Annotated from pedantic

    class AbstractResourceItem(BaseModel):
        name: str
        path: str
        comment_ids: dict
        created: datetime.datetime
        modified: datetime.datetime
        exif: dict
        resource_id: str
        revision: int
        share: dict
        public_key: Optional[str]
        public_url: Optional[str]
    
    
    class ResourceItemFile(AbstractResourceItem):
        size: int
        file: str
        media_type: str
        antivirus_status: str
        md5: str
        mime_type: str
        preview: str
        sha256: str
        type: Literal["file"]
    
    
    class ResourceItemDir(AbstractResourceItem):
        embedded: Optional["Embedded"]
        type: Literal["dir"]
    
    #here
    ResourceItem = Annotated[
        Union[ResourceItemDir, ResourceItemFile],
        Field(discriminator="type")
    ]
    
    
    class Embedded(BaseModel):
        path: str
        items: list[ResourceItem]
        limit: int
        offset: int
        sort: str
        total: int