File size: 1,592 Bytes
4baacf3
d6e5a14
4baacf3
 
d6e5a14
4baacf3
 
 
 
 
 
 
 
 
 
 
 
 
d6e5a14
 
 
 
 
 
 
4baacf3
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
from pydantic import BaseModel
from typing import get_origin, get_args, List, Dict, Optional, Union
from datetime import datetime

def pydantic_to_template(model: type[BaseModel]):
    """
    Recursively converts a pydantic model class into
    a minimal JSON template (dict).
    """
    fields = {}
    for name, field in model.model_fields.items():
        fields[name] = type_to_template(field.annotation)
    return fields


def type_to_template(annotation):
    origin = get_origin(annotation)

    # Optional[T] / Union[T, None] -> T
    # Handles both typing.Optional[T] and the newer `T | None` syntax
    if origin is Union:
        args = [arg for arg in get_args(annotation) if arg is not type(None)]
        if len(args) == 1:
            annotation = args[0]
            origin = get_origin(annotation)

    # List[T]
    if origin is list or origin is List:
        inner = get_args(annotation)[0]
        return [type_to_template(inner)]

    # Dict[str, T]
    if origin is dict or origin is Dict:
        inner = get_args(annotation)[1]
        return {"string": type_to_template(inner)}

    # Pydantic model
    if isinstance(annotation, type) and issubclass(annotation, BaseModel):
        return pydantic_to_template(annotation)

    # Primitive types
    if annotation in [str, int, float]:
        if annotation is str:
            return "string"
        if annotation is int:
            return 'int'
        if annotation is float:
            return 'float'

    # datetime
    if annotation is datetime:
        return 'datetime'

    # Fallback
    return 'any'