예제 #1
0
class BuildMol(Handler.TokenHandler):
    def __init__(self, enable_vfgraph):
        self.enable_vfgraph = enable_vfgraph
        
    def begin(self):
        self.closures = {}
        if vflib and self.enable_vfgraph:
            self.vfgraph = vflib.ARGEdit()
            self.insert_node = self.vfgraph.InsertNode
            self.insert_edge = self.vfgraph.InsertEdge
        else:
            self.vfgraph = None

        self.atoms = []
        self.bonds = []
        self._atom = None
        self._prev_atoms = []

        # None occurs after a '.'
        # implicit_bond means implicit single bond
        self._pending_bond = None

    def end(self):
        if len(self._prev_atoms) >= 2:
            raise AssertionError("Missing ')'")
        if self._pending_bond not in [implicit_bond, None]:
            raise AssertionError("Missing an atom after the bond")
        if self.closures:
            raise AssertionError("Missing closures for %s" %
                                 (self.closures.keys(),))
        self.mol = Molecule(self.atoms, self.bonds)
        if self.vfgraph:
            self.mol.vfgraph = weakref.ref(self.vfgraph)
    
    def add_token(self, field, pos, text):
        getattr(self, "do_" + field)(text)

    def add_atom(self, atom):
        atoms = self.atoms
        atom.index = len(atoms)
        atoms.append(atom)
        if self.vfgraph:
            index = self.insert_node(atom)
##            assert index == atom.index, "%s <--> %s"%(index, atom.index)
        
##        self.mol.add_atom(atom)
        
        if self._pending_bond == implicit_bond:
            # Implicit single or aromatic bond
            self._pending_bond = Bond()

        if self._pending_bond is not None:
            bond = self._pending_bond
            prev_atom = self._prev_atoms[-1]
            bond.atoms[:] = [prev_atom, atom]
            ##self.mol.add_bond(bond, prev_atom, atom)
            bond.atoms = [prev_atom, atom]
            atom.bonds.append(bond)
            prev_atom.bonds.append(bond)
            atom.oatoms.append(prev_atom)
            prev_atom.oatoms.append(atom)
            self.bonds.append(bond)
            if self.vfgraph:
                index1, index2 = prev_atom.index, atom.index
                insert_edge = self.insert_edge
                insert_edge(index1, index2, bond)
                insert_edge(index2, index1, bond)
            
        self._pending_bond = implicit_bond
        if not self._prev_atoms:
            self._prev_atoms.append(atom)
        else:
            self._prev_atoms[-1] = atom

        #self.mol.atoms.append(atom)
        
    def do_raw_atom(self, text):
        atom = Atom()
        symbol, atom.aromatic = get_symbol_aromatic(text)
        atom.set_symbol(symbol)
        self.add_atom(atom)

    def do_open_bracket(self, text):
        self._atom = Atom()
        self._atom.has_explicit_hcount = True

    def do_weight(self, text):
        self._atom.weight = int(text)

    def do_element(self, text):
        symbol, self._atom.aromatic = get_symbol_aromatic(text)
        self._atom.set_symbol(symbol)
        
    def do_chiral_count(self, text):
        print "setting chirality", self._atom, int(text[1:])
        self._atom.chirality = int(text[1:])

    def do_chiral_named(self, text):
        self._atom.chiral_class = text[1:3]
        self._atom.chirality = int(text[3:])

    def do_chiral_symbols(self, text):
        self._atom.chiral_class = len(text)

    def do_hcount(self, text):
        if text == "H":
            self._atom.explicit_hcount = 1
        else:
            self._atom.explicit_hcount = int(text[1:])

    def do_positive_count(self, text):
        self._atom.charge = int(text[1:])

    def do_positive_symbols(self, text):
        self._atom.charge = len(text)

    def do_negative_count(self, text):
        self._atom.charge = -int(text[1:])

    def do_negative_symbols(self, text):
        self._atom.charge = -len(text)

    def do_close_bracket(self, text):
        self.add_atom(self._atom)
        self._atom = None

    def do_bond(self, text):
        assert self._pending_bond in (implicit_bond, None)
        symbol, bondorder, bondtype, equiv_class, stereo = BONDLOOKUP[text]
        # if the bond came in as aromatic (which it
        #  CAN'T!))
        if bondtype == 4:
            assert 0, "Bond's shouldn't come in as ':'"
            fixed = 0
        else:
            fixed = 1
        bond = Bond(text, bondorder, bondtype, fixed, stereo)
        bond.equiv_class = equiv_class
        self._pending_bond = bond

    def do_dot(self, text):
        assert self._pending_bond in (implicit_bond, None)
        self._pending_bond = None

    def do_closure(self, text):
        num = normalize_closure(text)
        if self.closures.has_key(num):
            prev_atom, bond = self.closures[num]
            del self.closures[num]

            assert self._pending_bond is not None, "Can't happen"
            
            if self._pending_bond is not implicit_bond and \
               bond is not implicit_bond and \
               self._pending_bond.symbol != "-":  # according to toolkit

                # need to verify they are compatible
                prev_symbol = bond.symbol
                symbol = self._pending_bond.symbol
                if (prev_symbol == symbol) or \
                   (prev_symbol == "/" and symbol == "\\") or \
                   (prev_symbol == "\\" and symbol == "/"):
                    pass
                else:
                    raise AssertionError("bond types don't match")
            elif bond is implicit_bond and self._pending_bond is not implicit_bond:
                # see if one of the bonds is not implicit and keep it
                bond = self._pending_bond
            elif bond is implicit_bond:
                # both are implicit so make a new one
                bond = Bond()

            bond._closure = 1
            atom = self._prev_atoms[-1]
            if prev_atom is atom:
                raise AssertionError("cannot close a ring with itself")
            bond.atoms[:] = [prev_atom, atom]
            prev_atom._closure = 1
            atom._closure = 1
            ##self.mol.add_bond(bond, prev_atom, atom)
            
            bond.atoms = [prev_atom, atom]
            atom.bonds.append(bond)
            prev_atom.bonds.append(bond)
            atom.oatoms.append(prev_atom)
            prev_atom.oatoms.append(atom)
            self.bonds.append(bond)
            if self.vfgraph:
                index1, index2 = prev_atom.index, atom.index
                insert_edge = self.insert_edge
                insert_edge(index1, index2, bond)
                insert_edge(index2, index1, bond)

        else:
            self.closures[num] = (self._prev_atoms[-1], self._pending_bond)
        self._pending_bond = implicit_bond
            

    def do_open_branch(self, text):
        self._prev_atoms.append(self._prev_atoms[-1])
    
    def do_close_branch(self, text):
        self._prev_atoms.pop()
예제 #2
0
 def do_raw_atom(self, text):
     atom = Atom()
     symbol, atom.aromatic = get_symbol_aromatic(text)
     atom.set_symbol(symbol)
     self.add_atom(atom)
예제 #3
0
 def do_raw_atom(self, text):
     atom = Atom()
     symbol, atom.aromatic = get_symbol_aromatic(text)
     atom.set_symbol(symbol)
     self.add_atom(atom)
예제 #4
0
class BuildMol(Handler.TokenHandler):
    def __init__(self, enable_vfgraph):
        self.enable_vfgraph = enable_vfgraph

    def begin(self):
        self.closures = {}
        if vflib and self.enable_vfgraph:
            self.vfgraph = vflib.ARGEdit()
            self.insert_node = self.vfgraph.InsertNode
            self.insert_edge = self.vfgraph.InsertEdge
        else:
            self.vfgraph = None

        self.atoms = []
        self.bonds = []
        self._atom = None
        self._prev_atoms = []

        # None occurs after a '.'
        # implicit_bond means implicit single bond
        self._pending_bond = None

    def end(self):
        if len(self._prev_atoms) >= 2:
            raise AssertionError("Missing ')'")
        if self._pending_bond not in [implicit_bond, None]:
            raise AssertionError("Missing an atom after the bond")
        if self.closures:
            raise AssertionError("Missing closures for %s" %
                                 (self.closures.keys(), ))
        self.mol = Molecule(self.atoms, self.bonds)
        if self.vfgraph:
            self.mol.vfgraph = weakref.ref(self.vfgraph)

    def add_token(self, field, pos, text):
        getattr(self, "do_" + field)(text)

    def add_atom(self, atom):
        atoms = self.atoms
        atom.index = len(atoms)
        atoms.append(atom)
        if self.vfgraph:
            index = self.insert_node(atom)


##            assert index == atom.index, "%s <--> %s"%(index, atom.index)

##        self.mol.add_atom(atom)

        if self._pending_bond == implicit_bond:
            # Implicit single or aromatic bond
            self._pending_bond = Bond()

        if self._pending_bond is not None:
            bond = self._pending_bond
            prev_atom = self._prev_atoms[-1]
            bond.atoms[:] = [prev_atom, atom]
            ##self.mol.add_bond(bond, prev_atom, atom)
            bond.atoms = [prev_atom, atom]
            atom.bonds.append(bond)
            prev_atom.bonds.append(bond)
            atom.oatoms.append(prev_atom)
            prev_atom.oatoms.append(atom)
            self.bonds.append(bond)
            if self.vfgraph:
                index1, index2 = prev_atom.index, atom.index
                insert_edge = self.insert_edge
                insert_edge(index1, index2, bond)
                insert_edge(index2, index1, bond)

        self._pending_bond = implicit_bond
        if not self._prev_atoms:
            self._prev_atoms.append(atom)
        else:
            self._prev_atoms[-1] = atom

        #self.mol.atoms.append(atom)

    def do_raw_atom(self, text):
        atom = Atom()
        symbol, atom.aromatic = get_symbol_aromatic(text)
        atom.set_symbol(symbol)
        self.add_atom(atom)

    def do_open_bracket(self, text):
        self._atom = Atom()
        self._atom.has_explicit_hcount = True

    def do_weight(self, text):
        self._atom.weight = int(text)

    def do_element(self, text):
        symbol, self._atom.aromatic = get_symbol_aromatic(text)
        self._atom.set_symbol(symbol)

    def do_chiral_count(self, text):
        print "setting chirality", self._atom, int(text[1:])
        self._atom.chirality = int(text[1:])

    def do_chiral_named(self, text):
        self._atom.chiral_class = text[1:3]
        self._atom.chirality = int(text[3:])

    def do_chiral_symbols(self, text):
        self._atom.chiral_class = len(text)

    def do_hcount(self, text):
        if text == "H":
            self._atom.explicit_hcount = 1
        else:
            self._atom.explicit_hcount = int(text[1:])

    def do_positive_count(self, text):
        self._atom.charge = int(text[1:])

    def do_positive_symbols(self, text):
        self._atom.charge = len(text)

    def do_negative_count(self, text):
        self._atom.charge = -int(text[1:])

    def do_negative_symbols(self, text):
        self._atom.charge = -len(text)

    def do_close_bracket(self, text):
        self.add_atom(self._atom)
        self._atom = None

    def do_bond(self, text):
        assert self._pending_bond in (implicit_bond, None)
        symbol, bondorder, bondtype, equiv_class, stereo = BONDLOOKUP[text]
        # if the bond came in as aromatic (which it
        #  CAN'T!))
        if bondtype == 4:
            assert 0, "Bond's shouldn't come in as ':'"
            fixed = 0
        else:
            fixed = 1
        bond = Bond(text, bondorder, bondtype, fixed, stereo)
        bond.equiv_class = equiv_class
        self._pending_bond = bond

    def do_dot(self, text):
        assert self._pending_bond in (implicit_bond, None)
        self._pending_bond = None

    def do_closure(self, text):
        num = normalize_closure(text)
        if self.closures.has_key(num):
            prev_atom, bond = self.closures[num]
            del self.closures[num]

            assert self._pending_bond is not None, "Can't happen"

            if self._pending_bond is not implicit_bond and \
               bond is not implicit_bond and \
               self._pending_bond.symbol != "-":  # according to toolkit

                # need to verify they are compatible
                prev_symbol = bond.symbol
                symbol = self._pending_bond.symbol
                if (prev_symbol == symbol) or \
                   (prev_symbol == "/" and symbol == "\\") or \
                   (prev_symbol == "\\" and symbol == "/"):
                    pass
                else:
                    raise AssertionError("bond types don't match")
            elif bond is implicit_bond and self._pending_bond is not implicit_bond:
                # see if one of the bonds is not implicit and keep it
                bond = self._pending_bond
            elif bond is implicit_bond:
                # both are implicit so make a new one
                bond = Bond()

            bond._closure = 1
            atom = self._prev_atoms[-1]
            if prev_atom is atom:
                raise AssertionError("cannot close a ring with itself")
            bond.atoms[:] = [prev_atom, atom]
            prev_atom._closure = 1
            atom._closure = 1
            ##self.mol.add_bond(bond, prev_atom, atom)

            bond.atoms = [prev_atom, atom]
            atom.bonds.append(bond)
            prev_atom.bonds.append(bond)
            atom.oatoms.append(prev_atom)
            prev_atom.oatoms.append(atom)
            self.bonds.append(bond)
            if self.vfgraph:
                index1, index2 = prev_atom.index, atom.index
                insert_edge = self.insert_edge
                insert_edge(index1, index2, bond)
                insert_edge(index2, index1, bond)

        else:
            self.closures[num] = (self._prev_atoms[-1], self._pending_bond)
        self._pending_bond = implicit_bond

    def do_open_branch(self, text):
        self._prev_atoms.append(self._prev_atoms[-1])

    def do_close_branch(self, text):
        self._prev_atoms.pop()
예제 #5
0
def reader(file, stripHydrogens=1):
    lines = collector(file)

    while 1:
        try:
            fields = {}
            name = lines.next().strip()
            userLine = lines.next().strip()
            comment = lines.next().strip()
            molinfo = lines.next()
            numAtoms, numBonds = int(molinfo[0:3]), int(molinfo[3:6])

            atoms = []   # this is the full list of atoms
            _atoms = []  # this is the (potentially stripped list
                         # of atoms.  I.e. no hydrogens.)
            i = 0
            for index in range(numAtoms):
                line = lines.next()
                x,y,z,symbol,mass,charge,stereo,hcount,hcount_fixed = parse_atom(line)
                if symbol == "H" and stripHydrogens:
                    atoms.append(None)
                else:
                    atom = Atom()
                    atoms.append(atom)
                    _atoms.append(atom)
                    atom.set_symbol(symbol)# = symbol
                    atom.explicit_hcount = hcount
                    atom.charge = charge
                    atom._line = line
                    atom.x = x
                    atom.y = y
                    atom.z = z
                    if hcount_fixed:
                        print "hcount fixed"
                        atom.fixed_hcount = 1 # oops, we shouldn't use this
                        atom.has_explicit_hcount = True
                    if mass:
                        atom.weight = atom.mass + mass

                    atom.index = i
                    i = i + 1

            bonds = []
            for index in range(numBonds):
                line = lines.next()
                a1, a2, bondtype, stereo, remainder = parse_bond(line)
                symbol, bondorder, bondtype, fixed = BOND_SYMBOL[bondtype]

                atom1, atom2 = atoms[a1], atoms[a2]
                
                if atom1 is not None and atom2 is not None:
                    h1, h2 = atom1.handle, atom2.handle
                    bond = Bond(symbol, bondorder, bondtype, fixed)
                    bonds.append(bond)
                    bond._line = remainder
                    bond.index = index
                    bond.atoms = [atom1, atom2]
                    try:
                        bond.stereo = BOND_LOOKUP_STEREO[bondtype-1][stereo]
                    except KeyError:
                        raise MolReaderError("An SD record cannot have a bondtype of %s and a stereo value of %s"%(bondtype, stereo))
                    except IndexError:
                        print "*"*44
                        print line
                        print "bondtype, stereo", bondtype, stero
                        raise
                        
                    atom1.bonds.append(bond)
                    atom2.bonds.append(bond)
                    atom1.oatoms.append(atom2)
                    atom2.oatoms.append(atom1)
                    if atom1.symbol == "H": atom2.explicit_hcount += 1
                    if atom2.symbol == "H": atom1.explicit_hcount += 1
                else:
                    if atom1 is None and atom2 is not None:
                        atom2.explicit_hcount += 1
                    elif atom2 is None and atom1 is not None:
                        atom1.explicit_hcount += 1
                        
            ##############################################################
            # read the mprops if necessary
            line = lines.next().strip()
            while 1:
                if line and line[0:6] == "M  END":
                    line = lines.next().strip()
                    break
                elif line == "M  CHG":
                    groups = line[6:].split()[1:]
                    index = 0
                    while index < len(groups):
                        atomIndex = int(groups[index]) - 1
                        atom = self.atoms[atomIndex]
                        charge = int(groups[index+1])
                        self.atoms[atomIndex].charge = charge
                        index += 2
                    line = lines.next().strip()
                elif line and line[0] == ">":
                    break
                elif line[0:4] == "$$$$":
                    break
                line = lines.next().strip()
                # What about end of mol?

            #############################################################
            # read the fields if necessary
            
            while line != "$$$$":
                if line and line[0] == ">":
                    res = FIELDPATTERN.match(line)
                    if res: field, potentialID = res.groups()
                    else:
                        res = ALTFIELDPATTERN.match(line)
                        if res:
                            field = res.groups()[0]
                            potentialID = None
                        else:
                            field, potentialID = None, None
                            
                    if name is None: name = potentialID

                    if field:
                        data = []
                        line = lines.next().strip()
                        while line and line != "$$$$":
                            data.append(line)
                            line = lines.next().strip()
                            
                        fields[field] = os.linesep.join(data)
                    
                line = lines.next().strip()
            mol = Molecule(_atoms, bonds)
            mol.name = name
            mol.fields = fields
            mol.name = name
            yield mol, lines.dump(), None
            
        except StopIteration:
            break
        except Exception:
            line = lines.current.strip()
            
            while line[0:4] != "$$$$":
                line = lines.next().strip()                
                
            stdout, stderr = sys.stdout, sys.stderr
            sys.stdout = sys.stderr = io = StringIO()
            traceback.print_exc()
            sys.stdout = stdout
            sys.stderr = stderr
            yield None, lines.dump(), io.getvalue()