73 lines
2.0 KiB
Python
73 lines
2.0 KiB
Python
"""
|
|
Type Helpers
|
|
|
|
Utilities for type introspection and resolution.
|
|
Used by generators and loaders.
|
|
"""
|
|
|
|
import dataclasses as dc
|
|
from enum import Enum
|
|
from typing import Any, Union, get_args, get_origin
|
|
|
|
|
|
def unwrap_optional(type_hint: Any) -> tuple[Any, bool]:
|
|
"""Unwrap Optional[T] -> (T, True) or (T, False) if not optional."""
|
|
origin = get_origin(type_hint)
|
|
if origin is Union:
|
|
args = [a for a in get_args(type_hint) if a is not type(None)]
|
|
return (args[0] if args else str, True)
|
|
return (type_hint, False)
|
|
|
|
|
|
def get_origin_name(type_hint: Any) -> str | None:
|
|
"""Get origin type name: 'dict', 'list', or None."""
|
|
origin = get_origin(type_hint)
|
|
if origin is dict:
|
|
return "dict"
|
|
if origin is list:
|
|
return "list"
|
|
return None
|
|
|
|
|
|
def get_type_name(type_hint: Any) -> str | None:
|
|
"""Get type name for special types like UUID, datetime."""
|
|
if hasattr(type_hint, "__name__"):
|
|
return type_hint.__name__
|
|
return None
|
|
|
|
|
|
def get_list_inner(type_hint: Any) -> str:
|
|
"""Get inner type of List[T]."""
|
|
args = get_args(type_hint)
|
|
if args and args[0] in (str, int, float, bool):
|
|
return {str: "str", int: "int", float: "float", bool: "bool"}[args[0]]
|
|
return "str"
|
|
|
|
|
|
def get_field_default(field: dc.Field) -> Any:
|
|
"""Get default value from dataclass field."""
|
|
if field.default is not dc.MISSING:
|
|
return field.default
|
|
return dc.MISSING
|
|
|
|
|
|
def format_opts(optional: bool, extra: list[str] | None = None) -> str:
|
|
"""Format field options string for Django."""
|
|
parts = []
|
|
if optional:
|
|
parts.append("null=True, blank=True")
|
|
if extra:
|
|
parts.extend(extra)
|
|
return ", ".join(parts)
|
|
|
|
|
|
def is_enum(type_hint: Any) -> bool:
|
|
"""Check if type is an Enum."""
|
|
base, _ = unwrap_optional(type_hint)
|
|
return isinstance(base, type) and issubclass(base, Enum)
|
|
|
|
|
|
def get_enum_values(enum_class: type) -> list[tuple[str, str]]:
|
|
"""Get list of (name, value) pairs from an Enum."""
|
|
return [(m.name, m.value) for m in enum_class]
|