예제 #1
0
def test_signal_and(mocker):
    sig = s("mysig")
    conjunct = s("sig1") & s("sig2")
    disjunct = s("sig1") | s("sig2")

    with mocker.patch('ravestate.constraint.Conjunct.__init__',
                      return_value=None):
        _ = sig & sig
        Conjunct.__init__.assert_called_once_with(sig, sig)

    with mocker.patch('ravestate.constraint.Conjunct.__init__',
                      return_value=None):
        with mocker.patch('ravestate.constraint.Conjunct.__iter__',
                          return_value=iter([1])):
            _ = sig & conjunct
            Conjunct.__init__.assert_called_once_with(sig, 1)

    with mocker.patch('ravestate.constraint.Disjunct.__init__',
                      return_value=None):
        with mocker.patch('ravestate.constraint.Conjunct.__init__',
                          return_value=None):
            with mocker.patch.object(disjunct,
                                     '_conjunctions',
                                     return_value={}):
                _ = sig & disjunct
            Disjunct.__init__.assert_called_with()
예제 #2
0
def test_signal(activation_fixture):
    sig = s("mysig")

    assert not sig.evaluate()
    assert set(sig.signals()) == {s("mysig")}
    sig.acquire(Spike(sig="notmysig"), activation_fixture)
    assert not sig.evaluate()
    sig.acquire(Spike(sig="mysig"), activation_fixture)
    assert sig.evaluate()

    sig_and_dis = s("sig") & (s("dis") | s("junct"))
    assert not sig_and_dis.evaluate()
    sig_and_dis.acquire(Spike(sig="sig"), activation_fixture)
    assert not sig_and_dis.evaluate()
    sig_and_dis.acquire(Spike(sig="junct"), activation_fixture)
    assert sig_and_dis.evaluate()

    expected = [(sig, sig.spike)]
    return_value = list(sig.dereference())
    assert expected == return_value

    sig.spike = Spike(sig='mysig')
    sig.spike._age = 200
    return_value = list(sig.update(activation_fixture))
    assert return_value == [sig]

    assert str(sig) == "mysig"
예제 #3
0
def test_flag_property(context_mock):
    prop_base = PropertyBase(name="flag_prop", is_flag_property=True)
    prop_base.set_parent_path(DEFAULT_MODULE_NAME)
    prop_wrapper = PropertyWrapper(prop=prop_base,
                                   ctx=context_mock,
                                   allow_read=True,
                                   allow_write=True)
    assert (prop_base._lock.locked())

    prop_wrapper.set(True)
    assert (prop_wrapper.get() is True)
    context_mock.emit.assert_any_call(s(f"{prop_wrapper.prop.id()}:changed"),
                                      parents=None,
                                      wipe=True)
    context_mock.emit.assert_any_call(s(f"{prop_wrapper.prop.id()}:true"),
                                      parents=None,
                                      wipe=True)

    context_mock.emit.reset_mock()
    prop_wrapper.set(False)
    assert (prop_wrapper.get() is False)
    context_mock.emit.assert_any_call(s(f"{prop_wrapper.prop.id()}:changed"),
                                      parents=None,
                                      wipe=True)
    context_mock.emit.assert_any_call(s(f"{prop_wrapper.prop.id()}:false"),
                                      parents=None,
                                      wipe=True)

    context_mock.emit.reset_mock()
    prop_wrapper.set(None)
    assert (prop_wrapper.get() is None)
    context_mock.emit.assert_called_once_with(
        s(f"{prop_wrapper.prop.id()}:changed"), parents=None, wipe=True)
예제 #4
0
def state_signal_d_fixture(mocker):
    @state(signal_name="d", cond=s("module:b") | s("module:c"))
    def state_mock_c_fn(ctx):
        pass

    state_mock_c_fn.module_name = DEFAULT_MODULE_NAME
    return state_mock_c_fn
예제 #5
0
def test_decorator_illegal_trigger(under_test, default_signal, default_read,
                                   default_write, default_action):
    with pytest.raises(ValueError):

        @state(signal_name=default_signal,
               read=default_read,
               write=default_write,
               cond=(s("rawio:in:changed") | s("facerec:face:changed")) &
               (s("sys:has-internet") | s("foo:poo")))
        def test_state(_):
            return "Hello world!"
예제 #6
0
def test_disjunct_or(mocker):
    disjunct = (s("sig1") & s("sig2")) | s("sig3")
    with mocker.patch('ravestate.constraint.Disjunct.__iter__',
                      return_value=iter([1])):
        with mocker.patch('ravestate.constraint.Disjunct.__init__',
                          return_value=None):
            conjunct = s("sig1") & s("sig2")
            _ = disjunct | conjunct
            Disjunct.__init__.assert_called_with(1, conjunct)

    with mocker.patch('ravestate.constraint.Disjunct.__iter__',
                      return_value=iter([1])):
        with mocker.patch('ravestate.constraint.Disjunct.__init__',
                          return_value=None):
            signal = s("sig1")
            with mocker.patch('ravestate.constraint.Conjunct.__init__',
                              return_value=None):
                _ = disjunct | signal
                Conjunct.__init__.assert_called_once_with(signal)
            Disjunct.__init__.assert_called_once()

    with mocker.patch('ravestate.constraint.Disjunct.__init__',
                      return_value=None):
        with mocker.patch('ravestate.constraint.Disjunct.__iter__',
                          return_value=iter([1])):
            disjunct2 = s("sig1") | s("sig2")
            _ = disjunct | disjunct2
            Disjunct.__init__.assert_called_with(1)
예제 #7
0
 def shutdown(self) -> None:
     """
     Sets the shutdown flag and waits for the signal processing thread to join.
     """
     self._shutdown_flag.set()
     self.emit(s(":shutdown"))
     self._run_task.join()
예제 #8
0
def startup(**kwargs) -> Signal:
    """
    Obtain the startup signal, which is fired once when `Context.run()` is executed.<br>
    __Hint:__ All key-word arguments of #constraint.s(...)
     (`min_age`, `max_age`, `detached`) are supported.
    """
    return s(":startup", **kwargs)
예제 #9
0
def shutdown(**kwargs) -> Signal:
    """
    Obtain the shutdown signal, which is fired once when `Context.shutdown()` is called.<br>
    __Hint:__ All key-word arguments of #constraint.s(...)
     (`min_age`, `max_age`, `detached`) are supported.
    """
    return s(":shutdown", **kwargs)
예제 #10
0
def state_signal_b_fixture(mocker):
    @state(signal_name="b", cond=s("module:a"))
    def state_mock_b_fn(ctx):
        pass

    state_mock_b_fn.module_name = DEFAULT_MODULE_NAME
    return state_mock_b_fn
예제 #11
0
def test_signal_or(mocker):
    sig = s("mysig")
    with mocker.patch('ravestate.constraint.Disjunct.__init__',
                      return_value=None):
        conjunct = s("sig1") & s("sig2")
        with mocker.patch('ravestate.constraint.Conjunct.__init__',
                          return_value=None):
            _ = sig | conjunct
            Conjunct.__init__.assert_called_once_with(sig)
        Disjunct.__init__.assert_called_once()

    with mocker.patch('ravestate.constraint.Disjunct.__init__',
                      return_value=None):
        with mocker.patch('ravestate.constraint.Disjunct.__iter__',
                          return_value=iter([1])):
            disjunct = s("sig1") | s("sig2")
            _ = sig | disjunct
            Disjunct.__init__.assert_called_with(sig, 1)
예제 #12
0
def popped(property_name, **kwargs) -> Signal:
    """
    Returns the `popped` Signal for the given property. This signal
     is emitted, when a child property removed from it.
     From the perspective of a state, this can be achieved
     with the `ContextWrapper.pop(...)` function.<br>
    __Hint:__ All key-word arguments of #constraint.s(...)
     (`min_age`, `max_age`, `detached`) are supported.
    """
    return s(f"{property_name}:popped", **kwargs)
예제 #13
0
def changed(property_name, **kwargs) -> Signal:
    """
    Returns the `changed` Signal for the given property.
    This signal is emitted, when the Property is written to,
     and the new property value is different from the old one,
     or the propertie's `always_signal_changed` flag is True.<br>
    __Hint:__ All key-word arguments of #constraint.s(...)
     (`min_age`, `max_age`, `detached`) are supported.
    """
    return s(f"{property_name}:changed", **kwargs)
예제 #14
0
 def run(self) -> None:
     """
     Creates a signal processing thread, starts it, and emits the :startup signal.
     """
     if self._run_task:
         logger.error("Attempt to start context twice!")
         return
     self._run_task = Thread(target=self._run_loop)
     self._run_task.start()
     self.emit(s(":startup"))
예제 #15
0
def test_property_write(under_test_read_write: PropertyWrapper,
                        default_property_base, context_mock):
    # Make sure that writing to writable wrapper is effective
    assert (default_property_base._lock.locked())
    under_test_read_write.set(NEW_PROPERTY_VALUE)
    assert (under_test_read_write.get() == NEW_PROPERTY_VALUE)
    context_mock.emit.assert_called_once_with(
        s(f"{under_test_read_write.prop.id()}:changed"),
        parents=None,
        wipe=True)
예제 #16
0
파일: state.py 프로젝트: WiktorJ/ravestate
    def __init__(self, *,
                 signal_name: Optional[str],
                 write: Union[str, Tuple[str]],
                 read: Union[str, Tuple[str]],
                 cond: Constraint,
                 action,
                 is_receptor: bool=False,
                 emit_detached: bool=False,
                 weight: float=1.,
                 cooldown: float=0.):

        assert(callable(action))
        self.name = action.__name__
        self.consumable = Consumable(f"@{action.__name__}")

        # check to recognize states using old signal implementation
        if isinstance(cond, str):
            logger.error(f"Attempt to create state {self.name} which has a string as condition, not a constraint!")
            cond = None

        # catch the insane case
        if not len(read) and not cond and not is_receptor:
            logger.warning(
                f"The state `{self.name}` is not reading any properties, nor waiting for any signals. " +
                "It will never be activated!")

        # convert read/write properties to tuples
        if isinstance(write, str):
            write = (write,)
        if isinstance(read, str):
            read = (read,)

        # listen to default changed-signals if no signals are given.
        # convert triggers to disjunctive normal form.
        if not cond and len(read) > 0:
            cond = Disjunct(*list(Conjunct(s(f"{rprop_name}:changed")) for rprop_name in read))

        self.signal_name = signal_name
        self.write_props = write
        self.read_props = read
        self.constraint = cond
        self.completed_constraint = cond
        self.action = action
        self.module_name = ""
        self.signal_object = None
        self.emit_detached = emit_detached
        self.activated = Semaphore(0)
        self.weight = self.current_weight = weight
        self.cooldown = cooldown
        self.lock = Lock()

        # add state to module in current `with Module(...)` clause
        module_under_construction = getattr(ravestate_thread_local, 'module_under_construction', None)
        if module_under_construction:
            module_under_construction.add(self)
예제 #17
0
def test_disjunct_and(mocker):
    sig = s("mysig")
    conjunct = s("sig1") & s("sig2")
    disjunct = s("sig1") | s("sig2")

    with mocker.patch('ravestate.constraint.Disjunct.__init__',
                      return_value=None):
        with mocker.patch.object(disjunct, '_conjunctions', return_value={}):
            _ = disjunct & sig
            Disjunct.__init__.assert_called_once_with()

    with mocker.patch('ravestate.constraint.Disjunct.__init__',
                      return_value=None):
        with mocker.patch.object(disjunct, '_conjunctions', return_value={}):
            _ = disjunct & conjunct
            Disjunct.__init__.assert_called_once_with()

    with pytest.raises(ValueError):
        with LogCapture(attributes=strip_prefix) as log_capture:
            _ = disjunct & disjunct
            log_capture.check("Can't conjunct two disjunctions.")
예제 #18
0
def test_disjunct(activation_fixture):
    disjunct = (s("sig1") & s("sig2")) | s("sig3")
    assert not disjunct.evaluate()
    assert set(disjunct.signals()) == {s("sig1"), s("sig2"), s("sig3")}
    disjunct.acquire(Spike(sig="sig1"), activation_fixture)
    assert not disjunct.evaluate()
    disjunct.acquire(Spike(sig="sig3"), activation_fixture)
    assert disjunct.evaluate()
예제 #19
0
def test_conjunct_or(mocker):
    conjunct = s("sig1") & s("sig2") & s("sig3")
    with mocker.patch('ravestate.constraint.Disjunct.__init__',
                      return_value=None):
        conjunct2 = s("sig1") & s("sig2")
        _ = conjunct | conjunct2
        Disjunct.__init__.assert_called_once_with(conjunct, conjunct2)

    with mocker.patch('ravestate.constraint.Disjunct.__init__',
                      return_value=None):
        with mocker.patch('ravestate.constraint.Disjunct.__iter__',
                          return_value=iter([1])):
            disjunct = s("sig1") | s("sig2")
            _ = conjunct | disjunct
            Disjunct.__init__.assert_called_with(conjunct, 1)
예제 #20
0
def test_conjunct(activation_fixture):
    conjunct = s("sig1") & s("sig2") & s("sig3")
    assert not conjunct.evaluate()
    assert set(conjunct.signals()) == {s("sig1"), s("sig2"), s("sig3")}
    conjunct.acquire(Spike(sig="sig1"), activation_fixture)
    assert not conjunct.evaluate()
    conjunct.acquire(Spike(sig="sig2"), activation_fixture)
    assert not conjunct.evaluate()
    conjunct.acquire(Spike(sig="sig2"), activation_fixture)
    assert not conjunct.evaluate()
    conjunct.acquire(Spike(sig="sig3"), activation_fixture)
    assert conjunct.evaluate()
예제 #21
0
ROS2_AVAILABLE = True
try:
    import rclpy
except ImportError:
    logger.error(
        "Could not import rclpy. Please make sure to have ROS2 installed.")
    ROS2_AVAILABLE = False

NODE_NAME_CONFIG_KEY = "ros2-node-name"
SPIN_FREQUENCY_CONFIG_KEY = "ros2-spin-frequency"

global_prop_set = set()


@state(cond=s(":startup"))
def sync_ros_properties(ctx: ContextWrapper):
    """
    State that creates a ROS2-Node, registers all Ros2SubProperties and Ros2PubProperties in ROS2 and keeps them synced
    """
    # check for ROS2 availability
    if not ROS2_AVAILABLE:
        logger.error(
            "ROS2 is not available, therefore all ROS2-Properties "
            "will be just normal properties without connection to ROS2!")
        return Delete()

    # get config stuff
    node_name = ctx.conf(key=NODE_NAME_CONFIG_KEY)
    if not node_name:
        logger.error(
예제 #22
0
                           default_value="",
                           always_signal_changed=True,
                           allow_pop=False,
                           allow_push=False),
    roboy = PropertyBase(name="roboy",
                         default_value="",
                         always_signal_changed=True,
                         allow_pop=False,
                         allow_push=False),
    yesno = PropertyBase(name="yesno",
                         default_value="",
                         always_signal_changed=True,
                         allow_pop=False,
                         allow_push=False)

    @state(cond=s("rawio:in:changed"),
           read="rawio:in",
           write=("nlp:tokens", "nlp:postags", "nlp:lemmas", "nlp:tags",
                  "nlp:ner", "nlp:triples", "nlp:roboy", "nlp:yesno"))
    def nlp_preprocess(ctx):
        text = ctx["rawio:in"]
        if not text:
            return False
        nlp_doc = nlp(text)

        nlp_tokens = tuple(str(token) for token in nlp_doc)
        ctx["nlp:tokens"] = nlp_tokens
        logger.info(f"[NLP:tokens]: {nlp_tokens}")

        nlp_postags = tuple(str(token.pos_) for token in nlp_doc)
        ctx["nlp:postags"] = nlp_postags
예제 #23
0
    def _run_once(self, seconds_passed=1.):
        with self._lock:

            # ---------- Update weights wrt/ cooldown for all states -----------

            for state in self._activations_per_state:
                state.update_weight(seconds_passed)

            # ----------- For every state, compress it's activations -----------

            for st, acts in self._activations_per_state.items():
                assert len(acts) > 0
                if len(acts) > 1:
                    # We could do some fancy merge of partially fulfilled activations,
                    #  but for now let's just remove all completely unfulfilled
                    #  ones apart from one.
                    allowed_unfulfilled: Activation = None
                    for act in acts.copy():
                        if not act.spiky():
                            if allowed_unfulfilled:
                                for signal in act.constraint.signals():
                                    if signal in self._act_per_state_per_signal_age and \
                                            act in self._act_per_state_per_signal_age[signal][0][act.state_to_activate]:
                                        self._act_per_state_per_signal_age[
                                            signal][0][act.state_to_activate].remove(act)
                                acts.remove(act)
                            else:
                                allowed_unfulfilled = act

            # --------- Acquire new state activations for every spike ----------

            for spike in self._spikes:
                if spike.is_wiped():
                    continue
                for state, acts in self._act_per_state_per_signal_age[s(spike.name())][spike.age()].items():
                    old_acts = acts.copy()
                    for act in old_acts:
                        if act.acquire(spike):
                            # Remove the Activation instance from _act_per_state_per_signal_age
                            #  for the Spike with a certain minimum age. In place of the removed
                            #  activation, if no activation with the same target state is left,
                            #  a new Activation will be created.
                            acts.remove(act)
                            if len(acts) == 0:
                                self._new_state_activation(state)
                        else:
                            logger.error(
                                "An activation rejected a spike it was registered to be interested in.")

            # ------------------ Update all state activations. -----------------

            for act in self._state_activations():
                if act.update():
                    self._activations_per_state[act.state_to_activate].discard(act)

            # ----------------- Forget fully unreferenced spikes ---------------

            old_spike_set = self._spikes.copy()
            for spike in old_spike_set:
                with spike.causal_group() as cg:
                    if cg.stale(spike):
                        # This should lead to the deletion of the spike
                        self._spikes.remove(spike)
                        spike.wipe(already_wiped_in_causal_group=True)
                        logger.debug(f"{cg}.stale({spike})->Y")

            # ----------------- Increment age on active spikes -----------------

            for spike in self._spikes:
                spike.tick()

            # -------------------- Force garbage collect -----------------------

            gc.collect()

        self._update_core_properties(False)
예제 #24
0
from ravestate.constraint import ConfigurableAge
from ravestate.constraint import s
from ravestate.wrappers import ContextWrapper
from ravestate.state import state, Emit

from reggol import get_logger
logger = get_logger(__name__)

IMPATIENCE_THRESHOLD_CONFIG_KEY = "impatience_threshold"
CONFIG = {
    # duration in seconds how long ":pressure" should be true before getting impatient
    IMPATIENCE_THRESHOLD_CONFIG_KEY: 1.0
}

with Module(name="idle", config=CONFIG):

    @state(read=":activity", signal_name="bored")
    def am_i_bored(ctx: ContextWrapper):
        """
        Emits idle:bored signal if no states are currently partially fulfilled
        """
        if ctx[":activity"] == 0:
            return Emit(wipe=True)

    @state(cond=s(signal_name=":pressure:true",
                  min_age=ConfigurableAge(key=IMPATIENCE_THRESHOLD_CONFIG_KEY),
                  max_age=-1.),
           signal_name="impatient")
    def am_i_impatient(ctx: ContextWrapper):
        return Emit(wipe=True)
예제 #25
0
from ravestate.state import state
from ravestate.module import Module
from ravestate.constraint import s

from roboy_parlai import wildtalk
import ravestate_rawio

with Module(name="wildtalk"):

    @state(cond=s("rawio:in:changed", max_age=-1),
           read="rawio:in",
           write="rawio:out")
    def wildtalk_state(ctx):
        text = ctx["rawio:in"]
        if not text:  # make sure that text is not empty
            text = " "
        ctx["rawio:out"] = wildtalk(text)
예제 #26
0
def default_signal():
    return s("test-signal")
예제 #27
0
from ravestate_verbaliser.verbaliser import get_phrase_list
import ravestate_phrases_basic_en
import ravestate_ontology

from scientio.ontology.node import Node
from scientio.session import Session
from scientio.ontology.ontology import Ontology

from reggol import get_logger
logger = get_logger(__name__)

DEFAULT_INTERLOC_ID = "terminal_user"

with Module(name="consoleio"):

    @state(cond=s(":startup"), read="interloc:all")
    def console_input(ctx: ContextWrapper):
        @receptor(ctx_wrap=ctx, write="rawio:in")
        def write_console_input(ctx_input, value: str):
            ctx_input["rawio:in"] = value

        @receptor(ctx_wrap=ctx, write="interloc:all")
        def push_console_interloc(ctx: ContextWrapper, console_node: Node):
            if ctx.push(parentpath="interloc:all",
                        child=PropertyBase(name=DEFAULT_INTERLOC_ID,
                                           default_value=console_node)):
                logger.debug(f"Pushed {console_node} to interloc:all")

        @receptor(ctx_wrap=ctx, write="interloc:all")
        def pop_console_interloc(ctx: ContextWrapper):
            if ctx.pop(f"interloc:all:{DEFAULT_INTERLOC_ID}"):
예제 #28
0
def default_triggers():
    return s(":idle")
예제 #29
0
    question = PropertyBase(name="question",
                            default_value="",
                            always_signal_changed=True,
                            allow_pop=False,
                            allow_push=False,
                            is_flag_property=True)

    wrong_input = PropertyBase(name="wrong_input",
                               default_value="",
                               always_signal_changed=True,
                               allow_pop=False,
                               allow_push=False,
                               is_flag_property=True)

    @state(cond=s("nlp:intent-play") | s("idle:bored"),
           write="rawio:out",
           signal_name="initiate-play",
           emit_detached=True)
    def akinator_play_ask(ctx):
        """
        Asks if interlocutor wants to play 20 question / akinator
        Triggered when nlp:play property is changed by "i want to play a game" or a similar input
        """
        ctx["rawio:out"] = "Do you want to play 20 questions?"
        return Emit()

    @state(cond=s("nlp:yes-no") &
           (s("akinator:initiate-play", max_age=-1)
            | s("akinator:initiate_play_again:changed", max_age=-1)),
           read="nlp:yesno",
예제 #30
0
 def signal(self) -> Optional[Signal]:
     assert self.module_name
     if not self._signal and self.signal_name:
         self._signal = s(f"{self.module_name}:{self.signal_name}")
     return self._signal