Skip to content

Commit 00a9eda

Browse files
authored
Merge pull request #22553 from guerler/toolrequests.000
Fix tool id handling for shed-installed tools
2 parents 808e1ee + 6fcc21f commit 00a9eda

9 files changed

Lines changed: 65 additions & 15 deletions

File tree

client/src/components/Form/utilities.js

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -194,23 +194,32 @@ function _convertValue(node, value) {
194194
return _convertDataValue(value, node.multiple);
195195
}
196196
if (node.type === "data_column") {
197-
if (value === null || value === undefined || value === "") {
198-
return value;
197+
if (value === undefined) {
198+
return undefined;
199+
}
200+
if (value === null || value === "") {
201+
return null;
199202
}
200203
if (Array.isArray(value)) {
201204
return value.map((v) => (typeof v === "string" ? parseInt(v, 10) : v));
202205
}
203206
return typeof value === "string" ? parseInt(value, 10) : value;
204207
}
205208
if (node.type === "integer") {
206-
if (value === null || value === undefined || value === "") {
207-
return value;
209+
if (value === undefined) {
210+
return undefined;
211+
}
212+
if (value === null || value === "") {
213+
return null;
208214
}
209215
return typeof value === "string" ? parseInt(value, 10) : value;
210216
}
211217
if (node.type === "float") {
212-
if (value === null || value === undefined || value === "") {
213-
return value;
218+
if (value === undefined) {
219+
return undefined;
220+
}
221+
if (value === null || value === "") {
222+
return null;
214223
}
215224
return typeof value === "string" ? parseFloat(value) : value;
216225
}

client/src/components/Form/utilities.test.js

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -726,10 +726,10 @@ describe("form component utilities", () => {
726726
expect(buildNestedState(inputs, formData)).toEqual({ col: [1, 2, 5] });
727727
});
728728

729-
it("should preserve data_column null/empty/undefined values", () => {
729+
it("should convert cleared data_column values to null but keep undefined as-is", () => {
730730
const inputs = [{ name: "col", type: "data_column" }];
731731
expect(buildNestedState(inputs, { col: null })).toEqual({ col: null });
732-
expect(buildNestedState(inputs, { col: "" })).toEqual({ col: "" });
732+
expect(buildNestedState(inputs, { col: "" })).toEqual({ col: null });
733733
expect(buildNestedState(inputs, { col: undefined })).toEqual({ col: undefined });
734734
});
735735

@@ -744,10 +744,10 @@ describe("form component utilities", () => {
744744
expect(buildNestedState(inputs, { num: "42" })).toEqual({ num: 42 });
745745
});
746746

747-
it("should preserve integer null/empty/undefined values", () => {
747+
it("should convert cleared integer values to null but keep undefined as-is", () => {
748748
const inputs = [{ name: "num", type: "integer" }];
749749
expect(buildNestedState(inputs, { num: null })).toEqual({ num: null });
750-
expect(buildNestedState(inputs, { num: "" })).toEqual({ num: "" });
750+
expect(buildNestedState(inputs, { num: "" })).toEqual({ num: null });
751751
expect(buildNestedState(inputs, { num: undefined })).toEqual({ num: undefined });
752752
});
753753

@@ -761,10 +761,10 @@ describe("form component utilities", () => {
761761
expect(buildNestedState(inputs, { val: "3.14" })).toEqual({ val: 3.14 });
762762
});
763763

764-
it("should preserve float null/empty/undefined values", () => {
764+
it("should convert cleared float values to null but keep undefined as-is", () => {
765765
const inputs = [{ name: "val", type: "float" }];
766766
expect(buildNestedState(inputs, { val: null })).toEqual({ val: null });
767-
expect(buildNestedState(inputs, { val: "" })).toEqual({ val: "" });
767+
expect(buildNestedState(inputs, { val: "" })).toEqual({ val: null });
768768
expect(buildNestedState(inputs, { val: undefined })).toEqual({ val: undefined });
769769
});
770770

lib/galaxy/celery/tasks.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,9 +92,14 @@ def cached_create_tool_from_representation(
9292
raw_tool_source: str,
9393
tool_source_class: TOOL_SOURCE_CLASS,
9494
tool_dir: Optional[str] = None,
95+
tool_id: Optional[str] = None,
9596
):
9697
return create_tool_from_representation(
97-
app=app, raw_tool_source=raw_tool_source, tool_dir=tool_dir, tool_source_class=tool_source_class
98+
app=app,
99+
raw_tool_source=raw_tool_source,
100+
tool_dir=tool_dir,
101+
tool_source_class=tool_source_class,
102+
guid=tool_id,
98103
)
99104

100105

@@ -441,6 +446,7 @@ def queue_jobs(request: QueueJobs, app: MinimalManagerApp, job_submitter: JobSub
441446
raw_tool_source=raw_tool_source,
442447
tool_dir=request.tool_source.tool_dir,
443448
tool_source_class=tool_source_class,
449+
tool_id=request.tool_source.tool_id,
444450
)
445451

446452
job_submitter.queue_jobs(

lib/galaxy/schema/tasks.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,7 @@ class ToolSource(Model):
182182
raw_tool_source: str
183183
tool_dir: Optional[str] = None
184184
tool_source_class: TOOL_SOURCE_CLASS = "XmlToolSource"
185+
tool_id: Optional[str] = None
185186

186187

187188
class QueueJobs(Model):

lib/galaxy/tool_util/parameters/convert.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -481,12 +481,16 @@ def encode_element(element: dict):
481481

482482
def encode_callback(parameter: ToolParameterT, value: Any):
483483
if isinstance(parameter, DataParameterModel):
484+
if value is None:
485+
return VISITOR_NO_REPLACEMENT
484486
if parameter.multiple and isinstance(value, list):
485487
return list(map(encode_element, value))
486488
else:
487489
assert isinstance(value, dict), str(value)
488490
return encode_element(value)
489491
elif isinstance(parameter, DataCollectionParameterModel):
492+
if value is None:
493+
return VISITOR_NO_REPLACEMENT
490494
assert isinstance(value, dict), str(value)
491495
return encode_element(value)
492496
else:

lib/galaxy/tools/__init__.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -469,10 +469,14 @@ def create_tool_from_source(app, tool_source: ToolSource, config_file: Optional[
469469

470470

471471
def create_tool_from_representation(
472-
app, raw_tool_source: str, tool_dir: Optional[StrPath] = None, tool_source_class="XmlToolSource"
472+
app,
473+
raw_tool_source: str,
474+
tool_dir: Optional[StrPath] = None,
475+
tool_source_class="XmlToolSource",
476+
guid: Optional[str] = None,
473477
) -> "Tool":
474478
tool_source = get_tool_source(tool_source_class=tool_source_class, raw_tool_source=raw_tool_source)
475-
return create_tool_from_source(app, tool_source=tool_source, tool_dir=tool_dir)
479+
return create_tool_from_source(app, tool_source=tool_source, tool_dir=tool_dir, guid=guid)
476480

477481

478482
class NullToolTagManager(AbstractToolTagManager):

lib/galaxy/webapps/galaxy/services/jobs.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -282,6 +282,7 @@ def create(self, trans: ProvidesHistoryContext, job_request: JobRequest) -> JobC
282282
raw_tool_source=tool_source_model.source,
283283
tool_dir=tool.tool_dir,
284284
tool_source_class=tool_source_model.source_class,
285+
tool_id=tool.id,
285286
)
286287
task_request = QueueJobs(
287288
user=trans.async_request_user,

test/unit/app/tools/test_tool_serialization_roundtrip.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,23 @@ def test_repopulate_after_serialization_yaml():
3636
)
3737

3838

39+
def test_repopulate_applies_guid():
40+
tool = simple_constructs_tool()
41+
raw_tool_source, tool_source_class = tool.to_raw_tool_source()
42+
guid = "toolshed.example.com/repos/owner/repo/simple_constructs_y/1.0"
43+
44+
app = mock_app_for_tool_support()
45+
rebuilt = create_tool_from_representation(
46+
app,
47+
raw_tool_source,
48+
tool.tool_dir,
49+
tool_source_class,
50+
guid=guid,
51+
)
52+
assert rebuilt.id == guid
53+
assert rebuilt.old_id == "simple_constructs_y"
54+
55+
3956
def simple_constructs_tool() -> Tool:
4057
tool_path = functional_test_tool_path("simple_constructs.yml")
4158
tool_source = functional_test_tool_source("simple_constructs_y")

test/unit/tool_util/test_parameter_convert.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,14 @@ def test_multi_data():
121121
assert encoded_state.input_state["parameter"][1]["id"] == EXAMPLE_ID_2_ENCODED
122122

123123

124+
def test_encode_optional_data_collection_none():
125+
tool_source = tool_source_for("parameters/gx_data_collection_optional")
126+
bundle = input_models_for_tool_source(tool_source)
127+
internal_state = RequestInternalToolState({"parameter": None})
128+
encoded_state = encode(internal_state, bundle, _fake_encode)
129+
assert encoded_state.input_state["parameter"] is None
130+
131+
124132
def test_landing_encode_data():
125133
tool_source = tool_source_for("parameters/gx_data")
126134
bundle = input_models_for_tool_source(tool_source)

0 commit comments

Comments
 (0)