@@ -73,7 +73,7 @@
Loading
73 73
    out_idx = out_list[list_idx]
74 74
    return string[in_idx:out_idx+1], in_idx, out_idx
75 75
76 -
def _convert_embedded_SMIRKS(smirks):
76 +
def _convert_embedded_smirks(smirks):
77 77
    """
78 78
    Converts a SMIRKS string with the $(...) in an atom to the
79 79
    form expected by the environment parser
@@ -81,7 +81,7 @@
Loading
81 81
    smirks = any smirks string, if no $(...) then the original smirks is returned
82 82
83 83
    initial_smirks = "[#1$(*~[#6]):1]"
84 -
    new_smirks = _convert_embedded_SMIRKS(initial_smirks)
84 +
    new_smirks = _convert_embedded_smirks(initial_smirks)
85 85
    # new_smirks = [#1:1]~[#6]
86 86
    """
87 87
    a_out = 0
@@ -114,7 +114,7 @@
Loading
114 114
        # in the latter case the first atom refers the current atom
115 115
        if embedded[1] == '[':
116 116
            first, f_in, f_out = _find_embedded_brackets(embedded, r'\[',r'\]')
117 -
            first = _convert_embedded_SMIRKS(first)
117 +
            first = _convert_embedded_smirks(first)
118 118
            new_atom = atom[:d]+first[1:-1]+atom[p_out+1:]
119 119
            embedded = embedded[f_out+1:]
120 120
            # if embedded is empty between brackets, remove it
@@ -136,7 +136,7 @@
Loading
136 136
            else:
137 137
                new_atom = atom[:d]+atom[p_out+1]
138 138
139 -
        # Look for ring insided embedded SMIRKS "[#6$(*1CCC1)]"
139 +
        # Look for ring inside embedded SMIRKS "[#6$(*1CCC1)]"
140 140
        match = re.match(r'(\d+)', embedded)
141 141
        if match is not None: # embedded starts with an int
142 142
            ring_in = re.findall(r'(\d+)', embedded)[0]
@@ -181,59 +181,61 @@
Loading
181 181
    """Chemical environment abstract base class that matches an atom, bond, angle, etc.
182 182
    """
183 183
    class Atom(object):
184 -
        """Atom representation, which may have some ORtypes and ANDtypes properties.
184 +
        """Atom representation, which may have some or_types and ANDtypes properties.
185 185
186 186
        Attributes
187 187
        ----------
188 -
        ORtypes : list of tuples in the form (base, [list of decorators])
188 +
        or_types : list of tuples in the form (base, [list of decorators])
189 189
            where bases and decorators are both strings
190 190
            The descriptor types that will be combined with logical OR
191 -
        ANDtypes : list of string
191 +
        and_types : list of string
192 192
            The descriptor types  that will be combined with logical AND
193 193
        """
194 -
        def __init__(self, ORtypes = None, ANDtypes = None, index = None, ring = None):
194 +
        def __init__(self, or_types = None, and_types = None, index = 0, ring = None):
195 195
            """Initialize an Atom object with optional descriptors.
196 196
197 197
            Parameters
198 198
            -----------
199 -
            ORtypes: list of tuples for ORbases and ORdecorators,
199 +
            or_types: list of tuples for ORbases and ORdecorators,
200 200
                in the form (base, [list of decorators])
201 201
                optional, default = []
202 -
            ANDtypes: list of str,
202 +
            and_types: list of str
203 203
                strings that will be AND'd together in a SMARTS
204 204
                optional, default = None
205 -
            index : int, optional, default=None
206 -
                If not None, the specified index will be attached as a SMIRKS index (e.g. '[#6:1]')
205 +
            index : int
206 +
                If greater than zero,
207 +
                the specified index will be attached as a SMIRKS index (e.g. '[#6:1]')
208 +
                otherwise, it is only used for accessing atom information
207 209
            ring : int, optional, default = None
208 210
                If not None, the specified ring index will be attached at the end of the atom i.e. '[#6:1]1'
209 211
            """
210 212
            # List of 2 tuples in the form [ (ORbase, ORdecorator), ...]
211 -
            if ORtypes is not None:
212 -
                self.ORtypes = copy.deepcopy(ORtypes)
213 +
            if or_types is not None:
214 +
                self._or_types = copy.deepcopy(or_types)
213 215
            else:
214 -
                self.ORtypes = list()
216 +
                self._or_types = list()
215 217
216 218
            # Set of strings that will be AND'd to the the end
217 -
            if ANDtypes is not None:
218 -
                self.ANDtypes = list(copy.deepcopy(ANDtypes))
219 +
            if and_types is not None:
220 +
                self._and_types = list(copy.deepcopy(and_types))
219 221
            else:
220 -
                self.ANDtypes = list()
222 +
                self._and_types = list()
221 223
222 224
            self.index = index
223 225
            self.ring = ring
224 -
            self._atom = True
226 +
            self.is_atom = True
225 227
226 228
        def is_generic(self):
227 229
            """
228 230
            returns True if there are no decorators on this atom
229 231
            (IMPORTANT: this is newly added and in chemper only as of 8/9/18)
230 232
            """
231 -
            if not self.ORtypes:
232 -
                if not self.ANDtypes:
233 +
            if not self._or_types:
234 +
                if not self._and_types:
233 235
                    return True
234 236
            return False
235 237
236 -
        def asSMARTS(self):
238 +
        def as_smarts(self):
237 239
            """Return the atom representation as SMARTS.
238 240
239 241
            Returns
@@ -245,31 +247,31 @@
Loading
245 247
            smarts = '['
246 248
247 249
            # Add the OR'd features
248 -
            if self.ORtypes:
249 -
                ORList = list()
250 -
                for (base, ORdecorators) in self.ORtypes:
250 +
            if self._or_types:
251 +
                or_list = list()
252 +
                for (base, or_decorators) in self._or_types:
251 253
                    if len(base) > 0 and base[0] == '$':
252 254
                        # after a $base an explicit '&' is necessary
253 -
                        if ORdecorators:
254 -
                            OR = base+'&'+''.join(ORdecorators)
255 +
                        if or_decorators:
256 +
                            or_bit = base + '&' + ''.join(or_decorators)
255 257
                        else:
256 -
                            OR = base
258 +
                            or_bit = base
257 259
                    else: # base doesn't start with $
258 -
                        OR = base+''.join(ORdecorators)
259 -
                    ORList.append(OR)
260 -
                smarts += ','.join(ORList)
260 +
                        or_bit = base + ''.join(or_decorators)
261 +
                    or_list.append(or_bit)
262 +
                smarts += ','.join(or_list)
261 263
            else:
262 264
                smarts += '*'
263 265
264 -
            if len(self.ANDtypes) > 0:
265 -
                smarts += ';' + ';'.join(self.ANDtypes)
266 +
            if len(self._and_types) > 0:
267 +
                smarts += ';' + ';'.join(self._and_types)
266 268
267 269
            if self.ring is not None:
268 270
                return smarts + ']' + str(self.ring)
269 271
            else:
270 272
                return smarts + ']'
271 273
272 -
        def asSMIRKS(self):
274 +
        def as_smirks(self):
273 275
            """Return the atom representation as SMIRKS.
274 276
275 277
            Returns
@@ -277,117 +279,116 @@
Loading
277 279
            smirks : str
278 280
            The SMIRKS string for this atom
279 281
            """
280 -
            smirks = self.asSMARTS()
282 +
            smirks = self.as_smarts()
281 283
282 284
            # No index specified so SMIRKS = SMARTS
283 -
            if self.index is None:
285 +
            if self.index <= 0:
284 286
                return smirks
285 287
286 288
            # Add label to the end of SMARTS
287 -
            else:
288 -
                sub_string, start, end = _find_embedded_brackets(smirks, r'\[',r'\]')
289 -
                if self.ring is not None:
290 -
                    return sub_string[:-1] + ':' + str(self.index) + ']'+str(self.ring)
291 -
                else:
292 -
                    return sub_string[:-1] + ':' + str(self.index) + ']'
289 +
            sub_string, start, end = _find_embedded_brackets(smirks, r'\[', r'\]')
290 +
            end_string = smirks[end:]
291 +
            return sub_string[:-1] + ':' + str(self.index) + end_string
293 292
294 -
        def addORtype(self, ORbase, ORdecorators):
293 +
        def add_or_type(self, or_base, or_decorators):
295 294
            """
296 295
            Adds ORtype to the set for this atom.
297 296
298 297
            Parameters
299 298
            --------
300 -
            ORbase: string, such as '#6'
301 -
            ORdecorators: list of strings, such as ['X4','+0']
299 +
            or_base: string, such as '#6'
300 +
            or_decorators: list of strings, such as ['X4','+0']
302 301
            """
303 -
            ORdecorators = _remove_blanks_repeats(ORdecorators, ['',ORbase])
304 -
            self.ORtypes.append((ORbase, ORdecorators))
302 +
            or_decorators = _remove_blanks_repeats(or_decorators, ['', or_base])
303 +
            self._or_types.append((or_base, or_decorators))
305 304
306 -
        def addANDtype(self, ANDtype):
305 +
        def add_and_type(self, and_type):
307 306
            """
308 307
            Adds ANDtype to the set for this atom.
309 308
310 309
            Parameters
311 310
            --------
312 -
            ANDtype: string
313 -
                added to the list of ANDtypes for this atom
311 +
            and_type: string
312 +
                added to the list of and_types for this atom
314 313
            """
315 -
            self.ANDtypes.append(ANDtype)
316 -
            self.ANDtypes = _remove_blanks_repeats(self.ANDtypes)
314 +
            self._and_types.append(and_type)
315 +
            self._and_types = _remove_blanks_repeats(self._and_types)
317 316
318 -
        def getORtypes(self):
319 -
            """
320 -
            returns a copy of the dictionary of ORtypes for this atom
321 -
            """
322 -
            return copy.deepcopy(self.ORtypes)
317 +
        @property
318 +
        def or_types(self):
319 +
            """Provides the or_types in this atom"""
320 +
            return self._or_types
323 321
324 -
        def setORtypes(self, newORtypes):
322 +
        @or_types.setter
323 +
        def or_types(self, new_or_types):
325 324
            """
326 -
            sets new ORtypes for this atom
325 +
            sets new or_types for this atom
327 326
328 327
            Parameters
329 328
            ----------
330 -
            newORtypes: list of tuples in the form (base, [ORdecorators])
329 +
            new_or_types: list of tuples in the form (base, [ORdecorators])
331 330
                for example: ('#6', ['X4','H0','+0']) --> '#6X4H0+0'
332 331
            """
333 -
            self.ORtypes = list()
334 -
            if newORtypes is not None:
335 -
                for (base, decs) in newORtypes:
332 +
            self._or_types = list()
333 +
            if new_or_types is not None:
334 +
                for (base, decs) in new_or_types:
336 335
                    adjusted_decs = _remove_blanks_repeats(decs, ['', base])
337 -
                    self.ORtypes.append( (base, adjusted_decs) )
336 +
                    self._or_types.append((base, adjusted_decs))
338 337
339 -
        def getANDtypes(self):
338 +
        @property
339 +
        def and_types(self):
340 340
            """
341 -
            returns a copy of the list of ANDtypes for this atom
341 +
            returns a copy of the list of and_types for this atom
342 342
            """
343 -
            return list(copy.deepcopy(self.ANDtypes))
343 +
            return list(copy.deepcopy(self._and_types))
344 344
345 -
        def setANDtypes(self, newANDtypes):
345 +
        @and_types.setter
346 +
        def and_types(self, new_and_types):
346 347
            """
347 -
            sets new ANDtypes for this atom
348 +
            sets new and_types for this atom
348 349
349 350
            Parameters
350 351
            ----------
351 -
            newANDtypes: list of strings
352 +
            new_and_types: list of strings
352 353
                strings that will be AND'd together in a SMARTS
353 354
            """
354 -
            if newANDtypes is None:
355 -
                self.ANDtypes = list()
355 +
            if new_and_types is None:
356 +
                self._and_types = list()
356 357
            else:
357 -
                self.ANDtypes = _remove_blanks_repeats(newANDtypes)
358 +
                self._and_types = _remove_blanks_repeats(new_and_types)
358 359
359 360
    class Bond(Atom):
360 361
        """Bond representation, which may have ORtype and ANDtype descriptors.
361 362
362 363
        Attributes
363 364
        ----------
364 -
        ORtypes : list of tuples of ORbases and ORdecorators
365 +
        or_types : list of tuples of ORbases and ORdecorators
365 366
            in form (base: [list of decorators])
366 367
            The ORtype types that will be combined with logical OR
367 -
        ANDtypes : list of string
368 -
            The ANDtypes that will be combined with logical AND
368 +
        and_types : list of string
369 +
            The and_types that will be combined with logical AND
369 370
370 371
        """
371 372
        # Implementation identical to atoms apart from what is put in the asSMARTS/asSMIRKS strings
372 373
373 -
        def __init__(self, ORtypes = None, ANDtypes = None):
374 +
        def __init__(self, or_types = None, and_types = None, index = 0):
374 375
            """
375 376
            Parameters
376 377
            -----------
377 -
            ORtypes: list of tuples, optional, default = None
378 +
            or_types: list of tuples, optional, default = None
378 379
                tuples have form (base, [ORdecorators])
379 380
                bond descriptors that will be OR'd together in a SMARTS
380 -
            ANDtypes: list of str, optional, default = None
381 +
            and_types: list of str, optional, default = None
381 382
                strings that will be AND'd together in a SMARTS
382 -
            index: integer, default = None
383 +
            index: integer, default = 0
383 384
                This is for book keeping inside environments and will not be shown in SMARTS or SMIRKS
384 385
                example: bond1 in a Bond is the bond between atom1 and atom2
385 386
            """
386 -
            super(ChemicalEnvironment.Bond,self).__init__(ORtypes, ANDtypes, None, None)
387 -
            self._atom = False
387 +
            super(ChemicalEnvironment.Bond,self).__init__(or_types, and_types, index)
388 +
            self.is_atom = False
388 389
            return
389 390
390 -
        def asSMARTS(self):
391 +
        def as_smarts(self):
391 392
            """Return the atom representation as SMARTS.
392 393
393 394
            Returns
@@ -395,20 +396,20 @@
Loading
395 396
            smarts : str
396 397
                The SMARTS string for just this atom
397 398
            """
398 -
            if self.ORtypes:
399 -
                ORcombos = list()
400 -
                for (ORbase, ORdecorators) in self.ORtypes:
401 -
                    ORcombos.append(ORbase+''.join(ORdecorators))
402 -
                smarts = ','.join(ORcombos)
399 +
            if self._or_types:
400 +
                or_combos = list()
401 +
                for (ORbase, ORdecorators) in self._or_types:
402 +
                    or_combos.append(ORbase + ''.join(ORdecorators))
403 +
                smarts = ','.join(or_combos)
403 404
            else:
404 405
                smarts = '~'
405 406
406 -
            if len(self.ANDtypes) > 0:
407 -
                smarts += ';' + ';'.join(self.ANDtypes)
407 +
            if len(self._and_types) > 0:
408 +
                smarts += ';' + ';'.join(self._and_types)
408 409
409 410
            return smarts
410 411
411 -
        def asSMIRKS(self):
412 +
        def as_smirks(self):
412 413
            """
413 414
            Returns
414 415
            --------
@@ -418,23 +419,23 @@
Loading
418 419
            #the same as asSMARTS()
419 420
            #    for consistency asSMARTS() or asSMIRKS() can be called
420 421
            #    for all environment objects
421 -
            return self.asSMARTS()
422 +
            return self.as_smarts()
422 423
423 -
        def getOrder(self):
424 +
        def get_order(self):
424 425
            """
425 426
            Returns a float for the order of this bond
426 -
            for multiple ORtypes or ~ it returns the minimum possible order
427 +
            for multiple or_types or ~ it returns the minimum possible order
427 428
            the intended application is for checking valence around a given atom
428 429
            """
429 -
            # Minimum order for empty ORtypes is 1:
430 -
            if not self.ORtypes:
430 +
            # Minimum order for empty or_types is 1:
431 +
            if not self._or_types:
431 432
                return 1
432 433
433 -
            orderDict = {'~':1.,
434 +
            order_dict = {'~':1.,
434 435
                    '-':1., ':': 1.5, '=':2., '#':3.,
435 436
                    '!-':1.5, '!:':1., '!=':1., '!#':1.}
436 -
            orderList = [orderDict[base] for (base, decor) in self.ORtypes]
437 -
            return min(orderList)
437 +
            order_list = [order_dict.get(base,1) for (base, decor) in self._or_types]
438 +
            return min(order_list)
438 439
439 440
    def __init__(self, smirks = None, label = None, replacements = None):
440 441
        """Initialize a chemical environment abstract base class.
@@ -489,7 +490,7 @@
Loading
489 490
490 491
        if smirks is not None:
491 492
            # Check that it is a valid SMIRKS
492 -
            if not self.isValid(smirks):
493 +
            if not self.is_valid(smirks):
493 494
                raise SMIRKSParsingError("Error Provided SMIRKS ('%s') was \
494 495
not parseable with current toolkit" % smirks)
495 496
@@ -511,9 +512,9 @@
Loading
511 512
                        into a ChemicalEnvironment" % smirks)
512 513
513 514
        # Check that the created Environment is valid
514 -
        if not self.isValid():
515 +
        if not self.is_valid():
515 516
            raise SMIRKSParsingError("Input SMIRKS (%s), converted to %s \
516 -
                    is now invalid" % (smirks, self.asSMIRKS()))
517 +
                    is now invalid" % (smirks, self.as_smirks()))
517 518
518 519
        return
519 520
@@ -554,13 +555,13 @@
Loading
554 555
        """
555 556
        return self._graph.get_edge_data(node1, node2)
556 557
557 -
    def isValid(self, smirks = None):
558 +
    def is_valid(self, smirks = None):
558 559
        """
559 560
        Returns if the environment is valid, that is if it
560 561
        creates a parseable SMIRKS string.
561 562
        """
562 563
        if smirks is None:
563 -
            smirks = self._asSMIRKS()
564 +
            smirks = self._as_smirks()
564 565
        from chemper.chemper_utils import is_valid_smirks
565 566
        return is_valid_smirks(smirks)
566 567
@@ -568,11 +569,11 @@
Loading
568 569
        """
569 570
        This function converts a smirks string to a Chemical Environment
570 571
        """
571 -
        smirks = _convert_embedded_SMIRKS(input_smirks)
572 +
        smirks = _convert_embedded_smirks(input_smirks)
572 573
        atoms = dict() # store created atom
573 574
        idx = 1 # current atom being created
574 575
        store = list() # to store indices while branching
575 -
        bondingTo = idx # which atom are we going to bond to
576 +
        bonding_to = idx # which atom are we going to bond to
576 577
577 578
        atom_string, start, end = _find_embedded_brackets(smirks, r'\[', r'\]')
578 579
@@ -599,29 +600,28 @@
Loading
599 600
600 601
        # Check for ring index, i.e. the 1s in "[#6:1]1-CCCCC1"
601 602
        match = re.match(r'(\d+)',leftover)
602 -
        if match is not None: # leftover starts with int
603 +
        if match is not None:  # leftover starts with int
603 604
            ring = re.findall(r'(\d+)',leftover)[0]
604 605
            leftover = leftover[match.end():]
605 606
        else:
606 607
            ring = None
607 608
608 609
        # Get atom information and create first atom
609 -
        OR, AND, index = self._getAtomInfo(atom_string)
610 -
        new_atom = self.addAtom(None, newORtypes = OR, newANDtypes = AND,
611 -
                newAtomIndex = index, newAtomRing = ring, beyondBeta = True)
610 +
        ors, ands, index = self._get_atom_info(atom_string)
611 +
        new_atom = self.add_atom(None, new_or_types= ors, new_and_types= ands,
612 +
                                 new_atom_index= index, new_atom_ring= ring, beyond_beta= True)
612 613
        atoms[idx] = new_atom
613 614
614 615
        while len(leftover) > 0:
615 616
            idx += 1
616 -
617 617
            # Check for branching
618 618
            if leftover[0] == ')':
619 -
                bondingTo = store.pop()
619 +
                bonding_to = store.pop()
620 620
                leftover = leftover[1:]
621 621
                continue
622 622
623 623
            if leftover[0] == '(':
624 -
                store.append(bondingTo)
624 +
                store.append(bonding_to)
625 625
                leftover = leftover[1:]
626 626
                continue
627 627
@@ -650,8 +650,8 @@
Loading
650 650
                leftover = leftover[end+1:]
651 651
652 652
            # Get bond and atom info
653 -
            bOR, bAND = self._getBondInfo(bond_string)
654 -
            aOR, aAND, index = self._getAtomInfo(atom_string[1:-1])
653 +
            b_or, b_and = self._get_bond_info(bond_string)
654 +
            a_or, a_and, index = self._get_atom_info(atom_string[1:-1])
655 655
656 656
            # Check for ring index, i.e. the 1s in "[#6:1]1-CCCCC1"
657 657
            match = re.match(r'(\d+)',leftover)
@@ -662,18 +662,18 @@
Loading
662 662
                ring = None
663 663
664 664
            # create new atom
665 -
            new_atom = self.addAtom(atoms[bondingTo], bondORtypes=bOR,
666 -
                    bondANDtypes=bAND, newORtypes=aOR, newANDtypes=aAND,
667 -
                    newAtomIndex=index, newAtomRing=ring, beyondBeta=True)
665 +
            new_atom = self.add_atom(atoms[bonding_to], bond_or_types=b_or,
666 +
                                     bond_and_types=b_and, new_or_types=a_or, new_and_types=a_and,
667 +
                                     new_atom_index=index, new_atom_ring=ring, beyond_beta=True)
668 668
669 669
            # update state
670 670
            atoms[idx] = new_atom
671 -
            bondingTo = idx
671 +
            bonding_to = idx
672 672
        return
673 673
674 -
    def _getAtomInfo(self, atom):
674 +
    def _get_atom_info(self, atom):
675 675
        """
676 -
        given atom string, returns ORtypes, ANDtypes, and index
676 +
        given atom string, returns or_types, and_types, and index
677 677
        """
678 678
        # Find atom index
679 679
        colon = atom.find(':')
@@ -685,37 +685,37 @@
Loading
685 685
686 686
        split = atom.split(';')
687 687
688 -
        # Get ANDtypes (and split them if they don't use ;)
689 -
        ANDtypes = list()
688 +
        # Get and_types (and split them if they don't use ;)
689 +
        and_types = list()
690 690
        for a in split[1:]:
691 -
            ANDtypes += re.findall(self.atom_reg, a)
691 +
            and_types += re.findall(self.atom_reg, a)
692 692
693 -
        # Get ORtypes
694 -
        ORList = split[0].split(',')
695 -
        ORtypes = list()
696 -
        # Separate ORtypes into bases and decorators
697 -
        for OR in ORList:
698 -
            ORbase, ORdecors = self._separateORtypes(OR)
699 -
            if ORbase is not None:
700 -
                ORtypes.append( (ORbase, ORdecors) )
693 +
        # Get or_types
694 +
        or_list = split[0].split(',')
695 +
        or_types = list()
696 +
        # Separate or_types into bases and decorators
697 +
        for OR in or_list:
698 +
            or_base, or_decors = self._separate_or_types(OR)
699 +
            if or_base is not None:
700 +
                or_types.append((or_base, or_decors))
701 701
702 -
        return ORtypes, ANDtypes, index
702 +
        return or_types, and_types, index
703 703
704 -
    def _separateORtypes(self, ORtype):
704 +
    def _separate_or_types(self, or_type):
705 705
        """
706 706
        Separates ORtype (i.e. "#6X4R+0") into
707 707
        a base and decorators (i.e. '#6', ['X4','R','+0'] )
708 708
        """
709 709
        # special case 1: wild card
710 -
        if ORtype == '*':
710 +
        if or_type == '*':
711 711
            return None, []
712 712
713 713
        # if ORbase is a wildcard
714 -
        if ORtype[0] == '*':
715 -
            return '*', re.findall(self.atom_reg, ORtype[1:])
714 +
        if or_type[0] == '*':
715 +
            return '*', re.findall(self.atom_reg, or_type[1:])
716 716
717 717
        # Split up decorators by RegEx strings for atoms
718 -
        split = re.findall(self.atom_reg, ORtype)
718 +
        split = re.findall(self.atom_reg, or_type)
719 719
        if len(split) == 0:
720 720
            return None, []
721 721
@@ -723,36 +723,36 @@
Loading
723 723
        decs = _remove_blanks_repeats(split[1:], ['',base])
724 724
        return base, decs
725 725
726 -
    def _getBondInfo(self, bond):
726 +
    def _get_bond_info(self, bond):
727 727
        """
728 -
        given bond strings returns ORtypes and ANDtypes
728 +
        given bond strings returns or_types and and_types
729 729
        """
730 730
        # blank bond string is single or aromatic
731 -
        # empty ORtypes in Chemical Environments are treated as ~ bonds
731 +
        # empty or_types in Chemical Environments are treated as ~ bonds
732 732
        if bond == "":
733 -
            ANDtypes = list()
734 -
            ORtypes = [ ('-', []), (':', []) ]
735 -
            return ORtypes, ANDtypes
733 +
            and_types = list()
734 +
            or_types = [('-', []), (':', [])]
735 +
            return or_types, and_types
736 736
737 737
        # AND types indicated by ; at the end
738 738
        split = bond.split(';')
739 -
        ANDtypes = list()
739 +
        and_types = list()
740 740
        for a in split[1:]:
741 -
            ANDtypes += re.findall(self.bond_regs, a)
741 +
            and_types += re.findall(self.bond_regs, a)
742 742
743 -
        # ORtypes are divided by ,
744 -
        ORList = split[0].split(',')
745 -
        ORtypes = list()
746 -
        for OR in ORList:
743 +
        # or_types are divided by ,
744 +
        or_list = split[0].split(',')
745 +
        or_types = list()
746 +
        for OR in or_list:
747 747
            if OR == '~':
748 748
                continue
749 749
            or_divide = re.findall(self.bond_regs, OR)
750 750
            if len(or_divide) > 0:
751 -
                ORtypes.append( (or_divide[0], or_divide[1:]))
751 +
                or_types.append((or_divide[0], or_divide[1:]))
752 752
753 -
        return ORtypes, ANDtypes
753 +
        return or_types, and_types
754 754
755 -
    def asSMIRKS(self, smarts = False):
755 +
    def as_smirks(self, smarts = False):
756 756
        """
757 757
        Returns a SMIRKS representation of the chemical environment
758 758
@@ -761,10 +761,10 @@
Loading
761 761
        smarts: optional, boolean
762 762
            if True, returns a SMARTS instead of SMIRKS without index labels
763 763
        """
764 -
        init_atom = self.selectAtom(1)
765 -
        return self._asSMIRKS(init_atom, None, smarts)
764 +
        init_atom = self.select_atom(1)
765 +
        return self._as_smirks(init_atom, None, smarts)
766 766
767 -
    def _asSMIRKS(self, initialAtom = None, neighbors = None, smarts = False):
767 +
    def _as_smirks(self, initial_atom = None, neighbors = None, smarts = False):
768 768
        """Return a SMIRKS representation of the chemical environment.
769 769
770 770
        Parameters
@@ -782,46 +782,46 @@
Loading
782 782
        if len(self._graph_nodes()) == 0:
783 783
            return ""
784 784
785 -
        if initialAtom is None:
786 -
            initialAtom = self.getAtoms()[0]
785 +
        if initial_atom is None:
786 +
            initial_atom = self.get_atoms()[0]
787 787
788 788
        if neighbors is None:
789 -
            neighbors = self._graph_neighbors(initialAtom)
789 +
            neighbors = self._graph_neighbors(initial_atom)
790 790
791 791
        # sort neighbors to guarantee order is constant
792 -
        neighbors = sorted(neighbors, key=lambda atom: atom.asSMIRKS())
792 +
        neighbors = sorted(neighbors, key=lambda atom: atom.as_smirks())
793 793
794 794
        # initialize smirks for starting atom
795 795
        if smarts:
796 -
            smirks = initialAtom.asSMARTS()
796 +
            smirks = initial_atom.as_smarts()
797 797
        else:
798 -
            smirks = initialAtom.asSMIRKS()
798 +
            smirks = initial_atom.as_smirks()
799 799
800 800
        # loop through neighbors
801 801
        for idx, neighbor in enumerate(neighbors):
802 802
            # get the SMIRKS for the bond between these atoms
803 803
            # bonds are the same if smarts or smirks
804 -
            bond_edge = self._graph_get_edge_data(initialAtom, neighbor)
805 -
            bondSMIRKS = bond_edge['bond'].asSMIRKS()
804 +
            bond_edge = self._graph_get_edge_data(initial_atom, neighbor)
805 +
            bond_smirks = bond_edge['bond'].as_smirks()
806 806
807 807
            # Get the neighbors for this neighbor
808 808
            new_neighbors = self._graph_neighbors(neighbor)
809 809
            # Remove initialAtom so it doesn't get reprinted
810 -
            new_neighbors.remove(initialAtom)
810 +
            new_neighbors.remove(initial_atom)
811 811
812 812
            # Call asSMIRKS again to get the details for that atom
813 -
            atomSMIRKS = self._asSMIRKS(neighbor, new_neighbors, smarts)
813 +
            atom_smirks = self._as_smirks(neighbor, new_neighbors, smarts)
814 814
815 815
            # Use ( ) for branch atoms (all but last)
816 816
            if idx < len(neighbors) - 1:
817 -
                smirks += '(' + bondSMIRKS + atomSMIRKS + ')'
817 +
                smirks += '(' + bond_smirks + atom_smirks + ')'
818 818
            # This is for the atoms that are a part of the main chain
819 819
            else:
820 -
                smirks += bondSMIRKS + atomSMIRKS
820 +
                smirks += bond_smirks + atom_smirks
821 821
822 822
        return smirks
823 823
824 -
    def selectAtom(self, descriptor = None):
824 +
    def select_atom(self, descriptor = None):
825 825
        """Select a random atom fitting the descriptor.
826 826
827 827
        Parameters
@@ -840,7 +840,7 @@
Loading
840 840
        or None if no such atom exists
841 841
        """
842 842
        if descriptor is None or isinstance(descriptor,str):
843 -
            atoms = self.getComponentList('atom', descriptor)
843 +
            atoms = self.get_component_list('atom', descriptor)
844 844
            if len(atoms) == 0:
845 845
                return None
846 846
            return random.choice(atoms)
@@ -848,12 +848,12 @@
Loading
848 848
        if not isinstance(descriptor, int):
849 849
            return None
850 850
851 -
        for atom in self.getAtoms():
851 +
        for atom in self.get_atoms():
852 852
            if atom.index == descriptor:
853 853
                return atom
854 854
        return None
855 855
856 -
    def getComponentList(self, component_type, descriptor = None):
856 +
    def get_component_list(self, component_type, descriptor = None):
857 857
        """
858 858
        Returns a list of atoms or bonds matching the descriptor
859 859
@@ -869,42 +869,42 @@
Loading
869 869
        des_list = ['indexed', 'unindexed', 'alpha', 'beta', 'all']
870 870
        if descriptor is not None:
871 871
            d = descriptor.lower()
872 -
            if not d in des_list:
873 -
                raise Exception("Error: descriptor must be in the list [%s]" %
872 +
            if d not in des_list:
873 +
                raise LookupError("Error: descriptor must be in the list [%s]" %
874 874
                                ', '.join(des_list))
875 875
        else:
876 876
            d = None
877 877
878 878
        if not component_type.lower() in ['atom', 'bond']:
879 -
            raise Exception("Error: 'getComponentList()' component_type must be 'atom' or 'bond'")
879 +
            raise LookupError("Error: component_type must be 'atom' or 'bond'")
880 880
881 881
        if component_type.lower() == 'atom':
882 882
            if d == 'indexed':
883 -
                return self.getIndexedAtoms()
883 +
                return self.get_indexed_atoms()
884 884
            elif d == 'unindexed':
885 -
                return self.getUnindexedAtoms()
885 +
                return self.get_unindexed_atoms()
886 886
            elif d == 'alpha':
887 -
                return self.getAlphaAtoms()
887 +
                return self.get_alpha_atoms()
888 888
            elif d == 'beta':
889 -
                return self.getBetaAtoms()
889 +
                return self.get_beta_atoms()
890 890
            else:
891 -
                return self.getAtoms()
891 +
                return self.get_atoms()
892 892
893 893
        elif component_type.lower() == 'bond':
894 894
            if d == 'indexed':
895 -
                return self.getIndexedBonds()
895 +
                return self.get_indexed_bonds()
896 896
            elif d == 'unindexed':
897 -
                return self.getUnindexedBonds()
897 +
                return self.get_unindexed_bonds()
898 898
            elif d == 'alpha':
899 -
                return self.getAlphaBonds()
899 +
                return self.get_alpha_bonds()
900 900
            elif d == 'beta':
901 -
                return self.getBetaBonds()
901 +
                return self.get_beta_bonds()
902 902
903 -
            return self.getBonds()
903 +
            return self.get_bonds()
904 904
905 905
        return None
906 906
907 -
    def selectBond(self, descriptor = None):
907 +
    def select_bond(self, descriptor = None):
908 908
        """Select a random bond fitting the descriptor.
909 909
910 910
        Parameters
@@ -923,88 +923,90 @@
Loading
923 923
        or None if no such atom exists
924 924
        """
925 925
        if descriptor is None or isinstance(descriptor,str):
926 -
            bonds = self.getComponentList('bond', descriptor)
926 +
            bonds = self.get_component_list('bond', descriptor)
927 927
            if len(bonds) == 0:
928 928
                return None
929 929
            return random.choice(bonds)
930 930
931 931
        if not isinstance(descriptor, int):
932 932
            return None
933 -
        for bond in self.getBonds():
934 -
            if bond._bond_type == descriptor:
933 +
        for bond in self.get_bonds():
934 +
            if bond.index == descriptor:
935 935
                return bond
936 936
937 937
        return None
938 938
939 -
    def addAtom(self, bondToAtom, bondORtypes = None, bondANDtypes = None,
940 -
            newORtypes = None, newANDtypes = None, newAtomIndex = None,
941 -
            newAtomRing = None, beyondBeta = False):
939 +
    def add_atom(self, bond_to_atom, bond_or_types = None, bond_and_types = None,
940 +
                 new_or_types = None, new_and_types = None, new_atom_index = None,
941 +
                 new_atom_ring = None, beyond_beta = False):
942 942
        """Add an atom to the specified target atom.
943 943
944 944
        Parameters
945 945
        -----------
946 -
        bondToAtom: atom object, required
946 +
        bond_to_atom: atom object, required
947 947
            atom the new atom will be bound to
948 -
        bondORtypes: list of tuples, optional
949 -
            strings that will be used for the ORtypes for the new bond
950 -
        bondANDtypes: list of strings, optional
951 -
            strings that will be used for the ANDtypes for the new bond
952 -
        newORtypes: list of strings, optional
953 -
            strings that will be used for the ORtypes for the new atom
954 -
        newANDtypes: list of strings, optional
955 -
            strings that will be used for the ANDtypes for the new atom
956 -
        newAtomIndex: int, optional
948 +
        bond_or_types: list of tuples, optional
949 +
            strings that will be used for the or_types for the new bond
950 +
        bond_and_types: list of strings, optional
951 +
            strings that will be used for the and_types for the new bond
952 +
        new_or_types: list of strings, optional
953 +
            strings that will be used for the or_types for the new atom
954 +
        new_and_types: list of strings, optional
955 +
            strings that will be used for the and_types for the new atom
956 +
        new_atom_index: int, optional
957 957
            integer label that could be used to index the atom in a SMIRKS string
958 -
        beyondBeta: boolean, optional
958 +
        new_atom_ring: int, optional
959 +
            integer used to track the openning and closing of rings in SMARTS/SMIRKS patterns
960 +
        beyond_beta: boolean, optional
959 961
            if True, allows bonding beyond beta position
960 962
961 963
        Returns
962 964
        --------
963 -
        newAtom: atom object for the newly created atom
965 +
        new_atom: atom object for the newly created atom
964 966
        """
965 -
        if bondToAtom is None:
967 +
        if bond_to_atom is None:
966 968
            if len(self._graph_nodes()) > 0:
967 969
                return None
968 -
            newType = newAtomIndex
969 -
            if newType is None:
970 -
                newType = 0
971 970
972 -
            newAtom = self.Atom(newORtypes, newANDtypes, newAtomIndex, newAtomRing)
973 -
            self._graph.add_node(newAtom, atom_type = newType)
974 -
            return newAtom
971 +
            if new_atom_index is None:
972 +
                new_atom_index = 0
973 +
974 +
            new_atom = self.Atom(new_or_types, new_and_types, new_atom_index, new_atom_ring)
975 +
            self._graph.add_node(new_atom)
976 +
            return new_atom
975 977
976 978
        # Check if we can get past beta position
977 -
        bondToType = self._graph_nodes(data=True)[bondToAtom]['atom_type']
978 -
        if bondToType < 0 and not beyondBeta:
979 +
        bond_to_index = bond_to_atom.index
980 +
        if bond_to_index < 0 and not beyond_beta:
979 981
            return None
980 982
981 983
        # determine the type integer for the new atom and bond
982 -
        if newAtomIndex is not None:
983 -
            newType = newAtomIndex
984 -
            bondType = max(newType, bondToType) - 1
985 -
        else:
986 -
            if bondToType > 0:
987 -
                newType = 0
984 +
        if new_atom_index is None:
985 +
            if bond_to_index > 0:
986 +
                new_atom_index = 0
988 987
            else:
989 -
                newType = bondToType - 1
990 -
            bondType = newType
988 +
                new_atom_index = bond_to_index - 1
989 +
990 +
        if new_atom_index > 0 and bond_to_index > 0:
991 +
            bond_index = max(new_atom_index, bond_to_index) - 1
992 +
        else:
993 +
            bond_index = new_atom_index
991 994
992 995
        # create new bond
993 -
        newBond = self.Bond(bondORtypes, bondANDtypes)
996 +
        new_bond = self.Bond(bond_or_types, bond_and_types, bond_index)
994 997
995 998
        # create new atom
996 -
        newAtom = self.Atom(newORtypes, newANDtypes, newAtomIndex, newAtomRing)
999 +
        new_atom = self.Atom(new_or_types, new_and_types, new_atom_index, new_atom_ring)
997 1000
998 -
        # Add node for newAtom
999 -
        self._graph.add_node(newAtom, atom_type = newType)
1001 +
        # Add node for new_atom
1002 +
        self._graph.add_node(new_atom)
1000 1003
1001 1004
        # Connect original atom and new atom
1002 -
        self._graph.add_edge(bondToAtom, newAtom, bond = newBond, bond_type = bondType)
1003 -
        newBond._bond_type = bondType
1005 +
        self._graph.add_edge(bond_to_atom, new_atom, bond = new_bond)
1004 1006
1005 -
        return newAtom
1007 +
        return new_atom
1006 1008
1007 -
    def removeAtom(self, atom, onlyEmpty=False):
1009 +
    def remove_atom(self, atom, only_empty=False):
1008 1010
        """Remove the specified atom from the chemical environment.
1009 1011
        if the atom is not indexed for the SMIRKS string or
1010 1012
        used to connect two other atoms.
@@ -1013,15 +1015,15 @@
Loading
1013 1015
        ----------
1014 1016
        atom: atom object, required
1015 1017
            atom to be removed if it meets the conditions.
1016 -
        onlyEmpty: boolean, optional
1017 -
            True only an atom with no ANDtypes and 1 ORtype can be removed
1018 +
        only_empty: boolean, optional
1019 +
            True only an atom with no and_types and 1 ORtype can be removed
1018 1020
1019 1021
        Returns
1020 1022
        --------
1021 1023
        Boolean True: atom was removed, False: atom was not removed
1022 1024
        """
1023 1025
        # labeled atoms can't be removed
1024 -
        if atom.index is not None:
1026 +
        if atom.index > 0:
1025 1027
            return False
1026 1028
1027 1029
        # Atom connected to more than one other atom cannot be removed
@@ -1029,7 +1031,7 @@
Loading
1029 1031
            return False
1030 1032
1031 1033
        # if you can remove "decorated atoms" remove it
1032 -
        if not onlyEmpty:
1034 +
        if not only_empty:
1033 1035
            self._graph_remove_node(atom)
1034 1036
            return True
1035 1037
@@ -1041,7 +1043,7 @@
Loading
1041 1043
        self._graph_remove_node(atom)
1042 1044
        return True
1043 1045
1044 -
    def getAtoms(self):
1046 +
    def get_atoms(self):
1045 1047
        """
1046 1048
        Returns
1047 1049
        -------
@@ -1049,7 +1051,7 @@
Loading
1049 1051
        """
1050 1052
        return self._graph_nodes()
1051 1053
1052 -
    def getBonds(self, atom=None):
1054 +
    def get_bonds(self, atom=None):
1053 1055
        """
1054 1056
        Parameters
1055 1057
        ----------
@@ -1070,7 +1072,7 @@
Loading
1070 1072
1071 1073
        return bonds
1072 1074
1073 -
    def getBond(self, atom1, atom2):
1075 +
    def get_bond(self, atom1, atom2):
1074 1076
        """
1075 1077
        Get bond betwen two atoms
1076 1078
@@ -1087,132 +1089,118 @@
Loading
1087 1089
        else:
1088 1090
            return None
1089 1091
1090 -
    def getIndexedAtoms(self):
1092 +
    def get_indexed_atoms(self):
1091 1093
        """
1092 1094
        returns the list of Atom objects with an index
1093 1095
        """
1094 1096
        index_atoms = []
1095 -
        for atom, info in self._graph_nodes(data=True).items():
1096 -
            if info['atom_type'] > 0:
1097 +
        for atom in self.get_atoms():
1098 +
            if atom.index > 0:
1097 1099
                index_atoms.append(atom)
1098 1100
        return index_atoms
1099 1101
1100 -
    def getUnindexedAtoms(self):
1102 +
    def get_unindexed_atoms(self):
1101 1103
        """
1102 1104
        returns a list of Atom objects that are not indexed
1103 1105
        """
1104 1106
        unindexed_atoms = []
1105 -
        for atom, info in self._graph_nodes(data=True).items():
1106 -
            if info['atom_type'] < 1:
1107 +
        for atom in self.get_atoms():
1108 +
            if atom.index < 1:
1107 1109
                unindexed_atoms.append(atom)
1108 1110
        return unindexed_atoms
1109 1111
1110 -
    def getAlphaAtoms(self):
1112 +
    def get_alpha_atoms(self):
1111 1113
        """
1112 1114
        Returns a list of atoms alpha to any indexed atom
1113 1115
            that are not also indexed
1114 1116
        """
1115 1117
        alpha_atoms = []
1116 -
        for atom, info in self._graph_nodes(data=True).items():
1117 -
            if info['atom_type'] == 0:
1118 +
        for atom in self.get_atoms():
1119 +
            if atom.index == 0:
1118 1120
                alpha_atoms.append(atom)
1119 1121
1120 1122
        return alpha_atoms
1121 1123
1122 -
    def getBetaAtoms(self):
1124 +
    def get_beta_atoms(self):
1123 1125
        """
1124 1126
        Returns a list of atoms beta to any indexed atom
1125 1127
            that are not alpha or indexed atoms
1126 1128
        """
1127 1129
        beta_atoms = []
1128 -
        for atom, info in self._graph_nodes(data=True).items():
1129 -
            if info['atom_type'] == -1:
1130 +
        for atom in self.get_atoms():
1131 +
            if atom.index == -1:
1130 1132
                beta_atoms.append(atom)
1131 1133
        return beta_atoms
1132 1134
1133 -
    def getIndexedBonds(self):
1135 +
    def get_indexed_bonds(self):
1134 1136
        """
1135 1137
        Returns a list of Bond objects that connect two indexed atoms
1136 1138
        """
1137 -
        indexedBonds = []
1138 -
        for bond in self.getBonds():
1139 -
            if bond._bond_type > 0:
1140 -
                indexedBonds.append(bond)
1141 -
        return indexedBonds
1139 +
        indexed_bonds = []
1140 +
        for bond in self.get_bonds():
1141 +
            if bond.index > 0:
1142 +
                indexed_bonds.append(bond)
1143 +
        return indexed_bonds
1142 1144
1143 -
    def getUnindexedBonds(self):
1145 +
    def get_unindexed_bonds(self):
1144 1146
        """
1145 1147
        Returns a list of Bond objects that connect
1146 1148
            an indexed atom to an unindexed atom
1147 1149
            two unindexed atoms
1148 1150
        """
1149 -
        unindexedBonds = []
1150 -
        for bond in self.getBonds():
1151 -
            if bond._bond_type < 1:
1152 -
                unindexedBonds.append(bond)
1153 -
        return unindexedBonds
1151 +
        unindexed_bonds = []
1152 +
        for bond in self.get_bonds():
1153 +
            if bond.index < 1:
1154 +
                unindexed_bonds.append(bond)
1155 +
        return unindexed_bonds
1154 1156
1155 -
    def getAlphaBonds(self):
1157 +
    def get_alpha_bonds(self):
1156 1158
        """
1157 1159
        Returns a list of Bond objects that connect
1158 1160
            an indexed atom to alpha atoms
1159 1161
        """
1160 -
        alphaBonds = []
1161 -
        for bond in self.getBonds():
1162 -
            if bond._bond_type == 0:
1163 -
                alphaBonds.append(bond)
1164 -
        return alphaBonds
1162 +
        alpha_bonds = []
1163 +
        for bond in self.get_bonds():
1164 +
            if bond.index == 0:
1165 +
                alpha_bonds.append(bond)
1166 +
        return alpha_bonds
1165 1167
1166 -
    def getBetaBonds(self):
1168 +
    def get_beta_bonds(self):
1167 1169
        """
1168 1170
        Returns a list of Bond objects that connect
1169 1171
            alpha atoms to beta atoms
1170 1172
        """
1171 1173
        betaBonds = []
1172 -
        for bond in self.getBonds():
1173 -
            if bond._bond_type == -1:
1174 +
        for bond in self.get_bonds():
1175 +
            if bond.index == -1:
1174 1176
                betaBonds.append(bond)
1175 1177
        return betaBonds
1176 1178
1177 -
    def isAlpha(self, component):
1179 +
    def is_alpha(self, component):
1178 1180
        """
1179 1181
        Takes an atom or bond are returns True if it is alpha to an indexed atom
1180 1182
        """
1181 -
        if component._atom:
1182 -
            return self._graph_nodes(data=True)[component]['atom_type'] == 0
1183 -
        else:
1184 -
            return component._bond_type == 0
1183 +
        return component.index == 0
1185 1184
1186 -
    def isUnindexed(self, component):
1185 +
    def is_unindexed(self, component):
1187 1186
        """
1188 1187
        returns True if the atom or bond is not indexed
1189 1188
        """
1190 -
        if component._atom:
1191 -
            return component.index is None
1192 -
        else:
1193 -
            return component._bond_type < 1
1189 +
        return component.index < 1
1194 1190
1195 -
    def isIndexed(self, component):
1191 +
    def is_indexed(self, component):
1196 1192
        """
1197 1193
        returns True if the atom or bond is indexed
1198 1194
        """
1199 -
        if component._atom:
1200 -
            return component.index is not None
1201 -
        else:
1202 -
            return component._bond_type > 0
1195 +
        return component.index > 0
1203 1196
1204 -
    def isBeta(self, component):
1197 +
    def is_beta(self, component):
1205 1198
        """
1206 1199
        Takes an atom or bond are returns True if it is beta to an indexed atom
1207 1200
        """
1208 -
        if component._atom:
1209 -
            return self._graph_nodes(data=True)[component]['atom_type'] == -1
1210 -
        else:
1211 -
            return component._bond_type == -1
1201 +
        return component.index == -1
1212 1202
1213 -
    # TODO: We may want to overhaul ChemicalEnvironment.getType() to return one of ['atom', 'bond', 'angle', 'proper', 'improper']
1214 -
    # and check to make sure the expected connectivity is represented in the SMIRKS expression.
1215 -
    def getType(self):
1203 +
    def get_type(self):
1216 1204
        """
1217 1205
        Uses number of indexed atoms and bond connectivity
1218 1206
        to determine the type of chemical environment
@@ -1223,40 +1211,56 @@
Loading
1223 1211
            'Atom', 'Bond', 'Angle', 'ProperTorsion', 'ImproperTorsion'
1224 1212
            None if number of indexed atoms is 0 or > 4
1225 1213
        """
1226 -
        index_atoms = self.getIndexedAtoms()
1214 +
        index_atoms = self.get_indexed_atoms()
1227 1215
        natoms = len(index_atoms)
1228 1216
1217 +
        if natoms == 0 or natoms > 4:
1218 +
            return None
1219 +
1220 +
        # one indexed atom can only be atom
1229 1221
        if natoms == 1:
1230 1222
            return "Atom"
1223 +
1224 +
        # if 2 indexed atoms check they are connected
1225 +
        bond12 = self.get_bond(self.select_atom(1), self.select_atom(2))
1226 +
        if bond12 is None:
1227 +
            return None
1231 1228
        if natoms == 2:
1232 1229
            return "Bond"
1230 +
1231 +
        # if 3 indexed atoms check connected in an angle
1232 +
        bond23 = self.get_bond(self.select_atom(2), self.select_atom(3))
1233 +
        if bond23 is None:
1234 +
            return None
1233 1235
        if natoms == 3:
1234 1236
            return "Angle"
1235 -
        if natoms == 4:
1236 -
            atom2 = self.selectAtom(2)
1237 -
            atom4 = self.selectAtom(4)
1238 -
            bond24 = self.getBond(atom2, atom4)
1239 -
            if bond24 is not None:
1240 -
                return "ImproperTorsion"
1237 +
1238 +
        # if 4 indexed atoms check for proper or improper torsion connections
1239 +
        bond34 = self.get_bond(self.select_atom(3), self.select_atom(4))
1240 +
        bond24 = self.get_bond(self.select_atom(2), self.select_atom(4))
1241 +
        if bond24 is not None:
1242 +
            return "ImproperTorsion"
1243 +
        if bond34 is not None:
1241 1244
            return "ProperTorsion"
1242 -
        else:
1243 -
            return None
1244 1245
1245 -
    def getNeighbors(self, atom):
1246 +
        # must have 4 indexed atoms with incorrect connectivity
1247 +
        return None
1248 +
1249 +
    def get_neighbors(self, atom):
1246 1250
        """
1247 1251
        Returns atoms that are bound to the given atom
1248 1252
        in the form of a list of Atom objects
1249 1253
        """
1250 1254
        return self._graph_neighbors(atom)
1251 1255
1252 -
    def getValence(self, atom):
1256 +
    def get_valence(self, atom):
1253 1257
        """
1254 1258
        Returns the valence (number of neighboring atoms)
1255 1259
        around the given atom
1256 1260
        """
1257 1261
        return len(self._graph_neighbors(atom))
1258 1262
1259 -
    def getBondOrder(self, atom):
1263 +
    def get_bond_order(self, atom):
1260 1264
        """
1261 1265
        Returns minimum bond order around a given atom
1262 1266
        0 if atom has no neighbors
@@ -1265,6 +1269,6 @@
Loading
1265 1269
        """
1266 1270
        order = 0.
1267 1271
        for a1, a2, info in self._graph_edges(data=True, node=atom):
1268 -
            order += info['bond'].getOrder()
1272 +
            order += info['bond'].get_order()
1269 1273
        return order
1270 1274

@@ -126,10 +126,10 @@
Loading
126 126
        graph = ClusterGraph(self.molecules, cluster_list[0][1], 0)
127 127
        test_smirks = graph.as_smirks(compress=True)
128 128
        env = CE(test_smirks)
129 -
        if env.getType() is None:
129 +
        if env.get_type() is None:
130 130
            # corresponds to an unknown chemical pattern
131 131
            self.dict_type = dict
132 -
        elif env.getType().lower() == 'impropertorsion':
132 +
        elif env.get_type().lower() == 'impropertorsion':
133 133
            self.dict_type = ImproperDict
134 134
        else:
135 135
            self.dict_type = ValenceDict
@@ -278,7 +278,19 @@
Loading
278 278
279 279
class Reducer():
280 280
    """
281 -
    # TODO: add a description
281 +
    Reducer starts with any list of SMIRKS and removes unnecessary decorators
282 +
    while maintaining typing on input molecules.
283 +
284 +
    Attributes
285 +
    ----------
286 +
    current_smirks: list of tuples
287 +
                    current SMIRKS patterns in the form (label, smirks)
288 +
    mols: list of chemper molecules
289 +
          molecules being used to reduce the input SMIRKS
290 +
    cluster_dict: dictionary
291 +
                  Dictionary specifying typing using current SMIRKS in the form:
292 +
                  {mol_idx:
293 +
                        { (tuple of atom indices): label } }
282 294
    """
283 295
    def __init__(self, smirks_list, mols, verbose=False):
284 296
        """
@@ -287,7 +299,7 @@
Loading
287 299
        smirks_list: list of tuples
288 300
            set of SMIRKS patterns in the form (label, smirks)
289 301
        mols: list of molecules
290 -
            Any chemper compatible molecules accepted
302 +
            Any chemper compatible molecules accepted (ChemPer, OpenEye, or RDKit)
291 303
        """
292 304
        self.verbose = verbose
293 305
        self.current_smirks = copy.deepcopy(smirks_list)
@@ -485,16 +497,16 @@
Loading
485 497
        """
486 498
        items = list()
487 499
        odds = list()
488 -
        for a_b in env.getAtoms() + env.getBonds():
489 -
            count = len(a_b.getANDtypes())
490 -
            for o in a_b.getORtypes():
500 +
        for a_b in env.get_atoms() + env.get_bonds():
501 +
            count = len(a_b.and_types)
502 +
            for o in a_b.or_types:
491 503
                if o[0] != '*':
492 504
                    count += 1
493 505
                count += len(o[1])
494 506
495 507
            # a wild card, atom with no index should be considered ([*])
496 508
            # should also be on this list so it can be removed
497 -
            if isinstance(a_b, CE.Atom) and not isinstance(a_b, CE.Bond) and env.isUnindexed(a_b):
509 +
            if isinstance(a_b, CE.Atom) and not isinstance(a_b, CE.Bond) and env.is_unindexed(a_b):
498 510
                count += 1
499 511
500 512
            items.append(a_b)
@@ -512,13 +524,13 @@
Loading
512 524
        # choose an atom or bond with the probabilities:
513 525
        item = np.random.choice(items, p=weights)
514 526
        dec_opts = list()
515 -
        if len(item.getORtypes()) > 0:
527 +
        if len(item.or_types) > 0:
516 528
            dec_opts.append('remove_ors')
517 -
        if len(item.getANDtypes()) > 0:
529 +
        if len(item.and_types) > 0:
518 530
            dec_opts.append('remove_ands')
519 531
520 532
        if not isinstance(item, CE.Bond): # then it is an atom
521 -
            if env.getValence(item) == 1 and env.isUnindexed(item):
533 +
            if env.get_valence(item) == 1 and env.is_unindexed(item):
522 534
                dec_opts.append('remove_atom')
523 535
524 536
        return item, dec_opts
@@ -537,21 +549,21 @@
Loading
537 549
538 550
        change = np.random.choice(dec_opts)
539 551
        if change == 'remove_ors':
540 -
            new_or_types, changed = self.remove_or(sub.getORtypes(), isinstance(sub, CE.Bond))
552 +
            new_or_types, changed = self.remove_or(sub.or_types, isinstance(sub, CE.Bond))
541 553
            if not changed:
542 554
                return smirks, False
543 -
            sub.setORtypes(new_or_types)
555 +
            sub.or_types = new_or_types
544 556
        elif change == 'remove_ands':
545 -
            new_and_types, changed = self.remove_and(sub.getANDtypes())
557 +
            new_and_types, changed = self.remove_and(sub.and_types)
546 558
            if not changed:
547 559
                return smirks, False
548 -
            sub.setANDtypes(new_and_types)
560 +
            sub.and_types = new_and_types
549 561
        else: # change == 'remove_atom'
550 -
            remove = env.removeAtom(sub)
562 +
            remove = env.remove_atom(sub)
551 563
            if not remove:
552 564
                return smirks, False
553 565
554 -
        return env.asSMIRKS(), True
566 +
        return env.as_smirks(), True
555 567
556 568
    def run(self, max_its=1000, verbose=None):
557 569
        """

@@ -478,7 +478,7 @@
Loading
478 478
479 479
        if len(self.mols) == 0:
480 480
            self._add_first_smirks_atoms(mol, smirks_atoms_list[0])
481 -
            self._symmetry_funct = self.get_symmetry_funct(CE(self.as_smirks()).getType())
481 +
            self._symmetry_funct = self.get_symmetry_funct(CE(self.as_smirks()).get_type())
482 482
            self._add_mol(mol, smirks_atoms_list[1:])
483 483
        else:
484 484
            self._add_mol(mol, smirks_atoms_list)

@@ -256,7 +256,7 @@
Loading
256 256
    from chemper.graphs.environment import ChemicalEnvironment
257 257
258 258
    env = ChemicalEnvironment(smirks)
259 -
    if env.getType().lower() == 'impropertorsion':
259 +
    if env.get_type().lower() == 'impropertorsion':
260 260
        matches = ImproperDict()
261 261
    else:
262 262
        matches = ValenceDict()

@@ -0,0 +1,3 @@
Loading
1 +
from . import cluster_graph
2 +
from . import environment
3 +
from . import fragment_graph
Files Coverage
chemper 89.13%
Project Totals (12 files) 89.13%
580.3
TRAVIS_OS_NAME=linux
580.6
TRAVIS_PYTHON_VERSION=3.6
TRAVIS_OS_NAME=linux
580.1
TRAVIS_OS_NAME=osx
580.4
TRAVIS_PYTHON_VERSION=3.6
TRAVIS_OS_NAME=linux
xmau4y0t6yqirr3c
580.2
TRAVIS_OS_NAME=osx
1
coverage:
2
  ignore:
3
    - test/.*
4
    - compare/.*
5
    - test_helper.py
6
    - setup.py
7
  status:
8
    patch: false
9
    project:
10
      default:
11
        threshold: 80%
12
comment:
13
  layout: "header"
14
  require_changes: false
15
  branches: null
16
  behavior: default
17
  flags: null
18
  paths: null
Sunburst
The inner-most circle is the entire project, moving away from the center are folders then, finally, a single file. The size and color of each slice is representing the number of statements and the coverage, respectively.
Icicle
The top section represents the entire project. Proceeding with folders and finally individual files. The size and color of each slice is representing the number of statements and the coverage, respectively.
Grid
Each block represents a single file in the project. The size and color of each block is represented by the number of statements and the coverage, respectively.
Loading