1 //
2 //  Copyright (C) 2003-2019 Greg Landrum and Rational Discovery LLC
3 //
4 //   @@ All Rights Reserved @@
5 //  This file is part of the RDKit.
6 //  The contents are covered by the terms of the BSD license
7 //  which is included in the file license.txt, found at the root
8 //  of the RDKit source tree.
9 //
10 #include "rdmolops.h"
11 
12 #include <RDGeneral/BoostStartInclude.h>
13 #include <RDBoost/python.h>
14 #include <boost/dynamic_bitset.hpp>
15 #include <RDGeneral/BoostStartInclude.h>
16 
17 #include <RDGeneral/types.h>
18 #include <GraphMol/RDKitBase.h>
19 #include <GraphMol/MolOps.h>
20 #include <GraphMol/new_canon.h>
21 #include <GraphMol/SmilesParse/SmilesParse.h>
22 #include <GraphMol/SmilesParse/SmilesWrite.h>
23 #include <GraphMol/SmilesParse/SmartsWrite.h>
24 #include <GraphMol/FileParsers/FileParsers.h>
25 #include <GraphMol/FileParsers/FileParserUtils.h>
26 #include <GraphMol/FileParsers/SequenceParsers.h>
27 #include <GraphMol/FileParsers/SequenceWriters.h>
28 #include <GraphMol/FileParsers/PNGParser.h>
29 #include <RDGeneral/BadFileException.h>
30 #include <RDGeneral/FileParseException.h>
31 
32 #include <RDBoost/Wrap.h>
33 #include <RDGeneral/Exceptions.h>
34 #include <RDGeneral/BadFileException.h>
35 #include <GraphMol/SanitException.h>
36 
37 namespace python = boost::python;
38 using namespace RDKit;
39 
rdBadFileExceptionTranslator(RDKit::BadFileException const & x)40 void rdBadFileExceptionTranslator(RDKit::BadFileException const &x) {
41   std::ostringstream ss;
42   ss << "File error: " << x.what();
43   PyErr_SetString(PyExc_IOError, ss.str().c_str());
44 }
rdFileParseExceptionTranslator(RDKit::FileParseException const & x)45 void rdFileParseExceptionTranslator(RDKit::FileParseException const &x) {
46   std::ostringstream ss;
47   ss << "File parsing error: " << x.what();
48   PyErr_SetString(PyExc_RuntimeError, ss.str().c_str());
49 }
50 
51 namespace RDKit {
pyObjectToString(python::object input)52 std::string pyObjectToString(python::object input) {
53   python::extract<std::string> ex(input);
54   if (ex.check()) {
55     return ex();
56   }
57   std::wstring ws = python::extract<std::wstring>(input);
58   return std::string(ws.begin(), ws.end());
59 }
60 
MolFromSmiles(python::object ismiles,bool sanitize,python::dict replDict)61 ROMol *MolFromSmiles(python::object ismiles, bool sanitize,
62                      python::dict replDict) {
63   std::map<std::string, std::string> replacements;
64   for (unsigned int i = 0;
65        i < python::extract<unsigned int>(replDict.keys().attr("__len__")());
66        ++i) {
67     replacements[python::extract<std::string>(replDict.keys()[i])] =
68         python::extract<std::string>(replDict.values()[i]);
69   }
70   RWMol *newM;
71   std::string smiles = pyObjectToString(ismiles);
72   try {
73     newM = SmilesToMol(smiles, 0, sanitize, &replacements);
74   } catch (...) {
75     newM = nullptr;
76   }
77   return static_cast<ROMol *>(newM);
78 }
79 
MolFromSmarts(python::object ismarts,bool mergeHs,python::dict replDict)80 ROMol *MolFromSmarts(python::object ismarts, bool mergeHs,
81                      python::dict replDict) {
82   std::map<std::string, std::string> replacements;
83   for (unsigned int i = 0;
84        i < python::extract<unsigned int>(replDict.keys().attr("__len__")());
85        ++i) {
86     replacements[python::extract<std::string>(replDict.keys()[i])] =
87         python::extract<std::string>(replDict.values()[i]);
88   }
89   std::string smarts = pyObjectToString(ismarts);
90 
91   RWMol *newM;
92   try {
93     newM = SmartsToMol(smarts, 0, mergeHs, &replacements);
94   } catch (...) {
95     newM = nullptr;
96   }
97   return static_cast<ROMol *>(newM);
98 }
MolFromTPLFile(const char * filename,bool sanitize=true,bool skipFirstConf=false)99 ROMol *MolFromTPLFile(const char *filename, bool sanitize = true,
100                       bool skipFirstConf = false) {
101   RWMol *newM;
102   try {
103     newM = TPLFileToMol(filename, sanitize, skipFirstConf);
104   } catch (RDKit::BadFileException &e) {
105     PyErr_SetString(PyExc_IOError, e.what());
106     throw python::error_already_set();
107   } catch (...) {
108     newM = nullptr;
109   }
110   return static_cast<ROMol *>(newM);
111 }
112 
MolFromTPLBlock(python::object itplBlock,bool sanitize=true,bool skipFirstConf=false)113 ROMol *MolFromTPLBlock(python::object itplBlock, bool sanitize = true,
114                        bool skipFirstConf = false) {
115   std::istringstream inStream(pyObjectToString(itplBlock));
116   unsigned int line = 0;
117   RWMol *newM;
118   try {
119     newM = TPLDataStreamToMol(&inStream, line, sanitize, skipFirstConf);
120   } catch (...) {
121     newM = nullptr;
122   }
123   return static_cast<ROMol *>(newM);
124 }
125 
MolFromMolFile(const char * molFilename,bool sanitize,bool removeHs,bool strictParsing)126 ROMol *MolFromMolFile(const char *molFilename, bool sanitize, bool removeHs,
127                       bool strictParsing) {
128   RWMol *newM = nullptr;
129   try {
130     newM = MolFileToMol(molFilename, sanitize, removeHs, strictParsing);
131   } catch (RDKit::BadFileException &e) {
132     PyErr_SetString(PyExc_IOError, e.what());
133     throw python::error_already_set();
134   } catch (RDKit::FileParseException &e) {
135     BOOST_LOG(rdWarningLog) << e.what() << std::endl;
136   } catch (...) {
137   }
138   return static_cast<ROMol *>(newM);
139 }
140 
MolFromMolBlock(python::object imolBlock,bool sanitize,bool removeHs,bool strictParsing)141 ROMol *MolFromMolBlock(python::object imolBlock, bool sanitize, bool removeHs,
142                        bool strictParsing) {
143   std::istringstream inStream(pyObjectToString(imolBlock));
144   unsigned int line = 0;
145   RWMol *newM = nullptr;
146   try {
147     newM =
148         MolDataStreamToMol(inStream, line, sanitize, removeHs, strictParsing);
149   } catch (RDKit::FileParseException &e) {
150     BOOST_LOG(rdWarningLog) << e.what() << std::endl;
151   } catch (...) {
152   }
153   return static_cast<ROMol *>(newM);
154 }
155 
MolFromSVG(python::object imolBlock,bool sanitize,bool removeHs)156 ROMol *MolFromSVG(python::object imolBlock, bool sanitize, bool removeHs) {
157   RWMol *res = nullptr;
158   res = RDKitSVGToMol(pyObjectToString(imolBlock), sanitize, removeHs);
159   return static_cast<ROMol *>(res);
160 }
161 
MolFromMol2File(const char * molFilename,bool sanitize=true,bool removeHs=true,bool cleanupSubstructures=true)162 ROMol *MolFromMol2File(const char *molFilename, bool sanitize = true,
163                        bool removeHs = true, bool cleanupSubstructures = true) {
164   RWMol *newM;
165   try {
166     newM = Mol2FileToMol(molFilename, sanitize, removeHs, CORINA,
167                          cleanupSubstructures);
168   } catch (RDKit::BadFileException &e) {
169     PyErr_SetString(PyExc_IOError, e.what());
170     throw python::error_already_set();
171   } catch (...) {
172     newM = nullptr;
173   }
174   return static_cast<ROMol *>(newM);
175 }
176 
MolFromMol2Block(std::string mol2Block,bool sanitize=true,bool removeHs=true,bool cleanupSubstructures=true)177 ROMol *MolFromMol2Block(std::string mol2Block, bool sanitize = true,
178                         bool removeHs = true,
179                         bool cleanupSubstructures = true) {
180   std::istringstream inStream(mol2Block);
181   RWMol *newM;
182   try {
183     newM = Mol2DataStreamToMol(inStream, sanitize, removeHs, CORINA,
184                                cleanupSubstructures);
185   } catch (...) {
186     newM = nullptr;
187   }
188   return static_cast<ROMol *>(newM);
189 }
190 
MolFromPDBFile(const char * filename,bool sanitize,bool removeHs,unsigned int flavor,bool proximityBonding)191 ROMol *MolFromPDBFile(const char *filename, bool sanitize, bool removeHs,
192                       unsigned int flavor, bool proximityBonding) {
193   RWMol *newM = nullptr;
194   try {
195     newM = PDBFileToMol(filename, sanitize, removeHs, flavor, proximityBonding);
196   } catch (RDKit::BadFileException &e) {
197     PyErr_SetString(PyExc_IOError, e.what());
198     throw python::error_already_set();
199   } catch (RDKit::FileParseException &e) {
200     BOOST_LOG(rdWarningLog) << e.what() << std::endl;
201   } catch (...) {
202   }
203   return static_cast<ROMol *>(newM);
204 }
205 
MolFromPDBBlock(python::object molBlock,bool sanitize,bool removeHs,unsigned int flavor,bool proximityBonding)206 ROMol *MolFromPDBBlock(python::object molBlock, bool sanitize, bool removeHs,
207                        unsigned int flavor, bool proximityBonding) {
208   std::istringstream inStream(pyObjectToString(molBlock));
209   RWMol *newM = nullptr;
210   try {
211     newM = PDBDataStreamToMol(inStream, sanitize, removeHs, flavor,
212                               proximityBonding);
213   } catch (RDKit::FileParseException &e) {
214     BOOST_LOG(rdWarningLog) << e.what() << std::endl;
215   } catch (...) {
216   }
217   return static_cast<ROMol *>(newM);
218 }
219 
MolFromSequence(python::object seq,bool sanitize,int flavor)220 ROMol *MolFromSequence(python::object seq, bool sanitize, int flavor) {
221   RWMol *newM = nullptr;
222   try {
223     newM = SequenceToMol(pyObjectToString(seq), sanitize, flavor);
224   } catch (RDKit::FileParseException &e) {
225     BOOST_LOG(rdWarningLog) << e.what() << std::endl;
226   } catch (...) {
227   }
228   return static_cast<ROMol *>(newM);
229 }
MolFromFASTA(python::object seq,bool sanitize,int flavor)230 ROMol *MolFromFASTA(python::object seq, bool sanitize, int flavor) {
231   RWMol *newM = nullptr;
232   try {
233     newM = FASTAToMol(pyObjectToString(seq), sanitize, flavor);
234   } catch (RDKit::FileParseException &e) {
235     BOOST_LOG(rdWarningLog) << e.what() << std::endl;
236   } catch (...) {
237   }
238   return static_cast<ROMol *>(newM);
239 }
MolFromHELM(python::object seq,bool sanitize)240 ROMol *MolFromHELM(python::object seq, bool sanitize) {
241   RWMol *newM = nullptr;
242   try {
243     newM = HELMToMol(pyObjectToString(seq), sanitize);
244   } catch (RDKit::FileParseException &e) {
245     BOOST_LOG(rdWarningLog) << e.what() << std::endl;
246   } catch (...) {
247   }
248   return static_cast<ROMol *>(newM);
249 }
250 
molFragmentToSmarts(const ROMol & mol,python::object atomsToUse,python::object bondsToUse,bool doIsomericSmarts=true)251 std::string molFragmentToSmarts(const ROMol &mol, python::object atomsToUse,
252                                 python::object bondsToUse,
253                                 bool doIsomericSmarts = true) {
254   auto atomIndices =
255       pythonObjectToVect(atomsToUse, static_cast<int>(mol.getNumAtoms()));
256   auto bondIndices =
257       pythonObjectToVect(bondsToUse, static_cast<int>(mol.getNumBonds()));
258   return RDKit::MolFragmentToSmarts(mol, *atomIndices, bondIndices.get(),
259                                     doIsomericSmarts);
260 }
261 
262 struct smilesfrag_gen {
operator ()RDKit::smilesfrag_gen263   std::string operator()(const ROMol &mol, const std::vector<int> &atomsToUse,
264                          const std::vector<int> *bondsToUse,
265                          const std::vector<std::string> *atomSymbols,
266                          const std::vector<std::string> *bondSymbols,
267                          bool doIsomericSmiles, bool doKekule, int rootedAtAtom,
268                          bool canonical, bool allBondsExplicit,
269                          bool allHsExplicit) {
270     return MolFragmentToSmiles(
271         mol, atomsToUse, bondsToUse, atomSymbols, bondSymbols, doIsomericSmiles,
272         doKekule, rootedAtAtom, canonical, allBondsExplicit, allHsExplicit);
273   }
274 };
275 struct cxsmilesfrag_gen {
operator ()RDKit::cxsmilesfrag_gen276   std::string operator()(const ROMol &mol, const std::vector<int> &atomsToUse,
277                          const std::vector<int> *bondsToUse,
278                          const std::vector<std::string> *atomSymbols,
279                          const std::vector<std::string> *bondSymbols,
280                          bool doIsomericSmiles, bool doKekule, int rootedAtAtom,
281                          bool canonical, bool allBondsExplicit,
282                          bool allHsExplicit) {
283     return MolFragmentToCXSmiles(
284         mol, atomsToUse, bondsToUse, atomSymbols, bondSymbols, doIsomericSmiles,
285         doKekule, rootedAtAtom, canonical, allBondsExplicit, allHsExplicit);
286   }
287 };
288 
289 template <typename F>
MolFragmentToSmilesHelper(const ROMol & mol,python::object atomsToUse,python::object bondsToUse,python::object atomSymbols,python::object bondSymbols,bool doIsomericSmiles,bool doKekule,int rootedAtAtom,bool canonical,bool allBondsExplicit,bool allHsExplicit)290 std::string MolFragmentToSmilesHelper(
291     const ROMol &mol, python::object atomsToUse, python::object bondsToUse,
292     python::object atomSymbols, python::object bondSymbols,
293     bool doIsomericSmiles, bool doKekule, int rootedAtAtom, bool canonical,
294     bool allBondsExplicit, bool allHsExplicit) {
295   auto avect =
296       pythonObjectToVect(atomsToUse, static_cast<int>(mol.getNumAtoms()));
297   if (!avect.get() || !(avect->size())) {
298     throw_value_error("atomsToUse must not be empty");
299   }
300   auto bvect =
301       pythonObjectToVect(bondsToUse, static_cast<int>(mol.getNumBonds()));
302   std::unique_ptr<std::vector<std::string>> asymbols =
303       pythonObjectToVect<std::string>(atomSymbols);
304   std::unique_ptr<std::vector<std::string>> bsymbols =
305       pythonObjectToVect<std::string>(bondSymbols);
306   if (asymbols.get() && asymbols->size() != mol.getNumAtoms()) {
307     throw_value_error("length of atom symbol list != number of atoms");
308   }
309   if (bsymbols.get() && bsymbols->size() != mol.getNumBonds()) {
310     throw_value_error("length of bond symbol list != number of bonds");
311   }
312 
313   std::string res =
314       F()(mol, *avect.get(), bvect.get(), asymbols.get(), bsymbols.get(),
315           doIsomericSmiles, doKekule, rootedAtAtom, canonical, allBondsExplicit,
316           allHsExplicit);
317   return res;
318 }
319 
CanonicalRankAtoms(const ROMol & mol,bool breakTies=true,bool includeChirality=true,bool includeIsotopes=true)320 std::vector<unsigned int> CanonicalRankAtoms(const ROMol &mol,
321                                              bool breakTies = true,
322                                              bool includeChirality = true,
323                                              bool includeIsotopes = true) {
324   std::vector<unsigned int> ranks(mol.getNumAtoms());
325   Canon::rankMolAtoms(mol, ranks, breakTies, includeChirality, includeIsotopes);
326   return ranks;
327 }
328 
CanonicalRankAtomsInFragment(const ROMol & mol,python::object atomsToUse,python::object bondsToUse,python::object atomSymbols,bool breakTies=true,bool includeChirality=true,bool includeIsotopes=true)329 std::vector<int> CanonicalRankAtomsInFragment(
330     const ROMol &mol, python::object atomsToUse, python::object bondsToUse,
331     python::object atomSymbols, bool breakTies = true,
332     bool includeChirality = true, bool includeIsotopes = true)
333 
334 {
335   std::unique_ptr<std::vector<int>> avect =
336       pythonObjectToVect(atomsToUse, static_cast<int>(mol.getNumAtoms()));
337   if (!avect.get() || !(avect->size())) {
338     throw_value_error("atomsToUse must not be empty");
339   }
340   std::unique_ptr<std::vector<int>> bvect =
341       pythonObjectToVect(bondsToUse, static_cast<int>(mol.getNumBonds()));
342   std::unique_ptr<std::vector<std::string>> asymbols =
343       pythonObjectToVect<std::string>(atomSymbols);
344   if (asymbols.get() && asymbols->size() != mol.getNumAtoms()) {
345     throw_value_error("length of atom symbol list != number of atoms");
346   }
347 
348   boost::dynamic_bitset<> atoms(mol.getNumAtoms());
349   for (size_t i = 0; i < avect->size(); ++i) {
350     atoms[(*avect)[i]] = true;
351   }
352 
353   boost::dynamic_bitset<> bonds(mol.getNumBonds());
354   for (size_t i = 0; bvect.get() && i < bvect->size(); ++i) {
355     bonds[(*bvect)[i]] = true;
356   }
357 
358   std::vector<unsigned int> ranks(mol.getNumAtoms());
359   Canon::rankFragmentAtoms(mol, ranks, atoms, bonds, asymbols.get(), breakTies,
360                            includeChirality, includeIsotopes);
361 
362   std::vector<int> resRanks(mol.getNumAtoms());
363   // set unused ranks to -1 for the Python interface
364   for (size_t i = 0; i < atoms.size(); ++i) {
365     if (!atoms[i]) {
366       resRanks[i] = -1;
367     } else {
368       resRanks[i] = static_cast<int>(ranks[i]);
369     }
370   }
371 
372   return resRanks;
373 }
374 
MolFromSmilesHelper(python::object ismiles,const SmilesParserParams & params)375 ROMol *MolFromSmilesHelper(python::object ismiles,
376                            const SmilesParserParams &params) {
377   std::string smiles = pyObjectToString(ismiles);
378 
379   try {
380     return SmilesToMol(smiles, params);
381   } catch (...) {
382     return nullptr;
383   }
384 }
385 
MolToRandomSmilesHelper(const ROMol & mol,unsigned int numSmiles,unsigned int randomSeed,bool doIsomericSmiles,bool doKekule,bool allBondsExplicit,bool allHsExplicit)386 python::list MolToRandomSmilesHelper(const ROMol &mol, unsigned int numSmiles,
387                                      unsigned int randomSeed,
388                                      bool doIsomericSmiles, bool doKekule,
389                                      bool allBondsExplicit,
390                                      bool allHsExplicit) {
391   auto res = MolToRandomSmilesVect(mol, numSmiles, randomSeed, doIsomericSmiles,
392                                    doKekule, allBondsExplicit, allHsExplicit);
393   python::list pyres;
394   for (auto smi : res) {
395     pyres.append(smi);
396   }
397   return pyres;
398 }
399 
MolFromPNGFile(const char * filename,python::object pyParams)400 ROMol *MolFromPNGFile(const char *filename, python::object pyParams) {
401   SmilesParserParams params;
402   if (pyParams) {
403     params = python::extract<SmilesParserParams>(pyParams);
404   }
405   ROMol *newM = nullptr;
406   try {
407     newM = PNGFileToMol(filename, params);
408   } catch (RDKit::BadFileException &e) {
409     PyErr_SetString(PyExc_IOError, e.what());
410     throw python::error_already_set();
411   } catch (RDKit::FileParseException &e) {
412     BOOST_LOG(rdWarningLog) << e.what() << std::endl;
413   } catch (...) {
414   }
415   return newM;
416 }
417 
MolFromPNGString(python::object png,python::object pyParams)418 ROMol *MolFromPNGString(python::object png, python::object pyParams) {
419   SmilesParserParams params;
420   if (pyParams) {
421     params = python::extract<SmilesParserParams>(pyParams);
422   }
423   ROMol *newM = nullptr;
424   try {
425     newM = PNGStringToMol(pyObjectToString(png), params);
426   } catch (RDKit::FileParseException &e) {
427     BOOST_LOG(rdWarningLog) << e.what() << std::endl;
428   } catch (...) {
429   }
430   return newM;
431 }
432 
addMolToPNGFileHelper(const ROMol & mol,python::object fname,bool includePkl,bool includeSmiles,bool includeMol)433 python::object addMolToPNGFileHelper(const ROMol &mol, python::object fname,
434                                      bool includePkl, bool includeSmiles,
435                                      bool includeMol) {
436   std::string cstr = python::extract<std::string>(fname);
437 
438   auto res = addMolToPNGFile(mol, cstr, includePkl, includeSmiles, includeMol);
439 
440   python::object retval = python::object(
441       python::handle<>(PyBytes_FromStringAndSize(res.c_str(), res.length())));
442   return retval;
443 }
444 
addMolToPNGStringHelper(const ROMol & mol,python::object png,bool includePkl,bool includeSmiles,bool includeMol)445 python::object addMolToPNGStringHelper(const ROMol &mol, python::object png,
446                                        bool includePkl, bool includeSmiles,
447                                        bool includeMol) {
448   std::string cstr = python::extract<std::string>(png);
449 
450   auto res =
451       addMolToPNGString(mol, cstr, includePkl, includeSmiles, includeMol);
452 
453   python::object retval = python::object(
454       python::handle<>(PyBytes_FromStringAndSize(res.c_str(), res.length())));
455   return retval;
456 }
457 
addMetadataToPNGFileHelper(python::dict pymetadata,python::object fname)458 python::object addMetadataToPNGFileHelper(python::dict pymetadata, python::object fname) {
459   std::string cstr = python::extract<std::string>(fname);
460 
461   std::vector<std::pair<std::string, std::string>> metadata;
462   for (unsigned int i = 0;
463        i < python::extract<unsigned int>(pymetadata.keys().attr("__len__")());
464        ++i) {
465     std::string key = python::extract<std::string>(pymetadata.keys()[i]);
466     std::string val = python::extract<std::string>(pymetadata.values()[i]);
467     metadata.push_back(std::make_pair(key,val));
468   }
469 
470   auto res = addMetadataToPNGFile(cstr, metadata);
471 
472   python::object retval = python::object(
473       python::handle<>(PyBytes_FromStringAndSize(res.c_str(), res.length())));
474   return retval;
475 }
476 
addMetadataToPNGStringHelper(python::dict pymetadata,python::object png)477 python::object addMetadataToPNGStringHelper(python::dict pymetadata, python::object png) {
478   std::string cstr = python::extract<std::string>(png);
479 
480   std::vector<std::pair<std::string, std::string>> metadata;
481   for (unsigned int i = 0;
482        i < python::extract<unsigned int>(pymetadata.keys().attr("__len__")());
483        ++i) {
484     std::string key = python::extract<std::string>(pymetadata.keys()[i]);
485     std::string val = python::extract<std::string>(pymetadata.values()[i]);
486     metadata.push_back(std::make_pair(key,val));
487   }
488 
489   auto res = addMetadataToPNGString(cstr, metadata);
490 
491   python::object retval = python::object(
492       python::handle<>(PyBytes_FromStringAndSize(res.c_str(), res.length())));
493   return retval;
494 }
495 
496 
MolsFromPNGFile(const char * filename,const std::string & tag,python::object pyParams)497 python::object MolsFromPNGFile(const char *filename, const std::string &tag,
498                                python::object pyParams) {
499   SmilesParserParams params;
500   if (pyParams) {
501     params = python::extract<SmilesParserParams>(pyParams);
502   }
503   std::vector<std::unique_ptr<ROMol>> mols;
504   try {
505     mols = PNGFileToMols(filename, tag, params);
506   } catch (RDKit::BadFileException &e) {
507     PyErr_SetString(PyExc_IOError, e.what());
508     throw python::error_already_set();
509   } catch (RDKit::FileParseException &e) {
510     BOOST_LOG(rdWarningLog) << e.what() << std::endl;
511   } catch (...) {
512   }
513   python::list res;
514   for (auto &mol : mols) {
515     // take ownership of the data from the unique_ptr
516     ROMOL_SPTR sptr(mol.release());
517     res.append(sptr);
518   }
519   return python::tuple(res);
520 }
521 
MolsFromPNGString(python::object png,const std::string & tag,python::object pyParams)522 python::tuple MolsFromPNGString(python::object png, const std::string &tag,
523                                 python::object pyParams) {
524   SmilesParserParams params;
525   if (pyParams) {
526     params = python::extract<SmilesParserParams>(pyParams);
527   }
528   auto mols = PNGStringToMols(pyObjectToString(png), tag, params);
529   python::list res;
530   for (auto &mol : mols) {
531     // take ownership of the data from the unique_ptr
532     ROMOL_SPTR sptr(mol.release());
533     res.append(sptr);
534   }
535   return python::tuple(res);
536 }
537 
538 namespace {
translateMetadata(const std::vector<std::pair<std::string,std::string>> & metadata)539 python::dict translateMetadata(const std::vector<std::pair<std::string,std::string>> &metadata){
540   python::dict res;
541   for(const auto &pr : metadata ){
542     // keys are safe to extract:
543     std::string key = pr.first;
544     // but values may include binary, so we convert them directly to bytes:
545     python::object val = python::object(
546         python::handle<>(PyBytes_FromStringAndSize(pr.second.c_str(), pr.second.length())));
547     res[key] = val;
548   }
549   return res;
550 }
551 
552 }
MetadataFromPNGFile(python::object fname)553 python::dict MetadataFromPNGFile(python::object fname){
554   std::string cstr = python::extract<std::string>(fname);
555   auto metadata = PNGFileToMetadata(cstr);
556   return translateMetadata(metadata);
557 }
558 
MetadataFromPNGString(python::object png)559 python::dict MetadataFromPNGString(python::object png){
560   std::string cstr = python::extract<std::string>(png);
561   auto metadata = PNGStringToMetadata(cstr);
562   return translateMetadata(metadata);
563 }
564 
565 
566 
567 }  // namespace RDKit
568 
569 // MolSupplier stuff
570 #ifdef SUPPORT_COMPRESSED_SUPPLIERS
571 void wrap_compressedsdsupplier();
572 #endif
573 void wrap_sdsupplier();
574 void wrap_forwardsdsupplier();
575 void wrap_tdtsupplier();
576 void wrap_smisupplier();
577 #ifdef RDK_BUILD_MAEPARSER_SUPPORT
578 void wrap_maesupplier();
579 #endif
580 
581 // mol writer stuff
582 void wrap_smiwriter();
583 void wrap_sdwriter();
584 void wrap_tdtwriter();
585 void wrap_pdbwriter();
586 
587 // MultithreadedMolSupplier stuff
588 void wrap_multiSmiSupplier();
589 void wrap_multiSDSupplier();
590 
BOOST_PYTHON_MODULE(rdmolfiles)591 BOOST_PYTHON_MODULE(rdmolfiles) {
592   std::string docString;
593 
594   python::scope().attr("__doc__") =
595       "Module containing RDKit functionality for working with molecular file "
596       "formats.";
597   python::register_exception_translator<RDKit::BadFileException>(
598       &rdBadFileExceptionTranslator);
599 
600   python::register_exception_translator<RDKit::FileParseException>(
601       &rdFileParseExceptionTranslator);
602 
603   docString =
604       "Construct a molecule from a TPL file.\n\n\
605   ARGUMENTS:\n\
606 \n\
607     - fileName: name of the file to read\n\
608 \n\
609     - sanitize: (optional) toggles sanitization of the molecule.\n\
610       Defaults to True.\n\
611 \n\
612     - skipFirstConf: (optional) skips reading the first conformer.\n\
613       Defaults to False.\n\
614       This should be set to True when reading TPLs written by \n\
615       the CombiCode.\n\
616 \n\
617   RETURNS:\n\
618 \n\
619     a Mol object, None on failure.\n\
620 \n";
621   python::def("MolFromTPLFile", RDKit::MolFromTPLFile,
622               (python::arg("fileName"), python::arg("sanitize") = true,
623                python::arg("skipFirstConf") = false),
624               docString.c_str(),
625               python::return_value_policy<python::manage_new_object>());
626 
627   docString =
628       "Construct a molecule from a TPL block.\n\n\
629   ARGUMENTS:\n\
630 \n\
631     - fileName: name of the file to read\n\
632 \n\
633     - sanitize: (optional) toggles sanitization of the molecule.\n\
634       Defaults to True.\n\
635 \n\
636     - skipFirstConf: (optional) skips reading the first conformer.\n\
637       Defaults to False.\n\
638       This should be set to True when reading TPLs written by \n\
639       the CombiCode.\n\
640 \n\
641   RETURNS:\n\
642 \n\
643     a Mol object, None on failure.\n\
644 \n";
645   python::def("MolFromTPLBlock", RDKit::MolFromTPLBlock,
646               (python::arg("tplBlock"), python::arg("sanitize") = true,
647                python::arg("skipFirstConf") = false),
648               docString.c_str(),
649               python::return_value_policy<python::manage_new_object>());
650 
651   docString =
652       "Construct a molecule from a Mol file.\n\n\
653   ARGUMENTS:\n\
654 \n\
655     - fileName: name of the file to read\n\
656 \n\
657     - sanitize: (optional) toggles sanitization of the molecule.\n\
658       Defaults to true.\n\
659 \n\
660     - removeHs: (optional) toggles removing hydrogens from the molecule.\n\
661       This only make sense when sanitization is done.\n\
662       Defaults to true.\n\
663 \n\
664     - strictParsing: (optional) if this is false, the parser is more lax about.\n\
665       correctness of the content.\n\
666       Defaults to true.\n\
667 \n\
668   RETURNS:\n\
669 \n\
670     a Mol object, None on failure.\n\
671 \n";
672   python::def(
673       "MolFromMolFile", RDKit::MolFromMolFile,
674       (python::arg("molFileName"), python::arg("sanitize") = true,
675        python::arg("removeHs") = true, python::arg("strictParsing") = true),
676       docString.c_str(),
677       python::return_value_policy<python::manage_new_object>());
678 
679   docString =
680       "Construct a molecule from a Mol block.\n\n\
681   ARGUMENTS:\n\
682 \n\
683     - molBlock: string containing the Mol block\n\
684 \n\
685     - sanitize: (optional) toggles sanitization of the molecule.\n\
686       Defaults to True.\n\
687 \n\
688     - removeHs: (optional) toggles removing hydrogens from the molecule.\n\
689       This only make sense when sanitization is done.\n\
690       Defaults to true.\n\
691 \n\
692     - strictParsing: (optional) if this is false, the parser is more lax about.\n\
693       correctness of the content.\n\
694       Defaults to true.\n\
695 \n\
696   RETURNS:\n\
697 \n\
698     a Mol object, None on failure.\n\
699 \n";
700   python::def(
701       "MolFromMolBlock", RDKit::MolFromMolBlock,
702       (python::arg("molBlock"), python::arg("sanitize") = true,
703        python::arg("removeHs") = true, python::arg("strictParsing") = true),
704       docString.c_str(),
705       python::return_value_policy<python::manage_new_object>());
706 
707   docString =
708       "Construct a molecule from an RDKit-generate SVG string.\n\n\
709   ARGUMENTS:\n\
710 \n\
711     - svg: string containing the SVG data (must include molecule metadata)\n\
712 \n\
713     - sanitize: (optional) toggles sanitization of the molecule.\n\
714       Defaults to True.\n\
715 \n\
716     - removeHs: (optional) toggles removing hydrogens from the molecule.\n\
717       This only make sense when sanitization is done.\n\
718       Defaults to true.\n\
719 \n\
720   RETURNS:\n\
721 \n\
722     a Mol object, None on failure.\n\
723 \n\
724   NOTE: this functionality should be considered beta.\n\
725 \n";
726   python::def("MolFromRDKitSVG", RDKit::MolFromSVG,
727               (python::arg("molBlock"), python::arg("sanitize") = true,
728                python::arg("removeHs") = true),
729               docString.c_str(),
730               python::return_value_policy<python::manage_new_object>());
731 
732   docString =
733       "Construct a molecule from a Tripos Mol2 file.\n\n\
734   NOTE:\n\
735     The parser expects the atom-typing scheme used by Corina.\n\
736     Atom types from Tripos' dbtranslate are less supported.\n\
737     Other atom typing schemes are unlikely to work.\n\
738 \n\
739   ARGUMENTS:\n                                  \
740 \n\
741     - fileName: name of the file to read\n\
742 \n\
743     - sanitize: (optional) toggles sanitization of the molecule.\n\
744       Defaults to true.\n\
745 \n\
746     - removeHs: (optional) toggles removing hydrogens from the molecule.\n\
747       This only make sense when sanitization is done.\n\
748       Defaults to true.\n\
749 \n\
750     - cleanupSubstructures: (optional) toggles standardizing some \n\
751       substructures found in mol2 files.\n\
752       Defaults to true.\n\
753 \n\
754   RETURNS:\n\
755 \n\
756     a Mol object, None on failure.\n\
757 \n";
758   python::def("MolFromMol2File", RDKit::MolFromMol2File,
759               (python::arg("molFileName"), python::arg("sanitize") = true,
760                python::arg("removeHs") = true,
761                python::arg("cleanupSubstructures") = true),
762               docString.c_str(),
763               python::return_value_policy<python::manage_new_object>());
764   docString =
765       "Construct a molecule from a Tripos Mol2 block.\n\n\
766   NOTE:\n\
767     The parser expects the atom-typing scheme used by Corina.\n\
768     Atom types from Tripos' dbtranslate are less supported.\n\
769     Other atom typing schemes are unlikely to work.\n\
770 \n\
771   ARGUMENTS:\n\
772 \n\
773     - mol2Block: string containing the Mol2 block\n\
774 \n\
775     - sanitize: (optional) toggles sanitization of the molecule.\n\
776       Defaults to True.\n\
777 \n\
778     - removeHs: (optional) toggles removing hydrogens from the molecule.\n\
779       This only make sense when sanitization is done.\n\
780       Defaults to true.\n\
781 \n\
782     - cleanupSubstructures: (optional) toggles standardizing some \n\
783       substructures found in mol2 files.\n\
784       Defaults to true.\n\
785 \n\
786   RETURNS:\n\
787 \n\
788     a Mol object, None on failure.\n\
789 \n";
790   python::def("MolFromMol2Block", RDKit::MolFromMol2Block,
791               (python::arg("molBlock"), python::arg("sanitize") = true,
792                python::arg("removeHs") = true,
793                python::arg("cleanupSubstructures") = true),
794               docString.c_str(),
795               python::return_value_policy<python::manage_new_object>());
796 
797   docString =
798       "Construct a molecule from a Mol file.\n\n\
799   ARGUMENTS:\n\
800 \n\
801     - fileName: name of the file to read\n\
802 \n\
803     - sanitize: (optional) toggles sanitization of the molecule.\n\
804       Defaults to true.\n\
805 \n\
806     - removeHs: (optional) toggles removing hydrogens from the molecule.\n\
807       This only make sense when sanitization is done.\n\
808       Defaults to true.\n\
809 \n\
810     - strictParsing: (optional) if this is false, the parser is more lax about.\n\
811       correctness of the content.\n\
812       Defaults to true.\n\
813 \n\
814   RETURNS:\n\
815 \n\
816     a Mol object, None on failure.\n\
817 \n";
818   python::def(
819       "MolFromMolFile", RDKit::MolFromMolFile,
820       (python::arg("molFileName"), python::arg("sanitize") = true,
821        python::arg("removeHs") = true, python::arg("strictParsing") = true),
822       docString.c_str(),
823       python::return_value_policy<python::manage_new_object>());
824 
825   docString =
826       "Construct a molecule from a Mol block.\n\n\
827   ARGUMENTS:\n\
828 \n\
829     - molBlock: string containing the Mol block\n\
830 \n\
831     - sanitize: (optional) toggles sanitization of the molecule.\n\
832       Defaults to True.\n\
833 \n\
834     - removeHs: (optional) toggles removing hydrogens from the molecule.\n\
835       This only make sense when sanitization is done.\n\
836       Defaults to true.\n\
837 \n\
838     - strictParsing: (optional) if this is false, the parser is more lax about.\n\
839       correctness of the content.\n\
840       Defaults to true.\n\
841 \n\
842   RETURNS:\n\
843 \n\
844     a Mol object, None on failure.\n\
845 \n";
846   python::def(
847       "MolFromMolBlock", RDKit::MolFromMolBlock,
848       (python::arg("molBlock"), python::arg("sanitize") = true,
849        python::arg("removeHs") = true, python::arg("strictParsing") = true),
850       docString.c_str(),
851       python::return_value_policy<python::manage_new_object>());
852 
853   docString =
854       "Returns a Mol block for a molecule\n\
855   ARGUMENTS:\n\
856 \n\
857     - mol: the molecule\n\
858     - includeStereo: (optional) toggles inclusion of stereochemical\n\
859       information in the output\n\
860     - confId: (optional) selects which conformation to output (-1 = default)\n\
861     - kekulize: (optional) triggers kekulization of the molecule before it's written,\n\
862       as suggested by the MDL spec.\n\
863     - forceV3000 (optional) force generation a V3000 mol block (happens automatically with \n\
864       more than 999 atoms or bonds)\n\
865 \n\
866   RETURNS:\n\
867 \n\
868     a string\n\
869 \n";
870   python::def("MolToMolBlock", RDKit::MolToMolBlock,
871               (python::arg("mol"), python::arg("includeStereo") = true,
872                python::arg("confId") = -1, python::arg("kekulize") = true,
873                python::arg("forceV3000") = false),
874               docString.c_str());
875   docString =
876       "Returns a V3000 Mol block for a molecule\n\
877   ARGUMENTS:\n\
878 \n\
879     - mol: the molecule\n\
880     - includeStereo: (optional) toggles inclusion of stereochemical\n\
881       information in the output\n\
882     - confId: (optional) selects which conformation to output (-1 = default)\n\
883     - kekulize: (optional) triggers kekulization of the molecule before it's written,\n\
884       as suggested by the MDL spec.\n\
885 \n\
886   RETURNS:\n\
887 \n\
888     a string\n\
889 \n";
890   python::def("MolToV3KMolBlock", RDKit::MolToV3KMolBlock,
891               (python::arg("mol"), python::arg("includeStereo") = true,
892                python::arg("confId") = -1, python::arg("kekulize") = true),
893               docString.c_str());
894 
895   docString =
896       "Writes a Mol file for a molecule\n\
897   ARGUMENTS:\n\
898 \n\
899     - mol: the molecule\n\
900     - filename: the file to write to\n\
901     - includeStereo: (optional) toggles inclusion of stereochemical\n\
902       information in the output\n\
903     - confId: (optional) selects which conformation to output (-1 = default)\n\
904     - kekulize: (optional) triggers kekulization of the molecule before it's written,\n\
905       as suggested by the MDL spec.\n\
906     - forceV3000 (optional) force generation a V3000 mol block (happens automatically with \n\
907       more than 999 atoms or bonds)\n\
908 \n\
909   RETURNS:\n\
910 \n\
911     a string\n\
912 \n";
913   python::def(
914       "MolToMolFile", RDKit::MolToMolFile,
915       (python::arg("mol"), python::arg("filename"),
916        python::arg("includeStereo") = true, python::arg("confId") = -1,
917        python::arg("kekulize") = true, python::arg("forceV3000") = false),
918       docString.c_str());
919 
920   docString =
921       "Writes a V3000 Mol file for a molecule\n\
922   ARGUMENTS:\n\
923 \n\
924     - mol: the molecule\n\
925     - filename: the file to write to\n\
926     - includeStereo: (optional) toggles inclusion of stereochemical\n\
927       information in the output\n\
928     - confId: (optional) selects which conformation to output (-1 = default)\n\
929     - kekulize: (optional) triggers kekulization of the molecule before it's written,\n\
930       as suggested by the MDL spec.\n\
931 \n\
932   RETURNS:\n\
933 \n\
934     a string\n\
935 \n";
936   python::def("MolToV3KMolFile", RDKit::MolToV3KMolFile,
937               (python::arg("mol"), python::arg("filename"),
938                python::arg("includeStereo") = true, python::arg("confId") = -1,
939                python::arg("kekulize") = true),
940               docString.c_str());
941 
942   //
943 
944   docString =
945       "Returns a XYZ block for a molecule\n\
946   ARGUMENTS:\n\
947 \n\
948     - mol: the molecule\n\
949     - confId: (optional) selects which conformation to output (-1 = default)\n\
950 \n\
951   RETURNS:\n\
952 \n\
953     a string\n\
954 \n";
955   python::def("MolToXYZBlock", RDKit::MolToXYZBlock,
956               (python::arg("mol"), python::arg("confId") = -1),
957               docString.c_str());
958 
959   docString =
960       "Writes a XYZ file for a molecule\n\
961   ARGUMENTS:\n\
962 \n\
963     - mol: the molecule\n\
964     - filename: the file to write to\n\
965     - confId: (optional) selects which conformation to output (-1 = default)\n\
966 \n";
967   python::def(
968       "MolToXYZFile", RDKit::MolToXYZFile,
969       (python::arg("mol"), python::arg("filename"), python::arg("confId") = -1),
970       docString.c_str());
971 
972   //
973 
974   python::class_<RDKit::SmilesParserParams, boost::noncopyable>(
975       "SmilesParserParams", "Parameters controlling SMILES Parsing")
976       .def_readwrite("maxIterations", &RDKit::SmilesParserParams::debugParse,
977                      "controls the amount of debugging information produced")
978       .def_readwrite("parseName", &RDKit::SmilesParserParams::parseName,
979                      "controls whether or not the molecule name is also parsed")
980       .def_readwrite(
981           "allowCXSMILES", &RDKit::SmilesParserParams::allowCXSMILES,
982           "controls whether or not the CXSMILES extensions are parsed")
983       .def_readwrite("strictCXSMILES",
984                      &RDKit::SmilesParserParams::strictCXSMILES,
985                      "controls whether or not problems in CXSMILES parsing "
986                      "causes molecule parsing to fail")
987       .def_readwrite("sanitize", &RDKit::SmilesParserParams::sanitize,
988                      "controls whether or not the molecule is sanitized before "
989                      "being returned")
990       .def_readwrite("removeHs", &RDKit::SmilesParserParams::removeHs,
991                      "controls whether or not Hs are removed before the "
992                      "molecule is returned")
993       .def_readwrite("useLegacyStereo",
994                      &RDKit::SmilesParserParams::useLegacyStereo,
995                      "controls whether or not the legacy stereochemistry "
996                      "perception code is used");
997   docString =
998       "Construct a molecule from a SMILES string.\n\n\
999      ARGUMENTS:\n\
1000    \n\
1001        - SMILES: the smiles string\n\
1002    \n\
1003        - params: used to provide optional parameters for the SMILES parsing\n\
1004    \n\
1005      RETURNS:\n\
1006    \n\
1007        a Mol object, None on failure.\n\
1008    \n";
1009   python::def("MolFromSmiles", MolFromSmilesHelper,
1010               (python::arg("SMILES"), python::arg("params")), docString.c_str(),
1011               python::return_value_policy<python::manage_new_object>());
1012 
1013   docString =
1014       "Construct a molecule from a SMILES string.\n\n\
1015   ARGUMENTS:\n\
1016 \n\
1017     - SMILES: the smiles string\n\
1018 \n\
1019     - sanitize: (optional) toggles sanitization of the molecule.\n\
1020       Defaults to True.\n\
1021 \n\
1022     - replacements: (optional) a dictionary of replacement strings (see below)\n\
1023       Defaults to {}.\n\
1024 \n\
1025   RETURNS:\n\
1026 \n\
1027     a Mol object, None on failure.\n\
1028 \n\
1029    The optional replacements dict can be used to do string substitution of abbreviations \n\
1030    in the input SMILES. The set of substitutions is repeatedly looped through until \n\
1031    the string no longer changes. It is the responsibility of the caller to make sure \n\
1032    that substitutions results in legal and sensible SMILES. \n\
1033  \n\
1034    Examples of replacements: \n\
1035  \n\
1036      CC{Q}C with {'{Q}':'OCCO'} -> CCOCCOC  \n\n\
1037      C{A}C{Q}C with {'{Q}':'OCCO', '{A}':'C1(CC1)'} -> CC1(CC1)COCCOC  \n\n\
1038      C{A}C{Q}C with {'{Q}':'{X}CC{X}', '{A}':'C1CC1', '{X}':'N'} -> CC1CC1CNCCNC  \n\n\
1039 \n";
1040   python::def("MolFromSmiles", RDKit::MolFromSmiles,
1041               (python::arg("SMILES"), python::arg("sanitize") = true,
1042                python::arg("replacements") = python::dict()),
1043               docString.c_str(),
1044               python::return_value_policy<python::manage_new_object>());
1045   docString = "Construct an atom from a SMILES string";
1046   python::def("AtomFromSmiles", SmilesToAtom, python::arg("SMILES"),
1047               docString.c_str(),
1048               python::return_value_policy<python::manage_new_object>());
1049   docString = "Construct a bond from a SMILES string";
1050   python::def("BondFromSmiles", SmilesToBond, python::arg("SMILES"),
1051               docString.c_str(),
1052               python::return_value_policy<python::manage_new_object>());
1053 
1054   docString =
1055       "Construct a molecule from a SMARTS string.\n\n\
1056   ARGUMENTS:\n\
1057 \n\
1058     - SMARTS: the smarts string\n\
1059 \n\
1060     - mergeHs: (optional) toggles the merging of explicit Hs in the query into the attached\n\
1061       atoms.  So, for example, 'C[H]' becomes '[C;!H0]'.\n\
1062       Defaults to 0.\n\
1063 \n\
1064     - replacements: (optional) a dictionary of replacement strings (see below)\n\
1065       Defaults to {}. See the documentation for MolFromSmiles for an explanation.\n\
1066 \n\
1067   RETURNS:\n\
1068 \n\
1069     a Mol object, None on failure.\n\
1070 \n";
1071   python::def("MolFromSmarts", RDKit::MolFromSmarts,
1072               (python::arg("SMARTS"), python::arg("mergeHs") = false,
1073                python::arg("replacements") = python::dict()),
1074               docString.c_str(),
1075               python::return_value_policy<python::manage_new_object>());
1076   docString = "Construct an atom from a SMARTS string";
1077   python::def("AtomFromSmarts", SmartsToAtom, python::arg("SMARTS"),
1078               docString.c_str(),
1079               python::return_value_policy<python::manage_new_object>());
1080   docString = "Construct a bond from a SMARTS string";
1081   python::def("BondFromSmarts", SmartsToBond, python::arg("SMILES"),
1082               docString.c_str(),
1083               python::return_value_policy<python::manage_new_object>());
1084 
1085   docString =
1086       "Returns the canonical SMILES string for a molecule\n\
1087   ARGUMENTS:\n\
1088 \n\
1089     - mol: the molecule\n\
1090     - isomericSmiles: (optional) include information about stereochemistry in\n\
1091       the SMILES.  Defaults to true.\n\
1092     - kekuleSmiles: (optional) use the Kekule form (no aromatic bonds) in\n\
1093       the SMILES.  Defaults to false.\n\
1094     - rootedAtAtom: (optional) if non-negative, this forces the SMILES \n\
1095       to start at a particular atom. Defaults to -1.\n\
1096     - canonical: (optional) if false no attempt will be made to canonicalize\n\
1097       the molecule. Defaults to true.\n\
1098     - allBondsExplicit: (optional) if true, all bond orders will be explicitly indicated\n\
1099       in the output SMILES. Defaults to false.\n\
1100     - allHsExplicit: (optional) if true, all H counts will be explicitly indicated\n\
1101       in the output SMILES. Defaults to false.\n\
1102 \n\
1103   RETURNS:\n\
1104 \n\
1105     a string\n\
1106 \n";
1107   python::def(
1108       "MolToSmiles", RDKit::MolToSmiles,
1109       (python::arg("mol"), python::arg("isomericSmiles") = true,
1110        python::arg("kekuleSmiles") = false, python::arg("rootedAtAtom") = -1,
1111        python::arg("canonical") = true, python::arg("allBondsExplicit") = false,
1112        python::arg("allHsExplicit") = false, python::arg("doRandom") = false),
1113       docString.c_str());
1114 
1115   docString =
1116       "Returns the canonical SMILES string for a fragment of a molecule\n\
1117   ARGUMENTS:\n\
1118 \n\
1119     - mol: the molecule\n\
1120     - atomsToUse : a list of atoms to include in the fragment\n\
1121     - bondsToUse : (optional) a list of bonds to include in the fragment\n\
1122       if not provided, all bonds between the atoms provided\n\
1123       will be included.\n\
1124     - atomSymbols : (optional) a list with the symbols to use for the atoms\n\
1125       in the SMILES. This should have be mol.GetNumAtoms() long.\n\
1126     - bondSymbols : (optional) a list with the symbols to use for the bonds\n\
1127       in the SMILES. This should have be mol.GetNumBonds() long.\n\
1128     - isomericSmiles: (optional) include information about stereochemistry in\n\
1129       the SMILES.  Defaults to true.\n\
1130     - kekuleSmiles: (optional) use the Kekule form (no aromatic bonds) in\n\
1131       the SMILES.  Defaults to false.\n\
1132     - rootedAtAtom: (optional) if non-negative, this forces the SMILES \n\
1133       to start at a particular atom. Defaults to -1.\n\
1134     - canonical: (optional) if false no attempt will be made to canonicalize\n\
1135       the molecule. Defaults to true.\n\
1136     - allBondsExplicit: (optional) if true, all bond orders will be explicitly indicated\n\
1137       in the output SMILES. Defaults to false.\n\
1138     - allHsExplicit: (optional) if true, all H counts will be explicitly indicated\n\
1139       in the output SMILES. Defaults to false.\n\
1140     - doRandom: (optional) if true, randomized the DFS transversal graph,\n\
1141       so we can generate random smiles. Defaults to false.\n\
1142 \n\
1143   RETURNS:\n\
1144 \n\
1145     a string\n\
1146 \n";
1147   python::def(
1148       "MolFragmentToSmiles", MolFragmentToSmilesHelper<smilesfrag_gen>,
1149       (python::arg("mol"), python::arg("atomsToUse"),
1150        python::arg("bondsToUse") = 0, python::arg("atomSymbols") = 0,
1151        python::arg("bondSymbols") = 0, python::arg("isomericSmiles") = true,
1152        python::arg("kekuleSmiles") = false, python::arg("rootedAtAtom") = -1,
1153        python::arg("canonical") = true, python::arg("allBondsExplicit") = false,
1154        python::arg("allHsExplicit") = false),
1155       docString.c_str());
1156 
1157   docString =
1158       "Returns the CXSMILES string for a molecule\n\
1159   ARGUMENTS:\n\
1160 \n\
1161     - mol: the molecule\n\
1162     - isomericSmiles: (optional) include information about stereochemistry in\n\
1163       the SMILES.  Defaults to true.\n\
1164     - kekuleSmiles: (optional) use the Kekule form (no aromatic bonds) in\n\
1165       the SMILES.  Defaults to false.\n\
1166     - rootedAtAtom: (optional) if non-negative, this forces the SMILES \n\
1167       to start at a particular atom. Defaults to -1.\n\
1168     - canonical: (optional) if false no attempt will be made to canonicalize\n\
1169       the molecule. Defaults to true.\n\
1170     - allBondsExplicit: (optional) if true, all bond orders will be explicitly indicated\n\
1171       in the output SMILES. Defaults to false.\n\
1172     - allHsExplicit: (optional) if true, all H counts will be explicitly indicated\n\
1173       in the output SMILES. Defaults to false.\n\
1174 \n\
1175   RETURNS:\n\
1176 \n\
1177     a string\n\
1178 \n";
1179   python::def(
1180       "MolToCXSmiles", RDKit::MolToCXSmiles,
1181       (python::arg("mol"), python::arg("isomericSmiles") = true,
1182        python::arg("kekuleSmiles") = false, python::arg("rootedAtAtom") = -1,
1183        python::arg("canonical") = true, python::arg("allBondsExplicit") = false,
1184        python::arg("allHsExplicit") = false, python::arg("doRandom") = false),
1185       docString.c_str());
1186 
1187   docString =
1188       "Returns the CXSMILES string for a fragment of a molecule\n\
1189   ARGUMENTS:\n\
1190 \n\
1191     - mol: the molecule\n\
1192     - atomsToUse : a list of atoms to include in the fragment\n\
1193     - bondsToUse : (optional) a list of bonds to include in the fragment\n\
1194       if not provided, all bonds between the atoms provided\n\
1195       will be included.\n\
1196     - atomSymbols : (optional) a list with the symbols to use for the atoms\n\
1197       in the SMILES. This should have be mol.GetNumAtoms() long.\n\
1198     - bondSymbols : (optional) a list with the symbols to use for the bonds\n\
1199       in the SMILES. This should have be mol.GetNumBonds() long.\n\
1200     - isomericSmiles: (optional) include information about stereochemistry in\n\
1201       the SMILES.  Defaults to true.\n\
1202     - kekuleSmiles: (optional) use the Kekule form (no aromatic bonds) in\n\
1203       the SMILES.  Defaults to false.\n\
1204     - rootedAtAtom: (optional) if non-negative, this forces the SMILES \n\
1205       to start at a particular atom. Defaults to -1.\n\
1206     - canonical: (optional) if false no attempt will be made to canonicalize\n\
1207       the molecule. Defaults to true.\n\
1208     - allBondsExplicit: (optional) if true, all bond orders will be explicitly indicated\n\
1209       in the output SMILES. Defaults to false.\n\
1210     - allHsExplicit: (optional) if true, all H counts will be explicitly indicated\n\
1211       in the output SMILES. Defaults to false.\n\
1212     - doRandom: (optional) if true, randomized the DFS transversal graph,\n\
1213       so we can generate random smiles. Defaults to false.\n\
1214 \n\
1215   RETURNS:\n\
1216 \n\
1217     a string\n\
1218 \n";
1219   python::def(
1220       "MolFragmentToCXSmiles", MolFragmentToSmilesHelper<cxsmilesfrag_gen>,
1221       (python::arg("mol"), python::arg("atomsToUse"),
1222        python::arg("bondsToUse") = 0, python::arg("atomSymbols") = 0,
1223        python::arg("bondSymbols") = 0, python::arg("isomericSmiles") = true,
1224        python::arg("kekuleSmiles") = false, python::arg("rootedAtAtom") = -1,
1225        python::arg("canonical") = true, python::arg("allBondsExplicit") = false,
1226        python::arg("allHsExplicit") = false),
1227       docString.c_str());
1228 
1229   docString =
1230       "Returns a SMARTS string for a molecule\n\
1231   ARGUMENTS:\n\
1232 \n\
1233     - mol: the molecule\n\
1234     - isomericSmiles: (optional) include information about stereochemistry in\n\
1235       the SMARTS.  Defaults to true.\n\
1236 \n\
1237   RETURNS:\n\
1238 \n\
1239     a string\n\
1240 \n";
1241   python::def("MolToSmarts", RDKit::MolToSmarts,
1242               (python::arg("mol"), python::arg("isomericSmiles") = true),
1243               docString.c_str());
1244 
1245   docString =
1246       "Returns a SMARTS string for a fragment of a molecule\n\
1247   ARGUMENTS:\n\
1248 \n\
1249     - mol: the molecule\n\
1250     - atomsToUse: indices of atoms to include in the SMARTS string\n\
1251     - bondsToUse: indices of bonds to include in the SMARTS string (optional)\n\
1252     - isomericSmarts: (optional) include information about stereochemistry in\n\
1253       the SMARTS.  Defaults to true.\n\
1254 \n\
1255   RETURNS:\n\
1256 \n\
1257     a string\n\
1258 \n";
1259   python::def(
1260       "MolFragmentToSmarts", molFragmentToSmarts,
1261       (python::arg("mol"), python::arg("atomsToUse"),
1262        python::arg("bondsToUse") = 0, python::arg("isomericSmarts") = true),
1263       docString.c_str());
1264 
1265   docString =
1266       "Writes a molecule to a TPL file.\n\n\
1267   ARGUMENTS:\n\
1268 \n\
1269     - mol: the molecule\n\
1270     - fileName: name of the file to write\n\
1271     - partialChargeProp: name of the property to use for partial charges\n\
1272       Defaults to '_GasteigerCharge'.\n\
1273     - writeFirstConfTwice: Defaults to False.\n\
1274       This should be set to True when writing TPLs to be read by \n\
1275       the CombiCode.\n\
1276 \n";
1277   python::def("MolToTPLFile", RDKit::MolToTPLFile,
1278               (python::arg("mol"), python::arg("fileName"),
1279                python::arg("partialChargeProp") = "_GasteigerCharge",
1280                python::arg("writeFirstConfTwice") = false),
1281               docString.c_str());
1282 
1283   docString =
1284       "Returns the Tpl block for a molecule.\n\n\
1285   ARGUMENTS:\n\
1286 \n\
1287     - mol: the molecule\n\
1288     - partialChargeProp: name of the property to use for partial charges\n\
1289       Defaults to '_GasteigerCharge'.\n\
1290     - writeFirstConfTwice: Defaults to False.\n\
1291       This should be set to True when writing TPLs to be read by \n\
1292       the CombiCode.\n\
1293 \n\
1294   RETURNS:\n\
1295 \n\
1296     a string\n\
1297 \n";
1298   python::def("MolToTPLBlock", RDKit::MolToTPLText,
1299               (python::arg("mol"),
1300                python::arg("partialChargeProp") = "_GasteigerCharge",
1301                python::arg("writeFirstConfTwice") = false),
1302               docString.c_str());
1303 
1304   docString =
1305       "Construct a molecule from a PDB file.\n\n\
1306   ARGUMENTS:\n\
1307 \n\
1308     - fileName: name of the file to read\n\
1309 \n\
1310     - sanitize: (optional) toggles sanitization of the molecule.\n\
1311       Defaults to true.\n\
1312 \n\
1313     - removeHs: (optional) toggles removing hydrogens from the molecule.\n\
1314       This only make sense when sanitization is done.\n\
1315       Defaults to true.\n\
1316 \n\
1317     - flavor: (optional) \n\
1318 \n\
1319     - proximityBonding: (optional) toggles automatic proximity bonding\n\
1320 \n\
1321   RETURNS:\n\
1322 \n\
1323     a Mol object, None on failure.\n\
1324 \n";
1325   python::def("MolFromPDBFile", RDKit::MolFromPDBFile,
1326               (python::arg("molFileName"), python::arg("sanitize") = true,
1327                python::arg("removeHs") = true, python::arg("flavor") = 0,
1328                python::arg("proximityBonding") = true),
1329               docString.c_str(),
1330               python::return_value_policy<python::manage_new_object>());
1331 
1332   docString =
1333       "Construct a molecule from a PDB block.\n\n\
1334   ARGUMENTS:\n\
1335 \n\
1336     - molBlock: string containing the PDB block\n\
1337 \n\
1338     - sanitize: (optional) toggles sanitization of the molecule.\n\
1339       Defaults to True.\n\
1340 \n\
1341     - removeHs: (optional) toggles removing hydrogens from the molecule.\n\
1342       This only make sense when sanitization is done.\n\
1343       Defaults to true.\n\
1344 \n\
1345     - flavor: (optional) \n\
1346 \n\
1347     - proximityBonding: (optional) toggles automatic proximity bonding\n\
1348 \n\
1349   RETURNS:\n\
1350 \n\
1351     a Mol object, None on failure.\n\
1352 \n";
1353   python::def("MolFromPDBBlock", RDKit::MolFromPDBBlock,
1354               (python::arg("molBlock"), python::arg("sanitize") = true,
1355                python::arg("removeHs") = true, python::arg("flavor") = 0,
1356                python::arg("proximityBonding") = true),
1357               docString.c_str(),
1358               python::return_value_policy<python::manage_new_object>());
1359 
1360   docString =
1361       "Returns a PDB block for a molecule\n\
1362   ARGUMENTS:\n\
1363 \n\
1364     - mol: the molecule\n\
1365     - confId: (optional) selects which conformation to output (-1 = default)\n\
1366     - flavor: (optional) \n\
1367             - flavor & 1 : Write MODEL/ENDMDL lines around each record \n\
1368             - flavor & 2 : Don't write any CONECT records \n\
1369             - flavor & 4 : Write CONECT records in both directions \n\
1370             - flavor & 8 : Don't use multiple CONECTs to encode bond order \n\
1371             - flavor & 16 : Write MASTER record \n\
1372             - flavor & 32 : Write TER record \n\
1373 \n\
1374   RETURNS:\n\
1375 \n\
1376     a string\n\
1377 \n";
1378   python::def("MolToPDBBlock", RDKit::MolToPDBBlock,
1379               (python::arg("mol"), python::arg("confId") = -1,
1380                python::arg("flavor") = 0),
1381               docString.c_str());
1382   docString =
1383       "Writes a PDB file for a molecule\n\
1384   ARGUMENTS:\n\
1385 \n\
1386     - mol: the molecule\n\
1387     - filename: name of the file to write\n\
1388     - confId: (optional) selects which conformation to output (-1 = default)\n\
1389     - flavor: (optional) \n\
1390             - flavor & 1 : Write MODEL/ENDMDL lines around each record \n\
1391             - flavor & 2 : Don't write any CONECT records \n\
1392             - flavor & 4 : Write CONECT records in both directions \n\
1393             - flavor & 8 : Don't use multiple CONECTs to encode bond order \n\
1394             - flavor & 16 : Write MASTER record \n\
1395             - flavor & 32 : Write TER record \n\
1396 \n\
1397   RETURNS:\n\
1398 \n\
1399     a string\n\
1400 \n";
1401   python::def("MolToPDBFile", RDKit::MolToPDBFile,
1402               (python::arg("mol"), python::arg("filename"),
1403                python::arg("confId") = -1, python::arg("flavor") = 0),
1404               docString.c_str());
1405 
1406   docString =
1407       "Construct a molecule from a sequence string (currently only supports peptides).\n\n\
1408   ARGUMENTS:\n\
1409 \n\
1410     - text: string containing the sequence\n\
1411 \n\
1412     - sanitize: (optional) toggles sanitization of the molecule.\n\
1413       Defaults to True.\n\
1414 \n\
1415     - flavor: (optional)\n\
1416         - 0 Protein, L amino acids (default)\n\
1417         - 1 Protein, D amino acids\n\
1418         - 2 RNA, no cap\n\
1419         - 3 RNA, 5' cap\n\
1420         - 4 RNA, 3' cap\n\
1421         - 5 RNA, both caps\n\
1422         - 6 DNA, no cap\n\
1423         - 7 DNA, 5' cap\n\
1424         - 8 DNA, 3' cap\n\
1425         - 9 DNA, both caps\n\
1426 \n\
1427   RETURNS:\n\
1428 \n\
1429     a Mol object, None on failure.\n\
1430 \n";
1431   python::def("MolFromSequence", RDKit::MolFromSequence,
1432               (python::arg("text"), python::arg("sanitize") = true,
1433                python::arg("flavor") = 0),
1434               docString.c_str(),
1435               python::return_value_policy<python::manage_new_object>());
1436   docString =
1437       "Returns the sequence string for a molecule\n\
1438   ARGUMENTS:\n\
1439 \n\
1440     - mol: the molecule\n\
1441 \n\
1442   NOTE: the molecule should contain monomer information in AtomMonomerInfo structures \n\
1443 \n\
1444   RETURNS:\n\
1445 \n\
1446     a string\n\
1447 \n";
1448   python::def("MolToSequence", RDKit::MolToSequence, (python::arg("mol")),
1449               docString.c_str());
1450 
1451   docString =
1452       "Construct a molecule from a FASTA string (currently only supports peptides).\n\n\
1453   ARGUMENTS:\n\
1454 \n\
1455     - text: string containing the FASTA\n\
1456 \n\
1457     - sanitize: (optional) toggles sanitization of the molecule.\n\
1458       Defaults to True.\n\
1459 \n\
1460 - flavor: (optional)\n\
1461     - 0 Protein, L amino acids (default)\n\
1462     - 1 Protein, D amino acids\n\
1463     - 2 RNA, no cap\n\
1464     - 3 RNA, 5' cap\n\
1465     - 4 RNA, 3' cap\n\
1466     - 5 RNA, both caps\n\
1467     - 6 DNA, no cap\n\
1468     - 7 DNA, 5' cap\n\
1469     - 8 DNA, 3' cap\n\
1470     - 9 DNA, both caps\n\
1471   RETURNS:\n\
1472 \n\
1473     a Mol object, None on failure.\n\
1474 \n";
1475   python::def("MolFromFASTA", RDKit::MolFromFASTA,
1476               (python::arg("text"), python::arg("sanitize") = true,
1477                python::arg("flavor") = 0),
1478               docString.c_str(),
1479               python::return_value_policy<python::manage_new_object>());
1480   docString =
1481       "Returns the FASTA string for a molecule\n\
1482   ARGUMENTS:\n\
1483 \n\
1484     - mol: the molecule\n\
1485 \n\
1486   NOTE: the molecule should contain monomer information in AtomMonomerInfo structures \n\
1487 \n\
1488   RETURNS:\n\
1489 \n\
1490     a string\n\
1491 \n";
1492   python::def("MolToFASTA", RDKit::MolToFASTA, (python::arg("mol")),
1493               docString.c_str());
1494 
1495   docString =
1496       "Construct a molecule from a HELM string (currently only supports peptides).\n\n\
1497   ARGUMENTS:\n\
1498 \n\
1499     - text: string containing the HELM\n\
1500 \n\
1501     - sanitize: (optional) toggles sanitization of the molecule.\n\
1502       Defaults to true.\n\
1503 \n\
1504   RETURNS:\n\
1505 \n\
1506     a Mol object, None on failure.\n\
1507 \n";
1508   python::def("MolFromHELM", RDKit::MolFromHELM,
1509               (python::arg("text"), python::arg("sanitize") = true),
1510               docString.c_str(),
1511               python::return_value_policy<python::manage_new_object>());
1512   docString =
1513       "Returns the HELM string for a molecule\n\
1514   ARGUMENTS:\n\
1515 \n\
1516     - mol: the molecule\n\
1517 \n\
1518   NOTE: the molecule should contain monomer information in AtomMonomerInfo structures \n\
1519 \n\
1520   RETURNS:\n\
1521 \n\
1522     a string\n\
1523 \n";
1524   python::def("MolToHELM", RDKit::MolToHELM, (python::arg("mol")),
1525               docString.c_str());
1526 
1527   docString =
1528       "Returns the canonical atom ranking for each atom of a molecule fragment.\n\
1529   If breakTies is False, this returns the symmetry class for each atom.  The symmetry\n\
1530   class is used by the canonicalization routines to type each atom based on the whole\n\
1531   chemistry of the molecular graph.  Any atom with the same rank (symmetry class) is\n\
1532   indistinguishable.  For example:\n\
1533 \n\
1534     >>> mol = MolFromSmiles('C1NCN1')\n\
1535     >>> list(CanonicalRankAtoms(mol, breakTies=False))\n\
1536     [0,1,0,1]\n\
1537 \n\
1538   In this case the carbons have the same symmetry class and the nitrogens have the same\n\
1539   symmetry class.  From the perspective of the Molecular Graph, they are identical.\n\
1540 \n\
1541   ARGUMENTS:\n\
1542 \n\
1543     - mol: the molecule\n\
1544     - breakTies: (optional) force breaking of ranked ties [default=True]\n\
1545     - includeChirality: (optional) use chiral information when computing rank [default=True]\n\
1546     - includeIsotopes: (optional) use isotope information when computing rank [default=True]\n\
1547 \n\
1548   RETURNS:\n\
1549 \n\
1550     a string\n\
1551 \n";
1552   python::def("CanonicalRankAtoms", CanonicalRankAtoms,
1553               (python::arg("mol"), python::arg("breakTies") = true,
1554                python::arg("includeChirality") = true,
1555                python::arg("includeIsotopes") = true),
1556               docString.c_str());
1557 
1558   docString =
1559       "Returns the canonical atom ranking for each atom of a molecule fragment\n\
1560   See help(CanonicalRankAtoms) for more information.\n\
1561 \n\
1562    >>> mol = MolFromSmiles('C1NCN1.C1NCN1')\n\
1563    >>> list(CanonicalRankAtomsInFragment(mol, atomsToUse=range(0,4), breakTies=False))\n\
1564    [0,1,0,1,-1,-1,-1,-1]\n\
1565    >>> list(CanonicalRankAtomsInFragment(mol, atomsToUse=range(4,8), breakTies=False))\n\
1566    [-1,-1,-1,-1,0,1,0,1]\n\
1567 \n\
1568   ARGUMENTS:\n\
1569 \n\
1570     - mol: the molecule\n\
1571     - atomsToUse : a list of atoms to include in the fragment\n\
1572     - bondsToUse : (optional) a list of bonds to include in the fragment\n\
1573       if not provided, all bonds between the atoms provided\n\
1574       will be included.\n\
1575     - atomSymbols : (optional) a list with the symbols to use for the atoms\n\
1576       in the SMILES. This should have be mol.GetNumAtoms() long.\n\
1577     - breakTies: (optional) force breaking of ranked ties\n\
1578     - includeChirality: (optional) use chiral information when computing rank [default=True]\n\
1579     - includeIsotopes: (optional) use isotope information when computing rank [default=True]\n\
1580 \n\
1581   RETURNS:\n\
1582 \n\
1583     a string\n\
1584 \n";
1585   python::def(
1586       "CanonicalRankAtomsInFragment", CanonicalRankAtomsInFragment,
1587       (python::arg("mol"), python::arg("atomsToUse"),
1588        python::arg("bondsToUse") = 0, python::arg("atomSymbols") = 0,
1589        python::arg("breakTies") = true, python::arg("includeChirality") = true,
1590        python::arg("includeIsotopes") = true),
1591       docString.c_str());
1592 
1593   python::def(
1594       "CreateAtomIntPropertyList", FileParserUtils::createAtomIntPropertyList,
1595       (python::arg("mol"), python::arg("propName"),
1596        python::arg("missingValueMarker") = "", python::arg("lineSize") = 190),
1597       "creates a list property on the molecule from individual atom property "
1598       "values");
1599   python::def(
1600       "CreateAtomDoublePropertyList",
1601       FileParserUtils::createAtomDoublePropertyList,
1602       (python::arg("mol"), python::arg("propName"),
1603        python::arg("missingValueMarker") = "", python::arg("lineSize") = 190),
1604       "creates a list property on the molecule from individual atom property "
1605       "values");
1606   python::def(
1607       "CreateAtomBoolPropertyList", FileParserUtils::createAtomBoolPropertyList,
1608       (python::arg("mol"), python::arg("propName"),
1609        python::arg("missingValueMarker") = "", python::arg("lineSize") = 190),
1610       "creates a list property on the molecule from individual atom property "
1611       "values");
1612   python::def(
1613       "CreateAtomStringPropertyList",
1614       FileParserUtils::createAtomStringPropertyList,
1615       (python::arg("mol"), python::arg("propName"),
1616        python::arg("missingValueMarker") = "", python::arg("lineSize") = 190),
1617       "creates a list property on the molecule from individual atom property "
1618       "values");
1619 
1620   python::def(
1621       "MolToRandomSmilesVect", RDKit::MolToRandomSmilesHelper,
1622       (python::arg("mol"), python::arg("numSmiles"),
1623        python::arg("randomSeed") = 0, python::arg("isomericSmiles") = true,
1624        python::arg("kekuleSmiles") = false,
1625        python::arg("allBondsExplicit") = false,
1626        python::arg("allHsExplicit") = false),
1627       "returns a list of SMILES generated using the randomSmiles algorithm");
1628 
1629   docString =
1630       R"DOC(Construct a molecule from metadata in a PNG string.
1631 
1632      ARGUMENTS:
1633 
1634        - png: the PNG string
1635 
1636        - params: used to provide optional parameters for the metadata parsing
1637 
1638      RETURNS:
1639        a Mol object, None on failure.
1640   )DOC";
1641   python::def("MolFromPNGString", MolFromPNGString,
1642               (python::arg("png"), python::arg("params") = python::object()),
1643               docString.c_str(),
1644               python::return_value_policy<python::manage_new_object>());
1645 
1646   docString =
1647       R"DOC(Construct a molecule from metadata in a PNG file.
1648 
1649      ARGUMENTS:
1650 
1651        - filename: the PNG filename
1652 
1653        - params: used to provide optional parameters for the metadata parsing
1654 
1655      RETURNS:
1656        a Mol object, None on failure.)DOC";
1657   python::def(
1658       "MolFromPNGFile", MolFromPNGFile,
1659       (python::arg("filename"), python::arg("params") = python::object()),
1660       docString.c_str(),
1661       python::return_value_policy<python::manage_new_object>());
1662 
1663   python::def("MolsFromPNGString", MolsFromPNGString,
1664               (python::arg("png"), python::arg("tag") = PNGData::pklTag,
1665                python::arg("params") = python::object()),
1666               "returns a tuple of molecules constructed from the PNG string");
1667   python::def("MolsFromPNGFile", MolsFromPNGFile,
1668               (python::arg("filename"), python::arg("tag") = PNGData::pklTag,
1669                python::arg("params") = python::object()),
1670               "returns a tuple of molecules constructed from the PNG file");
1671 
1672   docString =
1673       R"DOC(Adds molecular metadata to PNG data read from a file.
1674 
1675      ARGUMENTS:
1676 
1677        - mol: the molecule
1678 
1679        - filename: the PNG filename
1680 
1681        - includePkl: include the RDKit's internal binary format in the output
1682 
1683        - includeSmiles: include CXSmiles in the output
1684 
1685        - includeMol: include CTAB (Mol) in the output
1686 
1687      RETURNS:
1688        the updated PNG data)DOC";
1689   python::def(
1690       "MolMetadataToPNGFile", addMolToPNGFileHelper,
1691       (python::arg("mol"), python::arg("filename"),
1692        python::arg("includePkl") = true, python::arg("includeSmiles") = true,
1693        python::arg("includeMol") = false),
1694       docString.c_str());
1695 
1696   docString =
1697       R"DOC(Adds molecular metadata to a PNG string.
1698 
1699      ARGUMENTS:
1700 
1701        - mol: the molecule
1702 
1703        - png: the PNG string
1704 
1705        - includePkl: include the RDKit's internal binary format in the output
1706 
1707        - includeSmiles: include CXSmiles in the output
1708 
1709        - includeMol: include CTAB (Mol) in the output
1710 
1711      RETURNS:
1712        the updated PNG data)DOC";
1713   python::def(
1714       "MolMetadataToPNGString", addMolToPNGStringHelper,
1715       (python::arg("mol"), python::arg("png"), python::arg("includePkl") = true,
1716        python::arg("includeSmiles") = true, python::arg("includeMol") = false),
1717       docString.c_str());
1718 
1719   docString =
1720       R"DOC(Adds metadata to PNG data read from a file.
1721 
1722      ARGUMENTS:
1723 
1724        - metadata: dict with the metadata to be written
1725                    (keys and values should be strings)
1726 
1727        - filename: the PNG filename
1728 
1729      RETURNS:
1730        the updated PNG data)DOC";
1731   python::def(
1732       "AddMetadataToPNGFile", addMetadataToPNGFileHelper,
1733       (python::arg("metadata"), python::arg("filename")),
1734       docString.c_str());
1735 
1736   docString =
1737       R"DOC(Adds metadata to a PNG string.
1738 
1739      ARGUMENTS:
1740 
1741        - metadata: dict with the metadata to be written
1742                    (keys and values should be strings)
1743 
1744        - png: the PNG string
1745 
1746      RETURNS:
1747        the updated PNG data)DOC";
1748   python::def(
1749       "AddMetadataToPNGString", addMetadataToPNGStringHelper,
1750       (python::arg("metadata"), python::arg("png")),
1751       docString.c_str());
1752 
1753   python::def(
1754       "MetadataFromPNGFile", MetadataFromPNGFile,
1755       (python::arg("filename")),
1756       "Returns a dict with all metadata from the PNG file. Keys are strings, values are bytes.");
1757 
1758   python::def(
1759       "MetadataFromPNGString", MetadataFromPNGString,
1760       (python::arg("png")),
1761       "Returns a dict with all metadata from the PNG string. Keys are strings, values are bytes.");
1762 
1763 
1764 
1765 /********************************************************
1766  * MolSupplier stuff
1767  *******************************************************/
1768 #ifdef SUPPORT_COMPRESSED_SUPPLIERS
1769   wrap_compressedsdsupplier();
1770 #endif
1771   wrap_sdsupplier();
1772   wrap_forwardsdsupplier();
1773   wrap_tdtsupplier();
1774   wrap_smisupplier();
1775 #ifdef RDK_BUILD_MAEPARSER_SUPPORT
1776   wrap_maesupplier();
1777 #endif
1778   // wrap_pdbsupplier();
1779 
1780   /********************************************************
1781    * MolWriter stuff
1782    *******************************************************/
1783   wrap_smiwriter();
1784   wrap_sdwriter();
1785   wrap_tdtwriter();
1786   wrap_pdbwriter();
1787 
1788 #ifdef RDK_THREADSAFE_SSS
1789   /********************************************************
1790    * MultithreadedMolWriter stuff
1791    *******************************************************/
1792   wrap_multiSmiSupplier();
1793   wrap_multiSDSupplier();
1794 #endif
1795 }
1796