1 //
2 //  Copyright (C) 2003-2021  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 
11 #define NO_IMPORT_ARRAY
12 #include <RDBoost/python.h>
13 #include <string>
14 
15 // ours
16 #include <GraphMol/FileParsers/MolSupplier.h>
17 #include <GraphMol/RDKitBase.h>
18 #include <RDGeneral/FileParseException.h>
19 #include "MolSupplier.h"
20 #include "ContextManagers.h"
21 
22 namespace python = boost::python;
23 
24 namespace RDKit {
25 
SmilesSupplierFromText(std::string text,std::string delimiter=" ",int smilesColumn=0,int nameColumn=1,bool titleLine=true,bool sanitize=true)26 SmilesMolSupplier *SmilesSupplierFromText(
27     std::string text, std::string delimiter = " ", int smilesColumn = 0,
28     int nameColumn = 1, bool titleLine = true, bool sanitize = true) {
29   auto *res = new SmilesMolSupplier();
30   res->setData(text, delimiter, smilesColumn, nameColumn, titleLine, sanitize);
31   return res;
32 }
33 
34 std::string smilesMolSupplierClassDoc =
35     "A class which supplies molecules from a text file.\n\
36 \n\
37   Usage examples:\n\
38 \n\
39     1) Lazy evaluation: the molecules are not constructed until we ask for them:\n\n\
40        >>> suppl = SmilesMolSupplier('in.smi')\n\
41        >>> for mol in suppl:\n\
42        ...    mol.GetNumAtoms()\n\
43 \n\
44     2) Lazy evaluation 2:\n\n\
45        >>> suppl = SmilesMolSupplier('in.smi')\n\
46        >>> mol1 = next(suppl)\n\
47        >>> mol2 = next(suppl)\n\
48        >>> suppl.reset()\n\
49        >>> mol3 = next(suppl)\n\
50        # mol3 and mol1 are the same:\n\
51        >>> MolToSmiles(mol3)==MolToSmiles(mol1)\n\
52 \n\
53     3) Random Access:  all molecules are constructed as soon as we ask for the\n\
54        length:\n\n\
55        >>> suppl = SmilesMolSupplier('in.smi')\n\
56        >>> nMols = len(suppl)\n\
57        >>> for i in range(nMols):\n\
58        ...   suppl[i].GetNumAtoms()\n\
59 \n\
60   If the input file has a title line and more than two columns (smiles and id), the\n\
61   additional columns will be used to set properties on each molecule.  The properties\n\
62   are accessible using the mol.GetProp(propName) method.\n\
63 \n";
64 
65 std::string smsDocStr =
66     "Constructor\n\n\
67   ARGUMENTS: \n\
68 \n\
69     - fileName: name of the file to be read\n\
70 \n\
71     - delimiter: (optional) text delimiter (a string).  Defauts to ' '.\n\
72 \n\
73     - smilesColumn: (optional) index of the column containing the SMILES\n\
74       data.  Defaults to 0.\n\
75 \n\
76     - nameColumn: (optional) index of the column containing molecule names.\n\
77       Defaults to 1.\n\
78 \n\
79     - titleLine: (optional) set this toggle if the file contains a title line.\n\
80       Defaults to 1.\n\
81 \n\
82     - sanitize: (optional) toggles sanitization of molecules as they are read.\n\
83       Defaults to 1.\n\
84 \n";
85 struct smimolsup_wrap {
wrapRDKit::smimolsup_wrap86   static void wrap() {
87     python::class_<SmilesMolSupplier, boost::noncopyable>(
88         "SmilesMolSupplier", smilesMolSupplierClassDoc.c_str(),
89         python::init<std::string, std::string, int, int, bool, bool>(
90             (python::arg("data"), python::arg("delimiter") = " ",
91              python::arg("smilesColumn") = 0, python::arg("nameColumn") = 1,
92              python::arg("titleLine") = true, python::arg("sanitize") = true),
93             smsDocStr.c_str()))
94         .def(python::init<>())
95         .def("__enter__", &MolIOEnter<SmilesMolSupplier>,
96              python::return_internal_reference<>())
97         .def("__exit__", &MolIOExit<SmilesMolSupplier>)
98         .def("__iter__", &MolSupplIter<SmilesMolSupplier>,
99              python::return_internal_reference<1>())
100         .def("__next__", &MolSupplNext<SmilesMolSupplier>,
101              "Returns the next molecule in the file.  Raises _StopIteration_ "
102              "on EOF.\n",
103              python::return_value_policy<python::manage_new_object>())
104         .def("__getitem__", &MolSupplGetItem<SmilesMolSupplier>,
105              python::return_value_policy<python::manage_new_object>())
106         .def("reset", &SmilesMolSupplier::reset,
107              "Resets our position in the file to the beginning.\n")
108         .def("__len__", &SmilesMolSupplier::length)
109         .def("SetData", &SmilesMolSupplier::setData,
110              "Sets the text to be parsed",
111              (python::arg("self"), python::arg("data"),
112               python::arg("delimiter") = " ", python::arg("smilesColumn") = 0,
113               python::arg("nameColumn") = 1, python::arg("titleLine") = true,
114               python::arg("sanitize") = true))
115         .def("GetItemText", &SmilesMolSupplier::getItemText,
116              "returns the text for an item",
117              (python::arg("self"), python::arg("index")));
118 
119     python::def(
120         "SmilesMolSupplierFromText", SmilesSupplierFromText,
121         (python::arg("text"), python::arg("delimiter") = " ",
122          python::arg("smilesColumn") = 0, python::arg("nameColumn") = 1,
123          python::arg("titleLine") = true, python::arg("sanitize") = true),
124         python::return_value_policy<python::manage_new_object>());
125   }
126 };
127 }  // namespace RDKit
128 
wrap_smisupplier()129 void wrap_smisupplier() { RDKit::smimolsup_wrap::wrap(); }
130