Coverage for autocrud/converter.py: 63%
68 statements
« prev ^ index » next coverage.py v7.9.2, created at 2025-07-23 23:00 +0800
« prev ^ index » next coverage.py v7.9.2, created at 2025-07-23 23:00 +0800
1"""數據類型轉換器模組"""
3from typing import Any, Dict, Type, get_type_hints
4from dataclasses import dataclass, is_dataclass, fields
6# 嘗試導入 TypedDict,Python 3.8+ 可從 typing 導入
7try:
8 from typing import TypedDict
9except ImportError:
10 pass
13class ModelConverter:
14 """統一的數據模型轉換器"""
16 @staticmethod
17 def detect_model_type(model_class: Type) -> str:
18 """檢測模型類型"""
19 if is_dataclass(model_class):
20 return "dataclass"
22 # 檢查是否為 Pydantic 模型
23 if hasattr(model_class, "__pydantic_core_schema__") or hasattr(
24 model_class, "__fields__"
25 ):
26 return "pydantic"
28 # 檢查是否為 TypedDict
29 if hasattr(model_class, "__annotations__") and hasattr(
30 model_class, "__total__"
31 ):
32 return "typeddict"
34 raise ValueError(f"不支援的模型類型: {model_class}")
36 @staticmethod
37 def extract_fields(model_class: Type) -> Dict[str, Type]:
38 """提取模型的欄位和類型"""
39 model_type = ModelConverter.detect_model_type(model_class)
41 if model_type == "dataclass":
42 return {field.name: field.type for field in fields(model_class)}
44 elif model_type == "pydantic":
45 # Pydantic v2
46 if hasattr(model_class, "model_fields"):
47 return {
48 name: field.annotation
49 for name, field in model_class.model_fields.items()
50 }
51 # Pydantic v1
52 elif hasattr(model_class, "__fields__"):
53 return {
54 name: field.type_ for name, field in model_class.__fields__.items()
55 }
57 elif model_type == "typeddict":
58 return get_type_hints(model_class)
60 return {}
62 @staticmethod
63 def to_dict(instance: Any) -> Dict[str, Any]:
64 """將模型實例轉換為字典"""
65 if is_dataclass(instance):
66 from dataclasses import asdict
68 return asdict(instance)
70 # Pydantic 模型
71 if hasattr(instance, "model_dump"):
72 return instance.model_dump()
73 elif hasattr(instance, "dict"):
74 return instance.dict()
76 # TypedDict 或普通字典
77 if isinstance(instance, dict):
78 return instance
80 raise ValueError(f"無法轉換為字典: {type(instance)}")
82 @staticmethod
83 def from_dict(model_class: Type, data: Dict[str, Any]) -> Any:
84 """從字典創建模型實例"""
85 model_type = ModelConverter.detect_model_type(model_class)
87 if model_type == "dataclass":
88 return model_class(**data)
90 elif model_type == "pydantic":
91 return model_class(**data)
93 elif model_type == "typeddict":
94 # TypedDict 只是類型提示,實際上還是字典
95 return data
97 raise ValueError(f"無法從字典創建實例: {model_class}")
100# 使用範例
101if __name__ == "__main__":
102 from dataclasses import dataclass
103 from typing import Dict
105 @dataclass
106 class User:
107 name: str
108 age: int
109 email: str
111 # 測試轉換器
112 converter = ModelConverter()
114 # 檢測類型
115 print(f"模型類型: {converter.detect_model_type(User)}")
117 # 提取欄位
118 fields_info = converter.extract_fields(User)
119 print(f"欄位信息: {fields_info}")
121 # 創建實例並轉換
122 user = User(name="Alice", age=30, email="alice@example.com")
123 user_dict = converter.to_dict(user)
124 print(f"轉為字典: {user_dict}")
126 # 從字典創建實例
127 new_user = converter.from_dict(User, user_dict)
128 print(f"從字典創建: {new_user}")