def _compute_direction(self, classpath): klass = get_class(classpath) from morse.core.actuator import Actuator from morse.core.sensor import Sensor if klass: if issubclass(klass, Actuator): return "IN" elif issubclass(klass, Sensor): return "OUT" else: logger.error("%s: no direction is precised nor can be " "computed automatically." % classpath) return None
def _compute_direction(self, classpath): klass = get_class(classpath) from morse.core.actuator import Actuator from morse.core.sensor import Sensor if klass: if issubclass(klass, Actuator): return 'IN' elif issubclass(klass, Sensor): return 'OUT' else: logger.error("%s: no direction is precised nor can be " "computed automatically." % classpath) return None
def add_stream(self, datastream, method=None, path=None, classpath=None, direction=None, **kwargs): """ Add a data stream interface to the component Do the binding between a component and the method to export/import its data. This must be used in general by sensors and actuators. A single component can make several calls to this function to add bindings with more than one middleware. :param datastream: enum in ['ros', 'socket', 'yarp', 'text', 'pocolibs', 'moos'] :param classpath: if set, force to use the configuration of the given component, instead of our own (default=None). You can pass other argument to this method, they will be added as a map to the configuration. .. code-block:: python component.add_stream('ros', topic='/myrobots/data') component.add_stream('moos', moos_host='127.0.0.1', moos_port=9000, moos_name='iMorse') """ self._err_if_not_exportable() if not classpath: classpath = self.property_value("classpath") if not classpath: logger.error("%s: no classpath defined for this " "component! Check component definition " % self.name) return level = self.property_value("abstraction_level") or "default" if not direction: direction = self._compute_direction(classpath) if not direction: return config = [] # Configure the datastream for this component if not method: if not classpath in MORSE_DATASTREAM_DICT: klass = get_class(classpath) from morse.core.actuator import Actuator from morse.core.sensor import Sensor # Check if we can use default interface... if klass and \ issubclass(klass, Actuator) and \ datastream in INTERFACE_DEFAULT_IN: logger.warning("%s: no interfaces available for this " "component! Trying to use default one " "for %s." % (classpath, datastream)) config = [INTERFACE_DEFAULT_IN[datastream]] elif klass and \ issubclass(klass, Sensor) and \ datastream in INTERFACE_DEFAULT_OUT: logger.warning("%s: no interfaces available for this " "component! Trying to use default one " "for %s." % (classpath, datastream)) config = [INTERFACE_DEFAULT_OUT[datastream]] else: logger.error( "%s: no interfaces available for this component!" " Check builder/data.py." % classpath) return else: interfaces = MORSE_DATASTREAM_DICT[classpath] if not level in interfaces: if level == "default": # we need to look for the default level module_name, class_name = classpath.rsplit('.', 1) klass = load_module_attribute(module_name, class_name) if not hasattr(klass, "_levels"): logger.error( "Component <%s> does not declare any " "default interface. You must call " "`add_stream` with an explicit method " "and Python module." % str(classpath)) return # iterate over levels to find the one with the default flag for key, value in klass._levels.items(): if value[2]: level = key # set the right default level self.properties(abstraction_level=level) logger.info("Using default level <%s> for " "component <%s>" % (level, classpath)) break if level == "default": logger.error( "Component <%s> does not declare any" "default interface, and none of its " "abstraction levels is marked as the " "default one. You must call `add_stream`" " with an explicit method and Python " "module." % str(classpath)) return if not level in interfaces: logger.error( "%s: no interfaces defined for this " "component for abstraction level <%s>!" "Check builder/data.py." % (classpath, level)) return else: logger.error( "%s: no interfaces defined for this component" "for abstraction level <%s>! Check " "builder/data.py." % (classpath, level)) interfaces = interfaces[level] if not datastream in interfaces: logger.error( "%s: no %s interface defined for this component " "for abstraction level <%s>! " "Check builder/data.py." % (classpath, datastream, level)) return config = interfaces[datastream] if isinstance(config, list): config = config[0] if config == INTERFACE_DEFAULT_OUT: config = INTERFACE_DEFAULT_OUT[datastream] if config == INTERFACE_DEFAULT_IN: config = INTERFACE_DEFAULT_IN[datastream] if isinstance(config, str): config = [config] elif not path: config = [method] else: config = [method, path] if datastream in MORSE_DATASTREAM_MODULE: datastream_classpath = MORSE_DATASTREAM_MODULE[datastream] else: datastream_classpath = datastream config.insert(0, datastream_classpath) config.append(direction) config.append( kwargs) # append additional configuration (eg. topic name) Configuration.link_datastream(self, config)
def add_stream(self, datastream, method=None, path=None, classpath=None, direction=None, **kwargs): """ Add a data stream interface to the component Do the binding between a component and the method to export/import its data. This must be used in general by sensors and actuators. A single component can make several calls to this function to add bindings with more than one middleware. :param datastream: enum in ['ros', 'socket', 'yarp', 'text', 'pocolibs'] :param classpath: if set, force to use the configuration of the given component, instead of our own (default=None). You can pass other argument to this method, they will be added as a map to the configuration. .. code-block:: python component.add_stream('ros', topic='/myrobots/data') """ if not classpath: classpath = self.property_value("classpath") if not classpath: logger.error("%s: no classpath defined for this " "component! Check component definition " % self.name) return level = self.property_value("abstraction_level") or "default" config = [] # Configure the datastream for this component if not method: if not classpath in MORSE_DATASTREAM_DICT: # Check if we can use default interface... from morse.core.actuator import Actuator from morse.core.sensor import Sensor klass = get_class(classpath) if klass and issubclass(klass, Actuator) and datastream in INTERFACE_DEFAULT_IN: logger.warning( "%s: no interfaces available for this " "component! Trying to use default one " "for %s." % (classpath, datastream) ) config = [INTERFACE_DEFAULT_IN[datastream]] elif klass and issubclass(klass, Sensor) and datastream in INTERFACE_DEFAULT_OUT: logger.warning( "%s: no interfaces available for this " "component! Trying to use default one " "for %s." % (classpath, datastream) ) config = [INTERFACE_DEFAULT_OUT[datastream]] else: logger.error( "%s: no interfaces available for this component!" " Check builder/data.py." % classpath ) return else: interfaces = MORSE_DATASTREAM_DICT[classpath] if not level in interfaces: if level == "default": # we need to look for the default level module_name, class_name = classpath.rsplit(".", 1) klass = load_module_attribute(module_name, class_name) if not hasattr(klass, "_levels"): logger.error( "Component <%s> does not declare any " "default interface. You must call " "`add_stream` with an explicit method " "and Python module." % str(classpath) ) return # iterate over levels to find the one with the default flag for key, value in klass._levels.items(): if value[2] == True: level = key # set the right default level self.properties(abstraction_level=level) logger.info("Using default level <%s> for " "component <%s>" % (level, classpath)) break if level == "default": logger.error( "Component <%s> does not declare any" "default interface, and none of its " "abstraction levels is marked as the " "default one. You must call `add_stream`" " with an explicit method and Python " "module." % str(classpath) ) return if not level in interfaces: logger.error( "%s: no interfaces defined for this " "component for abstraction level <%s>!" "Check builder/data.py." % (classpath, level) ) return else: logger.error( "%s: no interfaces defined for this component" "for abstraction level <%s>! Check " "builder/data.py." % (classpath, level) ) interfaces = interfaces[level] if not datastream in interfaces: logger.error( "%s: no %s interface defined for this component " "for abstraction level <%s>! " "Check builder/data.py." % (classpath, datastream, level) ) return config = interfaces[datastream] if isinstance(config, list): config = config[0] if config == INTERFACE_DEFAULT_OUT: config = INTERFACE_DEFAULT_OUT[datastream] if config == INTERFACE_DEFAULT_IN: config = INTERFACE_DEFAULT_IN[datastream] if isinstance(config, str): config = [config] elif not path: config = [method] else: config = [method, path] if datastream in MORSE_DATASTREAM_MODULE: datastream_classpath = MORSE_DATASTREAM_MODULE[datastream] else: datastream_classpath = datastream config.insert(0, datastream_classpath) config.append(kwargs) # append additional configuration (eg. topic name) Configuration.link_datastream(self, config)