def add_component(self, _component_config): """Add the component configuration passed as parameter Add it to MonanasDSL configuration, and return a new unique ID generated for it. The configuration passed as parameter is validated, raising exceptions if the module does not exist or the configuration is invalid. :type _component_config: dict :param _component_config: configuration of the component to be added :rtype: str :returns: Component ID for the added component :raises: MonanasNoSuchClassError -- if the defined class doesn't exist or is not of a valid type :raises: SchemaError -- if the configuration is not valid for the class. """ if type(_component_config) == str: _component_config = json.loads(_component_config) clz = cu.get_class_by_name(_component_config[MODULE]) clz.validate_config(_component_config) comp_type = cu.get_component_type(_component_config[MODULE]) comp_id = self._generate_id(comp_type) self._config[comp_type][comp_id] = _component_config self._config[const.CONNECTIONS][comp_id] = [] return comp_id
def eval_comp(context, comp, expected_type): """ Instantiate the given component, computing the required config. :type context: ctx.EvaluationContext :param context: Evaluation context. :type comp: ast.Component :param comp: the node to evaluate. :type expected_type: type_util.IsType :param expected_type: The expected type of this computation. :return: Returns the instantiated component. """ arguments = {} # Compute arguments for arg in comp.args: arg_name = ast.DotPath(arg.arg_name.span, arg.arg_name, []) arg_value = eval_rhs(context, arg.value, expected_type[arg_name]) arguments[arg.arg_name.inner_val()] = arg_value # Lookup component component_type = introspect.get_class_by_name(comp.type_name.val) # Get default config for the component conf = component_type.get_default_config() # Update modified params for k, val in arguments.iteritems(): conf[k] = val # Delay evaluation until we do the assign return component_type, conf
def eval_comp(context, comp, expected_type): """ Instantiate the given component, computing the required config. :type context: ctx.EvaluationContext :param context: Evaluation context. :type comp: ast.Component :param comp: the node to evaluate. :type expected_type: type_util.IsType :param expected_type: The expected type of this computation. :return: Returns the instantiated component. """ arguments = {} # Compute arguments for arg in comp.args: arg_name = ast.DotPath(arg.arg_name.span, arg.arg_name, []) arg_value = eval_rhs(context, arg.value, expected_type[arg_name]) arguments[arg.arg_name.inner_val()] = arg_value # Lookup component component_type = introspect.get_class_by_name(comp.type_name.val) # Get default config for the component conf = component_type.get_default_config() # Update modified params for k, val in six.iteritems(arguments): conf[k] = val # Delay evaluation until we do the assign return component_type, conf
def create(self, varname, modulename): """Add a module defined by modulename in the configuration :type varname: str :param varname: name of the variable representing the new component :rtype: str :returns: new component ID """ clz = cu.get_class_by_name(modulename) conf = copy.deepcopy(clz.get_default_config()) comp_id = self.dsl.add_component(conf) self.mappings[varname] = comp_id return comp_id
def modify_component(self, comp_id, params_path, value): """Overrides the value of the configuration path of a component Modifies the configuration of the component defined by comp_id, following the path in the dictionary defined by params_path, and assigning the value value. :type comp_id: str :param comp_id: ID of the component to be modified :type params_path: list :param params_path: parameters path to modify in the config :type value: str | int | float :param value: new value to be assigned, will be parsed according to the expected configuration :rtype: bool :returns: True if the component was modified (or if the modification result was the same as the existing configuration), False otherwise :raises: SchemaError -- if the new configuration would not be valid """ comp_type = self._get_type_by_id(comp_id) if not comp_type: return False new_conf = copy.deepcopy(self._config[comp_type][comp_id]) logger.debug("Modifying " + comp_id + ", existing config = " + str(new_conf)) clz = cu.get_class_by_name(new_conf[MODULE]) for var_type in [str, int, float]: try: parsed_value = var_type(value) except ValueError as e: logger.debug(str(e)) continue new_conf = self._modify_dictionary(new_conf, params_path, parsed_value) try: clz.validate_config(new_conf) logger.debug("New validated config = " + str(new_conf)) self._config[comp_type][comp_id] = new_conf return True except voluptuous.Invalid as e: logger.debug(str(e)) continue return False
def _create_component_by_module(comp_id, comp_config, comp_type): """Create a single component matching the past configuration. The id assigned to that component will be comp_id. :type comp_id: str :param comp_id: ID of the component to create :type comp_config: dict :param comp_config: Configuration of the component to create :type comp_type: str :param comp_type: type of component to create :rtype: monasca_analytics.component.base.BaseComponent :returns: Instantiated component object """ logger.debug("deploying " + comp_config["module"] + " object") clazz = common_util.get_class_by_name(comp_config["module"], comp_type) _comp = clazz(comp_id, comp_config) return _comp
def typeck_component(component, type_table): """ Type-check the provided component. Returns the appropriate subclass of util.Component if successful, or raise an exception if there's an error. :type component: ast.Component :param component: The component ast node. :type type_table: typetbl.TypeTable :param type_table: the type table. :rtype: u.Source | u.Sink | u.Voter | u.Ldp | u.Sml | u.Ingestor :return: Returns the appropriate type for the component. """ # TODO(Joan): This wont't work for type that are defined # TODO(Joan): at the language level. We need a registration service # TODO(Joan): to manage the Types of component that we can create # TODO(Joan): instead of this hacky function call. try: component_type = introspect.get_class_by_name(component.type_name.val) comp_params = component_type.get_params() except exception_monanas.MonanasNoSuchClassError: raise exception.BananaUnknown(component) # Compute the type of the component if issubclass(component_type, source.BaseSource): comp_type = u.Source(component_type.__name__, comp_params) elif issubclass(component_type, sink.BaseSink): comp_type = u.Sink(component_type.__name__, comp_params) elif issubclass(component_type, sml.BaseSML): comp_type = u.Sml(component_type.__name__, comp_params) elif issubclass(component_type, voter.BaseVoter): comp_type = u.Voter(component_type.__name__, comp_params) elif issubclass(component_type, ldp.BaseLDP): comp_type = u.Ldp(component_type.__name__, comp_params) elif issubclass(component_type, ingestor.BaseIngestor): comp_type = u.Ingestor(component_type.__name__, comp_params) else: raise exception.BananaTypeCheckerBug( "Couldn't find a type for '{}'".format(component.type_name.val)) # Type check the parameters if len(component.args) > len(comp_params): raise exception.BananaComponentTooManyParams(component.span) # Does saying that parameter should either all have a name # or non at all satisfying? -> Yes # Are parameter all named? all_named = -1 for arg in component.args: if arg.arg_name is not None: if all_named == 0: raise exception.BananaComponentMixingParams(arg.span, False) all_named = 1 else: if all_named == 1: raise exception.BananaComponentMixingParams(arg.span, True) all_named = 0 if all_named == 1: for arg in component.args: param = filter(lambda x: x.param_name == arg.arg_name.inner_val(), comp_params) if len(param) != 1: raise exception.BananaComponentIncorrectParamName( component=component.type_name, found=arg.arg_name) param = param[0] expr_type = typeck_rhs(arg.value, type_table) if not u.can_be_cast_to(expr_type, param.param_type): raise exception.BananaArgumentTypeError( where=arg, expected_type=param.param_type, received_type=expr_type) else: for arg, param in zip(component.args, comp_params): arg.arg_name = ast.Ident(arg.span, param.param_name) expr_type = typeck_rhs(arg.value, type_table) if not u.can_be_cast_to(expr_type, param.param_type): raise exception.BananaArgumentTypeError( where=arg, expected_type=param.param_type, received_type=expr_type) return comp_type
def typeck_component(component, type_table): """ Type-check the provided component. Returns the appropriate subclass of util.Component if successful, or raise an exception if there's an error. :type component: ast.Component :param component: The component ast node. :type type_table: typetbl.TypeTable :param type_table: the type table. :rtype: u.Source | u.Sink | u.Voter | u.Ldp | u.Sml | u.Ingestor :return: Returns the appropriate type for the component. """ # TODO(Joan): This wont't work for type that are defined # TODO(Joan): at the language level. We need a registration service # TODO(Joan): to manage the Types of component that we can create # TODO(Joan): instead of this hacky function call. try: component_type = introspect.get_class_by_name(component.type_name.val) comp_params = component_type.get_params() except exception_monanas.MonanasNoSuchClassError: raise exception.BananaUnknown( component ) # Compute the type of the component if issubclass(component_type, source.BaseSource): comp_type = u.Source(component_type.__name__, comp_params) elif issubclass(component_type, sink.BaseSink): comp_type = u.Sink(component_type.__name__, comp_params) elif issubclass(component_type, sml.BaseSML): comp_type = u.Sml(component_type.__name__, comp_params) elif issubclass(component_type, voter.BaseVoter): comp_type = u.Voter(component_type.__name__, comp_params) elif issubclass(component_type, ldp.BaseLDP): comp_type = u.Ldp(component_type.__name__, comp_params) elif issubclass(component_type, ingestor.BaseIngestor): comp_type = u.Ingestor(component_type.__name__, comp_params) else: raise exception.BananaTypeCheckerBug("Couldn't find a type for '{}'" .format(component.type_name.val)) # Type check the parameters if len(component.args) > len(comp_params): raise exception.BananaComponentTooManyParams(component.span) # Does saying that parameter should either all have a name # or non at all satisfying? -> Yes # Are parameter all named? all_named = -1 for arg in component.args: if arg.arg_name is not None: if all_named == 0: raise exception.BananaComponentMixingParams(arg.span, False) all_named = 1 else: if all_named == 1: raise exception.BananaComponentMixingParams(arg.span, True) all_named = 0 if all_named == 1: for arg in component.args: param = list(filter(lambda x: x.param_name == arg.arg_name.inner_val(), comp_params)) if len(param) != 1: raise exception.BananaComponentIncorrectParamName( component=component.type_name, found=arg.arg_name ) param = param[0] expr_type = typeck_rhs(arg.value, type_table) if not u.can_be_cast_to(expr_type, param.param_type): raise exception.BananaArgumentTypeError( where=arg, expected_type=param.param_type, received_type=expr_type ) else: for arg, param in zip(component.args, comp_params): arg.arg_name = ast.Ident(arg.span, param.param_name) expr_type = typeck_rhs(arg.value, type_table) if not u.can_be_cast_to(expr_type, param.param_type): raise exception.BananaArgumentTypeError( where=arg, expected_type=param.param_type, received_type=expr_type ) return comp_type
def test_get_class_by_name(self): common_util.get_class_by_name("RandomSource", const.SOURCES)