Files
mediaproc/tools/helpers.py

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]