Skip to content

Commit

Permalink
Merge pull request #154 from hjkgrp/code_quality
Browse files Browse the repository at this point in the history
Code quality
  • Loading branch information
ralf-meyer committed Apr 27, 2023
2 parents 1c39c62 + 1c0f102 commit 2b60ea1
Show file tree
Hide file tree
Showing 31 changed files with 822 additions and 687 deletions.
7 changes: 6 additions & 1 deletion .github/workflows/CI.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,11 @@ jobs:
run: |
pytest -v --cov=molSimplify --cov-report=xml
- name: Run doctest
# For now still excluding several subfolders and files
run: |
pytest --doctest-modules --ignore=molSimplify/job_manager --ignore=molSimplify/Informatics/MOF --ignore=molSimplify/Scripts/in_b3lyp_usetc.py --ignore=molSimplify/Informatics/jupyter_vis.py --ignore=molSimplify/Informatics/macrocycle_synthesis.py --ignore=molSimplify/Informatics/organic_fingerprints.py molSimplify
- name: Upload coverage report to codecov
uses: codecov/codecov-action@v3
with:
Expand All @@ -92,7 +97,7 @@ jobs:

- name: Report Status
# Slack notifications only on the main repo
if: ${{ github.event_name != 'pull_request' && github.repository == 'hjkgrp/molSimplify' }}
if: ${{job.status == 'failure' && github.event_name != 'pull_request' && github.repository == 'hjkgrp/molSimplify' }}
#uses: ravsamhq/notify-slack-action@v1
uses: 8398a7/action-slack@v3
with:
Expand Down
7 changes: 6 additions & 1 deletion devtools/conda-envs/mols.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,15 +13,20 @@ dependencies:
- pytest

# Optional
# GUI
# GUI / plotting
- pyqt
- qt
- matplotlib
# Database
- pymongo
# PDB interaction
- beautifulsoup4
# Machine learning
#- pytorch::pytorch
#- hyperopt
# QM interfaces
- theochem::iodata
- xtb
#- psi4::psi4
# molscontrol
- scikit-image
2 changes: 1 addition & 1 deletion molSimplify/Classes/README.md
Original file line number Diff line number Diff line change
@@ -1 +1 @@
To members of the Kulik group: If you have custom data that you want to use for yourself but do not want to push to the main repo, e.g. custom ligands for molSimplify ligand construction, you can make a file `.molSimplify` and include in it a line like `CUSTOM_DATA_PATH=/Users/ralf/molSimplify_custom_data`. In that folder you specified, you can place a folder `Ligands`, and molSimplify will look there first before looking at the Ligands folder in the central repo. This functionality is implemented in `globalvars.py`.
To members of the Kulik group: If you have custom data that you want to use for yourself but do not want to push to the main repo, e.g. custom ligands for molSimplify ligand construction, you can make a file `.molSimplify` and include in it a line like `CUSTOM_DATA_PATH=/Users/your_user/molSimplify_custom_data`. In that folder you specified, you can place a folder `Ligands`, and molSimplify will look there first before looking at the Ligands folder in the central repo. This functionality is implemented in `globalvars.py`.
5 changes: 4 additions & 1 deletion molSimplify/Classes/mGUI.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,10 @@
from pkg_resources import resource_filename, Requirement
import xml.etree.ElementTree as ET

import openbabel
try:
from openbabel import openbabel # version 3 style import
except ImportError:
import openbabel # fallback to version 2

# Main GUI class

Expand Down
138 changes: 75 additions & 63 deletions molSimplify/Classes/mol3D.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,10 @@
import time
import xml.etree.ElementTree as ET
import numpy as np
import openbabel
try:
from openbabel import openbabel # version 3 style import
except ImportError:
import openbabel # fallback to version 2
from typing import List, Optional
from scipy.spatial import ConvexHull
from molSimplify.utils.decorators import deprecated
Expand Down Expand Up @@ -42,7 +45,7 @@ class mol3D:
Example instantiation of an octahedral iron-ammonia complex from an XYZ file:
>>> complex_mol = mol3D()
>>> complex_mol.readfromxyz('fe_nh3_6.xyz')
>>> complex_mol.readfromxyz('fe_nh3_6.xyz') # doctest: +SKIP
"""

Expand Down Expand Up @@ -122,21 +125,9 @@ def __init__(self, name='ABC', loc='', use_atom_specific_cutoffs=False):
self.use_atom_specific_cutoffs = use_atom_specific_cutoffs

def __repr__(self):
"""
Returns all bound methods of the mol3D class.
Returns
-------
method_string : string
String of methods available in mol3D class.
"""

method_string = "\nClass mol3D has the following methods:\n"
for method in dir(self):
if callable(getattr(self, method)):
method_string += method + '\n'
return method_string
return f"mol3D({self.make_formula(latex=False)})"

@deprecated("Preliminary testing showed this function is unreliable at best")
def ACM(self, idx1, idx2, idx3, angle):
"""
Performs angular movement on mol3D class. A submolecule is
Expand All @@ -152,8 +143,6 @@ def ACM(self, idx1, idx2, idx3, angle):
Index of anchor atom 2.
angle : float
New bond angle in degrees.
>>> complex_mol.ACM(2, 1, 0, 180) # Make atom 2 form a 180 degree angle with atoms 1 and 0.
"""

atidxs_to_move = self.findsubMol(idx1, idx2)
Expand Down Expand Up @@ -231,7 +220,8 @@ def addAtom(self, atom: atom3D, index: Optional[int] = None, auto_populate_BO_di
auto_populate_BO_dict : bool, optional
Populate bond order dictionary with newly added atom. Default is True.
>>> C_atom = atom3D('C',[1, 1, 1])
>>> complex_mol = mol3D()
>>> C_atom = atom3D('C', [1, 1, 1])
>>> complex_mol.addAtom(C_atom) # Add carbon atom at cartesian position 1, 1, 1 to mol3D object.
"""

Expand Down Expand Up @@ -484,7 +474,13 @@ def BCM(self, idx1, idx2, d):
d : float
Bond distance in angstroms.
>>> complex_mol.BCM(1, 0, 1.5) # Set distance between atoms 0 and 1 to be 1.5 angstroms. Move atom 1.
>>> complex_mol = mol3D()
>>> complex_mol.addAtom(atom3D('H', [0, 0, 0]))
>>> complex_mol.addAtom(atom3D('H', [0, 0, 1]))
>>> complex_mol.BCM(1, 0, 0.7) # Set distance between atoms 0 and 1 to be 1.5 angstroms. Move atom 1.
>>> complex_mol.coordsvect()
array([[0. , 0. , 0. ],
[0. , 0. , 0.7]])
"""

bondv = self.getAtom(idx1).distancev(self.getAtom(idx2)) # 1 - 2
Expand Down Expand Up @@ -1663,7 +1659,7 @@ def getBondedAtoms(self, idx):
"""

if len(self.graph): # The graph exists.
if len(self.graph): # The graph exists.
nats = list(np.nonzero(np.ravel(self.graph[idx]))[0])
else:
ratom = self.getAtom(idx)
Expand Down Expand Up @@ -2577,25 +2573,33 @@ def RCAngle(self, idx1, idx2, idx3, anglei, anglef, angleint=1.0, writegeo=False
The directory to which generated reaction coordinate
geoemtries are written, if writegeo=True.
>>> complex_mol.RCAngle(2, 1, 0, 90, 180, 0.5, True, 'rc_geometries') # Generate reaction coordinate
>>> # geometries using the given structure by changing the angle between atoms 2, 1,
>>> # and 0 from 90 degrees to 180 degrees in intervals of 0.5 degrees, and write the
>>> # generated geometries to 'rc_geometries' directory.
>>> complex_mol.RCAngle(2, 1, 0, 180, 90, -0.5) # Generate reaction coordinates
>>> # with the given geometry by changing the angle between atoms 2, 1, and 0 from
>>> # 180 degrees to 90 degrees in intervals of 0.5 degrees, and the generated
>>> # geometries will not be written to a directory.
>>> complex_mol = mol3D()
>>> complex_mol.addAtom(atom3D('O', [0, 0, 0]))
>>> complex_mol.addAtom(atom3D('H', [0, 0, 1]))
>>> complex_mol.addAtom(atom3D('H', [0, 1, 0]))
Generate reaction coordinate geometries using the given structure by changing the angle between atoms 2, 1,
and 0 from 90 degrees to 160 degrees in intervals of 10 degrees
>>> complex_mol.RCAngle(2, 1, 0, 90, 160, 10)
[mol3D(O1H2), mol3D(O1H2), mol3D(O1H2), mol3D(O1H2), mol3D(O1H2), mol3D(O1H2), mol3D(O1H2), mol3D(O1H2)]
Generate reaction coordinates with the given geometry by changing the angle between atoms 2, 1, and 0 from
160 degrees to 90 degrees in intervals of 10 degrees, and the generated geometries will not be written to
a directory.
>>> complex_mol.RCAngle(2, 1, 0, 160, 90, -10)
[mol3D(O1H2), mol3D(O1H2), mol3D(O1H2), mol3D(O1H2), mol3D(O1H2), mol3D(O1H2), mol3D(O1H2), mol3D(O1H2)]
"""
if writegeo:
os.mkdir(dir_name)
temp_list = []
for ang_val in np.arange(anglei, anglef+angleint, angleint):
temp_angle = mol3D()
temp_angle.copymol3D(self)
temp_angle.ACM(idx1, idx2, idx3, ang_val)
temp_list.append(temp_angle)
temp_list = []
for ang_val in np.arange(anglei, anglef+angleint, angleint):
temp_angle = mol3D()
temp_angle.copymol3D(self)
temp_angle.ACM(idx1, idx2, idx3, ang_val)
temp_list.append(temp_angle)
if writegeo:
temp_angle.writexyz(str(dir_name)+"/rc_"+str(str("{:.4f}".format(ang_val)))+'.xyz')
return temp_list
return temp_list

def RCDistance(self, idx1, idx2, disti, distf, distint=0.05, writegeo=False, dir_name='rc_distance_geometries'):
"""
Expand All @@ -2622,26 +2626,34 @@ def RCDistance(self, idx1, idx2, disti, distf, distint=0.05, writegeo=False, dir
The directory to which generated reaction coordinate
geoemtries are written if writegeo=True.
>>> complex_mol.RCDistance(1, 0, 1.0, 3.0, 0.01, True, 'rc_geometries') # Generate reaction coordinate
>>> # geometries using the given structure by changing the distance between atoms 1 and 0
>>> # from 1.0 to 3.0 angstrom (atom 1 is moved) in intervals of 0.01 angstrom, and write
>>> # the generated geometries to 'rc_geometries' directory.
>>> complex_mol.RCDistance(1, 0, 3.0, 1.0, -0.02) # Generate reaction coordinates
>>> # geometries using the given structure by changing the distance between atoms 1 and 0
>>> # from 3.0 to 1.0 angstrom (atom 1 is moved) in intervals of 0.02 angstrom, and
>>> # the generated geometries will not be written to a directory.
>>> complex_mol = mol3D()
>>> complex_mol.addAtom(atom3D('H', [0, 0, 0]))
>>> complex_mol.addAtom(atom3D('H', [0, 0, 1]))
Generate reaction coordinate geometries using the given structure by changing the distance between atoms 1 and 0
from 1.0 to 3.0 angstrom (atom 1 is moved) in intervals of 0.5 angstrom
>>> complex_mol.RCDistance(1, 0, 1.0, 3.0, 0.5)
[mol3D(H2), mol3D(H2), mol3D(H2), mol3D(H2), mol3D(H2)]
Generate reaction coordinates
geometries using the given structure by changing the distance between atoms 1 and 0
from 3.0 to 1.0 angstrom (atom 1 is moved) in intervals of 0.2 angstrom, and
the generated geometries will not be written to a directory.
>>> complex_mol.RCDistance(1, 0, 3.0, 1.0, -0.25)
[mol3D(H2), mol3D(H2), mol3D(H2), mol3D(H2), mol3D(H2), mol3D(H2), mol3D(H2), mol3D(H2), mol3D(H2)]
"""

if writegeo:
os.mkdir(dir_name)
temp_list = []
for dist_val in np.arange(disti, distf+distint, distint):
temp_dist = mol3D()
temp_dist.copymol3D(self)
temp_dist.BCM(idx1, idx2, dist_val)
temp_list.append(temp_dist)
temp_list = []
for dist_val in np.arange(disti, distf+distint, distint):
temp_dist = mol3D()
temp_dist.copymol3D(self)
temp_dist.BCM(idx1, idx2, dist_val)
temp_list.append(temp_dist)
if writegeo:
temp_dist.writexyz(str(dir_name)+"/rc_"+str(str("{:.4f}".format(dist_val)))+'.xyz')
return temp_list
return temp_list

def returnxyz(self):
"""
Expand Down Expand Up @@ -4840,7 +4852,7 @@ def Structure_inspection(self, init_mol=None, catoms_arr=None, num_coord=5, dict
return flag_oct, flag_list, dict_oct_info, flag_oct_loose, flag_list_loose

def get_fcs(self, strict_cutoff=False, catom_list=None):
"""
"""
Get first coordination shell of a transition metal complex.
Parameters
Expand All @@ -4865,7 +4877,7 @@ def get_fcs(self, strict_cutoff=False, catom_list=None):
return fcs

def get_bo_dict_from_inds(self, inds):
"""
"""
Recreate bo_dict with correct indices
Parameters
Expand Down Expand Up @@ -4897,7 +4909,7 @@ def get_bo_dict_from_inds(self, inds):
return new_bo_dict

def create_mol_with_inds(self, inds):
"""
"""
Create molecule with indices.
Parameters
Expand Down Expand Up @@ -4926,7 +4938,7 @@ def create_mol_with_inds(self, inds):
return molnew

def make_formula(self, latex=True):
"""
"""
Get a chemical formula from the mol3D class instance.
Parameters
Expand Down Expand Up @@ -4961,7 +4973,7 @@ def make_formula(self, latex=True):
return retstr

def read_smiles(self, smiles, ff="mmff94", steps=2500):
"""
"""
Read a smiles string and convert it to a mol3D class instance.
Parameters
Expand Down Expand Up @@ -5036,7 +5048,7 @@ def get_smiles(self, canonicalize=False, use_mol2=False) -> str:
return smi

def mols_symbols(self):
"""
"""
Store symbols and their frequencies in symbols_dict attributes.
"""
self.symbols_dict = {}
Expand All @@ -5047,7 +5059,7 @@ def mols_symbols(self):
self.symbols_dict[atom.symbol()] += 1

def read_bonder_order(self, bofile):
"""
"""
Get bond order information from file.
Parameters
Expand Down Expand Up @@ -5091,7 +5103,7 @@ def read_bonder_order(self, bofile):
self.bodavrg_dict.update({ii: np.mean(devi)})

def read_charge(self, chargefile):
"""
"""
Get charge information from file.
Parameters
Expand All @@ -5112,7 +5124,7 @@ def read_charge(self, chargefile):
print(("chargefile does not exist.", chargefile))

def get_mol_graph_det(self, oct=True, useBOMat=False):
"""
"""
Get molecular graph determinant.
Parameters
Expand Down Expand Up @@ -5521,7 +5533,7 @@ def get_features(self, lac=True, force_generate=False, eq_sym=False,
return results

def getMLBondLengths(self):
"""
"""
Outputs the metal-ligand bond lengths in the complex.
Returns
Expand All @@ -5548,7 +5560,7 @@ def getMLBondLengths(self):

@deprecated('Using this function might lead to inconsistent behavior.')
def setAtoms(self, atoms):
"""
"""
Set atoms of a mol3D class to atoms.
Parameters
Expand All @@ -5560,7 +5572,7 @@ def setAtoms(self, atoms):
self.natoms = len(atoms)

def setLoc(self, loc):
"""
"""
Sets the conformation of an amino acid in the chain of a protein.
Parameters
Expand Down
9 changes: 5 additions & 4 deletions molSimplify/Classes/monomer3D.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@


class monomer3D:
"""Holds information about a monomer, used to do manipulations. Reads information from structure file (pdb) or is directly built from molsimplify.
"""Holds information about a monomer, used to do manipulations.
Reads information from structure file (pdb) or is directly built from molsimplify.
"""

Expand Down Expand Up @@ -42,6 +43,9 @@ def __init__(self, three_lc='GLY', chain='undef', id=-1, occup=1.00, loc=''):
# Temporary list for storing conformations
self.temp_list = []

def __repr__(self):
return f"monomer3D({self.three_lc}, id={self.id})"

def identify(self):
""" States whether the amino acid is (positively/negatively) charged, polar, or hydrophobic.
Expand Down Expand Up @@ -228,9 +232,6 @@ def addAtom(self, atom, index=None):
Index of added atom. Default is None.
auto_populate_BO_dict : bool, optional
Populate bond order dictionary with newly added atom. Default is True.
>>> C_atom = atom3D('C',[1, 1, 1])
>>> complex_mol.addAtom(C_atom) # Add carbon atom at cartesian position 1, 1, 1 to mol3D object.
"""

if index is None:
Expand Down

0 comments on commit 2b60ea1

Please sign in to comment.