diff --git a/lib/galaxy/model/__init__.py b/lib/galaxy/model/__init__.py index 3df40b27bc0e..c8128a19b730 100644 --- a/lib/galaxy/model/__init__.py +++ b/lib/galaxy/model/__init__.py @@ -1838,7 +1838,8 @@ def io_dicts(self, exclude_implicit_outputs=False) -> IoDicts: if obj.name not in out_data: out_collections[obj.name] = obj.dataset_collection_instance # else this is a mapped over output - out_collections.update([(obj.name, obj.dataset_collection) for obj in self.output_dataset_collections]) + if not exclude_implicit_outputs: + out_collections.update([(obj.name, obj.dataset_collection) for obj in self.output_dataset_collections]) return IoDicts(inp_data, out_data, out_collections) # TODO: Add accessors for members defined in SQL Alchemy for the Job table and diff --git a/test/unit/data/model/test_model.py b/test/unit/data/model/test_model.py index 692578533dc5..4ec6c459af8a 100644 --- a/test/unit/data/model/test_model.py +++ b/test/unit/data/model/test_model.py @@ -18,3 +18,27 @@ def test_get_uuid(): def test_permitted_actions(): actions = model.Dataset.permitted_actions assert actions and len(actions.values()) == 2 + + +def test_io_dicts_excludes_implicit_output_collections(): + """Regression test for https://github.com/galaxyproject/galaxy/issues/22015 + + When a tool with an explicit collection output is mapped over a list, + each job gets a JobToImplicitOutputDatasetCollectionAssociation pointing + to a DatasetCollection with precreated (unpopulated) elements. + io_dicts(exclude_implicit_outputs=True) must exclude these to avoid + crashes during metadata serialization on unpopulated elements. + """ + job = model.Job() + dc = model.DatasetCollection(collection_type="paired") + assoc = model.JobToImplicitOutputDatasetCollectionAssociation(name="paired_output", dataset_collection=dc) + job.output_dataset_collections.append(assoc) + + # With exclude_implicit_outputs=True, output_dataset_collections must be excluded + io = job.io_dicts(exclude_implicit_outputs=True) + assert "paired_output" not in io.out_collections + + # With exclude_implicit_outputs=False (default), they should be included + io = job.io_dicts(exclude_implicit_outputs=False) + assert "paired_output" in io.out_collections + assert io.out_collections["paired_output"] is dc