Fixes #6816 (rdkit/rdkit#6827)

This PR addressees #6816 by making sure that `reapplyMolBlockWedging()` also restores the double bond stereo depiction as originally specified in the molblock, either V2000 (`sss` bond stereo field) or V3000 (through the `CFG` field in the bond block).
Currently, this was happening only partially for the V3000 format, and not at all for the V2000 format.
I added a unit test to make sure things works as expected; here's the gist that I used to set up the unit test:

[Jupyter notebook used for `TEST_CASE("test GitHub6816")` in `Code/GraphMol/Depictor/catch_tests.cpp`](https://gist.github.com/ptosco/aa51700b3fcafa6e0629a638e1f1cc0a)

UPDATE: this PR also fixes #6893, which was found by @rvianello at a later stage.

Double bonds should not be depicted as crossed bonds in the presence of wavy bonds

I have compared the ChemDraw depictions to RDKit depictions for a few cases where undefined geometric isomerism at a double bond is represented as:

1. _Either_ single bonds on the stereochemistry-determining atoms (bond stereo 4) (Examples 1-3)
2. _Cis or trans (either)_ double bond (bond stereo 3) (Example 4)

```
from rdkit import Chem
from rdkit.Chem.Draw import IPythonConsole, rdMolDraw2D, rdDepictor
```

# Example 1
### ChemDraw
![image](https://github.com/rdkit/rdkit/assets/5244385/fda6d3a9-9427-49b7-b1c1-51fc8d791212)

### RDKit
```
mol = Chem.MolFromMolBlock("""double.mol
  ChemDraw10192311132D

  4  3  0  0  0  0  0  0  0  0999 V2000
   -0.7145    0.2062    0.0000 C   0  0  0  0  0  0  0  0  0  0  0  0
    0.0000    0.6188    0.0000 C   0  0  0  0  0  0  0  0  0  0  0  0
    0.7145    0.2062    0.0000 F   0  0  0  0  0  0  0  0  0  0  0  0
   -0.7145   -0.6188    0.0000 O   0  0  0  0  0  0  0  0  0  0  0  0
  1  2  2  0        0
  2  3  1  4        0
  1  4  1  4        0
M  END
""")
Chem.ReapplyMolBlockWedging(mol)
mol
```
![image](https://github.com/rdkit/rdkit/assets/5244385/48c7b5d1-81e3-4315-9cfc-4a3730157581)

# Example 2
### ChemDraw
![image](https://github.com/rdkit/rdkit/assets/5244385/5d045eb3-2c6e-4bd7-9d2b-194472aaff31)

### RDKit
```
mol = Chem.MolFromMolBlock("""double-2.mol
  ChemDraw10192311332D

  4  3  0  0  0  0  0  0  0  0999 V2000
   -0.3572   -0.2062    0.0000 C   0  0  0  0  0  0  0  0  0  0  0  0
    0.3572    0.2062    0.0000 C   0  0  0  0  0  0  0  0  0  0  0  0
    1.0717    0.6188    0.0000 F   0  0  0  0  0  0  0  0  0  0  0  0
   -1.0717   -0.6188    0.0000 O   0  0  0  0  0  0  0  0  0  0  0  0
  1  2  2  0        0
  2  3  1  4        0
  1  4  1  4        0
M  END
""")
Chem.ReapplyMolBlockWedging(mol)
mol
```
![image](https://github.com/rdkit/rdkit/assets/5244385/38482587-0365-4a9b-81c3-3d169a10cd1f)

# Example 3
### ChemDraw
![image](https://github.com/rdkit/rdkit/assets/5244385/d0951139-484e-41b6-94e4-b4371d4acaaa)

### RDKit
```
mol = Chem.MolFromMolBlock("""di-imine-2-2000.mol
  ChemDraw10192311522D

  8  7  0  0  0  0  0  0  0  0999 V2000
   -0.9959   -1.0600    0.0000 C   0  0  0  0  0  0  0  0  0  0  0  0
   -0.4125   -0.4767    0.0000 C   0  0  0  0  0  0  0  0  0  0  0  0
    0.4125   -0.4767    0.0000 C   0  0  0  0  0  0  0  0  0  0  0  0
    0.9959   -1.0600    0.0000 C   0  0  0  0  0  0  0  0  0  0  0  0
   -0.7282    0.2855    0.0000 N   0  0  0  0  0  0  0  0  0  0  0  0
   -0.9971    1.0600    0.0000 C   0  0  0  0  0  0  0  0  0  0  0  0
    0.7282    0.2855    0.0000 N   0  0  0  0  0  0  0  0  0  0  0  0
    0.9971    1.0270    0.0000 C   0  0  0  0  0  0  0  0  0  0  0  0
  1  2  1  0        0
  2  3  1  0        0
  3  4  1  0        0
  2  5  2  0        0
  5  6  1  4        0
  3  7  2  0        0
  7  8  1  4        0
M  END
""")
Chem.ReapplyMolBlockWedging(mol)
mol
```
![image](https://github.com/rdkit/rdkit/assets/5244385/4092b183-a56c-4ef2-a335-e9c094cb4d6c)

# Example 4
### ChemDraw
![image](https://github.com/rdkit/rdkit/assets/5244385/6aad781d-b086-404d-bdbc-9fe1ad39f363)

### RDKit
```
mol = Chem.MolFromMolBlock("""di-imine-cross-2000.mol
  ChemDraw10192311582D

  8  7  0  0  0  0  0  0  0  0999 V2000
   -1.0099   -1.1129    0.0000 C   0  0  0  0  0  0  0  0  0  0  0  0
   -0.5974   -0.3984    0.0000 C   0  0  0  0  0  0  0  0  0  0  0  0
    0.2276   -0.3984    0.0000 C   0  0  0  0  0  0  0  0  0  0  0  0
    0.6401   -1.1129    0.0000 C   0  0  0  0  0  0  0  0  0  0  0  0
   -0.8109    0.3984    0.0000 N   0  0  0  0  0  0  0  0  0  0  0  0
    0.6401    0.3160    0.0000 N   0  0  0  0  0  0  0  0  0  0  0  0
   -1.2234    1.1129    0.0000 C   0  0  0  0  0  0  0  0  0  0  0  0
    1.2234    0.8994    0.0000 C   0  0  0  0  0  0  0  0  0  0  0  0
  1  2  1  0        0
  2  3  1  0        0
  3  4  1  0        0
  2  5  2  3        0
  3  6  2  3        0
  5  7  1  0        0
  6  8  1  0        0
M  END
""")
Chem.ReapplyMolBlockWedging(mol)
mol
```
![image](https://github.com/rdkit/rdkit/assets/5244385/d43c0563-d6cc-4c1d-ad67-10c1e440e997)

Example 4 looks correct to me.
In examples 1-3 I believe the crossed bond depicted by RDKit is redundant since the wavy bonds are sufficient to specificy undefined stereochemistry.

diff --git a/Code/GraphMol/Chirality.cpp b/Code/GraphMol/Chirality.cpp
index f748b413ca5..ba6b3fdae43 100644
--- a/Code/GraphMol/Chirality.cpp
+++ b/Code/GraphMol/Chirality.cpp
@@ -3303,13 +3303,17 @@ void detectBondStereochemistry(ROMol &mol, int confId) {
   }
 }

-void clearSingleBondDirFlags(ROMol &mol) {
+void clearSingleBondDirFlags(ROMol &mol, bool retainCisTransInfo) {
   for (auto bond : mol.bonds()) {
     if (bond->getBondType() == Bond::SINGLE) {
-      if (bond->getBondDir() == Bond::UNKNOWN) {
+      auto bondDir = bond->getBondDir();
+      if (bondDir == Bond::UNKNOWN) {
         bond->setProp(common_properties::_UnknownStereo, 1);
       }
-      bond->setBondDir(Bond::NONE);
+      if (!retainCisTransInfo ||
+          (bondDir != Bond::ENDDOWNRIGHT && bondDir != Bond::ENDUPRIGHT)) {
+        bond->setBondDir(Bond::NONE);
+      }
     }
   }
 }
diff --git a/Code/GraphMol/MolOps.h b/Code/GraphMol/MolOps.h
index 47bf9bdb3b8..8d611d84e02 100644
--- a/Code/GraphMol/MolOps.h
+++ b/Code/GraphMol/MolOps.h
@@ -975,8 +975,10 @@ RDKIT_GRAPHMOL_EXPORT void detectBondStereochemistry(ROMol &mol,
 RDKIT_GRAPHMOL_EXPORT void setDoubleBondNeighborDirections(
     ROMol &mol, const Conformer *conf = nullptr);
 //! removes directions from single bonds. Wiggly bonds will have the property
-//! _UnknownStereo set on them
-RDKIT_GRAPHMOL_EXPORT void clearSingleBondDirFlags(ROMol &mol);
+//! _UnknownStereo set on them. If retainCisTransInfo is true,
+//! ENDUPRIGHT and ENDDOWNRIGHT bond directions will not be cleared
+RDKIT_GRAPHMOL_EXPORT void clearSingleBondDirFlags(
+    ROMol &mol, bool retainCisTransInfo = false);

 //! Assign CIS/TRANS bond stereochemistry tags based on neighboring
 //! directions
diff --git a/Code/GraphMol/WedgeBonds.cpp b/Code/GraphMol/WedgeBonds.cpp
index 7ed32594fb3..a24a1e85eaf 100644
--- a/Code/GraphMol/WedgeBonds.cpp
+++ b/Code/GraphMol/WedgeBonds.cpp
@@ -506,7 +506,7 @@ void wedgeBond(Bond *bond, unsigned int fromAtomIdx, const Conformer *conf) {
 }

 void reapplyMolBlockWedging(ROMol &mol) {
-  MolOps::clearSingleBondDirFlags(mol);
+  MolOps::clearSingleBondDirFlags(mol, true);
   for (auto b : mol.bonds()) {
     int explicit_unknown_stereo = -1;
     if (b->getPropIfPresent<int>(common_properties::_UnknownStereo,
@@ -522,25 +522,40 @@ void reapplyMolBlockWedging(ROMol &mol) {
       } else if (bond_dir == 6) {
         b->setBondDir(Bond::BEGINDASH);
       }
+      if (b->getBondType() == Bond::DOUBLE) {
+        if (bond_dir == 0 && b->getStereo() == Bond::STEREOANY) {
+          b->setBondDir(Bond::NONE);
+          b->setStereo(Bond::STEREONONE);
+        } else if (bond_dir == 3) {
+          b->setBondDir(Bond::EITHERDOUBLE);
+          b->setStereo(Bond::STEREOANY);
+        }
+      }
     }
     int cfg = -1;
-    if (b->getPropIfPresent<int>(common_properties::_MolFileBondCfg, cfg)) {
-      switch (cfg) {
-        case 1:
-          b->setBondDir(Bond::BEGINWEDGE);
-          break;
-        case 2:
-          if (b->getBondType() == Bond::SINGLE) {
-            b->setBondDir(Bond::UNKNOWN);
-          } else if (b->getBondType() == Bond::DOUBLE) {
-            b->setBondDir(Bond::EITHERDOUBLE);
-            b->setStereo(Bond::STEREOANY);
-          }
-          break;
-        case 3:
-          b->setBondDir(Bond::BEGINDASH);
-          break;
-      }
+    b->getPropIfPresent<int>(common_properties::_MolFileBondCfg, cfg);
+    switch (cfg) {
+      case 1:
+        b->setBondDir(Bond::BEGINWEDGE);
+        break;
+      case 2:
+        if (b->getBondType() == Bond::SINGLE) {
+          b->setBondDir(Bond::UNKNOWN);
+        } else if (b->getBondType() == Bond::DOUBLE) {
+          b->setBondDir(Bond::EITHERDOUBLE);
+          b->setStereo(Bond::STEREOANY);
+        }
+        break;
+      case 3:
+        b->setBondDir(Bond::BEGINDASH);
+        break;
+      case 0:
+      case -1:
+        if (bond_dir == -1 && b->getBondType() == Bond::DOUBLE &&
+            b->getStereo() == Bond::STEREOANY) {
+          b->setBondDir(Bond::NONE);
+          b->setStereo(Bond::STEREONONE);
+        }
     }
   }
 }

diff --git a/Code/GraphMol/Depictor/catch_tests.cpp b/Code/GraphMol/Depictor/catch_tests.cpp
index a4dbf1ccb22..eb371851c17 100644
--- a/Code/GraphMol/Depictor/catch_tests.cpp
+++ b/Code/GraphMol/Depictor/catch_tests.cpp
@@ -1179,3 +1179,878 @@ M  END
     }
   }
 }
+
+TEST_CASE("test GitHub6816") {
+  SECTION("double-2000") {
+    auto mol = R"CTAB(double-2000.mol
+  ChemDraw10192311132D
+
+  4  3  0  0  0  0  0  0  0  0999 V2000
+   -0.7145    0.2062    0.0000 C   0  0  0  0  0  0  0  0  0  0  0  0
+    0.0000    0.6188    0.0000 C   0  0  0  0  0  0  0  0  0  0  0  0
+    0.7145    0.2062    0.0000 F   0  0  0  0  0  0  0  0  0  0  0  0
+   -0.7145   -0.6188    0.0000 O   0  0  0  0  0  0  0  0  0  0  0  0
+  1  2  2  0        0
+  2  3  1  4        0
+  1  4  1  4        0
+M  END
+)CTAB"_ctab;
+    REQUIRE(mol);
+    CHECK(mol->getBondWithIdx(0)->getStereo() == Bond::STEREOANY);
+    CHECK(mol->getBondWithIdx(0)->getBondDir() == Bond::NONE);
+    CHECK(!mol->getBondWithIdx(0)->hasProp(
+        common_properties::_MolFileBondStereo));
+    CHECK(!mol->getBondWithIdx(0)->hasProp(common_properties::_MolFileBondCfg));
+    CHECK(!mol->getBondWithIdx(0)->hasProp(common_properties::_UnknownStereo));
+
+    CHECK(mol->getBondWithIdx(1)->getStereo() == Bond::STEREONONE);
+    CHECK(mol->getBondWithIdx(1)->getBondDir() == Bond::NONE);
+    CHECK(mol->getBondWithIdx(1)->getProp<int>(
+              common_properties::_MolFileBondStereo) == 4);
+    CHECK(!mol->getBondWithIdx(1)->hasProp(common_properties::_MolFileBondCfg));
+    CHECK(mol->getBondWithIdx(1)->getProp<int>(
+        common_properties::_UnknownStereo));
+
+    CHECK(mol->getBondWithIdx(2)->getStereo() == Bond::STEREONONE);
+    CHECK(mol->getBondWithIdx(2)->getBondDir() == Bond::NONE);
+    CHECK(mol->getBondWithIdx(2)->getProp<int>(
+              common_properties::_MolFileBondStereo) == 4);
+    CHECK(!mol->getBondWithIdx(2)->hasProp(common_properties::_MolFileBondCfg));
+    CHECK(mol->getBondWithIdx(2)->getProp<int>(
+        common_properties::_UnknownStereo));
+
+    Chirality::reapplyMolBlockWedging(*mol);
+    CHECK(mol->getBondWithIdx(0)->getStereo() == Bond::STEREONONE);
+    CHECK(mol->getBondWithIdx(0)->getBondDir() == Bond::NONE);
+
+    CHECK(mol->getBondWithIdx(1)->getStereo() == Bond::STEREONONE);
+    CHECK(mol->getBondWithIdx(1)->getBondDir() == Bond::UNKNOWN);
+
+    CHECK(mol->getBondWithIdx(2)->getStereo() == Bond::STEREONONE);
+    CHECK(mol->getBondWithIdx(2)->getBondDir() == Bond::UNKNOWN);
+  }
+  SECTION("double-3000") {
+    auto mol = R"CTAB(double-3000.mol
+  ChemDraw10232310312D
+
+  0  0  0     0  0              0 V3000
+M  V30 BEGIN CTAB
+M  V30 COUNTS 4 3 0 0 0
+M  V30 BEGIN ATOM
+M  V30 1 C -0.714435 0.206182 0.000000 0
+M  V30 2 C 0.000000 0.618744 0.000000 0
+M  V30 3 F 0.714435 0.206182 0.000000 0
+M  V30 4 O -0.714435 -0.618744 0.000000 0
+M  V30 END ATOM
+M  V30 BEGIN BOND
+M  V30 1 2 1 2
+M  V30 2 1 2 3 CFG=2
+M  V30 3 1 1 4 CFG=2
+M  V30 END BOND
+M  V30 END CTAB
+M  END
+)CTAB"_ctab;
+    REQUIRE(mol);
+    CHECK(mol->getBondWithIdx(0)->getStereo() == Bond::STEREOANY);
+    CHECK(mol->getBondWithIdx(0)->getBondDir() == Bond::NONE);
+    CHECK(!mol->getBondWithIdx(0)->hasProp(
+        common_properties::_MolFileBondStereo));
+    CHECK(!mol->getBondWithIdx(0)->hasProp(common_properties::_MolFileBondCfg));
+    CHECK(!mol->getBondWithIdx(0)->hasProp(common_properties::_UnknownStereo));
+
+    CHECK(mol->getBondWithIdx(1)->getStereo() == Bond::STEREONONE);
+    CHECK(mol->getBondWithIdx(1)->getBondDir() == Bond::NONE);
+    CHECK(!mol->getBondWithIdx(1)->hasProp(
+        common_properties::_MolFileBondStereo));
+    CHECK(mol->getBondWithIdx(1)->getProp<int>(
+              common_properties::_MolFileBondCfg) == 2);
+    CHECK(mol->getBondWithIdx(1)->getProp<int>(
+        common_properties::_UnknownStereo));
+
+    CHECK(mol->getBondWithIdx(2)->getStereo() == Bond::STEREONONE);
+    CHECK(mol->getBondWithIdx(2)->getBondDir() == Bond::NONE);
+    CHECK(!mol->getBondWithIdx(2)->hasProp(
+        common_properties::_MolFileBondStereo));
+    CHECK(mol->getBondWithIdx(2)->getProp<int>(
+              common_properties::_MolFileBondCfg) == 2);
+    CHECK(mol->getBondWithIdx(2)->getProp<int>(
+        common_properties::_UnknownStereo));
+
+    Chirality::reapplyMolBlockWedging(*mol);
+    CHECK(mol->getBondWithIdx(0)->getStereo() == Bond::STEREONONE);
+    CHECK(mol->getBondWithIdx(0)->getBondDir() == Bond::NONE);
+
+    CHECK(mol->getBondWithIdx(1)->getStereo() == Bond::STEREONONE);
+    CHECK(mol->getBondWithIdx(1)->getBondDir() == Bond::UNKNOWN);
+
+    CHECK(mol->getBondWithIdx(2)->getStereo() == Bond::STEREONONE);
+    CHECK(mol->getBondWithIdx(2)->getBondDir() == Bond::UNKNOWN);
+  }
+  SECTION("double-explicit-crossed-2000") {
+    auto mol = R"CTAB(double-explicit-crossed-2000.mol
+  ChemDraw10232310432D
+
+  4  3  0  0  0  0  0  0  0  0999 V2000
+   -0.7144    0.2062    0.0000 C   0  0  0  0  0  0  0  0  0  0  0  0
+    0.0000    0.6187    0.0000 C   0  0  0  0  0  0  0  0  0  0  0  0
+    0.7144    0.2062    0.0000 F   0  0  0  0  0  0  0  0  0  0  0  0
+   -0.7144   -0.6187    0.0000 O   0  0  0  0  0  0  0  0  0  0  0  0
+  1  2  2  3
+  2  3  1  4
+  1  4  1  4
+M  END
+)CTAB"_ctab;
+    REQUIRE(mol);
+    CHECK(mol->getBondWithIdx(0)->getStereo() == Bond::STEREOANY);
+    CHECK(mol->getBondWithIdx(0)->getBondDir() == Bond::NONE);
+    CHECK(mol->getBondWithIdx(0)->getProp<int>(
+              common_properties::_MolFileBondStereo) == 3);
+    CHECK(!mol->getBondWithIdx(0)->hasProp(common_properties::_MolFileBondCfg));
+    CHECK(!mol->getBondWithIdx(0)->hasProp(common_properties::_UnknownStereo));
+
+    CHECK(mol->getBondWithIdx(1)->getStereo() == Bond::STEREONONE);
+    CHECK(mol->getBondWithIdx(1)->getBondDir() == Bond::NONE);
+    CHECK(mol->getBondWithIdx(1)->getProp<int>(
+              common_properties::_MolFileBondStereo) == 4);
+    CHECK(!mol->getBondWithIdx(1)->hasProp(common_properties::_MolFileBondCfg));
+    CHECK(mol->getBondWithIdx(1)->getProp<int>(
+        common_properties::_UnknownStereo));
+
+    CHECK(mol->getBondWithIdx(2)->getStereo() == Bond::STEREONONE);
+    CHECK(mol->getBondWithIdx(2)->getBondDir() == Bond::NONE);
+    CHECK(mol->getBondWithIdx(2)->getProp<int>(
+              common_properties::_MolFileBondStereo) == 4);
+    CHECK(!mol->getBondWithIdx(2)->hasProp(common_properties::_MolFileBondCfg));
+    CHECK(mol->getBondWithIdx(2)->getProp<int>(
+        common_properties::_UnknownStereo));
+
+    Chirality::reapplyMolBlockWedging(*mol);
+    CHECK(mol->getBondWithIdx(0)->getStereo() == Bond::STEREOANY);
+    CHECK(mol->getBondWithIdx(0)->getBondDir() == Bond::EITHERDOUBLE);
+
+    CHECK(mol->getBondWithIdx(1)->getStereo() == Bond::STEREONONE);
+    CHECK(mol->getBondWithIdx(1)->getBondDir() == Bond::UNKNOWN);
+
+    CHECK(mol->getBondWithIdx(2)->getStereo() == Bond::STEREONONE);
+    CHECK(mol->getBondWithIdx(2)->getBondDir() == Bond::UNKNOWN);
+  }
+  SECTION("double-explicit-crossed-3000") {
+    auto mol = R"CTAB(double-explicit-crossed-3000.mol
+  ChemDraw10232310422D
+
+  0  0  0     0  0              0 V3000
+M  V30 BEGIN CTAB
+M  V30 COUNTS 4 3 0 0 0
+M  V30 BEGIN ATOM
+M  V30 1 C -0.714435 0.206182 0.000000 0
+M  V30 2 C 0.000000 0.618744 0.000000 0
+M  V30 3 F 0.714435 0.206182 0.000000 0
+M  V30 4 O -0.714435 -0.618744 0.000000 0
+M  V30 END ATOM
+M  V30 BEGIN BOND
+M  V30 1 2 1 2 CFG=2
+M  V30 2 1 2 3 CFG=2
+M  V30 3 1 1 4 CFG=2
+M  V30 END BOND
+M  V30 END CTAB
+M  END
+)CTAB"_ctab;
+    REQUIRE(mol);
+    CHECK(mol->getBondWithIdx(0)->getStereo() == Bond::STEREOANY);
+    CHECK(mol->getBondWithIdx(0)->getBondDir() == Bond::NONE);
+    CHECK(!mol->getBondWithIdx(0)->hasProp(
+        common_properties::_MolFileBondStereo));
+    CHECK(mol->getBondWithIdx(0)->getProp<int>(
+              common_properties::_MolFileBondCfg) == 2);
+    CHECK(!mol->getBondWithIdx(0)->hasProp(common_properties::_UnknownStereo));
+
+    CHECK(mol->getBondWithIdx(1)->getStereo() == Bond::STEREONONE);
+    CHECK(mol->getBondWithIdx(1)->getBondDir() == Bond::NONE);
+    CHECK(!mol->getBondWithIdx(1)->hasProp(
+        common_properties::_MolFileBondStereo));
+    CHECK(mol->getBondWithIdx(1)->getProp<int>(
+              common_properties::_MolFileBondCfg) == 2);
+    CHECK(mol->getBondWithIdx(1)->getProp<int>(
+        common_properties::_UnknownStereo));
+
+    CHECK(mol->getBondWithIdx(2)->getStereo() == Bond::STEREONONE);
+    CHECK(mol->getBondWithIdx(2)->getBondDir() == Bond::NONE);
+    CHECK(!mol->getBondWithIdx(2)->hasProp(
+        common_properties::_MolFileBondStereo));
+    CHECK(mol->getBondWithIdx(2)->getProp<int>(
+              common_properties::_MolFileBondCfg) == 2);
+    CHECK(mol->getBondWithIdx(2)->getProp<int>(
+        common_properties::_UnknownStereo));
+
+    Chirality::reapplyMolBlockWedging(*mol);
+    CHECK(mol->getBondWithIdx(0)->getStereo() == Bond::STEREOANY);
+    CHECK(mol->getBondWithIdx(0)->getBondDir() == Bond::EITHERDOUBLE);
+
+    CHECK(mol->getBondWithIdx(1)->getStereo() == Bond::STEREONONE);
+    CHECK(mol->getBondWithIdx(1)->getBondDir() == Bond::UNKNOWN);
+
+    CHECK(mol->getBondWithIdx(2)->getStereo() == Bond::STEREONONE);
+    CHECK(mol->getBondWithIdx(2)->getBondDir() == Bond::UNKNOWN);
+  }
+  SECTION("double-2-2000") {
+    auto mol = R"CTAB(double-2-2000.mol
+  ChemDraw10192311332D
+
+  4  3  0  0  0  0  0  0  0  0999 V2000
+   -0.3572   -0.2062    0.0000 C   0  0  0  0  0  0  0  0  0  0  0  0
+    0.3572    0.2062    0.0000 C   0  0  0  0  0  0  0  0  0  0  0  0
+    1.0717    0.6188    0.0000 F   0  0  0  0  0  0  0  0  0  0  0  0
+   -1.0717   -0.6188    0.0000 O   0  0  0  0  0  0  0  0  0  0  0  0
+  1  2  2  0        0
+  2  3  1  4        0
+  1  4  1  4        0
+M  END
+)CTAB"_ctab;
+    REQUIRE(mol);
+    CHECK(mol->getBondWithIdx(0)->getStereo() == Bond::STEREOANY);
+    CHECK(mol->getBondWithIdx(0)->getBondDir() == Bond::NONE);
+    CHECK(!mol->getBondWithIdx(0)->hasProp(
+        common_properties::_MolFileBondStereo));
+    CHECK(!mol->getBondWithIdx(0)->hasProp(common_properties::_MolFileBondCfg));
+    CHECK(!mol->getBondWithIdx(0)->hasProp(common_properties::_UnknownStereo));
+
+    CHECK(mol->getBondWithIdx(1)->getStereo() == Bond::STEREONONE);
+    CHECK(mol->getBondWithIdx(1)->getBondDir() == Bond::NONE);
+    CHECK(mol->getBondWithIdx(1)->getProp<int>(
+              common_properties::_MolFileBondStereo) == 4);
+    CHECK(!mol->getBondWithIdx(1)->hasProp(common_properties::_MolFileBondCfg));
+    CHECK(mol->getBondWithIdx(1)->getProp<int>(
+        common_properties::_UnknownStereo));
+
+    CHECK(mol->getBondWithIdx(2)->getStereo() == Bond::STEREONONE);
+    CHECK(mol->getBondWithIdx(2)->getBondDir() == Bond::NONE);
+    CHECK(mol->getBondWithIdx(2)->getProp<int>(
+              common_properties::_MolFileBondStereo) == 4);
+    CHECK(!mol->getBondWithIdx(2)->hasProp(common_properties::_MolFileBondCfg));
+    CHECK(mol->getBondWithIdx(2)->getProp<int>(
+        common_properties::_UnknownStereo));
+
+    Chirality::reapplyMolBlockWedging(*mol);
+    CHECK(mol->getBondWithIdx(0)->getStereo() == Bond::STEREONONE);
+    CHECK(mol->getBondWithIdx(0)->getBondDir() == Bond::NONE);
+
+    CHECK(mol->getBondWithIdx(1)->getStereo() == Bond::STEREONONE);
+    CHECK(mol->getBondWithIdx(1)->getBondDir() == Bond::UNKNOWN);
+
+    CHECK(mol->getBondWithIdx(2)->getStereo() == Bond::STEREONONE);
+    CHECK(mol->getBondWithIdx(2)->getBondDir() == Bond::UNKNOWN);
+  }
+  SECTION("double-2-3000") {
+    auto mol = R"CTAB(double-2-3000.mol
+  ChemDraw10232310312D
+
+  0  0  0     0  0              0 V3000
+M  V30 BEGIN CTAB
+M  V30 COUNTS 4 3 0 0 0
+M  V30 BEGIN ATOM
+M  V30 1 C -0.357168 -0.206181 0.000000 0
+M  V30 2 C 0.357167 0.206182 0.000000 0
+M  V30 3 F 1.071603 0.618744 0.000000 0
+M  V30 4 O -1.071603 -0.618744 0.000000 0
+M  V30 END ATOM
+M  V30 BEGIN BOND
+M  V30 1 2 1 2
+M  V30 2 1 2 3 CFG=2
+M  V30 3 1 1 4 CFG=2
+M  V30 END BOND
+M  V30 END CTAB
+M  END
+)CTAB"_ctab;
+    REQUIRE(mol);
+    CHECK(mol->getBondWithIdx(0)->getStereo() == Bond::STEREOANY);
+    CHECK(mol->getBondWithIdx(0)->getBondDir() == Bond::NONE);
+    CHECK(!mol->getBondWithIdx(0)->hasProp(
+        common_properties::_MolFileBondStereo));
+    CHECK(!mol->getBondWithIdx(0)->hasProp(common_properties::_MolFileBondCfg));
+    CHECK(!mol->getBondWithIdx(0)->hasProp(common_properties::_UnknownStereo));
+
+    CHECK(mol->getBondWithIdx(1)->getStereo() == Bond::STEREONONE);
+    CHECK(mol->getBondWithIdx(1)->getBondDir() == Bond::NONE);
+    CHECK(!mol->getBondWithIdx(1)->hasProp(
+        common_properties::_MolFileBondStereo));
+    CHECK(mol->getBondWithIdx(1)->getProp<int>(
+              common_properties::_MolFileBondCfg) == 2);
+    CHECK(mol->getBondWithIdx(1)->getProp<int>(
+        common_properties::_UnknownStereo));
+
+    CHECK(mol->getBondWithIdx(2)->getStereo() == Bond::STEREONONE);
+    CHECK(mol->getBondWithIdx(2)->getBondDir() == Bond::NONE);
+    CHECK(!mol->getBondWithIdx(2)->hasProp(
+        common_properties::_MolFileBondStereo));
+    CHECK(mol->getBondWithIdx(2)->getProp<int>(
+              common_properties::_MolFileBondCfg) == 2);
+    CHECK(mol->getBondWithIdx(2)->getProp<int>(
+        common_properties::_UnknownStereo));
+
+    Chirality::reapplyMolBlockWedging(*mol);
+    CHECK(mol->getBondWithIdx(0)->getStereo() == Bond::STEREONONE);
+    CHECK(mol->getBondWithIdx(0)->getBondDir() == Bond::NONE);
+
+    CHECK(mol->getBondWithIdx(1)->getStereo() == Bond::STEREONONE);
+    CHECK(mol->getBondWithIdx(1)->getBondDir() == Bond::UNKNOWN);
+
+    CHECK(mol->getBondWithIdx(2)->getStereo() == Bond::STEREONONE);
+    CHECK(mol->getBondWithIdx(2)->getBondDir() == Bond::UNKNOWN);
+  }
+  SECTION("double-2-explicit-crossed-2000") {
+    auto mol = R"CTAB(double-2-explicit-crossed-2000.mol
+  ChemDraw10232310432D
+
+  4  3  0  0  0  0  0  0  0  0999 V2000
+   -0.3572   -0.2062    0.0000 C   0  0  0  0  0  0  0  0  0  0  0  0
+    0.3572    0.2062    0.0000 C   0  0  0  0  0  0  0  0  0  0  0  0
+    1.0716    0.6187    0.0000 F   0  0  0  0  0  0  0  0  0  0  0  0
+   -1.0716   -0.6187    0.0000 O   0  0  0  0  0  0  0  0  0  0  0  0
+  1  2  2  3
+  2  3  1  4
+  1  4  1  4
+M  END
+)CTAB"_ctab;
+    REQUIRE(mol);
+    CHECK(mol->getBondWithIdx(0)->getStereo() == Bond::STEREOANY);
+    CHECK(mol->getBondWithIdx(0)->getBondDir() == Bond::NONE);
+    CHECK(mol->getBondWithIdx(0)->getProp<int>(
+              common_properties::_MolFileBondStereo) == 3);
+    CHECK(!mol->getBondWithIdx(0)->hasProp(common_properties::_MolFileBondCfg));
+    CHECK(!mol->getBondWithIdx(0)->hasProp(common_properties::_UnknownStereo));
+
+    CHECK(mol->getBondWithIdx(1)->getStereo() == Bond::STEREONONE);
+    CHECK(mol->getBondWithIdx(1)->getBondDir() == Bond::NONE);
+    CHECK(mol->getBondWithIdx(1)->getProp<int>(
+              common_properties::_MolFileBondStereo) == 4);
+    CHECK(!mol->getBondWithIdx(1)->hasProp(common_properties::_MolFileBondCfg));
+    CHECK(mol->getBondWithIdx(1)->getProp<int>(
+        common_properties::_UnknownStereo));
+
+    CHECK(mol->getBondWithIdx(2)->getStereo() == Bond::STEREONONE);
+    CHECK(mol->getBondWithIdx(2)->getBondDir() == Bond::NONE);
+    CHECK(mol->getBondWithIdx(2)->getProp<int>(
+              common_properties::_MolFileBondStereo) == 4);
+    CHECK(!mol->getBondWithIdx(2)->hasProp(common_properties::_MolFileBondCfg));
+    CHECK(mol->getBondWithIdx(2)->getProp<int>(
+        common_properties::_UnknownStereo));
+
+    Chirality::reapplyMolBlockWedging(*mol);
+    CHECK(mol->getBondWithIdx(0)->getStereo() == Bond::STEREOANY);
+    CHECK(mol->getBondWithIdx(0)->getBondDir() == Bond::EITHERDOUBLE);
+
+    CHECK(mol->getBondWithIdx(1)->getStereo() == Bond::STEREONONE);
+    CHECK(mol->getBondWithIdx(1)->getBondDir() == Bond::UNKNOWN);
+
+    CHECK(mol->getBondWithIdx(2)->getStereo() == Bond::STEREONONE);
+    CHECK(mol->getBondWithIdx(2)->getBondDir() == Bond::UNKNOWN);
+  }
+  SECTION("double-2-explicit-crossed-3000") {
+    auto mol = R"CTAB(double-2-explicit-crossed-3000.mol
+  ChemDraw10232310422D
+
+  0  0  0     0  0              0 V3000
+M  V30 BEGIN CTAB
+M  V30 COUNTS 4 3 0 0 0
+M  V30 BEGIN ATOM
+M  V30 1 C -0.357168 -0.206181 0.000000 0
+M  V30 2 C 0.357167 0.206182 0.000000 0
+M  V30 3 F 1.071603 0.618744 0.000000 0
+M  V30 4 O -1.071603 -0.618744 0.000000 0
+M  V30 END ATOM
+M  V30 BEGIN BOND
+M  V30 1 2 1 2 CFG=2
+M  V30 2 1 2 3 CFG=2
+M  V30 3 1 1 4 CFG=2
+M  V30 END BOND
+M  V30 END CTAB
+M  END
+)CTAB"_ctab;
+    REQUIRE(mol);
+    CHECK(mol->getBondWithIdx(0)->getStereo() == Bond::STEREOANY);
+    CHECK(mol->getBondWithIdx(0)->getBondDir() == Bond::NONE);
+    CHECK(!mol->getBondWithIdx(0)->hasProp(
+        common_properties::_MolFileBondStereo));
+    CHECK(mol->getBondWithIdx(0)->getProp<int>(
+              common_properties::_MolFileBondCfg) == 2);
+    CHECK(!mol->getBondWithIdx(0)->hasProp(common_properties::_UnknownStereo));
+
+    CHECK(mol->getBondWithIdx(1)->getStereo() == Bond::STEREONONE);
+    CHECK(mol->getBondWithIdx(1)->getBondDir() == Bond::NONE);
+    CHECK(!mol->getBondWithIdx(1)->hasProp(
+        common_properties::_MolFileBondStereo));
+    CHECK(mol->getBondWithIdx(1)->getProp<int>(
+              common_properties::_MolFileBondCfg) == 2);
+    CHECK(mol->getBondWithIdx(1)->getProp<int>(
+        common_properties::_UnknownStereo));
+
+    CHECK(mol->getBondWithIdx(2)->getStereo() == Bond::STEREONONE);
+    CHECK(mol->getBondWithIdx(2)->getBondDir() == Bond::NONE);
+    CHECK(!mol->getBondWithIdx(2)->hasProp(
+        common_properties::_MolFileBondStereo));
+    CHECK(mol->getBondWithIdx(2)->getProp<int>(
+              common_properties::_MolFileBondCfg) == 2);
+    CHECK(mol->getBondWithIdx(2)->getProp<int>(
+        common_properties::_UnknownStereo));
+
+    Chirality::reapplyMolBlockWedging(*mol);
+    CHECK(mol->getBondWithIdx(0)->getStereo() == Bond::STEREOANY);
+    CHECK(mol->getBondWithIdx(0)->getBondDir() == Bond::EITHERDOUBLE);
+
+    CHECK(mol->getBondWithIdx(1)->getStereo() == Bond::STEREONONE);
+    CHECK(mol->getBondWithIdx(1)->getBondDir() == Bond::UNKNOWN);
+
+    CHECK(mol->getBondWithIdx(2)->getStereo() == Bond::STEREONONE);
+    CHECK(mol->getBondWithIdx(2)->getBondDir() == Bond::UNKNOWN);
+  }
+  SECTION("di-imine-2-2000") {
+    auto mol = R"CTAB(di-imine-2-2000.mol
+  ChemDraw10192311522D
+
+  8  7  0  0  0  0  0  0  0  0999 V2000
+   -0.9959   -1.0600    0.0000 C   0  0  0  0  0  0  0  0  0  0  0  0
+   -0.4125   -0.4767    0.0000 C   0  0  0  0  0  0  0  0  0  0  0  0
+    0.4125   -0.4767    0.0000 C   0  0  0  0  0  0  0  0  0  0  0  0
+    0.9959   -1.0600    0.0000 C   0  0  0  0  0  0  0  0  0  0  0  0
+   -0.7282    0.2855    0.0000 N   0  0  0  0  0  0  0  0  0  0  0  0
+   -0.9971    1.0600    0.0000 C   0  0  0  0  0  0  0  0  0  0  0  0
+    0.7282    0.2855    0.0000 N   0  0  0  0  0  0  0  0  0  0  0  0
+    0.9971    1.0270    0.0000 C   0  0  0  0  0  0  0  0  0  0  0  0
+  1  2  1  0        0
+  2  3  1  0        0
+  3  4  1  0        0
+  2  5  2  0        0
+  5  6  1  4        0
+  3  7  2  0        0
+  7  8  1  4        0
+M  END
+)CTAB"_ctab;
+    REQUIRE(mol);
+    CHECK(mol->getBondWithIdx(3)->getStereo() == Bond::STEREOANY);
+    CHECK(mol->getBondWithIdx(3)->getBondDir() == Bond::NONE);
+    CHECK(!mol->getBondWithIdx(3)->hasProp(
+        common_properties::_MolFileBondStereo));
+    CHECK(!mol->getBondWithIdx(3)->hasProp(common_properties::_MolFileBondCfg));
+    CHECK(!mol->getBondWithIdx(3)->hasProp(common_properties::_UnknownStereo));
+
+    CHECK(mol->getBondWithIdx(4)->getStereo() == Bond::STEREONONE);
+    CHECK(mol->getBondWithIdx(4)->getBondDir() == Bond::NONE);
+    CHECK(mol->getBondWithIdx(4)->getProp<int>(
+              common_properties::_MolFileBondStereo) == 4);
+    CHECK(!mol->getBondWithIdx(4)->hasProp(common_properties::_MolFileBondCfg));
+    CHECK(mol->getBondWithIdx(4)->getProp<int>(
+        common_properties::_UnknownStereo));
+
+    CHECK(mol->getBondWithIdx(5)->getStereo() == Bond::STEREOANY);
+    CHECK(mol->getBondWithIdx(5)->getBondDir() == Bond::NONE);
+    CHECK(!mol->getBondWithIdx(5)->hasProp(
+        common_properties::_MolFileBondStereo));
+    CHECK(!mol->getBondWithIdx(5)->hasProp(common_properties::_MolFileBondCfg));
+    CHECK(!mol->getBondWithIdx(5)->hasProp(common_properties::_UnknownStereo));
+
+    CHECK(mol->getBondWithIdx(6)->getStereo() == Bond::STEREONONE);
+    CHECK(mol->getBondWithIdx(6)->getBondDir() == Bond::NONE);
+    CHECK(mol->getBondWithIdx(6)->getProp<int>(
+              common_properties::_MolFileBondStereo) == 4);
+    CHECK(!mol->getBondWithIdx(6)->hasProp(common_properties::_MolFileBondCfg));
+    CHECK(mol->getBondWithIdx(6)->getProp<int>(
+        common_properties::_UnknownStereo));
+
+    Chirality::reapplyMolBlockWedging(*mol);
+    CHECK(mol->getBondWithIdx(3)->getStereo() == Bond::STEREONONE);
+    CHECK(mol->getBondWithIdx(3)->getBondDir() == Bond::NONE);
+
+    CHECK(mol->getBondWithIdx(4)->getStereo() == Bond::STEREONONE);
+    CHECK(mol->getBondWithIdx(4)->getBondDir() == Bond::UNKNOWN);
+
+    CHECK(mol->getBondWithIdx(5)->getStereo() == Bond::STEREONONE);
+    CHECK(mol->getBondWithIdx(5)->getBondDir() == Bond::NONE);
+
+    CHECK(mol->getBondWithIdx(6)->getStereo() == Bond::STEREONONE);
+    CHECK(mol->getBondWithIdx(6)->getBondDir() == Bond::UNKNOWN);
+  }
+  SECTION("di-imine-2-3000") {
+    auto mol = R"CTAB(di-imine-2-3000.mol
+  ChemDraw10232310302D
+
+  0  0  0     0  0              0 V3000
+M  V30 BEGIN CTAB
+M  V30 COUNTS 8 7 0 0 0
+M  V30 BEGIN ATOM
+M  V30 1 C -0.995922 -1.060024 0.000000 0
+M  V30 2 C -0.412509 -0.476711 0.000000 0
+M  V30 3 C 0.412509 -0.476711 0.000000 0
+M  V30 4 C 0.995923 -1.060024 0.000000 0
+M  V30 5 N -0.728217 0.285506 0.000000 0
+M  V30 6 C -0.997122 1.060024 0.000000 0
+M  V30 7 N 0.728216 0.285506 0.000000 0
+M  V30 8 C 0.997122 1.027023 0.000000 0
+M  V30 END ATOM
+M  V30 BEGIN BOND
+M  V30 1 1 1 2
+M  V30 2 1 2 3
+M  V30 3 1 3 4
+M  V30 4 2 2 5
+M  V30 5 1 5 6 CFG=2
+M  V30 6 2 3 7
+M  V30 7 1 7 8 CFG=2
+M  V30 END BOND
+M  V30 END CTAB
+M  END
+)CTAB"_ctab;
+    REQUIRE(mol);
+    CHECK(mol->getBondWithIdx(3)->getStereo() == Bond::STEREOANY);
+    CHECK(mol->getBondWithIdx(3)->getBondDir() == Bond::NONE);
+    CHECK(!mol->getBondWithIdx(3)->hasProp(
+        common_properties::_MolFileBondStereo));
+    CHECK(!mol->getBondWithIdx(3)->hasProp(common_properties::_MolFileBondCfg));
+    CHECK(!mol->getBondWithIdx(3)->hasProp(common_properties::_UnknownStereo));
+
+    CHECK(mol->getBondWithIdx(4)->getStereo() == Bond::STEREONONE);
+    CHECK(mol->getBondWithIdx(4)->getBondDir() == Bond::NONE);
+    CHECK(!mol->getBondWithIdx(4)->hasProp(
+        common_properties::_MolFileBondStereo));
+    CHECK(mol->getBondWithIdx(4)->getProp<int>(
+              common_properties::_MolFileBondCfg) == 2);
+    CHECK(mol->getBondWithIdx(4)->getProp<int>(
+        common_properties::_UnknownStereo));
+
+    CHECK(mol->getBondWithIdx(5)->getStereo() == Bond::STEREOANY);
+    CHECK(mol->getBondWithIdx(5)->getBondDir() == Bond::NONE);
+    CHECK(!mol->getBondWithIdx(5)->hasProp(
+        common_properties::_MolFileBondStereo));
+    CHECK(!mol->getBondWithIdx(5)->hasProp(common_properties::_MolFileBondCfg));
+    CHECK(!mol->getBondWithIdx(5)->hasProp(common_properties::_UnknownStereo));
+
+    CHECK(mol->getBondWithIdx(6)->getStereo() == Bond::STEREONONE);
+    CHECK(mol->getBondWithIdx(6)->getBondDir() == Bond::NONE);
+    CHECK(!mol->getBondWithIdx(6)->hasProp(
+        common_properties::_MolFileBondStereo));
+    CHECK(mol->getBondWithIdx(6)->getProp<int>(
+              common_properties::_MolFileBondCfg) == 2);
+    CHECK(mol->getBondWithIdx(6)->getProp<int>(
+        common_properties::_UnknownStereo));
+
+    Chirality::reapplyMolBlockWedging(*mol);
+    CHECK(mol->getBondWithIdx(3)->getStereo() == Bond::STEREONONE);
+    CHECK(mol->getBondWithIdx(3)->getBondDir() == Bond::NONE);
+
+    CHECK(mol->getBondWithIdx(4)->getStereo() == Bond::STEREONONE);
+    CHECK(mol->getBondWithIdx(4)->getBondDir() == Bond::UNKNOWN);
+
+    CHECK(mol->getBondWithIdx(5)->getStereo() == Bond::STEREONONE);
+    CHECK(mol->getBondWithIdx(5)->getBondDir() == Bond::NONE);
+
+    CHECK(mol->getBondWithIdx(6)->getStereo() == Bond::STEREONONE);
+    CHECK(mol->getBondWithIdx(6)->getBondDir() == Bond::UNKNOWN);
+  }
+  SECTION("di-imine-2-explicit-crossed-2000") {
+    auto mol = R"CTAB(di-imine-2-explicit-crossed-2000.mol
+  ChemDraw10232310432D
+
+  8  7  0  0  0  0  0  0  0  0999 V2000
+   -0.9959   -1.0600    0.0000 C   0  0  0  0  0  0  0  0  0  0  0  0
+   -0.4125   -0.4767    0.0000 C   0  0  0  0  0  0  0  0  0  0  0  0
+    0.4125   -0.4767    0.0000 C   0  0  0  0  0  0  0  0  0  0  0  0
+    0.9959   -1.0600    0.0000 C   0  0  0  0  0  0  0  0  0  0  0  0
+   -0.7282    0.2855    0.0000 N   0  0  0  0  0  0  0  0  0  0  0  0
+   -0.9971    1.0600    0.0000 C   0  0  0  0  0  0  0  0  0  0  0  0
+    0.7282    0.2855    0.0000 N   0  0  0  0  0  0  0  0  0  0  0  0
+    0.9971    1.0270    0.0000 C   0  0  0  0  0  0  0  0  0  0  0  0
+  1  2  1  0
+  2  3  1  0
+  3  4  1  0
+  2  5  2  3
+  5  6  1  4
+  3  7  2  0
+  7  8  1  4
+M  END
+)CTAB"_ctab;
+    REQUIRE(mol);
+    CHECK(mol->getBondWithIdx(3)->getStereo() == Bond::STEREOANY);
+    CHECK(mol->getBondWithIdx(3)->getBondDir() == Bond::NONE);
+    CHECK(mol->getBondWithIdx(3)->getProp<int>(
+              common_properties::_MolFileBondStereo) == 3);
+    CHECK(!mol->getBondWithIdx(3)->hasProp(common_properties::_MolFileBondCfg));
+    CHECK(!mol->getBondWithIdx(3)->hasProp(common_properties::_UnknownStereo));
+
+    CHECK(mol->getBondWithIdx(4)->getStereo() == Bond::STEREONONE);
+    CHECK(mol->getBondWithIdx(4)->getBondDir() == Bond::NONE);
+    CHECK(mol->getBondWithIdx(4)->getProp<int>(
+              common_properties::_MolFileBondStereo) == 4);
+    CHECK(!mol->getBondWithIdx(4)->hasProp(common_properties::_MolFileBondCfg));
+    CHECK(mol->getBondWithIdx(4)->getProp<int>(
+        common_properties::_UnknownStereo));
+
+    CHECK(mol->getBondWithIdx(5)->getStereo() == Bond::STEREOANY);
+    CHECK(mol->getBondWithIdx(5)->getBondDir() == Bond::NONE);
+    CHECK(!mol->getBondWithIdx(5)->hasProp(
+        common_properties::_MolFileBondStereo));
+    CHECK(!mol->getBondWithIdx(5)->hasProp(common_properties::_MolFileBondCfg));
+    CHECK(!mol->getBondWithIdx(5)->hasProp(common_properties::_UnknownStereo));
+
+    CHECK(mol->getBondWithIdx(6)->getStereo() == Bond::STEREONONE);
+    CHECK(mol->getBondWithIdx(6)->getBondDir() == Bond::NONE);
+    CHECK(mol->getBondWithIdx(6)->getProp<int>(
+              common_properties::_MolFileBondStereo) == 4);
+    CHECK(!mol->getBondWithIdx(6)->hasProp(common_properties::_MolFileBondCfg));
+    CHECK(mol->getBondWithIdx(6)->getProp<int>(
+        common_properties::_UnknownStereo));
+
+    Chirality::reapplyMolBlockWedging(*mol);
+    CHECK(mol->getBondWithIdx(3)->getStereo() == Bond::STEREOANY);
+    CHECK(mol->getBondWithIdx(3)->getBondDir() == Bond::EITHERDOUBLE);
+
+    CHECK(mol->getBondWithIdx(4)->getStereo() == Bond::STEREONONE);
+    CHECK(mol->getBondWithIdx(4)->getBondDir() == Bond::UNKNOWN);
+
+    CHECK(mol->getBondWithIdx(5)->getStereo() == Bond::STEREONONE);
+    CHECK(mol->getBondWithIdx(5)->getBondDir() == Bond::NONE);
+
+    CHECK(mol->getBondWithIdx(6)->getStereo() == Bond::STEREONONE);
+    CHECK(mol->getBondWithIdx(6)->getBondDir() == Bond::UNKNOWN);
+  }
+  SECTION("di-imine-2-explicit-crossed-3000") {
+    auto mol = R"CTAB(di-imine-2-explicit-crossed-3000.mol
+  ChemDraw10232310432D
+
+  0  0  0     0  0              0 V3000
+M  V30 BEGIN CTAB
+M  V30 COUNTS 8 7 0 0 0
+M  V30 BEGIN ATOM
+M  V30 1 C -0.995922 -1.060024 0.000000 0
+M  V30 2 C -0.412509 -0.476711 0.000000 0
+M  V30 3 C 0.412509 -0.476711 0.000000 0
+M  V30 4 C 0.995923 -1.060024 0.000000 0
+M  V30 5 N -0.728217 0.285506 0.000000 0
+M  V30 6 C -0.997122 1.060024 0.000000 0
+M  V30 7 N 0.728216 0.285506 0.000000 0
+M  V30 8 C 0.997122 1.027023 0.000000 0
+M  V30 END ATOM
+M  V30 BEGIN BOND
+M  V30 1 1 1 2
+M  V30 2 1 2 3
+M  V30 3 1 3 4
+M  V30 4 2 2 5 CFG=2
+M  V30 5 1 5 6 CFG=2
+M  V30 6 2 3 7
+M  V30 7 1 7 8 CFG=2
+M  V30 END BOND
+M  V30 END CTAB
+M  END
+)CTAB"_ctab;
+    REQUIRE(mol);
+    CHECK(mol->getBondWithIdx(3)->getStereo() == Bond::STEREOANY);
+    CHECK(mol->getBondWithIdx(3)->getBondDir() == Bond::NONE);
+    CHECK(!mol->getBondWithIdx(3)->hasProp(
+        common_properties::_MolFileBondStereo));
+    CHECK(mol->getBondWithIdx(3)->getProp<int>(
+              common_properties::_MolFileBondCfg) == 2);
+    CHECK(!mol->getBondWithIdx(3)->hasProp(common_properties::_UnknownStereo));
+
+    CHECK(mol->getBondWithIdx(4)->getStereo() == Bond::STEREONONE);
+    CHECK(mol->getBondWithIdx(4)->getBondDir() == Bond::NONE);
+    CHECK(!mol->getBondWithIdx(4)->hasProp(
+        common_properties::_MolFileBondStereo));
+    CHECK(mol->getBondWithIdx(4)->getProp<int>(
+              common_properties::_MolFileBondCfg) == 2);
+    CHECK(mol->getBondWithIdx(4)->getProp<int>(
+        common_properties::_UnknownStereo));
+
+    CHECK(mol->getBondWithIdx(5)->getStereo() == Bond::STEREOANY);
+    CHECK(mol->getBondWithIdx(5)->getBondDir() == Bond::NONE);
+    CHECK(!mol->getBondWithIdx(5)->hasProp(
+        common_properties::_MolFileBondStereo));
+    CHECK(!mol->getBondWithIdx(5)->hasProp(common_properties::_MolFileBondCfg));
+    CHECK(!mol->getBondWithIdx(5)->hasProp(common_properties::_UnknownStereo));
+
+    CHECK(mol->getBondWithIdx(6)->getStereo() == Bond::STEREONONE);
+    CHECK(mol->getBondWithIdx(6)->getBondDir() == Bond::NONE);
+    CHECK(!mol->getBondWithIdx(6)->hasProp(
+        common_properties::_MolFileBondStereo));
+    CHECK(mol->getBondWithIdx(6)->getProp<int>(
+              common_properties::_MolFileBondCfg) == 2);
+    CHECK(mol->getBondWithIdx(6)->getProp<int>(
+        common_properties::_UnknownStereo));
+
+    Chirality::reapplyMolBlockWedging(*mol);
+    CHECK(mol->getBondWithIdx(3)->getStereo() == Bond::STEREOANY);
+    CHECK(mol->getBondWithIdx(3)->getBondDir() == Bond::EITHERDOUBLE);
+
+    CHECK(mol->getBondWithIdx(4)->getStereo() == Bond::STEREONONE);
+    CHECK(mol->getBondWithIdx(4)->getBondDir() == Bond::UNKNOWN);
+
+    CHECK(mol->getBondWithIdx(5)->getStereo() == Bond::STEREONONE);
+    CHECK(mol->getBondWithIdx(5)->getBondDir() == Bond::NONE);
+
+    CHECK(mol->getBondWithIdx(6)->getStereo() == Bond::STEREONONE);
+    CHECK(mol->getBondWithIdx(6)->getBondDir() == Bond::UNKNOWN);
+  }
+
+  SECTION("di-imine-cross-2000") {
+    auto mol = R"CTAB(di-imine-cross-2000.mol
+  ChemDraw10192311582D
+
+  8  7  0  0  0  0  0  0  0  0999 V2000
+   -1.0099   -1.1129    0.0000 C   0  0  0  0  0  0  0  0  0  0  0  0
+   -0.5974   -0.3984    0.0000 C   0  0  0  0  0  0  0  0  0  0  0  0
+    0.2276   -0.3984    0.0000 C   0  0  0  0  0  0  0  0  0  0  0  0
+    0.6401   -1.1129    0.0000 C   0  0  0  0  0  0  0  0  0  0  0  0
+   -0.8109    0.3984    0.0000 N   0  0  0  0  0  0  0  0  0  0  0  0
+    0.6401    0.3160    0.0000 N   0  0  0  0  0  0  0  0  0  0  0  0
+   -1.2234    1.1129    0.0000 C   0  0  0  0  0  0  0  0  0  0  0  0
+    1.2234    0.8994    0.0000 C   0  0  0  0  0  0  0  0  0  0  0  0
+  1  2  1  0        0
+  2  3  1  0        0
+  3  4  1  0        0
+  2  5  2  3        0
+  3  6  2  3        0
+  5  7  1  0        0
+  6  8  1  0        0
+M  END
+)CTAB"_ctab;
+    REQUIRE(mol);
+    CHECK(mol->getBondWithIdx(3)->getStereo() == Bond::STEREOANY);
+    CHECK(mol->getBondWithIdx(3)->getBondDir() == Bond::NONE);
+    CHECK(mol->getBondWithIdx(3)->getProp<int>(
+              common_properties::_MolFileBondStereo) == 3);
+    CHECK(!mol->getBondWithIdx(3)->hasProp(common_properties::_MolFileBondCfg));
+    CHECK(!mol->getBondWithIdx(3)->hasProp(common_properties::_UnknownStereo));
+
+    CHECK(mol->getBondWithIdx(4)->getStereo() == Bond::STEREOANY);
+    CHECK(mol->getBondWithIdx(4)->getBondDir() == Bond::NONE);
+    CHECK(mol->getBondWithIdx(4)->getProp<int>(
+              common_properties::_MolFileBondStereo) == 3);
+    CHECK(!mol->getBondWithIdx(4)->hasProp(common_properties::_MolFileBondCfg));
+    CHECK(!mol->getBondWithIdx(4)->hasProp(common_properties::_UnknownStereo));
+
+    CHECK(mol->getBondWithIdx(5)->getStereo() == Bond::STEREONONE);
+    CHECK(mol->getBondWithIdx(5)->getBondDir() == Bond::NONE);
+    CHECK(!mol->getBondWithIdx(5)->hasProp(
+        common_properties::_MolFileBondStereo));
+    CHECK(!mol->getBondWithIdx(5)->hasProp(common_properties::_MolFileBondCfg));
+    CHECK(!mol->getBondWithIdx(5)->hasProp(common_properties::_UnknownStereo));
+
+    CHECK(mol->getBondWithIdx(6)->getStereo() == Bond::STEREONONE);
+    CHECK(mol->getBondWithIdx(6)->getBondDir() == Bond::NONE);
+    CHECK(!mol->getBondWithIdx(6)->hasProp(
+        common_properties::_MolFileBondStereo));
+    CHECK(!mol->getBondWithIdx(6)->hasProp(common_properties::_MolFileBondCfg));
+    CHECK(!mol->getBondWithIdx(6)->hasProp(common_properties::_UnknownStereo));
+
+    Chirality::reapplyMolBlockWedging(*mol);
+    CHECK(mol->getBondWithIdx(3)->getStereo() == Bond::STEREOANY);
+    CHECK(mol->getBondWithIdx(3)->getBondDir() == Bond::EITHERDOUBLE);
+
+    CHECK(mol->getBondWithIdx(4)->getStereo() == Bond::STEREOANY);
+    CHECK(mol->getBondWithIdx(4)->getBondDir() == Bond::EITHERDOUBLE);
+
+    CHECK(mol->getBondWithIdx(5)->getStereo() == Bond::STEREONONE);
+    CHECK(mol->getBondWithIdx(5)->getBondDir() == Bond::NONE);
+
+    CHECK(mol->getBondWithIdx(6)->getStereo() == Bond::STEREONONE);
+    CHECK(mol->getBondWithIdx(6)->getBondDir() == Bond::NONE);
+  }
+  SECTION("di-imine-cross-3000") {
+    auto mol = R"CTAB(di-imine-cross-3000.mol
+  ChemDraw10232310302D
+
+  0  0  0     0  0              0 V3000
+M  V30 BEGIN CTAB
+M  V30 COUNTS 8 7 0 0 0
+M  V30 BEGIN ATOM
+M  V30 1 C -1.009900 -1.112900 0.000000 0
+M  V30 2 C -0.597400 -0.398400 0.000000 0
+M  V30 3 C 0.227600 -0.398400 0.000000 0
+M  V30 4 C 0.640100 -1.112900 0.000000 0
+M  V30 5 N -0.810900 0.398400 0.000000 0
+M  V30 6 N 0.640100 0.316000 0.000000 0
+M  V30 7 C -1.223400 1.112900 0.000000 0
+M  V30 8 C 1.223400 0.899400 0.000000 0
+M  V30 END ATOM
+M  V30 BEGIN BOND
+M  V30 1 1 1 2
+M  V30 2 1 2 3
+M  V30 3 1 3 4
+M  V30 4 2 2 5 CFG=2
+M  V30 5 2 3 6 CFG=2
+M  V30 6 1 5 7
+M  V30 7 1 6 8
+M  V30 END BOND
+M  V30 END CTAB
+M  END
+)CTAB"_ctab;
+    REQUIRE(mol);
+    CHECK(mol->getBondWithIdx(3)->getStereo() == Bond::STEREOANY);
+    CHECK(mol->getBondWithIdx(3)->getBondDir() == Bond::NONE);
+    CHECK(!mol->getBondWithIdx(3)->hasProp(
+        common_properties::_MolFileBondStereo));
+    CHECK(mol->getBondWithIdx(3)->getProp<int>(
+              common_properties::_MolFileBondCfg) == 2);
+    CHECK(!mol->getBondWithIdx(3)->hasProp(common_properties::_UnknownStereo));
+
+    CHECK(mol->getBondWithIdx(4)->getStereo() == Bond::STEREOANY);
+    CHECK(mol->getBondWithIdx(4)->getBondDir() == Bond::NONE);
+    CHECK(!mol->getBondWithIdx(4)->hasProp(
+        common_properties::_MolFileBondStereo));
+    CHECK(mol->getBondWithIdx(4)->getProp<int>(
+              common_properties::_MolFileBondCfg) == 2);
+    CHECK(!mol->getBondWithIdx(4)->hasProp(common_properties::_UnknownStereo));
+
+    CHECK(mol->getBondWithIdx(5)->getStereo() == Bond::STEREONONE);
+    CHECK(mol->getBondWithIdx(5)->getBondDir() == Bond::NONE);
+    CHECK(!mol->getBondWithIdx(5)->hasProp(
+        common_properties::_MolFileBondStereo));
+    CHECK(!mol->getBondWithIdx(5)->hasProp(common_properties::_MolFileBondCfg));
+    CHECK(!mol->getBondWithIdx(5)->hasProp(common_properties::_UnknownStereo));
+
+    CHECK(mol->getBondWithIdx(6)->getStereo() == Bond::STEREONONE);
+    CHECK(mol->getBondWithIdx(6)->getBondDir() == Bond::NONE);
+    CHECK(!mol->getBondWithIdx(6)->hasProp(
+        common_properties::_MolFileBondStereo));
+    CHECK(!mol->getBondWithIdx(6)->hasProp(common_properties::_MolFileBondCfg));
+    CHECK(!mol->getBondWithIdx(6)->hasProp(common_properties::_UnknownStereo));
+
+    Chirality::reapplyMolBlockWedging(*mol);
+    CHECK(mol->getBondWithIdx(3)->getStereo() == Bond::STEREOANY);
+    CHECK(mol->getBondWithIdx(3)->getBondDir() == Bond::EITHERDOUBLE);
+
+    CHECK(mol->getBondWithIdx(4)->getStereo() == Bond::STEREOANY);
+    CHECK(mol->getBondWithIdx(4)->getBondDir() == Bond::EITHERDOUBLE);
+
+    CHECK(mol->getBondWithIdx(5)->getStereo() == Bond::STEREONONE);
+    CHECK(mol->getBondWithIdx(5)->getBondDir() == Bond::NONE);
+
+    CHECK(mol->getBondWithIdx(6)->getStereo() == Bond::STEREONONE);
+    CHECK(mol->getBondWithIdx(6)->getBondDir() == Bond::NONE);
+  }
+  SECTION(
+      "roundtripping molblock with cis double bond should not change it into crosssed") {
+    auto molblockIn = R"CTAB(
+     RDKit          2D
+
+  5  4  0  0  0  0  0  0  0  0999 V2000
+   -2.4998    2.4772    0.0000 C   0  0  0  0  0  0  0  0  0  0  0  0
+   -3.2142    2.0647    0.0000 C   0  0  0  0  0  0  0  0  0  0  0  0
+   -2.4998    3.3022    0.0000 C   0  0  0  0  0  0  0  0  0  0  0  0
+   -3.2142    3.7147    0.0000 C   0  0  0  0  0  0  0  0  0  0  0  0
+   -3.9287    3.3022    0.0000 Cl  0  0  0  0  0  0  0  0  0  0  0  0
+  2  1  1  0
+  1  3  2  0
+  3  4  1  0
+  4  5  1  0
+M  END
+)CTAB";
+    {
+      std::unique_ptr<RWMol> mol(MolBlockToMol(molblockIn, false));
+      auto molblockOut = MolToMolBlock(*mol);
+      CHECK(molblockIn == molblockOut);
+    }
+    {
+      std::unique_ptr<RWMol> mol(MolBlockToMol(molblockIn, false));
+      reapplyMolBlockWedging(*mol);
+      auto molblockOut = MolToMolBlock(*mol);
+      CHECK(molblockIn == molblockOut);
+    }
+  }
+}


Sanitize number of radical electrons in case of invalid value assigned by CXSMILES (rdkit/rdkit#6842)

#### Reference Issue
Fixes #6370

#### What does this implement/fix? Explain your changes.
Number of radical electrons are first assigned by the regular SMILES, and then get overridden by the CXSMILES extension. For example,

```python
Chem.MolFromSmiles('[CH4]').Debug()
#	0 6 C chg: 0  deg: 0 exp: 4 imp: 0 hyb: 4 arom?: 0 chi: 0
Chem.MolFromSmiles('[CH4] |^1:0|').Debug()
#	0 6 C chg: 0  deg: 0 exp: 4 imp: 0 hyb: 4 arom?: 0 chi: 0 rad: 1
Chem.MolFromSmiles('[CH4] |^2:0|').Debug()
#	0 6 C chg: 0  deg: 0 exp: 4 imp: 0 hyb: 4 arom?: 0 chi: 0 rad: 2
```

The radical info from CXSMILES may be invalid and therefore should be sanitized. However, current implementation of `assignRadicals()` within `sanitizeMol()` will do nothing if the preset number of radical electrons is non-zero. The fix is then to allow such sanitization by removing the condition `if (atom->getNumRadicalElectrons())`.

Unittests are added for a set of CXSMILES:
1. `[XHn] |^m:0|` where X is the element symbol, n = 1, ..., valence, m = 1, ..., 7 denotes the radical type.
2. `[NH4+] |^m:0|` where m = 1, ..., 7 denotes the radical type.

I also fix a minor issue in `calcImplicitValence()` where `d_implicitValence` is not overwritten by the return value.

**Describe the bug**
Sanitization is leaving radicals on molecules where they don't make sense.

**To Reproduce**
```
In [8]: Chem.MolFromSmiles('[NH4+] |^1:0|').Debug()
Atoms:
	0 7 N chg: 1  deg: 0 exp: 4 imp: 0 hyb: 4 arom?: 0 chi: 0 rad: 1
Bonds:

In [9]: Chem.MolFromSmiles('[CH4] |^1:0|').Debug()
Atoms:
	0 6 C chg: 0  deg: 0 exp: 4 imp: 0 hyb: 4 arom?: 0 chi: 0 rad: 1
Bonds:

```
Neither of those should have a radical on it.

**Configuration (please complete the following information):**
 - RDKit version: all
 - OS: all

diff --git a/Code/GraphMol/MolOps.cpp b/Code/GraphMol/MolOps.cpp
index 4ba259f3808..971ee8c7217 100644
--- a/Code/GraphMol/MolOps.cpp
+++ b/Code/GraphMol/MolOps.cpp
@@ -388,9 +388,8 @@ void adjustHs(RWMol &mol) {
 void assignRadicals(RWMol &mol) {
   for (auto atom : mol.atoms()) {
     // we only put automatically assign radicals to things that
-    // don't have them already and don't have implicit Hs:
-    if (!atom->getNoImplicit() || atom->getNumRadicalElectrons() ||
-        !atom->getAtomicNum()) {
+    // don't have implicit Hs:
+    if (!atom->getNoImplicit() || !atom->getAtomicNum()) {
       continue;
     }
     const auto &valens =
diff --git a/ReleaseNotes.md b/ReleaseNotes.md
index f392dd3e07b..7f3fce596cf 100644
--- a/ReleaseNotes.md
+++ b/ReleaseNotes.md
@@ -10,7 +10,7 @@ GitHub)

 ## Backwards incompatible changes
 - Two changes to improve the defaults for conformer generation: the functions EmbedMolecule() and EmbedMultipleConfis() now use ETKDGv3 by default (previously they were using ETKDGV1) and only consider heavy atoms when calculating RMSD for conformer pruning (previously Hs were alos considered).
-
+- The way that the number of radical electrons is calculated for atoms coming from mol blocks has been changed. Systems like a `[CH]` marked as a `DOUBLET` will now have three radical electrons assigned. This is consistent with the value from SMILES.

 ## New Features and Enhancements:

diff --git a/Code/GraphMol/FileParsers/test1.cpp b/Code/GraphMol/FileParsers/test1.cpp
index 6abe90cb05a..509bcb59554 100644
--- a/Code/GraphMol/FileParsers/test1.cpp
+++ b/Code/GraphMol/FileParsers/test1.cpp
@@ -2475,12 +2475,12 @@ void test3V3K() {
   {
     // radical and valence
     fName = rdbase + "CH.v3k.mol";
-    RWMol *m = MolFileToMol(fName);
+    RWMol *m = MolFileToMol(fName);  // cxsmiles = "[CH] |(0,0,),^5:0|"
     TEST_ASSERT(m);
     TEST_ASSERT(m->getNumAtoms() == 1);
     TEST_ASSERT(m->getAtomWithIdx(0)->getNoImplicit());
     TEST_ASSERT(m->getAtomWithIdx(0)->getNumExplicitHs() == 1);
-    TEST_ASSERT(m->getAtomWithIdx(0)->getNumRadicalElectrons() == 1);
+    TEST_ASSERT(m->getAtomWithIdx(0)->getNumRadicalElectrons() == 3);

     std::string mb = MolToMolBlock(*m, true, -1, true, true);
     delete m;
@@ -2494,7 +2494,7 @@ void test3V3K() {
     TEST_ASSERT(m->getNumAtoms() == 1);
     TEST_ASSERT(m->getAtomWithIdx(0)->getNoImplicit());
     TEST_ASSERT(m->getAtomWithIdx(0)->getNumExplicitHs() == 1);
-    TEST_ASSERT(m->getAtomWithIdx(0)->getNumRadicalElectrons() == 1);
+    TEST_ASSERT(m->getAtomWithIdx(0)->getNumRadicalElectrons() == 3);

     delete m;
   }
@@ -3007,10 +3007,7 @@ void testIssue3359739() {
   delete m;
   m = MolBlockToMol(molBlock);
   TEST_ASSERT(m);
-  // NOTE: the following is correct according to the current
-  // state of the code and what the CTAB format supports,
-  // but it's definitely not chemically correct
-  TEST_ASSERT(m->getAtomWithIdx(0)->getNumRadicalElectrons() == 1);
+  TEST_ASSERT(m->getAtomWithIdx(0)->getNumRadicalElectrons() == 3);
   delete m;

   BOOST_LOG(rdInfoLog) << " Finished <---------- " << std::endl;
@@ -3528,12 +3525,12 @@ void testMolFileTotalValence() {
     RWMol *m1;
     std::string fName;
     fName = rdbase + "CH.mol";
-    m1 = MolFileToMol(fName);
+    m1 = MolFileToMol(fName);  // cxsmi = "[CH] |(-1.2375,2.1509,),^5:0|"
     TEST_ASSERT(m1);
     TEST_ASSERT(m1->getNumAtoms() == 1);
     TEST_ASSERT(m1->getAtomWithIdx(0)->getNoImplicit());
     TEST_ASSERT(m1->getAtomWithIdx(0)->getNumExplicitHs() == 1);
-    TEST_ASSERT(m1->getAtomWithIdx(0)->getNumRadicalElectrons() == 1);
+    TEST_ASSERT(m1->getAtomWithIdx(0)->getNumRadicalElectrons() == 3);

     delete m1;
   }
@@ -3566,12 +3563,12 @@ void testMolFileTotalValence() {
     RWMol *m1;
     std::string fName;
     fName = rdbase + "CH.v3k.mol";
-    m1 = MolFileToMol(fName);
+    m1 = MolFileToMol(fName);  // cxsmiles = "[CH] |(0,0,),^5:0|"
     TEST_ASSERT(m1);
     TEST_ASSERT(m1->getNumAtoms() == 1);
     TEST_ASSERT(m1->getAtomWithIdx(0)->getNoImplicit());
     TEST_ASSERT(m1->getAtomWithIdx(0)->getNumExplicitHs() == 1);
-    TEST_ASSERT(m1->getAtomWithIdx(0)->getNumRadicalElectrons() == 1);
+    TEST_ASSERT(m1->getAtomWithIdx(0)->getNumRadicalElectrons() == 3);

     delete m1;
   }
diff --git a/Code/GraphMol/FileParsers/testMolWriter.cpp b/Code/GraphMol/FileParsers/testMolWriter.cpp
index 78275f62864..8fbb0b4c7cb 100644
--- a/Code/GraphMol/FileParsers/testMolWriter.cpp
+++ b/Code/GraphMol/FileParsers/testMolWriter.cpp
@@ -739,7 +739,7 @@ void testMolFileTotalValence() {
     TEST_ASSERT(m1->getNumAtoms() == 1);
     TEST_ASSERT(m1->getAtomWithIdx(0)->getNoImplicit());
     TEST_ASSERT(m1->getAtomWithIdx(0)->getNumExplicitHs() == 1);
-    TEST_ASSERT(m1->getAtomWithIdx(0)->getNumRadicalElectrons() == 1);
+    TEST_ASSERT(m1->getAtomWithIdx(0)->getNumRadicalElectrons() == 3);

     delete m1;
   }
diff --git a/Code/GraphMol/MarvinParse/test_data/mrvValence_value.mrv.expected.mrv b/Code/GraphMol/MarvinParse/test_data/mrvValence_value.mrv.expected.mrv
index 99d10b08c82..2036bd947ff 100644
--- a/Code/GraphMol/MarvinParse/test_data/mrvValence_value.mrv.expected.mrv
+++ b/Code/GraphMol/MarvinParse/test_data/mrvValence_value.mrv.expected.mrv
@@ -1,2 +1,2 @@
 <?xml version="1.0" encoding="utf-8"?>
-<cml xmlns="http://www.chemaxon.com" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.chemaxon.com http://www.chemaxon.com/marvin/schema/mrvSchema_20_20_0.xsd"><MDocument><MChemicalStruct><molecule molID="m1"><atomArray><atom id="a1" elementType="B" x2="4.51182" y2="0.00000" formalCharge="-1" radical="monovalent"/><atom id="a2" elementType="C" x2="2.97182" y2="0.00000"/><atom id="a3" elementType="N" x2="1.43182" y2="0.00000"/></atomArray><bondArray><bond id="b1" atomRefs2="a1 a2" order="1"/><bond id="b2" atomRefs2="a2 a3" order="3"/></bondArray></molecule></MChemicalStruct></MDocument></cml>
\ No newline at end of file
+<cml xmlns="http://www.chemaxon.com" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.chemaxon.com http://www.chemaxon.com/marvin/schema/mrvSchema_20_20_0.xsd"><MDocument><MChemicalStruct><molecule molID="m1"><atomArray><atom id="a1" elementType="B" x2="4.51182" y2="0.00000" formalCharge="-1" radical="trivalent4"/><atom id="a2" elementType="C" x2="2.97182" y2="0.00000"/><atom id="a3" elementType="N" x2="1.43182" y2="0.00000"/></atomArray><bondArray><bond id="b1" atomRefs2="a1 a2" order="1"/><bond id="b2" atomRefs2="a2 a3" order="3"/></bondArray></molecule></MChemicalStruct></MDocument></cml>
\ No newline at end of file
diff --git a/Code/GraphMol/test1.cpp b/Code/GraphMol/test1.cpp
index dcce2fd0aa2..1d2b64e0d07 100644
--- a/Code/GraphMol/test1.cpp
+++ b/Code/GraphMol/test1.cpp
@@ -14,7 +14,6 @@
 #include <GraphMol/RDKitQueries.h>
 #include <RDGeneral/types.h>
 #include <RDGeneral/RDLog.h>
-//#include <boost/log/functions.hpp>
 #include <GraphMol/FileParsers/FileParsers.h>
 #include <GraphMol/FileParsers/MolWriters.h>
 #include <GraphMol/SmilesParse/SmilesParse.h>
@@ -22,6 +21,7 @@
 #include <GraphMol/SmilesParse/SmartsWrite.h>
 #include <sstream>
 #include <iostream>
+#include <boost/format.hpp>
 #include <boost/range/iterator_range.hpp>

 using namespace std;
@@ -1666,6 +1666,60 @@ void testHasValenceViolation() {
   BOOST_LOG(rdInfoLog) << "Finished" << std::endl;
 }

+void testGithub6370() {
+  BOOST_LOG(rdErrorLog) << "-------------------------------------" << std::endl;
+  BOOST_LOG(rdErrorLog)
+      << "    Test Github 6370: non-physical radical counts being preserved"
+      << std::endl;
+
+  auto testRadicalsForSingleAtom = [](const std::string &element, int valence) {
+    for (int explicitHCount = 0; explicitHCount <= valence; explicitHCount++) {
+      for (int radicalType = 1; radicalType <= 7; radicalType++) {
+        std::string smi;
+        if (explicitHCount == 0) {
+          smi = (boost::format("[%s] |^%d:0|") % element % radicalType).str();
+        } else {
+          smi = (boost::format("[%sH%d] |^%d:0|") % element % explicitHCount %
+                 radicalType)
+                    .str();
+        }
+        RWMol *m = SmilesToMol(smi);
+        TEST_ASSERT(
+            static_cast<int>(m->getAtomWithIdx(0)->getNumRadicalElectrons()) ==
+            valence - explicitHCount);
+      }
+    }
+  };
+
+  // Checks CXSMILES in the form of [XHn] |^m:0|
+  // where X is the element symbol,
+  // n = 0, ..., valence,
+  // m = 1, ..., 7 denotes the radical type
+  for (int atomicNum = 2; atomicNum <= 118; atomicNum++) {
+    const auto &defaultVs =
+        PeriodicTable::getTable()->getValenceList(atomicNum);
+    if (defaultVs.size() != 1) {
+      // Skips elements with multiple valences, e.g., transition metals
+      continue;
+    }
+    int valence = defaultVs[0];
+    std::string element =
+        PeriodicTable::getTable()->getElementSymbol(atomicNum);
+    testRadicalsForSingleAtom(element, valence);
+  }
+
+  // Checks CXSMILES in the form of [NH4+] |^m:0|
+  // where m = 1, ..., 7 denotes the radical type
+  for (int radicalType = 1; radicalType <= 7; radicalType++) {
+    std::string smi = (boost::format("[NH4+] |^%d:0|") % radicalType).str();
+    RWMol *m = SmilesToMol(smi);
+    TEST_ASSERT(
+        static_cast<int>(m->getAtomWithIdx(0)->getNumRadicalElectrons()) == 0);
+  }
+
+  BOOST_LOG(rdErrorLog) << "Finished" << std::endl;
+}
+
 // -------------------------------------------------------------------
 int main() {
   RDLog::InitLogs();
@@ -1695,6 +1749,7 @@ int main() {
   testRanges();
   testGithub1642();
   testGithub1843();
+  testGithub6370();
   testAtomListLineRoundTrip();
   testAtomListLineWithOtherQueries();
   testReplaceChargedAtomWithQueryAtom();


Set squiggle bonds to STEREOANY with stereo atoms (rdkit/rdkit#6877)

Fixes #6876

This allows squiggle bonds in mol blocks to be stereo enumerated.  If we round trip through CXSmiles, the bonds are stereo enumerable so this is intended behavior.

Wavy bonds in mol blocks can't be stereo enumerated

Test case.

If we round trip them through cx smiles, they can be stereo enumerated.

```
  SECTION("ensure we can enumerate stereo on either double bonds") {
    auto mol = R"CTAB(
  Mrv2004 11072316002D

  0  0  0     0  0            999 V3000
M  V30 BEGIN CTAB
M  V30 COUNTS 8 8 0 0 1
M  V30 BEGIN ATOM
M  V30 1 C 1.859 2.7821 0 0
M  V30 2 C 3.2818 2.1928 0 0
M  V30 3 C 3.8711 0.77 0 0
M  V30 4 C 3.2818 -0.6528 0 0
M  V30 5 C 1.859 -1.2421 0 0
M  V30 6 C 0.4362 -0.6528 0 0
M  V30 7 C -0.1533 0.77 0 0
M  V30 8 C 0.4362 2.1928 0 0
M  V30 END ATOM
M  V30 BEGIN BOND
M  V30 1 1 1 2
M  V30 2 1 2 3
M  V30 3 1 4 3 CFG=2
M  V30 4 2 4 5
M  V30 5 1 5 6
M  V30 6 1 6 7
M  V30 7 1 7 8
M  V30 8 1 1 8
M  V30 END BOND
M  V30 END CTAB
M  END)CTAB"_ctab;
      //mol->debugMol(std::cerr);
      std::string smi = MolToCXSmiles(*mol, SmilesWriteParams());
      std::cout << smi << std::endl;
      auto f = SmilesToMol(smi);
      f->getBondWithIdx(0)->setStereo(Bond::BondStereo::STEREOCIS);
      mol->getBondWithIdx(3)->setStereo(Bond::BondStereo::STEREOCIS);
      delete f;
  }
}
```

diff --git a/Code/GraphMol/Chirality.cpp b/Code/GraphMol/Chirality.cpp
index f748b413ca5..8bc03e8ba66 100644
--- a/Code/GraphMol/Chirality.cpp
+++ b/Code/GraphMol/Chirality.cpp
@@ -185,7 +185,7 @@ void updateDoubleBondNeighbors(ROMol &mol, Bond *dblBond, const Conformer *conf,
   // Don't do any direction setting if we've seen a squiggle bond, but do mark
   // the double bond as a crossed bond and return
   if (squiggleBondSeen) {
-    dblBond->setBondDir(Bond::EITHERDOUBLE);
+    Chirality::detail::setStereoanyFromSquiggleBond(mol, dblBond);
     return;
   }
   if (!bond1) {
@@ -200,7 +200,7 @@ void updateDoubleBondNeighbors(ROMol &mol, Bond *dblBond, const Conformer *conf,
   // Don't do any direction setting if we've seen a squiggle bond, but do mark
   // the double bond as a crossed bond and return
   if (squiggleBondSeen) {
-    dblBond->setBondDir(Bond::EITHERDOUBLE);
+      Chirality::detail::setStereoanyFromSquiggleBond(mol, dblBond);
     return;
   }
   if (!bond2) {
@@ -259,7 +259,7 @@ void updateDoubleBondNeighbors(ROMol &mol, Bond *dblBond, const Conformer *conf,
       }
     }
     if (linear) {
-      dblBond->setBondDir(Bond::EITHERDOUBLE);
+        Chirality::detail::setStereoanyFromSquiggleBond(mol, dblBond);
       return;
     }

@@ -919,6 +919,41 @@ bool has_protium_neighbor(const ROMol &mol, const Atom *atom) {
   return false;
 }

+void setStereoanyFromSquiggleBond(ROMol &mol, Bond *bond,
+				  Bond::BondStereo stereo) {
+    // NOTE:  moved from parse_doublebond_stereo CXSmilesOps
+    // the cis/trans/unknown marker is relative to the lowest numbered atom
+    // connected to the lowest numbered double bond atom and the
+    // highest-numbered atom connected to the highest-numbered double bond
+    // atom find those
+    auto begAtom = bond->getBeginAtom();
+    auto endAtom = bond->getEndAtom();
+    if (begAtom->getIdx() > endAtom->getIdx()) {
+        std::swap(begAtom, endAtom);
+    }
+    if (begAtom->getDegree() > 1 && endAtom->getDegree() > 1) {
+        unsigned int begControl = mol.getNumAtoms();
+        for (auto nbr : mol.atomNeighbors(begAtom)) {
+            if (nbr == endAtom) {
+                continue;
+            }
+            begControl = std::min(nbr->getIdx(), begControl);
+        }
+        unsigned int endControl = 0;
+        for (auto nbr : mol.atomNeighbors(endAtom)) {
+            if (nbr == begAtom) {
+                continue;
+            }
+            endControl = std::max(nbr->getIdx(), endControl);
+        }
+        if (begAtom != bond->getBeginAtom()) {
+            std::swap(begControl, endControl);
+        }
+        bond->setStereoAtoms(begControl, endControl);
+        bond->setStereo(stereo);
+        mol.setProp("_needsDetectBondStereo", 1);
+    }
+}
 }  // namespace detail

 typedef std::pair<int, int> INT_PAIR;
diff --git a/Code/GraphMol/Chirality.h b/Code/GraphMol/Chirality.h
index ebf92c972e2..8aa2e4d02f1 100644
--- a/Code/GraphMol/Chirality.h
+++ b/Code/GraphMol/Chirality.h
@@ -234,6 +234,8 @@ RDKIT_GRAPHMOL_EXPORT int pickBondToWedge(const Atom *atom, const ROMol &mol,
                                           const INT_VECT &nChiralNbrs,
                                           const INT_MAP_INT &resSoFar,
                                           int noNbrs);
+RDKIT_GRAPHMOL_EXPORT void setStereoanyFromSquiggleBond(ROMol &mol, Bond *bond,
+							Bond::BondStereo stereo=Bond::STEREOANY);
 }  // namespace detail

 //! picks the bonds which should be wedged
diff --git a/Code/GraphMol/SmilesParse/CXSmilesOps.cpp b/Code/GraphMol/SmilesParse/CXSmilesOps.cpp
index b434826e68d..27548e01230 100644
--- a/Code/GraphMol/SmilesParse/CXSmilesOps.cpp
+++ b/Code/GraphMol/SmilesParse/CXSmilesOps.cpp
@@ -1147,37 +1147,7 @@ bool parse_doublebond_stereo(Iterator &first, Iterator last, RDKit::RWMol &mol,
         return false;
       }

-      // the cis/trans/unknown marker is relative to the lowest numbered atom
-      // connected to the lowest numbered double bond atom and the
-      // highest-numbered atom connected to the highest-numbered double bond
-      // atom find those
-      auto begAtom = bond->getBeginAtom();
-      auto endAtom = bond->getEndAtom();
-      if (begAtom->getIdx() > endAtom->getIdx()) {
-        std::swap(begAtom, endAtom);
-      }
-      if (begAtom->getDegree() > 1 && endAtom->getDegree() > 1) {
-        unsigned int begControl = mol.getNumAtoms();
-        for (auto nbr : mol.atomNeighbors(begAtom)) {
-          if (nbr == endAtom) {
-            continue;
-          }
-          begControl = std::min(nbr->getIdx(), begControl);
-        }
-        unsigned int endControl = 0;
-        for (auto nbr : mol.atomNeighbors(endAtom)) {
-          if (nbr == begAtom) {
-            continue;
-          }
-          endControl = std::max(nbr->getIdx(), endControl);
-        }
-        if (begAtom != bond->getBeginAtom()) {
-          std::swap(begControl, endControl);
-        }
-        bond->setStereoAtoms(begControl, endControl);
-        bond->setStereo(stereo);
-        mol.setProp(SmilesParseOps::detail::_needsDetectBondStereo, 1);
-      }
+      Chirality::detail::setStereoanyFromSquiggleBond(mol, bond, stereo);
     }
     if (first < last && *first == ',') {
       ++first;
diff --git a/Code/GraphMol/catch_chirality.cpp b/Code/GraphMol/catch_chirality.cpp
index c3d5c2f5849..2ae73537461 100644
--- a/Code/GraphMol/catch_chirality.cpp
+++ b/Code/GraphMol/catch_chirality.cpp
@@ -3799,8 +3799,49 @@ TEST_CASE(
       CHECK(cp.getBondWithIdx(1)->getStereoAtoms().empty());
     }
   }
-}
+  SECTION("ensure we can enumerate stereo on either double bonds") {
+    auto mol = R"CTAB(
+  Mrv2004 11072316002D

+  0  0  0     0  0            999 V3000
+M  V30 BEGIN CTAB
+M  V30 COUNTS 8 8 0 0 1
+M  V30 BEGIN ATOM
+M  V30 1 C 1.859 2.7821 0 0
+M  V30 2 C 3.2818 2.1928 0 0
+M  V30 3 C 3.8711 0.77 0 0
+M  V30 4 C 3.2818 -0.6528 0 0
+M  V30 5 C 1.859 -1.2421 0 0
+M  V30 6 C 0.4362 -0.6528 0 0
+M  V30 7 C -0.1533 0.77 0 0
+M  V30 8 C 0.4362 2.1928 0 0
+M  V30 END ATOM
+M  V30 BEGIN BOND
+M  V30 1 1 1 2
+M  V30 2 1 2 3
+M  V30 3 1 4 3 CFG=2
+M  V30 4 2 4 5
+M  V30 5 1 5 6
+M  V30 6 1 6 7
+M  V30 7 1 7 8
+M  V30 8 1 1 8
+M  V30 END BOND
+M  V30 END CTAB
+M  END)CTAB"_ctab;
+      //mol->debugMol(std::cerr);
+      std::string smi = MolToCXSmiles(*mol, SmilesWriteParams());
+      std::unique_ptr<ROMol> f(SmilesToMol(smi));
+      mol->getBondWithIdx(3)->setStereo(Bond::BondStereo::STEREOCIS);
+      f->getBondWithIdx(0)->setStereo(Bond::BondStereo::STEREOCIS);
+      CHECK(MolToSmiles(*mol) == "C1=C\\CCCCCC/1");
+      CHECK(MolToSmiles(*f) == "C1=C\\CCCCCC/1");
+      mol->getBondWithIdx(3)->setStereo(Bond::BondStereo::STEREOTRANS);
+      f->getBondWithIdx(0)->setStereo(Bond::BondStereo::STEREOTRANS);
+      CHECK(MolToSmiles(*mol) == "C1=C/CCCCCC/1");
+      CHECK(MolToSmiles(*f) == "C1=C/CCCCCC/1");
+  }
+
+}
 TEST_CASE("adding two wedges to chiral centers") {
   SECTION("basics") {
     auto mol = R"CTAB(

diff --git a/Code/GraphMol/FileParsers/test1.cpp b/Code/GraphMol/FileParsers/test1.cpp
index 7550487ba06..30fda253451 100644
--- a/Code/GraphMol/FileParsers/test1.cpp
+++ b/Code/GraphMol/FileParsers/test1.cpp
@@ -4769,10 +4769,11 @@ void testGithub1034() {
         explicit_unknown_stereo)

     TEST_ASSERT(m->getBondWithIdx(0)->getBondType() == Bond::DOUBLE);
-    TEST_ASSERT(m->getBondWithIdx(0)->getStereo() == Bond::STEREONONE);
+    TEST_ASSERT(m->getBondWithIdx(0)->getStereo() == Bond::STEREOANY);  // now set in detectStereochemistry
+    ROMol(*m).getBondWithIdx(0)->setStereo(Bond::STEREOCIS); // ensure we have stereo atoms
     MolOps::sanitizeMol(*m);
     TEST_ASSERT(m->getBondWithIdx(0)->getBondType() == Bond::DOUBLE);
-    TEST_ASSERT(m->getBondWithIdx(0)->getStereo() == Bond::STEREONONE);
+    TEST_ASSERT(m->getBondWithIdx(0)->getStereo() == Bond::STEREOANY);
     TEST_ASSERT(m->getBondWithIdx(1)->getBondType() == Bond::SINGLE);
     TEST_ASSERT(m->getBondWithIdx(1)->getBondDir() == Bond::NONE);
     TEST_ASSERT(m->getBondWithIdx(2)->getBondType() == Bond::SINGLE);


Fixes #5819 (rdkit/rdkit#6897)

This adds SMARTSQ DAT SGroups to the output for atoms which have queries.

It does not do the standard `AtomType` query, so converting the SMARTS `CC` into CTAB and back will give `[#6][#6]` as an output SMARTS. This isn't nice, but otherwise CTABs are going to end up having SMARTSQ queries on almost all atoms constructed from SMARTS, and that's potentially even worse. Something to discuss...

The example from the test starts with the SMARTS `[C,N,O]C[#6]*[$(C(=O)O)]` and produces this CTAB:
```

     RDKit          2D

  0  0  0  0  0  0  0  0  0  0999 V3000
M  V30 BEGIN CTAB
M  V30 COUNTS 5 4 1 0 0
M  V30 BEGIN ATOM
M  V30 1 [C,N,O] 0.000000 0.000000 0.000000 0
M  V30 2 C 1.299038 0.750000 0.000000 0
M  V30 3 C 2.598076 -0.000000 0.000000 0
M  V30 4 * 3.897114 0.750000 0.000000 0
M  V30 5 * 5.196152 -0.000000 0.000000 0
M  V30 END ATOM
M  V30 BEGIN BOND
M  V30 1 6 1 2
M  V30 2 6 2 3
M  V30 3 6 3 4
M  V30 4 6 4 5
M  V30 END BOND
M  V30 BEGIN SGROUP
M  V30 1 DAT 0 ATOMS=(1 5) QUERYTYPE=SMARTSQ QUERYOP== -
M  V30 FIELDDATA="[$(C(=O)O)]"
M  V30 END SGROUP
M  V30 END CTAB
M  END
```

Some discussion of this in #5718  and #5825, but the idea is to allow atom-based SMARTS queries to be serialized into v3000 mol blocks via substance groups. The trick is going to be figuring out which queries get serialized this way.

Implement this using a new CTABWritingParams (or some such name) class.

diff --git a/Code/GraphMol/ChemReactions/ReactionWriter.cpp b/Code/GraphMol/ChemReactions/ReactionWriter.cpp
index 9e150487fde..21317021cb4 100644
--- a/Code/GraphMol/ChemReactions/ReactionWriter.cpp
+++ b/Code/GraphMol/ChemReactions/ReactionWriter.cpp
@@ -103,14 +103,18 @@ std::string chemicalReactionToRxnToString(const RDKit::ChemicalReaction &rxn,
 }

 void write_template(std::ostringstream &res, RDKit::ROMol &tpl) {
-  if (tpl.needsUpdatePropertyCache()) {
-    tpl.updatePropertyCache(false);
+  RDKit::RWMol trwmol(tpl);
+
+  if (trwmol.needsUpdatePropertyCache()) {
+    trwmol.updatePropertyCache(false);
   }
   // to write the mol block, we need ring information:
-  if (!tpl.getRingInfo()->isInitialized()) {
-    RDKit::MolOps::findSSSR(tpl);
+  if (!trwmol.getRingInfo()->isInitialized()) {
+    RDKit::MolOps::findSSSR(trwmol);
   }
-  res << RDKit::FileParserUtils::getV3000CTAB(tpl, -1);
+  RDKit::FileParserUtils::moveAdditionalPropertiesToSGroups(trwmol);
+
+  res << RDKit::FileParserUtils::getV3000CTAB(trwmol, -1);
 }

 }  // namespace
diff --git a/Code/GraphMol/FileParsers/FileParserUtils.h b/Code/GraphMol/FileParsers/FileParserUtils.h
index dd19dcadd8d..529089741a8 100644
--- a/Code/GraphMol/FileParsers/FileParserUtils.h
+++ b/Code/GraphMol/FileParsers/FileParserUtils.h
@@ -250,6 +250,8 @@ inline void createAtomStringPropertyList(
                                                missingValueMarker, lineSize));
 }

+RDKIT_FILEPARSERS_EXPORT void moveAdditionalPropertiesToSGroups(RWMol &mol);
+
 }  // namespace FileParserUtils
 }  // namespace RDKit

diff --git a/Code/GraphMol/FileParsers/MolFileParser.cpp b/Code/GraphMol/FileParsers/MolFileParser.cpp
index c55662c87a6..748746d69b4 100644
--- a/Code/GraphMol/FileParsers/MolFileParser.cpp
+++ b/Code/GraphMol/FileParsers/MolFileParser.cpp
@@ -1548,7 +1548,6 @@ Atom *ParseMolFileAtomLine(const std::string_view text, RDGeom::Point3D &pos,
           << " has a negative isotope offset. line:  " << line << std::endl;
     }
     res->setIsotope(dIso);
-    res->setProp(common_properties::_hasMassQuery, true);
   }

   if (text.size() >= 42 && text.substr(39, 3) != "  0") {
diff --git a/Code/GraphMol/FileParsers/MolFileWriter.cpp b/Code/GraphMol/FileParsers/MolFileWriter.cpp
index c0d29d80d47..579e8236324 100644
--- a/Code/GraphMol/FileParsers/MolFileWriter.cpp
+++ b/Code/GraphMol/FileParsers/MolFileWriter.cpp
@@ -1,5 +1,5 @@
 //
-//  Copyright (C) 2003-2021 Greg Landrum and other RDKit contributors
+//  Copyright (C) 2003-2023 Greg Landrum and other RDKit contributors
 //
 //   @@ All Rights Reserved @@
 //  This file is part of the RDKit.
@@ -1037,28 +1037,55 @@ int BondStereoCodeV2000ToV3000(int dirCode) {

 namespace {
 void createSMARTSQSubstanceGroups(ROMol &mol) {
+  auto isRedundantQuery = [](const auto query) {
+    if (query->getDescription() == "AtomAnd" &&
+        (query->endChildren() - query->beginChildren() == 2) &&
+        (*query->beginChildren())->getDescription() == "AtomAtomicNum" &&
+        !(*query->beginChildren())->getNegation() &&
+        !(*(query->beginChildren() + 1))->getNegation() &&
+        ((*(query->beginChildren() + 1))->getDescription() == "AtomIsotope" ||
+         (*(query->beginChildren() + 1))->getDescription() ==
+             "AtomFormalCharge")) {
+      return true;
+    }
+    return false;
+  };
   for (const auto atom : mol.atoms()) {
-    std::string sma;
-    if (atom->hasQuery() &&
-        atom->getPropIfPresent(common_properties::MRV_SMA, sma) &&
-        !sma.empty()) {
-      SubstanceGroup sg(&mol, "DAT");
-      sg.setProp("QUERYTYPE", "SMARTSQ");
-      sg.setProp("QUERYOP", "=");
-      std::vector<std::string> dataFields{sma};
-      sg.setProp("DATAFIELDS", dataFields);
-      sg.addAtomWithIdx(atom->getIdx());
-      addSubstanceGroup(mol, sg);
+    if (atom->hasQuery()) {
+      std::string sma;
+
+      if (!atom->getPropIfPresent(common_properties::MRV_SMA, sma) &&
+          !isAtomListQuery(atom) &&
+          atom->getQuery()->getDescription() != "AtomNull" &&
+          // we may want to re-think this next one.
+          // including AtomType queries will result in an entry
+          // for every atom that comes from SMARTS, and I don't think
+          // we want that.
+          !boost::starts_with(atom->getQuery()->getDescription(), "AtomType") &&
+          !boost::starts_with(atom->getQuery()->getDescription(),
+                              "AtomAtomicNum") &&
+          !isRedundantQuery(atom->getQuery())) {
+        sma = SmartsWrite::GetAtomSmarts(static_cast<const QueryAtom *>(atom));
+      }
+      if (!sma.empty()) {
+        SubstanceGroup sg(&mol, "DAT");
+        sg.setProp("QUERYTYPE", "SMARTSQ");
+        sg.setProp("QUERYOP", "=");
+        std::vector<std::string> dataFields{sma};
+        sg.setProp("DATAFIELDS", dataFields);
+        sg.addAtomWithIdx(atom->getIdx());
+        addSubstanceGroup(mol, sg);
+      }
     }
   }
 }
 }  // namespace
-
+namespace FileParserUtils {
 void moveAdditionalPropertiesToSGroups(RWMol &mol) {
   GenericGroups::convertGenericQueriesToSubstanceGroups(mol);
   createSMARTSQSubstanceGroups(mol);
 }
-
+}  // namespace FileParserUtils
 const std::string GetV3000MolFileBondLine(const Bond *bond,
                                           const INT_MAP_INT &wedgeBonds,
                                           const Conformer *conf) {
@@ -1374,7 +1401,7 @@ std::string MolToMolBlock(const ROMol &mol, bool includeStereo, int confId,
       MolOps::assignStereochemistry(trwmol);
     }
 #endif
-  moveAdditionalPropertiesToSGroups(trwmol);
+  FileParserUtils::moveAdditionalPropertiesToSGroups(trwmol);

   try {
     return outputMolToMolBlock(trwmol, confId, forceV3000);
diff --git a/Code/GraphMol/FileParsers/file_parsers_catch.cpp b/Code/GraphMol/FileParsers/file_parsers_catch.cpp
index 0f4e441406a..b46fe9e4649 100644
--- a/Code/GraphMol/FileParsers/file_parsers_catch.cpp
+++ b/Code/GraphMol/FileParsers/file_parsers_catch.cpp
@@ -6804,4 +6804,27 @@ TEST_CASE(
   REQUIRE(bond2->getBondType() == Bond::DOUBLE);
   CHECK(bond2->getStereo() == Bond::BondStereo::STEREONONE);
   CHECK(bond2->getBondDir() == Bond::BondDir::NONE);
+}
+
+TEST_CASE(
+    "github #5819: Support writing detailed SMARTS queries to CTABs using the SMARTSQ mechanism") {
+  SECTION("as reported") {
+    auto m = "[C,N,O]C[#6]*[$(C(=O)O)]"_smarts;
+    REQUIRE(m);
+    auto ctab = MolToV3KMolBlock(*m);
+    // std::cerr << ctab << std::endl;
+    // make sure we still do list queries correctly
+    CHECK(ctab.find("V30 1 [C,N,O]") != std::string::npos);
+    CHECK(ctab.find("FIELDDATA=\"[C,N,O]") == std::string::npos);
+    CHECK(ctab.find("FIELDDATA=\"C\"") == std::string::npos);
+    CHECK(ctab.find("FIELDDATA=\"[#6]\"") == std::string::npos);
+    CHECK(ctab.find("FIELDDATA=\"*\"") == std::string::npos);
+    CHECK(ctab.find("SMARTSQ") != std::string::npos);
+    CHECK(ctab.find("[$(C(=O)O)]") != std::string::npos);
+
+    // make sure we can properly parse that
+    std::unique_ptr<RWMol> nm{MolBlockToMol(ctab)};
+    REQUIRE(nm);
+    CHECK(MolToSmarts(*nm) == "[#6,#7,#8][#6][#6]*[$(C(=O)O)]");
+  }
 }
\ No newline at end of file
diff --git a/Code/GraphMol/MarvinParse/MarvinParser.cpp b/Code/GraphMol/MarvinParse/MarvinParser.cpp
index f5eb1f2ccc0..ead8127f03d 100644
--- a/Code/GraphMol/MarvinParse/MarvinParser.cpp
+++ b/Code/GraphMol/MarvinParse/MarvinParser.cpp
@@ -192,7 +192,6 @@ class MarvinCMLReader {

       if (marvinAtom->isotope != 0) {
         res->setIsotope(marvinAtom->isotope);
-        res->setProp(common_properties::_hasMassQuery, true);
       }

       // mrvValence and hydrogenCount both set the number of explicit hydrogens

diff --git a/Code/GraphMol/ChemReactions/catch_tests.cpp b/Code/GraphMol/ChemReactions/catch_tests.cpp
index 38f22642d6a..c7809c5f277 100644
--- a/Code/GraphMol/ChemReactions/catch_tests.cpp
+++ b/Code/GraphMol/ChemReactions/catch_tests.cpp
@@ -1584,4 +1584,75 @@ TEST_CASE("problematic in-place example from MolStandardize") {
     rxn->runReactant(*m);
     CHECK(MolToSmiles(*m)=="CN(C)c1cc[nH+]cc1");
   }
+}
+
+TEST_CASE(
+    "github #5819: Support writing detailed SMARTS queries to CTABs using the SMARTSQ mechanism") {
+  SECTION("as reported") {
+    auto rxn = "[C;$(C([#6])=O):1][OH:2]>>[C:1][NH2:2]"_rxnsmarts;
+    REQUIRE(rxn);
+    auto ctab = ChemicalReactionToV3KRxnBlock(*rxn);
+
+    // make sure the templates haven't been modified by that operation
+    CHECK(getSubstanceGroups(*rxn->getReactants()[0]).empty());
+
+    CHECK(ctab.find("SMARTSQ") != std::string::npos);
+    CHECK(ctab.find("FIELDDATA=\"[C&$(C([#6])=O):1]\"") != std::string::npos);
+    CHECK(ctab.find("FIELDDATA=\"[N&H2:2]\"") != std::string::npos);
+
+    // make sure we can properly parse that
+    std::unique_ptr<ChemicalReaction> nrxn{RxnBlockToChemicalReaction(ctab)};
+    REQUIRE(nrxn);
+    CHECK(MolToSmarts(*nrxn->getReactants()[0]) == "[C&$(C([#6])=O):1][O&H1:2]");
+  }
+
+
+SECTION("isotopes are weird"){
+  auto rxnb = R"CTAB($RXN V3000
+
+      Mrv2211  111620231722
+
+M  V30 COUNTS 1 1
+M  V30 BEGIN REACTANT
+M  V30 BEGIN CTAB
+M  V30 COUNTS 4 3 0 0 0
+M  V30 BEGIN ATOM
+M  V30 1 C 6.9035 -10.0923 0 1
+M  V30 2 O 6.9035 -8.5923 0 2 MASS=18
+M  V30 3 Cl 5.6045 -10.8423 0 0
+M  V30 4 C 8.2025 -10.8423 0 4
+M  V30 END ATOM
+M  V30 BEGIN BOND
+M  V30 1 1 1 4
+M  V30 2 2 1 2
+M  V30 3 1 1 3
+M  V30 END BOND
+M  V30 END CTAB
+M  V30 END REACTANT
+M  V30 BEGIN PRODUCT
+M  V30 BEGIN CTAB
+M  V30 COUNTS 4 3 0 0 0
+M  V30 BEGIN ATOM
+M  V30 1 C 22.0416 -9.3829 0 0
+M  V30 2 C 23.3406 -8.6329 0 1
+M  V30 3 O 23.3406 -7.1329 0 2 MASS=18
+M  V30 4 C 24.6396 -9.3829 0 4
+M  V30 END ATOM
+M  V30 BEGIN BOND
+M  V30 1 1 1 2
+M  V30 2 1 2 4
+M  V30 3 2 2 3
+M  V30 END BOND
+M  V30 END CTAB
+M  V30 END PRODUCT
+M  END
+)CTAB";
+  std::unique_ptr<ChemicalReaction> rxn{RxnBlockToChemicalReaction(rxnb)};
+  REQUIRE(rxn);
+  CHECK(rxn->getReactants()[0]->getAtomWithIdx(0)->hasQuery());
+  CHECK(rxn->getReactants()[0]->getAtomWithIdx(1)->hasQuery());
+  auto ctab = ChemicalReactionToV3KRxnBlock(*rxn);
+  CHECK(ctab.find("SMARTSQ") == std::string::npos);
+
+}
 }
\ No newline at end of file


Removing stereoatoms requires removing CIS/Trans stereo flags (rdkit/rdkit#6901)

Fixes #6900

When we remove stereo atoms from a cis/trans bond we should also remove the CIS/TRANS stereo flags since they require stereo atoms for canonicalization.

This might not be the correct fix for this particular problem since we should want:

"C/C=C/N" to fragment with the  into "*/C=C/N" not
"*C=CN"

However, because we removethe first bond which affects the stereo atoms in the double bond, this causes the errors down stream.

The correct fix is probably to have a custom removeBond that detects this and handles it correctly by adding the new dummy atoms to the stereo bond.

However this fix preserves the current behavior:

```
mol = MolFromSmiles("N/C=C/C")
frag1 = rdMMPA.FragmentMol(mol)

for a,b in frag1:
    if a: print(Chem.MolToSmiles(a),end=", ")
    else: print(a,end=", " )
    print(Chem.MolToSmiles(b))
```

results in

```
None, CC=C[*:1].N[*:1]
C(=C[*:2])[*:1], C[*:1].N[*:2]
None, C[*:1].NC=C[*:1]
```

MMPA FragmentMol segfaults when new stereo perception is turned on

For this molecule, the MMPA fragmentation runs fine when legacy stereo perception is used but crashes otherwise

```
>>> from rdkit.Chem import MolFromSmiles
>>> from rdkit.Chem import rdMMPA
>>> from rdkit.Chem import rdmolops
>>> rdmolops.SetUseLegacyStereoPerception(False)
>>> mol = MolFromSmiles("CN1CCCN=C1/C=C/c1cccs1")
>>> frag1 = rdMMPA.FragmentMol(mol)
zsh: segmentation fault  python

```

diff --git a/Code/GraphMol/RWMol.cpp b/Code/GraphMol/RWMol.cpp
index e92e6cc5ead..d102bacaf15 100644
--- a/Code/GraphMol/RWMol.cpp
+++ b/Code/GraphMol/RWMol.cpp
@@ -468,6 +468,12 @@ void RWMol::removeBond(unsigned int aid1, unsigned int aid2) {
     }
     if (std::find(obnd->getStereoAtoms().begin(), obnd->getStereoAtoms().end(),
                   aid2) != obnd->getStereoAtoms().end()) {
+      // github #6900 if we remove stereo atoms we need to remove
+      //  the CIS and or TRANS since this requires stereo atoms
+      if (obnd->getStereo() == Bond::BondStereo::STEREOCIS ||
+          obnd->getStereo() == Bond::BondStereo::STEREOTRANS ) {
+          obnd->setStereo(Bond::BondStereo::STEREONONE);
+      }
       obnd->getStereoAtoms().clear();
     }
   }
@@ -484,6 +490,12 @@ void RWMol::removeBond(unsigned int aid1, unsigned int aid2) {
     }
     if (std::find(obnd->getStereoAtoms().begin(), obnd->getStereoAtoms().end(),
                   aid1) != obnd->getStereoAtoms().end()) {
+      // github #6900 if we remove stereo atoms we need to remove
+      //  the CIS and or TRANS since this requires stereo atoms
+      if (obnd->getStereo() == Bond::BondStereo::STEREOCIS ||
+        obnd->getStereo() == Bond::BondStereo::STEREOTRANS ) {
+        obnd->setStereo(Bond::BondStereo::STEREONONE);
+      }
       obnd->getStereoAtoms().clear();
     }
   }
diff --git a/Code/GraphMol/catch_chirality.cpp b/Code/GraphMol/catch_chirality.cpp
index c3d5c2f5849..f449aaf03de 100644
--- a/Code/GraphMol/catch_chirality.cpp
+++ b/Code/GraphMol/catch_chirality.cpp
@@ -1297,6 +1297,26 @@ TEST_CASE("ring stereo finding is overly aggressive", "[chirality][bug]") {
         Chirality::findPotentialStereo(*mol, cleanIt, flagPossible);
     CHECK(stereoInfo.size() == 2);
   }
+  SECTION("Removal of stereoatoms requires removing CIS/TRANS when using legacy stereo") {
+      UseLegacyStereoPerceptionFixture reset_stereo_perception;
+      Chirality::setUseLegacyStereoPerception(false);
+
+    {
+      auto mol = "N/C=C/C"_smiles;
+      CHECK(mol->getBondWithIdx(1)->getStereo() == Bond::BondStereo::STEREOTRANS);
+      auto rwmol = dynamic_cast<RWMol*>(mol.get());
+      rwmol->removeBond(0,1);
+      CHECK(mol->getBondWithIdx(0)->getStereo() == Bond::BondStereo::STEREONONE);
+    }
+    {
+      auto mol = "N/C=C/C"_smiles;
+      CHECK(mol->getBondWithIdx(1)->getStereo() == Bond::BondStereo::STEREOTRANS);
+      auto rwmol = dynamic_cast<RWMol*>(mol.get());
+      rwmol->removeBond(2,3);
+      CHECK(mol->getBondWithIdx(1)->getStereo() == Bond::BondStereo::STEREONONE);
+    }
+
+  }
 }

 TEST_CASE(

diff --git a/Code/GraphMol/MMPA/MMPA_UnitTest.cpp b/Code/GraphMol/MMPA/MMPA_UnitTest.cpp
index 962d2558e49..a82c1700704 100644
--- a/Code/GraphMol/MMPA/MMPA_UnitTest.cpp
+++ b/Code/GraphMol/MMPA/MMPA_UnitTest.cpp
@@ -49,6 +49,7 @@
 #include <iostream>
 #include <RDGeneral/RDLog.h>
 #include <RDGeneral/utils.h>
+#include <GraphMol/Chirality.h>
 #include "../RDKitBase.h"
 #include "../FileParsers/FileParsers.h"  //MOL single molecule !
 #include "../FileParsers/MolSupplier.h"  //SDF
@@ -690,6 +691,14 @@ std::endl;
 //====================================================================================================
 //====================================================================================================

+void testGithub6900 () {
+  RDKit::Chirality::setUseLegacyStereoPerception(false);
+  //auto mol = "CN1CCCN=C1/C=C/c1cccs1"_smiles;
+  auto mol = "N/C=C/C"_smiles;
+  std::vector<std::pair<ROMOL_SPTR, ROMOL_SPTR>> res;
+  RDKit::MMPA::fragmentMol(*mol, res, 3);
+  RDKit::Chirality::setUseLegacyStereoPerception(true);
+}
 int main() {
   BOOST_LOG(rdInfoLog)
       << "*******************************************************\n";
@@ -703,7 +712,7 @@ int main() {
 #else
   setpriority(PRIO_PROCESS, getpid(), -20);
 #endif
-
+  testGithub6900();
   T0 = nanoClock();
   t0 = nanoClock();

@@ -711,6 +720,7 @@ int main() {
   // /*
   test2();
   test3();
+
   //    test4();
   // */
   //    debugTest1("C[*:1].O=C(NCCO)c1c([*:1])n([O-])c2ccccc2[n+]1=O");


Fixes #7367 (rdkit/rdkit#7426)

Fixes #7367

The cause of the issue is simply that we don't consider the `Chem.CXSmilesFields.CX_BOND_ATROPISOMER` SMILES extension when computing the registration hash. Fixing the issue is as simple as adding it to the flags we use.

While working on this, I noticed that `wedgeBondsFromAtropisomers()` is missing a check for ring info, since both `WedgeBondFromAtropisomerOneBond2d()` and `WedgeBondFromAtropisomerOneBond3d` require ring info and call `minBondRingSize()`.

RegistrationHash.GetMolLayers does not distinguish atropisomers

The registration hash should be able to distinguish between atropisomers, but that's currently not the case:

```python3
In [1]: from rdkit import Chem

In [2]: from rdkit.Chem import RegistrationHash

# This is one of the examples from the initial atropisomers PR
In [3]: m = Chem.MolFromMolFile('RP-6306_atrop1.sdf')

In [4]: b = m.GetBondWithIdx(3)

# The atropisomer was correctly identified
In [5]: b.GetStereo()
Out[5]: rdkit.Chem.rdchem.BondStereo.STEREOATROPCW

In [6]: hash1 = RegistrationHash.GetMolLayers(m, enable_tautomer_hash_v2=True)

# No atropisomer info in the hash: for SMILES, it's encoded in the CX extension, which is not part of the hash
In [7]: print(hash1)
{
<HashLayer.CANONICAL_SMILES: 1>: 'Cc1cc2c(C(N)=O)c(N)n(-c3c(C)ccc(O)c3C)c2nc1C',
<HashLayer.ESCAPE: 2>: '',
<HashLayer.FORMULA: 3>: 'C18H20N4O2',
<HashLayer.NO_STEREO_SMILES: 4>: 'Cc1cc2c(C(N)=O)c(N)n(-c3c(C)ccc(O)c3C)c2nc1C',
<HashLayer.NO_STEREO_TAUTOMER_HASH: 5>: '[C]:[C]1:[N]:[C]2:[C](:[C]:[C]:1-[CH3]):[C](:[C](:[N]):[O]):[C](:[N]):[N]:2:[C]1:[C](-[CH3]):[C]:[C]:[C](:[O]):[C]:1-[CH3]_11_0',
<HashLayer.SGROUP_DATA: 6>: '[]',
<HashLayer.TAUTOMER_HASH: 7>: '[C]:[C]1:[N]:[C]2:[C](:[C]:[C]:1-[CH3]):[C](:[C](:[N]):[O]):[C](:[N]):[N]:2:[C]1:[C](-[CH3]):[C]:[C]:[C](:[O]):[C]:1-[CH3]_11_0'
}

# Now, reverse the atropisomer
In [8]: b.SetStereo(Chem.BondStereo.STEREOATROPCCW)

In [9]: hash2 = RegistrationHash.GetMolLayers(m, enable_tautomer_hash_v2=True)

# No atropisomer info either
In [10]: print(hash2)
{
<HashLayer.CANONICAL_SMILES: 1>: 'Cc1cc2c(C(N)=O)c(N)n(-c3c(C)ccc(O)c3C)c2nc1C',
<HashLayer.ESCAPE: 2>: '',
<HashLayer.FORMULA: 3>: 'C18H20N4O2',
<HashLayer.NO_STEREO_SMILES: 4>: 'Cc1cc2c(C(N)=O)c(N)n(-c3c(C)ccc(O)c3C)c2nc1C',
<HashLayer.NO_STEREO_TAUTOMER_HASH: 5>: '[C]:[C]1:[N]:[C]2:[C](:[C]:[C]:1-[CH3]):[C](:[C](:[N]):[O]):[C](:[N]):[N]:2:[C]1:[C](-[CH3]):[C]:[C]:[C](:[O]):[C]:1-[CH3]_11_0',
<HashLayer.SGROUP_DATA: 6>: '[]',
<HashLayer.TAUTOMER_HASH: 7>: '[C]:[C]1:[N]:[C]2:[C](:[C]:[C]:1-[CH3]):[C](:[C](:[N]):[O]):[C](:[N]):[N]:2:[C]1:[C](-[CH3]):[C]:[C]:[C](:[O]):[C]:1-[CH3]_11_0'
}

# We'd want these to be different to deduplicate the atropisomers, but ...
In [11]: hash1 != hash2
Out[11]: False
```

diff --git a/Code/GraphMol/Atropisomers.cpp b/Code/GraphMol/Atropisomers.cpp
index 1ea48d7b588..e82f86bffd4 100644
--- a/Code/GraphMol/Atropisomers.cpp
+++ b/Code/GraphMol/Atropisomers.cpp
@@ -1166,6 +1166,12 @@ void wedgeBondsFromAtropisomers(
         &wedgeBonds) {
   PRECONDITION(conf == nullptr || &(conf->getOwningMol()) == &mol,
                "conformer does not belong to molecule");
+
+  // WedgeBondFromAtropisomerOneBond 2d/3d requires ring bond counts
+  if (!mol.getRingInfo()->isSssrOrBetter()) {
+    RDKit::MolOps::findSSSR(mol);
+  }
+
   for (auto bond : mol.bonds()) {
     auto bondStereo = bond->getStereo();

diff --git a/rdkit/Chem/RegistrationHash.py b/rdkit/Chem/RegistrationHash.py
index 23c483d9eb4..0d70cc8e71b 100644
--- a/rdkit/Chem/RegistrationHash.py
+++ b/rdkit/Chem/RegistrationHash.py
@@ -35,7 +35,8 @@

 logger = logging.getLogger(__name__)

-DEFAULT_CXFLAG = Chem.CXSmilesFields.CX_ATOM_LABELS | Chem.CXSmilesFields.CX_ENHANCEDSTEREO
+DEFAULT_CXFLAG = (Chem.CXSmilesFields.CX_ATOM_LABELS | Chem.CXSmilesFields.CX_ENHANCEDSTEREO
+                  | Chem.CXSmilesFields.CX_BOND_ATROPISOMER)

 ENHANCED_STEREO_GROUP_REGEX = re.compile(r'((?:a|[&o]\d+):\d+(?:,\d+)*)')

diff --git a/Code/GraphMol/SmilesParse/catch_tests.cpp b/Code/GraphMol/SmilesParse/catch_tests.cpp
index 7495ecb61da..9a74f6b1562 100644
--- a/Code/GraphMol/SmilesParse/catch_tests.cpp
+++ b/Code/GraphMol/SmilesParse/catch_tests.cpp
@@ -2801,9 +2801,34 @@ TEST_CASE("Github #7295") {
     auto smi2 = MolToSmiles(*m);
     CHECK(smi1 == smi2);
     auto m2(*m);
-    bool cleanIt=true;
+    bool cleanIt = true;
     MolOps::assignStereochemistry(m2, cleanIt);
     auto smi3 = MolToSmiles(m2);
     CHECK(smi1 == smi3);
   }
-}
\ No newline at end of file
+}
+
+TEST_CASE("CX_BOND_ATROPISOMER option requires ring info", "[bug][cxsmiles]") {
+  std::string rdbase = getenv("RDBASE");
+  std::string fName =
+      rdbase +
+      "/Code/GraphMol/FileParsers/test_data/atropisomers/RP-6306_atrop1.sdf";
+
+  auto m = v2::FileParsers::MolFromMolFile(fName);
+  REQUIRE(m);
+
+  auto atropBond = m->getBondWithIdx(3);
+  REQUIRE(atropBond->getStereo() == Bond::STEREOATROPCW);
+
+  // Clear ring info to check that atropisomer wedging doesn't fail
+  // if the info is not present
+  bool includeRingInfo = true;
+  m->clearComputedProps(includeRingInfo);
+
+  auto ps = SmilesWriteParams();
+  auto flags = SmilesWrite::CXSmilesFields::CX_BOND_ATROPISOMER;
+
+  // This will fail if there's no ring information
+  auto smi = MolToCXSmiles(*m, ps, flags);
+  CHECK(smi == "Cc1cc2c(C(N)=O)c(N)n(-c3c(C)ccc(O)c3C)c2nc1C |wD:10.9|");
+}
diff --git a/rdkit/Chem/UnitTestRegistrationHash.py b/rdkit/Chem/UnitTestRegistrationHash.py
index 152b7b68f11..de9c13eb394 100644
--- a/rdkit/Chem/UnitTestRegistrationHash.py
+++ b/rdkit/Chem/UnitTestRegistrationHash.py
@@ -5,9 +5,11 @@
 are actually the same.
 """

+import os
 import unittest

 from rdkit import Chem
+from rdkit import RDConfig
 from rdkit.Chem import RegistrationHash
 from rdkit.Chem.RegistrationHash import HashLayer

@@ -806,6 +808,42 @@ def test_tautomer_v2_hash(self):
       RegistrationHash.GetMolHash(
         keto_layers, hash_scheme=RegistrationHash.HashScheme.TAUTOMER_INSENSITIVE_LAYERS))

+  def testAtropisomer(self):
+    atropTestFile = os.path.join(
+      RDConfig.RDBaseDir, 'Code/GraphMol/FileParsers/test_data/atropisomers/RP-6306_atrop1.sdf')
+    mol = Chem.MolFromMolFile(atropTestFile)
+
+    bond = mol.GetBondWithIdx(3)
+    self.assertEqual(bond.GetStereo(), Chem.BondStereo.STEREOATROPCW)
+
+    layersCw = RegistrationHash.GetMolLayers(mol)
+
+    smiles1, smiExt1 = layersCw[HashLayer.CANONICAL_SMILES].split()
+    taut1, tautExt1 = layersCw[HashLayer.TAUTOMER_HASH].split()
+    self.assertEqual(smiles1, 'Cc1cc2c(C(N)=O)c(N)n(-c3c(C)ccc(O)c3C)c2nc1C')
+    self.assertEqual(
+      taut1,
+      'C[C]1[CH][C]2[C]([C]([N])[O])[C]([N])N([C]3[C](C)[CH][CH][C]([O])[C]3C)[C]2[N][C]1C_5_0')
+    self.assertEqual(smiExt1, '|wD:10.9|')
+    self.assertEqual(smiExt1, tautExt1)
+
+    # Now look at the other atropisomer
+    bond = mol.GetBondWithIdx(3)
+    bond.SetStereo(Chem.BondStereo.STEREOATROPCCW)
+
+    # Hashes should not match
+    layersCcw = RegistrationHash.GetMolLayers(mol)
+    self.assertNotEqual(layersCw, layersCcw)
+
+    smiles2, smiExt2 = layersCcw[HashLayer.CANONICAL_SMILES].split()
+    taut2, tautExt2 = layersCcw[HashLayer.TAUTOMER_HASH].split()
+
+    # SMILES and tautomer hash should be the same, but the extensions must be different
+    self.assertEqual(smiles2, smiles1)
+    self.assertEqual(taut2, taut1)
+    self.assertEqual(smiExt2, '|wD:10.20|')  # same atom, but "down" wedge on a different bond
+    self.assertEqual(smiExt2, tautExt2)
+

 if __name__ == '__main__':  # pragma: nocover
   unittest.main()