from functools import lru_cache
from functools import wraps, partial
from typing import Mapping, Optional, Any, Type, TypeVar, Union, Callable, Tuple
from graphviz import Digraph
from hbutils.reflection import dynamic_call, raising
from ..func import method_treelize, MISSING_NOT_ALLOW, func_treelize
from ..tree import TreeValue, jsonify, clone, typetrans, mapping, mask, filter_, reduce_, union, graphics
from ..tree import rise as rise_func
from ..tree import subside as subside_func
_BASE_GENERATION_CONFIG = {}
[docs]def general_tree_value(base: Optional[Mapping[str, Any]] = None,
methods: Optional[Mapping[str, Any]] = None):
"""
Overview:
Get general tree value class.
Arguments:
- base (:obj:`Optional[Mapping[str, Any]]`): Base configuration of `func_treelize`.
- methods (:obj:`Optional[Mapping[str, Any]]`): Method configurations of `func_treelize`.
Returns:
- clazz (:obj:`Type[TreeValue]`): General tree value class.
"""
base = base or {}
methods = methods or {}
def _dynamic_suffix_dec(func, f):
return wraps(func)(dynamic_call(f))
@lru_cache()
def _get_decorator(name, treelize: bool, ext_cfg: Optional[tuple] = None):
_item = methods.get(name, None)
if treelize and isinstance(_item or {}, dict):
_config = _BASE_GENERATION_CONFIG.copy()
_config.update(base)
_config.update(_item or {})
_config.update(dict(ext_cfg or ()))
return lambda func: method_treelize(**_config)(func)
elif isinstance(_item, BaseException) or (isinstance(_item, type) and issubclass(_item, BaseException)):
return lambda func: _dynamic_suffix_dec(func, raising(_item))
elif hasattr(_item, '__call__'):
return lambda func: _dynamic_suffix_dec(func, _item)
elif name in methods.keys():
return lambda func: _dynamic_suffix_dec(func, lambda: methods[name])
else:
return lambda func: func
def _decorate(func, treelize: bool, ext_cfg: Optional[dict] = None):
return _get_decorator(func.__name__, treelize, tuple(sorted((ext_cfg or {}).items())))(func)
_decorate_treelize = partial(_decorate, treelize=True)
_decorate_method = partial(_decorate, treelize=False)
_decorate_and_replace = partial(_decorate, treelize=True, ext_cfg=dict(self_copy=True))
_TreeValue = TypeVar("_TreeValue", bound=TreeValue)
# noinspection PyUnresolvedReferences,PyMethodFirstArgAssignment
class _GeneralTreeValue(TreeValue):
@method_treelize()
def _attr_extern(self, key):
"""
Overview:
External protected function for support the unfounded attributes. \
In `FastTreeValue` it is extended to support the access to values' attribute.
Arguments:
- key (:obj:`str`): Attribute name.
Returns:
- return (:obj:): TreeValue of the values' attribute.
Example:
>>> class Container:
>>> def __init__(self, value):
>>> self.__value = value
>>>
>>> @property
>>> def value(self):
>>> return self.__value
>>>
>>> def append(self, v):
>>> return self.__value + v
>>>
>>> t = FastTreeValue({'a': Container(1), 'b': Container(2)})
>>> t.value # FastTreeValue({'a': 1, 'b': 2})
>>> t.append # FastTreeValue({'a': <method 'append' of Container(1)>, 'b': <method 'append' of Container(2)>})
"""
return getattr(self, key)
@_decorate_method
def json(self):
"""
Overview:
Dump current `TreeValue` object to json data.
Returns:
- json (:obj:`dict`): Dumped json data.
Example:
>>> t = FastTreeValue({'a': 1, 'b': 2, 'x': {'c': 3, 'd': 4}})
>>> t.json() # {'a': 1, 'b': 2, 'x': {'c': 3, 'd': 4}}
"""
return jsonify(self)
@_decorate_method
def clone(self, copy_value: Union[None, bool, Callable, Any] = None):
"""
Overview:
Create a fully clone of the current tree.
Returns:
- tree (:obj:`_TreeValue`): Cloned tree value object.
- copy_value (:obj:`Union[None, bool, Callable, Any]`): Deep copy value or not, \
default is `None` which means do not deep copy the values. \
If deep copy is required, just set it to `True`.
Example:
>>> t = FastTreeValue({'a': 1, 'b': 2, 'x': {'c': 3, 'd': 4}})
>>> t.x.clone() # FastTreeValue({'c': 3, 'd': 4})
"""
return clone(self, copy_value)
@_decorate_method
def type(self, clazz: Type[_TreeValue]) -> _TreeValue:
"""
Overview:
Transform tree value object to another tree value type. \
Attention that in this function, no copy will be made, \
the original tree value and the transformed tree value are using the same space area.
Arguments:
- return_type (:obj:`Type[_TreeValue]`): Target tree value type
Returns:
- tree (:obj:`_TreeValue`): Transformed tree value object.
Example:
>>> t = FastTreeValue({'a': 1, 'b': 2, 'x': {'c': 3, 'd': 4}})
>>> t.type(TreeValue) # TreeValue({'a': 1, 'b': 2, 'x': {'c': 3, 'd': 4}})
"""
return typetrans(self, clazz)
@_decorate_method
def map(self, mapper, delayed=False):
"""
Overview:
Do mapping on every value in this tree.
Arguments:
- func (:obj:): Function for mapping
- delayed (:obj:`bool`): Enable delayed mode for this mapping.
Returns:
- tree (:obj:`_TreeValue`): Mapped tree value object.
Example:
>>> t = FastTreeValue({'a': 1, 'b': 2, 'x': {'c': 3, 'd': 4}})
>>> t.map(lambda x: x + 2) # FastTreeValue({'a': 3, 'b': 4, 'x': {'c': 5, 'd': 6}})
>>> t.map(lambda: 1) # FastTreeValue({'a': 1, 'b': 1, 'x': {'c': 1, 'd': 1}})
>>> t.map(lambda x, p: p) # FastTreeValue({'a': ('a',), 'b': ('b',), 'x': {'c': ('x', 'c'), 'd': ('x', 'd')}})
"""
return mapping(self, mapper, delayed)
@_decorate_method
def mask(self, mask_: TreeValue, remove_empty: bool = True):
"""
Overview:
Filter the element in the tree with a mask
Arguments:
- `mask_` (:obj:`TreeValue`): Tree value mask object
- `remove_empty` (:obj:`bool`): Remove empty tree node automatically, default is `True`.
Returns:
- tree (:obj:`_TreeValue`): Filtered tree value object.
Example:
>>> t = FastTreeValue({'a': 1, 'b': 2, 'x': {'c': 3, 'd': 4}})
>>> t.mask(TreeValue({'a': True, 'b': False, 'x': False})) # FastTreeValue({'a': 1})
>>> t.mask(TreeValue({'a': True, 'b': False, 'x': {'c': True, 'd': False}})) # FastTreeValue({'a': 1, 'x': {'c': 3}})
"""
return mask(self, mask_, remove_empty)
@_decorate_method
def filter(self, func, remove_empty: bool = True):
"""
Overview:
Filter the element in the tree with a predict function.
Arguments:
- func (:obj:): Function for filtering
- remove_empty (:obj:`bool`): Remove empty tree node automatically, default is `True`.
Returns:
- tree (:obj:`_TreeValue`): Filtered tree value object.
Example:
>>> t = FastTreeValue({'a': 1, 'b': 2, 'x': {'c': 3, 'd': 4}})
>>> t.filter(lambda x: x < 3) # FastTreeValue({'a': 1, 'b': 2})
>>> t.filter(lambda x: x < 3, False) # FastTreeValue({'a': 1, 'b': 2, 'x': {}})
>>> t.filter(lambda x: x % 2 == 1) # FastTreeValue({'a': 1, 'x': {'c': 3}})
>>> t.filter(lambda x, p: p[0] in {'b', 'x'}) # FastTreeValue({'b': 2, 'x': {'c': 3, 'd': 4}})
"""
return filter_(self, func, remove_empty)
@_decorate_method
def reduce(self, func):
"""
Overview
Reduce the tree to value.
Arguments:
- func (:obj:): Function for reducing
Returns:
- result (:obj:): Reduce result
Examples:
>>> from functools import reduce
>>>
>>> t = FastTreeValue({'a': 1, 'b': 2, 'x': {'c': 3, 'd': 4}})
>>> t.reduce(lambda **kwargs: sum(kwargs.values())) # 10, 1 + 2 + (3 + 4)
>>> t.reduce(lambda **kwargs: reduce(lambda x, y: x * y, list(kwargs.values()))) # 24, 1 * 2 * (3 * 4)
"""
return reduce_(self, func)
@_decorate_method
def rise(self, dict_: bool = True, list_: bool = True, tuple_: bool = True, template=None):
"""
Overview:
Make the structure (dict, list, tuple) in value rise up to the top, above the tree value.
Arguments:
- `dict_` (:obj:`bool`): Enable dict rise, default is `True`.
- `list_` (:obj:`bool`): Enable list rise, default is `True`.
- `tuple_` (:obj:`bool`): Enable list rise, default is `True`.
- template (:obj:): Rising template, default is `None`, which means auto detect.
Returns:
- risen (:obj:): Risen value.
Example:
>>> t = FastTreeValue({'x': raw({'a': [1, 2], 'b': [2, 3]}), 'y': raw({'a': [5, 6, 7], 'b': [7, 8]})})
>>> dt = t.rise()
>>> # dt will be {'a': <FastTreeValue 1>, 'b': [<FastTreeValue 2>, <FastTreeValue 3>]}
>>> # FastTreeValue 1 will be FastTreeValue({'x': [1, 2], 'y': [5, 6, 7]})
>>> # FastTreeValue 2 will be FastTreeValue({'x': 2, 'y': 7})
>>> # FastTreeValue 3 will be FastTreeValue({'x': 3, 'y': 8})
>>>
>>> t2 = FastTreeValue({'x': raw({'a': [1, 2], 'b': [2, 3]}), 'y': raw({'a': [5, 6], 'b': [7, 8]})})
>>> dt2 = t2.rise()
>>> # dt2 will be {'a': [<FastTreeValue 1>, <FastTreeValue 2>], 'b': [<FastTreeValue 3>, <FastTreeValue 4>]}
>>> # FastTreeValue 1 will be FastTreeValue({'x': 1, 'y': 5})
>>> # FastTreeValue 2 will be FastTreeValue({'x': 2, 'y': 6})
>>> # FastTreeValue 3 will be FastTreeValue({'x': 2, 'y': 7})
>>> # FastTreeValue 4 will be FastTreeValue({'x': 3, 'y': 8})
>>>
>>> dt3 = t2.rise(template={'a': None, 'b': None})
>>> # dt3 will be {'a': <FastTreeValue 1>, 'b': <FastTreeValue 2>}
>>> # FastTreeValue 1 will be FastTreeValue({'x': [1, 2], 'y': [5, 6]})
>>> # FastTreeValue 2 will be FastTreeValue({'x': [2, 3], 'y': [7, 8]})
"""
return rise_func(self, dict_, list_, tuple_, template)
@_decorate_method
def graph(self, root: Optional[str] = None, title: Optional[str] = None,
cfg: Optional[dict] = None,
dup_value: Union[bool, Callable, type, Tuple[Type, ...]] = False,
repr_gen: Optional[Callable] = None,
node_cfg_gen: Optional[Callable] = None,
edge_cfg_gen: Optional[Callable] = None) -> Digraph:
"""
Overview:
Draw graph of this tree value.
Args:
- root (:obj:`Optional[str]`): Root name of the graph, default is ``None``, \
this name will be automatically generated.
- title (:obj:`Optional[str]`): Title of the graph, default is ``None``, \
this title will be automatically generated from ``root`` argument.
- cfg (:obj:`Optional[dict]`): Configuration of the graph.
- dup_value (:obj:`Union[bool, Callable, type, Tuple[Type, ...]]`): Value duplicator, \
set `True` to make value with same id use the same node in graph, \
you can also define your own node id algorithm by this argument. \
Default is `False` which means do not use value duplicator.
- repr_gen (:obj:`Optional[Callable]`): Representation format generator, \
default is `None` which means using `repr` function.
- node_cfg_gen (:obj:`Optional[Callable]`): Node configuration generator, \
default is `None` which means no configuration.
- edge_cfg_gen (:obj:`Optional[Callable]`): Edge configuration generator, \
default is `None` which means no configuration.
Returns:
- graph (:obj:`Digraph`): Generated graph of tree values.
"""
root = root or ('<%s #%x>' % (type(self).__name__, id(self._detach())))
title = title or ('Graph of tree %s.' % (root,))
return graphics(
(self, root), title=title, cfg=cfg, dup_value=dup_value,
repr_gen=repr_gen, node_cfg_gen=node_cfg_gen, edge_cfg_gen=edge_cfg_gen,
)
@classmethod
@_decorate_method
def func(cls, mode: str = 'strict', 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 based on this type.
Arguments:
- mode (:obj:`str`): Mode of the wrapping, default is `strict`.
- inherit (:obj:`bool`): Allow inherit 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:
>>> from treevalue import FastTreeValue
>>>
>>> @FastTreeValue.func()
>>> 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) # FastTreeValue({'a': 12, 'b': 24, 'x': {'c': 36, 'd': 9}})
"""
return func_treelize(mode, cls, inherit, missing, delayed, subside, rise)
@classmethod
@_decorate_method
def union(cls, *trees, return_type=None, **kwargs):
"""
Overview:
Union tree values together.
Arguments:
- trees (:obj:`_TreeValue`): Tree value objects.
- mode (:obj:): Mode of the wrapping, default is `strict`.
- return_type (:obj:`Optional[Type[_ClassType]]`): Return type of the wrapped function, default is `TreeValue`.
- inherit (:obj:`bool`): Allow inherit in wrapped function, default is `True`.
- missing (:obj:): Missing value or lambda generator of when missing, default is `MISSING_NOT_ALLOW`, which \
means raise `KeyError` when missing detected.
Returns:
- result (:obj:`TreeValue`): Unionised tree value.
Example:
>>> t = FastTreeValue({'a': 1, 'b': 2, 'x': {'c': 3, 'd': 4}})
>>> tx = t.map(lambda v: v % 2 == 1)
>>> FastTreeValue.union(t, tx) # FastTreeValue({'a': (1, True), 'b': (2, False), 'x': {'c': (3, True), 'd': (4, False)}})
"""
return union(*trees, return_type=return_type or cls, **kwargs)
@classmethod
@_decorate_method
def subside(cls, value, dict_: bool = True, list_: bool = True, tuple_: bool = True,
return_type: Optional[Type[_TreeValue]] = None, **kwargs):
"""
Overview:
Drift down the structures (list, tuple, dict) down to the tree's value.
Arguments:
- value (:obj:): Original value object, may be nested dict, list or tuple.
- `dict_` (:obj:`bool`): Enable dict subside, default is `True`.
- `list_` (:obj:`bool`): Enable list subside, default is `True`.
- `tuple_` (:obj:`bool`): Enable list subside, default is `True`.
- mode (:obj:): Mode of the wrapping, default is `strict`.
- return_type (:obj:`Optional[Type[_ClassType]]`): Return type of the wrapped function, \
will be auto detected when there is exactly one tree value type in this original value, \
otherwise the default will be `TreeValue`.
- inherit (:obj:`bool`): Allow inherit in wrapped function, default is `True`.
- missing (:obj:): Missing value or lambda generator of when missing, default is `MISSING_NOT_ALLOW`, which \
means raise `KeyError` when missing detected.
Returns:
- return (:obj:`_TreeValue`): Subsided tree value.
Example:
>>> data = {
>>> 'a': TreeValue({'a': 1, 'b': 2}),
>>> 'x': {
>>> 'c': TreeValue({'a': 3, 'b': 4}),
>>> 'd': [
>>> TreeValue({'a': 5, 'b': 6}),
>>> TreeValue({'a': 7, 'b': 8}),
>>> ]
>>> },
>>> 'k': '233'
>>> }
>>>
>>> tree = FastTreeValue.subside(data)
>>> # tree should be --> FastTreeValue({
>>> # 'a': raw({'a': 1, 'k': '233', 'x': {'c': 3, 'd': [5, 7]}}),
>>> # 'b': raw({'a': 2, 'k': '233', 'x': {'c': 4, 'd': [6, 8]}}),
>>> #}), all structures above the tree values are subsided to the bottom of the tree.
"""
return subside_func(value, dict_, list_, tuple_,
return_type=return_type or cls, **kwargs)
@classmethod
@_decorate_method
def graphics(cls, *trees, title: Optional[str] = None, cfg: Optional[dict] = None,
dup_value: Union[bool, Callable, type, Tuple[Type, ...]] = False,
repr_gen: Optional[Callable] = None,
node_cfg_gen: Optional[Callable] = None,
edge_cfg_gen: Optional[Callable] = None) -> Digraph:
"""
Overview:
Draw graph by tree values.
Multiple tree values is supported.
Args:
- trees: Given tree values, tuples of `Tuple[TreeValue, str]` or tree values are both accepted.
- title (:obj:`Optional[str]`): Title of the graph.
- cfg (:obj:`Optional[dict]`): Configuration of the graph.
- dup_value (:obj:`Union[bool, Callable, type, Tuple[Type, ...]]`): Value duplicator, \
set `True` to make value with same id use the same node in graph, \
you can also define your own node id algorithm by this argument. \
Default is `False` which means do not use value duplicator.
- repr_gen (:obj:`Optional[Callable]`): Representation format generator, \
default is `None` which means using `repr` function.
- node_cfg_gen (:obj:`Optional[Callable]`): Node configuration generator, \
default is `None` which means no configuration.
- edge_cfg_gen (:obj:`Optional[Callable]`): Edge configuration generator, \
default is `None` which means no configuration.
Returns:
- graph (:obj:`Digraph`): Generated graph of tree values.
"""
return graphics(
*trees, title=title, cfg=cfg, dup_value=dup_value,
repr_gen=repr_gen, node_cfg_gen=node_cfg_gen, edge_cfg_gen=edge_cfg_gen,
)
@_decorate_treelize
def __add__(self, other):
"""
Overview:
Add tree values together.
Example:
>>> t1 = FastTreeValue({'a': 1, 'b': 2, 'x': {'c': 3, 'd': 4}})
>>> t2 = FastTreeValue({'a': 11, 'b': 22, 'x': {'c': 30, 'd': 40}})
>>> t1 + t2 # FastTreeValue({'a': 12, 'b': 24, 'x': {'c': 33, 'd': 44}})
"""
return self + other
@_decorate_treelize
def __radd__(self, other):
"""
Overview:
Right version of `__add__`.
Example:
>>> t1 = FastTreeValue({'a': 1, 'b': 2, 'x': {'c': 3, 'd': 4}})
>>> 1 + t1 # FastTreeValue({'a': 2, 'b': 3, 'x': {'c': 4, 'd': 5}})
"""
return other + self
@_decorate_and_replace
def __iadd__(self, other):
"""
Overview:
Self version of `__add__`.
Original id of self will be kept.
Example:
>>> t1 = FastTreeValue({'a': 1, 'b': 2, 'x': {'c': 3, 'd': 4}})
>>> t2 = FastTreeValue({'a': 11, 'b': 22, 'x': {'c': 30, 'd': 40}})
>>> t1 += t2
>>> t1 # t1's id will not change, FastTreeValue({'a': 12, 'b': 24, 'x': {'c': 33, 'd': 44}})
"""
self += other
return self
@_decorate_treelize
def __sub__(self, other):
"""
Overview:
Substract tree values.
Example:
>>> t1 = FastTreeValue({'a': 1, 'b': 2, 'x': {'c': 3, 'd': 4}})
>>> t2 = FastTreeValue({'a': 11, 'b': 22, 'x': {'c': 30, 'd': 40}})
>>> t1 - t2 # FastTreeValue({'a': -10, 'b': -20, 'x': {'c': -27, 'd': -36}})
"""
return self - other
@_decorate_treelize
def __rsub__(self, other):
"""
Overview:
Right version of `__sub__`.
Example:
>>> t1 = FastTreeValue({'a': 1, 'b': 2, 'x': {'c': 3, 'd': 4}})
>>> 1 - t1 # FastTreeValue({'a': 0, 'b': -1, 'x': {'c': -2, 'd': -3}})
"""
return other - self
@_decorate_and_replace
def __isub__(self, other):
"""
Overview:
Self version of `__sub__`.
Original id of self will be kept.
Example:
>>> t1 = FastTreeValue({'a': 1, 'b': 2, 'x': {'c': 3, 'd': 4}})
>>> t2 = FastTreeValue({'a': 11, 'b': 22, 'x': {'c': 30, 'd': 40}})
>>> t1 -= t2
>>> t1 # t1's id will not change, FastTreeValue({'a': -10, 'b': -20, 'x': {'c': -27, 'd': -36}})
"""
self -= other
return self
@_decorate_treelize
def __mul__(self, other):
"""
Overview:
Multiply tree values together.
Example:
>>> t1 = FastTreeValue({'a': 1, 'b': 2, 'x': {'c': 3, 'd': 4}})
>>> t2 = FastTreeValue({'a': 11, 'b': 22, 'x': {'c': 30, 'd': 40}})
>>> t1 * t2 # FastTreeValue({'a': 11, 'b': 44, 'x': {'c': 90, 'd': 160}})
"""
return self * other
@_decorate_treelize
def __rmul__(self, other):
"""
Overview:
Right version of `__mul__`.
Example:
>>> t1 = FastTreeValue({'a': 1, 'b': 2, 'x': {'c': 3, 'd': 4}})
>>> 2 * t1 # FastTreeValue({'a': 2, 'b': 4, 'x': {'c': 6, 'd': 8}})
"""
return other * self
@_decorate_and_replace
def __imul__(self, other):
"""
Overview:
Self version of `__mul__`.
Original id of self will be kept.
Example:
>>> t1 = FastTreeValue({'a': 1, 'b': 2, 'x': {'c': 3, 'd': 4}})
>>> t2 = FastTreeValue({'a': 11, 'b': 22, 'x': {'c': 30, 'd': 40}})
>>> t1 *= t2
>>> t1 # t1's id will not change, FastTreeValue({'a': 11, 'b': 44, 'x': {'c': 90, 'd': 160}})
"""
self *= other
return self
@_decorate_treelize
def __matmul__(self, other):
"""
Overview:
Matrix tree values together, can be used in numpy or torch.
"""
return self @ other
@_decorate_treelize
def __rmatmul__(self, other):
"""
Overview:
Right version of `__matmul__`.
"""
return other @ self
@_decorate_and_replace
def __imatmul__(self, other):
"""
Overview:
Self version of `__matmul__`.
Original id of self will be kept.
"""
self @= other
return self
@_decorate_treelize
def __truediv__(self, other):
"""
Overview:
True divide tree values.
Example:
>>> t1 = FastTreeValue({'a': 1, 'b': 2, 'x': {'c': 3, 'd': 4}})
>>> t2 = FastTreeValue({'a': 10, 'b': 25, 'x': {'c': 30, 'd': 40}})
>>> t1 / t2 # FastTreeValue({'a': 0.1, 'b': 0.08, 'x': {'c': 0.1, 'd': 0.1}})
"""
return self / other
@_decorate_treelize
def __rtruediv__(self, other):
"""
Overview:
Right version of `__truediv__`.
Example:
>>> t1 = FastTreeValue({'a': 1, 'b': 2, 'x': {'c': 3, 'd': 4}})
>>> 6 / t1 # FastTreeValue({'a': 6, 'b': 3, 'x': {'c': 2, 'd': 1.5}})
"""
return other / self
@_decorate_and_replace
def __itruediv__(self, other):
"""
Overview:
Self version of `__truediv__`.
Original id of self will be kept.
Example:
>>> t1 = FastTreeValue({'a': 1, 'b': 2, 'x': {'c': 3, 'd': 4}})
>>> t2 = FastTreeValue({'a': 10, 'b': 25, 'x': {'c': 30, 'd': 40}})
>>> t1 /= t2
>>> t1 # t1's id will not change, FastTreeValue({'a': 0.1, 'b': 0.08, 'x': {'c': 0.1, 'd': 0.1}})
"""
self /= other
return self
@_decorate_treelize
def __floordiv__(self, other):
"""
Overview:
Floor divide tree values.
Example:
>>> t1 = FastTreeValue({'a': 1, 'b': 2, 'x': {'c': 3, 'd': 4}})
>>> t2 = FastTreeValue({'a': 10, 'b': 25, 'x': {'c': 30, 'd': 40}})
>>> t2 // t1 # FastTreeValue({'a': 10, 'b': 12, 'x': {'c': 10, 'd': 10}})
"""
return self // other
@_decorate_treelize
def __rfloordiv__(self, other):
"""
Overview:
Right version of `__floordiv__`.
Example:
>>> t1 = FastTreeValue({'a': 1, 'b': 2, 'x': {'c': 3, 'd': 4}})
>>> 6 // t1 # FastTreeValue({'a': 6, 'b': 3, 'x': {'c': 2, 'd': 1}})
"""
return other // self
@_decorate_and_replace
def __ifloordiv__(self, other):
"""
Overview:
Self version of `__floordiv__`.
Original id of self will be kept.
Example:
>>> t1 = FastTreeValue({'a': 1, 'b': 2, 'x': {'c': 3, 'd': 4}})
>>> t2 = FastTreeValue({'a': 10, 'b': 25, 'x': {'c': 30, 'd': 40}})
>>> t2 //= t1
>>> t2 # t2's id will not change, FastTreeValue({'a': 10, 'b': 12, 'x': {'c': 10, 'd': 10}})
"""
self //= other
return self
@_decorate_treelize
def __mod__(self, other):
"""
Overview:
Mod tree values.
Example:
>>> t1 = FastTreeValue({'a': 1, 'b': 2, 'x': {'c': 3, 'd': 4}})
>>> t2 = FastTreeValue({'a': 10, 'b': 25, 'x': {'c': 30, 'd': 40}})
>>> t2 % t1 # FastTreeValue({'a': 0, 'b': 1, 'x': {'c': 0, 'd': 0}})
"""
return self % other
@_decorate_treelize
def __rmod__(self, other):
"""
Overview:
Right version of `__mod__`.
Example:
>>> t1 = FastTreeValue({'a': 1, 'b': 2, 'x': {'c': 3, 'd': 4}})
>>> 6 % t1 # FastTreeValue({'a': 0, 'b': 0, 'x': {'c': 0, 'd': 2}})
"""
return other % self
@_decorate_and_replace
def __imod__(self, other):
"""
Overview:
Self version of `__mod__`.
Original id of self will be kept.
Example:
>>> t1 = FastTreeValue({'a': 1, 'b': 2, 'x': {'c': 3, 'd': 4}})
>>> t2 = FastTreeValue({'a': 10, 'b': 25, 'x': {'c': 30, 'd': 40}})
>>> t2 %= t1
>>> t2 # t2's id will not change, FastTreeValue({'a': 0, 'b': 1, 'x': {'c': 0, 'd': 0}})
"""
self %= other
return self
@_decorate_treelize
def __pow__(self, power):
"""
Overview:
Mod tree values.
Example:
>>> t1 = FastTreeValue({'a': 1, 'b': 2, 'x': {'c': 3, 'd': 4}})
>>> t2 = FastTreeValue({'a': 2, 'b': 3, 'x': {'c': 4, 'd': 5}})
>>> t1 ** t2 # FastTreeValue({'a': 1, 'b': 8, 'x': {'c': 81, 'd': 1024}})
"""
return self ** power
@_decorate_treelize
def __rpow__(self, other):
"""
Overview:
Right version of `__pow__`.
Example:
>>> t1 = FastTreeValue({'a': 1, 'b': 2, 'x': {'c': 3, 'd': 4}})
>>> 2 ** t1 # FastTreeValue({'a': 2, 'b': 4, 'x': {'c': 8, 'd': 16}})
"""
return other ** self
@_decorate_and_replace
def __ipow__(self, other):
"""
Overview:
Self version of `__pow__`.
Original id of self will be kept.
Example:
>>> t1 = FastTreeValue({'a': 1, 'b': 2, 'x': {'c': 3, 'd': 4}})
>>> t2 = FastTreeValue({'a': 2, 'b': 3, 'x': {'c': 4, 'd': 5}})
>>> t1 **= t2
>>> t1 # t1's id will not change, FastTreeValue({'a': 1, 'b': 8, 'x': {'c': 81, 'd': 1024}})
"""
self **= other
return self
@_decorate_treelize
def __and__(self, other):
"""
Overview:
Bitwise and tree values.
Example:
>>> t1 = FastTreeValue({'a': 1, 'b': 2, 'x': {'c': 3, 'd': 4}})
>>> t2 = FastTreeValue({'a': 2, 'b': 3, 'x': {'c': 4, 'd': 5}})
>>> t1 & t2 # FastTreeValue({'a': 0, 'b': 2, 'x': {'c': 0, 'd': 4}})
"""
return self & other
@_decorate_treelize
def __rand__(self, other):
"""
Overview:
Right version of `__and__`.
Example:
>>> t1 = FastTreeValue({'a': 1, 'b': 2, 'x': {'c': 3, 'd': 4}})
>>> 5 & t1 # FastTreeValue({'a': 1, 'b': 0, 'x': {'c': 1, 'd': 4}})
"""
return other & self
@_decorate_and_replace
def __iand__(self, other):
"""
Overview:
Self version of `__and__`.
Original id of self will be kept.
Example:
>>> t1 = FastTreeValue({'a': 1, 'b': 2, 'x': {'c': 3, 'd': 4}})
>>> t2 = FastTreeValue({'a': 2, 'b': 3, 'x': {'c': 4, 'd': 5}})
>>> t1 &= t2
>>> t1 # t1's id will not change, FastTreeValue({'a': 0, 'b': 2, 'x': {'c': 0, 'd': 4}})
"""
self &= other
return self
@_decorate_treelize
def __or__(self, other):
"""
Overview:
Bitwise or tree values.
Example:
>>> t1 = FastTreeValue({'a': 1, 'b': 2, 'x': {'c': 3, 'd': 4}})
>>> t2 = FastTreeValue({'a': 2, 'b': 3, 'x': {'c': 4, 'd': 5}})
>>> t1 | t2 # FastTreeValue({'a': 3, 'b': 3, 'x': {'c': 7, 'd': 5}})
"""
return self | other
@_decorate_treelize
def __ror__(self, other):
"""
Overview:
Right version of `__or__`.
Example:
>>> t1 = FastTreeValue({'a': 1, 'b': 2, 'x': {'c': 3, 'd': 4}})
>>> 5 | t1 # FastTreeValue({'a': 5, 'b': 7, 'x': {'c': 7, 'd': 5}})
"""
return other | self
@_decorate_and_replace
def __ior__(self, other):
"""
Overview:
Self version of `__or__`.
Original id of self will be kept.
Example:
>>> t1 = FastTreeValue({'a': 1, 'b': 2, 'x': {'c': 3, 'd': 4}})
>>> t2 = FastTreeValue({'a': 2, 'b': 3, 'x': {'c': 4, 'd': 5}})
>>> t1 |= t2
>>> t1 # t1's id will not change, FastTreeValue({'a': 3, 'b': 3, 'x': {'c': 7, 'd': 5}})
"""
self |= other
return self
@_decorate_treelize
def __xor__(self, other):
"""
Overview:
Bitwise or tree values.
Example:
>>> t1 = FastTreeValue({'a': 1, 'b': 2, 'x': {'c': 3, 'd': 4}})
>>> t2 = FastTreeValue({'a': 2, 'b': 3, 'x': {'c': 4, 'd': 5}})
>>> t1 ^ t2 # FastTreeValue({'a': 3, 'b': 1, 'x': {'c': 7, 'd': 1}})
"""
return self ^ other
@_decorate_treelize
def __rxor__(self, other):
"""
Overview:
Right version of `__xor__`.
Example:
>>> t1 = FastTreeValue({'a': 1, 'b': 2, 'x': {'c': 3, 'd': 4}})
>>> 5 ^ t1 # FastTreeValue({'a': 4, 'b': 7, 'x': {'c': 6, 'd': 1}})
"""
return other ^ self
@_decorate_and_replace
def __ixor__(self, other):
"""
Overview:
Self version of `__xor__`.
Original id of self will be kept.
Example:
>>> t1 = FastTreeValue({'a': 1, 'b': 2, 'x': {'c': 3, 'd': 4}})
>>> t2 = FastTreeValue({'a': 2, 'b': 3, 'x': {'c': 4, 'd': 5}})
>>> t1 ^= t2
>>> t1 # t1's id will not change, FastTreeValue({'a': 3, 'b': 1, 'x': {'c': 7, 'd': 1}})
"""
self ^= other
return self
@_decorate_treelize
def __lshift__(self, other):
"""
Overview:
Left shift tree values.
Example:
>>> t1 = FastTreeValue({'a': 1, 'b': 2, 'x': {'c': 3, 'd': 4}})
>>> t2 = FastTreeValue({'a': 2, 'b': 3, 'x': {'c': 4, 'd': 5}})
>>> t1 << t2 # FastTreeValue({'a': 4, 'b': 16, 'x': {'c': 48, 'd': 128}})
"""
return self << other
@_decorate_treelize
def __rlshift__(self, other):
"""
Overview:
Right version of `__lshift__`.
Example:
>>> t1 = FastTreeValue({'a': 1, 'b': 2, 'x': {'c': 3, 'd': 4}})
>>> 3 << t1 # FastTreeValue({'a': 6, 'b': 12, 'x': {'c': 24, 'd': 48}})
"""
return other << self
@_decorate_and_replace
def __ilshift__(self, other):
"""
Overview:
Self version of `__xor__`.
Original id of self will be kept.
Example:
>>> t1 = FastTreeValue({'a': 1, 'b': 2, 'x': {'c': 3, 'd': 4}})
>>> t2 = FastTreeValue({'a': 2, 'b': 3, 'x': {'c': 4, 'd': 5}})
>>> t1 <<= t2
>>> t1 # t1's id will not change, FastTreeValue({'a': 4, 'b': 16, 'x': {'c': 48, 'd': 128}})
"""
self <<= other
return self
@_decorate_treelize
def __rshift__(self, other):
"""
Overview:
Left shift tree values.
Example:
>>> t1 = FastTreeValue({'a': 1, 'b': 2, 'x': {'c': 3, 'd': 4}})
>>> t2 = FastTreeValue({'a': 20, 'b': 30, 'x': {'c': 40, 'd': 50}})
>>> t2 >> t1 # FastTreeValue({'a': 10, 'b': 7, 'x': {'c': 5, 'd': 3}})
"""
return self >> other
@_decorate_treelize
def __rrshift__(self, other):
"""
Overview:
Right version of `__rshift__`.
Example:
>>> t1 = FastTreeValue({'a': 1, 'b': 2, 'x': {'c': 3, 'd': 4}})
>>> 64 >> t1 # FastTreeValue({'a': 32, 'b': 16, 'x': {'c': 8, 'd': 4}})
"""
return other >> self
@_decorate_and_replace
def __irshift__(self, other):
"""
Overview:
Self version of `__xor__`.
Original id of self will be kept.
Example:
>>> t1 = FastTreeValue({'a': 1, 'b': 2, 'x': {'c': 3, 'd': 4}})
>>> t2 = FastTreeValue({'a': 20, 'b': 30, 'x': {'c': 40, 'd': 50}})
>>> t2 >>= t1
>>> t2 # t2's id will not change, FastTreeValue({'a': 10, 'b': 7, 'x': {'c': 5, 'd': 3}})
"""
self >>= other
return self
@_decorate_treelize
def __pos__(self):
"""
Overview:
Positive tree values.
Examples:
>>> t1 = FastTreeValue({'a': 1, 'b': 2, 'x': {'c': 3, 'd': 4}})
>>> +t1 # FastTreeValue({'a': 1, 'b': 2, 'x': {'c': 3, 'd': 4}})
"""
return +self
@_decorate_treelize
def __neg__(self):
"""
Overview:
Negative tree values.
Examples:
>>> t1 = FastTreeValue({'a': 1, 'b': 2, 'x': {'c': 3, 'd': 4}})
>>> -t1 # FastTreeValue({'a': -1, 'b': -2, 'x': {'c': -3, 'd': -4}})
"""
return -self
@_decorate_treelize
def __invert__(self):
"""
Overview:
Bitwise invert tree values.
Examples:
>>> t1 = FastTreeValue({'a': 1, 'b': -2, 'x': {'c': 3, 'd': -4}})
>>> ~t1 # FastTreeValue({'a': -2, 'b': 1, 'x': {'c': -4, 'd': 3}})
"""
return ~self
@_decorate_treelize
def __getitem__(self, item):
"""
Overview:
Get item of tree values.
Examples:
>>> t1 = FastTreeValue({'a': [1, 2], 'b': [2, 3], 'x': {'c': [3, 4], 'd': [4, 5]}})
>>> t1[0] # FastTreeValue({'a': 1, 'b': 2, 'x': {'c': 3, 'd': 4}})
>>> t1[-1] # FastTreeValue({'a': 2, 'b': 3, 'x': {'c': 4, 'd': 5}})
>>> t1[::-1] # FastTreeValue({'a': [2, 1], 'b': [3, 2], 'x': {'c': [4, 3], 'd': [5, 4]}})
"""
return self[item]
@_decorate_treelize
def __setitem__(self, key, value):
"""
Overview:
Set item of tree values.
Examples:
>>> t1 = FastTreeValue({'a': [1, 2], 'b': [2, 3], 'x': {'c': [3, 4], 'd': [4, 5]}})
>>> t1[0] = -2 # FastTreeValue({'a': [-2, 2], 'b': [-2, 3], 'x': {'c': [-2, 4], 'd': [-2, 5]}})
>>> t1[0] = FastTreeValue({'a': 2, 'b': 3, 'x': {'c': 4, 'd': 5}})
>>> # FastTreeValue({'a': [2, 2], 'b': [3, 3], 'x': {'c': [4, 4], 'd': [5, 5]}})
"""
self[key] = value
@_decorate_treelize
def __delitem__(self, key):
"""
Overview:
Delete item of tree values.
Examples:
>>> t1 = FastTreeValue({'a': [1, 2], 'b': [2, 3], 'x': {'c': [3, 4], 'd': [4, 5]}})
>>> del t1[0] # FastTreeValue({'a': [2], 'b': [3], 'x': {'c': [4], 'd': [5]}})
"""
del self[key]
@_decorate_treelize
def __call__(self, *args, **kwargs):
"""
Overview:
Call of tree values.
Example:
>>> class Container:
>>> def __init__(self, value):
>>> self.__value = value
>>>
>>> def append(self, v):
>>> return self.__value + v
>>>
>>> t = FastTreeValue({'a': Container(1), 'b': Container(2)})
>>> t.append(2) # FastTreeValue({'a': 3, 'b': 4})
>>> t.append(FastTreeValue({'a': 10, 'b': 20})) # FastTreeValue({'a': 11, 'b': 22})
"""
return self(*args, **kwargs)
return _GeneralTreeValue