diff --git a/Code/GraphMol/ChemReactions/catch_tests.cpp b/Code/GraphMol/ChemReactions/catch_tests.cpp index 6e9ef301f..864ed6b13 100644 --- a/Code/GraphMol/ChemReactions/catch_tests.cpp +++ b/Code/GraphMol/ChemReactions/catch_tests.cpp @@ -1089,10 +1089,12 @@ TEST_CASE("CXSMILES for reactions", "[cxsmiles]") { common_properties::atomLabel, alabel)); CHECK(alabel == "_AP1"); - auto expected_cxsmiles = "[CH3:1][CH:2]([CH3:3])[*:4].[OH:5][CH2:6][*:7]>>[CH3:1][CH:2]([CH3:3])[CH2:6][OH:5] |$;;;_AP1;;;_AP1;;;;;$|"; + auto expected_cxsmiles = + "[CH3:1][CH:2]([CH3:3])[*:4].[OH:5][CH2:6][*:7]>>[CH3:1][CH:2]([CH3:3])[CH2:6][OH:5] |$;;;_AP1;;;_AP1;;;;;$|"; SmilesWriteParams params; auto flags = RDKit::SmilesWrite::CX_ALL ^ RDKit::SmilesWrite::CX_ATOM_PROPS; - std::string output_cxsmiles = ChemicalReactionToCXRxnSmiles(*rxn, params, flags); + std::string output_cxsmiles = + ChemicalReactionToCXRxnSmiles(*rxn, params, flags); CHECK(output_cxsmiles == expected_cxsmiles); auto roundtrip = v2::ReactionParser::ReactionFromSmiles(output_cxsmiles); @@ -1121,13 +1123,14 @@ TEST_CASE("CXSMILES for reactions", "[cxsmiles]") { common_properties::atomLabel, alabel)); CHECK(alabel == "_AP1"); - std::string expected_cxsmarts = "[C&H3:1][C&H1:2]([C&H3:3])[*:4].[O&H1:5][C&H2:6][*:7]>O=C=O>[C&H3:1][C&H1:2]([C&H3:3])[C&H2:6][O&H1:5] |$;;;_AP1;;;_AP1;;;;;;;;$|"; + std::string expected_cxsmarts = + "[C&H3:1][C&H1:2]([C&H3:3])[*:4].[O&H1:5][C&H2:6][*:7]>O=C=O>[C&H3:1][C&H1:2]([C&H3:3])[C&H2:6][O&H1:5] |$;;;_AP1;;;_AP1;;;;;;;;$|"; SmilesWriteParams params; auto flags = RDKit::SmilesWrite::CX_ALL ^ RDKit::SmilesWrite::CX_ATOM_PROPS; - std::string output_cxsmarts = ChemicalReactionToCXRxnSmarts(*rxn, params, flags); + std::string output_cxsmarts = + ChemicalReactionToCXRxnSmarts(*rxn, params, flags); auto roundtrip = v2::ReactionParser::ReactionFromSmarts(output_cxsmarts); - REQUIRE(roundtrip); CHECK(roundtrip->getReactants().size() == 2); CHECK(roundtrip->getReactants()[0]->getAtomWithIdx(3)->getPropIfPresent( @@ -1138,7 +1141,6 @@ TEST_CASE("CXSMILES for reactions", "[cxsmiles]") { CHECK(alabel == "_AP1"); CHECK(output_cxsmarts == expected_cxsmarts); - } SECTION("missing products") { @@ -1155,7 +1157,8 @@ TEST_CASE("CXSMILES for reactions", "[cxsmiles]") { common_properties::atomLabel, alabel)); CHECK(alabel == "_AP1"); - auto roundtrip = v2::ReactionParser::ReactionFromSmarts(ChemicalReactionToCXRxnSmarts(*rxn)); + auto roundtrip = v2::ReactionParser::ReactionFromSmarts( + ChemicalReactionToCXRxnSmarts(*rxn)); REQUIRE(roundtrip); CHECK(roundtrip->getReactants().size() == 2); CHECK(roundtrip->getReactants()[0]->getAtomWithIdx(3)->getPropIfPresent( @@ -1165,10 +1168,12 @@ TEST_CASE("CXSMILES for reactions", "[cxsmiles]") { common_properties::atomLabel, alabel)); CHECK(alabel == "_AP1"); - std::string expected_cxsmarts = "[C&H3:1][C&H1:2]([C&H3:3])[*:4].[O&H1:5][C&H2:6][*:7]>> |$;;;_AP1;;;_AP1$|"; + std::string expected_cxsmarts = + "[C&H3:1][C&H1:2]([C&H3:3])[*:4].[O&H1:5][C&H2:6][*:7]>> |$;;;_AP1;;;_AP1$|"; SmilesWriteParams params; auto flags = RDKit::SmilesWrite::CX_ALL ^ RDKit::SmilesWrite::CX_ATOM_PROPS; - std::string output_cxsmarts = ChemicalReactionToCXRxnSmarts(*rxn, params, flags); + std::string output_cxsmarts = + ChemicalReactionToCXRxnSmarts(*rxn, params, flags); CHECK(output_cxsmarts == expected_cxsmarts); } @@ -1202,7 +1207,8 @@ TEST_CASE("CXSMILES for reactions", "[cxsmiles]") { SmilesWriteParams params; auto flags = RDKit::SmilesWrite::CX_ALL ^ RDKit::SmilesWrite::CX_ATOM_PROPS; auto output_cxsmarts = ChemicalReactionToCXRxnSmarts(*rxn, params, flags); - auto expected_cxsmarts = "[#6H3:1]-[#6H:2](-[#6H3:3])-[#0:4].[Fe:8]<-[#8H:5]-[#6H2:6]-[#0:7]>>[Fe:8]<-[#8H:5]-[#6H2:6]-[#6H2:1]-[#6H:2](-[#6H3:3])-[#0:4] |$;;;_AP1;;;;_AP1;;;;;;;_AP1$,C:5.3,9.6,SgD:6:foo:bar::::,SgD:10:bar:baz::::|"; + auto expected_cxsmarts = + "[#6:1]-[#6:2](-[#6:3])-[#0:4].[Fe:8]<-[#8:5]-[#6:6]-[#0:7]>>[Fe:8]<-[#8:5]-[#6:6]-[#6:1]-[#6:2](-[#6:3])-[#0:4] |$;;;_AP1;;;;_AP1;;;;;;;_AP1$,C:5.3,9.6,SgD:6:foo:bar::::,SgD:10:bar:baz::::|"; CHECK(output_cxsmarts == expected_cxsmarts); } @@ -1213,10 +1219,12 @@ TEST_CASE("CXSMILES for reactions", "[cxsmiles]") { // clang-format on REQUIRE(rxn); - std::string expected_cxsmarts = "[#6H3:6]-[#8:5]-[#6H:3](-*)-[#8:2]-*>>[#6H3:6]-[#7H:5]-[#6H:3](-*)-[#8:2]-* |$;;;star_e;;star_e;;;;star_e;;star_e$,SgD:1,0:foo:bar::::,,SgD:7,6:foo:baz::::,,,Sg:n:4,2,1,0::ht:::,,Sg:n:10,8,7,6::ht:::,SgH:3:1.1|"; + std::string expected_cxsmarts = + "[#6:6]-[#8:5]-[#6:3](-*)-[#8:2]-*>>[#6:6]-[#7:5]-[#6:3](-*)-[#8:2]-* |$;;;star_e;;star_e;;;;star_e;;star_e$,SgD:1,0:foo:bar::::,,SgD:7,6:foo:baz::::,,,Sg:n:4,2,1,0::ht:::,,Sg:n:10,8,7,6::ht:::,SgH:3:1.1|"; SmilesWriteParams params; auto flags = RDKit::SmilesWrite::CX_ALL ^ RDKit::SmilesWrite::CX_ATOM_PROPS; - std::string output_cxsmarts = ChemicalReactionToCXRxnSmarts(*rxn, params, flags); + std::string output_cxsmarts = + ChemicalReactionToCXRxnSmarts(*rxn, params, flags); CHECK(output_cxsmarts == expected_cxsmarts); // Test properties of the rxn itself. @@ -1240,7 +1248,8 @@ TEST_CASE("CXSMILES for reactions", "[cxsmiles]") { auto roundtrip = v2::ReactionParser::ReactionFromSmarts(output_cxsmarts); REQUIRE(roundtrip); - const auto &sgsRoundReact = getSubstanceGroups(*roundtrip->getReactants()[0]); + const auto &sgsRoundReact = + getSubstanceGroups(*roundtrip->getReactants()[0]); REQUIRE(&sgsRoundReact); const auto &sgsRoundProd = getSubstanceGroups(*roundtrip->getProducts()[0]); REQUIRE(&sgsRoundProd); @@ -1255,8 +1264,9 @@ TEST_CASE("CXSMILES for reactions", "[cxsmiles]") { // Check that the properties are set on the roundtrip rxn. CHECK(sgsRoundProd[0].getProp("PARENT") == 2); - // Doesn't work because .... maybe because the substance groups are intertwined react/prod? The sg hierarchy is not being written for the reactant... - // CHECK(sgsRoundReact[0].getProp("PARENT") == 2); + // Doesn't work because .... maybe because the substance groups are + // intertwined react/prod? The sg hierarchy is not being written for the + // reactant... CHECK(sgsRoundReact[0].getProp("PARENT") == 2); } SECTION("link nodes") { // clang-format off @@ -1314,7 +1324,8 @@ TEST_CASE("CXSMILES for reactions", "[cxsmiles]") { CHECK(rxn->getProducts()[0]->getBondWithIdx(1)->getStereo() == Bond::BondStereo::STEREOCIS); - auto roundtrip = v2::ReactionParser::ReactionFromSmarts(ChemicalReactionToCXRxnSmarts(*rxn)); + auto roundtrip = v2::ReactionParser::ReactionFromSmarts( + ChemicalReactionToCXRxnSmarts(*rxn)); REQUIRE(roundtrip); CHECK(roundtrip->getReactants().size() == 1); CHECK(roundtrip->getProducts().size() == 1); @@ -1336,7 +1347,8 @@ TEST_CASE("CXSMILES for reactions", "[cxsmiles]") { "_MolFileBondCfg", bondcfg)); CHECK(bondcfg == 2); - auto roundtrip = v2::ReactionParser::ReactionFromSmarts(ChemicalReactionToCXRxnSmarts(*rxn)); + auto roundtrip = v2::ReactionParser::ReactionFromSmarts( + ChemicalReactionToCXRxnSmarts(*rxn)); REQUIRE(roundtrip); CHECK(roundtrip->getReactants().size() == 1); CHECK(roundtrip->getProducts().size() == 1); @@ -1351,7 +1363,8 @@ TEST_CASE("CXSMILES for reactions", "[cxsmiles]") { SmilesWriteParams params; auto flags = RDKit::SmilesWrite::CX_ALL ^ RDKit::SmilesWrite::CX_ATOM_PROPS; auto output_cxsmarts = ChemicalReactionToCXRxnSmarts(*rxn, params, flags); - auto expected_cxsmarts = "[#6]-[#6](-[#8])(-[#9])-[#17]>>[#6]-[#6](-[#7])(-[#9])-[#17] |w:1.0,6.5|"; + auto expected_cxsmarts = + "[#6]-[#6](-[#8])(-[#9])-[#17]>>[#6]-[#6](-[#7])(-[#9])-[#17] |w:1.0,6.5|"; CHECK(output_cxsmarts == expected_cxsmarts); } } @@ -2229,11 +2242,10 @@ TEST_CASE("Structural fingerprints values") { } } -TEST_CASE( - "Github #6015: react_idx property") { +TEST_CASE("Github #6015: react_idx property") { SECTION("Ensure that atoms are marked with their reactant idx") { - std::unique_ptr rxn{ - RxnSmartsToChemicalReaction("[C:1][O:2].[N:3][S:4]>>[C:1][O:2][N:3][S:4]C")}; + std::unique_ptr rxn{RxnSmartsToChemicalReaction( + "[C:1][O:2].[N:3][S:4]>>[C:1][O:2][N:3][S:4]C")}; REQUIRE(rxn); rxn->initReactantMatchers(); ROMOL_SPTR mol1(SmilesToMol("CO")); @@ -2242,27 +2254,37 @@ TEST_CASE( REQUIRE(reactants.size() == 2); REQUIRE(reactants[0]); REQUIRE(reactants[1]); - + auto products = rxn->runReactants(reactants); REQUIRE(products.size() == 1); - - CHECK(products[0][0]->getAtomWithIdx(0)->getProp("react_idx") == 0); - CHECK(products[0][0]->getAtomWithIdx(0)->getProp("react_atom_idx") == 0); - - CHECK(products[0][0]->getAtomWithIdx(1)->getProp("react_idx") == 0); - CHECK(products[0][0]->getAtomWithIdx(1)->getProp("react_atom_idx") == 1); - - CHECK(products[0][0]->getAtomWithIdx(2)->getProp("react_idx") == 1); - CHECK(products[0][0]->getAtomWithIdx(2)->getProp("react_atom_idx") == 0); - - CHECK(products[0][0]->getAtomWithIdx(3)->getProp("react_idx") == 1); - CHECK(products[0][0]->getAtomWithIdx(3)->getProp("react_atom_idx") == 1); - - CHECK(products[0][0]->getAtomWithIdx(4)->hasProp("react_atom_idx") == false); + + CHECK(products[0][0]->getAtomWithIdx(0)->getProp( + "react_idx") == 0); + CHECK(products[0][0]->getAtomWithIdx(0)->getProp( + "react_atom_idx") == 0); + + CHECK(products[0][0]->getAtomWithIdx(1)->getProp( + "react_idx") == 0); + CHECK(products[0][0]->getAtomWithIdx(1)->getProp( + "react_atom_idx") == 1); + + CHECK(products[0][0]->getAtomWithIdx(2)->getProp( + "react_idx") == 1); + CHECK(products[0][0]->getAtomWithIdx(2)->getProp( + "react_atom_idx") == 0); + + CHECK(products[0][0]->getAtomWithIdx(3)->getProp( + "react_idx") == 1); + CHECK(products[0][0]->getAtomWithIdx(3)->getProp( + "react_atom_idx") == 1); + + CHECK(products[0][0]->getAtomWithIdx(4)->hasProp("react_atom_idx") == + false); CHECK(products[0][0]->getAtomWithIdx(4)->hasProp("react_idx") == false); - - CHECK(products[0][0]->getAtomWithIdx(5)->getProp("react_idx") == 1); - CHECK(products[0][0]->getAtomWithIdx(5)->getProp("react_atom_idx") == 2); - + + CHECK(products[0][0]->getAtomWithIdx(5)->getProp( + "react_idx") == 1); + CHECK(products[0][0]->getAtomWithIdx(5)->getProp( + "react_atom_idx") == 2); } } diff --git a/Code/GraphMol/SmilesParse/SmartsWrite.cpp b/Code/GraphMol/SmilesParse/SmartsWrite.cpp index c9e1ad2c1..baaf2531d 100644 --- a/Code/GraphMol/SmilesParse/SmartsWrite.cpp +++ b/Code/GraphMol/SmilesParse/SmartsWrite.cpp @@ -747,7 +747,7 @@ std::string getNonQueryAtomSmarts(const Atom *atom) { } else { res << atom->getSymbol(); } - + bool addedChirality = false; if (atom->hasOwningMol() && atom->getOwningMol().hasProp(common_properties::_doIsoSmiles)) { if (atom->getChiralTag() != Atom::CHI_UNSPECIFIED && @@ -757,9 +757,11 @@ std::string getNonQueryAtomSmarts(const Atom *atom) { switch (atom->getChiralTag()) { case Atom::CHI_TETRAHEDRAL_CW: res << "@@"; + addedChirality = true; break; case Atom::CHI_TETRAHEDRAL_CCW: res << "@"; + addedChirality = true; break; default: break; @@ -767,13 +769,11 @@ std::string getNonQueryAtomSmarts(const Atom *atom) { } } - auto hs = atom->getNumExplicitHs(); - // FIX: probably should be smarter about Hs: - if (hs) { + if (addedChirality && atom->getNumExplicitHs() == 1) { + // FIX: this isn't really correct in many cases, but + // fixing it requires opening a fairly large construction site on the + // SMARTS handling side. We'll do this later. res << "H"; - if (hs > 1) { - res << hs; - } } auto chg = atom->getFormalCharge(); if (chg) { diff --git a/Code/GraphMol/SmilesParse/catch_tests.cpp b/Code/GraphMol/SmilesParse/catch_tests.cpp index 424d3e4af..f5bbc88bf 100644 --- a/Code/GraphMol/SmilesParse/catch_tests.cpp +++ b/Code/GraphMol/SmilesParse/catch_tests.cpp @@ -2978,11 +2978,11 @@ TEST_CASE("Github #7372: SMILES output option to disable dative bonds") { auto m = "[NH3]->[Fe]-[NH2]"_smiles; REQUIRE(m); auto smi = MolToSmarts(*m); - CHECK(smi == "[#7H3]->[Fe]-[#7H2]"); + CHECK(smi == "[#7]->[Fe]-[#7]"); SmilesWriteParams ps; ps.includeDativeBonds = false; auto newSmi = MolToSmarts(*m, ps); - CHECK(newSmi == "[#7H3]-[Fe]-[#7H2]"); + CHECK(newSmi == "[#7]-[Fe]-[#7]"); } } diff --git a/Code/GraphMol/SmilesParse/cxsmiles_test.cpp b/Code/GraphMol/SmilesParse/cxsmiles_test.cpp index d11fce7ab..7bbbfe977 100644 --- a/Code/GraphMol/SmilesParse/cxsmiles_test.cpp +++ b/Code/GraphMol/SmilesParse/cxsmiles_test.cpp @@ -1509,7 +1509,7 @@ TEST_CASE("Github #7372: SMILES output option to disable dative bonds") { auto m = "[NH3]->[Fe]-[NH2]"_smiles; REQUIRE(m); auto smi = MolToCXSmarts(*m); - CHECK(smi == "[#7H3]-[Fe]-[#7H2] |C:0.0|"); + CHECK(smi == "[#7]-[Fe]-[#7] |C:0.0|"); } SECTION("two dative bonds") { auto m = "[NH3][Fe][NH3]"_smiles; // auto single->dative conversion @@ -1521,7 +1521,7 @@ TEST_CASE("Github #7372: SMILES output option to disable dative bonds") { auto m = "[NH3][Fe][NH3]"_smiles; // auto single->dative conversion REQUIRE(m); auto smi = MolToCXSmarts(*m); - CHECK(smi == "[#7H3]-[Fe]-[#7H3] |C:0.0,2.1|"); + CHECK(smi == "[#7]-[Fe]-[#7] |C:0.0,2.1|"); } } diff --git a/Code/GraphMol/SmilesParse/smarts_catch_tests.cpp b/Code/GraphMol/SmilesParse/smarts_catch_tests.cpp index 872e66037..05e7ba305 100644 --- a/Code/GraphMol/SmilesParse/smarts_catch_tests.cpp +++ b/Code/GraphMol/SmilesParse/smarts_catch_tests.cpp @@ -29,7 +29,7 @@ TEST_CASE("Github #8424: direction on aromatic bonds in SMARTS") { auto m = "C/N=c1/[nH]cc(Br)nc1"_smiles; REQUIRE(m); auto smarts = MolToSmarts(*m); - CHECK(smarts == "[#6]/[#7]=[#6]1/[#7H]:[#6]:[#6](-[#35]):[#7]:[#6]:1"); + CHECK(smarts == "[#6]/[#7]=[#6]1/[#7]:[#6]:[#6](-[#35]):[#7]:[#6]:1"); } SECTION("as reported") { auto m = @@ -65,4 +65,22 @@ TEST_CASE("repeated explicit H counts and charges") { CHECK(m->getAtomWithIdx(0)->getFormalCharge() == 0); } } +} + +TEST_CASE("implicit Hs from SMILES should not make it into SMARTS") { + SECTION("aromatic N") { + auto m = "c1ccc[nH]1"_smiles; + REQUIRE(m); + auto smarts = MolToSmarts(*m); + CHECK(smarts == "[#6]1:[#6]:[#6]:[#6]:[#7]:1"); + } + SECTION("chirality") { + // as of this writing, we still keep Hs in the SMARTS for chiral centers. + // it's inconsistent to do so, but we have explicitly punted on fixing + // this for now. + auto m = "C[C@H](N)F"_smiles; + REQUIRE(m); + auto smarts = MolToSmarts(*m); + CHECK(smarts == "[#6]-[#6@H](-[#7])-[#9]"); + } } \ No newline at end of file diff --git a/Code/GraphMol/SmilesParse/smatest.cpp b/Code/GraphMol/SmilesParse/smatest.cpp index 30b6065da..d7d40c1e1 100644 --- a/Code/GraphMol/SmilesParse/smatest.cpp +++ b/Code/GraphMol/SmilesParse/smatest.cpp @@ -1021,14 +1021,14 @@ void testSmilesSmarts() { mol = SmilesToMol(smi); TEST_ASSERT(mol); sma = MolToSmarts(*mol); - TEST_ASSERT(sma == "[#6H2-]-[#6]"); + TEST_ASSERT(sma == "[#6-]-[#6]"); delete mol; smi = "[CH-2]C"; mol = SmilesToMol(smi); TEST_ASSERT(mol); sma = MolToSmarts(*mol); - TEST_ASSERT(sma == "[#6H-2]-[#6]"); + TEST_ASSERT(sma == "[#6-2]-[#6]"); delete mol; smi = "[CH4+]C"; @@ -1037,14 +1037,14 @@ void testSmilesSmarts() { mol = SmilesToMol(smi, debugParse, sanitize); TEST_ASSERT(mol); sma = MolToSmarts(*mol); - TEST_ASSERT(sma == "[#6H4+]-[#6]"); + TEST_ASSERT(sma == "[#6+]-[#6]"); delete mol; smi = "[CH5+2]C"; mol = SmilesToMol(smi, debugParse, sanitize); TEST_ASSERT(mol); sma = MolToSmarts(*mol); - TEST_ASSERT(sma == "[#6H5+2]-[#6]"); + TEST_ASSERT(sma == "[#6+2]-[#6]"); delete mol; smi = "c1ccccc1"; @@ -2646,6 +2646,7 @@ void testGithub2565() { bool recursionPossible = true; bool useChirality = true; std::vector matches; + std::cerr << "Testing SMILES: " << smi << " " << smarts << std::endl; TEST_ASSERT(SubstructMatch(*mol, *query, matches, uniquify, recursionPossible, useChirality)); } diff --git a/Code/GraphMol/Wrap/rough_test.py b/Code/GraphMol/Wrap/rough_test.py index 0afeb26ef..bdfc7370b 100644 --- a/Code/GraphMol/Wrap/rough_test.py +++ b/Code/GraphMol/Wrap/rough_test.py @@ -6674,11 +6674,11 @@ M END mol = Chem.MolFromSmiles('c1cc[nH]c1') nops = Chem.AdjustQueryParameters.NoAdjustments() nmol = Chem.AdjustQueryProperties(mol, nops) - self.assertEqual(Chem.MolToSmarts(nmol), "[#6]1:[#6]:[#6]:[#7H]:[#6]:1") + self.assertEqual(Chem.MolToSmarts(nmol), "[#6]1:[#6]:[#6]:[#7]:[#6]:1") nops.adjustConjugatedFiveRings = True nmol = Chem.AdjustQueryProperties(mol, nops) - self.assertEqual(Chem.MolToSmarts(nmol), "[#6]1-,=,:[#6]-,=,:[#6]-,=,:[#7H]-,=,:[#6]-,=,:1") + self.assertEqual(Chem.MolToSmarts(nmol), "[#6]1-,=,:[#6]-,=,:[#6]-,=,:[#7]-,=,:[#6]-,=,:1") def testFindPotentialStereo(self): mol = Chem.MolFromSmiles('C[C@H](F)C=CC') @@ -8528,10 +8528,10 @@ M END self.assertIsNotNone(mol) ps = Chem.SmilesWriteParams() sma = Chem.MolToSmarts(mol, ps) - self.assertEqual(sma, '[#7H3]->[Fe]-[#7]') + self.assertEqual(sma, '[#7]->[Fe]-[#7]') ps.includeDativeBonds = False sma = Chem.MolToSmarts(mol, ps) - self.assertEqual(sma, '[#7H3]-[Fe]-[#7]') + self.assertEqual(sma, '[#7]-[Fe]-[#7]') def testMolToV2KMolBlock(self): mol = Chem.MolFromSmiles('[NH3]->[Fe]') diff --git a/Code/GraphMol/catch_adjustquery.cpp b/Code/GraphMol/catch_adjustquery.cpp index f18aa63d2..002a900a1 100644 --- a/Code/GraphMol/catch_adjustquery.cpp +++ b/Code/GraphMol/catch_adjustquery.cpp @@ -439,7 +439,7 @@ TEST_CASE("MDL five-rings") { // clang-format off std::vector examples = { // no queries, no change - extuple{"adjustqueryprops_MDLfivering_1.mol","[#7H]1:[#6]:[#6]:[#6]:[#6]:1",""}, + extuple{"adjustqueryprops_MDLfivering_1.mol","[#7]1:[#6]:[#6]:[#6]:[#6]:1",""}, // Q atom, no change extuple{"adjustqueryprops_MDLfivering_2.mol","[!#6&!#1]1:[#6]:[#6]:[#6]:[#6]:1",""}, // A atom, this one changes @@ -792,7 +792,7 @@ TEST_CASE("makeAtomsGeneric") { auto m = "C[CH3:1]"_smiles; REQUIRE(m); MolOps::adjustQueryProperties(*m, &ps); - CHECK(MolToSmarts(*m) == "*-[#6H3:1]"); + CHECK(MolToSmarts(*m) == "*-[#6:1]"); } } diff --git a/Docs/Book/GettingStartedInPython.rst b/Docs/Book/GettingStartedInPython.rst index ede6995af..a25dcfce0 100644 --- a/Docs/Book/GettingStartedInPython.rst +++ b/Docs/Book/GettingStartedInPython.rst @@ -2581,7 +2581,7 @@ reaction to be reconstructed: >>> newRxn = AllChem.ReactionFromPNGString(png) >>> AllChem.ReactionToSmarts(newRxn) - '[#6H:5]1:[#6H:6]:[#6:7]2:[#6H:8]:[#7:9]:[#6H:10]:[#6H:11]:[#6:12]:2:[#6:3](:[#6H:4]:1)-[#6:2](=[#8:1])-[#8].[#7-:13]=[#7+:14]=[#7-:15]>[#6](-[#17])-[#17].[#6](=[#8])(-[#6](=[#8])-[#17])-[#17]>[#6H:5]1:[#6H:6]:[#6:7]2:[#6H:8]:[#7:9]:[#6H:10]:[#6H:11]:[#6:12]:2:[#6:3](:[#6H:4]:1)-[#6:2](=[#8:1])-[#7:13]=[#7+:14]=[#7-:15]' + '[#6:5]1:[#6:6]:[#6:7]2:[#6:8]:[#7:9]:[#6:10]:[#6:11]:[#6:12]:2:[#6:3](:[#6:4]:1)-[#6:2](=[#8:1])-[#8].[#7-:13]=[#7+:14]=[#7-:15]>[#6](-[#17])-[#17].[#6](=[#8])(-[#6](=[#8])-[#17])-[#17]>[#6:5]1:[#6:6]:[#6:7]2:[#6:8]:[#7:9]:[#6:10]:[#6:11]:[#6:12]:2:[#6:3](:[#6:4]:1)-[#6:2](=[#8:1])-[#7:13]=[#7+:14]=[#7-:15]' Advanced Reaction Functionality =============================== diff --git a/ReleaseNotes.md b/ReleaseNotes.md index 353b1e63b..4bff80d0a 100644 --- a/ReleaseNotes.md +++ b/ReleaseNotes.md @@ -22,6 +22,9 @@ GitHub) `Chem.CanonicalRankAtoms(mol, breakTies=False)`. - The behavior of H removal has changed slightly: hydrides will no longer removed by default, as this changes the global charge of the mol. +- `MolToSmarts()` no longer adds implicit hydrogens to atoms without queries. The + one exception to this is for chiral atoms, which will still have an implicit H + added if present. ## New Features and Enhancements: