Skip to content

Read a metabolite SMILES annotation whatever shape it is in - #56

Merged
edkerk merged 3 commits into
developfrom
fix/smiles-annotation-round-trip
Sep 20, 2026
Merged

edkerk merged 3 commits into
developfrom
fix/smiles-annotation-round-trip

Conversation

@edkerk

@edkerk edkerk commented Sep 20, 2026

Copy link
Copy Markdown
Collaborator

cobra returns an annotation value as the object it was assigned, and as a list for a model read back from a file. A metabolite annotated in memory by find_met_smiles carries "CCO"; the same metabolite after save_ec_model + load_ec_model carries ["CCO"].

extract_enzyme_substrate_pairs — which both write_dlkcat_input and the OpenKineticsPredictor input builder go through — assumed the string:

met_smiles = [m.annotation.get("smiles", "") for m in metabolites]
...
or (smiles and smiles in ignore_smiles_set)   # hashes a list

On a reloaded model that raises TypeError: cannot use 'list' as a set element (unhashable type: 'list'), and had it not, the list would have been written into the DLKcat input in place of the SMILES.

Reproduced on the full_ecModel tutorial: save the stage-1 model after find_met_smiles, reload it, call write_dlkcat_input — TypeError. The tutorial itself does not hit it because it annotates and writes in one session, but it documents reloading from the saved model between those steps.

databases.met_smiles now reads either shape and is the one place that knows the difference. Two regression tests cover the list-valued annotation: that the SMILES still reaches the output, and that the ignore-list check still matches.

Found while benchmarking something unrelated, where it silently degraded structure-based substrate matching to name-only matching rather than raising.

cobra returns an annotation value as the object it was assigned, and as
a list for a model read back from a file. A metabolite annotated in
memory by find_met_smiles carries "CCO"; the same metabolite after
save_ec_model + load_ec_model carries ["CCO"].

extract_enzyme_substrate_pairs -- which both write_dlkcat_input and the
OpenKineticsPredictor input builder go through -- assumed the string. On
a reloaded model the ignore-list membership test hashed a list and the
whole step died with TypeError, and had it not, the list would have been
written into the DLKcat input in place of the SMILES.

The tutorial does not hit this because it annotates and writes in one
session, but it documents reloading from the saved stage-1 model between
those steps, which is enough to reach it.

databases.met_smiles reads either shape and is the one place that knows
the difference.
`parse_okp_output`: indexing metabolites by `annotation['smiles']` used
the annotation value as a dict key, which raises
`TypeError: cannot use 'list' as a dict key` on a saved-and-reloaded
model, the same shape mismatch `met_smiles` already handles for the
DLKcat input writer.
@edkerk
edkerk merged commit 206e02c into develop Sep 20, 2026
5 checks passed
@edkerk
edkerk deleted the fix/smiles-annotation-round-trip branch September 20, 2026 13:40
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant