mirror of
https://github.com/dptech-corp/Uni-Lab-OS.git
synced 2025-12-17 04:51:10 +00:00
Initial commit
This commit is contained in:
138
unilabos/utils/cls_creator.py
Normal file
138
unilabos/utils/cls_creator.py
Normal file
@@ -0,0 +1,138 @@
|
||||
"""
|
||||
类实例创建工具
|
||||
|
||||
此模块提供了通过字典配置创建类实例的功能,支持嵌套实例的递归创建。
|
||||
类似于Hydra和Weights & Biases的配置系统。
|
||||
"""
|
||||
|
||||
import importlib
|
||||
import traceback
|
||||
from typing import Any, Dict, TypeVar
|
||||
from unilabos.utils import import_manager, logger
|
||||
|
||||
T = TypeVar("T")
|
||||
|
||||
# 定义实例创建规范的关键字
|
||||
INSTANCE_TYPE_KEY = "_cls" # 类的完整路径
|
||||
INSTANCE_PARAMS_KEY = "_params" # 构造函数参数
|
||||
INSTANCE_ARGS_KEY = "_args" # 位置参数列表(可选)
|
||||
|
||||
|
||||
def is_instance_config(config: Any) -> bool:
|
||||
"""
|
||||
检查配置是否符合实例创建规范
|
||||
|
||||
Args:
|
||||
config: 要检查的配置对象
|
||||
|
||||
Returns:
|
||||
是否符合实例创建规范
|
||||
"""
|
||||
if not isinstance(config, dict):
|
||||
return False
|
||||
|
||||
return INSTANCE_TYPE_KEY in config and INSTANCE_PARAMS_KEY in config
|
||||
|
||||
|
||||
def import_class(class_path: str) -> type:
|
||||
"""
|
||||
根据类路径导入类
|
||||
|
||||
Args:
|
||||
class_path: 类的完整路径,如"pylabrobot.liquid_handling:LiquidHandler"
|
||||
|
||||
Returns:
|
||||
导入的类
|
||||
|
||||
Raises:
|
||||
ImportError: 如果导入失败
|
||||
AttributeError: 如果找不到指定的类
|
||||
"""
|
||||
try:
|
||||
return import_manager.get_class(class_path)
|
||||
except ValueError as e:
|
||||
raise ImportError(f"无法导入类 {class_path}: {str(e)}")
|
||||
except (ImportError, AttributeError) as e:
|
||||
raise ImportError(f"无法导入类 {class_path}: {str(e)}")
|
||||
|
||||
|
||||
def create_instance_from_config(config: Dict[str, Any]) -> Any:
|
||||
"""
|
||||
从配置字典创建实例,递归处理嵌套的实例配置
|
||||
|
||||
Args:
|
||||
config: 配置字典,必须包含_type和_params键
|
||||
|
||||
Returns:
|
||||
创建的实例
|
||||
|
||||
Raises:
|
||||
ValueError: 如果配置不符合规范
|
||||
ImportError: 如果类导入失败
|
||||
"""
|
||||
if not is_instance_config(config):
|
||||
raise ValueError(f"配置不符合实例创建规范: {config}")
|
||||
|
||||
class_path = config[INSTANCE_TYPE_KEY]
|
||||
params = config[INSTANCE_PARAMS_KEY]
|
||||
args = config.get(INSTANCE_ARGS_KEY, [])
|
||||
|
||||
# 递归处理嵌套的实例配置
|
||||
processed_args = []
|
||||
for arg in args:
|
||||
if is_instance_config(arg):
|
||||
processed_args.append(create_instance_from_config(arg))
|
||||
else:
|
||||
processed_args.append(arg)
|
||||
|
||||
processed_params = {}
|
||||
for key, value in params.items():
|
||||
if is_instance_config(value):
|
||||
processed_params[key] = create_instance_from_config(value)
|
||||
elif isinstance(value, list):
|
||||
# 处理列表中的实例配置
|
||||
processed_list = []
|
||||
for item in value:
|
||||
if is_instance_config(item):
|
||||
processed_list.append(create_instance_from_config(item))
|
||||
else:
|
||||
processed_list.append(item)
|
||||
processed_params[key] = processed_list
|
||||
elif isinstance(value, dict) and not is_instance_config(value):
|
||||
# 处理普通字典中可能包含的实例配置
|
||||
processed_dict = {}
|
||||
for k, v in value.items():
|
||||
if is_instance_config(v):
|
||||
processed_dict[k] = create_instance_from_config(v)
|
||||
else:
|
||||
processed_dict[k] = v
|
||||
processed_params[key] = processed_dict
|
||||
else:
|
||||
processed_params[key] = value
|
||||
|
||||
# 导入类并创建实例
|
||||
cls = import_class(class_path)
|
||||
return cls(*processed_args, **processed_params)
|
||||
|
||||
|
||||
def create_config_from_instance(instance: Any, include_args: bool = False) -> Dict[str, Any]:
|
||||
"""
|
||||
从实例创建配置字典(序列化)
|
||||
|
||||
Args:
|
||||
instance: 要序列化的实例
|
||||
include_args: 是否包含位置参数(通常无法获取)
|
||||
|
||||
Returns:
|
||||
配置字典
|
||||
"""
|
||||
if instance is None:
|
||||
return {}
|
||||
|
||||
# 获取实例的类路径
|
||||
cls = instance.__class__
|
||||
class_path = f"{cls.__module__}.{cls.__name__}"
|
||||
|
||||
# 无法获取实例的构造参数,这里返回空字典
|
||||
# 实际使用时可能需要手动指定或通过其他方式获取
|
||||
return {INSTANCE_TYPE_KEY: class_path, INSTANCE_PARAMS_KEY: {}, INSTANCE_ARGS_KEY: [] if include_args else None}
|
||||
Reference in New Issue
Block a user