Skip to content
This repository has been archived by the owner on Jul 16, 2020. It is now read-only.

Commit

Permalink
Add context input type
Browse files Browse the repository at this point in the history
  • Loading branch information
kofalt committed Mar 14, 2018
1 parent 6cbb9cc commit 0223b86
Show file tree
Hide file tree
Showing 6 changed files with 85 additions and 16 deletions.
45 changes: 37 additions & 8 deletions gears/generator.py
Original file line number Diff line number Diff line change
Expand Up @@ -94,18 +94,46 @@ def derive_invocation_schema(manifest):
for kind in ['config', 'inputs']:
for key in manifest[kind]:
# Copy constraints, removing 'base' and 'description' keywords which are not constraints
val = copy.deepcopy(manifest[kind][key])
val.pop('base', None)
val.pop('description', None)
optional = val.pop('optional', False)
value = copy.deepcopy(manifest[kind][key])
value.pop('base', None)
value.pop('description', None)
optional = value.pop('optional', False)

# The config map holds scalars, while the inputs map holds objects.
if kind == 'config':
result['properties'][kind]['properties'][key] = val
result['properties'][kind]['properties'][key] = value
else:
result['properties'][kind]['properties'][key] = {}
result['properties'][kind]['properties'][key]['properties'] = val
result['properties'][kind]['properties'][key]['type'] = 'object'
keyType = manifest[kind][key]['base']
spec = {}

if keyType == 'file' or keyType == 'api-key':
# Object with any particular properties (could be refined further)
spec = {
'type': 'object',
'properties': value, # copy over schema snippet from manifest
}

elif keyType == 'context':
# Object with information about a lookup value
spec = {
'type': 'object',
'properties': {
'base': {
'type': 'string',
},
'found': {
'type': 'boolean',
},
'value': { }, # Context inputs can have any type, or none at all
},
'required': [ 'base', 'found', 'value' ]
}
else:
# Whitelist input types
raise Exception("Unknown input type " + str(keyType))

# Save into result
result['properties'][kind]['properties'][key] = spec

# Require the key be present unless optional flag is set.
if not optional:
Expand Down Expand Up @@ -165,3 +193,4 @@ def validate_invocation(manifest, invocation):

inv_schema = derive_invocation_schema(manifest)
jsonschema.validate(invocation, inv_schema)
return inv_schema
5 changes: 5 additions & 0 deletions gears/invocation.example.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,11 @@
"inputs": {
"dicom": {
"type": "dicom"
},
"matlab_license_code": {
"base": "context",
"found": true,
"value": "ABC"
}
}
}
3 changes: 3 additions & 0 deletions gears/manifest.example.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@
"base": "file",
"type": { "enum": [ "dicom" ] }

},
"matlab_license_code": {
"base": "context"
}
}
}
2 changes: 1 addition & 1 deletion spec/manifest.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@
"properties": {
"base": {
"type": "string",
"enum": [ "file", "api-key" ],
"enum": [ "file", "api-key", "context" ],
"description": "The type of gear input."
},
"description": {
Expand Down
28 changes: 25 additions & 3 deletions spec/readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -100,10 +100,10 @@ Note, the `// comments` shown below are not JSON syntax and cannot be included i
},

"description": "A set of 3D coordinates."
}
},
},

// Inputs (files) that the gear consumes
// Inputs that the gear consumes
"inputs": {

// A label - describes one of the inputs. Used by the user interface and by the run script.
Expand All @@ -116,7 +116,13 @@ Note, the `// comments` shown below are not JSON syntax and cannot be included i
"type": { "enum": [ "dicom" ] },

"description": "Any dicom file."
}
},

// A contextual key-value, provided by the environment. Used for values that are generally the same for an entire project.
// Not guaranteed to be found - the gear should decide if it can continue to run, or exit with an error.
"matlab_license_code": {
"base": "context",
},
}
}
```
Expand All @@ -139,6 +145,16 @@ Like the inputs, you can add JSON schema constraints as desired. Please specify

The example has named one config option, called "speed", which must be an integer between zero and three, and another called "coordinates", which must be a set of three floats.

### Contextual values

Context inputs are values that are generally provided by the environment, rather than the human or process running the gear. These are generally values that are incidentally required rather than directly a part of the algorithm - for example, a license key.

It is up to the gear executor to decide how (and if) context is provided. In the Flywheel system, the values can be provided by setting a `context.key-name` value on a container's metadata. For example, you could set `context.matlab_license_code: "AEX"` on the project, and then any gear running in that project with a context input called `matlab_license_code` would receive the value.

Unlike a gear's config values, contexts are not guaranteed to exist _or_ have a specific type or format. It is up to the gear to decide if it can continue, or exit with an error, when a context value does not match what the gear expects. In the example config file below, note that the `found` key can be checked to determine if a value was provided by the environment.

Because context values are not namespaced, it is suggested that you use a specific and descriptive name. The `matlab_license_code` example is a good, self-explanatory key that many gears could likely reuse.

### The input folder

When a gear is executed, an `input` folder will be created relative to the base folder. If a gear has anything previously existing in the `input` folder it will be removed at launch time.
Expand Down Expand Up @@ -176,6 +192,12 @@ Inside the `/flywheel/v0` folder a `config.json` file will be provided with any
"modality" : null,
"size" : 2913379
}
},

"matlab_license_code": {
"base": "context",
"found": true,
"value": "ABC"
}
}
}
Expand Down
18 changes: 14 additions & 4 deletions validate.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,17 @@
import gears

x = gears.load_json_from_file("gears/manifest.example.json")
gears.validate_manifest(x)
manifest = gears.load_json_from_file("gears/manifest.example.json")
invocation = gears.load_json_from_file("gears/invocation.example.json")

y = gears.load_json_from_file("gears/invocation.example.json")
gears.validate_invocation(x, y)
print "Validating manifest:"
print gears.format_json(manifest)
print
gears.validate_manifest(manifest)

print "Validating invocation:"
print gears.format_json(invocation)
print
schema = gears.validate_invocation(manifest, invocation)

print "Resulted in invocation schema:"
print gears.format_json(schema)

0 comments on commit 0223b86

Please sign in to comment.