def _apply_forward_reaction(template_row: pd.Series, config: Config) -> Optional[pd.DataFrame]: smarts_fwd = reverse_template(template_row.retro_template) mols = create_reactants_molecules(template_row.reactants) try: ref_mol = Molecule(smiles=template_row.products, sanitize=True) except MoleculeException as err: raise _ReactionException( f"reaction {template_row.reaction_hash} failed with msg {str(err)}" ) try: products = Reaction(mols=mols, smarts=smarts_fwd).apply() except ValueError as err: raise _ReactionException( f"reaction {template_row.reaction_hash} failed with msg {str(err)}" ) new_products = { product[0] for product in products if product[0] != ref_mol } if not new_products: return None correct_products = { product[0] for product in products if product[0].basic_compare(ref_mol) } if not correct_products: raise _ReactionException( f"reaction {template_row.reaction_hash} failed to produce correct product" ) return _new_dataframe( template_row, config, nrows=len(new_products), reaction_hash=[ reaction_hash(template_row.reactants, product) for product in new_products ], products=[product.smiles for product in new_products], )
def _sample_library(library: pd.DataFrame, config: Config, sampler_func: Callable) -> _DfGenerator: for _, row in library.iterrows(): mols = create_reactants_molecules(row.reactants) try: ref_mol = Molecule(smiles=row.products, sanitize=True) except MoleculeException: yield None continue new_product = None for template_row in sampler_func(row): if row.template_hash == template_row.template_hash: continue smarts_fwd = reverse_template(template_row.retro_template) try: new_product = Reaction(mols=mols, smarts=smarts_fwd).apply()[0][0] except (ValueError, IndexError): continue if new_product.basic_compare(ref_mol): continue break # If we have reached here, we have found a match that fits all criteria if not new_product: yield None continue # pylint: disable=undefined-loop-variable yield _new_dataframe( row, config, reaction_hash=[reaction_hash(row.reactants, new_product)], products=[new_product.smiles], classification=[""], retro_template=[template_row.retro_template], template_hash=[template_row.template_hash], selectivity=[0], outcomes=[1], template_code=[template_row.template_code], )
def test_reverse_template(): retro_template = "([C:2]-[C:3](=[O;D1;H0:4])-[N;H0;D3;+0:5](-[CH3;D1;+0:1])-[c:6])>>(I-[CH3;D1;+0:1]).([C:2]-[C:3](=[O;D1;H0:4])-[NH;D2;+0:5]-[c:6])" # noqa expected = "(I-[CH3;D1;+0:1]).([C:2]-[C:3](=[O;D1;H0:4])-[NH;D2;+0:5]-[c:6])>>([C:2]-[C:3](=[O;D1;H0:4])-[N;H0;D3;+0:5](-[CH3;D1;+0:1])-[c:6])" # noqa assert reverse_template(retro_template) == expected