Repository navigation
Conversation
MSTemplate.get_data writes the template drains as "drain_list", and MSTemplateBuilder.build adds self.drains to the template, but from_dict never read the field. Templates loaded from JSON therefore had no drains, and MSBuilder.build_drains fell back to DEFAULT_SINKS. The ModelSEED templates list six drains; DEFAULT_SINKS has five (cpd22811 is missing), and any other drain a template defines was ignored. Read drain_list in from_dict (empty when absent, as before). Test: from_dict loads a drain_list, and get_data -> from_dict keeps it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This was referenced Nov 6, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Heads-up: this changes gap-fill picks in real builds. With the standard templates, the set of sinks stays the same
for models that lack cpd22811. But the sinks are now created in the template's
drain_listorder instead ofDEFAULT_SINKSorder. That changes the column order of the gap-fill LP, and with it which of two near-equal solutionsthe solver picks. In two genome-scale builds, one or two gap-filled reactions swapped for an alternative, and growth
changed by less than 1e-4. With
drain_listreordered to matchDEFAULT_SINKS, the builds are identical to dev(details below).
Why this matters in our workflow
We load templates from JSON with
MSTemplateBuilder.from_dict(...).build(), and we edit them. A template'sdrain_listnever reaches the model: dev ignores it and buildsDEFAULT_SINKSinstead. cobrakbase's template loader(
NewModelTemplateBuilder.from_dict) already readsdrain_list, so templates loaded through KBase carry theirdrains, while the same JSON loaded through ModelSEEDpy does not.
What happens
MSTemplateBuilder.from_dict(
mstemplate.pyL1510-L1531 at 062714b)copies every top-level field except
drain_list.MSTemplateBuilder.buildaddsself.drainsto the template(L1641-L1642),
and
MSTemplate.get_datawrites them back asdrain_list(L1431-L1432).
Only the reader drops the field, so a template saved and loaded again loses its drains.
MSBuilder.build_drainsfalls back toDEFAULT_SINKSwhentemplate.drainsis empty(
msbuilder.pyL324-L368).DEFAULT_SINKS's five plus cpd22811 ((2R,4S)-2-methyl-2,4-dihydroxydihydrofuran-3-one, whose only templatereaction is rxn20806). On dev the cpd22811 sink is never built, and any drain a curator adds is dropped.
How to reproduce
The fix
builder.biomasses = d["biomasses"] + builder.drains = d.get("drain_list", {})DEFAULT_SINKSis used.drain_listcompound exists in its template'scompcompounds. Sobuild()'sadd_drain, which raisesValueErrorfor an unknown compound, accepts all of them. The Core templates have nodrain_list.template.drainsisMSBuilder.build_drains,build_sinksandbuild_demands.into a
DM_reaction inbuild_demands, and its message said FBA returns 0 growth withoutDM_cpd11416_c0. Thatclaim was wrong: on dev the
SK_sinks already give biomass an outlet, and builds grow without anyDM_reaction.So this PR does not include that change.
Tests
tests/core/test_mstemplate.py::test_template_builder_from_dict_drain_list:from_dictloads adrain_list(a sinkand a demand on
template_core_bigg.json), andget_datafollowed byfrom_dictkeeps it.Against dev's code:
With the fix, it passes. Full suite (Python 3.10, cobra 0.32.1, CPLEX 22.1.1):
tests/coregoes from 56 to 57passed, and
tests/from 58 to 59.black22.8.0 and the other pre-commit hooks pass.Real-model check
We ran
MSBuilder.build()on two genome-scale builds (E. coli K-12 and a Pantoea strain, from RAST annotations,GramNeg template v7.1 with Core-V6.1, minimal glucose) three ways: on dev, on this branch, and on this branch with a
template copy whose
drain_listkeys are inDEFAULT_SINKSorder (control).rxn00599instead ofrxn00181+rxn02990rxn00957+rxn12239instead ofrxn00966+rxn12376(+ an exchange)All three builds have the same sink reactions, because neither model has cpd22811; only their order differs. ATP
produced from nothing and from water + H+ + each of 7 electron acceptors stays 0.
Related
🤖 Generated with Claude Code