mirror of
https://github.com/rdkit/rdkit.git
synced 2026-06-03 21:44:30 +08:00
* Fixes #3553 * add another test * Apply suggestions from code review Co-authored-by: Paolo Tosco <paolo.tosco.mail@gmail.com> * add an additional test for that Co-authored-by: Paolo Tosco <paolo.tosco.mail@gmail.com>
This commit is contained in:
@@ -5917,11 +5917,14 @@ M END
|
||||
self.assertEqual(m_noh.GetNumAtoms(), m.GetNumAtoms() - 2)
|
||||
self.assertTrue(m_noh.GetAtomWithIdx(2).HasProp("_isotopicHs"))
|
||||
self.assertEqual(tuple(map(int,
|
||||
m_noh.GetAtomWithIdx(2).GetProp("_isotopicHs").split())), (2,2))
|
||||
m_noh.GetAtomWithIdx(2).GetProp("_isotopicHs").split())), (2, 2))
|
||||
m_h = Chem.AddHs(m_noh)
|
||||
self.assertFalse(m_h.GetAtomWithIdx(2).HasProp("_isotopicHs"))
|
||||
self.assertEqual(sum([1 for nbr in m_h.GetAtomWithIdx(2).GetNeighbors()
|
||||
if (nbr.GetAtomicNum() == 1 and nbr.GetIsotope())]), 2)
|
||||
self.assertEqual(
|
||||
sum([
|
||||
1 for nbr in m_h.GetAtomWithIdx(2).GetNeighbors()
|
||||
if (nbr.GetAtomicNum() == 1 and nbr.GetIsotope())
|
||||
]), 2)
|
||||
|
||||
m = Chem.MolFromSmiles('*[H]', smips)
|
||||
ps = Chem.RemoveHsParameters()
|
||||
@@ -6166,36 +6169,36 @@ M END
|
||||
with open(fileN, 'rb') as inf:
|
||||
d = inf.read()
|
||||
mol = Chem.MolFromPNGString(d)
|
||||
nd = Chem.MolMetadataToPNGString(mol,d)
|
||||
vals = {'foo':'1','bar':'2'}
|
||||
nd = Chem.MolMetadataToPNGString(mol, d)
|
||||
vals = {'foo': '1', 'bar': '2'}
|
||||
nd = Chem.AddMetadataToPNGString(vals, nd)
|
||||
nvals = Chem.MetadataFromPNGString(nd)
|
||||
self.assertTrue('foo' in nvals)
|
||||
self.assertEqual(nvals['foo'],b'1')
|
||||
self.assertEqual(nvals['foo'], b'1')
|
||||
self.assertTrue('bar' in nvals)
|
||||
self.assertEqual(nvals['bar'],b'2')
|
||||
self.assertEqual(nvals['bar'], b'2')
|
||||
|
||||
nd = Chem.AddMetadataToPNGFile(vals, fileN)
|
||||
nvals = Chem.MetadataFromPNGString(nd)
|
||||
self.assertTrue('foo' in nvals)
|
||||
self.assertEqual(nvals['foo'],b'1')
|
||||
self.assertEqual(nvals['foo'], b'1')
|
||||
self.assertTrue('bar' in nvals)
|
||||
self.assertEqual(nvals['bar'],b'2')
|
||||
self.assertEqual(nvals['bar'], b'2')
|
||||
|
||||
vals = {'foo':1,'bar':'2'}
|
||||
vals = {'foo': 1, 'bar': '2'}
|
||||
with self.assertRaises(TypeError):
|
||||
nd = Chem.AddMetadataToPNGString(vals,d)
|
||||
nd = Chem.AddMetadataToPNGString(vals, d)
|
||||
|
||||
def test_github3403(self):
|
||||
core1 = "[$(C-!@[a])](=O)(Cl)"
|
||||
sma = Chem.MolFromSmarts(core1)
|
||||
|
||||
|
||||
m = Chem.MolFromSmiles("c1ccccc1C(=O)Cl")
|
||||
self.assertFalse(m.HasSubstructMatch(sma, recursionPossible=False))
|
||||
|
||||
|
||||
m = Chem.MolFromSmiles("c1ccccc1C(=O)Cl")
|
||||
self.assertTrue(m.HasSubstructMatch(sma))
|
||||
|
||||
|
||||
m = Chem.MolFromSmiles("c1ccccc1C(=O)Cl")
|
||||
self.assertFalse(m.HasSubstructMatch(sma, recursionPossible=False))
|
||||
|
||||
@@ -6208,24 +6211,44 @@ M END
|
||||
self.assertEqual(len(mols_list), len(mols_list_compr))
|
||||
|
||||
def test_github3492(self):
|
||||
|
||||
def read_smile(s):
|
||||
m = Chem.MolFromSmiles(s)
|
||||
rdkit.Chem.rdDepictor.Compute2DCoords(m)
|
||||
return m
|
||||
m = Chem.MolFromSmiles(s)
|
||||
rdkit.Chem.rdDepictor.Compute2DCoords(m)
|
||||
return m
|
||||
|
||||
def sq_dist(a, b):
|
||||
ab = [a[i] - b[i] for i, _ in enumerate(a)]
|
||||
return sum([d * d for d in ab])
|
||||
|
||||
self.assertIsNotNone(Chem.MolFromSmiles("OCCN").GetAtoms()[0].GetOwningMol())
|
||||
self.assertEqual([Chem.MolFromSmiles("OCCN").GetAtoms()[i].GetAtomicNum() for i in range(4)], [8, 6, 6, 7])
|
||||
self.assertEqual([Chem.MolFromSmiles("OCCN").GetAtoms()[i].GetAtomicNum() for i in range(4)],
|
||||
[8, 6, 6, 7])
|
||||
self.assertIsNotNone(Chem.MolFromSmiles("O=CCC=N").GetBonds()[0].GetOwningMol())
|
||||
self.assertEqual([Chem.MolFromSmiles("O=CCC=N").GetBonds()[i].GetBondType() for i in range(4)],
|
||||
[Chem.BondType.DOUBLE, Chem.BondType.SINGLE, Chem.BondType.SINGLE, Chem.BondType.DOUBLE])
|
||||
self.assertEqual(
|
||||
[Chem.MolFromSmiles("O=CCC=N").GetBonds()[i].GetBondType() for i in range(4)],
|
||||
[Chem.BondType.DOUBLE, Chem.BondType.SINGLE, Chem.BondType.SINGLE, Chem.BondType.DOUBLE])
|
||||
self.assertIsNotNone(read_smile("CCC").GetConformers()[0].GetOwningMol())
|
||||
pos = read_smile("CCC").GetConformers()[0].GetPositions()
|
||||
self.assertAlmostEqual(sq_dist(pos[0], pos[1]), sq_dist(pos[1], pos[2]))
|
||||
|
||||
def test_github3553(self):
|
||||
from io import StringIO
|
||||
fileN = os.path.join(RDConfig.RDBaseDir, 'Code', 'GraphMol', 'Wrap', 'test_data',
|
||||
'github3553.sdf')
|
||||
sdSup = Chem.SDMolSupplier(fileN)
|
||||
for mol in sdSup:
|
||||
pval = mol.GetProp('boiling.point.predicted')
|
||||
sio = StringIO()
|
||||
w = Chem.SDWriter(sio)
|
||||
w.SetKekulize(True)
|
||||
w.SetForceV3000(True)
|
||||
w.write(mol)
|
||||
w.flush()
|
||||
txt = sio.getvalue()
|
||||
self.assertTrue(pval in txt)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
if "RDTESTCASE" in os.environ:
|
||||
suite = unittest.TestSuite()
|
||||
|
||||
208
Code/GraphMol/Wrap/test_data/github3553.sdf
Normal file
208
Code/GraphMol/Wrap/test_data/github3553.sdf
Normal file
@@ -0,0 +1,208 @@
|
||||
some padding that is just the ri
|
||||
RDKit 2D
|
||||
|
||||
0 0 0 0 0 0 0 0 0 0999 V3000
|
||||
M V30 BEGIN CTAB
|
||||
M V30 COUNTS 12 12 0 0 0
|
||||
M V30 BEGIN ATOM
|
||||
M V30 1 C -1.08313 -0.7909 0 0
|
||||
M V30 2 O -1.08393 -1.7909 0 0
|
||||
M V30 3 O -1.94873 -0.2901 0 0
|
||||
M V30 4 Cl -1.08153 1.2091 0 0
|
||||
M V30 5 Cl 0.648067 -1.7921 0 0
|
||||
M V30 6 N 0.651267 2.2079 0 0
|
||||
M V30 7 C -0.216733 -0.2915 0 0
|
||||
M V30 8 C -0.215933 0.7085 0 0
|
||||
M V30 9 C 0.648867 -0.7921 0 0
|
||||
M V30 10 C 0.650467 1.2079 0 0
|
||||
M V30 11 C 1.51527 -0.2929 0 0
|
||||
M V30 12 C 1.51607 0.7071 0 0
|
||||
M V30 END ATOM
|
||||
M V30 BEGIN BOND
|
||||
M V30 1 1 1 2
|
||||
M V30 2 2 1 3
|
||||
M V30 3 1 1 7
|
||||
M V30 4 1 4 8
|
||||
M V30 5 1 5 9
|
||||
M V30 6 1 6 10
|
||||
M V30 7 2 7 8
|
||||
M V30 8 1 7 9
|
||||
M V30 9 1 8 10
|
||||
M V30 10 2 9 11
|
||||
M V30 11 2 10 12
|
||||
M V30 12 1 11 12
|
||||
M V30 END BOND
|
||||
M V30 END CTAB
|
||||
M END
|
||||
> <cas.rn> (1)
|
||||
paddingpad
|
||||
|
||||
> <cas.index.name> (1)
|
||||
paddingpaddingpaddingpaddingpadding
|
||||
|
||||
> <molecular.formula> (1)
|
||||
C7H5Cl2NO2
|
||||
|
||||
> <molecular.weight> (1)
|
||||
206.03
|
||||
|
||||
> <boiling.point.predicted> (1)
|
||||
123.4±56.7 𐍈C paddingpaddingp
|
||||
|
||||
$$$$
|
||||
some padding that is just the ri
|
||||
RDKit 2D
|
||||
|
||||
0 0 0 0 0 0 0 0 0 0999 V3000
|
||||
M V30 BEGIN CTAB
|
||||
M V30 COUNTS 12 12 0 0 0
|
||||
M V30 BEGIN ATOM
|
||||
M V30 1 C -1.08313 -0.7909 0 0
|
||||
M V30 2 O -1.08393 -1.7909 0 0
|
||||
M V30 3 O -1.94873 -0.2901 0 0
|
||||
M V30 4 Cl -1.08153 1.2091 0 0
|
||||
M V30 5 Cl 0.648067 -1.7921 0 0
|
||||
M V30 6 N 0.651267 2.2079 0 0
|
||||
M V30 7 C -0.216733 -0.2915 0 0
|
||||
M V30 8 C -0.215933 0.7085 0 0
|
||||
M V30 9 C 0.648867 -0.7921 0 0
|
||||
M V30 10 C 0.650467 1.2079 0 0
|
||||
M V30 11 C 1.51527 -0.2929 0 0
|
||||
M V30 12 C 1.51607 0.7071 0 0
|
||||
M V30 END ATOM
|
||||
M V30 BEGIN BOND
|
||||
M V30 1 1 1 2
|
||||
M V30 2 2 1 3
|
||||
M V30 3 1 1 7
|
||||
M V30 4 1 4 8
|
||||
M V30 5 1 5 9
|
||||
M V30 6 1 6 10
|
||||
M V30 7 2 7 8
|
||||
M V30 8 1 7 9
|
||||
M V30 9 1 8 10
|
||||
M V30 10 2 9 11
|
||||
M V30 11 2 10 12
|
||||
M V30 12 1 11 12
|
||||
M V30 END BOND
|
||||
M V30 END CTAB
|
||||
M END
|
||||
> <cas.rn> (1)
|
||||
paddingpad
|
||||
|
||||
> <cas.index.name> (1)
|
||||
paddingpaddingpaddingpaddingpadding
|
||||
|
||||
> <molecular.formula> (1)
|
||||
C7H5Cl2NO2
|
||||
|
||||
> <molecular.weight> (1)
|
||||
206.03
|
||||
|
||||
> <boiling.point.predicted> (1)
|
||||
123.4±56.7 €C paddingpaddingp
|
||||
|
||||
$$$$
|
||||
some padding that is just the ri
|
||||
RDKit 2D
|
||||
|
||||
0 0 0 0 0 0 0 0 0 0999 V3000
|
||||
M V30 BEGIN CTAB
|
||||
M V30 COUNTS 12 12 0 0 0
|
||||
M V30 BEGIN ATOM
|
||||
M V30 1 C -1.08313 -0.7909 0 0
|
||||
M V30 2 O -1.08393 -1.7909 0 0
|
||||
M V30 3 O -1.94873 -0.2901 0 0
|
||||
M V30 4 Cl -1.08153 1.2091 0 0
|
||||
M V30 5 Cl 0.648067 -1.7921 0 0
|
||||
M V30 6 N 0.651267 2.2079 0 0
|
||||
M V30 7 C -0.216733 -0.2915 0 0
|
||||
M V30 8 C -0.215933 0.7085 0 0
|
||||
M V30 9 C 0.648867 -0.7921 0 0
|
||||
M V30 10 C 0.650467 1.2079 0 0
|
||||
M V30 11 C 1.51527 -0.2929 0 0
|
||||
M V30 12 C 1.51607 0.7071 0 0
|
||||
M V30 END ATOM
|
||||
M V30 BEGIN BOND
|
||||
M V30 1 1 1 2
|
||||
M V30 2 2 1 3
|
||||
M V30 3 1 1 7
|
||||
M V30 4 1 4 8
|
||||
M V30 5 1 5 9
|
||||
M V30 6 1 6 10
|
||||
M V30 7 2 7 8
|
||||
M V30 8 1 7 9
|
||||
M V30 9 1 8 10
|
||||
M V30 10 2 9 11
|
||||
M V30 11 2 10 12
|
||||
M V30 12 1 11 12
|
||||
M V30 END BOND
|
||||
M V30 END CTAB
|
||||
M END
|
||||
> <cas.rn> (1)
|
||||
paddingpad
|
||||
|
||||
> <cas.index.name> (1)
|
||||
paddingpaddingpaddingpaddingpadding
|
||||
|
||||
> <molecular.formula> (1)
|
||||
C7H5Cl2NO2
|
||||
|
||||
> <molecular.weight> (1)
|
||||
206.03
|
||||
|
||||
> <boiling.point.predicted> (1)
|
||||
123.4±56.7 °C paddingpaddingp
|
||||
|
||||
$$$$
|
||||
some padding that is just the ri
|
||||
RDKit 2D
|
||||
|
||||
0 0 0 0 0 0 0 0 0 0999 V3000
|
||||
M V30 BEGIN CTAB
|
||||
M V30 COUNTS 12 12 0 0 0
|
||||
M V30 BEGIN ATOM
|
||||
M V30 1 C -1.08313 -0.7909 0 0
|
||||
M V30 2 O -1.08393 -1.7909 0 0
|
||||
M V30 3 O -1.94873 -0.2901 0 0
|
||||
M V30 4 Cl -1.08153 1.2091 0 0
|
||||
M V30 5 Cl 0.648067 -1.7921 0 0
|
||||
M V30 6 N 0.651267 2.2079 0 0
|
||||
M V30 7 C -0.216733 -0.2915 0 0
|
||||
M V30 8 C -0.215933 0.7085 0 0
|
||||
M V30 9 C 0.648867 -0.7921 0 0
|
||||
M V30 10 C 0.650467 1.2079 0 0
|
||||
M V30 11 C 1.51527 -0.2929 0 0
|
||||
M V30 12 C 1.51607 0.7071 0 0
|
||||
M V30 END ATOM
|
||||
M V30 BEGIN BOND
|
||||
M V30 1 1 1 2
|
||||
M V30 2 2 1 3
|
||||
M V30 3 1 1 7
|
||||
M V30 4 1 4 8
|
||||
M V30 5 1 5 9
|
||||
M V30 6 1 6 10
|
||||
M V30 7 2 7 8
|
||||
M V30 8 1 7 9
|
||||
M V30 9 1 8 10
|
||||
M V30 10 2 9 11
|
||||
M V30 11 2 10 12
|
||||
M V30 12 1 11 12
|
||||
M V30 END BOND
|
||||
M V30 END CTAB
|
||||
M END
|
||||
> <cas.rn> (1)
|
||||
paddingpad
|
||||
|
||||
> <cas.index.name> (1)
|
||||
paddingpaddingpaddingpaddingpadding
|
||||
|
||||
> <molecular.formula> (1)
|
||||
C7H5Cl2NO2
|
||||
|
||||
> <molecular.weight> (1)
|
||||
206.03
|
||||
|
||||
> <boiling.point.predicted> (1)
|
||||
123.4±5°°°°°C paddingpaddingp
|
||||
|
||||
$$$$
|
||||
@@ -211,17 +211,17 @@ class streambuf : public std::basic_streambuf<char> {
|
||||
CHECK_INVARIANT(iobase, "base class not found");
|
||||
#endif
|
||||
|
||||
bool isTextMode = PyObject_IsInstance(python_file_obj.ptr(), iobase.ptr());
|
||||
df_isTextMode = PyObject_IsInstance(python_file_obj.ptr(), iobase.ptr());
|
||||
switch (mode) {
|
||||
case 's': /// yeah, is redundant, but it is somehow natural to do "s"
|
||||
case 't':
|
||||
if (!isTextMode)
|
||||
if (!df_isTextMode)
|
||||
throw ValueErrorException(
|
||||
"Need a text mode file object like StringIO or a file opened "
|
||||
"with mode 't'");
|
||||
break;
|
||||
case 'b':
|
||||
if (isTextMode)
|
||||
if (df_isTextMode)
|
||||
throw ValueErrorException(
|
||||
"Need a binary mode file object like BytesIO or a file opened "
|
||||
"with mode 'b'");
|
||||
@@ -280,17 +280,42 @@ class streambuf : public std::basic_streambuf<char> {
|
||||
}
|
||||
farthest_pptr = std::max(farthest_pptr, pptr());
|
||||
off_type n_written = (off_type)(farthest_pptr - pbase());
|
||||
bp::str chunk(pbase(), farthest_pptr);
|
||||
off_type orig_n_written = n_written;
|
||||
const unsigned int STD_ASCII = 0x7F;
|
||||
if (df_isTextMode && c > STD_ASCII) {
|
||||
// we're somewhere in the middle of a utf8 block. If we
|
||||
// only write part of it we'll end up with an exception,
|
||||
// so push everything that could be utf8 into the next block
|
||||
while (n_written > 0 &&
|
||||
static_cast<unsigned int>(write_buffer[n_written - 1]) > STD_ASCII) {
|
||||
--n_written;
|
||||
}
|
||||
}
|
||||
bp::str chunk(pbase(), pbase() + n_written);
|
||||
py_write(chunk);
|
||||
if (!traits_type::eq_int_type(c, traits_type::eof())) {
|
||||
|
||||
if ((!df_isTextMode || c <= STD_ASCII) &&
|
||||
!traits_type::eq_int_type(c, traits_type::eof())) {
|
||||
py_write(traits_type::to_char_type(c));
|
||||
n_written++;
|
||||
}
|
||||
|
||||
setp(pbase(), epptr());
|
||||
// ^^^ 27.5.2.4.5 (5)
|
||||
farthest_pptr = pptr();
|
||||
if (n_written) {
|
||||
pos_of_write_buffer_end_in_py_file += n_written;
|
||||
setp(pbase(), epptr());
|
||||
// ^^^ 27.5.2.4.5 (5)
|
||||
farthest_pptr = pptr();
|
||||
if (df_isTextMode && c > STD_ASCII &&
|
||||
!traits_type::eq_int_type(c, traits_type::eof())) {
|
||||
size_t n_to_copy = orig_n_written - n_written;
|
||||
|
||||
for (size_t i = 0; i < n_to_copy; ++i) {
|
||||
sputc(write_buffer[n_written + i]);
|
||||
++farthest_pptr;
|
||||
}
|
||||
sputc(c);
|
||||
++farthest_pptr;
|
||||
}
|
||||
}
|
||||
return traits_type::eq_int_type(c, traits_type::eof())
|
||||
? traits_type::not_eof(c)
|
||||
@@ -405,6 +430,7 @@ class streambuf : public std::basic_streambuf<char> {
|
||||
de-allocated only at destruction time.
|
||||
*/
|
||||
char* write_buffer;
|
||||
bool df_isTextMode;
|
||||
|
||||
off_type pos_of_read_buffer_end_in_py_file,
|
||||
pos_of_write_buffer_end_in_py_file;
|
||||
|
||||
Reference in New Issue
Block a user