From ce5db3e6617a1181ebe3d10a5925ae1dc7c6a298 Mon Sep 17 00:00:00 2001 From: Alan Silva <3899850+alanwilter@users.noreply.github.com> Date: Sat, 27 Nov 2021 20:39:09 +0000 Subject: [PATCH 01/15] Case if babel is not installed --- acpype_lib/parser_args.py | 1 + acpype_lib/topol.py | 18 ++++++++++-------- acpype_lib/utils.py | 24 +++++++++++++++--------- tests/test_acpype.py | 2 +- tests/test_acs_api.py | 3 ++- 5 files changed, 29 insertions(+), 19 deletions(-) diff --git a/acpype_lib/parser_args.py b/acpype_lib/parser_args.py index c748ae08..eeab4b3d 100644 --- a/acpype_lib/parser_args.py +++ b/acpype_lib/parser_args.py @@ -3,6 +3,7 @@ def get_option_parser(): + # not used yet: -e -l -r parser = argparse.ArgumentParser(usage=usage + epilog) group = parser.add_mutually_exclusive_group() parser.add_argument( diff --git a/acpype_lib/topol.py b/acpype_lib/topol.py index d8c87e98..02fae7a8 100644 --- a/acpype_lib/topol.py +++ b/acpype_lib/topol.py @@ -1,3 +1,4 @@ +import re import signal import math import os @@ -3053,14 +3054,15 @@ def __init__( self.inputFile = os.path.basename(inputFile) self.rootDir = os.path.abspath(".") self.absInputFile = os.path.abspath(inputFile) - if not os.path.exists(self.absInputFile) and checkSmiles(inputFile): - self.is_smiles = True - self.smiles = inputFile - if not basename: - self.inputFile = "smiles_molecule.mol2" - else: - self.inputFile = f"{basename}.mol2" - self.absInputFile = os.path.abspath(self.inputFile) + if not os.path.exists(self.absInputFile) and not re.search(r"\.mol2$|\.mdl$|\.pdb$", self.inputFile): + if checkSmiles(inputFile): + self.is_smiles = True + self.smiles = inputFile + if not basename: + self.inputFile = "smiles_molecule.mol2" + else: + self.inputFile = f"{basename}.mol2" + self.absInputFile = os.path.abspath(self.inputFile) elif not os.path.exists(self.absInputFile): raise Exception(f"Input file {inputFile} DOES NOT EXIST") baseOriginal, ext = os.path.splitext(self.inputFile) diff --git a/acpype_lib/utils.py b/acpype_lib/utils.py index 415cf324..a26c8c5c 100644 --- a/acpype_lib/utils.py +++ b/acpype_lib/utils.py @@ -16,25 +16,31 @@ def checkOpenBabelVersion(): def checkSmiles(smiles): - if checkOpenBabelVersion() >= 300: - from openbabel import openbabel as ob - from openbabel import pybel + try: + if checkOpenBabelVersion() >= 300: + from openbabel import openbabel as ob + from openbabel import pybel - ob.cvar.obErrorLog.StopLogging() - elif checkOpenBabelVersion() >= 200 and checkOpenBabelVersion() < 300: - import openbabel as ob - import pybel # type: ignore + ob.cvar.obErrorLog.StopLogging() - ob.cvar.obErrorLog.StopLogging() + elif checkOpenBabelVersion() >= 200 and checkOpenBabelVersion() < 300: + import openbabel as ob + import pybel # type: ignore - " Check if input is a smiles string " + ob.cvar.obErrorLog.StopLogging() + except AttributeError: + print("WARNING: your input may be a SMILES but") + print(" without OpenBabel, this functionality won't work") + return False + # Check if input is a smiles string try: ob.obErrorLog.SetOutputLevel(0) pybel.readstring("smi", smiles) return True except Exception: ob.obErrorLog.SetOutputLevel(0) + return False diff --git a/tests/test_acpype.py b/tests/test_acpype.py index 1ea4997d..70bc8d21 100644 --- a/tests/test_acpype.py +++ b/tests/test_acpype.py @@ -254,7 +254,7 @@ def test_inputs(capsys, argv): (None, 2, " error: "), # NOTE: None -> sys.argv from pystest (["-v"], 0, version), ([], 2, "error: missing input files"), - (["-di", " 123"], 19, "ACPYPE FAILED: Input file 123 DOES NOT EXIST"), + (["-di", " 123"], 19, "ACPYPE FAILED: [Errno 2] No such file or directory"), (["-di", " 123", "-x", "abc"], 2, "either '-i' or ('-p', '-x'), but not both"), (["-di", " 123", "-u"], 2, "option -u is only meaningful in 'amb2gmx' mode (args '-p' and '-x')"), ], diff --git a/tests/test_acs_api.py b/tests/test_acs_api.py index 8865b575..560ba0ed 100644 --- a/tests/test_acs_api.py +++ b/tests/test_acs_api.py @@ -48,7 +48,8 @@ def test_json_simple(): def test_json_failed(): os.chdir(os.path.dirname(os.path.abspath(__file__))) jj = json.loads(acpype_api(inputFile="_fake_", debug=True)) - assert jj.get("file_name") == "ERROR: Input file _fake_ DOES NOT EXIST" + assert "ERROR: [Errno 2] No such file or directory" in jj.get("file_name") + assert "tests/_fake_" in jj.get("file_name") def get_json(): From d87eba26f6cc2e1620bfe31045212bdf242bb6e8 Mon Sep 17 00:00:00 2001 From: Alan Silva <3899850+alanwilter@users.noreply.github.com> Date: Sun, 28 Nov 2021 18:36:09 +0000 Subject: [PATCH 02/15] Important changes: binaries dict in --- acpype_lib/__init__.py | 2 +- acpype_lib/acpype.py | 43 ++++++++++++++++++++++++++---------------- acpype_lib/params.py | 2 ++ acpype_lib/topol.py | 29 +++++++++++++++------------- acpype_lib/utils.py | 15 +++------------ tests/test_acpype.py | 13 +++++++++---- 6 files changed, 58 insertions(+), 46 deletions(-) diff --git a/acpype_lib/__init__.py b/acpype_lib/__init__.py index 05d4d6c6..99f6808d 100644 --- a/acpype_lib/__init__.py +++ b/acpype_lib/__init__.py @@ -1,3 +1,3 @@ # from https://packaging.python.org/guides/single-sourcing-package-version/ # using option 2 -__version__ = "2021.11.27" +__version__ = "2021.11.28" diff --git a/acpype_lib/acpype.py b/acpype_lib/acpype.py index 87accab0..7a894052 100755 --- a/acpype_lib/acpype.py +++ b/acpype_lib/acpype.py @@ -65,30 +65,40 @@ from acpype_lib.parser_args import get_option_parser from acpype_lib.utils import while_replace from acpype_lib.utils import checkSmiles, elapsedTime +from acpype_lib.params import binaries -# For pip package -if which("antechamber") is None: - LOCAL_PATH = sysconfig.get_paths()["purelib"] - if sys.platform == "linux": - os.environ["PATH"] += os.pathsep + LOCAL_PATH + "/amber21-11_linux/bin:" + LOCAL_PATH + "/amber21-11_linux/dat/" - os.environ["AMBERHOME"] = LOCAL_PATH + "/amber21-11_linux/" - os.environ["ACHOME"] = LOCAL_PATH + "/amber21-11_linux/bin/" - os.environ["LD_LIBRARY_PATH"] = LOCAL_PATH + "/amber21-11_linux/lib/" - elif sys.platform == "darwin": - os.environ["PATH"] += os.pathsep + LOCAL_PATH + "/amber21-11_os/bin:" + LOCAL_PATH + "/amber21-11_os/dat/" - os.environ["AMBERHOME"] = LOCAL_PATH + "/amber21-11_os/" - os.environ["ACHOME"] = LOCAL_PATH + "/amber21-11_os/bin/" - os.environ["LD_LIBRARY_PATH"] = LOCAL_PATH + "/amber21-11_os/lib/" -if sys.version_info < (3, 6): - raise Exception("Sorry, you need python 3.6 or higher") +def set_for_pip(): + # For pip package + if which(binaries["ac_bin"]) is None: + LOCAL_PATH = sysconfig.get_paths()["purelib"] + if sys.platform == "linux": + os.environ["PATH"] += ( + os.pathsep + LOCAL_PATH + "/amber21-11_linux/bin:" + LOCAL_PATH + "/amber21-11_linux/dat/" + ) + os.environ["AMBERHOME"] = LOCAL_PATH + "/amber21-11_linux/" + os.environ["ACHOME"] = LOCAL_PATH + "/amber21-11_linux/bin/" + os.environ["LD_LIBRARY_PATH"] = LOCAL_PATH + "/amber21-11_linux/lib/" + elif sys.platform == "darwin": + os.environ["PATH"] += os.pathsep + LOCAL_PATH + "/amber21-11_os/bin:" + LOCAL_PATH + "/amber21-11_os/dat/" + os.environ["AMBERHOME"] = LOCAL_PATH + "/amber21-11_os/" + os.environ["ACHOME"] = LOCAL_PATH + "/amber21-11_os/bin/" + os.environ["LD_LIBRARY_PATH"] = LOCAL_PATH + "/amber21-11_os/lib/" + os.environ["DYLD_LIBRARY_PATH"] = LOCAL_PATH + "/amber21-11_os/lib/" + + +def chk_py_ver(): + if sys.version_info < (3, 6): + raise Exception("Sorry, you need python 3.6 or higher") -def init_main(argv=None): +def init_main(binaries=binaries, argv=None): """ Main function, to satisfy Conda """ + chk_py_ver() + set_for_pip() if argv is None: argv = sys.argv[1:] @@ -141,6 +151,7 @@ def init_main(argv=None): else: molecule = ACTopol( args.input, + binaries=binaries, chargeType=args.charge_method, chargeVal=args.net_charge, debug=args.debug, diff --git a/acpype_lib/params.py b/acpype_lib/params.py index 80bea120..de515203 100644 --- a/acpype_lib/params.py +++ b/acpype_lib/params.py @@ -1,3 +1,5 @@ +binaries = {"ac_bin": "antechamber", "obabel_bin": "obabel"} + MAXTIME = 3 * 3600 cal = 4.184 Pi = 3.141593 diff --git a/acpype_lib/topol.py b/acpype_lib/topol.py index 02fae7a8..ed43b777 100644 --- a/acpype_lib/topol.py +++ b/acpype_lib/topol.py @@ -11,7 +11,7 @@ from acpype_lib.mol import Atom, Angle, AtomType, Bond, Dihedral from acpype_lib import __version__ as version from acpype_lib.params import minDist, minDist2, maxDist, maxDist2, MAXTIME, TLEAP_TEMPLATE, leapAmberFile -from acpype_lib.params import ionOrSolResNameList, radPi, cal, outTopols, qDict, qConv, diffTol +from acpype_lib.params import binaries, ionOrSolResNameList, radPi, cal, outTopols, qDict, qConv, diffTol from acpype_lib.params import dictAtomTypeAmb2OplsGmxCode, dictAtomTypeGaff2OplsGmxCode, oplsCode2AtomTypeDict from acpype_lib.utils import _getoutput, while_replace, distanceAA, job_pids_family, checkOpenBabelVersion from acpype_lib.utils import checkSmiles, find_antechamber, elapsedTime, imprDihAngle, parmMerge @@ -3022,6 +3022,7 @@ class ACTopol(AbstractTopol): def __init__( self, inputFile, + binaries=binaries, chargeType="bcc", chargeVal=None, multiplicity="1", @@ -3051,6 +3052,18 @@ def __init__( self.direct = direct self.sorted = is_sorted self.chiral = chiral + self.acExe = find_antechamber(binaries["ac_bin"]) + if not os.path.exists(self.acExe): + self.printError("no 'antechamber' executable... aborting! ") + hint1 = "HINT1: is 'AMBERHOME' or 'ACHOME' environment variable set?" + hint2 = ( + "HINT2: is 'antechamber' in your $PATH?" + + "\n What 'which antechamber' in your terminal says?" + + "\n 'alias' doesn't work for ACPYPE." + ) + self.printMess(hint1) + self.printMess(hint2) + raise Exception("Missing ANTECHAMBER") self.inputFile = os.path.basename(inputFile) self.rootDir = os.path.abspath(".") self.absInputFile = os.path.abspath(inputFile) @@ -3063,6 +3076,8 @@ def __init__( else: self.inputFile = f"{basename}.mol2" self.absInputFile = os.path.abspath(self.inputFile) + else: + self.is_smiles = False elif not os.path.exists(self.absInputFile): raise Exception(f"Input file {inputFile} DOES NOT EXIST") baseOriginal, ext = os.path.splitext(self.inputFile) @@ -3099,18 +3114,6 @@ def __init__( self.gaffDatfile = "gaff2.dat" self.force = force self.allhdg = allhdg - self.acExe = find_antechamber() - if not os.path.exists(self.acExe): - self.printError("no 'antechamber' executable... aborting ! ") - hint1 = "HINT1: is 'AMBERHOME' or 'ACHOME' environment variable set?" - hint2 = ( - "HINT2: is 'antechamber' in your $PATH?" - + "\n What 'which antechamber' in your terminal says?" - + "\n 'alias' doesn't work for ACPYPE." - ) - self.printMess(hint1) - self.printMess(hint2) - raise Exception("Missing ANTECHAMBER") self.tleapExe = which("tleap") or "" self.parmchkExe = which("parmchk2") or "" acBase = base + "_AC" diff --git a/acpype_lib/utils.py b/acpype_lib/utils.py index a26c8c5c..b7f9d24e 100644 --- a/acpype_lib/utils.py +++ b/acpype_lib/utils.py @@ -28,7 +28,7 @@ def checkSmiles(smiles): import pybel # type: ignore ob.cvar.obErrorLog.StopLogging() - except AttributeError: + except Exception: print("WARNING: your input may be a SMILES but") print(" without OpenBabel, this functionality won't work") return False @@ -281,15 +281,6 @@ def while_replace(string): return string -def find_antechamber(): - acExe = "" - dirAmber = os.getenv("AMBERHOME", os.getenv("ACHOME")) - if dirAmber: - for ac_bin in ["bin", "exe"]: - ac_path = os.path.join(dirAmber, ac_bin, "antechamber") - if os.path.exists(ac_path): - acExe = ac_path - break - if not acExe: - acExe = which("antechamber") or "" +def find_antechamber(abin): + acExe = which(abin) or "" return acExe diff --git a/tests/test_acpype.py b/tests/test_acpype.py index 70bc8d21..9dc4b6da 100644 --- a/tests/test_acpype.py +++ b/tests/test_acpype.py @@ -132,13 +132,17 @@ def test_ildn_gmx4_fail(): shutil.rmtree(molecule.absHomeDir) -def test_smiles(): +@pytest.mark.parametrize( + ("base", "msg"), [(None, "smiles_molecule.mol2"), ("thalidomide_smiles", "thalidomide_smiles.mol2")], +) +def test_smiles(base, msg): os.chdir(os.path.dirname(os.path.abspath(__file__))) smiles = "c1ccc2c(c1)C(=O)N(C2=O)C3CCC(=NC3=O)O" - molecule = ACTopol(smiles, basename="thalidomide_smiles", chargeType="gas", debug=True) + molecule = ACTopol(smiles, basename=base, chargeType="gas", debug=True) molecule.createACTopol() molecule.createMolTopol() assert molecule + assert molecule.inputFile == msg assert len(molecule.molTopol.atoms) == 29 shutil.rmtree(molecule.absHomeDir) os.remove(molecule.absInputFile) @@ -241,7 +245,7 @@ def test_charge_user(): def test_inputs(capsys, argv): os.chdir(os.path.dirname(os.path.abspath(__file__))) temp_base = "vir_temp" - init_main(argv + ["-b", temp_base]) + init_main(argv=argv + ["-b", temp_base]) captured = capsys.readouterr() assert "Total time of execution:" in captured.out os.chdir(os.path.dirname(os.path.abspath(__file__))) @@ -254,6 +258,7 @@ def test_inputs(capsys, argv): (None, 2, " error: "), # NOTE: None -> sys.argv from pystest (["-v"], 0, version), ([], 2, "error: missing input files"), + (["-di", "AAAx.mol2"], 19, "ACPYPE FAILED: Input file AAAx.mol2 DOES NOT EXIST"), (["-di", " 123"], 19, "ACPYPE FAILED: [Errno 2] No such file or directory"), (["-di", " 123", "-x", "abc"], 2, "either '-i' or ('-p', '-x'), but not both"), (["-di", " 123", "-u"], 2, "option -u is only meaningful in 'amb2gmx' mode (args '-p' and '-x')"), @@ -261,7 +266,7 @@ def test_inputs(capsys, argv): ) def test_args_wrong_inputs(capsys, argv, code, msg): with pytest.raises(SystemExit) as e_info: - init_main(argv) + init_main(argv=argv) captured = capsys.readouterr() assert msg in captured.err + captured.out assert e_info.typename == "SystemExit" From 3d53821fef354a5264bf922bd8ee0a25d7b12c5f Mon Sep 17 00:00:00 2001 From: Alan Silva <3899850+alanwilter@users.noreply.github.com> Date: Sun, 28 Nov 2021 20:39:26 +0000 Subject: [PATCH 03/15] Refactored checkSmiles --- acpype_lib/acpype.py | 11 +++--- acpype_lib/topol.py | 89 ++++++++++++++++++++++++++++++-------------- acpype_lib/utils.py | 39 ++----------------- 3 files changed, 70 insertions(+), 69 deletions(-) diff --git a/acpype_lib/acpype.py b/acpype_lib/acpype.py index 7a894052..465c6415 100755 --- a/acpype_lib/acpype.py +++ b/acpype_lib/acpype.py @@ -63,8 +63,7 @@ from shutil import rmtree, which from acpype_lib.topol import MolTopol, ACTopol, header from acpype_lib.parser_args import get_option_parser -from acpype_lib.utils import while_replace -from acpype_lib.utils import checkSmiles, elapsedTime +from acpype_lib.utils import while_replace, elapsedTime from acpype_lib.params import binaries @@ -77,12 +76,12 @@ def set_for_pip(): os.pathsep + LOCAL_PATH + "/amber21-11_linux/bin:" + LOCAL_PATH + "/amber21-11_linux/dat/" ) os.environ["AMBERHOME"] = LOCAL_PATH + "/amber21-11_linux/" - os.environ["ACHOME"] = LOCAL_PATH + "/amber21-11_linux/bin/" + # os.environ["ACHOME"] = LOCAL_PATH + "/amber21-11_linux/bin/" os.environ["LD_LIBRARY_PATH"] = LOCAL_PATH + "/amber21-11_linux/lib/" elif sys.platform == "darwin": os.environ["PATH"] += os.pathsep + LOCAL_PATH + "/amber21-11_os/bin:" + LOCAL_PATH + "/amber21-11_os/dat/" os.environ["AMBERHOME"] = LOCAL_PATH + "/amber21-11_os/" - os.environ["ACHOME"] = LOCAL_PATH + "/amber21-11_os/bin/" + # os.environ["ACHOME"] = LOCAL_PATH + "/amber21-11_os/bin/" os.environ["LD_LIBRARY_PATH"] = LOCAL_PATH + "/amber21-11_os/lib/" os.environ["DYLD_LIBRARY_PATH"] = LOCAL_PATH + "/amber21-11_os/lib/" @@ -207,8 +206,8 @@ def init_main(binaries=binaries, argv=None): except Exception: pass - if not amb2gmxF and molecule.babelExe: - if checkSmiles(args.input): + if not amb2gmxF and molecule.obabelExe: + if molecule.checkSmiles(): afile = "smiles_molecule.mol2" if os.path.exists(afile): os.remove(afile) diff --git a/acpype_lib/topol.py b/acpype_lib/topol.py index ed43b777..3391ff56 100644 --- a/acpype_lib/topol.py +++ b/acpype_lib/topol.py @@ -14,7 +14,7 @@ from acpype_lib.params import binaries, ionOrSolResNameList, radPi, cal, outTopols, qDict, qConv, diffTol from acpype_lib.params import dictAtomTypeAmb2OplsGmxCode, dictAtomTypeGaff2OplsGmxCode, oplsCode2AtomTypeDict from acpype_lib.utils import _getoutput, while_replace, distanceAA, job_pids_family, checkOpenBabelVersion -from acpype_lib.utils import checkSmiles, find_antechamber, elapsedTime, imprDihAngle, parmMerge +from acpype_lib.utils import find_bin, elapsedTime, imprDihAngle, parmMerge year = datetime.today().year tag = version @@ -210,7 +210,7 @@ def __init__(self): self.tmpDir = None self.absInputFile = None self.chargeType = None - self.babelExe = None + self.obabelExe = None self.baseName = None self.acExe = None self.force = None @@ -251,7 +251,7 @@ def __init__(self): self.tleapLog = None self.parmchkLog = None self.inputFile = None - self.babelLog = None + self.obabelLog = None self.absHomeDir = None self.molTopol = None self.topFileData = None @@ -316,6 +316,35 @@ def search(self, name=None, alist=False): ll = ll[0] return ll + def checkSmiles(self): + + if find_bin(self.binaries["obabel_bin"]): + if checkOpenBabelVersion() >= 300: + from openbabel import openbabel as ob + from openbabel import pybel + + ob.cvar.obErrorLog.StopLogging() + + elif checkOpenBabelVersion() >= 200 and checkOpenBabelVersion() < 300: + import openbabel as ob + import pybel # type: ignore + + ob.cvar.obErrorLog.StopLogging() + else: + print("WARNING: your input may be a SMILES but") + print(" without OpenBabel, this functionality won't work") + return False + + # Check if input is a smiles string + try: + ob.obErrorLog.SetOutputLevel(0) + pybel.readstring("smi", self.smiles) + return True + except Exception: + ob.obErrorLog.SetOutputLevel(0) + + return False + def guessCharge(self): """ Guess the charge of a system based on antechamber @@ -344,7 +373,7 @@ def guessCharge(self): self.printWarn("no charge value given, trying to guess one...") mol2FileForGuessCharge = self.inputFile if self.ext == ".pdb": - cmd = f"{self.babelExe} -ipdb {self.inputFile} -omol2 -O {self.baseName}.mol2" + cmd = f"{self.obabelExe} -ipdb {self.inputFile} -omol2 -O {self.baseName}.mol2" self.printDebug(f"guessCharge: {cmd}") out = _getoutput(cmd) self.printDebug(out) @@ -955,23 +984,24 @@ def checkFrcmod(self): return check def convertPdbToMol2(self): - """Convert PDB to MOL2 by using babel""" + """Convert PDB to MOL2 by using obabel""" if self.ext == ".pdb": - if self.execBabel(): - self.printError("convert pdb to mol2 via babel failed") + if self.execObabel(): + self.printError(f"convert pdb to mol2 via {binaries['obabel_bin']} failed") return True return False def convertSmilesToMol2(self): - if not self.babelExe: - raise Exception("SMILES needs openbabel python module") + """Convert Smiles to MOL2 by using obabel""" + + if not self.obabelExe: + raise Exception("SMILES needs OpenBabel python module") if checkOpenBabelVersion() >= 300: from openbabel import pybel elif checkOpenBabelVersion() >= 200 and checkOpenBabelVersion() < 300: import pybel # type: ignore - """Convert Smiles to MOL2 by using babel""" try: mymol = pybel.readstring("smi", str(self.smiles)) mymol.addh() @@ -981,20 +1011,20 @@ def convertSmilesToMol2(self): except Exception: return False - def execBabel(self): - """Execute babel""" + def execObabel(self): + """Execute obabel""" self.makeDir() - cmd = f"{self.babelExe} -ipdb {self.inputFile} -omol2 -O {self.baseName}.mol2" + cmd = f"{self.obabelExe} -ipdb {self.inputFile} -omol2 -O {self.baseName}.mol2" self.printDebug(cmd) - self.babelLog = _getoutput(cmd) + self.obabelLog = _getoutput(cmd) self.ext = ".mol2" self.inputFile = self.baseName + self.ext self.acParDict["ext"] = "mol2" if os.path.exists(self.inputFile): self.printMess("* Babel OK *") else: - self.printQuoted(self.babelLog) + self.printQuoted(self.obabelLog) return True return False @@ -1352,7 +1382,7 @@ def getChirals(self): Get chiral atoms, its 4 neighbours and improper dihedral angle to store non-planar improper dihedrals for CNS (and CNS only!) """ - if not self._parent.babelExe: + if not self._parent.obabelExe: self.printWarn("No Openbabel python module, no chiral groups") self.chiralGroups = [] return @@ -3044,6 +3074,7 @@ def __init__( amb2gmx=False, ): super().__init__() + self.binaries = binaries self.amb2gmx = amb2gmx self.debug = debug self.verbose = verbose @@ -3052,13 +3083,13 @@ def __init__( self.direct = direct self.sorted = is_sorted self.chiral = chiral - self.acExe = find_antechamber(binaries["ac_bin"]) + self.acExe = find_bin(binaries["ac_bin"]) if not os.path.exists(self.acExe): - self.printError("no 'antechamber' executable... aborting! ") - hint1 = "HINT1: is 'AMBERHOME' or 'ACHOME' environment variable set?" + self.printError(f"no '{binaries['ac_bin']}' executable... aborting! ") + hint1 = "HINT1: is 'AMBERHOME' environment variable set?" hint2 = ( - "HINT2: is 'antechamber' in your $PATH?" - + "\n What 'which antechamber' in your terminal says?" + f"HINT2: is '{binaries['ac_bin']}' in your $PATH?" + + f"\n What 'which {binaries['ac_bin']}' in your terminal says?" + "\n 'alias' doesn't work for ACPYPE." ) self.printMess(hint1) @@ -3067,10 +3098,11 @@ def __init__( self.inputFile = os.path.basename(inputFile) self.rootDir = os.path.abspath(".") self.absInputFile = os.path.abspath(inputFile) + if not os.path.exists(self.absInputFile) and not re.search(r"\.mol2$|\.mdl$|\.pdb$", self.inputFile): - if checkSmiles(inputFile): + self.smiles = inputFile + if self.checkSmiles(): self.is_smiles = True - self.smiles = inputFile if not basename: self.inputFile = "smiles_molecule.mol2" else: @@ -3078,6 +3110,7 @@ def __init__( self.absInputFile = os.path.abspath(self.inputFile) else: self.is_smiles = False + self.smiles = None elif not os.path.exists(self.absInputFile): raise Exception(f"Input file {inputFile} DOES NOT EXIST") baseOriginal, ext = os.path.splitext(self.inputFile) @@ -3085,14 +3118,14 @@ def __init__( self.baseOriginal = baseOriginal self.ext = ext self.baseName = base # name of the input file without ext. - self.babelExe = which("obabel") or "" - if not os.path.exists(self.babelExe): + self.obabelExe = find_bin(binaries["obabel_bin"]) + if not os.path.exists(self.obabelExe): if self.ext != ".mol2" and self.ext != ".mdl": - self.printError("no 'babel' executable; you need it if input is PDB or SMILES") + self.printError(f"no '{binaries['obabel_bin']}' executable; you need it if input is PDB or SMILES") self.printError("otherwise use only MOL2 or MDL file as input ... aborting!") - raise Exception("Missing BABEL") + raise Exception("Missing OBABEL") else: - self.printWarn("no 'babel' executable, no PDB file as input can be used!") + self.printWarn(f"no '{binaries['obabel_bin']}' executable, no PDB file can be used as input!") if self.is_smiles: self.convertSmilesToMol2() self.timeTol = timeTol diff --git a/acpype_lib/utils.py b/acpype_lib/utils.py index b7f9d24e..bf88662b 100644 --- a/acpype_lib/utils.py +++ b/acpype_lib/utils.py @@ -5,6 +5,10 @@ from acpype_lib.params import Pi +def find_bin(abin): + return which(abin) or "" + + def checkOpenBabelVersion(): "check openbabel version" import openbabel as obl @@ -14,36 +18,6 @@ def checkOpenBabelVersion(): return int(obl.OBReleaseVersion().replace(".", "")) -def checkSmiles(smiles): - - try: - if checkOpenBabelVersion() >= 300: - from openbabel import openbabel as ob - from openbabel import pybel - - ob.cvar.obErrorLog.StopLogging() - - elif checkOpenBabelVersion() >= 200 and checkOpenBabelVersion() < 300: - import openbabel as ob - import pybel # type: ignore - - ob.cvar.obErrorLog.StopLogging() - except Exception: - print("WARNING: your input may be a SMILES but") - print(" without OpenBabel, this functionality won't work") - return False - - # Check if input is a smiles string - try: - ob.obErrorLog.SetOutputLevel(0) - pybel.readstring("smi", smiles) - return True - except Exception: - ob.obErrorLog.SetOutputLevel(0) - - return False - - def dotproduct(aa, bb): """scalar product""" return sum((a * b) for a, b in zip(aa, bb)) @@ -279,8 +253,3 @@ def while_replace(string): while " " in string: string = string.replace(" ", " ") return string - - -def find_antechamber(abin): - acExe = which(abin) or "" - return acExe From eb8ded651218a2c528869ebab05c953fe641eb5e Mon Sep 17 00:00:00 2001 From: Alan Silva <3899850+alanwilter@users.noreply.github.com> Date: Sun, 28 Nov 2021 20:42:56 +0000 Subject: [PATCH 04/15] New tests for user's scenarios --- tests/test_scenarios.py | 51 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) create mode 100644 tests/test_scenarios.py diff --git a/tests/test_scenarios.py b/tests/test_scenarios.py new file mode 100644 index 00000000..1c4de1e0 --- /dev/null +++ b/tests/test_scenarios.py @@ -0,0 +1,51 @@ +import os +import pytest +from acpype_lib.acpype import init_main +from acpype_lib.utils import _getoutput + + +def test_no_ac(capsys): + binaries = {"ac_bin": "no_ac", "obabel_bin": "obabel"} + msg = f"ERROR: no '{binaries['ac_bin']}' executable... aborting!" + inp = "AAA.mol2" + os.chdir(os.path.dirname(os.path.abspath(__file__))) + with pytest.raises(SystemExit) as e_info: + init_main(argv=["-di", inp, "-c", "gas"], binaries=binaries) + captured = capsys.readouterr() + assert msg in captured.out + assert e_info.typename == "SystemExit" + assert e_info.value.code == 19 + + +def test_only_ac(capsys): + binaries = {"ac_bin": "antechamber", "obabel_bin": "no_obabel"} + msg1 = f"WARNING: no '{binaries['obabel_bin']}' executable, no PDB file can be used as input!" + msg2 = "Total time of execution:" + msg3 = "WARNING: No Openbabel python module, no chiral groups" + inp = "AAA.mol2" + temp_base = "vir_temp" + os.chdir(os.path.dirname(os.path.abspath(__file__))) + init_main(argv=["-di", inp, "-c", "gas", "-b", temp_base], binaries=binaries) + captured = capsys.readouterr() + assert msg1 in captured.out + assert msg2 in captured.out + assert msg3 in captured.out + _getoutput(f"rm -fr {temp_base}*") + + +@pytest.mark.parametrize( + ("inp", "msg"), + [ + ("AAA.pdb", "ERROR: no 'no_obabel' executable; you need it if input is PDB or SMILES"), + ("cccc", "WARNING: your input may be a SMILES but"), + ], +) +def test_no_obabel(capsys, inp, msg): + binaries = {"ac_bin": "antechamber", "obabel_bin": "no_obabel"} + os.chdir(os.path.dirname(os.path.abspath(__file__))) + with pytest.raises(SystemExit) as e_info: + init_main(argv=["-di", inp, "-c", "gas"], binaries=binaries) + captured = capsys.readouterr() + assert msg in captured.out + assert e_info.typename == "SystemExit" + assert e_info.value.code == 19 From 32407d94f339b866f1c43b2fffc1c976ea828712 Mon Sep 17 00:00:00 2001 From: Alan Silva <3899850+alanwilter@users.noreply.github.com> Date: Sun, 28 Nov 2021 20:54:07 +0000 Subject: [PATCH 05/15] Added test_amb2gmx_no_bins --- tests/test_scenarios.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/tests/test_scenarios.py b/tests/test_scenarios.py index 1c4de1e0..9a2ed52d 100644 --- a/tests/test_scenarios.py +++ b/tests/test_scenarios.py @@ -49,3 +49,15 @@ def test_no_obabel(capsys, inp, msg): assert msg in captured.out assert e_info.typename == "SystemExit" assert e_info.value.code == 19 + + +def test_amb2gmx_no_bins(capsys): + binaries = {"ac_bin": "no_ac", "obabel_bin": "no_obabel"} + os.chdir(os.path.dirname(os.path.abspath(__file__))) + argv = ["-x", "Base.inpcrd", "-p", "Base.prmtop"] + temp_base = "vir_temp" + init_main(argv=argv + ["-b", temp_base], binaries=binaries) + captured = capsys.readouterr() + assert "Total time of execution:" in captured.out + os.chdir(os.path.dirname(os.path.abspath(__file__))) + _getoutput(f"rm -fr {temp_base}*") From 4af778b477a2cb46272689d509385877dd9da13c Mon Sep 17 00:00:00 2001 From: Alan Silva <3899850+alanwilter@users.noreply.github.com> Date: Sun, 28 Nov 2021 23:11:28 +0000 Subject: [PATCH 06/15] Bash script to simplify acpype docker usage --- Dockerfile | 4 +++- acpype_docker.sh | 3 +++ 2 files changed, 6 insertions(+), 1 deletion(-) create mode 100755 acpype_docker.sh diff --git a/Dockerfile b/Dockerfile index 4476a734..3228512b 100644 --- a/Dockerfile +++ b/Dockerfile @@ -29,9 +29,11 @@ RUN apt-get update && apt-get install -y \ python3-openbabel \ libgfortran5 \ libarpack++2-dev \ + python3-ipython \ && apt-get autoremove -y && apt-get autoclean -y && apt-get clean -y \ && rm -rf /var/lib/apt/lists/* COPY run_acpype.py /home COPY acpype_lib /home/acpype_lib -RUN ln -s /home/run_acpype.py /usr/local/bin/acpype \ No newline at end of file +RUN ln -s /home/run_acpype.py /usr/local/bin/acpype +ENV PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/home/amber21/bin" \ No newline at end of file diff --git a/acpype_docker.sh b/acpype_docker.sh new file mode 100755 index 00000000..f8827b85 --- /dev/null +++ b/acpype_docker.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash + +docker run -i -t -v "${PWD}":/wdir -w /wdir acpype/acpype acpype "$@" From abf38dd646d5abfa77fbf76926aa3571f361ce2e Mon Sep 17 00:00:00 2001 From: Alan Silva <3899850+alanwilter@users.noreply.github.com> Date: Sun, 28 Nov 2021 23:21:39 +0000 Subject: [PATCH 07/15] Update README for acpype_docker usage --- README.md | 23 +++++++++-------------- 1 file changed, 9 insertions(+), 14 deletions(-) diff --git a/README.md b/README.md index 27679390..86c22d7d 100644 --- a/README.md +++ b/README.md @@ -110,23 +110,18 @@ There are several ways of obtaining `acpype`: 4. Via **[Docker](https://hub.docker.com/repository/docker/acpype/acpype/)**: - If you have Docker installed, you can run `acpype` by: - - ```bash - docker pull acpype/acpype:latest - ``` + If you have Docker installed, you can run `acpype_docker.sh` by: + + NOTE: first time may take some time as it pulls the `acpype` docker image. - Then, on Linux / MacOS choose a folder where to work (e.g. contains your PDB, MOL2 or inpcrd/prmtop files) and do: + On Linux / MacOS: ```bash + ln -fsv "$PWD/acpype_docker.sh" /usr/local/bin/acpype_docker + + acpype_docker -i CCCC - # it opens a terminal inside docker with access to your working folder - docker run -i -t --rm -v ${PWD}:/wdir -w /wdir acpype/acpype bash - - # use acpype - acpype -i CCCC - acpype -i DDD.pdb -c gas # if you have a DDD.pdb file there in "wdir" ($PWD) - exit # and your output files will be at your working directory ($PWD) + acpype_docker -i tests/DDD.pdb -c gas ``` On Windows: @@ -174,7 +169,7 @@ To get help and more information, type: At folder `acpype/`, type: ```bash - ln -s $PWD/run_acpype.py /usr/local/bin/acpype + ln -fsv "$PWD/run_acpype.py" /usr/local/bin/acpype ``` Then re-login or start another shell session. From 10c7548a5ed775d44b73f23f251341c27780b353 Mon Sep 17 00:00:00 2001 From: Alan Silva <3899850+alanwilter@users.noreply.github.com> Date: Mon, 29 Nov 2021 10:59:33 +0000 Subject: [PATCH 08/15] Script for releasing in pip and docker --- release.sh | 80 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 80 insertions(+) create mode 100755 release.sh diff --git a/release.sh b/release.sh new file mode 100755 index 00000000..74ce1966 --- /dev/null +++ b/release.sh @@ -0,0 +1,80 @@ +#!/usr/bin/env bash + +# Create releases for pip or docker or both + +set -euo pipefail + +function usage() { + echo "syntax: $0 < [-p, -d] | -a > to create a release for pip or docker or both" + echo " -p : for pip, create wheel and upload to https://pypi.org/project/acpype/ (if you have permission)" + echo " -d : for docker, create images and upload to https://hub.docker.com/u/acpype (if you have permission)" + echo " -a : do both above" + echo " -v : verbose mode, print all commands" + echo " -h : prints this message" + exit 1 +} + +function run_pip() { + echo ">>> Creating pip package" + python3 -m build + python3 -m twine upload --repository testpypi dist/*"$today"* # TestPyPI + python3 -m twine upload --repository acpype dist/*"$today"* # official release + rm -vfr dist/*"$today"* +} + +function run_docker() { + echo ">>> Creating docker images" + docker build -t acpype/acpype:latest -t acpype/acpype:"$today" . + + echo ">>> Pushing docker images" + docker push acpype/acpype --all-tags + docker image rm acpype/acpype:"$today" +} + +function run_both() { + run_docker + run_pip +} + +do_pip=false +do_doc=false +do_all=false +verb=false +no_args=true + +while getopts "adpvh" optionName; do + case "$optionName" in + a) do_all=true ;; + d) do_doc=true ;; + p) do_pip=true ;; + v) verb=true ;; + h) usage ;; + ?) usage ;; + *) usage ;; + esac + no_args=false +done + +if "${no_args}"; then + usage +elif $do_all && ($do_doc || $do_pip); then + usage +fi + +if ${verb}; then + set -x +fi + +today="$(date +%Y.%m.%d)" + +if $do_pip; then + run_pip +fi + +if $do_doc; then + run_docker +fi + +if $do_all; then + run_both +fi From 00f0a7e0429fbdab34912c8bef02159048ca7a60 Mon Sep 17 00:00:00 2001 From: Alan Silva <3899850+alanwilter@users.noreply.github.com> Date: Mon, 29 Nov 2021 14:01:14 +0000 Subject: [PATCH 09/15] Use verson instead of today --- release.sh | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/release.sh b/release.sh index 74ce1966..c38d434c 100755 --- a/release.sh +++ b/release.sh @@ -4,6 +4,8 @@ set -euo pipefail +version="$(grep -o '[0-9]\{4\}\.[0-9]\{2\}\.[0-9]\{2\}' acpype_lib/__init__.py)" + function usage() { echo "syntax: $0 < [-p, -d] | -a > to create a release for pip or docker or both" echo " -p : for pip, create wheel and upload to https://pypi.org/project/acpype/ (if you have permission)" @@ -17,18 +19,17 @@ function usage() { function run_pip() { echo ">>> Creating pip package" python3 -m build - python3 -m twine upload --repository testpypi dist/*"$today"* # TestPyPI - python3 -m twine upload --repository acpype dist/*"$today"* # official release - rm -vfr dist/*"$today"* + python3 -m twine upload --repository testpypi dist/*"$version"* # TestPyPI + python3 -m twine upload --repository pypi dist/*"$version"* # official release + rm -vfr dist/*"$version"* } function run_docker() { echo ">>> Creating docker images" - docker build -t acpype/acpype:latest -t acpype/acpype:"$today" . - + docker build -t acpype/acpype:latest -t acpype/acpype:"$version" . echo ">>> Pushing docker images" docker push acpype/acpype --all-tags - docker image rm acpype/acpype:"$today" + docker image rm acpype/acpype:"$version" } function run_both() { @@ -65,8 +66,6 @@ if ${verb}; then set -x fi -today="$(date +%Y.%m.%d)" - if $do_pip; then run_pip fi From aecc53973d02618a6c9d78cd20b8b6115a738041 Mon Sep 17 00:00:00 2001 From: Alan Silva <3899850+alanwilter@users.noreply.github.com> Date: Mon, 29 Nov 2021 14:12:21 +0000 Subject: [PATCH 10/15] Simplified set_for_pip() --- acpype_lib/acpype.py | 28 +++++++++++++--------------- 1 file changed, 13 insertions(+), 15 deletions(-) diff --git a/acpype_lib/acpype.py b/acpype_lib/acpype.py index 465c6415..aa949568 100755 --- a/acpype_lib/acpype.py +++ b/acpype_lib/acpype.py @@ -59,7 +59,6 @@ import time import os import sys -import sysconfig from shutil import rmtree, which from acpype_lib.topol import MolTopol, ACTopol, header from acpype_lib.parser_args import get_option_parser @@ -70,20 +69,19 @@ def set_for_pip(): # For pip package if which(binaries["ac_bin"]) is None: - LOCAL_PATH = sysconfig.get_paths()["purelib"] - if sys.platform == "linux": - os.environ["PATH"] += ( - os.pathsep + LOCAL_PATH + "/amber21-11_linux/bin:" + LOCAL_PATH + "/amber21-11_linux/dat/" - ) - os.environ["AMBERHOME"] = LOCAL_PATH + "/amber21-11_linux/" - # os.environ["ACHOME"] = LOCAL_PATH + "/amber21-11_linux/bin/" - os.environ["LD_LIBRARY_PATH"] = LOCAL_PATH + "/amber21-11_linux/lib/" - elif sys.platform == "darwin": - os.environ["PATH"] += os.pathsep + LOCAL_PATH + "/amber21-11_os/bin:" + LOCAL_PATH + "/amber21-11_os/dat/" - os.environ["AMBERHOME"] = LOCAL_PATH + "/amber21-11_os/" - # os.environ["ACHOME"] = LOCAL_PATH + "/amber21-11_os/bin/" - os.environ["LD_LIBRARY_PATH"] = LOCAL_PATH + "/amber21-11_os/lib/" - os.environ["DYLD_LIBRARY_PATH"] = LOCAL_PATH + "/amber21-11_os/lib/" + try: + LOCAL_PATH = os.path.dirname(os.path.dirname(__file__)) + if sys.platform == "linux": + os.environ["PATH"] += os.pathsep + LOCAL_PATH + "/amber21-11_linux/bin" + os.environ["AMBERHOME"] = LOCAL_PATH + "/amber21-11_linux/" + os.environ["LD_LIBRARY_PATH"] = LOCAL_PATH + "/amber21-11_linux/lib/" + elif sys.platform == "darwin": + os.environ["PATH"] += os.pathsep + LOCAL_PATH + "/amber21-11_os/bin" + os.environ["AMBERHOME"] = LOCAL_PATH + "/amber21-11_os/" + os.environ["LD_LIBRARY_PATH"] = LOCAL_PATH + "/amber21-11_os/lib/" + os.environ["DYLD_LIBRARY_PATH"] = LOCAL_PATH + "/amber21-11_os/lib/" + except Exception: + print("ERROR: AmberTools NOT FOUND") def chk_py_ver(): From 69f38eafc69ca8b124202f66643d36e8e3606e7f Mon Sep 17 00:00:00 2001 From: Alan Silva <3899850+alanwilter@users.noreply.github.com> Date: Mon, 29 Nov 2021 19:40:55 +0000 Subject: [PATCH 11/15] Badges and review usage --- README.md | 44 +++++++++++++++++++++++++++++++++----------- 1 file changed, 33 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index 86c22d7d..54026a1d 100644 --- a/README.md +++ b/README.md @@ -1,12 +1,17 @@ # ACPYPE -![GitHub](https://img.shields.io/github/license/alanwilter/acpype?style=social) -![GitHub All Releases](https://img.shields.io/github/downloads/alanwilter/acpype/total?style=social) -![Docker Pulls](https://img.shields.io/docker/pulls/acpype/acpype?style=social&logo=docker) -![Docker Image Size (tag)](https://img.shields.io/docker/image-size/lpkagami/acpype/latest?style=social&logo=docker) -![GitHub Relase](https://img.shields.io/github/release-date/alanwilter/acpype?style=social) -![Conda Version](https://img.shields.io/conda/vn/conda-forge/acpype.svg) -![Conda Downloads](https://img.shields.io/conda/dn/conda-forge/acpype.svg) +![GitHub](https://img.shields.io/github/license/alanwilter/acpype?style=plastic) +![GitHub release (latest by date)](https://img.shields.io/github/v/release/alanwilter/acpype?display_name=tag&logo=github&style=plastic) +![GitHub Relase](https://img.shields.io/github/release-date/alanwilter/acpype?style=plastic&logo=github) +![Docker Pulls](https://img.shields.io/docker/pulls/acpype/acpype?style=plastic&logo=docker) +![Docker Image Size (tag)](https://img.shields.io/docker/image-size/acpype/acpype/latest?style=plastic&logo=docker) +![Conda Version](https://img.shields.io/conda/vn/conda-forge/acpype.svg?style=plastic&logo=conda-forge) +![Conda Downloads](https://img.shields.io/conda/dn/conda-forge/acpype.svg?style=plastic&logo=conda-forge) +![PyPI](https://img.shields.io/pypi/v/acpype?style=plastic&logo=pypi) +![PyPI - Downloads](https://img.shields.io/pypi/dm/acpype?style=plastic&logo=pypi) +![GitHub Workflow Status](https://img.shields.io/github/workflow/status/alanwilter/acpype/check_acpype) + + ## AnteChamber PYthon Parser interfacE @@ -87,21 +92,33 @@ There are several ways of obtaining `acpype`: 1. Via **[CONDA](https://anaconda.org/search?q=acpype)**: + *(It should be wholesome, fully funcional, all batteries included)* + ```bash conda install -c conda-forge acpype ``` 2. Via **[PyPI](https://pypi.org/project/acpype/)**: + *(Make sure you have `AmberTools` and, optionally but highly recommended, `OpenBabel` )* + ```bash + # You can use conda to get the needed 3rd parties for example + conda create -n acpype --channel conda-forge ambertools openbabel + + pip install acpype + + # or if you daring + pip install git+https://github.com/alanwilter/acpype.git ``` - note that `pip install acpype`, unfortunately, is not *yet* picking the original one. - 3. By downloading it via `git`: + *(Make sure you have `AmberTools` and, optionally but highly recommended, `OpenBabel` )* + ```bash + # You can use conda to get the needed 3rd parties for example conda create -n acpype --channel conda-forge ambertools openbabel git clone https://github.com/alanwilter/acpype.git ``` @@ -110,6 +127,8 @@ There are several ways of obtaining `acpype`: 4. Via **[Docker](https://hub.docker.com/repository/docker/acpype/acpype/)**: + *(It should be wholesome, fully funcional, all batteries included)* + If you have Docker installed, you can run `acpype_docker.sh` by: NOTE: first time may take some time as it pulls the `acpype` docker image. @@ -137,7 +156,10 @@ There are several ways of obtaining `acpype`: docker run -i -t --rm -v ${PWD}:/wdir -w /wdir acpype bash ``` -**NB:** Installing via `conda` or via `pip/git` you get `AmberTools v.21.11` and `OpenBabel v3.11`. Our `AmberTools v.21.11` comes with binary `charmmgen` from `AmberTools17` in order to generate CHARMM topologies. +**NB:** + +- By installing via `conda` or using via `docker` you get `AmberTools v.21.11` and `OpenBabel v3.1.1`. Our `AmberTools v.21.11` comes with binary `charmmgen` from `AmberTools17` in order to generate CHARMM topologies. +- By installing via `pip` you get `AmberTools` (as described above) embeded. However, the included binaries may not work in your system (library dependecies issues) and with only provide binaries for Linux (Ubuntu20) and Mac OSX. ##### To Test, if doing via `git` @@ -236,4 +258,4 @@ cns < FFF_CNS.inp #### To Verify with NAMD -- see [TutorialNAMD] +- see [TutorialNAMD](../../Tutorial-NAMD) From ceef3f57c9c43a5e2038b0cbad9e39ba85d479ae Mon Sep 17 00:00:00 2001 From: Alan Silva <3899850+alanwilter@users.noreply.github.com> Date: Mon, 29 Nov 2021 19:59:26 +0000 Subject: [PATCH 12/15] Fixed typos --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 54026a1d..62aae06c 100644 --- a/README.md +++ b/README.md @@ -108,7 +108,7 @@ There are several ways of obtaining `acpype`: pip install acpype - # or if you daring + # or if you feel daring pip install git+https://github.com/alanwilter/acpype.git ``` @@ -258,4 +258,4 @@ cns < FFF_CNS.inp #### To Verify with NAMD -- see [TutorialNAMD](../../Tutorial-NAMD) +- see [TutorialNAMD](../../wiki/Tutorial-NAMD) From e4cd7b0a9d580497e3eb5610588289903b4b8fff Mon Sep 17 00:00:00 2001 From: Alan Silva <3899850+alanwilter@users.noreply.github.com> Date: Mon, 29 Nov 2021 20:23:44 +0000 Subject: [PATCH 13/15] Better documented tests, total coverage 92% --- tests/conftest.py | 10 ++++++++++ tests/test_acpype.py | 12 ------------ tests/test_acs_api.py | 12 ------------ 3 files changed, 10 insertions(+), 24 deletions(-) diff --git a/tests/conftest.py b/tests/conftest.py index aae41e23..3f681d1c 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -1,3 +1,13 @@ +""" +Requirements: +* pytest +* pytest-html + +To run: +pytest -s --html=report.html +pytest --cov=acpype_lib --cov-report=term-missing:skip-covered +""" + from acpype_lib import __version__ as version diff --git a/tests/test_acpype.py b/tests/test_acpype.py index 9dc4b6da..788d6aa3 100644 --- a/tests/test_acpype.py +++ b/tests/test_acpype.py @@ -1,15 +1,3 @@ -#!/usr/bin/env python3 -# -*- coding: utf-8 -*- - -""" -Requirements: -* pytest -* pytest-html - -To run: -pytest -s --html=report.html - -""" import os import shutil import pytest diff --git a/tests/test_acs_api.py b/tests/test_acs_api.py index 560ba0ed..ab0db65c 100644 --- a/tests/test_acs_api.py +++ b/tests/test_acs_api.py @@ -1,15 +1,3 @@ -#!/usr/bin/env python3 -# -*- coding: utf-8 -*- - -""" -Requirements: -* pytest -* pytest-html - -To run: -pytest -s --html=report.html - -""" import os import ujson as json from acpype_lib.acs_api import acpype_api From ac289b17a7a92ae8d975e23d88fe390f7f00d713 Mon Sep 17 00:00:00 2001 From: lkagami Date: Mon, 29 Nov 2021 18:45:32 -0300 Subject: [PATCH 14/15] add acpype_docker.bat file --- README.md | 20 +++++++++----------- acpype_docker.bat | 2 ++ 2 files changed, 11 insertions(+), 11 deletions(-) create mode 100755 acpype_docker.bat diff --git a/README.md b/README.md index 62aae06c..58095da6 100644 --- a/README.md +++ b/README.md @@ -107,9 +107,9 @@ There are several ways of obtaining `acpype`: conda create -n acpype --channel conda-forge ambertools openbabel pip install acpype - + # or if you feel daring - + pip install git+https://github.com/alanwilter/acpype.git ``` @@ -138,24 +138,22 @@ There are several ways of obtaining `acpype`: ```bash ln -fsv "$PWD/acpype_docker.sh" /usr/local/bin/acpype_docker - acpype_docker -i CCCC - - acpype_docker -i tests/DDD.pdb -c gas ``` On Windows: Using Command Prompt: - ```bash - docker run -i -t --rm -v%cd%:/wdir -w /wdir acpype bash - ``` - - Using PowerShell: + In the directory where the `acpype_docker.bat` file is found: ```bash - docker run -i -t --rm -v ${PWD}:/wdir -w /wdir acpype bash + setx /M path "%path%;%cd%" ``` + Commands: + ```bash + acpype_docker -i CCCC + acpype_docker -i tests/DDD.pdb -c gas + ``` **NB:** - By installing via `conda` or using via `docker` you get `AmberTools v.21.11` and `OpenBabel v3.1.1`. Our `AmberTools v.21.11` comes with binary `charmmgen` from `AmberTools17` in order to generate CHARMM topologies. diff --git a/acpype_docker.bat b/acpype_docker.bat new file mode 100755 index 00000000..ff9d0232 --- /dev/null +++ b/acpype_docker.bat @@ -0,0 +1,2 @@ +@echo on +docker run -i -t -v %cd%:/wdir -w /wdir acpype/acpype acpype %* \ No newline at end of file From 69302b0af7bc4be0bc3affa51fbcd4d39ad34dc7 Mon Sep 17 00:00:00 2001 From: Alan Silva <3899850+alanwilter@users.noreply.github.com> Date: Mon, 29 Nov 2021 21:57:14 +0000 Subject: [PATCH 15/15] Bump version --- acpype_lib/__init__.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/acpype_lib/__init__.py b/acpype_lib/__init__.py index 99f6808d..42bb8fdb 100644 --- a/acpype_lib/__init__.py +++ b/acpype_lib/__init__.py @@ -1,3 +1,4 @@ # from https://packaging.python.org/guides/single-sourcing-package-version/ # using option 2 -__version__ = "2021.11.28" +# updated automatically via pre-commit git-hook +__version__ = "2021.11.29"