Skip to content

Commit bc7080c

Browse files
jmchiltonclaude
andcommitted
accept 'format' alias on Data/DataCollection parameter models
AliasChoices("extensions", "format") on DataParameterModel and DataCollectionParameterModel; populate_by_name per-class. Serialization unchanged (always emits 'extensions'). model_validator hard-errors if both keys present. Regenerated ToolSourceSchema.json. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 42a2186 commit bc7080c

3 files changed

Lines changed: 68 additions & 2 deletions

File tree

client/src/components/Tool/ToolSourceSchema.json

Lines changed: 1 addition & 1 deletion
Large diffs are not rendered by default.

lib/galaxy/tool_util_models/parameters.py

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1113,11 +1113,14 @@ class BatchDataNonCollectionInstanceInternal(StrictModel):
11131113

11141114

11151115
class DataParameterModel(BaseGalaxyToolParameterModelDefinition):
1116+
model_config = ConfigDict(populate_by_name=True)
1117+
11161118
parameter_type: Literal["gx_data"] = "gx_data"
11171119
type: Literal["data"]
11181120
extensions: Annotated[
11191121
List[str],
11201122
Field(
1123+
validation_alias=AliasChoices("extensions", "format"),
11211124
description="Limit inputs to datasets with these extensions. Use 'data' to allow all input datasets.",
11221125
examples=["txt", "tabular", "tiff"],
11231126
),
@@ -1126,6 +1129,13 @@ class DataParameterModel(BaseGalaxyToolParameterModelDefinition):
11261129
min: Optional[int] = None
11271130
max: Optional[int] = None
11281131

1132+
@model_validator(mode="before")
1133+
@classmethod
1134+
def _reject_extensions_and_format(cls, data):
1135+
if isinstance(data, dict) and "extensions" in data and "format" in data:
1136+
raise ValueError("Specify either 'extensions' or 'format', not both")
1137+
return data
1138+
11291139
def field_kwargs(self) -> Dict[str, Any]:
11301140
kwargs = super().field_kwargs()
11311141
extra = kwargs["json_schema_extra"]
@@ -1341,12 +1351,24 @@ class AdaptedDataCollectionPromoteDatasetsToCollectionRequestInternal(AdaptedDat
13411351

13421352

13431353
class DataCollectionParameterModel(BaseGalaxyToolParameterModelDefinition):
1354+
model_config = ConfigDict(populate_by_name=True)
1355+
13441356
parameter_type: Literal["gx_data_collection"] = "gx_data_collection"
13451357
type: Literal["data_collection"]
13461358
collection_type: Optional[str] = None
1347-
extensions: List[str] = ["data"]
1359+
extensions: Annotated[
1360+
List[str],
1361+
Field(validation_alias=AliasChoices("extensions", "format")),
1362+
] = ["data"]
13481363
value: Optional[Dict[str, Any]]
13491364

1365+
@model_validator(mode="before")
1366+
@classmethod
1367+
def _reject_extensions_and_format(cls, data):
1368+
if isinstance(data, dict) and "extensions" in data and "format" in data:
1369+
raise ValueError("Specify either 'extensions' or 'format', not both")
1370+
return data
1371+
13501372
def field_kwargs(self) -> Dict[str, Any]:
13511373
kwargs = super().field_kwargs()
13521374
kwargs["json_schema_extra"]["gx_extensions"] = self.extensions

test/unit/tool_util/test_yaml_parameters.py

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
BooleanParameterModel,
1717
ConditionalParameterModel,
1818
create_job_runtime_model,
19+
DataCollectionParameterModel,
1920
DataParameterModel,
2021
HiddenParameterModel,
2122
RepeatParameterModel,
@@ -353,3 +354,46 @@ def test_published_tool_source_schema_has_no_xml_only_leaks():
353354
all_property_names.update(raw.get("properties", {}).keys())
354355
leaks = [bad for bad in _BLACKLIST_SUBSTRINGS if bad in all_property_names]
355356
assert not leaks, f"XML-only fields leaked into published schema: {leaks}"
357+
358+
359+
def test_data_param_accepts_format_alias():
360+
m = DataParameterModel(type="data", name="x", format=["txt", "tabular"])
361+
assert m.extensions == ["txt", "tabular"]
362+
363+
364+
def test_data_param_accepts_extensions_name():
365+
m = DataParameterModel(type="data", name="x", extensions=["bam"])
366+
assert m.extensions == ["bam"]
367+
368+
369+
def test_data_param_default_extensions():
370+
m = DataParameterModel(type="data", name="x")
371+
assert m.extensions == ["data"]
372+
373+
374+
def test_data_param_serializes_as_extensions():
375+
dumped = DataParameterModel(type="data", name="x", format=["txt"]).model_dump()
376+
assert "extensions" in dumped
377+
assert "format" not in dumped
378+
assert dumped["extensions"] == ["txt"]
379+
380+
381+
def test_data_param_rejects_both_format_and_extensions():
382+
with pytest.raises(ValidationError):
383+
DataParameterModel(type="data", name="x", extensions=["a"], format=["b"])
384+
385+
386+
def test_data_collection_param_accepts_format_alias():
387+
m = DataCollectionParameterModel(type="data_collection", name="c", format=["bam"], value=None)
388+
assert m.extensions == ["bam"]
389+
390+
391+
def test_data_collection_param_serializes_as_extensions():
392+
dumped = DataCollectionParameterModel(type="data_collection", name="c", format=["bam"], value=None).model_dump()
393+
assert "extensions" in dumped
394+
assert "format" not in dumped
395+
396+
397+
def test_data_collection_param_rejects_both_format_and_extensions():
398+
with pytest.raises(ValidationError):
399+
DataCollectionParameterModel(type="data_collection", name="c", extensions=["a"], format=["b"], value=None)

0 commit comments

Comments
 (0)