Пример #1
0
    def loadHandlerMethod(self, handler_module_path, onlyLoadInit=False):
        """
        Load method info (name, arg...) in the given handler file
        If onlyLoadInit is True, only the info of __init__ method will be loaded
        If over_write_h_type is given, then over write the handler type with it
        """
        # load the handler class first
        name, h_type, handler_class = self.loadHandlerClass(handler_module_path)

        # update the handler name and type info
        # handler name is the name of the file
        # handler type is the corresponding handler object defined in handlerTemplates.py
        self.name = name
        self.h_type = h_type

        # get all methods in this handler
        handler_methods = inspect.getmembers(handler_class, inspect.ismethod)

        # parse each method into method object
        for method_name, method in handler_methods:
            # only parse the method not start with underscore (exclude __inti__)
            # only parse the __init__ method if required
            if ((not onlyLoadInit and (not str(method_name).startswith('_')) or str(method_name)=='__init__') ):
                method_config = HandlerMethodConfig(name=method_name)
                try:
                    method_config.fromMethod(method, self)
                except SyntaxError as e:
                    raise ht.LoadingError("Error while inspecting method {!r} of handler {!r}: {}".format(method_name, handler_module_path, e))

                # add this method into the method list of the handler
                self.methods.append(method_config)
Пример #2
0
    def fromFile(self, file_path, hsub = None):
        """
        Given a robot file, load the robot info in it
        The file_path needs to be the path starting from lib/
        """

        logging.debug("Loading robot file {!r}".format(os.path.basename(file_path).split('.')[0]))
        try:
            # try to load the robot file
            robot_data = fileMethods.readFromFile(file_path)
        except IOError:
            ht.LoadingError("Cannot load the information")
            self._setLoadFailureFlag()
        else:
            # now load the robot config from the dictionary data
            self.fromData(robot_data, hsub)
Пример #3
0
    def _getCalibrationMatrixFromString(self, calib_mat_str):
        calib_mat_str = calib_mat_str.strip()

        # Convert the string into an array. Using `literal_eval` instead of
        # `eval` just so people can't put arbitrary code into the config
        # file and trick us into a running it.
        calib_mat_str = calib_mat_str.replace("array(", "")
        calib_mat_str = calib_mat_str.replace("matrix(", "")
        calib_mat_str = calib_mat_str.replace(")", "")

        # If empty or undefined, just return an identity matrix
        if calib_mat_str == "None" or calib_mat_str == "":
            return eye(3)

        try:
           return array(ast.literal_eval(calib_mat_str))
        except SyntaxError:
            self._setLoadFailureFlag()
            raise ht.LoadingError("Invalid calibration data found for robot {0}({1})".format(self.name, self.r_type))
Пример #4
0
    def fromFile(self, file_path, hsub = None):
        """
        Given an experiment config file, load the info
        """

        # Add extension to the name if there isn't one.
        if not file_path.endswith('.config'):
            file_path = file_path + '.config'

        logging.debug("Loading config file: {!r}".format(os.path.basename(file_path).split('.')[0]))
        try:
            # try to load the config file
            config_data = fileMethods.readFromFile(file_path)
        except IOError:
            ht.LoadingError("Cannot load the information")
        else:
            # now load the robot config from the dictionary data
            self.fromData(config_data, hsub)
            # update the file_path
            self.file_name = file_path
Пример #5
0
    def fromData(self, config_data, hsub = None):
        """
        Given a dictionary of experiment config information, returns an ExperimentConfig object holding all the information
        The dictionary is in the format returned by the readFromFile function
        """
        # make sure we have an instance of handlerSubsystem
        if hsub is None:
            raise TypeError("Need an instance of handlerSubsystem to parse experiment config data")
        try:
            self.name = config_data['General Config']['Name'][0]
        except (KeyError, IndexError):
            raise ht.LoadingError("Missing general config information")

        # parse the string for sensor and actuator prop mapping
        for prop_type in ['sensor', 'actuator']:
            if prop_type.title() + '_Proposition_Mapping' in config_data['General Config']:
                for mapping in config_data['General Config'][prop_type.title() + '_Proposition_Mapping']:
                    try:
                        prop, func = [s.strip() for s in mapping.split('=', 1)]
                    except IOError:
                        raise ht.LoadingError("Wrong {} mapping -- {!r}".format(prop_type, mapping))
                    else:
                        self.prop_mapping[prop] = func
            else:
                raise ht.LoadingError("Cannot find {} proposition mapping".format(prop_type))

        if 'Initial_Truths' in config_data['General Config']:
            # parse the initially true propositions
            for prop_name in config_data['General Config']['Initial_Truths']:
                self.initial_truths.append(prop_name)
        else:
            raise ht.LoadingError("Cannot find initial truth proposition")

        if 'Region_Tags' in config_data['General Config']:
            # parse the region tags
            try:
                self.region_tags = json.loads("".join(config_data['General Config']['Region_Tags']))
            except ValueError:
                logging.warning("Wrong region tags")

        # Load main robot name
        try:
            self.main_robot = config_data['General Config']['Main_Robot'][0]
        except (IndexError, KeyError):
            logging.warning("Cannot find main robot name in config file {}".format(self.file_name))

        # load robot configs
        robot_data = []
        for config_key, config_value in config_data.iteritems():
            if config_key.startswith('Robot'):
                robot_data.append(config_value)

        if robot_data == []:
            logging.warning("Missing robot data in config file {}".format(self.file_name))
        else:
            # using the parsing function to parse the data
            for data in robot_data:
                robot_config = RobotConfig()
                try:
                    robot_config.fromData(data, hsub)
                except ht.LoadingError, msg:
                    logging.warning(str(msg) + ' in robot data .')
                    continue
                except TypeError:
                    # missing hsub
                    continue
                else:
Пример #6
0
    def fromData(self, robot_data, hsub):
        """
        Given a dictionary of robot handler information, returns a robot object holding all the information
        The dictionary is in the format returned by the readFromFile function
        If the necessary handler of the robot is not specified or can't be loaded, return None
        """

        # update robot name and type
        try:
            self.name = robot_data['RobotName'][0]
        except (KeyError, IndexError):
            raise ht.LoadingError("Cannot find robot name")
            self._setLoadFailureFlag()

        try:
            self.r_type = robot_data['Type'][0]
        except (KeyError, IndexError):
            raise ht.LoadingError("Cannot find robot type")
            self._setLoadFailureFlag()

        # update robot calibration matrix
        if 'CalibrationMatrix' in robot_data:
            self.calibration_matrix = self._getCalibrationMatrixFromString(''.join(robot_data['CalibrationMatrix']))

        # load handler configs
        for key, val in robot_data.iteritems():
            # Ignore config sections that aren't for handlers
            if not key.endswith('Handler'):
                continue

            # Find the intended type of the handler
            try:
                handler_type = ht.getHandlerTypeClass(key)
            except KeyError:
                logging.warning('Cannot recognize handler type {!r} for robot {}({})'.format(key, self.name, self.r_type))
                self._setLoadFailureFlag()
                continue

            # Go through the handler listings for this type
            for handler_config_str in val:
                # Parse this line
                try:
                    call_descriptors, _ = parseCallString(handler_config_str, mode="single")
                except SyntaxError:
                    # This is an invalid handler config description
                    logging.exception('Cannot recognize handler config description: \n \t {!r} \n \
                                    for handler type {!r} of robot {}({})'.format(handler_config_str, key, self.name, self.r_type))
                    self._setLoadFailureFlag()
                    continue

                # Figure out how to interpret the different parts of the CallDescriptor name
                if len(call_descriptors[0].name) == 3:
                    robot_type, h_type, handler_name = call_descriptors[0].name
                    # 3-part name is only valid for shared handlers
                    if robot_type != 'share':
                        raise SyntaxError("Name must be in form of 'share.<handler_type>.<handler_name>' or '<robot_type>.<handler_name>'")
                elif len(call_descriptors[0].name) == 2:
                    robot_type, handler_name = call_descriptors[0].name
                    h_type = None
                else:
                    raise SyntaxError("Name must be in form of 'share.<handler_type>.<handler_name>' or '<robot_type>.<handler_name>'")

                # Check that this handler belongs to this robot (it's kind of redundant that the `robot_type` must be
                # specified if we're only going to let it be one value...)
                if (robot_type != 'share') and (robot_type.lower() != self.r_type.lower()):
                    # this is a handler for a wrong robot
                    logging.warning('The handler config description: \n \t {!r} \n \
                                    is for robot {}, but is located in data for robot {}({})' \
                                    .format(handler_config_str, robot_type, self.name, self.r_type))
                    self._setLoadFailureFlag()
                    continue

                # if the description also specifies the handler type in it
                # we need to make sure it matches with the handler type we get from section name
                if h_type is not None:
                    # get the handler type as class object
                    try:
                        handler_type_from_str = ht.getHandlerTypeClass(h_type)
                    except KeyError:
                        logging.warning('Cannot recognize handler type {!r} in config description: \n \t {!r} \n \
                                        for robot {}({})'.format(h_type, handler_config_str, self.name, self.r_type))
                        self._setLoadFailureFlag()
                        continue

                    if handler_type_from_str != handler_type:
                        # the handler type from the description does not match the one from section name
                        logging.warning('Misplaced handler description: \n \t {!r} \n \
                                        in handler type {!r} for robot {}({})' \
                                        .format(handler_config_str, handler_type, self.name, self.r_type))
                        # we still want to put this handler config into the right type
                        handler_type = handler_type_from_str

                if robot_type == 'share' and h_type is None:
                    # This is a shared handler but no handler type information is given
                    logging.warning('Handler type info missing for {!r} handler in config description: \n \t {!r} \n \
                                    for robot {}({})'.format(robot_type, handler_config_str, self.name, self.r_type))
                    self._setLoadFailureFlag()
                    continue

                # now let's get the handler config object based on the info we have got
                handler_config = hsub.getHandlerConfigDefault(robot_type, handler_type, handler_name)

                # make sure it successfully loaded
                if handler_config is None:
                    self._setLoadFailureFlag()
                    continue

                # load all parameter values and overwrite the ones in the __init__ method of default handler config object
                try:
                    init_method_config = handler_config.getMethodByName('__init__')
                except ValueError:
                    logging.warning('Cannot update default parameters of default handler config {!r}'.format(handler_config.name))
                else:
                    init_method_config.updateParaFromDict(call_descriptors[0].args)

                # if it is successfully fetched, we save it at the corresponding handler type of this robot
                if handler_type not in self.handlers:
                    # This type of handler has not been loaded yet
                    self.handlers[handler_type] = handler_config
                else:
                    # This type of handler has been loaded, for now, we will NOT overwrite it with new entry
                    # A warning will be shown
                    logging.warning('Multiple handler configs are detected for handler type {!r} of robot {}({}). \
                            Will only load the first one.'.format(key, self.name, self.r_type))
                    break
Пример #7
0
                robot_config = RobotConfig()
                try:
                    robot_config.fromData(data, hsub)
                except ht.LoadingError, msg:
                    logging.warning(str(msg) + ' in robot data .')
                    continue
                except TypeError:
                    # missing hsub
                    continue
                else:
                    self.robots.append(robot_config)

        # Missing main robot.
        # if the main robot for this config cannot be loaded, raise an error
        if self.main_robot not in [r.name for r in self.robots]:
            ht.LoadingError("Missing main robot config object")

    def saveConfig(self):
        """
        Save the config object.
        Return True for successfully saved, False for not
        """
        # TODO: check if the config is complete

        # the file name is default to be the config name with underscore
        if self.name == "":
            self.name = 'Untitled configuration'
        file_name = self.name.replace(' ', '_')

        # Add extension to the name
        file_name = file_name+'.config'