Repository navigation
A feature release for linker chemistry and reaction reconstruction. It adds carboxyl-side ester protecting groups, azole N-caps, ureas and thioureas, and N-H nucleophile coverage across the coupling rows. Stripped esters are labelled by mechanism, masking works on symmetric cores, and pyridone and azaindole tautomers are placed the same way whatever the atom order. Five things change for an existing caller; they are listed under Compatibility below.
The corpus grows. Functional groups go from 253 to 265, protective groups from 103 to 106, reaction rows from 294 under 72 names to 676 under 82, and role rows from 87 to 89.
| added | rows |
|---|---|
| N-H nucleophile groups: carbamate, urea, sulfonamide, activated (N-O) ester, ring enamine NH2, alkenyl halide and sulfonate | functional:254–265 |
| N-alkylation, Buchwald–Hartwig, SNAr, Mitsunobu, amidation, sulfonylation, N-acylation and Chan–Lam over the N-H set; Weinreb amidation, acid alkylation, alcohol amination, Appel iodide | reactions up to 676 |
urea_from_amines over every pair of the five N-nucleophiles, and thiourea_from_amines |
reactions:295–321 |
carboxyl_tbu, carboxyl_benzyl, carboxyl_allyl |
protective:104–106 |
azole_nitrogen, capping the h0 nitrogen of an NH-pyrazole and an NH-imidazole |
roles:88–89 |
Organozinc groups also match [Zn;*], so a zinc reagent drawn without its halide still matches.
>>> r = smiles('NCc1ccccc1.Nc1ccccc1>>O=C(NCc1ccccc1)Nc1ccccc1')
>>> r.reconstruct_mapping()
('react:urea_from_amines',)An ester is stripped from its alkyl half and labelled ester_hydrolysis. When both halves of an ester match a protective row, the alkyl half claims it, so the ester reads as a protected acid. A strip that cuts a carboxylic ester, on either side, is labelled by its mechanism. Carbonates, carbamates and ethers keep their row name. EnumeratedDeprotection gains a fourth field, labels, parallel to names:
>>> m = smiles('c1ccccc1C(=O)OC'); m.canonicalize()
>>> o = next(m.deprotect()); o.names, o.labels
(('hydroxyl_methyl',), ('ester_hydrolysis',))
>>> m = smiles('c1ccccc1C(=O)OC(C)(C)C'); m.canonicalize()
>>> next(m.deprotect()).names
('carboxyl_tbu',)reconstruct_mapping() builds its labels from these. deprotect+react:<row> becomes deprotect:<labels>+react:<row>, so the label says what was stripped. protect: keeps the row names. A lone ester cleaved to its acid stays react:ester_hydrolysis.
>>> smiles('CC(C)(C)OC(=O)NCCC(=O)OC.OC(=O)c1ccccc1>>O=C(O)CCNC(=O)c1ccccc1').reconstruct_mapping()
('deprotect:amine_boc+ester_hydrolysis+react:amidation',)Reconstruction is harder to fool.
- Outcomes are canonicalized before they are compared.
- A component the outcome carried through unchanged from its inputs is not evidence: a counterion in a salt product no longer confirms a row.
- The protect rung settles the strip against the inputs, which recovers azole THP, SEM and Boc protections left at
H_UNKNOWN. - A rewritten centre keeps its isotope unless the token states one.
An unmapped branch is part of the reaction centre. reaction_center compares the canonical SMILES of each unmapped branch on a mapped atom. An ester hydrolysis whose leaving and incoming oxygens are both unnumbered, which is the shape reconstruct_mapping() writes, now has a centre, and remove_reagents() no longer raises on it.
A mask applies before equivalent cuts collapse. Masking one nitrogen of piperazine used to leave nothing, because the collapse had kept the masked cut as the representative. The mask now applies first, so the other end is cut. Unmasked enumeration is unchanged. StickyFragment.atom and StickyLinker.atom_left / atom_right name the source atom each cap hangs off.
>>> m = smiles('C1CNCCN1'); m.canonicalize()
>>> f, = m.sticky_fragments('alkyl_amine')
>>> [g.atom for g in m.sticky_fragments('alkyl_amine', masked={f.atom})]
[6]The template gains dedupe=False, which yields every embedding's outcome, including two that build one structure from different atoms:
>>> t = read_smirks('[C:1][OH]>>[C:1]Cl')
>>> len(list(t(smiles('OCCO')))), len(list(t(smiles('OCCO'), dedupe=False)))
(1, 2)A lactam's N-H sits next to its carbonyl, whatever the atom order. standardize_isomers() ranks candidate placements in this order:
- the aromatic bond count
thiele()gives, most first; - N-H next to a C=O or C=S carbon;
- N-H on a five-membered ring;
- atom ranks.
Terms 1–3 are graph facts, so they do not depend on how the molecule was drawn. canonicalize() also fixes the C=N of an aromatic lactim in place when the Kekulé form it was handed left the hydroxy-azine repair nothing to match, so 3-hydroxyisoquinoline reaches its lactam from every atom order:
>>> for s in ('Cc1cc(O)ncn1', 'Cc1cc(=O)[nH]cn1'):
... m = smiles(s); m.canonicalize(); print(m)
O=C1NC=NC(=C1)C
O=C1NC=NC(=C1)C
>>> m = smiles('c1c[nH]c2nccc2c1'); m.canonicalize(); print(m) # 7-azaindole reads 1H
[nH]1ccc2cccnc12A lactam N-H also no longer moves onto a fused pyridine N as a quinoid imine. An azole-fused pyridine N-oxide reaches its fixed point in one canonicalize() call, because neutralize() re-runs every round.
A drawn hydrogen is a hydrogen. In SMARTS, D counts heavy-atom neighbours only, and h counts every attached hydrogen, implicit or drawn, of any isotope. [2H]C([2H])(C)O is therefore a primary_alcohol, exactly as CCO is. neutralize() refuses, and logs, a proton drawn as an atom rather than overflowing the implicit count.
Core. A patch that bonds an aromatic pnictogen recomputes every other pnictogen with hydrogens in that ring, so the replaced tautomer's N-H comes back as H_UNKNOWN for kekule(). Tetrazoles and 1,2,3-triazoles arylated at the h0 nitrogen come out aromatic.
Compatibility
canonical_byteschanges for lactams whose N-H had been placed away from the carbonyl (guanine drawn as its 1,2-imino form, quinazolinones, pyrimidinones), for 7-azaindoles and other azole/azine pairs that read the azine N-H, and for lactimscanonicalize()used to leave in their hydroxy form. Re-key a stored corpus.- The
deprotect+react:labels change todeprotect:<labels>+react:<row>, and thedeprotect:labels readester_hydrolysisfor an ester strip. EnumeratedDeprotection,StickyFragmentandStickyLinkergain fields. Code that unpacks them positionally needs the new arity.- Ester claims move to the alkyl half. tert-Butyl and allyl benzoate, tert-butyl pivalate and tert-butyl trifluoroacetate are now
carboxyl_*; methyl benzoate ishydroxyl_methyl. - SMARTS
Dandhread drawn hydrogen atoms. A pattern matched against a molecule carrying explicit hydrogen atoms matches as it would afterimplicify_hydrogens().