def spec(): """Workflow specification dictionary for test purposes.""" return { 'name': 'myname', 'var1': tp.VARIABLE('A'), 'var2': tp.VARIABLE('A'), 'var3': tp.VARIABLE('E? e1'), 'values': [{ 'name': 'name', 'el1': tp.VARIABLE('B'), 'el2': tp.VARIABLE('G?Z'), 'el3': tp.VARIABLE('F'), 'nest': { 'var': tp.VARIABLE('D') } }, tp.VARIABLE('C'), tp.VARIABLE('B'), 3, 'E'], 'count': 2 }
def test_parameter_references(spec): """Test getting parameter references for a workflow specification.""" params = tp.get_parameter_references(spec) assert params == set({'A', 'B', 'C', 'D', 'E', 'F', 'G'}) # Error for nested lists. spec = { 'values': [{ 'name': 'name', 'el': tp.VARIABLE('B'), 'nest': { 'var': tp.VARIABLE('D') } }, [tp.VARIABLE('C'), tp.VARIABLE('B')]], 'count': 2 } with pytest.raises(err.InvalidTemplateError): tp.get_parameter_references(spec)
def modify_template(self, template, parameters): """Modify a the workflow specification in a given template by adding the a set of parameters. If a parameter in the added parameters set already exists in the template the name, index, default value, the value list and the required flag of the existing parameter are replaced by the values of the given parameter. Returns a modified workflow template. Raises an error if the parameter identifier in the resulting template are no longer unique. Note that this currently will only work for serial REANA workflow specifications. Will raise an InvalidTemplateError otherwise. Parameters ---------- template: flowserv.model.template.base.WorkflowTemplate Workflow template handle. parameters: dict(flowserv.model.parameter.base.TemplateParameter) Additional template parameters Returns ------- flowserv.model.template.base.WorkflowTemplate Raises ------ flowserv.core.error.InvalidTemplateError """ workflow_spec = template.workflow_spec # Raise an invalid template error if the workflow specification is not # a REANA serial workflow. workflow_type = workflow_spec.get('workflow', {}).get('type', 'null') if workflow_type != 'serial': msg = "invalid workflow type '{}'".format(workflow_type) raise err.InvalidTemplateError(msg) # Get a copy of the files and parameters sections of the inputs # declaration inputs = workflow_spec.get('inputs', dict()) in_files = list(inputs.get('files', list())) in_params = dict(inputs.get('parameters', dict())) # Ensure that the identifier for all parameters are unique para_merge = dict(template.parameters) for para in parameters.values(): if para.identifier in para_merge: para = para_merge[para.identifier].merge(para) para_merge[para.identifier] = para # Depending on whether the type of the parameter is a file or not we # add a parameter reference to the respective input section if para.is_file(): in_files.append(tp.VARIABLE(para.identifier)) else: if para.identifier not in in_params: in_params[para.identifier] = tp.VARIABLE(para.identifier) spec = dict(workflow_spec) spec['inputs'] = {'files': in_files, 'parameters': in_params} return WorkflowTemplate(workflow_spec=spec, sourcedir=template.sourcedir, parameters=para_merge, modules=template.modules, postproc_spec=template.postproc_spec, result_schema=template.result_schema)
def test_extract_parameter_name(variable, name): """Test function to extract the parameter name from a template parameter string. """ assert tp.get_name(tp.VARIABLE(variable)) == name
'name': 'name', 'el1': tp.VARIABLE('B'), 'el2': tp.VARIABLE('G?Z'), 'el3': tp.VARIABLE('F'), 'nest': { 'var': tp.VARIABLE('D') } }, tp.VARIABLE('C'), tp.VARIABLE('B'), 3, 'E'], 'count': 2 } @pytest.mark.parametrize('value,args,result', [(tp.VARIABLE('A'), { 'A': 1 }, 1), (tp.VARIABLE('A ? xyz : abc'), { 'A': True }, 'xyz'), (tp.VARIABLE('A ? xyz : abc'), { 'A': 'true' }, 'xyz'), (tp.VARIABLE('A ? xyz : abc'), { 'A': False }, 'abc'), (tp.VARIABLE('C'), { 'A': 1 }, 'default')]) def test_expand_parameter_value(value, args, result): """Test expand parameter reference function.""" parameters = ParameterIndex() parameters['A'] = String(name='A', label='P1', index=0) parameters['B'] = String(name='B', label='P2', index=0)
def test_template_serialization(): """Test creating template instances from serializations.""" # Minimal template specification. doc = {'workflow': dict()} doc = WorkflowTemplate.from_dict(doc).to_dict() template = WorkflowTemplate.from_dict(doc) assert template.workflow_spec == dict() assert template.parameters == ParameterIndex() # Maximal template specification. doc = { 'workflow': { 'inputs': [tp.VARIABLE('A'), 'B', 'C'] }, 'parameters': [String(name='A', label='P1', index=0).to_dict()], 'parameterGroups': [{ 'name': '0', 'title': 'G1', 'index': 0 }, { 'name': '1', 'title': 'G2', 'index': 1 }], 'postproc': { 'workflow': dict(), 'inputs': { 'files': ['D', 'E'] } }, 'results': { 'file': 'results/analytics.json', 'schema': [{ 'name': '0', 'label': 'col0', 'dtype': PARA_STRING }] } } doc = WorkflowTemplate.from_dict(doc).to_dict() template = WorkflowTemplate.from_dict(doc) assert template.workflow_spec == {'inputs': [tp.VARIABLE('A'), 'B', 'C']} assert len(template.parameters) == 1 assert len(template.parameter_groups) == 2 assert template.postproc_spec['workflow'] == dict() # No error for invalid document only if validate is not set to False. para = String(name='0', label='P1', index=0).to_dict() para['addOn'] = 1 doc = { 'workflow': { 'inputs': ['A', 'B', 'C'] }, 'parameters': [para], 'parameterGroups': [{ 'name': '0', 'title': 'G1', 'index': 0, 'sortDesc': True }, { 'name': '1', 'title': 'G2', 'index': 1 }], 'postproc': { 'inputs': { 'files': ['D', 'E'] } } } WorkflowTemplate.from_dict(doc, validate=False) with pytest.raises(err.InvalidParameterError): WorkflowTemplate.from_dict(doc) # Error for missing workflow specification. with pytest.raises(err.InvalidTemplateError): WorkflowTemplate.from_dict(dict()) # Error for unknown parameter. with pytest.raises(err.UnknownParameterError): doc = { 'workflow': { 'inputs': [tp.VARIABLE('0'), 'B', 'C'] }, 'parameters': [String(name='A', label='P1', index=0).to_dict()] } WorkflowTemplate.from_dict(doc)
'el1': tp.VARIABLE('B'), 'el2': '{}{}'.format(tp.VARIABLE('G?Z'), tp.VARIABLE('F')), 'nest': { 'var': tp.VARIABLE('D') } }, tp.VARIABLE('C'), tp.VARIABLE('B'), 3, 'E'], 'count': 2 } @pytest.mark.parametrize( 'value,args,result', [(tp.VARIABLE('A'), { 'A': 1 }, '1'), (tp.VARIABLE('A ? xyz : abc'), { 'A': True }, 'xyz'), (tp.VARIABLE('A ? xyz : abc'), { 'A': 'true' }, 'xyz'), (tp.VARIABLE('A ? xyz : abc'), { 'A': False }, 'abc'), (tp.VARIABLE('C'), { 'A': 1 }, 'default'), ('{} : {} = {}{}'.format(tp.VARIABLE('A'), tp.VARIABLE('B ? y'), tp.VARIABLE('C'), tp.VARIABLE('A ? t')), { 'A': 'x', 'B': 'True'