def test_pluggable_inputs(self): algorithm_problems = set() for pluggable_name in local_pluggables(PluggableType.ALGORITHM): configuration = get_pluggable_configuration(PluggableType.ALGORITHM, pluggable_name) if isinstance(configuration, dict): algorithm_problems.update(configuration.get('problems', [])) err_msgs = [] all_problems = set() for pluggable_name in local_pluggables(PluggableType.INPUT): cls = get_pluggable_class(PluggableType.INPUT, pluggable_name) configuration = get_pluggable_configuration(PluggableType.INPUT, pluggable_name) missing_problems = [] if isinstance(configuration, dict): problem_names = configuration.get('problems', []) all_problems.update(problem_names) for problem_name in problem_names: if problem_name not in algorithm_problems: missing_problems.append(problem_name) if len(missing_problems) > 0: err_msgs.append("{}: No algorithm declares the problems {}.".format(cls, missing_problems)) invalid_problems = list(set(AlgorithmInput._PROBLEM_SET).difference(all_problems)) if len(invalid_problems) > 0: err_msgs.append("Base Class AlgorithmInput contains problems {} that don't belong to any Input class.".format(invalid_problems)) if len(err_msgs) > 0: self.fail('\n'.join(err_msgs))
def _update_dependencies(self, section_name, sections_to_be_deleted, pluggable_dependencies): # remove dependency pluggable type from sections to be deleted if section_name in sections_to_be_deleted: sections_to_be_deleted.remove(section_name) # update sections with dependencies recursevely for pluggable_type_dict in pluggable_dependencies: pluggable_type = pluggable_type_dict.get('pluggable_type') if pluggable_type is None: continue pluggable_name = None pluggable_defaults = pluggable_type_dict.get('default') if pluggable_defaults is not None: pluggable_name = pluggable_defaults.get(JSONSchema.NAME) if pluggable_name is not None: if pluggable_type not in self._sections: self.set_section_property(pluggable_type, JSONSchema.NAME, pluggable_name) # update default values for new dependency pluggable types default_properties = self.get_section_default_properties( pluggable_type) if isinstance(default_properties, dict): self.set_section_properties(pluggable_type, default_properties) config = get_pluggable_configuration(pluggable_type, pluggable_name) self._update_dependencies(pluggable_type, sections_to_be_deleted, config.get('depends', []))
def _update_dependency_schemas(self, pluggable_dependencies, input_parser): # update schema with dependencies recursevely for pluggable_type_dict in pluggable_dependencies: pluggable_type = pluggable_type_dict.get('pluggable_type') if pluggable_type is None: continue pluggable_name = None pluggable_defaults = pluggable_type_dict.get('default') default_properties = {} if pluggable_defaults is not None: for key, value in pluggable_defaults.items(): if key == JSONSchema.NAME: pluggable_name = value else: default_properties[key] = value default_name = pluggable_name pluggable_name = input_parser.get_section_property(pluggable_type, JSONSchema.NAME, pluggable_name) if default_name is None: default_name = pluggable_name # update dependency schema self._update_pluggable_schema(pluggable_type, pluggable_name, default_name) for property_name in self._schema['properties'][pluggable_type]['properties'].keys(): if property_name in default_properties: self._schema['properties'][pluggable_type]['properties'][property_name]['default'] = default_properties[property_name] if pluggable_name is not None: config = get_pluggable_configuration(pluggable_type, pluggable_name) self._update_dependency_schemas(config.get('depends', []), input_parser)
def _update_pluggable_schema(self, pluggable_type, pluggable_name, default_name): config = {} try: if pluggable_type is not None and pluggable_name is not None: config = get_pluggable_configuration(pluggable_type, pluggable_name) except: pass input_schema = config.get('input_schema', {}) properties = input_schema.get('properties', {}) properties[JSONSchema.NAME] = {'type': 'string'} required = input_schema.get('required', []) additionalProperties = input_schema.get('additionalProperties', True) if default_name is not None: properties[JSONSchema.NAME]['default'] = default_name required.append(JSONSchema.NAME) if pluggable_type not in self._schema['properties']: self._schema['properties'][pluggable_type] = {'type': 'object'} self._schema['properties'][pluggable_type]['properties'] = properties if len(required) > 0: self._schema['properties'][pluggable_type]['required'] = required elif 'required' in self._schema['properties'][pluggable_type]: del self._schema['properties'][pluggable_type]['required'] self._schema['properties'][pluggable_type][ 'additionalProperties'] = additionalProperties
def _validate_defaults_against_schema(self, dependency_pluggable_type, default_name, defaults): cls = get_pluggable_class(dependency_pluggable_type, default_name) default_config = get_pluggable_configuration(dependency_pluggable_type, default_name) if not isinstance(default_config, dict): return ["{} configuration isn't a dictionary.".format(cls)] schema = default_config.get('input_schema') if not isinstance(default_config, dict): return [ "{} configuration schema missing or isn't a dictionary.". format(cls) ] properties = schema.get('properties') if not isinstance(properties, dict): return [ "{} configuration schema '{}' missing or isn't a dictionary.". format(cls, 'properties') ] err_msgs = [] for default_property_name, default_property_value in defaults.items(): prop = properties.get(default_property_name) if not isinstance(prop, dict): err_msgs.append("{} configuration schema '{}/{}' " "missing or isn't a dictionary.".format( cls, 'properties', default_property_name)) return err_msgs
def get_input_problems(input_name): """ returns input problems """ config = get_pluggable_configuration(PluggableType.INPUT, input_name) if 'problems' in config: return config['problems'] return []
def test_pluggable_configuration(self): """ pluggable configuration tests """ err_msgs = [] for pluggable_type in local_pluggables_types(): for pluggable_name in local_pluggables(pluggable_type): cls = get_pluggable_class(pluggable_type, pluggable_name) configuration = get_pluggable_configuration( pluggable_type, pluggable_name) if not isinstance(configuration, dict): err_msgs.append( "{} configuration isn't a dictionary.".format(cls)) continue if pluggable_type in [ PluggableType.ALGORITHM, PluggableType.INPUT ]: if not configuration.get('problems', []): err_msgs.append( "{} missing or empty 'problems' section.".format( cls)) schema_found = False for configuration_name, configuration_value in configuration.items( ): if configuration_name in ['problems', 'depends']: if not isinstance(configuration_value, list): err_msgs.append( "{} configuration section:'{}' isn't a list.". format(cls, configuration_name)) continue if configuration_name == 'depends': err_msgs.extend( self._validate_depends(cls, configuration_value)) continue if configuration_name == 'input_schema': schema_found = True if not isinstance(configuration_value, dict): err_msgs.append( "{} configuration section:'{}' isn't a dictionary." .format(cls, configuration_name)) continue err_msgs.extend( self._validate_schema(cls, configuration_value)) continue if not schema_found: err_msgs.append( "{} configuration missing schema.".format(cls)) if err_msgs: self.fail('\n'.join(err_msgs))
def _update_algorithm_input_schema(self): # find algorithm input default_name = self.get_property_default_value(PluggableType.INPUT.value, JSONSchema.NAME) input_name = self.get_section_property(PluggableType.INPUT.value, JSONSchema.NAME, default_name) if input_name is None: # find the first valid input for the problem problem_name = self.get_section_property(JSONSchema.PROBLEM, JSONSchema.NAME) if problem_name is None: problem_name = self.get_property_default_value(JSONSchema.PROBLEM, JSONSchema.NAME) if problem_name is None: raise AquaError("No algorithm 'problem' section found on input.") for name in local_pluggables(PluggableType.INPUT): if problem_name in self.get_input_problems(name): # set to the first input to solve the problem input_name = name break if input_name is None: # just remove from schema if none solves the problem if PluggableType.INPUT.value in self.json_schema.schema['properties']: del self.json_schema.schema['properties'][PluggableType.INPUT.value] return if default_name is None: default_name = input_name config = {} try: config = get_pluggable_configuration(PluggableType.INPUT, input_name) except Exception: # pylint: disable=broad-except pass input_schema = config['input_schema'] if 'input_schema' in config else {} properties = input_schema['properties'] if 'properties' in input_schema else {} properties[JSONSchema.NAME] = {'type': 'string'} required = input_schema['required'] if 'required' in input_schema else [] additional_properties = input_schema['additionalProperties'] \ if 'additionalProperties' in input_schema else True if default_name is not None: properties[JSONSchema.NAME]['default'] = default_name required.append(JSONSchema.NAME) if PluggableType.INPUT.value not in self.json_schema.schema['properties']: self.json_schema.schema['properties'][PluggableType.INPUT.value] = {'type': 'object'} self.json_schema.schema['properties'][PluggableType.INPUT.value]['properties'] = properties self.json_schema.schema['properties'][PluggableType.INPUT.value]['required'] = required self.json_schema.schema['properties'][PluggableType.INPUT.value]['additionalProperties'] = \ additional_properties
def _get_dependency_sections(self, pluggable_type, pluggable_name): config = get_pluggable_configuration(pluggable_type, pluggable_name) dependency_sections = set() pluggable_dependencies = config.get('depends', []) for dependency_pluggable_type_dict in pluggable_dependencies: dependency_pluggable_type = dependency_pluggable_type_dict.get('pluggable_type') if dependency_pluggable_type is not None: dependency_sections.add(dependency_pluggable_type) dependency_pluggable_name = dependency_pluggable_type_dict.get('default', {}).get(JSONSchema.NAME) if dependency_pluggable_name is not None: dependency_sections.update(self._get_dependency_sections(dependency_pluggable_type, dependency_pluggable_name)) return dependency_sections
def _merge_dependencies(self): algo_name = self.get_section_property(PluggableType.ALGORITHM.value, JSONSchema.NAME) if algo_name is None: return config = get_pluggable_configuration(PluggableType.ALGORITHM, algo_name) pluggable_dependencies = [] if 'depends' not in config else config[ 'depends'] pluggable_defaults = {} if 'defaults' not in config else config[ 'defaults'] for pluggable_type in local_pluggables_types(): if pluggable_type not in [PluggableType.INPUT, PluggableType.ALGORITHM] and \ pluggable_type.value not in pluggable_dependencies: # remove pluggables from input that are not in the dependencies if pluggable_type.value in self._sections: del self._sections[pluggable_type.value] section_names = self.get_section_names() for pluggable_type in pluggable_dependencies: pluggable_name = None new_properties = {} if pluggable_type in pluggable_defaults: for key, value in pluggable_defaults[pluggable_type].items(): if key == JSONSchema.NAME: pluggable_name = pluggable_defaults[pluggable_type][ key] else: new_properties[key] = value if pluggable_name is None: continue if pluggable_type not in section_names: self.set_section(pluggable_type) if self.get_section_property(pluggable_type, JSONSchema.NAME) is None: self.set_section_property(pluggable_type, JSONSchema.NAME, pluggable_name) if pluggable_name == self.get_section_property( pluggable_type, JSONSchema.NAME): properties = self.get_section_properties(pluggable_type) if new_properties: new_properties.update(properties) else: new_properties = properties self.set_section_properties(pluggable_type, new_properties)
def get_algorithm_problems(algo_name): """ Get algorithm problem name list Args: algo_name (string): algorithm name Returns: Returns list of problem names """ config = get_pluggable_configuration(PluggableType.ALGORITHM, algo_name) if 'problems' in config: return config['problems'] return []
def _update_dependency_sections(self, section_name): prop_name = self.get_section_property(section_name, JSONSchema.NAME) config = {} if prop_name is None else get_pluggable_configuration(section_name, prop_name) pluggable_dependencies = config.get('depends', []) if section_name == PluggableType.ALGORITHM.value: classical = config.get('classical', False) # update backend based on classical if classical: if JSONSchema.BACKEND in self._sections: del self._sections[JSONSchema.BACKEND] else: if JSONSchema.BACKEND not in self._sections: self.set_section_properties(JSONSchema.BACKEND, self.get_section_default_properties(JSONSchema.BACKEND)) # update dependencies recursively self._update_dependencies(section_name, pluggable_dependencies)
def update_pluggable_schemas(self, input_parser): """ Updates schemas of all pluggables Args: input_parser (obj): input parser """ # find algorithm default_algo_name = self.get_property_default_value( PluggableType.ALGORITHM.value, JSONSchema.NAME) algo_name = input_parser.get_section_property( PluggableType.ALGORITHM.value, JSONSchema.NAME, default_algo_name) # update algorithm scheme if algo_name is not None: self._update_pluggable_schema(PluggableType.ALGORITHM.value, algo_name, default_algo_name) # update algorithm dependencies scheme config = {} if algo_name is None else get_pluggable_configuration( PluggableType.ALGORITHM, algo_name) classical = config.get('classical', False) # update algorithm backend from schema if it is classical or not if classical: if JSONSchema.BACKEND in self._schema['properties']: del self._schema['properties'][JSONSchema.BACKEND] else: if JSONSchema.BACKEND not in self._schema['properties']: self._schema['properties'][ JSONSchema.BACKEND] = self._original_schema['properties'][ JSONSchema.BACKEND] self.update_backend_schema(input_parser) pluggable_dependencies = config.get('depends', []) # remove pluggables from schema that are not in the dependencies of algorithm pluggable_dependency_names = [ item['pluggable_type'] for item in pluggable_dependencies if 'pluggable_type' in item ] for pluggable_type in local_pluggables_types(): if pluggable_type not in [PluggableType.INPUT, PluggableType.ALGORITHM] and \ pluggable_type.value not in pluggable_dependency_names and \ pluggable_type.value in self._schema['properties']: del self._schema['properties'][pluggable_type.value] self._update_dependency_schemas(pluggable_dependencies, input_parser)
def _update_dependencies(self, section_name, pluggable_dependencies): # update sections with dependencies recursevely for pluggable_type_dict in pluggable_dependencies: pluggable_type = pluggable_type_dict.get('pluggable_type') if pluggable_type is None: continue pluggable_name = pluggable_type_dict.get('default', {}).get(JSONSchema.NAME) if pluggable_name is not None: if pluggable_type not in self._sections: # update default values for new dependency pluggable types default_properties = self.get_section_default_properties(pluggable_type) if isinstance(default_properties, dict): self.set_section_properties(pluggable_type, default_properties) config = get_pluggable_configuration(pluggable_type, pluggable_name) self._update_dependencies(pluggable_type, config.get('depends', []))
def _merge_dependencies(self): algo_name = self.get_section_property(PluggableType.ALGORITHM.value, JSONSchema.NAME) if algo_name is None: return config = get_pluggable_configuration(PluggableType.ALGORITHM, algo_name) pluggable_dependencies = config.get('depends', []) section_names = self.get_section_names() for pluggable_type_dict in pluggable_dependencies: pluggable_type = pluggable_type_dict.get('pluggable_type') if pluggable_type is None: continue pluggable_name = None pluggable_defaults = pluggable_type_dict.get('default') new_properties = {} if pluggable_defaults is not None: for key, value in pluggable_defaults.items(): if key == JSONSchema.NAME: pluggable_name = value else: new_properties[key] = value if pluggable_name is None: continue if pluggable_type not in section_names: self.set_section(pluggable_type) if self.get_section_property(pluggable_type, JSONSchema.NAME) is None: self.set_section_property(pluggable_type, JSONSchema.NAME, pluggable_name) if pluggable_name == self.get_section_property( pluggable_type, JSONSchema.NAME): properties = self.get_section_properties(pluggable_type) if new_properties: new_properties.update(properties) else: new_properties = properties self.set_section_properties(pluggable_type, new_properties)
def _update_dependency_sections(self): algo_name = self.get_section_property(PluggableType.ALGORITHM.value, JSONSchema.NAME) config = {} if algo_name is None else get_pluggable_configuration( PluggableType.ALGORITHM, algo_name) classical = config['classical'] if 'classical' in config else False pluggable_dependencies = [] if 'depends' not in config else config[ 'depends'] pluggable_defaults = {} if 'defaults' not in config else config[ 'defaults'] for pluggable_type in local_pluggables_types(): # remove pluggables from input that are not in the dependencies if pluggable_type not in [PluggableType.INPUT, PluggableType.ALGORITHM] and \ pluggable_type.value not in pluggable_dependencies and \ pluggable_type.value in self._sections: del self._sections[pluggable_type.value] for pluggable_type in pluggable_dependencies: pluggable_name = None if pluggable_type in pluggable_defaults: if JSONSchema.NAME in pluggable_defaults[pluggable_type]: pluggable_name = pluggable_defaults[pluggable_type][ JSONSchema.NAME] if pluggable_name is not None and pluggable_type not in self._sections: self.set_section_property(pluggable_type, JSONSchema.NAME, pluggable_name) # update default values for new dependency pluggable types self.set_section_properties( pluggable_type, self.get_section_default_properties(pluggable_type)) # update backend based on classical if classical: if JSONSchema.BACKEND in self._sections: del self._sections[JSONSchema.BACKEND] else: if JSONSchema.BACKEND not in self._sections: self.set_section_properties( JSONSchema.BACKEND, self.get_section_default_properties(JSONSchema.BACKEND)) # reorder sections self._sections = self._order_sections(self._sections)
def _load_data(self): if self._data_loaded: return from qiskit.aqua import (local_pluggables_types, local_pluggables, get_pluggable_configuration) self._schema_property_titles = OrderedDict() self._sections = OrderedDict() for pluggable_type in sorted(local_pluggables_types(), key=lambda x: x.value): self._sections[pluggable_type.value] = OrderedDict() self._schema_property_titles[pluggable_type.value] = OrderedDict() for pluggable_name in sorted(local_pluggables(pluggable_type)): config = copy.deepcopy( get_pluggable_configuration(pluggable_type, pluggable_name)) self._populate_section(pluggable_type.value, pluggable_name, config) self._data_loaded = True
def _update_dependency_sections(self, section_name): sections_to_be_deleted = [] prop_name = self.get_section_property(section_name, JSONSchema.NAME) config = {} if prop_name is None else get_pluggable_configuration( section_name, prop_name) pluggable_dependencies = config.get('depends', []) if section_name == PluggableType.ALGORITHM.value: sections_to_be_deleted = [ name for name in self.get_section_names() if name != PluggableType.INPUT.value and self.is_pluggable_section(name) ] classical = config.get('classical', False) # update backend based on classical if classical: if JSONSchema.BACKEND in self._sections: del self._sections[JSONSchema.BACKEND] else: if JSONSchema.BACKEND not in self._sections: self.set_section_properties( JSONSchema.BACKEND, self.get_section_default_properties( JSONSchema.BACKEND)) # update dependencies recursively self._update_dependencies(section_name, sections_to_be_deleted, pluggable_dependencies) # remove pluggable sections not in algorithm dependency list for name in sections_to_be_deleted: if name in self._sections: del self._sections[name] # reorder sections self._sections = self._order_sections(self._sections)
def update_pluggable_input_schemas(self, input_parser): """ Updates schemas of all pluggables Args: input_parser (obj): input parser """ # find algorithm default_algo_name = self.get_property_default_value( PluggableType.ALGORITHM.value, JSONSchema.NAME) algo_name = input_parser.get_section_property( PluggableType.ALGORITHM.value, JSONSchema.NAME, default_algo_name) # update algorithm scheme if algo_name is not None: self._update_pluggable_input_schema(PluggableType.ALGORITHM.value, algo_name, default_algo_name) # update algorithm depoendencies scheme config = {} if algo_name is None else get_pluggable_configuration( PluggableType.ALGORITHM, algo_name) classical = config['classical'] if 'classical' in config else False pluggable_dependencies = [] if 'depends' not in config else config[ 'depends'] pluggable_defaults = {} if 'defaults' not in config else config[ 'defaults'] pluggable_types = local_pluggables_types() for pluggable_type in pluggable_types: if pluggable_type not in [PluggableType.INPUT, PluggableType.ALGORITHM] and \ pluggable_type.value not in pluggable_dependencies: # remove pluggables from schema that ate not in the dependencies if pluggable_type.value in self._schema['properties']: del self._schema['properties'][pluggable_type.value] # update algorithm backend from schema if it is classical or not if classical: if JSONSchema.BACKEND in self._schema['properties']: del self._schema['properties'][JSONSchema.BACKEND] else: if JSONSchema.BACKEND not in self._schema['properties']: self._schema['properties'][ JSONSchema.BACKEND] = self._original_schema['properties'][ JSONSchema.BACKEND] # update schema with dependencies for pluggable_type in pluggable_dependencies: pluggable_name = None default_properties = {} if pluggable_type in pluggable_defaults: for key, value in pluggable_defaults[pluggable_type].items(): if key == JSONSchema.NAME: pluggable_name = pluggable_defaults[pluggable_type][ key] else: default_properties[key] = value default_name = pluggable_name pluggable_name = input_parser.get_section_property( pluggable_type, JSONSchema.NAME, pluggable_name) # update dependency schema self._update_pluggable_input_schema(pluggable_type, pluggable_name, default_name) for property_name in self._schema['properties'][pluggable_type][ 'properties'].keys(): if property_name in default_properties: self._schema['properties'][pluggable_type]['properties'][ property_name]['default'] = default_properties[ property_name]