common-workflow-language / common-workflow-language/cwl-utils

[Feature Request] utility function to access nested fields

Open
#106 1 comment 0 reactions 0 assignees View on GitHub
Dominant language
Python
Stars
43
Forks
28
Avg merge
4h 7m
Merged PRs (30d)
4

Description

# Motivation
I want to check the existence of `DockerRequirement` and get the `DockerRequirement` object from a given CWL object obtained by `load_document`.
Similar situations happen in the case of `outputs.output_file.outputBinding.glob` and `inputs.input_file.inputBinding.position`, for example.

In the current situation, we can do it with the following steps (`cwl_obj` is a CWL object obtained by `load_document`):
- check `cwl_obj.requirements` is not `None`,
- get `cwl_obj.requirements` as an array,
- search for the element with `class: DockerRequirement`, and
- return it

Here is a pseudo code for it:
```python
if cwl_obj.requirements is None:
print("DockerRequirement is not provided")
return None

reqs = cwl_obj.requirements

# Note: even if the CWL document uses a map notation for `requirements`, it is converted into an array notation due to `mapPredicate`
assert isinstance(reqs, MutableSequence)

results = list(filter(lambda r: r.class_ == "DockerRequirement", reqs))
if not results:
print("DockerRequirement is not provided")
return None

return results[0]
```

Of course it works well.
However, it looks like a complicated code even though what I want to do is a simple task.
A simple task should be represented as a simple code, IMO.

# Proposal
It would be nice if cwl-utils provides handy ways to access nested fields in a given CWL object.
For example:

```python
docker_req = dig(cwl_obj, attrs = ["requirements", "DockerRequirement"], default = None)
if docker_req is None:
print("DockerRequirement is not provided")
return None
return docker_req
```

In this example, the `dig` function (its name comes from [Ruby](https://docs.ruby-lang.org/en/3.0.0/Hash.html#method-i-dig)) takes:
- a CWL object to be accessed
- attribute names to be checked and to be accessed recursively
- a default value

It returns a `DockerRequirement` object if there exists `requirements.DockerRequirement` in a given CWL object or returns the default value (i.e., `None`) in other cases (e.g., `requirements` is not provided or no `DockerRequirement` is specified in the object).

If it is OK to add such functions to cwl-utils, I will send a pull request for it.

Notes:
- It would be nice if `dig` can take care of [identifier map](https://www.commonwl.org/v1.2/CommandLineTool.html#map) fields. A problem is that the CWL classes generated by `schema-salad-tool --codegen` lack this information.
- Clojure has a similar function named [get-in](https://clojuredocs.org/clojure.core/get-in) for associative arrays.

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.