def test_serialization(self): """Test serialization of workflow templates.""" template = TemplateHandle( identifier='ABC', base_dir='XYZ', workflow_spec=dict(), parameters=[ TemplateParameter(pd.parameter_declaration('A')), TemplateParameter( pd.parameter_declaration('B', data_type=pd.DT_LIST)), TemplateParameter(pd.parameter_declaration('C', parent='B')) ]) doc = DefaultTemplateLoader().to_dict(template) parameters = DefaultTemplateLoader().from_dict(doc).parameters assert len(parameters) == 3 assert 'A' in parameters assert 'B' in parameters assert len(parameters['B'].children) == 1 template = DefaultTemplateLoader().from_dict(doc) assert template.identifier == 'ABC' # The base directory is not materialized assert template.base_dir is None # Invalid resource descriptor serializations with pytest.raises(err.InvalidTemplateError): ResourceDescriptor.from_dict(dict()) with pytest.raises(err.InvalidTemplateError): ResourceDescriptor.from_dict({LABEL_ID: 'A', 'noname': 'B'})
def test_validate(self): """Test error cases for argument validation.""" para_list = TemplateParameter( pd.parameter_declaration('E', data_type=pd.DT_LIST)) with pytest.raises(ValueError): values.TemplateArgument(parameter=para_list, value=1) para_record = TemplateParameter( pd.parameter_declaration('E', data_type=pd.DT_RECORD)) with pytest.raises(ValueError): values.TemplateArgument(parameter=para_record, value=list()) arg = values.TemplateArgument(parameter=TemplateParameter( pd.parameter_declaration('E', data_type=pd.DT_INTEGER)), value=1, validate=True) arg.data_type = 'unknown' with pytest.raises(ValueError): arg.validate()
def test_init(self): """Test initialization of attribuets and error cases when creating template instances. """ th = TemplateHandle( workflow_spec=dict(), parameters=[ TemplateParameter(pd.parameter_declaration('A')), TemplateParameter(pd.parameter_declaration('B')) ]) assert not th.identifier is None assert th.base_dir is None th = TemplateHandle( identifier='ABC', base_dir='XYZ', workflow_spec=dict(), parameters=[ TemplateParameter(pd.parameter_declaration('A')), TemplateParameter(pd.parameter_declaration('B')) ]) assert th.identifier == 'ABC' assert th.base_dir == 'XYZ' with pytest.raises(err.InvalidTemplateError): TemplateHandle( workflow_spec=dict(), parameters=[ TemplateParameter(pd.parameter_declaration('A')), TemplateParameter(pd.parameter_declaration('B')), TemplateParameter(pd.parameter_declaration('A')) ])
def test_read_with_record(self): """Read argument for a template that contains a parameter of data type DT_RECORD. """ template = TemplateHandle( workflow_spec=dict(), parameters=[ TemplateParameter( pd.parameter_declaration(identifier='codeFile', data_type=pd.DT_FILE, index=0, default_value=None, as_const=AS_INPUT)), TemplateParameter( pd.parameter_declaration(identifier='dataFile', data_type=pd.DT_FILE, index=1, default_value='data/names.txt')), TemplateParameter( pd.parameter_declaration(identifier='resultFile', data_type=pd.DT_FILE, index=2, default_value=None)), TemplateParameter( pd.parameter_declaration(identifier='sleeptime', data_type=pd.DT_INTEGER, index=3, default_value=10)), TemplateParameter( pd.parameter_declaration(identifier='verbose', data_type=pd.DT_BOOL, index=4, default_value=False)), TemplateParameter( pd.parameter_declaration(identifier='frac', data_type=pd.DT_DECIMAL, index=6)), TemplateParameter( pd.parameter_declaration(identifier='outputType', index=5)), ]) sc = Scanner(reader=ListReader([ 'ABC.txt', 'code/abc.py', '', 'result/output.txt', 3, True, 'XYZ', 0.123 ])) arguments = tmpl.read(template.list_parameters(), scanner=sc) assert arguments['codeFile'].name == 'ABC.txt' assert arguments['codeFile'].target_path == 'code/abc.py' assert arguments['dataFile'].name == 'names.txt' assert arguments['dataFile'].target_path is None assert arguments['resultFile'].name == 'output.txt' assert arguments['resultFile'].target_path is None assert arguments['sleeptime'] == 3 assert arguments['verbose'] assert arguments['outputType'] == 'XYZ' assert arguments['frac'] == 0.123
def create_parameter_index(parameters, validate=True): """Create instances of template parameters from a list of dictionaries containing parameter declarations. The result is a dictionary containing the top-level parameters, indexed by their unique identifier. Parameters ---------- parameters: list(dict) List of dictionaries containing template parameter declarations validate: bool, optional Flag indicating if given template parameter declarations are to be validated against the parameter schema or not. Returns ------- dict(benchtmpl.workflow.parameter.base.TemplateParameter) Raises ------ benchtmpl.error.InvalidTemplateError benchtmpl.error.UnknownParameterError """ result = dict() for para in parameters: # Validate the template parameters if the validate flag is True if validate: pd.validate_parameter(para) # Create a TemplateParameter instance for the parameter. Keep # track of children for parameter that are of type DT_LIST or # DT_RECORD. Children are added after all parameters have been # instantiated. p_id = para[pd.LABEL_ID] # Ensure that the identifier of all parameters are unique if p_id in result: raise err.InvalidTemplateError('parameter \'{}\' not unique'.format(p_id)) c = None if para[pd.LABEL_DATATYPE] in [pd.DT_LIST, pd.DT_RECORD]: c = list() tp = TemplateParameter(pd.set_defaults(para), children=c) result[p_id] = tp # Add parameter templates to the list of children for their # respective parent (if given). We currently only support one level # of nesting. for para in parameters: if pd.LABEL_PARENT in para: p_id = para[pd.LABEL_ID] parent = para[pd.LABEL_PARENT] if not parent is None: result[parent].add_child(result[p_id]) return result
def test_propmpt(self): """Test generated prompts when reading parameter values from standard input. """ # BOOL p = TemplateParameter( pd.set_defaults( pd.parameter_declaration(identifier='ABC', data_type=pd.DT_BOOL))).prompt() assert p == 'ABC (bool): ' # FILE p = TemplateParameter( pd.set_defaults( pd.parameter_declaration(identifier='ABC', data_type=pd.DT_FILE))).prompt() assert p == 'ABC (file): ' # FLOAT p = TemplateParameter( pd.set_defaults( pd.parameter_declaration(identifier='ABC', data_type=pd.DT_DECIMAL))).prompt() assert p == 'ABC (decimal): ' # INTEGER p = TemplateParameter( pd.set_defaults( pd.parameter_declaration(identifier='ABC', data_type=pd.DT_INTEGER))).prompt() assert p == 'ABC (integer): ' # STRING p = TemplateParameter( pd.set_defaults( pd.parameter_declaration(identifier='ABC', data_type=pd.DT_STRING))).prompt() assert p == 'ABC (string): ' # Default values in prompts p = TemplateParameter( pd.set_defaults( pd.parameter_declaration(identifier='ABC', data_type=pd.DT_INTEGER, default_value=100))).prompt() assert p == 'ABC (integer) [default 100]: ' p = TemplateParameter( pd.set_defaults( pd.parameter_declaration(identifier='ABC', data_type=pd.DT_STRING, default_value=100))).prompt() assert p == 'ABC (string) [default \'100\']: '
def test_flat_parse(self): """Test parsing arguments for a flat (un-nested) parameter declaration. """ template = TemplateHandle( workflow_spec=dict(), parameters=[ TemplateParameter( pd.parameter_declaration('A', data_type=pd.DT_INTEGER)), TemplateParameter( pd.parameter_declaration('B', data_type=pd.DT_BOOL)), TemplateParameter( pd.parameter_declaration('C', data_type=pd.DT_DECIMAL)), TemplateParameter( pd.parameter_declaration('D', data_type=pd.DT_FILE, required=False)), TemplateParameter( pd.parameter_declaration('E', data_type=pd.DT_STRING, required=False)) ]) params = template.parameters fh = InputFile(f_handle=FileHandle(filepath=LOCAL_FILE)) # Valid argument set args = values.parse_arguments(arguments={ 'A': 10, 'B': True, 'C': 12.5, 'D': fh, 'E': 'ABC' }, parameters=params, validate=True) assert len(args) == 5 for key in params.keys(): assert key in args values.parse_arguments(arguments=args, parameters=params, validate=False) # Error cases with pytest.raises(ValueError): values.parse_arguments(arguments={ 'A': 10, 'Z': 0 }, parameters=params) with pytest.raises(ValueError): values.parse_arguments(arguments={ 'A': 10, 'B': True }, parameters=params) # Validate data type with pytest.raises(ValueError): values.parse_arguments(arguments={ 'A': '10', 'B': True, 'C': 12.3, 'D': fh, 'E': 'ABC' }, parameters=params, validate=True) with pytest.raises(ValueError): values.parse_arguments(arguments={ 'A': 10, 'B': 23, 'C': 12.3, 'D': fh, 'E': 'ABC' }, parameters=params, validate=True) with pytest.raises(ValueError): values.parse_arguments(arguments={ 'A': 10, 'B': True, 'C': '12.3', 'D': fh, 'E': 'ABC' }, parameters=params, validate=True) with pytest.raises(ValueError): values.parse_arguments(arguments={ 'A': 10, 'B': True, 'C': 12.3, 'D': 'fh', 'E': 'ABC' }, parameters=params, validate=True) with pytest.raises(ValueError): values.parse_arguments(arguments={ 'A': 10, 'B': True, 'C': 12.3, 'D': fh, 'E': 12 }, parameters=params, validate=True)
def test_parameter_declaration(self): """Test methods of the parameter declaration object.""" obj = pd.set_defaults(pd.parameter_declaration(identifier='ABC')) obj[pd.LABEL_AS] = 'XYZ' p = TemplateParameter(obj) # Type flags assert not p.is_bool() assert not p.is_file() assert not p.is_float() assert not p.is_int() assert not p.is_list() assert not p.is_record() assert p.is_string() # Constant values assert p.has_constant() assert p.get_constant() == 'XYZ' # Error for invalid data type with pytest.raises(err.InvalidParameterError): TemplateParameter({pd.LABEL_ID: 'A', pd.LABEL_DATATYPE: 'XYZ'})