plinder.core.utils.sanitize#
Vendored copy of peppr’s sanitize with local over-valence fixes.
Warning
TEMPORARY. This is a local, hand-maintained copy of the modified
sanitize from unreleased peppr version. It carries boron-cage / main-group
over-valence tolerance and related valence/kekulization fixes that are
not yet in a released peppr and are not pip-installable from the
internal repo.
TODO(peppr): once these changes land in a published peppr release,
DELETE this module and revert every import of the form
from plinder.core.utils.sanitize import sanitize as peppr_sanitize
back to from peppr import sanitize as peppr_sanitize
(grep the tree for peppr_sanitize to find all call sites). Note that
mol_from_smiles() is a plinder wrapper, not part of upstream peppr —
RELOCATE it (e.g. to a core utils module) rather than deleting it.
Deliberate local deltas from the upstream peppr body: this warning docstring; the
bool(...) wraps on the predicate returns (plinder’s minimal mypy env has no rdkit
stubs, so Chem is Any and strict’s warn_return_any would flag them);
and a trimmed _ORGANOMETALLIC_OMITTED_ELEMENTS comment (correctness, pending upstream).
- plinder.core.utils.sanitize.mol_from_smiles(smiles: str | None) Mol | None[source]#
Parse a SMILES into a sanitized RDKit mol via the tolerant peppr sanitizer.
This is the canonical way to re-parse a stored ligand SMILES anywhere in plinder. Plain
Chem.MolFromSmilesapplies strict valence sanitization and returnsNonefor the over-valent main-group centres (boron cages, hypervalent metals) that the mol-building path accepts, so descriptors, classification, fingerprints and identity keys must reparse the same way or they silently drop those ligands. Here we parse without sanitizing and then runsanitize(), which accepts exactly what the build path accepts.For a valid organic molecule the result is chemically identical to
Chem.MolFromSmiles(sanitizefinishes with a fullSANITIZE_ALLpass), so fingerprints/canonical SMILES do not drift. It is a faithful tolerant drop-in: parsing withsanitize=Falseskips the parser’sassignStereochemistryfinalisation that strictMolFromSmilesruns, so we re-run it here — otherwise double-bond E/Z (parsed as bond directions but never translated into bond stereo) would be left unperceived while atom@/@@parity survived. ReturnsNonefor an empty/Noneinput or a SMILES that cannot be parsed or repaired.
- plinder.core.utils.sanitize.sanitize(mol: Mol, max_fix_iterations: int = 100) None[source]#
Sanitize a molecule, repairing the problems that make RDKit’s
SanitizeMol()fail on otherwise-valid heavy-atom input.- Parameters:
- molChem.rdchem.Mol
The molecule to sanitize, modified in place.
- max_fix_iterationsint, optional
The maximum number of fix passes per stage.
Notes
Runs in stages, in the order RDKit resolves them - valence, then kekulization, then the rest - fixing and re-checking each before moving on:
AtomValenceException: relieve over-valence via a zero-order bond (into a valence-unlimited metal or an over-valent partner), an “onium” charge (N/O), a terminal-ligand charge (hypervalent P/S), or a borate charge (B); metal centres and carborane cages are tolerated. See_fix_valence().KekulizeException: kekulize a ring heteroatom (N/O/S) neutral-first - reduce its bond to a coordinated metal, or add a ring-N[nH]- and only as a last resort invent an onium+1(pyridinium/pyrylium/thiopyrylium). See_fix_kekule().