Skip to content

Commit

Permalink
merge _checkArgumentType and _castParamTypes
Browse files Browse the repository at this point in the history
  • Loading branch information
rcannood committed Oct 9, 2023
1 parent ca44670 commit 25eba55
Show file tree
Hide file tree
Showing 2 changed files with 77 additions and 69 deletions.
Original file line number Diff line number Diff line change
@@ -1,36 +1,82 @@
class UnexpectedArgumentTypeException extends Exception {
String key
String id
String stage
String plainName
String expectedClass
String foundClass

UnexpectedArgumentTypeException(String key, String id, String stage, String plainName, String expectedClass, String foundClass) {
super("Error${key ? " module '$key'" : ""}${id ? " id '$id'" : ""}:${stage ? " $stage" : "" } argument '${plainName}' has the wrong type. " +
"Expected type: ${expectedClass}. Found type: ${foundClass}")
this.key = key
this.id = id
this.stage = stage
this.plainName = plainName
this.expectedClass = expectedClass
this.foundClass = foundClass
}
}

/**
* Checks if the given value is of the expected type. If not, an exception is thrown.
*
* @param stage The stage of the argument (input or output)
* @param par The parameter definition
* @param value The value to check
* @param id The id of tuple where the data comes from. Can be null if unknown.
* @param key The key of the module
* @return The value, if it is of the expected type
* @throws UnexpectedArgumentTypeException If the value is not of the expected type
*/
def _checkArgumentType(String stage, Map par, Object value, String id, String key) {
// expectedClass will only be != null if value is not of the expected type
def expectedClass = null
def foundClass = null

if (!par.required && value == null) {
expectedClass = null
} else if (par.multiple) {
if (par.type == "file" && par.direction == "input" && value instanceof String) {
value = file(value, hidden: true)
}
if (value !instanceof List) {
if (value !instanceof Collection) {
value = [value]
}
try {
value = value.collect { listVal ->
_checkArgumentType(stage, par + [multiple: false], listVal, id, key)
}
} catch (Exception e) {
expectedClass = "List[${par.type}]"
} catch (UnexpectedArgumentTypeException e) {
expectedClass = "List[${e.expectedClass}]"
foundClass = "List[${e.foundClass}]"
}
} else if (par.type == "string") {
if (value instanceof GString) {
value = value.toString()
}
expectedClass = value instanceof String ? null : "String"
} else if (par.type == "integer") {
// TODO: allow this?
if (value instanceof String && value.isInteger()) {
value = value.toInteger()
}
if (value instanceof java.math.BigInteger) {
value = value.intValue()
}
expectedClass = value instanceof Integer ? null : "Integer"
} else if (par.type == "long") {
if (value instanceof String && value.isLong()) {
value = value.toLong()
}
if (value instanceof Integer) {
value = value.toLong()
}
expectedClass = value instanceof Long ? null : "Long"
} else if (par.type == "double") {
if (value instanceof String && value.isDouble()) {
value = value.toDouble()
}
if (value instanceof java.math.BigDecimal) {
value = value.doubleValue()
}
Expand All @@ -39,15 +85,23 @@ def _checkArgumentType(String stage, Map par, Object value, String id, String ke
}
expectedClass = value instanceof Double ? null : "Double"
} else if (par.type == "boolean" | par.type == "boolean_true" | par.type == "boolean_false") {
if (value instanceof String) {
value = value.toLowerCase()
if (value == "true") {
value = true
} else if (value == "false") {
value = false
}
}
expectedClass = value instanceof Boolean ? null : "Boolean"
} else if (par.type == "file") {
if (stage == "output" || par.direction == "input") {
if (value instanceof File) {
value = value.toPath()
}
if (value instanceof String) {
value = file(value, hidden: true)
}
if (value instanceof File) {
value = value.toPath()
}
expectedClass = value instanceof Path ? null : "Path"
} else { // stage == "input" && par.direction == "output"
if (value instanceof GString) {
Expand All @@ -60,8 +114,10 @@ def _checkArgumentType(String stage, Map par, Object value, String id, String ke
}

if (expectedClass != null) {
error "Error in module '${key}' id '${id}': ${stage} argument '${par.plainName}' has the wrong type. " +
"Expected type: ${expectedClass}. Found type: ${value.getClass()}"
if (foundClass == null) {
foundClass = value.getClass().getName()
}
throw new UnexpectedArgumentTypeException(key, id, stage, par.plainName, expectedClass, foundClass)
}

return value
Expand Down
Original file line number Diff line number Diff line change
@@ -1,63 +1,3 @@
/**
* Cast parameters to the correct type as defined in the Viash config
*
* @param parValues A Map of input arguments.
*
* @return The input arguments that have been cast to the type from the viash config.
*/
private Map<String, Object> _castParamTypes(Map<String, Object> parValues, Map config) {
// Cast the input to the correct type according to viash config
def castParValues = parValues.collectEntries({ parName, parValue ->
def paramSettings = config.functionality.allArguments.find({it.plainName == parName})
// dont parse parameters like publish_dir ( in which case paramSettings = null)
def parType = paramSettings ? paramSettings.get("type", null) : null

// turn parValue into a list, if it isn't one already
if (parValue !instanceof Collection) {
parValue = [parValue]
}

if (parType == "file" && paramSettings.get("direction", "input") == "input") {
parValue = parValue.collectMany{ parValueItem ->
if (parValueItem instanceof String) {
parValueItem = file(parValueItem)
}
if (parValueItem !instanceof Collection) {
parValueItem = [parValueItem]
}
parValueItem
}
// cast Paths to File? Or vice versa?
// parValue = parValue.collect{
// if (path instanceof Path) {
// [path.toFile()]
// } else {
// [path]
// }
// }
} else if (parType == "integer") {
parValue = parValue.collect{it as Integer}
} else if (parType == "double") {
parValue = parValue.collect{it as Double}
} else if (parType == "boolean" ||
parType == "boolean_true" ||
parType == "boolean_false") {
parValue = parValue.collect{it as Boolean}
}

// simplify list to value if need be
if (paramSettings && !paramSettings.multiple) {
assert parValue.size() == 1 :
"Error: argument ${parName} has too many values.\n" +
" Expected amount: 1. Found: ${parValue.size()}"
parValue = parValue[0]
}

[parName, parValue]
})
return castParValues
}

/**
* Apply the argument settings specified in a Viash config to a single parameter set.
* - Split the parameter values according to their seperator if
Expand All @@ -74,7 +14,19 @@ private Map<String, Object> _castParamTypes(Map<String, Object> parValues, Map c
*/
Map<String, Object> applyConfigToOneParameterSet(Map<String, Object> paramValues, Map config){
def splitParamValues = _splitParams(paramValues, config)
def castParamValues = _castParamTypes(splitParamValues, config)
def castParamValues = paramValues.collectEntries({ parName, parValue ->
def paramSettings = config.functionality.allArguments.find({it.plainName == parName})
// dont parse parameters like publish_dir ( in which case paramSettings = null)

if (paramSettings) {
// check if the parameter is a list
def tupleId = null
def componentKey = null
parValue = _checkArgumentType("input", paramSettings, parValue, tupleId, componentKey)
}

[parName, parValue]
})

// Check if any unexpected arguments were passed
def knownParams = config.functionality.allArguments.collect({it.plainName}) + ["publishDir", "publish_dir"]
Expand Down

0 comments on commit 25eba55

Please sign in to comment.