orthonym.perception.molcache#
Note
Internal API. Names and behaviour may change between releases.
Per-naming-call cache of a molecule’s atom and bond tuples (audit 2026-09-03, S2).
Why: for a in mol.GetAtoms runs through RDKit’s Python sequence wrapper
(rdkit/Chem/__init__.py: __iter__ -> __getitem__ -> _sizeCalc per
step). A 58-atom walk costs about 88 us that way, 53 us through
GetAtomWithIdx and 14 us over a materialised tuple. The engine walks the
same input molecule hundreds of times per name – every dispatch predicate
scans the atoms once – so on a dev split this wrapper was 24% of engine CPU.
What atoms_of(mol) / bonds_of(mol) promise:
Same atoms, same order as
mol.GetAtoms/mol.GetBonds. The tuple is built fromGetAtomWithIdx(i)foriin index order, which is exactly the wrapper’s iteration order.Scope = one top-level naming call. The tuple lives in the memo scope that
assembly.memoopens aroundname; with no open scope nothing is cached and every call rebuilds. Cross-molecule staleness is structurally impossible.Never a stale tuple. Only immutable-by-convention
Chem.Molobjects are cached; aChem.RWMol(the only type on which atoms can be removed, replaced or added) is always rebuilt. The entry keeps a strong reference to the molecule, soid(mol)cannot be recycled by a new molecule while the entry exists, and a hit is also checked against the live atom/bond count.Verify mode.
ORTHONYM_MOLCACHE=verifyrebuilds on every hit and raisesMolCacheMismatchErrorif any cached atom’s identity, element or charge differs from the live molecule – the same continuous completeness checkassembly.memooffers.ORTHONYM_MOLCACHE=offdisables caching.
Atom and bond wrappers reference the live C++ objects, so property edits made
in place on a Chem.Mol (aromaticity, charges, isotopes) are visible through
the cached tuple exactly as through a fresh GetAtoms.
- exception orthonym.perception.molcache.MolCacheMismatchError#
Bases:
AssertionErrorVerify mode: a cached atom/bond tuple no longer matches the live molecule.
- orthonym.perception.molcache.atoms_of(mol)#
tuple(mol.GetAtoms)in index order, cached per naming call.
- orthonym.perception.molcache.bonds_of(mol)#
tuple(mol.GetBonds)in index order, cached per naming call.
- orthonym.perception.molcache.inchikey_of(mol)#
Chem.MolToInchiKey(mol)cached per mol object within the naming scope (Lever F, 2026-09-12). The entry pinsmol(so its id cannot be recycled) and stores the_inchi_sig()fingerprint; a hit is served only when the live fingerprint is equal, so an in-place edit of charge, isotope, H count, chirality or bond order/stereo forces a recompute. RWMol is never cached. Verify mode recomputes on every hit and raises on a difference.
- orthonym.perception.molcache.canon_smiles(smi)#
Chem.CanonSmiles(smi): a pure function of the string, so a process-wide LRU is exact.
- orthonym.perception.molcache.cached_by_key(mol, ns, key, fresh)#
Memoise
freshunder(ns, id(mol), key)for the naming scope (Lever E, 2026-09-12). The entry pinsmolso its id cannot be recycled; RWMol is never cached; verify mode recomputes on every hit and raises:class:MolCacheMismatchError on a difference. The caller puts everything the value depends on intokey(see ring_selection.ring_system_score).