I'm working with Pydantic models to implement a dataclass and I want a specific field to be immutable, hence I'm using tuples. However, for convenience, I want to be able to pass both a list and a tuple as input.
I consider two different users of the dataclass:
Is it possible to describe the object's field as a tuple and the object __init__()
as accepting two types?
The current way it is implemented is the following:
from pydantic import Field
from pydantic.dataclasses import dataclass
from typing import List, Union, Tuple
@dataclass(frozen=True)
class MyClass:
"""
Description of MyClass
Parameter
---------
field: Union[List[int], Tuple[int, ...]]
"""
@field_validator("field")
def make_immutable(cls, field):
if isinstance(field, list):
return tuple(field)
return field
...
My issue here is that because of the validation function, I don't know where I could write the docstring to describe the two different behaviours.
I think this is a non-issue. The default behavior of Pydantic is type-coercion. So a given type on init will be coerced (converted) into the annotated type. If the coercion succeeds everything is fine and your data will be stored as the annotated type. If it fails a meaningful error will be thrown. This means a field that is annotated as Tuple[int, ...]
:
from pydantic import Field
from pydantic.dataclasses import dataclass
from typing import Tuple
@dataclass(frozen=True)
class MyClass:
"""
Description of MyClass
Attributes
----------
field: Tuple[int, ...]
Tuple of integer values.
"""
field: Tuple[int, ...] = Field(...)
Can be instantiated with a list anyway or everything that is accepted by tuple()
. See the following examples:
import numpy as np
print(MyClass(field=np.array([1, 2, 3])))
print(MyClass(field=[1, 2, 3]))
print(MyClass(field={1, 2, 3}))
Which all print: MyClass(field=(1, 2, 3))
I would recommend to just keep the Pydantic convention. There is no need for an additional validator. Users will be able to instantiate the model with whatever works. In case it does not work Pydantic will throw a meaningful error.
I hope this helps!