Source code for treevalue.tree.func.func

import warnings
from functools import wraps
from typing import Type, TypeVar, Optional, Mapping, Union, Callable, Any

from hbutils.design import SingletonMark

from .cfunc import MISSING_NOT_ALLOW
from .cfunc import func_treelize as _c_func_treelize
from ..tree import TreeValue

TreeClassType_ = TypeVar("TreeClassType_", bound=TreeValue)


[docs]def func_treelize(mode: str = 'strict', return_type: Optional[Type[TreeClassType_]] = TreeValue, inherit: bool = True, missing: Union[Any, Callable] = MISSING_NOT_ALLOW, delayed: bool = False, subside: Union[Mapping, bool, None] = None, rise: Union[Mapping, bool, None] = None): """ Overview: Wrap a common function to tree-supported function. Arguments: - mode (:obj:`str`): Mode of the wrapping, default is `strict`. - return_type (:obj:`Optional[Type[TreeClassType_]]`): Return type of the wrapped function, default is `TreeValue`. - inherit (:obj:`bool`): Allow inheriting in wrapped function, default is `True`. - missing (:obj:`Union[Any, Callable]`): Missing value or lambda generator of when missing, \ default is `MISSING_NOT_ALLOW`, which means raise `KeyError` when missing detected. - delayed (:obj:`bool`): Enable delayed mode or not, the calculation will be delayed when enabled, \ default is ``False``, which means to all the calculation at once. - subside (:obj:`Union[Mapping, bool, None]`): Subside enabled to function's arguments or not, \ and subside configuration, default is `None` which means do not use subside. \ When subside is `True`, it will use all the default arguments in `subside` function. - rise (:obj:`Union[Mapping, bool, None]`): Rise enabled to function's return value or not, \ and rise configuration, default is `None` which means do not use rise. \ When rise is `True`, it will use all the default arguments in `rise` function. \ (Not recommend to use auto mode when your return structure is not so strict.) Returns: - decorator (:obj:`Callable`): Wrapper for tree-supported function. Example: >>> @func_treelize() >>> def ssum(a, b): >>> return a + b # the a and b will be integers, not TreeValue >>> >>> t1 = TreeValue({'a': 1, 'b': 2, 'x': {'c': 3, 'd': 4}}) >>> t2 = TreeValue({'a': 11, 'b': 22, 'x': {'c': 33, 'd': 5}}) >>> ssum(1, 2) # 3 >>> ssum(t1, t2) # TreeValue({'a': 12, 'b': 24, 'x': {'c': 36, 'd': 9}}) """ def _decorator(func): _treelized = _c_func_treelize(mode, return_type, inherit, missing, delayed, subside, rise)(func) @wraps(func) def _new_func(*args, **kwargs): return _treelized(*args, **kwargs) return _new_func return _decorator
#: Default value of the ``return_type`` arguments \ #: of ``method_treelize`` and ``classmethod_treelize``, \ #: which means return type will be auto configured to #: the current class. AUTO_DETECT_RETURN_TYPE = SingletonMark("auto_detect_return_type")
[docs]def method_treelize(mode: str = 'strict', return_type: Optional[Type[TreeClassType_]] = AUTO_DETECT_RETURN_TYPE, inherit: bool = True, missing: Union[Any, Callable] = MISSING_NOT_ALLOW, delayed: bool = False, subside: Union[Mapping, bool, None] = None, rise: Union[Mapping, bool, None] = None, self_copy: bool = False): """ Overview: Wrap a common instance method to tree-supported method. Attention: - This decorator can only used to instance method, usage with class method may cause unconditional fatal. - When decorated instance method is called, the `self` argument will be no longer the class instance, \ but the single element of the tree instead. Arguments: - mode (:obj:`str`): Mode of the wrapping, default is `strict`. - return_type (:obj:`Optional[Type[TreeClassType_]]`): Return type of the wrapped function, \ default is `AUTO_DETECT_RETURN_VALUE`, which means automatically use the decorated method's class. - inherit (:obj:`bool`): Allow inheriting in wrapped function, default is `True`. - missing (:obj:`Union[Any, Callable]`): Missing value or lambda generator of when missing, \ default is `MISSING_NOT_ALLOW`, which means raise `KeyError` when missing detected. - delayed (:obj:`bool`): Enable delayed mode or not, the calculation will be delayed when enabled, \ default is ``False``, which means to all the calculation at once. - subside (:obj:`Union[Mapping, bool, None]`): Subside enabled to function's arguments or not, \ and subside configuration, default is `None` which means do not use subside. \ When subside is `True`, it will use all the default arguments in `subside` function. - rise (:obj:`Union[Mapping, bool, None]`): Rise enabled to function's return value or not, \ and rise configuration, default is `None` which means do not use rise. \ When rise is `True`, it will use all the default arguments in `rise` function. \ (Not recommend to use auto mode when your return structure is not so strict.) - self_copy (:obj:`bool`): Self copy mode, if enabled, the result data will be copied to \ ``self`` argument and ``self`` will be returned as result. Default is ``False``, \ which means do not do self copy. Returns: - decorator (:obj:`Callable`): Wrapper for tree-supported method. Example: >>> class MyTreeValue(TreeValue): >>> @method_treelize() >>> def append(self, *args): >>> return sum([self, *args]) # the self will be the integers, not MyTreeValue >>> >>> t1 = MyTreeValue({'a': 1, 'b': 2, 'x': {'c': 3, 'd': 4}}) >>> t2 = MyTreeValue({'a': 11, 'b': 22, 'x': {'c': 33, 'd': 5}}) >>> t1.append(2) # MyTreeValue({'a': 3, 'b': 4, 'x': {'c': 5, 'd': 6}}) >>> t1.append(t2) # MyTreeValue({'a': 12, 'b': 24, 'x': {'c': 36, 'd': 9}}) """ if return_type is AUTO_DETECT_RETURN_TYPE: def _get_self_class(self): return self.__class__ else: def _get_self_class(self): return return_type if self_copy and rise is not None: warnings.warn(UserWarning(f'The rise configuration {repr(rise)} will be ignored ' f'due to the enable of the self_copy option.'), stacklevel=2) rise = None def _decorator(method): _treelized = _c_func_treelize(mode, _get_self_class, inherit, missing, delayed, subside, rise)(method) @wraps(method) def _new_method(self, *args, **kwargs): _result = _treelized(self, *args, **kwargs) if self_copy: self._detach().copy_from(_result._detach()) return self else: return _result return _new_method return _decorator
[docs]def classmethod_treelize(mode: str = 'strict', return_type: Optional[Type[TreeClassType_]] = AUTO_DETECT_RETURN_TYPE, inherit: bool = True, missing: Union[Any, Callable] = MISSING_NOT_ALLOW, delayed: bool = False, subside: Union[Mapping, bool, None] = None, rise: Union[Mapping, bool, None] = None): """ Overview: Wrap a common class method to tree-supported method. Attention: - This decorator can only used to class method, usage with instance method may cause unconditional fatal. - When decorated instance method is called, the `cls` argument will still be the calling class. Arguments: - mode (:obj:`str`): Mode of the wrapping, default is `strict`. - return_type (:obj:`Optional[Type[TreeClassType_]]`): Return type of the wrapped function, \ default is `AUTO_DETECT_RETURN_VALUE`, which means automatically use the decorated method's class. - inherit (:obj:`bool`): Allow inheriting in wrapped function, default is `True`. - missing (:obj:`Union[Any, Callable]`): Missing value or lambda generator of when missing, \ default is `MISSING_NOT_ALLOW`, which means raise `KeyError` when missing detected. - delayed (:obj:`bool`): Enable delayed mode or not, the calculation will be delayed when enabled, \ default is ``False``, which means to all the calculation at once. - subside (:obj:`Union[Mapping, bool, None]`): Subside enabled to function's arguments or not, \ and subside configuration, default is `None` which means do not use subside. \ When subside is `True`, it will use all the default arguments in `subside` function. - rise (:obj:`Union[Mapping, bool, None]`): Rise enabled to function's return value or not, \ and rise configuration, default is `None` which means do not use rise. \ When rise is `True`, it will use all the default arguments in `rise` function. \ (Not recommend to use auto mode when your return structure is not so strict.) Returns: - decorator (:obj:`Callable`): Wrapper for tree-supported class method. Example: >>> class TestUtils: >>> @classmethod >>> @classmethod_treelize(return_type=TreeValue) >>> def add(cls, a, b): >>> return cls, a + b >>> >>> TestUtils.add( >>> TreeValue({'a': 1, 'b': 2}), >>> TreeValue({'a': 11, 'b': 23}), >>> ) # TreeValue({'a': (TestUtils, 12), 'b': (TestUtils, 25)}) """ if return_type is AUTO_DETECT_RETURN_TYPE: def _get_cls_class(cls): return cls else: def _get_cls_class(cls): return return_type return func_treelize(mode, _get_cls_class, inherit, missing, delayed, subside, rise)