def validate_args(cls, project_filename, **kw): expected_args = set(['sample_file']) for k, v in kw.items(): expected_args.discard(k) if k == 'sample_file': if not isinstance(v, str): raise ValidationError( 'sample_file should be a path string') if not os.path.exists(path_rel_to_file(project_filename, v)): raise ValidationError(f'sample_file doesn\'t exist: {v}') else: raise ValidationError(f'Unknown argument for sampler: {k}') return True
def validate_args(cls, project_filename, **kw): expected_args = set(['n_datapoints']) for k, v in kw.items(): expected_args.discard(k) if k == 'n_datapoints': if not isinstance(v, int): raise ValidationError( 'n_datapoints needs to be an integer') if v <= 0: raise ValidationError('n_datapoints need to be >= 1') else: raise ValidationError(f'Unknown argument for sampler: {k}') if len(expected_args) > 0: raise ValidationError( 'The following sampler arguments are required: ' + ', '.join(expected_args)) return True
def validate_sampler(project_file): cfg = get_project_configuration(project_file) sampler_name = cfg['sampler']['type'] try: Sampler = BuildStockBatchBase.get_sampler_class(sampler_name) except AttributeError: raise ValidationError( f'Sampler class `{sampler_name}` is not available.') args = cfg['sampler']['args'] return Sampler.validate_args(project_file, **args)
def validate_xor_nor_schema_keys(project_file): cfg = get_project_configuration(project_file) major, minor = cfg.get('version', __schema_version__).split('.') if int(major) >= 0: if int(minor) >= 0: # xor if ('weather_files_url' in cfg.keys()) is \ ('weather_files_path' in cfg.keys()): raise ValidationError( 'Both/neither weather_files_url and weather_files_path found in yaml root' ) return True
def validate_args(cls, project_filename, **kw): expected_args = set(['logic']) extra_kw = {} for k, v in kw.items(): expected_args.discard(k) if k == 'logic': # TODO: do some validation of the logic here. pass elif k == 'resample': pass else: extra_kw[k] = v if len(expected_args) > 0: raise ValidationError('The following sampler arguments are required: ' + ', '.join(expected_args)) cls.SUB_SAMPLER_CLASS.validate_args(project_filename, **extra_kw) return True
def validate_measures_and_arguments(cfg): buildstock_dir = cfg["buildstock_directory"] measures_dir = os.path.join(buildstock_dir, 'measures') type_map = {'Integer': int, 'Boolean': bool, 'String': str, 'Double': float} measure_names = { 'BuildExistingModel': 'baseline', 'SimulationOutputReport': 'workflow_generator.args.simulation_output', 'ApplyUpgrade': 'upgrades', 'TimeseriesCSVExport': 'workflow_generator.args.timeseries_csv_export' } def cfg_path_exists(cfg_path): if cfg_path is None: return False path_items = cfg_path.split('.') a = cfg for path_item in path_items: try: a = a[path_item] # noqa F841 except KeyError: return False return True def get_cfg_path(cfg_path): if cfg_path is None: return None path_items = cfg_path.split('.') a = cfg for path_item in path_items: try: a = a[path_item] except KeyError: return None return a workflow_args = cfg['workflow_generator'].get('args', {}) if 'reporting_measures' in workflow_args.keys(): for reporting_measure in workflow_args['reporting_measures']: measure_names[reporting_measure['measure_dir_name']] = 'workflow_generator.args.reporting_measures' error_msgs = '' warning_msgs = '' for measure_name, cfg_key in measure_names.items(): measure_path = os.path.join(measures_dir, measure_name) if cfg_path_exists(cfg_key) or cfg_key == 'workflow_generator.args.residential_simulation_controls': # if they exist in the cfg, make sure they exist in the buildstock checkout if not os.path.exists(measure_path): error_msgs += f"* {measure_name} does not exist in {buildstock_dir}. \n" # check the rest only if that measure exists in cfg if not cfg_path_exists(cfg_key): continue # check argument value types for simulation output report and timeseries csv export measures if measure_name in ['SimulationOutputReport', 'TimeseriesCSVExport']: root = get_measure_xml(os.path.join(measure_path, 'measure.xml')) expected_arguments = {} required_args_with_default = {} required_args_no_default = {} for argument in root.findall('./arguments/argument'): name = argument.find('./name').text expected_arguments[name] = [] required = argument.find('./required').text default = argument.find('./default_value') default = default.text if default is not None else None if required == 'true' and not default: required_args_no_default[name] = None elif required == 'true': required_args_with_default[name] = default if argument.find('./type').text == 'Choice': for choice in argument.findall('./choices/choice'): for value in choice.findall('./value'): expected_arguments[name].append(value.text) else: expected_arguments[name] = argument.find('./type').text for actual_argument_key in get_cfg_path(measure_names[measure_name]).keys(): if actual_argument_key not in expected_arguments.keys(): error_msgs += f"* Found unexpected argument key {actual_argument_key} for "\ f"{measure_names[measure_name]} in yaml file. The available keys are: " \ f"{list(expected_arguments.keys())}\n" continue required_args_no_default.pop(actual_argument_key, None) required_args_with_default.pop(actual_argument_key, None) actual_argument_value = get_cfg_path(measure_names[measure_name])[actual_argument_key] expected_argument_type = expected_arguments[actual_argument_key] if type(expected_argument_type) is not list: try: if type(actual_argument_value) is not list: actual_argument_value = [actual_argument_value] for val in actual_argument_value: if not isinstance(val, type_map[expected_argument_type]): error_msgs += f"* Wrong argument value type for {actual_argument_key} for measure "\ f"{measure_names[measure_name]} in yaml file. Expected type:" \ f" {type_map[expected_argument_type]}, got: {val}" \ f" of type: {type(val)} \n" except KeyError: print(f"Found an unexpected argument value type: {expected_argument_type} for argument " f" {actual_argument_key} in measure {measure_name}.\n") else: # Choice if actual_argument_value not in expected_argument_type: error_msgs += f"* Found unexpected argument value {actual_argument_value} for "\ f"{measure_names[measure_name]} in yaml file. Valid values are " \ f"{expected_argument_type}.\n" for arg, default in required_args_no_default.items(): error_msgs += f"* Required argument {arg} for measure {measure_name} wasn't supplied. " \ f"There is no default for this argument.\n" for arg, default in required_args_with_default.items(): warning_msgs += f"* Required argument {arg} for measure {measure_name} wasn't supplied. " \ f"Using default value: {default}. \n" if warning_msgs: logger.warning(warning_msgs) if not error_msgs: return True else: logger.error(error_msgs) raise ValidationError(error_msgs)