Fixes for nontetrahedral stereo parsing from SMILES/SMARTS (#8932)

* backup

* fix nontet stereo parsing in SMARTS
This commit is contained in:
Greg Landrum
2025-11-09 05:31:12 +01:00
committed by GitHub
parent bda9ffbeec
commit 1a43f1cbef
6 changed files with 93 additions and 28 deletions

View File

@@ -3333,6 +3333,34 @@ TEST_CASE("github #8906") {
CHECK(m->getAtomWithIdx(1)->getIsotope() == 2);
auto csmi1 = MolToSmiles(*m);
CHECK(csmi1 == "[1*][2C]");
}
}
TEST_CASE("chiral class must be nonzero") {
SECTION("basics") {
{
auto m = "C[As@TB0](F)(Cl)(O)Br"_smiles;
REQUIRE(!m);
}
{
auto m = "C[As@TB0](F)(Cl)(O)Br"_smarts;
REQUIRE(!m);
}
{
auto m = "[As@TB1]"_smarts;
REQUIRE(m);
CHECK(m->getAtomWithIdx(0)->getChiralTag() ==
Atom::ChiralType::CHI_TRIGONALBIPYRAMIDAL);
CHECK(m->getAtomWithIdx(0)->getProp<int>(
common_properties::_chiralPermutation) == 1);
}
{
auto m = "C[As@TB1](F)(Cl)(O)Br"_smarts;
REQUIRE(m);
CHECK(m->getAtomWithIdx(1)->getChiralTag() ==
Atom::ChiralType::CHI_TRIGONALBIPYRAMIDAL);
CHECK(m->getAtomWithIdx(1)->getProp<int>(
common_properties::_chiralPermutation) == 1);
}
}
}

View File

@@ -114,6 +114,10 @@ namespace {
atom_expr->expandQuery(point_query->getQuery()->copy(), Queries::COMPOSITE_AND, true);
if (atom_expr->getChiralTag() == Atom::CHI_UNSPECIFIED) {
atom_expr->setChiralTag(point_query->getChiralTag());
int perm;
if (point_query->getPropIfPresent(common_properties::_chiralPermutation, perm)) {
atom_expr->setProp(common_properties::_chiralPermutation, perm);
}
}
if (point_query->getFlags() & SMARTS_H_MASK) {
if (!(atom_expr->getFlags() & SMARTS_H_MASK)) {
@@ -670,19 +674,19 @@ static const yytype_int8 yytranslate[] =
/* YYRLINE[YYN] -- Source line where rule number YYN was defined. */
static const yytype_int16 yyrline[] =
{
0, 187, 187, 190, 194, 197, 200, 204, 208, 211,
217, 222, 225, 233, 234, 235, 236, 244, 253, 267,
288, 294, 318, 339, 356, 379, 393, 394, 395, 399,
422, 426, 431, 437, 446, 453, 462, 471, 485, 492,
500, 507, 512, 517, 520, 526, 527, 531, 548, 572,
573, 578, 579, 584, 585, 590, 591, 592, 593, 594,
595, 596, 600, 604, 608, 612, 616, 620, 627, 634,
642, 652, 662, 671, 679, 686, 692, 698, 705, 712,
713, 720, 721, 725, 729, 733, 737, 741, 746, 754,
766, 771, 776, 781, 786, 791, 794, 795, 803, 804,
810, 816, 822, 827, 834, 835, 836, 837, 838, 839,
843, 844, 845, 846, 847, 848, 849, 854, 855, 859,
860, 869, 870, 874
0, 190, 190, 193, 197, 200, 203, 207, 211, 214,
220, 225, 228, 236, 237, 238, 239, 247, 256, 270,
291, 297, 321, 342, 359, 382, 396, 397, 398, 402,
425, 429, 434, 440, 449, 456, 465, 474, 488, 495,
503, 510, 515, 520, 523, 529, 530, 534, 551, 575,
576, 581, 582, 587, 588, 593, 594, 595, 596, 597,
598, 599, 603, 607, 611, 615, 619, 623, 630, 637,
645, 655, 665, 674, 682, 689, 695, 701, 708, 722,
723, 730, 731, 735, 739, 743, 747, 751, 756, 764,
776, 781, 786, 791, 796, 801, 804, 805, 813, 814,
820, 826, 832, 837, 844, 845, 846, 847, 848, 849,
853, 854, 855, 856, 857, 858, 859, 864, 865, 869,
870, 879, 880, 884
};
#endif
@@ -2200,6 +2204,13 @@ yyreduce:
case 78: /* atom_query: CHI_CLASS_TOKEN number */
{
if((yyvsp[0].ival)==0){
yyerror(input,molList,branchPoints,scanner,start_token, current_token_position,
"chiral permutation cannot be zero");
yyErrorCleanup(molList);
YYABORT;
}
QueryAtom *newQ = new QueryAtom();
newQ->setQuery(makeAtomNullQuery());
newQ->setChiralTag((yyvsp[-1].chiraltype));

View File

@@ -40,6 +40,10 @@ namespace {
atom_expr->expandQuery(point_query->getQuery()->copy(), Queries::COMPOSITE_AND, true);
if (atom_expr->getChiralTag() == Atom::CHI_UNSPECIFIED) {
atom_expr->setChiralTag(point_query->getChiralTag());
int perm;
if (point_query->getPropIfPresent(common_properties::_chiralPermutation, perm)) {
atom_expr->setProp(common_properties::_chiralPermutation, perm);
}
}
if (point_query->getFlags() & SMARTS_H_MASK) {
if (!(atom_expr->getFlags() & SMARTS_H_MASK)) {
@@ -702,6 +706,13 @@ atom_query: simple_atom
$$=newQ;
}
| CHI_CLASS_TOKEN number {
if($2==0){
yyerror(input,molList,branchPoints,scanner,start_token, current_token_position,
"chiral permutation cannot be zero");
yyErrorCleanup(molList);
YYABORT;
}
QueryAtom *newQ = new QueryAtom();
newQ->setQuery(makeAtomNullQuery());
newQ->setChiralTag($1);

View File

@@ -613,14 +613,14 @@ static const yytype_int8 yytranslate[] =
/* YYRLINE[YYN] -- Source line where rule number YYN was defined. */
static const yytype_int16 yyrline[] =
{
0, 138, 138, 141, 145, 148, 152, 156, 159, 165,
170, 173, 181, 182, 183, 184, 192, 203, 214, 235,
244, 250, 271, 295, 314, 324, 345, 353, 367, 370,
371, 377, 378, 384, 392, 393, 394, 395, 396, 397,
398, 402, 403, 404, 405, 406, 407, 408, 409, 410,
414, 415, 416, 417, 418, 422, 423, 424, 425, 426,
427, 431, 432, 436, 437, 438, 439, 440, 441, 442,
446, 447, 451, 452, 463, 464
0, 137, 137, 140, 144, 147, 151, 155, 158, 164,
169, 172, 180, 181, 182, 183, 191, 202, 213, 234,
243, 249, 270, 294, 313, 323, 344, 352, 366, 369,
370, 376, 377, 383, 391, 392, 393, 394, 395, 396,
397, 401, 402, 403, 404, 405, 406, 407, 408, 409,
413, 414, 415, 416, 417, 428, 429, 430, 431, 432,
433, 437, 438, 442, 443, 444, 445, 446, 447, 448,
452, 453, 457, 458, 469, 470
};
#endif
@@ -1706,7 +1706,15 @@ yyreduce:
break;
case 54: /* chiral_element: element CHI_CLASS_TOKEN number */
{ (yyvsp[-2].atom)->setChiralTag((yyvsp[-1].chiraltype)); (yyvsp[-2].atom)->setProp(common_properties::_chiralPermutation,(yyvsp[0].ival)); }
{
if((yyvsp[0].ival)==0){
yyerror(input,molList,branchPoints,scanner,start_token, current_token_position,
"chiral permutation cannot be zero");
yyErrorCleanup(molList);
YYABORT;
}
(yyvsp[-2].atom)->setChiralTag((yyvsp[-1].chiraltype)); (yyvsp[-2].atom)->setProp(common_properties::_chiralPermutation,(yyvsp[0].ival));
}
break;
case 56: /* element: number simple_atom */

View File

@@ -35,8 +35,8 @@
especially those whose name start with YY_ or yy_. They are
private implementation details that can be changed or removed. */
#ifndef YY_YYSMILES_USR_APP_RDKIT_CODE_GRAPHMOL_SMILESPARSE_SMILES_TAB_HPP_INCLUDED
# define YY_YYSMILES_USR_APP_RDKIT_CODE_GRAPHMOL_SMILESPARSE_SMILES_TAB_HPP_INCLUDED
#ifndef YY_YYSMILES_SCRATCH_RDKIT_GIT_CODE_GRAPHMOL_SMILESPARSE_SMILES_TAB_HPP_INCLUDED
# define YY_YYSMILES_SCRATCH_RDKIT_GIT_CODE_GRAPHMOL_SMILESPARSE_SMILES_TAB_HPP_INCLUDED
/* Debug traces. */
#ifndef YYDEBUG
# define YYDEBUG 0
@@ -112,4 +112,4 @@ int yysmiles_parse (const char *input, std::vector<RDKit::RWMol *> *molList, RDK
(YYSTYPE * yylval_param , yyscan_t yyscanner, int& start_token, unsigned int& current_token_position)
#endif /* !YY_YYSMILES_USR_APP_RDKIT_CODE_GRAPHMOL_SMILESPARSE_SMILES_TAB_HPP_INCLUDED */
#endif /* !YY_YYSMILES_SCRATCH_RDKIT_GIT_CODE_GRAPHMOL_SMILESPARSE_SMILES_TAB_HPP_INCLUDED */

View File

@@ -414,8 +414,15 @@ chiral_element: element
| element AT_TOKEN { $1->setChiralTag(Atom::CHI_TETRAHEDRAL_CCW); }
| element AT_TOKEN AT_TOKEN { $1->setChiralTag(Atom::CHI_TETRAHEDRAL_CW); }
| element CHI_CLASS_TOKEN { $1->setChiralTag($2); $1->setProp(common_properties::_chiralPermutation,0); }
| element CHI_CLASS_TOKEN number { $1->setChiralTag($2); $1->setProp(common_properties::_chiralPermutation,$3); }
;
| element CHI_CLASS_TOKEN number {
if($3==0){
yyerror(input,molList,branchPoints,scanner,start_token, current_token_position,
"chiral permutation cannot be zero");
yyErrorCleanup(molList);
YYABORT;
}
$1->setChiralTag($2); $1->setProp(common_properties::_chiralPermutation,$3);
};
/* --------------------------------------------------------------- */
element: simple_atom