This is a test version of Biostars. For the public version, visit https://www.biostars.org.
cwltool "invalid field" error messages

Hello everyone!

I have written an ExpressionTool that is supposed to take files/directories as input and put them all into a folder. When using this ExpressionTool in the context of a workflow i always get the following errors:

[step pooling_output] start
invalid field `nameroot`, expected one of: 'class', 'location', 'path', 'basename', 'listing'
invalid field `nameext`, expected one of: 'class', 'location', 'path', 'basename', 'listing'
[step pooling_output] completed success

I don't know what these are supposed to mean, and i don't know which part of the code is responsible. nameext isn't even referenced in the ExpressionTool. What makes me confused is that the error messages only show up when i use the ExpressionTool as part of a Workflow (example below). I tried running several workflows up to the point where the ExpressionTool would be used and collected their output at this point. When i then feed these exact outputs into the ExpressionTool, no error messages will show up. Could this just a be bug in cwltool? I now meticulously check the output of every workflow i run out of fear that the tool might somehow garble the output (which it has done once in the past, but that specific problem has been fixed).

A big thank you to anyone who can provide insight! Cheers

The ExpressionTool:

(I suspect this might strike some as a horrifying solution. Especially because of the separate inputs for arrays and single items. But i have yet to find a better way to do this in cwl. Happy to take suggestions!)

cwlVersion: v1.0
class: ExpressionTool
label: Returns a directory named after inputs.newname, containing all input files and directories.

requirements:
  InlineJavascriptRequirement: {}

inputs:
  file_single:
    type: File?
    label: A single file which will be placed in the output directory.
  file_array:
    type: File[]?
    label: An array of files which will be placed in the output directory.
  directory_single:
    type: Directory?
    label: A single directory which will be placed in the output directory as a subdirectory.
  directory_array:
    type: Directory[]?
    label: An array of directories which will be placed in the output directory as subdirectories.
  newname:
    type: string?
    label: Name of the output-directory. If no input is provided, tool will try use the nameroot of file_single, directory_single, file_array[0], directory_array[0] (in this order).

outputs:
  pool_directory:
    type: Directory
    label: Directory where all input files and subdirectories will be pooled. Named after inputs.newname.

expression: |
  ${
    //Check if an input for newname was provided. If yes, use this as new directory name.
    var newName = "";
    var needName = true;
    if ( inputs.newname != undefined ) {
      newName = inputs.newname;
      needName = false;
    }
    //Check which input files / directories are present. Add them to the new directory.
    //If no input for newname was provided, use the name of one of the files or directories.
    var outputList = [];
    if ( inputs.file_single != undefined ) {
      outputList.push( inputs.file_single );
      if ( needName == true ) {
        newName = inputs.file_single.nameroot;
        needName = false;
      }
    }
    if ( inputs.directory_single != undefined ) {
      outputList.push( inputs.directory_single );
      if ( needName == true ) {
        newName = inputs.directory_single.basename;
        needName = false;
      }
    }
    if ( inputs.file_array != undefined ) {
      for ( var count = 0; count < inputs.file_array.length; count++ ) {
        var nextfile = inputs.file_array[count];
        outputList.push( nextfile );
      }
      if ( needName == true ) {
        newName = ((inputs.file_array)[0]).nameroot;
        needName = false;
      }
    }
    if ( inputs.directory_array != undefined ) {
      for ( var count = 0; count < inputs.directory_array.length; count++ ) {
        var nextdir = inputs.directory_array[count];
        outputList.push( nextdir );
      }
      if ( needName == true ) {
        newName = ((inputs.directory_array)[0]).basename;
        needName = false;
      }
    }
    return {
      "pool_directory": {
        "class": "Directory",
        "basename": newName,
        "listing": outputList
      }
    };
  }

A simple workflow which uses it:

cwlVersion: v1.0
class: Workflow
label: Uses various quality control tools on the input assembly.

requirements:
  StepInputExpressionRequirement: {}

hints:
  SoftwareRequirement:
    packages:
      quast:
        specs: [ https://identifiers.org/RRID:SCR_001228 ]
        version: [ "5.0.2" ]

inputs:
  assembly:
    label: Assembly to perform qc on.
    type: File
  worker_threads:
    label: Number of CPU-threads used in computationally intensive steps.
    type: int
    default: 1

outputs:
  assembly_qc_directory:
    type: Directory
    outputSource: pooling_output/pool_directory

steps:
  quast:
    run: ../quastTool.cwl
    in:
      assembly: assembly
      worker_threads: worker_threads
    out: [report_directory]
  pooling_output:
    run: ../poolingTool.cwl
    in:
      directory_single: quast/report_directory
      newname:
        valueFrom: assembly-qc-reports
    out: [pool_directory]
cwl cwltool

FYI, this sounds like an error in cwltool, I am investigating

0 answers

No answers yet.

Log in to answer this question.