to_mmcif: quote empty pdbx_strand_id so _struct_ref_seq stays readable - #433
Merged
keitaroyam merged 1 commit intoJun 18, 2026
Merged
Conversation
When a structure has a blank chain name (e.g. a PDB file with no chain ID) and a DBREF, the _struct_ref_seq.pdbx_strand_id value is empty. It was added to the loop raw, so the writer emitted it as a zero-width token: the data row then had one value fewer than the loop has tags, making the whole mmCIF file unreadable (gemmi's own reader rejects it with "Wrong number of values in loop _struct_ref_seq", and strict third-party readers such as MMDB/clipper abort on it). Every sibling field in this row is already passed through a helper (string_or_qmark, string_or_dot, .str(), qchain); pdbx_strand_id was the only raw one. Wrap it in qchain(), matching the adjacent _struct_ref row's qchain(ent.name) and qchain's documented purpose (chain names, empty -> ''). The empty value now serialises as '' and the loop round-trips. Added a regression test that blanks a chain name on 1pfe and checks the written _struct_ref_seq re-reads cleanly.
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.
Problem
For a structure with a blank chain name (e.g. a PDB file with no chain ID) and a DBREF,
make_mmcif_document()produces an mmCIF file that gemmi itself cannot read back:The empty
_struct_ref_seq.pdbx_strand_idis written as a zero-width token, so the data row ends up with one value fewer than the loop has tags. The loop is ragged, and the whole file becomes unreadable — not just by gemmi's strict reader, but by other consumers too (this surfaced as an MMDB/clipperMessage_fatalabort in a downstream pipeline reading gemmi-written mmCIF).It reproduces on current
masterand on the 0.7.5 release. Real-world trigger: legacy single-chain PDB entries with a blank chain ID that carry DBREF records (e.g. PDB2ACY).Cause
In the
_struct_ref_seqrow builder (src/to_mmcif.cpp), every field is passed through a sanitising helper (string_or_qmark,string_or_dot,.str(),qchain) — exceptpdbx_strand_id, which was added raw:seq_loop.add_row({std::to_string(++counter2), std::to_string(counter), strand_id->second, // pdbx_strand_id <-- raw; empty -> zero-width token id, ...When
strand_id->secondis empty, nothing is emitted for that column.Fix
Wrap it in
qchain()— exactly what the adjacent_struct_refrow already does forqchain(ent.name), and whatqchain's own comment describes (chain names that may be empty, written as''). The empty value now serialises as''(a valid quoted empty string), the loop is well-formed, and it round-trips.One-line change. Added a regression test (
tests/test_mol.py::test_empty_strand_id_struct_ref_seq) that blanks a chain name on1pfeand asserts the written_struct_ref_seqre-reads cleanly; it fails before the change (Wrong number of values in loop _struct_ref_seq) and passes after. Fulltest_mol.py/test_cif.pypass with no regressions.