Compare 6f23b2c ... +5 ... b6ed6f5

No flags found

Use flags to group coverage reports by test type, project and/or folders.
Then setup custom commit statuses and notifications for each flag.

e.g., #unittest #integration

#production #enterprise

#frontend #backend

Learn more about Codecov Flags here.


@@ -1,8 +1,8 @@
Loading
1 1
"""
2 2
adapters.py
3 3
4 -
This script contains adapters or the structure for atoms, molecules and
5 -
substructure searches.
4 +
This script contains adapters or the structure for
5 +
molecules, atoms, and bonds.
6 6
Our chemical perception code is designed to be independent of the users
7 7
cheminformatics packages. For each cheminformatics package we support we
8 8
will provide classes following the structure in these adapters.
@@ -12,7 +12,7 @@
Loading
12 12
Caitlin C. Bannan <bannanc@uci.edu>, Mobley Group, University of California Irvine
13 13
"""
14 14
15 -
from abc import ABC, abstractmethod
15 +
from abc import ABC, abstractmethod, abstractclassmethod
16 16
17 17
18 18
# =======================================
@@ -21,12 +21,30 @@
Loading
21 21
22 22
class MolAdapter(ABC):
23 23
    """
24 -
    Template class for wrapping a molecule object
25 -
    from a given cheminformatics package into a chemper Mol.
26 -
    chemper `Mol` are initiated from the reference package molecule object.
27 -
    The class MolFromSmiles initiates a chemper Mol from a SMILES string.
28 -
    Currently we support OpenEye toolkits and RDKit
24 +
    This is a ChemPer wrapper for a molecule from
25 +
    one of the cheminformatics toolkits.
26 +
    ChemPer molecules are initiated from the reference package molecule object.
27 +
    Currently we support OpenEye and RDKit toolkits.
28 +
29 +
    Attributes
30 +
    ----------
31 +
    mol : toolkit Mol
32 +
          Mol object from the reference cheminformatics toolkit
29 33
    """
34 +
    @abstractclassmethod
35 +
    def from_smiles(cls, smiles):
36 +
        """
37 +
        Creates a ChemPer Mol form a SMILES string
38 +
39 +
        Parameters
40 +
        ----------
41 +
        smiles : str
42 +
                 SMILES used to create molecule with wrapped toolkit
43 +
44 +
        Returns
45 +
        -------
46 +
        Mol : ChemPer Mol
47 +
        """
30 48
    @abstractmethod
31 49
    def set_aromaticity_mdl(self):
32 50
        """
@@ -39,7 +57,7 @@
Loading
39 57
        """
40 58
        Returns
41 59
        -------
42 -
        atom_list: list of chemper Atoms
60 +
        atom_list : list[ChemPer Atoms]
43 61
            list of all atoms in the molecule
44 62
        """
45 63
        pass
@@ -49,12 +67,12 @@
Loading
49 67
        """
50 68
        Parameters
51 69
        ----------
52 -
        idx: int
70 +
        idx : int
53 71
            atom index
54 72
55 73
        Returns
56 74
        -------
57 -
        atom: chemper Atom object
75 +
        atom : ChemPer Atom
58 76
            atom with index idx
59 77
        """
60 78
        pass
@@ -64,7 +82,7 @@
Loading
64 82
        """
65 83
        Returns
66 84
        -------
67 -
        bond_list: list of chemper Bonds
85 +
        bond_list : list[ChemPer Bonds]
68 86
            list of all bonds in the molecule
69 87
        """
70 88
        pass
@@ -74,12 +92,12 @@
Loading
74 92
        """
75 93
        Parameters
76 94
        ----------
77 -
        idx: ing
95 +
        idx: int
78 96
            bond index
79 97
80 98
        Returns
81 99
        -------
82 -
        bond: chemper Bond object
100 +
        bond: ChemPer Bond
83 101
            bond with index idx
84 102
        """
85 103
        pass
@@ -88,15 +106,16 @@
Loading
88 106
    def get_bond_by_atoms(self, atom1, atom2):
89 107
        """
90 108
        Finds a bond between two atoms
109 +
91 110
        Parameters
92 111
        ----------
93 -
        atom1: chemper Atom object
94 -
        atom2: chemper Atom object
112 +
        atom1 : ChemPer Atom
113 +
        atom2 : ChemPer Atom
95 114
96 115
        Returns
97 116
        -------
98 -
        bond: chemper Bond object or None
99 -
            if atoms are connected returns bond otherwise None
117 +
        bond : ChemPer Bond or None
118 +
            If atoms are connected returns bond otherwise None
100 119
        """
101 120
        pass
102 121
@@ -109,13 +128,13 @@
Loading
109 128
110 129
        Parameters
111 130
        ----------
112 -
        smirks: str
131 +
        smirks : str
113 132
            SMIRKS pattern with indexed atoms (:n)
114 133
115 134
        Returns
116 135
        -------
117 -
        matches: list of dictionaries
118 -
            dictionary for each match with the form {smirks index: atom index}
136 +
        matches : list[match dictionary]
137 +
            match dictionaries have the form {smirks index: atom index}
119 138
        """
120 139
        pass
121 140
@@ -136,18 +155,21 @@
Loading
136 155
137 156
class AtomAdapter(ABC):
138 157
    """
139 -
    Template class for wrapping an atom object
140 -
    from a given cheminformatics package into a chemper Atom.
141 -
    These are always initiated from a reference package Atom object.
142 -
    Currently we support OpenEye toolkits and RDKit
158 +
    This is a ChemPer wrapper for an atom from
159 +
    one of the cheminformatics toolkits.
160 +
    ChemPer Atoms are initiated from the reference package object.
161 +
    Currently we support OpenEye and RDKit toolkits.
162 +
163 +
    Attributes
164 +
    ----------
165 +
    atom : Atom from reference toolkit
143 166
    """
144 -
145 167
    @abstractmethod
146 168
    def atomic_number(self):
147 169
        """
148 170
        Returns
149 171
        -------
150 -
        atomic_number: int
172 +
        atomic_number : int
151 173
            atomic number for the atom
152 174
        """
153 175
        pass
@@ -157,8 +179,8 @@
Loading
157 179
        """
158 180
        Returns
159 181
        -------
160 -
        degree: int
161 -
            degree or number of explicit bonds around the atom
182 +
        degree : int
183 +
            degree or number of explicit bond orders around the atom
162 184
        """
163 185
        pass
164 186
@@ -167,8 +189,8 @@
Loading
167 189
        """
168 190
        Returns
169 191
        -------
170 -
        connectivity: int
171 -
            connectivity or total number of bonds around the atom
192 +
        connectivity : int
193 +
            connectivity or total number of bonds (regardless of order) around the atom
172 194
        """
173 195
        pass
174 196
@@ -177,8 +199,8 @@
Loading
177 199
        """
178 200
        Returns
179 201
        -------
180 -
        valence: int
181 -
            the atoms valence
202 +
        valence : int
203 +
            the atoms valence (equivalent to degree when all bonds are explicit)
182 204
        """
183 205
        pass
184 206
@@ -187,7 +209,7 @@
Loading
187 209
        """
188 210
        Returns
189 211
        -------
190 -
        formal_charge: int
212 +
        formal_charge : int
191 213
            the atom's formal charge
192 214
        """
193 215
        pass
@@ -197,7 +219,7 @@
Loading
197 219
        """
198 220
        Returns
199 221
        -------
200 -
        H_count: int
222 +
        H_count : int
201 223
            total number of hydrogen atoms connected to this Atom
202 224
        """
203 225
        pass
@@ -207,7 +229,7 @@
Loading
207 229
        """
208 230
        Returns
209 231
        -------
210 -
        min_ring_size: int
232 +
        min_ring_size : int
211 233
            size of the smallest ring this atom is a part of
212 234
        """
213 235
        pass
@@ -217,7 +239,7 @@
Loading
217 239
        """
218 240
        Returns
219 241
        -------
220 -
        ring_connectivity: int
242 +
        ring_connectivity : int
221 243
            number of bonds on the atom that are a part of a ring
222 244
        """
223 245
        pass
@@ -227,7 +249,7 @@
Loading
227 249
        """
228 250
        Returns
229 251
        -------
230 -
        is_aromatic: boolean
252 +
        is_aromatic : boolean
231 253
            True if the atom is aromatic otherwise False
232 254
        """
233 255
        pass
@@ -237,7 +259,7 @@
Loading
237 259
        """
238 260
        Returns
239 261
        -------
240 -
        index: int
262 +
        index : int
241 263
            atom index in its molecule
242 264
        """
243 265
        pass
@@ -247,13 +269,13 @@
Loading
247 269
        """
248 270
        Parameters
249 271
        ----------
250 -
        atom2: chemper Atom object
251 -
            atom to check if it is connected to this atom
272 +
        atom2 : ChemPer Atom
273 +
            Atom to check if it is bonded to this atom
252 274
253 275
        Returns
254 276
        -------
255 -
        connected: boolean
256 -
            True if atom2 is a direct neighbor or atom1
277 +
        connected : boolean
278 +
            True if atom2 is a bonded to atom1
257 279
        """
258 280
        pass
259 281
@@ -262,8 +284,8 @@
Loading
262 284
        """
263 285
        Returns
264 286
        -------
265 -
        neighbors: list of chemper Atoms
266 -
            atoms that are one bond away from this atom
287 +
        neighbors : list[ChemPer Atoms]
288 +
            Atoms that are one bond away from this atom
267 289
        """
268 290
        pass
269 291
@@ -272,20 +294,20 @@
Loading
272 294
        """
273 295
        Returns
274 296
        -------
275 -
        bonds: list of chemper Bonds
276 -
            bonds connected to this atom
297 +
        bonds : list[ChemPer Bonds]
298 +
            Bonds connected to this atom
277 299
        """
278 300
        pass
279 301
280 302
    @abstractmethod
281 303
    def get_molecule(self):
282 304
        """
283 -
        Extracts the parent molecule this atom is in
305 +
        Extracts the parent molecule this atom is from.
284 306
285 307
        Returns
286 308
        -------
287 -
        mol: chemper Mol
288 -
            molecule this atom is stored in
309 +
        mol : ChemPer Mol
310 +
            Molecule this atom is stored in
289 311
        """
290 312
        pass
291 313
@@ -296,18 +318,21 @@
Loading
296 318
297 319
class BondAdapter(ABC):
298 320
    """
299 -
    Template class for wrapping a bond object
300 -
    from a given cheminformatics package into a chemper Bond.
301 -
    These are always initiated from a reference package Bond object.
302 -
    Currently we support OpenEye toolkits and RDKit
321 +
    This is a ChemPer wrapper for a bond from
322 +
    one of the cheminformatics toolkits.
323 +
    ChemPer Bonds are initiated from the reference package object.
324 +
    Currently we support OpenEye and RDKit toolkits.
325 +
326 +
    Attributes
327 +
    ----------
328 +
    bond : Bond from reference class
303 329
    """
304 -
305 330
    @abstractmethod
306 331
    def get_order(self):
307 332
        """
308 333
        Returns
309 334
        -------
310 -
        order: int or float
335 +
        order : int or float
311 336
            This is the absolute order, returns 1.5 if bond is aromatic
312 337
        """
313 338
        pass
@@ -317,8 +342,8 @@
Loading
317 342
        """
318 343
        Returns
319 344
        -------
320 -
        atoms: list of chemper Atoms
321 -
            the two atoms connected by this bond
345 +
        atoms : list[ChemPer Atoms]
346 +
            The two atoms connected by this bond
322 347
        """
323 348
        pass
324 349
@@ -327,7 +352,7 @@
Loading
327 352
        """
328 353
        Returns
329 354
        -------
330 -
        is_ring: boolean
355 +
        is_ring : boolean
331 356
            True if bond is a part of a ring, otherwise False
332 357
        """
333 358
        pass
@@ -337,7 +362,7 @@
Loading
337 362
        """
338 363
        Returns
339 364
        -------
340 -
        is_aromatic: boolean
365 +
        is_aromatic : boolean
341 366
            True if it is an aromatic bond
342 367
        """
343 368
        pass
@@ -347,7 +372,7 @@
Loading
347 372
        """
348 373
        Returns
349 374
        -------
350 -
        is_single: boolean
375 +
        is_single : boolean
351 376
            True if it is a single bond
352 377
        """
353 378
        pass
@@ -357,7 +382,7 @@
Loading
357 382
        """
358 383
        Returns
359 384
        -------
360 -
        is_double: boolean
385 +
        is_double : boolean
361 386
            True if it is a double bond
362 387
        """
363 388
        pass
@@ -367,20 +392,20 @@
Loading
367 392
        """
368 393
        Returns
369 394
        -------
370 -
        is_triple: boolean
395 +
        is_triple : boolean
371 396
            True if it is a triple bond
372 397
        """
373 398
        pass
374 399
375 400
    @abstractmethod
376 401
    def get_molecule(self):
377 402
        """
378 -
        Extracts the parent molecule this bond is in
403 +
        Extracts the parent molecule this bond is from
379 404
380 405
        Returns
381 406
        -------
382 -
        mol: chemper Mol
383 -
            molecule this bond is stored in
407 +
        mol : ChemPer Mol
408 +
            Molecule this bond is stored in
384 409
        """
385 410
        pass
386 411
@@ -389,7 +414,7 @@
Loading
389 414
        """
390 415
        Returns
391 416
        -------
392 -
        index: int
417 +
        index : int
393 418
            index of this bond in its parent molecule
394 419
        """
395 420
        pass

@@ -283,11 +283,11 @@
Loading
283 283
284 284
    Attributes
285 285
    ----------
286 -
    current_smirks: list of tuples
286 +
    current_smirks : list of tuples
287 287
                    current SMIRKS patterns in the form (label, smirks)
288 -
    mols: list of chemper molecules
288 +
    mols : list of chemper molecules
289 289
          molecules being used to reduce the input SMIRKS
290 -
    cluster_dict: dictionary
290 +
    cluster_dict : dictionary
291 291
                  Dictionary specifying typing using current SMIRKS in the form:
292 292
                  {mol_idx:
293 293
                        { (tuple of atom indices): label } }

@@ -18,12 +18,13 @@
Loading
18 18
import os
19 19
from chemper.chemper_utils import get_data_path
20 20
from chemper.mol_toolkits.adapters import MolAdapter, BondAdapter, AtomAdapter
21 -
# define default_toolkit:
21 +
22 +
# identify which toolkits are available
23 +
HAS_OE = False
24 +
HAS_RDK = False
22 25
try:
23 -
    from openeye.oechem import OEChemIsLicensed
24 -
    if not OEChemIsLicensed():
25 -
        HAS_OE = False
26 -
    else:
26 +
    from openeye import oechem
27 +
    if oechem.OEChemIsLicensed():
27 28
        from chemper.mol_toolkits import cp_openeye
28 29
        HAS_OE = True
29 30
except ImportError:
@@ -36,102 +37,95 @@
Loading
36 37
except ImportError:
37 38
    HAS_RDK = False
38 39
39 -
if not HAS_OE and not HAS_RDK:
40 -
    raise ImportWarning("No Cheminformatics toolkit was found."\
41 -
                        " currently chemper supports OpenEye and RDKit")
42 -
43 -
44 -
def Mol(mol):
45 -
    """
46 -
47 -
    Parameters
48 -
    ----------
49 -
    mol - a molecule object from any supported toolkit
50 -
51 -
    Returns
52 -
    -------
53 -
    mol - a chemper Mol
54 -
55 -
    """
56 -
    # if it is already a chemper molecule return as is
57 -
    if isinstance(mol, MolAdapter):
58 -
        return mol
59 -
60 -
    # check if this is an Openeye molecule
61 -
    if HAS_OE and isinstance(mol, oechem.OEMolBase):
62 -
        return cp_openeye.Mol(mol)
63 -
64 -
    # check if it is an RDK molecule
65 -
    if HAS_RDK and isinstance(mol, Chem.rdchem.Mol):
66 -
        return cp_rdk.Mol(mol)
67 -
68 -
    err_msg = """
69 -
    Your molecule has the type %s.
70 -
    Currently chemper only supports OpenEye and RDKit.
71 -
    To add support to a new toolkit submit an issue on GitHub at
72 -
    github.com/MobleyLab/chemper
73 -
    """
74 -
    raise TypeError(err_msg % type(mol))
75 -
76 -
77 -
def Atom(atom):
78 -
    """
79 -
80 -
    Parameters
81 -
    ----------
82 -
    atom - Atom object from any supported toolkit
83 -
84 -
    Returns
85 -
    -------
86 -
    atom - a chemper Atom object
87 -
88 -
    """
89 -
    if isinstance(atom, AtomAdapter):
90 -
        return atom
91 -
92 -
    if HAS_OE and isinstance(atom, oechem.OEAtomBase):
93 -
        return cp_openeye.Atom(atom)
94 -
95 -
    if HAS_RDK and isinstance(atom, Chem.rdchem.Atom):
96 -
        return cp_rdk.Atom(atom)
97 -
98 -
    err_msg = """
99 -
    Your atom has the type %s.
100 -
    Currently chemper only supports OpenEye and RDKit.
101 -
    To add support to a new toolkit submit an issue on GitHub at
102 -
    github.com/MobleyLab/chemper
103 -
    """
104 -
    raise TypeError(err_msg % type(atom))
105 40
41 +
# ======================================================================
42 +
# Find super Mol/Atom/Bond classes
43 +
# ======================================================================
106 44
107 -
def Bond(bond):
108 -
    """
109 -
110 -
    Parameters
111 -
    ----------
112 -
    bond - Bond object from any supported toolkit
113 -
114 -
    Returns
115 -
    -------
116 -
    bond - a chemper Bond object
117 -
118 -
    """
119 -
    if isinstance(bond, BondAdapter):
120 -
        return bond
121 -
122 -
    if HAS_OE and isinstance(bond, oechem.OEBondBase):
123 -
        return cp_openeye.Bond(bond)
124 -
125 -
    if HAS_RDK and isinstance(bond, Chem.rdchem.Bond):
126 -
        return cp_rdk.Bond(bond)
127 -
128 -
    err_msg = """
129 -
    Your bond has the type %s.
130 -
    Currently chemper only supports OpenEye and RDKit.
131 -
    To add support to a new toolkit submit an issue on GitHub at
132 -
    github.com/MobleyLab/chemper
133 -
    """
134 -
    raise TypeError(err_msg % type(bond))
45 +
if not HAS_OE and not HAS_RDK:
46 +
    raise ImportWarning("No Cheminformatics toolkit was found." \
47 +
                        " currently ChemPer supports OpenEye and RDKit")
48 +
49 +
50 +
class Mol:
51 +
    def __init__(self, mol):
52 +
        # if it is already a chemper molecule return as is
53 +
        if isinstance(mol, MolAdapter):
54 +
            self.mol = mol.mol
55 +
            self.__class__ = mol.__class__
56 +
57 +
        # check if this is an Openeye molecule
58 +
        elif HAS_OE and isinstance(mol, oechem.OEMolBase):
59 +
            self.__class__ = cp_openeye.Mol
60 +
            self.__class__.__init__(self,mol)
61 +
62 +
        # check if it is an RDK molecule
63 +
        elif HAS_RDK and isinstance(mol, Chem.rdchem.Mol):
64 +
            self.__class__ = cp_rdk.Mol
65 +
            self.__class__.__init__(self, mol)
66 +
67 +
        else:
68 +
            err_msg = """
69 +
            Your molecule has the type %s.
70 +
            Currently ChemPer only supports OpenEye and RDKit.
71 +
            To add support to a new toolkit submit an issue on GitHub at
72 +
            github.com/MobleyLab/chemper
73 +
            """
74 +
            raise TypeError(err_msg % type(mol))
75 +
76 +
    @staticmethod
77 +
    def from_smiles(smiles):
78 +
        if HAS_OE:
79 +
            return cp_openeye.Mol.from_smiles(smiles)
80 +
        return cp_rdk.Mol.from_smiles(smiles)
81 +
82 +
class Atom:
83 +
    def __init__(self, atom):
84 +
85 +
        if isinstance(atom, AtomAdapter):
86 +
            self.atom = atom.atom
87 +
            self.__class__ = atom.__class__
88 +
89 +
        elif HAS_OE and isinstance(atom, oechem.OEAtomBase):
90 +
            self.__class__ = cp_openeye.Atom
91 +
            self.__class__.__init__(self, atom)
92 +
93 +
        elif HAS_RDK and isinstance(atom, Chem.rdchem.Atom):
94 +
            self.__class__ = cp_rdk.Atom
95 +
            self.__class__.__init__(self, atom)
96 +
97 +
        else:
98 +
            err_msg = """
99 +
            Your atom has the type %s.
100 +
            Currently ChemPer only supports OpenEye and RDKit.
101 +
            To add support to a new toolkit submit an issue on GitHub at
102 +
            github.com/MobleyLab/chemper
103 +
            """
104 +
            raise TypeError(err_msg % type(atom))
105 +
106 +
107 +
class Bond:
108 +
    def __init__(self, bond):
109 +
        if isinstance(bond, BondAdapter):
110 +
            self.bond = bond.bond
111 +
            self.__class__ = bond.__class__
112 +
113 +
        elif HAS_OE and isinstance(bond, oechem.OEBondBase):
114 +
            self.__class__ = cp_openeye.Bond
115 +
            self.__class__.__init__(self,bond)
116 +
117 +
        elif HAS_RDK and isinstance(bond, Chem.rdchem.Bond):
118 +
            self.__class__ = cp_rdk.Bond
119 +
            self.__class__.__init__(self,bond)
120 +
121 +
        else:
122 +
            err_msg = """
123 +
            Your bond has the type %s.
124 +
            Currently ChemPer only supports OpenEye and RDKit.
125 +
            To add support to a new toolkit submit an issue on GitHub at
126 +
            github.com/MobleyLab/chemper
127 +
            """
128 +
            raise TypeError(err_msg % type(bond))
135 129
136 130
# =======================================
137 131
# check user specifications
@@ -142,16 +136,16 @@
Loading
142 136
143 137
    Parameters
144 138
    ----------
145 -
    toolkit - str
146 -
        'openeye', 'rdkit', or None
147 -
        if None then the toolkit will be picked automatically
139 +
    toolkit : str
140 +
              'openeye', 'rdkit', or None
141 +
              if None then the toolkit will be picked automatically
148 142
149 143
    Returns
150 144
    -------
151 -
    toolkit - str
152 -
    returns the name of the toolkit to be used.
153 -
    If the package isn't available for the specified toolkit
154 -
    then an error is raised instead
145 +
    toolkit : str
146 +
              returns the name of the toolkit to be used.
147 +
              If the package isn't available for the specified toolkit
148 +
              then an error is raised instead
155 149
    """
156 150
    # check for a stable
157 151
    if toolkit is None:
@@ -179,14 +173,14 @@
Loading
179 173
180 174
    Parameters
181 175
    ----------
182 -
    file_name - str
183 -
        path to a molecule file
176 +
    file_name : str
177 +
                path to a molecule file
184 178
185 179
    Returns
186 180
    -------
187 -
    path - str
188 -
        absolute path to a molecule file
189 -
        raises error if file isn't available
181 +
    path : str
182 +
           absolute path to a molecule file
183 +
           raises error if file isn't available
190 184
    """
191 185
    # is it a local file?
192 186
    if os.path.exists(file_name):
@@ -199,54 +193,29 @@
Loading
199 193
200 194
    return path
201 195
202 -
203 -
# ================================================================
204 -
# get molecule from SMILES
205 -
# ================================================================
206 -
207 -
def MolFromSmiles(smiles, toolkit=None):
208 -
    """
209 -
210 -
    Parameters
211 -
    ----------
212 -
    smiles - str
213 -
        SMILES string
214 -
    toolkit - str or None
215 -
        'openeye' or 'rdkit' or None to let chemper pick
216 -
217 -
    Returns
218 -
    -------
219 -
    mol - ChemPer Mol
220 -
    """
221 -
    toolkit = check_toolkit(toolkit)
222 -
    if toolkit.lower() == 'openeye':
223 -
        return cp_openeye.MolFromSmiles(smiles)
224 -
225 -
    return cp_rdk.MolFromSmiles(smiles)
226 -
227 196
# =======================================
228 197
# get molecules from files
229 198
# =======================================
230 199
231 200
def mols_from_mol2(mol2_file, toolkit=None):
232 201
    """
233 -
    Creates a list of chemper Mols from the provided mol2 file
202 +
    Creates a list of ChemPer Mols from the provided mol2 file
234 203
    using a specified or default toolkit
235 204
236 205
    Parameters
237 206
    ----------
238 -
    mol2_file: str
239 -
               path to mol2 file, this can be a relative or absolute path locally
240 -
               or the path to a molecules file stored in chemper at chemper/data/molecules/
241 -
    toolkit: None or str
242 -
             'openeye' or 'rdkit' are the two supported toolkits
243 -
             if None then the first package available (in the order listed here)
244 -
             will be used
207 +
    mol2_file : str
208 +
                path to mol2 file, this can be a relative or absolute path locally
209 +
                or the path to a molecules file stored in ChemPer at chemper/data/molecules/
210 +
    toolkit : None or str
211 +
              'openeye' or 'rdkit' are the two supported toolkits
212 +
              if None then the first package available (in the order listed here)
213 +
              will be used
245 214
246 215
    Returns
247 216
    -------
248 -
    mol2s: list of chemper Mol
249 -
           list of molecules in the provided mol2 file
217 +
    mol2s : list[ChemPer Mol]
218 +
            List of molecules in the provided mol2 file
250 219
    """
251 220
    toolkit = check_toolkit(toolkit)
252 221
    mol2_path = check_mol_file(mol2_file)

@@ -20,108 +20,50 @@
Loading
20 20
# =======================================
21 21
22 22
class Mol(MolAdapter):
23 -
    """
24 -
    Wrapper for RDKMol to create a chemper Mol
25 -
    """
26 23
    def __init__(self, mol):
27 24
        """
25 +
        Create a ChemPer Mol from an RDMol
26 +
28 27
        Parameters
29 28
        ----------
30 -
        mol: openeye RDKMol object
31 -
            openeye molecule to convert to chemper Mol object
29 +
        mol : openeye RDKMol object
30 +
              openeye molecule to convert to ChemPer Mol object
32 31
        """
33 32
        if not isinstance(mol, Chem.rdchem.Mol):
34 33
            raise TypeError("Expecting an rdchem.Mol instead of %s" % type(mol))
35 34
        self.mol = mol
36 35
37 36
    def __str__(self): return self.get_smiles()
38 37
38 +
    @classmethod
39 +
    def from_smiles(cls, smiles):
40 +
        mol = Chem.MolFromSmiles(smiles)
41 +
        if mol is None:
42 +
            raise ValueError('Could not parse SMILES %s' % smiles)
43 +
        cls(Chem.AddHs(mol))
44 +
39 45
    def set_aromaticity_mdl(self):
40 -
        """
41 -
        Sets the aromaticity flags in this molecule to use the MDL model
42 -
        """
43 46
        Chem.SanitizeMol(self.mol, Chem.SANITIZE_ALL^Chem.SANITIZE_SETAROMATICITY)
44 47
        Chem.SetAromaticity(self.mol, Chem.AromaticityModel.AROMATICITY_MDL)
45 48
46 49
    def get_atoms(self):
47 -
        """
48 -
        Returns
49 -
        -------
50 -
        atom_list: list of chemper Atoms
51 -
            list of all atoms in the molecule
52 -
        """
53 50
        return [Atom(a) for a in self.mol.GetAtoms()]
54 51
55 52
    def get_atom_by_index(self, idx):
56 -
        """
57 -
        Parameters
58 -
        ----------
59 -
        idx: int
60 -
            atom index
61 -
62 -
        Returns
63 -
        -------
64 -
        atom: chemper Atom object
65 -
            atom with index idx
66 -
        """
67 53
        return Atom(self.mol.GetAtomWithIdx(idx))
68 54
69 55
    def get_bonds(self):
70 -
        """
71 -
        Returns
72 -
        -------
73 -
        bond_list: list of chemper Bonds
74 -
            list of all bonds in the molecule
75 -
        """
76 56
        return [Bond(b) for b in self.mol.GetBonds()]
77 57
78 58
    def get_bond_by_index(self, idx):
79 -
        """
80 -
        Parameters
81 -
        ----------
82 -
        idx: ing
83 -
            bond index
84 -
85 -
        Returns
86 -
        -------
87 -
        bond: chemper Bond object
88 -
            bond with index idx
89 -
        """
90 59
        return Bond(self.mol.GetBondWithIdx(idx))
91 60
92 61
    def get_bond_by_atoms(self, atom1, atom2):
93 -
        """
94 -
        Finds a bond between two atoms
95 -
        Parameters
96 -
        ----------
97 -
        atom1: chemper Atom object
98 -
        atom2: chemper Atom object
99 -
100 -
        Returns
101 -
        -------
102 -
        bond: chemper Bond object or None
103 -
            if atoms are connected returns bond otherwise None
104 -
        """
105 62
        if not atom1.is_connected_to(atom2):
106 63
            return None
107 64
        return Bond(self.mol.GetBondBetweenAtoms(atom1.get_index(), atom2.get_index()))
108 65
109 66
    def smirks_search(self, smirks):
110 -
        """
111 -
        Performs a substructure search on the molecule with the provided
112 -
        SMIRKS pattern. Note - this function expects SMIRKS patterns with indexed atoms
113 -
        that is with :n for at least some atoms.
114 -
115 -
        Parameters
116 -
        ----------
117 -
        smirks: str
118 -
            SMIRKS pattern with indexed atoms (:n)
119 -
120 -
        Returns
121 -
        -------
122 -
        matches: list of dictionaries
123 -
            dictionary for each match with the form {smirks index: atom index}
124 -
        """
125 67
        cmol = Chem.Mol(self.mol)
126 68
127 69
        matches = list()
@@ -144,47 +86,24 @@
Loading
144 86
        return matches
145 87
146 88
    def get_smiles(self):
147 -
        """
148 -
        Returns
149 -
        -------
150 -
        smiles: str
151 -
            SMILES string for the molecule
152 -
        """
153 89
        smiles = Chem.MolToSmiles(Chem.RemoveHs(self.mol))
154 90
        return smiles
155 91
156 -
class MolFromSmiles(Mol):
157 -
    """
158 -
    Creates a chemper Mol from a smiles string
159 -
    It automatically adds explicit hydrogens.
160 -
    """
161 -
    def __init__(self, smiles):
162 -
        """
163 -
        Parameters
164 -
        ----------
165 -
        smiles: str
166 -
            SMILES string for a molecule
167 -
        """
168 -
        mol = Chem.MolFromSmiles(smiles)
169 -
        if mol is None:
170 -
            raise ValueError('Could not parse SMILES %s' % smiles)
171 -
        Mol.__init__(self, Chem.AddHs(mol))
172 92
173 93
# =======================================
174 94
# Atom Class
175 95
# =======================================
176 96
177 97
178 98
class Atom(AtomAdapter):
179 -
    """
180 -
    Wrapper for RDKAtom to create a chemper Atom
181 -
    """
182 99
    def __init__(self, atom):
183 100
        """
101 +
        Create a ChemPer Atom from an RDAtom
102 +
184 103
        Parameters
185 104
        ----------
186 -
        atom: RDKAtom
187 -
            Atom object from an RDK molecule
105 +
        atom : RDKit Atom
106 +
               Atom object from an RDK molecule
188 107
        """
189 108
        if not isinstance(atom, Chem.rdchem.Atom):
190 109
            raise TypeError("Expecting a rdchem.Atom instead of %s" % type(atom))
@@ -193,76 +112,23 @@
Loading
193 112
194 113
    def __str__(self): return '%i%s' % (self._idx, self.atom.GetSymbol())
195 114
196 -
    def atomic_number(self):
197 -
        """
198 -
        Returns
199 -
        -------
200 -
        atomic_number: int
201 -
            atomic number for the atom
202 -
        """
203 -
        return self.atom.GetAtomicNum()
115 +
    def atomic_number(self): return self.atom.GetAtomicNum()
204 116
205 -
    def degree(self):
206 -
        """
207 -
        Returns
208 -
        -------
209 -
        degree: int
210 -
            degree or number of explicit bonds around the atom
211 -
        """
212 -
        return self.atom.GetDegree()
117 +
    def degree(self): return self.atom.GetDegree()
213 118
214 -
    def connectivity(self):
215 -
        """
216 -
        Returns
217 -
        -------
218 -
        connectivity: int
219 -
            connectivity or total number of bonds around the atom
220 -
        """
221 -
        return self.atom.GetTotalDegree()
119 +
    def connectivity(self): return self.atom.GetTotalDegree()
222 120
223 -
    def valence(self):
224 -
        """
225 -
        Returns
226 -
        -------
227 -
        valence: int
228 -
            the atoms valence
229 -
        """
230 -
        return self.atom.GetTotalValence()
121 +
    def valence(self): return self.atom.GetTotalValence()
231 122
232 -
    def formal_charge(self):
233 -
        """
234 -
        Returns
235 -
        -------
236 -
        formal_charge: int
237 -
            the atom's formal charge
238 -
        """
239 -
        return self.atom.GetFormalCharge()
123 +
    def formal_charge(self): return self.atom.GetFormalCharge()
240 124
241 125
    def hydrogen_count(self):
242 -
        """
243 -
        Returns
244 -
        -------
245 -
        H_count: int
246 -
            total number of hydrogen atoms connected to this Atom
247 -
        """
248 126
        return self.atom.GetTotalNumHs(includeNeighbors=True)
249 127
250 128
    def ring_connectivity(self):
251 -
        """
252 -
        Returns
253 -
        -------
254 -
        ring_connectivity: int
255 -
            number of bonds on the atom that are a part of a ring
256 -
        """
257 129
        return len([b for b in self.atom.GetBonds() if b.IsInRing()])
258 130
259 131
    def min_ring_size(self):
260 -
        """
261 -
        Returns
262 -
        -------
263 -
        min_ring_size: int
264 -
            size of the smallest ring this atom is a part of
265 -
        """
266 132
        if not self.atom.IsInRing():
267 133
            return 0
268 134
        for i in range(10000):
@@ -271,68 +137,23 @@
Loading
271 137
        # TODO: raise exception instead?
272 138
        return 10000
273 139
274 -
    def is_aromatic(self):
275 -
        """
276 -
        Returns
277 -
        -------
278 -
        is_aromatic: boolean
279 -
            True if the atom is aromatic otherwise False
280 -
        """
281 -
        return self.atom.GetIsAromatic()
140 +
    def is_aromatic(self): return self.atom.GetIsAromatic()
282 141
283 -
    def get_index(self):
284 -
        """
285 -
        Returns
286 -
        -------
287 -
        index: int
288 -
            atom index in its molecule
289 -
        """
290 -
        return self._idx
142 +
    def get_index(self): return self._idx
291 143
292 144
    def is_connected_to(self, atom2):
293 -
        """
294 -
        Parameters
295 -
        ----------
296 -
        atom2: chemper Atom object
297 -
            atom to check if it is connected to this atom
298 -
299 -
        Returns
300 -
        -------
301 -
        connected: boolean
302 -
            True if atom2 is a direct neighbor or atom1
303 -
        """
304 145
        if not isinstance(atom2.atom, Chem.rdchem.Atom):
305 146
            return False
306 147
        neighbors = [a.GetIdx() for a in self.atom.GetNeighbors()]
307 148
        return atom2.get_index() in neighbors
308 149
309 150
    def get_neighbors(self):
310 -
        """
311 -
        Returns
312 -
        -------
313 -
        neighbors: list of chemper Atoms
314 -
            atoms that are one bond away from this atom
315 -
        """
316 151
        return [Atom(a) for a in self.atom.GetNeighbors()]
317 152
318 153
    def get_bonds(self):
319 -
        """
320 -
        Returns
321 -
        -------
322 -
        bonds: list of chemper Bonds
323 -
            bonds connected to this atom
324 -
        """
325 154
        return [Bond(b) for b in self.atom.GetBonds()]
326 155
327 156
    def get_molecule(self):
328 -
        """
329 -
        Extracts the parent molecule this atom is in
330 -
331 -
        Returns
332 -
        -------
333 -
        mol: chemper Mol
334 -
            molecule this atom is stored in
335 -
        """
336 157
        mol = Chem.Mol(self.atom.GetOwningMol())
337 158
        return Mol(mol)
338 159
@@ -342,15 +163,14 @@
Loading
342 163
343 164
344 165
class Bond(BondAdapter):
345 -
    """
346 -
    Wrapper for RDKBond to create a chemper Bond
347 -
    """
348 166
    def __init__(self, bond):
349 167
        """
168 +
        Creates a ChemPer Bond from an RDK Bond
169 +
350 170
        Parameters
351 171
        ----------
352 -
        bond: RDKBond
353 -
            Bond object from an RDK molecule
172 +
        bond : RDK Bond
173 +
               Bond object from an RDK molecule
354 174
        """
355 175
        if not isinstance(bond, Chem.rdchem.Bond):
356 176
            raise TypeError("Expecting an rdchem.Bond instead of %s" % type(bond))
@@ -365,119 +185,55 @@
Loading
365 185
        self._order_symbol = orders.get(self._order, '~')
366 186
367 187
        # save atoms in bond
368 -
        self.beginning = Atom(self.bond.GetBeginAtom())
369 -
        self.end = Atom(self.bond.GetEndAtom())
188 +
        self._beginning = Atom(self.bond.GetBeginAtom())
189 +
        self._end = Atom(self.bond.GetEndAtom())
370 190
371 191
    def __str__(self):
372 -
        return "%i %s%s%s" % (self.get_index(), self.beginning,
373 -
                              self._order_symbol, self.end)
192 +
        return "%i %s%s%s" % (self.get_index(), self._beginning,
193 +
                              self._order_symbol, self._end)
374 194
375 -
    def get_order(self):
376 -
        """
377 -
        Returns
378 -
        -------
379 -
        order: int or float
380 -
            This is the absolute order, returns 1.5 if bond is aromatic
381 -
        """
382 -
        return self._order
195 +
    def get_order(self): return self._order
383 196
384 -
    def get_atoms(self):
385 -
        """
386 -
        Returns
387 -
        -------
388 -
        atoms: list of chemper Atoms
389 -
            the two atoms connected by this bond
390 -
        """
391 -
        return [self.beginning, self.end]
197 +
    def get_atoms(self): return [self._beginning, self._end]
392 198
393 -
    def is_ring(self):
394 -
        """
395 -
        Returns
396 -
        -------
397 -
        is_ring: boolean
398 -
            True if bond is a part of a ring, otherwise False
399 -
        """
400 -
        return self.bond.IsInRing()
199 +
    def is_ring(self): return self.bond.IsInRing()
401 200
402 -
    def is_aromatic(self):
403 -
        """
404 -
        Returns
405 -
        -------
406 -
        is_aromatic: boolean
407 -
            True if it is an aromatic bond
408 -
        """
409 -
        return self.bond.GetIsAromatic()
201 +
    def is_aromatic(self): return self.bond.GetIsAromatic()
410 202
411 -
    def is_single(self):
412 -
        """
413 -
        Returns
414 -
        -------
415 -
        is_single: boolean
416 -
            True if it is a single bond
417 -
        """
418 -
        return self._order == 1
203 +
    def is_single(self): return self._order == 1
419 204
420 -
    def is_double(self):
421 -
        """
422 -
        Returns
423 -
        -------
424 -
        is_double: boolean
425 -
            True if it is a double bond
426 -
        """
427 -
        return self._order == 2
205 +
    def is_double(self): return self._order == 2
428 206
429 -
    def is_triple(self):
430 -
        """
431 -
        Returns
432 -
        -------
433 -
        is_triple: boolean
434 -
            True if it is a triple bond
435 -
        """
436 -
        return self._order == 3
207 +
    def is_triple(self): return self._order == 3
437 208
438 209
    def get_molecule(self):
439 -
        """
440 -
        Extracts the parent molecule this bond is in
441 -
442 -
        Returns
443 -
        -------
444 -
        mol: chemper Mol
445 -
            molecule this bond is stored in
446 -
        """
447 210
        mol = Chem.Mol(self.bond.GetOwningMol())
448 211
        return Mol(mol)
449 212
450 -
    def get_index(self):
451 -
        """
452 -
        Returns
453 -
        -------
454 -
        index: int
455 -
            index of this bond in its parent molecule
456 -
        """
457 -
        return self._idx
213 +
    def get_index(self): return self._idx
458 214
459 215
# =====================================================================
460 216
# functions for importing molecules from files
461 217
# =====================================================================
462 218
463 219
def mols_from_mol2(mol2_file):
464 220
    """
465 -
    Parses a mol2 file into chemper molecules using RDKit
221 +
    Parses a mol2 file into ChemPer molecules using RDKit
466 222
467 223
    This is a hack for separating mol2 files taken from a Source Forge discussion here:
468 224
    https://www.mail-archive.com/rdkit-discuss@lists.sourceforge.net/msg01510.html
469 225
    It splits up a mol2 file into blocks and then uses RDKit to parse those blocks
470 226
471 227
    Parameters
472 228
    ----------
473 -
    mol2_file: str
474 -
               relative or absolute path to a mol2 file you want to parse
475 -
               accessible form the current directory
229 +
    mol2_file : str
230 +
                relative or absolute path to a mol2 file you want to parse
231 +
                accessible form the current directory
476 232
477 233
    Returns
478 234
    -------
479 -
    mols: list of chemper Mols
480 -
          list of molecules in the mol2 file as chemper molecules
235 +
    mols : list[ChemPer Mol]
236 +
           list of molecules in the mol2 file as ChemPer molecules
481 237
    """
482 238
    # TODO: check that this works with mol2 files with a single molecule
483 239
    # TODO: figure out if @<TRIPOS>MOLECULE is the only delimiter acceptable in this file type

@@ -409,6 +409,10 @@
Loading
409 409
        return new_atom_storage
410 410
411 411
412 +
# ==============================================================================
413 +
# TODO: Isn't this the same thing as starting with a ChemPerGraph with mols=None
414 +
# and smirks_atoms=None as the default?
415 +
# ==============================================================================
412 416
class ChemPerGraphFromMol(ChemPerGraph):
413 417
    """
414 418
    Creates a ChemPerGraph from a chemper Mol object

Click to load this diff.
Loading diff...

Click to load this diff.
Loading diff...

Learn more Showing 3 files with coverage changes found.

Changes in chemper/mol_toolkits/cp_rdk.py
-46
+46
Loading file...
Changes in chemper/mol_toolkits/__init__.py
-1
+1
Loading file...
Changes in chemper/mol_toolkits/mol_toolkit.py
-7
+7
Loading file...
Files Coverage
chemper -7.72% 81.47%
Project Totals (12 files) 81.47%
Loading