pythonpydantic

Creating a dummy Pydantic model generator


I want to create a method on a base Pydantic model to instantiate child models with dummy data.

from __future__ import annotations
from pydantic import BaseModel


class BaseModelWrapper(BaseModel):
    @classmethod
    def make_dummy(cls) -> BaseModelWrapper:
        for name, field in cls.model_fields.items():
            if not field.is_required():
                continue
            
             # How can I create values based on the field type?
            print(field.annotation)
        return cls()


class XXX(BaseModelWrapper):
    a: int | None
    b: str
    c: int
    d: int | None = None
    e: list[str]


# These should be equivalent
XXX.make_dummy()
XXX(a=None, b="", c=0, e=[])

The part I'm struggling with is how to programmatically map type annotations to values.

Let's say field.annotation is int | None. I could just create a dictionary to map that to None, but there are tons of possible combinations of types, so this doesn't scale. There must be a cleaner way to create a value for each field.


Solution

  • I ultimately used @kamilcuk's answer to create the following method

    from __future__ import annotations
    from pydantic import BaseModel
    from types import UnionType
    from typing import Any, Union, get_args, get_origin
    
    
    def is_union_type(t: type | UnionType) -> bool:
        return get_origin(t) in [Union, UnionType]
    
    
    class BaseModelWrapper(BaseModel):
        @classmethod
        def make_dummy(cls) -> Self:
            kwargs = {}
            for name, field in cls.model_fields.items():
                if not field.is_required():
                    continue
                if field.annotation is None:
                    kwargs[name] = None
                    continue
                t = field.annotation
                if is_union_type(t):
                    types: tuple[type[Any]] = get_args(t)
                    if type(None) in types:
                        kwargs[name] = None
                        continue
                    t = types[0]
    
                try:
                    # Will error if given `list[str]` / `dict[str]`
                    if issubclass(t, BaseValidator):
                        kwargs[name] = t.make_dummy()
                    else:
                        kwargs[name] = t()
                except TypeError:
                    kwargs[name] = t()
            return cls(**kwargs)