Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

CWL Conditionals, when component doesn't handle condition when tool input parameter is a non-optional file with loadContents set to true #1969

Open
alexiswl opened this issue Jan 21, 2024 · 2 comments

Comments

@alexiswl
Copy link

alexiswl commented Jan 21, 2024

Expected Behavior

I have a small workflow below that runs an expression step that collects the file contents.

I want to only run this step if the input is not null.

Although the input file is a mandatory input for the step, I would hope that my workflow could continue because I am skipping the step with the when condition.

Actual Behavior

Unfortunately, because the tool input has a loadContents on the input file parameter, this is run before my 'when' condition on the step. Because the input file does not exist, this fails with the traceback below.

Workflow Code

class: Workflow
cwlVersion: v1.2

requirements:
  InlineJavascriptRequirement: {}

inputs:
  optional_small_file:
    label: Optional File
    type: File?
    doc: |
      This file is an optional file

steps:
  get_file_contents:
    in:
      input_file:
        source: optional_small_file
    out:
      - id: file_contents
    when: >-
      $( inputs.input_file !== null )
    run:
      class: ExpressionTool
      cwlVersion: v1.2
      inputs:
        input_file:
          type: File
          loadContents: true
      outputs:
        file_contents:
          type: string
      expression: | 
        ${
          return {
            "file_contents": inputs.input_file.contents
          };
        }
  

outputs:
  optional_file_contents:
    label: Optional file contents
    type: string?
    outputSource: get_file_contents/file_contents

Full Traceback

INFO /home/alexiswl/mambaforge/envs/cwl-ica/bin/cwltool 3.1.20240112164112
INFO Resolved 'load_contents_error_on_no_file.cwl' to 'file:///home/alexiswl/Projects/Personal/202401/cwltool-load-contents-issue/load_contents_error_on_no_file.cwl'
WARNING Workflow checker warning:
load_contents_error_on_no_file.cwl:10:5: Source 'optional_small_file' of type ["null", "File"] may
                                         be incompatible
load_contents_error_on_no_file.cwl:17:7:   with sink 'input_file' of type "File"
DEBUG Parsed job order from command line: {
    "__id": "load_contents_error_on_no_file.cwl",
    "optional_small_file": null
}
DEBUG [workflow ] initialized from file:///home/alexiswl/Projects/Personal/202401/cwltool-load-contents-issue/load_contents_error_on_no_file.cwl
INFO [workflow ] start
DEBUG [workflow ] inputs {
    "optional_small_file": null
}
INFO [workflow ] starting step get_file_contents
DEBUG [step get_file_contents] job input {
    "file:///home/alexiswl/Projects/Personal/202401/cwltool-load-contents-issue/load_contents_error_on_no_file.cwl#get_file_contents/input_file": null
}
ERROR Unhandled exception
Traceback (most recent call last):
  File "/home/alexiswl/mambaforge/envs/cwl-ica/lib/python3.12/site-packages/cwltool/workflow_job.py", line 729, in try_make_job
    inputobj = postScatterEval(inputobj)
               ^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/alexiswl/mambaforge/envs/cwl-ica/lib/python3.12/site-packages/cwltool/workflow_job.py", line 637, in postScatterEval
    if val.get("contents") is None:
       ^^^^^^^
AttributeError: 'NoneType' object has no attribute 'get'
INFO [workflow ] completed permanentFail
DEBUG [workflow ] outputs {
    "optional_file_contents": null
}
DEBUG Removing intermediate output directory /tmp/3zy6qnm7
{
    "optional_file_contents": null
}WARNING Final process status is permanentFail

Your Environment

  • cwltool version: 3.1.20240112164112
    Check using cwltool --version
@alexiswl
Copy link
Author

Workaround

I can instead create a dummy file object, before evaluating the when condition. I then add this as an element to the source component of the input_file step input parameter.

I then add the pickValue: first_non_null and update the when condition to be when the input_file contents are not empty.

class: Workflow
cwlVersion: v1.2

requirements:
  InlineJavascriptRequirement: {}
  StepInputExpressionRequirement: {}
  MultipleInputFeatureRequirement: {}

inputs:
  optional_small_file:
    label: Optional File
    type: File?
    doc: |
      This file is an optional file

steps:
  generate_dummy_file_object:
    in: []
    out:
      - id: empty_file
    run:
      class: ExpressionTool
      cwlVersion: v1.2
      inputs: []
      outputs:
        empty_file:
          type: File
      expression: |
        ${
          return {
            "empty_file": {
              "class": "File",
              "basename": "dummy_file.txt",
              "contents": ""
            }
          };
        }
  get_file_contents:
    in:
      input_file:
        source:
          - optional_small_file
          - generate_dummy_file_object/empty_file
        pickValue: first_non_null
    out:
      - id: file_contents
    when: >-
      $( inputs.input_file !== null && inputs.input_file.contents !== "" )
    run:
      class: ExpressionTool
      cwlVersion: v1.2
      inputs:
        input_file:
          type: File
          loadContents: true
      outputs:
        file_contents:
          type: string
      expression: |
        ${
          return {
            "file_contents": inputs.input_file.contents
          };
        }


outputs:
  optional_file_contents:
    label: Optional file contents
    type: string?
    outputSource: get_file_contents/file_contents

Show diff

5a6,7
>   StepInputExpressionRequirement: {}
>   MultipleInputFeatureRequirement: {}
14a17,37
>   generate_dummy_file_object:
>     in: []
>     out:
>       - id: empty_file
>     run:
>       class: ExpressionTool
>       cwlVersion: v1.2
>       inputs: []
>       outputs:
>         empty_file:
>           type: File
>       expression: |
>         ${
>           return {
>             "empty_file": {
>               "class": "File",
>               "basename": "dummy_file.txt",
>               "contents": ""
>             }
>           };
>         }
18c41,44
<         source: optional_small_file
---
>         source:
>           - optional_small_file
>           - generate_dummy_file_object/empty_file
>         pickValue: first_non_null
22c48
<       $( inputs.input_file !== null )
---
>       $( inputs.input_file !== null && inputs.input_file.contents !== "" )
39c65
<
---
>

@alexiswl
Copy link
Author

A practical example of this use-case is here:

https://github.com/alexiswl/cowsay-motd-cwl/blob/main/workflow/motd_workflow.cwl

In this case, I only want to run step B if I ran step A (because I use an output file of step A as an input in step B), Because step B uses the loadContents on this inputFile, it raises an error if I don't have an empty dummy file as a back up.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant