first commit

This commit is contained in:
2026-06-25 17:41:06 +08:00
commit b2f23a933b
370 changed files with 30526 additions and 0 deletions
+133
View File
@@ -0,0 +1,133 @@
import random
import string
from hashlib import md5
from typing import Any, Dict, List, Union, Optional, get_origin, get_args, Type
from pydantic import BaseModel
def gen_random_str(length=10, prefix="", suffix=""):
"""
生成随机字符串,默认长度为10,可添加前缀和后缀
"""
random_str = prefix + ''.join(random.choices(string.ascii_letters + string.digits, k=length)) + suffix
return md5(random_str.encode()).hexdigest()
def split_generator(iterable, chunk_size=50):
"""
将可迭代对象拆分为多个子列表
"""
chunk = []
for item in iterable:
chunk.append(item)
if len(chunk) == chunk_size:
yield chunk
chunk = []
if chunk:
yield chunk
async def async_split_generator(iterable, chunk_size=50):
"""
将可迭代对象拆分为多个子列表
"""
chunk = []
async for item in iterable:
chunk.append(item)
if len(chunk) == chunk_size:
yield chunk
chunk = []
if chunk:
yield chunk
async def async_generator_to_list(iterable):
"""
将可迭代对象转换为列表
"""
return [item async for item in iterable]
TYPE_MAPPING = {
"str": "string",
"int": "number",
"float": "number",
"bool": "boolean",
"list": "array",
"dict": "object",
"NoneType": "null", # 注意:None 的类型名是 'NoneType'
}
def transform_pydantic_to_list(
cls: Type[BaseModel],
prefix: str = "" # 新增:当前路径前缀
) -> List[Dict[str, Any]]:
if not issubclass(cls, BaseModel):
raise TypeError(f"{cls} is not a Pydantic BaseModel")
result = []
exclude_filter = getattr(cls, "__exclude_filter__", [])
meta_mapping = getattr(cls, "__meta_mapping__", {})
for field_name, field_info in cls.model_fields.items():
if field_name in exclude_filter:
continue
# 构建当前字段的完整路径
current_path = f"{prefix}.{field_name}" if prefix else field_name
field_meta = meta_mapping.get(field_name, {}) or {}
raw_type = field_info.annotation
children = []
display_type_name = "any"
origin = get_origin(raw_type)
args = get_args(raw_type)
# 处理 Optional[T](即 Union[T, None]
if origin is Union and type(None) in args:
# 提取非 None 的类型
non_none_types = [arg for arg in args if arg is not type(None)]
if len(non_none_types) == 1:
inner_type = non_none_types[0]
else:
inner_type = raw_type # 多类型 Union,暂不深入处理
else:
inner_type = raw_type
# 判断是否为 List[BaseModel]
list_origin = get_origin(inner_type)
if list_origin is list:
item_type = get_args(inner_type)[0] if get_args(inner_type) else Any
if isinstance(item_type, type) and issubclass(item_type, BaseModel):
children = transform_pydantic_to_list(item_type, prefix=current_path)
display_type_name = "list"
elif isinstance(inner_type, type) and issubclass(inner_type, BaseModel):
children = transform_pydantic_to_list(inner_type, prefix=current_path)
display_type_name = "object"
else:
# 基础类型:获取类型名
if inner_type is type(None):
display_type_name = "NoneType"
elif hasattr(inner_type, '__name__'):
display_type_name = inner_type.__name__
else:
display_type_name = str(inner_type)
frontend_type = TYPE_MAPPING.get(display_type_name, "string")
item = {
"value": current_path, # ✅ 使用层级路径
"label": field_info.description or field_name,
"type": frontend_type,
**field_meta,
}
if children:
item["children"] = children
result.append(item)
return result
if __name__ == "__main__":
print(gen_random_str())
print(gen_random_str())
print(gen_random_str())
print(gen_random_str())