Skip to content

Commit

Permalink
Implement regex validators for text workflow parameter
Browse files Browse the repository at this point in the history
  • Loading branch information
mvdbeek committed Sep 5, 2024
1 parent 9a231f7 commit ac74b15
Show file tree
Hide file tree
Showing 11 changed files with 278 additions and 91 deletions.
18 changes: 17 additions & 1 deletion client/src/api/schema/schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11559,6 +11559,21 @@ export interface components {
*/
workflow_step_id: number;
};
/** InvocationFailureWorkflowParameterInvalidResponse */
InvocationFailureWorkflowParameterInvalidResponse: {
/**
* Details
* @description Message raised by validator
*/
details: string;
/**
* @description discriminator enum property added by openapi-typescript
* @enum {string}
*/
reason: "workflow_parameter_invalid";
/** Workflow parameter step that failed validation */
workflow_step_id: number;
};
/** InvocationInput */
InvocationInput: {
/**
Expand Down Expand Up @@ -11640,7 +11655,8 @@ export interface components {
| components["schemas"]["InvocationFailureExpressionEvaluationFailedResponse"]
| components["schemas"]["InvocationFailureWhenNotBooleanResponse"]
| components["schemas"]["InvocationUnexpectedFailureResponse"]
| components["schemas"]["InvocationEvaluationWarningWorkflowOutputNotFoundResponse"];
| components["schemas"]["InvocationEvaluationWarningWorkflowOutputNotFoundResponse"]
| components["schemas"]["InvocationFailureWorkflowParameterInvalidResponse"];
/** InvocationOutput */
InvocationOutput: {
/**
Expand Down
2 changes: 1 addition & 1 deletion client/src/components/Workflow/Run/WorkflowRun.vue
Original file line number Diff line number Diff line change
Expand Up @@ -195,7 +195,7 @@ defineExpose({
Workflow submission failed: {{ submissionError }}
</BAlert>
<WorkflowRunFormSimple
v-else-if="fromVariant === 'simple'"
v-if="fromVariant === 'simple'"
:model="workflowModel"
:target-history="simpleFormTargetHistory"
:use-job-cache="simpleFormUseJobCache"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ type ReasonToLevel = {
when_not_boolean: "error";
unexpected_failure: "error";
workflow_output_not_found: "warning";
workflow_parameter_invalid: "error";
};
const level: ReasonToLevel = {
Expand All @@ -34,6 +35,7 @@ const level: ReasonToLevel = {
when_not_boolean: "error",
unexpected_failure: "error",
workflow_output_not_found: "warning",
workflow_parameter_invalid: "error",
};
const levelClasses = {
Expand Down Expand Up @@ -165,6 +167,10 @@ const infoString = computed(() => {
return `Defined workflow output '${invocationMessage.output_name}' was not found in step ${
invocationMessage.workflow_step_id + 1
}.`;
} else if (reason === "workflow_parameter_invalid") {
return `Workflow parameter on step ${invocationMessage.workflow_step_id + 1} failed validation: ${
invocationMessage.details
}`;
} else {
return reason;
}
Expand Down
15 changes: 15 additions & 0 deletions lib/galaxy/schema/invocation.py
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ class FailureReason(str, Enum):
expression_evaluation_failed = "expression_evaluation_failed"
when_not_boolean = "when_not_boolean"
unexpected_failure = "unexpected_failure"
workflow_parameter_invalid = "workflow_parameter_invalid"


# The reasons below are attached to the invocation and user-actionable.
Expand Down Expand Up @@ -212,6 +213,14 @@ class GenericInvocationEvaluationWarningWorkflowOutputNotFound(
)


class GenericInvocationFailureWorkflowParameterInvalid(InvocationFailureMessageBase[DatabaseIdT], Generic[DatabaseIdT]):
reason: Literal[FailureReason.workflow_parameter_invalid]
workflow_step_id: int = Field(
..., title="Workflow parameter step that failed validation", validation_alias="workflow_step_index"
)
details: str = Field(..., description="Message raised by validator")


InvocationCancellationReviewFailed = GenericInvocationCancellationReviewFailed[int]
InvocationCancellationHistoryDeleted = GenericInvocationCancellationHistoryDeleted[int]
InvocationCancellationUserRequest = GenericInvocationCancellationUserRequest[int]
Expand All @@ -223,6 +232,7 @@ class GenericInvocationEvaluationWarningWorkflowOutputNotFound(
InvocationFailureWhenNotBoolean = GenericInvocationFailureWhenNotBoolean[int]
InvocationUnexpectedFailure = GenericInvocationUnexpectedFailure[int]
InvocationWarningWorkflowOutputNotFound = GenericInvocationEvaluationWarningWorkflowOutputNotFound[int]
InvocationFailureWorkflowParameterInvalid = GenericInvocationFailureWorkflowParameterInvalid[int]

InvocationMessageUnion = Union[
InvocationCancellationReviewFailed,
Expand All @@ -236,6 +246,7 @@ class GenericInvocationEvaluationWarningWorkflowOutputNotFound(
InvocationFailureWhenNotBoolean,
InvocationUnexpectedFailure,
InvocationWarningWorkflowOutputNotFound,
InvocationFailureWorkflowParameterInvalid,
]

InvocationCancellationReviewFailedResponseModel = GenericInvocationCancellationReviewFailed[EncodedDatabaseIdField]
Expand All @@ -253,6 +264,9 @@ class GenericInvocationEvaluationWarningWorkflowOutputNotFound(
InvocationWarningWorkflowOutputNotFoundResponseModel = GenericInvocationEvaluationWarningWorkflowOutputNotFound[
EncodedDatabaseIdField
]
InvocationFailureWorkflowParameterInvalidResponseModel = GenericInvocationFailureWorkflowParameterInvalid[
EncodedDatabaseIdField
]

_InvocationMessageResponseUnion = Annotated[
Union[
Expand All @@ -267,6 +281,7 @@ class GenericInvocationEvaluationWarningWorkflowOutputNotFound(
InvocationFailureWhenNotBooleanResponseModel,
InvocationUnexpectedFailureResponseModel,
InvocationWarningWorkflowOutputNotFoundResponseModel,
InvocationFailureWorkflowParameterInvalidResponseModel,
],
Field(discriminator="reason"),
]
Expand Down
28 changes: 27 additions & 1 deletion lib/galaxy/tool_util/parser/xml.py
Original file line number Diff line number Diff line change
Expand Up @@ -1337,7 +1337,33 @@ def parse_sanitizer_elem(self):
return self.input_elem.find("sanitizer")

def parse_validator_elems(self):
return self.input_elem.findall("validator")
elements = []
attributes = {
"type": str,
"message": str,
"negate": string_as_bool,
"check": str,
"table_name": str,
"filename": str,
"metadata_name": str,
"metadata_column": str,
"min": float,
"max": float,
"exclude_min": string_as_bool,
"exclude_max": string_as_bool,
"split": str,
"skip": str,
"value": str,
"value_json": lambda v: json.loads(v) if v else None,
"line_startswith": str,
}
for elem in self.input_elem.findall("validator"):
elem_dict = {"content": elem.text}
for attribute, type_cast in attributes.items():
if val := elem.get(attribute):
elem_dict[attribute] = type_cast(val)
elements.append(elem_dict)
return elements

def parse_dynamic_options(self) -> Optional[XmlDynamicOptions]:
"""Return a XmlDynamicOptions to describe dynamic options if options elem is available."""
Expand Down
15 changes: 15 additions & 0 deletions lib/galaxy/tool_util/parser/yaml.py
Original file line number Diff line number Diff line change
Expand Up @@ -375,6 +375,21 @@ def parse_when_input_sources(self):
sources.append((value, case_page_source))
return sources

def parse_validator_elems(self):
elements = []
if "validators" in self.input_dict:
for elem in self.input_dict["validators"]:
if "regex_match" in elem:
elements.append(
{
"message": elem.get("regex_doc"),
"content": elem["regex_match"],
"negate": elem.get("negate", False),
"type": "regex",
}
)
return elements

def parse_static_options(self) -> List[Tuple[str, str, bool]]:
static_options = []
input_dict = self.input_dict
Expand Down
4 changes: 2 additions & 2 deletions lib/galaxy/tools/parameters/basic.py
Original file line number Diff line number Diff line change
Expand Up @@ -314,7 +314,7 @@ def validate(self, value, trans=None) -> None:
try:
validator.validate(value, trans)
except ValueError as e:
raise ValueError(f"Parameter {self.name}: {e}") from None
raise ParameterValueError(str(e), self.name, value) from None

def to_dict(self, trans, other_values=None):
"""to_dict tool parameter. This can be overridden by subclasses."""
Expand Down Expand Up @@ -1981,7 +1981,7 @@ def do_validate(v):
try:
validator.validate(v, trans)
except ValueError as e:
raise ValueError(f"Parameter {self.name}: {e}") from None
raise ParameterValueError(str(e), self.name, v) from None

dataset_count = 0
if value:
Expand Down
Loading

0 comments on commit ac74b15

Please sign in to comment.