feat(validation): enforce single-anchor fragments

- skip fused/shared/multi-anchor side systems during extraction
- add fragment library schema and fragment_library.csv export
- make scaffold prep strict for non-spliceable positions
This commit is contained in:
2026-03-19 14:20:32 +08:00
parent 07ba27be2b
commit 46a438dd36
10 changed files with 383 additions and 21 deletions

View File

@@ -2,7 +2,12 @@ from rdkit import Chem
from macro_lactone_toolkit import MacrolactoneFragmenter
from .helpers import build_macrolactone
from .helpers import (
build_macrolactone,
build_macrolactone_with_fused_side_ring,
build_macrolactone_with_shared_atom_side_ring,
build_macrolactone_with_single_anchor_side_ring,
)
def test_fragmentation_returns_empty_list_without_sidechains():
@@ -51,3 +56,24 @@ def test_fragmentation_preserves_attachment_bond_type():
neighbor = dummy_atom.GetNeighbors()[0]
bond = mol.GetBondBetweenAtoms(dummy_atom.GetIdx(), neighbor.GetIdx())
assert bond.GetBondType() == Chem.BondType.DOUBLE
def test_fragmentation_skips_fused_side_ring_but_keeps_single_anchor_sidechains():
built = build_macrolactone_with_fused_side_ring(side_chains={10: "methyl"})
result = MacrolactoneFragmenter().fragment_molecule(built.smiles, parent_id="fused")
assert {fragment.cleavage_position for fragment in result.fragments} == {10}
def test_fragmentation_skips_shared_atom_multi_anchor_component():
built = build_macrolactone_with_shared_atom_side_ring(side_chains={11: "ethyl"})
result = MacrolactoneFragmenter().fragment_molecule(built.smiles, parent_id="shared_atom")
assert {fragment.cleavage_position for fragment in result.fragments} == {11}
def test_fragmentation_allows_single_anchor_side_ring():
built = build_macrolactone_with_single_anchor_side_ring()
result = MacrolactoneFragmenter().fragment_molecule(built.smiles, parent_id="single_anchor_ring")
assert {fragment.cleavage_position for fragment in result.fragments} == {5}