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)
def context_with_property_fixture(mocker, context_fixture) -> Context: prop = PropertyBase(name=DEFAULT_PROPERTY_NAME, default_value=DEFAULT_PROPERTY_VALUE) prop.set_parent_path(DEFAULT_MODULE_NAME) context_fixture.add_prop(prop=prop) mocker.patch.object(context_fixture, 'add_prop') return context_fixture
def create_subscriber(ctx: ContextWrapper): face_names = Ros2SubProperty( "face_names", topic=ctx.conf(key=ROS2_FACE_TOPIC_CONFIG), msg_type=RecognizedFaces, always_signal_changed=False) rec_faces = PropertyBase(name="rec_faces", default_value={}, always_signal_changed=False, allow_pop=True, allow_push=True) ctx.push(subscriber_parent.id(), face_names) ctx.push(subscriber_parent.id(), rec_faces) @state(read=(face_names.id(), rec_faces.id()), write=(rec_faces.id(), raw_out.id())) def react_to_recognized_face(ctx: ContextWrapper): nonlocal face_names faces: RecognizedFaces = ctx[face_names.id()] rec_faces_dict: Dict = ctx[rec_faces.id()] phrases: List = ["Hey, aren't you, {}?!", "How are you doing, {}?!", "How are you, {}?!", "Whats up, {}?!", "Nice to see you, {}?!", "Looking great today, {}!", "Hello, {}!", "Hi, {}!", "Greetings, {}!", "Howdy, {}!", "Hey, {}!", "Greetings to {} over here!", "Hi there, {}!", "Gruse gott, {}!"] best_name_and_confidence = "", 0 for name_and_confidence in zip(faces.names, faces.confidence): logger.info(str(name_and_confidence[0])) if name_and_confidence[1] > best_name_and_confidence[1]: best_name_and_confidence = name_and_confidence if best_name_and_confidence[1] >= ctx.conf(key=FACE_CONFIDENCE_THRESHOLD): if best_name_and_confidence[0] not in rec_faces_dict.keys() or \ datetime.timestamp(datetime.now()) - rec_faces_dict.get(best_name_and_confidence[0]) > 300: rec_faces_dict.update({best_name_and_confidence[0]: datetime.timestamp(datetime.now())}) ctx[raw_out.id()] = phrases[randint(0, len(phrases) - 1)].format(best_name_and_confidence[0]) ctx[rec_faces.id()] = rec_faces_dict mod.add(react_to_recognized_face) ctx.add_state(react_to_recognized_face)
def add_prop(self, *, mod: module.Module, prop: property.PropertyBase): if prop.name in self.properties.values(): logging.error(f"Attempt to add property {prop.name} twice!") return # prepend module name to property name prop.module_name = mod.name # register property self.properties[prop.fullname()] = prop # register all of the property's signals with self.states_lock: for signal in self.default_property_signals: self.states_per_signal[prop.fullname() + signal] = set()
def test_property_illegal_push(context_mock): prop_no_push = PropertyBase(name=DEFAULT_PROPERTY_NAME, default_value=DEFAULT_PROPERTY_VALUE, allow_push=False) prop_no_push.set_parent_path(DEFAULT_MODULE_NAME) wrapper = PropertyWrapper(prop=prop_no_push, ctx=context_mock, allow_read=True, allow_write=True) with LogCapture(attributes=strip_prefix) as log_capture: assert not wrapper.push(child=PropertyBase(name=CHILD_PROPERTY_NAME)) log_capture.check( f'Unauthorized push in property {DEFAULT_MODULE_NAME}:{DEFAULT_PROPERTY_NAME}!', )
def push(self, parentpath: str, child: PropertyBase): """ Add a child to a property. Note: Child must not yet have a parent or children of itself. Write-access to parent is needed. * `parentpath`: Path of the parent that should receive the new child. * `child`: Parent-less, child-less property object to add. **Returns:** True if the push was successful, False otherwise """ if child.parent_path: logger.error( f"State {self.st.name} attempted to push child property {child.name} to parent {parentpath}, but it already has parent {child.parent_path}!" ) return False if parentpath in self.properties: if self.properties[parentpath].push(child): self.properties[child.id()] = PropertyWrapper( prop=child, ctx=self.ctx, spike_parents=self.spike_parents, allow_read=self.properties[parentpath].allow_read, allow_write=self.properties[parentpath].allow_write) self.ctx.add_prop(prop=child) return True else: logger.error( f'State {self.st.name} attempted to add child-property {child.name} to non-accessible parent {parentpath}!' ) return False
def test_property_child(under_test_read_write: PropertyWrapper, default_property_base, context_mock): assert under_test_read_write.push( PropertyBase(name=CHILD_PROPERTY_NAME, default_value=DEFAULT_PROPERTY_VALUE)) assert list(under_test_read_write.enum())[0] == CHILD_PROPERTY_ID assert under_test_read_write.prop.children[CHILD_PROPERTY_NAME].read( ) == DEFAULT_PROPERTY_VALUE
def push_telegram_interloc(ctx: ContextWrapper, telegram_node: Node, name: str): """ Push the telegram_node into interloc:all:name """ if ctx.push(parentpath="interloc:all", child=PropertyBase(name=name, default_value=telegram_node)): logger.debug(f"Pushed {telegram_node} to interloc:all")
def push(self, child: PropertyBase): """ Add a child to the property or to children of the property * `child`: Parent-less, child-less property object to add. Name of the child must be unique among existing children of this property. **Returns:** True if the push was successful, False otherwise """ if not self.allow_write: logger.error( f"Unauthorized push access in property-wrapper {self.prop.id()}!" ) return False if self.prop.push(child): self.ctx.emit(self.prop.pushed_signal(), parents=self.spike_parents, wipe=False, payload=child.id()) return True return False
import rclpy from ravestate.module import Module from ravestate.constraint import s from ravestate.state import state from ravestate.receptor import receptor from ravestate.property import PropertyBase from std_msgs.msg import String rclpy.init() node = rclpy.create_node("vision_node") with Module(name="facerec"): face = PropertyBase(name="face", default_value="") @state(cond=s(":startup")) def facerec_run(ctx): @receptor(ctx_wrap=ctx, write="facerec:face") def face_recognition_callback(ctx, msg): ctx["facerec:face"] = msg node.create_subscription(String, "/roboy/vision/recognized_faces", face_recognition_callback) rclpy.spin(node) @state(cond=s(":shutdown")) def facerec_shutdown(): node.destroy_node()
if ROBOY_COGNITION_AVAILABLE: ROS2_FACE_TOPIC_CONFIG = "ros2-node" FACE_CONFIDENCE_THRESHOLD = "min-confidence" CONFIG = { ROS2_FACE_TOPIC_CONFIG: "/roboy/cognition/vision/visible_face_names", FACE_CONFIDENCE_THRESHOLD: 0.85 } with Module(name="stalker", config=CONFIG) as mod: # Create a dummy parent, under which we can push the actual recognized faces topic, # once a context with a configuration is available. subscriber_parent = PropertyBase(name="face_names_parent") @state(cond=startup(), write=subscriber_parent.id()) def create_subscriber(ctx: ContextWrapper): face_names = Ros2SubProperty( "face_names", topic=ctx.conf(key=ROS2_FACE_TOPIC_CONFIG), msg_type=RecognizedFaces, always_signal_changed=False) rec_faces = PropertyBase(name="rec_faces", default_value={}, always_signal_changed=False, allow_pop=True, allow_push=True)
import rclpy from ravestate import registry from ravestate.state import state from ravestate.receptor import receptor from ravestate.property import PropertyBase from std_msgs.msg import String rclpy.init() node = rclpy.create_node("vision_node") @state(triggers=":startup") def facerec_run(ctx): @receptor(ctx_wrap=ctx, write="facerec:face") def face_recognition_callback(ctx, msg): ctx["facerec:face"] = msg node.create_subscription(String, "/roboy/vision/recognized_faces", face_recognition_callback) rclpy.spin(node) @state(triggers=":shutdown") def facerec_shutdown(): node.destroy_node() rclpy.shutdown() registry.register(name="facerec", props=PropertyBase(name="face", default=""), states=(facerec_run, facerec_shutdown))
from reggol import get_logger logger = get_logger(__name__) REDIS_HOST_CONF = "redis_host" REDIS_PORT_CONF = "redis_port" REDIS_PASS_CONF = "redis_pass" CONFIG = { REDIS_HOST_CONF: "localhost", REDIS_PORT_CONF: 6379, REDIS_PASS_CONF: None } with Module(name="sendpics", config=CONFIG): face_vec = PropertyBase(name="face_vec", always_signal_changed=True) @state(cond=s("idle:bored"), write="rawio:out", weight=1.2, cooldown=30.) def prompt_send(ctx): ctx["rawio:out"] = "Why don't you send me a picture? I'm really good at recognizing faces!" @state( read="rawio:pic_in", write=("rawio:out", "sendpics:face_vec"), emit_detached=True) def prompt_name(ctx): # Get face ancoding face = recognize_face_from_image_file(ctx["rawio:pic_in"]) # Prompt name if face is not None: ctx["rawio:out"] = "Nice picture! Who is that person?"
from ravestate.module import Module from ravestate.property import PropertyBase with Module(name="rawio"): input = PropertyBase(name="in", default_value="", allow_pop=False, allow_push=False, always_signal_changed=True) output = PropertyBase(name="out", default_value="", allow_pop=False, allow_push=False, always_signal_changed=True, wipe_on_changed=False) pic_in = PropertyBase(name="pic_in", default_value=None, allow_pop=False, allow_push=False, always_signal_changed=True)
def push_interloc(ctx: ContextWrapper, interlocutor_node: Node): if ctx.push(parentpath="interloc:all", child=PropertyBase(name=id, default_value=interlocutor_node)): logger.debug(f"Pushed {interlocutor_node} to interloc:all")
def test_property(under_test_read_only: PropertyWrapper, default_property_base: PropertyBase): assert (default_property_base.id() == f"{DEFAULT_MODULE_NAME}:{DEFAULT_PROPERTY_NAME}") assert (not default_property_base._lock.locked()) assert (default_property_base.read() == DEFAULT_PROPERTY_VALUE)
def default_property_base(): prop = PropertyBase(name=DEFAULT_PROPERTY_NAME, default_value=DEFAULT_PROPERTY_VALUE) prop.set_parent_path(DEFAULT_MODULE_NAME) return prop