Files
mediaproc/modelgen/types.py
buenosairesam ddb4f17faa modelgen: recurse through nested generics in list resolvers
_get_list_inner (Pydantic) and _resolve_ts_list (TypeScript) collapsed
nested generics to "str" / "string[]" — so List[List[int]] became
List[str] and List[Dict[str,Any]] became List[str]. Fix recurses on
list-of-list and falls back to Dict[str,Any] / Record<string,unknown>
for list-of-dict.

Regenerated outputs:
- core/gpu/models/models.py: SegmentFieldResponse.boundary now
  List[List[int]], unblocking /segment_field which was 500ing on every
  request with pydantic ValidationError
- core/db/models.py + ui/common/types/generated.ts: Brand.airings now
  matches its source schema (List[Dict[str,Any]] / Record<string,unknown>[])
2026-04-29 08:48:21 -03:00

195 lines
6.1 KiB
Python

"""
Type Dispatch Tables
Type mappings for each output format.
Used by generators to convert Python types to target framework types.
"""
import dataclasses as dc
from typing import Any, Callable, get_args
from .helpers import get_origin_name
# =============================================================================
# Django Type Mappings
# =============================================================================
DJANGO_TYPES: dict[Any, str] = {
str: "models.CharField(max_length={max_length}{opts})",
int: "models.IntegerField({opts})",
float: "models.FloatField({opts})",
bool: "models.BooleanField(default={default})",
"UUID": "models.UUIDField({opts})",
"datetime": "models.DateTimeField({opts})",
"dict": "models.JSONField(default=dict, blank=True)",
"list": "models.JSONField(default=list, blank=True)",
"text": "models.TextField(blank=True, default='')",
"bigint": "models.BigIntegerField({opts})",
"enum": "models.CharField(max_length=20, choices={enum_name}.choices{opts})",
}
DJANGO_SPECIAL: dict[str, str] = {
"id": "models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)",
"created_at": "models.DateTimeField(auto_now_add=True)",
"updated_at": "models.DateTimeField(auto_now=True)",
}
# =============================================================================
# Pydantic Type Resolvers
# =============================================================================
def _get_list_inner(type_hint: Any) -> str:
"""Get inner type of List[T] for Pydantic. Recurses for nested generics."""
args = get_args(type_hint)
if args:
inner = args[0]
if inner in (str, int, float, bool):
return {str: "str", int: "int", float: "float", bool: "bool"}[inner]
if isinstance(inner, type) and dc.is_dataclass(inner):
return inner.__name__
origin = get_origin_name(inner)
if origin == "list":
return f"List[{_get_list_inner(inner)}]"
if origin == "dict":
return "Dict[str, Any]"
return "str"
PYDANTIC_RESOLVERS: dict[Any, Callable[[Any], str]] = {
str: lambda _: "str",
int: lambda _: "int",
float: lambda _: "float",
bool: lambda _: "bool",
Any: lambda _: "Any",
"UUID": lambda _: "UUID",
"datetime": lambda _: "datetime",
"dict": lambda _: "Dict[str, Any]",
"list": lambda base: f"List[{_get_list_inner(base)}]",
"enum": lambda base: base.__name__,
"dataclass": lambda base: base.__name__,
}
# =============================================================================
# TypeScript Type Resolvers
# =============================================================================
def _resolve_ts_list(base: Any) -> str:
"""Resolve TypeScript list type. Recurses for nested generics."""
args = get_args(base)
if args:
inner = args[0]
if inner is str:
return "string[]"
elif inner is int or inner is float:
return "number[]"
elif inner is bool:
return "boolean[]"
elif isinstance(inner, type) and dc.is_dataclass(inner):
return f"{inner.__name__}[]"
origin = get_origin_name(inner)
if origin == "list":
return f"{_resolve_ts_list(inner)}[]"
if origin == "dict":
return "Record<string, unknown>[]"
return "string[]"
TS_RESOLVERS: dict[Any, Callable[[Any], str]] = {
str: lambda _: "string",
int: lambda _: "number",
float: lambda _: "number",
bool: lambda _: "boolean",
"UUID": lambda _: "string",
"datetime": lambda _: "string",
"dict": lambda _: "Record<string, unknown>",
"list": _resolve_ts_list,
"enum": lambda base: base.__name__,
"dataclass": lambda base: base.__name__,
}
# =============================================================================
# Protobuf Type Resolvers
# =============================================================================
def _resolve_proto_list(base: Any) -> str:
"""Resolve Protobuf repeated type."""
args = get_args(base)
if args:
inner = args[0]
if inner is str:
return "repeated string"
elif inner is int:
return "repeated int32"
elif inner is float:
return "repeated float"
elif inner is bool:
return "repeated bool"
return "repeated string"
PROTO_RESOLVERS: dict[Any, Callable[[Any], str]] = {
str: lambda _: "string",
int: lambda _: "int32",
float: lambda _: "float",
bool: lambda _: "bool",
"list": _resolve_proto_list,
}
# =============================================================================
# Prisma Type Mappings
# =============================================================================
PRISMA_TYPES: dict[Any, str] = {
str: "String",
int: "Int",
float: "Float",
bool: "Boolean",
"UUID": "String @default(uuid())",
"datetime": "DateTime",
"dict": "Json",
"list": "Json",
"bigint": "BigInt",
}
PRISMA_SPECIAL: dict[str, str] = {
"id": "String @id @default(uuid())",
"created_at": "DateTime @default(now())",
"updated_at": "DateTime @updatedAt",
}
# =============================================================================
# Strawberry Type Resolvers
# =============================================================================
def _resolve_strawberry_list(base: Any) -> str:
"""Resolve strawberry List type annotation."""
args = get_args(base)
if args:
inner = args[0]
if inner is str:
return "List[str]"
elif inner is int:
return "List[int]"
elif inner is float:
return "List[float]"
elif inner is bool:
return "List[bool]"
return "List[str]"
STRAWBERRY_RESOLVERS: dict[Any, Callable[[Any], str]] = {
str: lambda _: "str",
int: lambda _: "int",
float: lambda _: "float",
bool: lambda _: "bool",
"UUID": lambda _: "UUID",
"datetime": lambda _: "datetime",
"dict": lambda _: "JSON",
"list": _resolve_strawberry_list,
"enum": lambda base: base.__name__,
}