Coverage for src/c41811/config/basic/_generate_operators.py: 100%

45 statements  

« prev     ^ index     » next       coverage.py v7.15.0, created at 2026-07-04 11:16 +0000

1# cython: language_level = 3 # noqa: ERA001 

2 

3 

4""" 

5辅助生成 

6 

7.. versionadded:: 0.2.0 

8""" 

9 

10from collections.abc import Callable 

11from functools import update_wrapper 

12from typing import Any 

13 

14import wrapt 

15 

16from .core import BasicSingleConfigData 

17from .factory import ConfigDataFactory 

18from .utils import check_read_only 

19 

20type Operator = Callable[[Any, Any], Any] 

21type InplaceOperator[S] = Callable[[S, Any], S] 

22 

23 

24def _generate_operators[S: Any]( 

25 operate_func: Operator, inplace_func: InplaceOperator[S] 

26) -> tuple[Operator, Operator, InplaceOperator[S]]: 

27 """ 

28 闭包绑定操作函数 

29 

30 :param operate_func: 操作函数 

31 :type operate_func: Operator 

32 :param inplace_func: 原地操作函数 

33 :type inplace_func: InplaceOperator[S] 

34 

35 :return: 绑定后的操作符实现 

36 :rtype: tuple[Operator, Operator, InplaceOperator[S]] 

37 """ 

38 

39 def forward_op(self: Any, other: Any) -> Any: 

40 return ConfigDataFactory(operate_func(self._data, other)) 

41 

42 def reverse_op(self: Any, other: Any) -> Any: 

43 return ConfigDataFactory(operate_func(other, self._data)) 

44 

45 def inplace_op(self: S, other: Any) -> S: 

46 self._data = inplace_func(self._data, other) 

47 return self 

48 

49 return forward_op, reverse_op, inplace_op 

50 

51 

52def generate[C](cls: type[C]) -> type[C]: 

53 """ 

54 为类生成操作符 

55 

56 需要使用 :py:deco:`operate` 装饰器标记要自动生成的操作符 

57 

58 :param cls: 目标类 

59 :type cls: type[C] 

60 

61 :return: 原样返回类 

62 :rtype: type[C] 

63 """ 

64 for name, func in dict(vars(cls)).items(): 

65 if not hasattr(func, "__generate_operators__"): 

66 continue 

67 operator_funcs = func.__generate_operators__ 

68 delattr(func, "__generate_operators__") 

69 

70 # 动态创建函数 

71 forward_op, reverse_op, inplace_op = _generate_operators( 

72 operator_funcs["operate_func"], operator_funcs["inplace_func"] 

73 ) 

74 

75 # 设置函数标识符 

76 i_name = f"__i{name[2:-2]}__" 

77 r_name = f"__r{name[2:-2]}__" 

78 forward_op.__qualname__ = func.__qualname__ 

79 reverse_op.__qualname__ = f"{cls.__qualname__}.{r_name}" 

80 inplace_op.__qualname__ = f"{cls.__qualname__}.{i_name}" 

81 

82 # 应用装饰器 

83 @wrapt.decorator 

84 def wrapper(wrapped: Callable[..., Any], _instance: C, args: tuple[Any, ...], kwargs: dict[str, Any]) -> Any: 

85 if isinstance(args[0], BasicSingleConfigData): 

86 args = (args[0].data, *args[1:]) 

87 return wrapped(*args, **kwargs) 

88 

89 setattr(cls, name, update_wrapper(wrapper(forward_op), forward_op)) 

90 setattr(cls, r_name, reverse_op) 

91 setattr(cls, i_name, update_wrapper(wrapper(check_read_only(inplace_op)), inplace_op)) 

92 

93 return cls 

94 

95 

96def operate[F: Operator]( 

97 operate_func: Operator, 

98 inplace_func: InplaceOperator[Any], 

99) -> Callable[[F], F]: 

100 """ 

101 将方法标记为需要生成标记符 

102 

103 :param operate_func: 操作函数 

104 :type operate_func: Operator 

105 :param inplace_func: 原地操作函数 

106 :type inplace_func: InplaceOperator[Any] 

107 

108 :return: 装饰器 

109 :rtype: Callable[[F], F] 

110 """ 

111 

112 def decorator(func: F) -> F: 

113 func.__generate_operators__ = { # type: ignore[attr-defined] 

114 "operate_func": operate_func, 

115 "inplace_func": inplace_func, 

116 } 

117 return func 

118 

119 return decorator 

120 

121 

122__all__ = ( 

123 "generate", 

124 "operate", 

125)