"""
Provides :py:class:`CasesAction` action class
It provides several assignable conditional expression
"""
from typing import Any, Mapping, Optional, TypeVar, Union, cast
from dataclasses import dataclass
from .core import LazyAction, LazyNS, evaluate, update, repr_
from .call import lazy_call
from .lazy import Lazy
@dataclass
class CasesAction(LazyAction):
"""Cases action"""
__slots__ = ('condition', 'cases', 'default')
condition: Any
"""Condition"""
cases: Mapping[Any, Any]
"""Condition to value mapping"""
default: Any
"""Default value when no case is matched"""
def __str__(self) -> str:
condition = repr_(self.condition)
if len(self.cases) == 1:
if condition[:5] == 'bool(' and condition[-1] == ')':
condition = condition[5:-1]
elif condition[:8] == 'is_none(' and condition[-1] == ')':
if condition[8:-1] == repr_(self.default):
return f'Ensure({condition[8:-1]})'
cond, value = tuple(self.cases.items())[0]
if cond is True:
cond_ = ''
else:
cond_ = f' == {repr_(cond)}'
if self.default is None:
return f'If({condition}{cond_}, {repr_(value)})'
return (f'IfThenElse({condition}{cond_}, '
f'{repr_(value)}, {repr_(self.default)})')
return (f'Case({condition}, {{' +
', '.join(f'{repr_(cond)}: {repr_(value)}'
for cond, value in self.cases.items()) +
f'}}, {repr_(self.default)})')
def evaluate(self, namespace: LazyNS) -> Any:
cond = evaluate(self.condition, namespace)
for key, value in self.cases.items():
if evaluate(key, namespace) == cond:
return evaluate(value, namespace)
return evaluate(self.default, namespace)
def update(self, val: Any, namespace: LazyNS) -> None:
cond = evaluate(self.condition, namespace)
for key, value in self.cases.items():
if evaluate(key, namespace) == cond:
update(value, val, namespace)
break
else:
update(self.default, val, namespace)
_T = TypeVar('_T')
_U = TypeVar('_U')
# pylint: disable=invalid-name
_bool = lazy_call(bool)
[docs]def If(cond: bool, value: _T) -> Optional[_T]:
"""value if cond else None"""
return cast(_T, Lazy.create(action=CasesAction(_bool(cond), {True: value}, None)))
[docs]def IfThenElse(cond: bool, true: _T, false: _U) -> Union[_T, _U]:
"""true if cond else false"""
return cast(_T, Lazy.create(action=CasesAction(_bool(cond), {True: true}, false)))
[docs]def Case(cond: _T, cases: Mapping[_T, _U], default: _U) -> _U:
"""cases.get(cond, default)"""
return cast(_U, Lazy.create(action=CasesAction(cond, cases, default)))
[docs]@lazy_call
def is_none(obj: Any) -> bool:
"""obj is None"""
return obj is None
[docs]def Ensure(obj: Optional[_T], default: _T) -> _T:
"""obj if obj is not None else default"""
return cast(_T, Lazy.create(action=CasesAction(is_none(obj), {True: default}, obj)))
# pylint: enable=invalid-name
__all__ = ('If', 'IfThenElse', 'Case', 'is_none', 'Ensure')