From 72e56bae95e6e03a5f7e3df9d9c6a94395ad6ee6 Mon Sep 17 00:00:00 2001 From: "Michael R. Crusoe" Date: Sat, 12 Mar 2022 14:26:06 +0100 Subject: [PATCH] draft schema for paramter restrictions extension --- MANIFEST.in | 1 + cwltool/extensions-v1.2.yml | 272 +++++++++++++++++++++++++++++++ cwltool/main.py | 4 +- cwltool/process.py | 1 + tests/parameter_restrictions.cwl | 40 +++++ 5 files changed, 317 insertions(+), 1 deletion(-) create mode 100644 cwltool/extensions-v1.2.yml create mode 100644 tests/parameter_restrictions.cwl diff --git a/MANIFEST.in b/MANIFEST.in index ad16476929..a53dac4970 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -57,6 +57,7 @@ include cwltool/cwlNodeEngineJSConsole.js include cwltool/cwlNodeEngineWithContext.js include cwltool/extensions.yml include cwltool/extensions-v1.1.yml +include cwltool/extensions-v1.2.yml include cwltool/jshint/jshint_wrapper.js include cwltool/jshint/jshint.js include cwltool/hello.simg diff --git a/cwltool/extensions-v1.2.yml b/cwltool/extensions-v1.2.yml new file mode 100644 index 0000000000..6b9fb71302 --- /dev/null +++ b/cwltool/extensions-v1.2.yml @@ -0,0 +1,272 @@ +$base: http://commonwl.org/cwltool# +$namespaces: + cwl: "https://w3id.org/cwl/cwl#" + cwltool: "http://commonwl.org/cwltool#" +$graph: +- $import: https://w3id.org/cwl/CommonWorkflowLanguage.yml + +- name: Secrets + type: record + inVocab: false + extends: cwl:ProcessRequirement + fields: + class: + type: string + doc: "Always 'Secrets'" + jsonldPredicate: + "_id": "@type" + "_type": "@vocab" + secrets: + type: string[] + doc: | + List one or more input parameters that are sensitive (such as passwords) + which will be deliberately obscured from logging. + jsonldPredicate: + "_type": "@id" + refScope: 0 + + +- name: ProcessGenerator + type: record + inVocab: true + extends: cwl:Process + documentRoot: true + fields: + - name: class + jsonldPredicate: + "_id": "@type" + "_type": "@vocab" + type: string + - name: run + type: [string, cwl:Process] + jsonldPredicate: + _id: "cwl:run" + _type: "@id" + subscope: run + doc: | + Specifies the process to run. + +- name: MPIRequirement + type: record + inVocab: false + extends: cwl:ProcessRequirement + doc: | + Indicates that a process requires an MPI runtime. + fields: + - name: class + type: string + doc: "Always 'MPIRequirement'" + jsonldPredicate: + "_id": "@type" + "_type": "@vocab" + - name: processes + type: [int, cwl:Expression] + doc: | + The number of MPI processes to start. If you give a string, + this will be evaluated as a CWL Expression and it must + evaluate to an integer. + +- name: CUDARequirement + type: record + extends: cwl:ProcessRequirement + inVocab: false + doc: | + Require support for NVIDA CUDA (GPU hardware acceleration). + fields: + class: + type: string + doc: 'cwltool:CUDARequirement' + jsonldPredicate: + _id: "@type" + _type: "@vocab" + cudaVersionMin: + type: string + doc: | + Minimum CUDA version to run the software, in X.Y format. This + corresponds to a CUDA SDK release. When running directly on + the host (not in a container) the host must have a compatible + CUDA SDK (matching the exact version, or, starting with CUDA + 11.3, matching major version). When run in a container, the + container image should provide the CUDA runtime, and the host + driver is injected into the container. In this case, because + CUDA drivers are backwards compatible, it is possible to + use an older SDK with a newer driver across major versions. + + See https://docs.nvidia.com/deploy/cuda-compatibility/ for + details. + cudaComputeCapability: + type: + - 'string' + - 'string[]' + doc: | + CUDA hardware capability required to run the software, in X.Y + format. + + * If this is a single value, it defines only the minimum + compute capability. GPUs with higher capability are also + accepted. + + * If it is an array value, then only select GPUs with compute + capabilities that explicitly appear in the array. + cudaDeviceCountMin: + type: ['null', int, cwl:Expression] + default: 1 + doc: | + Minimum number of GPU devices to request. If not specified, + same as `cudaDeviceCountMax`. If neither are specified, + default 1. + cudaDeviceCountMax: + type: ['null', int, cwl:Expression] + doc: | + Maximum number of GPU devices to request. If not specified, + same as `cudaDeviceCountMin`. + +- name: intervalBase + type: record + abstract: true + fields: + low: + type: [int, float, double] + default: -.inf # negative infinity + jsonldPredicate: "cwltool:low" + high: + type: [int, float, double] + default: .inf # positive infinity + jsonldPredicate: "cwltool:high" + +- name: intInterval + type: record + extends: intervalBase + doc: | + Integer number interval specification. All integer intervals are inclusive. + fields: + class: + type: + type: enum + name: intInterval_class + symbols: + - cwltool:intInterval + jsonldPredicate: + _id: "@type" + _type: "@vocab" + low: + type: int + default: -.inf # negative infinity + jsonldPredicate: "cwltool:low" + high: + type: int + default: .inf # positive infinity + jsonldPredicate: "cwltool:high" + # compact form proposal + # doc: | + # Examples: + # "[0,3)" any real number between 0 (inclusive) and 3 (exclusive) + # "[6,)" any real number greater than or equal to 6 + # "(0,1)" any real number between 0 and 1 (exclusive) + + +- name: realInterval + type: record + extends: intervalBase + doc: | + Integer number interval + fields: + class: + type: + type: enum + name: realInterval_class + symbols: + - cwltool:realInterval + jsonldPredicate: + _id: "@type" + _type: "@vocab" + low_inclusive: + type: boolean + default: true + high_inclusive: + type: boolean + default: true + # compact form proposal + # doc: | + # Use "(" or "[" to indicate an exclusive or inclusive beginning, + # and ")" or "]" to indicate an exclusive or inclusive end. + # Default is inclusive. + # Examples: + # "[0,3)" any real number between 0 (inclusive) and 3 (exclusive) + # "[6,)" any real number greater than or equal to 6 + # "(0,1)" any real number between 0 and 1 (exclusive) + +- name: regex + type: record + doc: | + Regular Expression + TODO: what type of regex? + fields: + class: + type: + type: enum + name: regex_class + symbols: + - cwltool:regex + jsonldPredicate: + _id: "@type" + _type: "@vocab" + rpattern: + type: string + + +- name: Restrictions + type: record + fields: + input: + type: string + jsonldPredicate: + "_type": "@id" + refScope: 2 + constraints: + type: + type: array + items: + - string + - int + - float + - double + - regex + - cwl:Expression + - intInterval + - realInterval + +- name: ParameterRestrictions + type: record + extends: cwl:ProcessRequirement + inVocab: false + doc: | + Prototype of input value restrictions construct. + fields: + class: + type: + type: enum + name: ParameterRestrictions_class + symbols: + - cwltool:ParameterRestrictions + jsonldPredicate: + _id: "@type" + _type: "@vocab" + restrictions: + type: Restrictions[] + jsonldPredicate: + _id: "cwltool:restrictions" + mapSubject: input + mapPredicate: constraints + doc: | + (Only applicable for string, int, long, float and double parameters) + List of restrictions that apply to the input parameter "id". + A given parameter value should be accepted if any of the restrictions + match the input. Restrictions can be + single values (applies to all types), + ranges of the same type (applies to int, float and double), + regular expressions (for string parameters) + or Expressions (if an expression is provided, the expression must + return a boolean representing a match). + If the parameter is an array type, every value has to match at least + one of the restrictions. diff --git a/cwltool/main.py b/cwltool/main.py index df7b0f748c..0adec86c84 100755 --- a/cwltool/main.py +++ b/cwltool/main.py @@ -661,9 +661,11 @@ def setup_schema( ext10 = res.read().decode("utf-8") with pkg_resources.resource_stream(__name__, "extensions-v1.1.yml") as res: ext11 = res.read().decode("utf-8") + with pkg_resources.resource_stream(__name__, "extensions-v1.2.yml") as res: + ext12 = res.read().decode("utf-8") use_custom_schema("v1.0", "http://commonwl.org/cwltool", ext10) use_custom_schema("v1.1", "http://commonwl.org/cwltool", ext11) - use_custom_schema("v1.2", "http://commonwl.org/cwltool", ext11) + use_custom_schema("v1.2", "http://commonwl.org/cwltool", ext12) use_custom_schema("v1.2.0-dev1", "http://commonwl.org/cwltool", ext11) use_custom_schema("v1.2.0-dev2", "http://commonwl.org/cwltool", ext11) use_custom_schema("v1.2.0-dev3", "http://commonwl.org/cwltool", ext11) diff --git a/cwltool/process.py b/cwltool/process.py index 9abbfd7048..c34cfb2714 100644 --- a/cwltool/process.py +++ b/cwltool/process.py @@ -121,6 +121,7 @@ def filter(self, record: logging.LogRecord) -> bool: "http://commonwl.org/cwltool#LoadListingRequirement", "http://commonwl.org/cwltool#InplaceUpdateRequirement", "http://commonwl.org/cwltool#CUDARequirement", + "http://commonwl.org/cwltool#ParameterRestrictions", ] cwl_files = ( diff --git a/tests/parameter_restrictions.cwl b/tests/parameter_restrictions.cwl new file mode 100644 index 0000000000..a8a18eebed --- /dev/null +++ b/tests/parameter_restrictions.cwl @@ -0,0 +1,40 @@ +cwlVersion: v1.2 +class: CommandLineTool + +doc: | + Tests of paramater restrictions extension + +inputs: + one: double + two: string + + +hints: + cwltool:ParameterRestrictions: + restrictions: + one: + - class: cwltool:realInterval + low: 0 + high: 3 + high_inclusive: false + - class: cwltool:realInterval + low: 6 + # high should be the default of positive infinity + high_inclusive: false + two: + - class: cwltool:regex + rpattern: "foo.*bar" + + +baseCommand: echo + +arguments: + - $(inputs.one) + - $(inputs.two) + +outputs: + result: stdout + +$namespaces: + cwltool: "http://commonwl.org/cwltool#" +