Source code for larch.reactive.agent

"""reactive agent"""
from .pointer import Pointer, ResolveError, _check_getter_exception
# __pragma__ ('skip')
from .core import rcontext, Container, CellBase
__all__ = ("Agent", "CellAgent", "OldAgent", "old", "cell")
# __pragma__ ('noskip')
# __pragma__ ('ecom')
"""?
from .pcore import rcontext, Container, CellBase
?"""
# __pragma__ ('noecom')


class Agent:
    def __init__(self, src):
        self.__src__ = src

    def __dir__(self):
        return self.__src__.__reactive_cells__.keys()

    def __getattr__(self, name):
        src = self.__src__
        cell = getattr(src.__class__, name)

        if isinstance(cell, Pointer):
            src, getter, setter = cell.__state__.split(src)
            try:
                cell = getter(src.__class__)
            except Exception:
                _check_getter_exception(cell.__state__, ResolveError)

            if not isinstance(cell, CellBase):
                raise TypeError("Attribute does not point to a cell", name)

        return cell.get_container(src)


class CellAgent(Agent):
    """returns cell containers as attributes"""

    def __setattr__(self, name, value):
        if name == "__src__":
            super().__setattr__(name, value)
        else:
            if isinstance(value, Container):
                cell = getattr(self.__src__.__class__, name)
                cell.set_container(self.__src__, value)
            else:
                raise TypeError("%r must be of type container" % value)


class OldAgent(Agent):
    """returns old cell values as attributes"""

    def __getattr__(self, name):
        try:
            container = super().__getattr__(name)
        except AttributeError:
            return getattr(self.__src__, name)

        # the default container.get_value() also touches the container
        return rcontext.old_values.get(id(container), container.get_value())


def _get_holder_cell(obj):
    holder, getter, setter = obj.__state__.split()
    try:
        return holder, getter(holder.__class__)
    except Exception as e:
        _check_getter_exception(e, obj.__state__, ResolveError)


[docs] def old(obj): """ Returns an `old`-agent of `obj`. This function is helpfull within a rule, to access the old cell values before the current atomic operation. Args: obj (Reactive): A reactive object. Returns: An agent object offering the same attributes as `obj`, with the old cell values. """ if isinstance(obj, Pointer): holder, cell = _get_holder_cell(obj) try: container = cell.get_container(holder) except AttributeError: return obj() return rcontext.old_values.get(id(container), container.get_value()) else: return OldAgent(obj)
[docs] def cell(obj, value=None): """ Returns a `cell`-agent of `obj`. This function can be used to manipulate the cell containers of `obj`. Args: obj (Reactive): A reactive object. Returns: An agent object offering the same attributes as `obj`, with the cell containers as attribute values. """ if isinstance(obj, Pointer): holder, cell = _get_holder_cell(obj) if value is not None: if isinstance(value, Container): cell.set_container(holder, value) else: raise TypeError("must be of type container", value) return cell.get_container(holder) else: return CellAgent(obj)