Command Line Interface and Options¶
This chapter describes how Options classes that are derived from
OEOptions
can be configured with command line
inputs passed in through argv
.
The OESystem.OEConfigureOpts
is a convenience function
that takes an OEOptions
derivative options class and
the command line arguments argv
, parses the command line arguments,
and configures the option parameters with command line inputs. A
OEInterface
is generated internally from the
OEOptions
, which performs the command lines parsing.
Note that this only applies to Options classes that are derived from the
OEOptions
. There are a handful of Options classes
that still does not derive from OEOptions
, and hence cannot
be configured with command line inputs directly.
Command Line Interface Definitions is an
alternative way to work with command line interfaces for such cases.
In addition to the convenience function OESystem.OEConfigureOpts
,
two additional general purpose Options classes, OESimpleAppOptions
,
and OERefInputAppOptions
, are provided that extends
any other options classes to include necessary input/output parameters that are
generally required to create an application.
See also
OEConfigureOpts
functionOEOptions
classOESimpleAppOptions
classOERefInputAppOptions
class
Application with Input, output, and Options¶
The following example shows how to use the OESimpleAppOptions
class to extend an Options class with an additional input and output file.
The specific example is taken from OEDocking, and uses the
the OEMakeReceptor
function to make a receptor in
a design unit. In this example, the OEMakeReceptorOptions
is extended with an input and output.
Listing 1: Application with input, output, and options (Making Receptor)
#!/usr/bin/env python
# (C) 2017 OpenEye Scientific Software Inc. All rights reserved.
#
# TERMS FOR USE OF SAMPLE CODE The software below ("Sample Code") is
# provided to current licensees or subscribers of OpenEye products or
# SaaS offerings (each a "Customer").
# Customer is hereby permitted to use, copy, and modify the Sample Code,
# subject to these terms. OpenEye claims no rights to Customer's
# modifications. Modification of Sample Code is at Customer's sole and
# exclusive risk. Sample Code may require Customer to have a then
# current license or subscription to the applicable OpenEye offering.
# THE SAMPLE CODE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
# EXPRESS OR IMPLIED. OPENEYE DISCLAIMS ALL WARRANTIES, INCLUDING, BUT
# NOT LIMITED TO, WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
# PARTICULAR PURPOSE AND NONINFRINGEMENT. In no event shall OpenEye be
# liable for any damages or liability in connection with the Sample Code
# or its use.
import sys
from openeye import oechem
from openeye import oedocking
def main(argv=[__name__]):
recOpts = oedocking.OEMakeReceptorOptions()
opts = oechem.OESimpleAppOptions(recOpts, "MakeReceptor", oechem.OEFileStringType_DU, oechem.OEFileStringType_DU)
if oechem.OEConfigureOpts(opts, argv, False) == oechem.OEOptsConfigureStatus_Help:
return 0
recOpts.UpdateValues(opts)
ifs = oechem.oeifstream()
if not ifs.open(opts.GetInFile()):
oechem.OEThrow.Fatal("Unable to open %s for reading" % opts.GetInFile())
ofs = oechem.oeofstream()
if not ofs.open(opts.GetOutFile()):
oechem.OEThrow.Fatal("Unable to open %s for writing" % opts.GetOutFile())
du = oechem.OEDesignUnit()
while oechem.OEReadDesignUnit(ifs, du):
if oedocking.OEMakeReceptor(du, recOpts):
oechem.OEWriteDesignUnit(ofs, du)
else:
oechem.OEThrow.Warning("%s: %s" % (du.GetTitle(), "Failed to make receptor"))
return 0
if __name__ == "__main__":
sys.exit(main(sys.argv))
Download code
Application with Reference system, Input, output, and Options¶
Besides an input and output, some application requires an additional
reference system input. The OERefInputAppOptions
class
can be used to extend an options class with three additional parameters,
an input, output, and a reference system.
The following code example is taken from OEDocking, and uses
the OEDock
object to perform docking. In this example,
the OEDockOptions
is extended with an input, output,
and a receptor (i.e., the reference system).
Listing 2: Application with input, reference, output, and options (Docking Molecules)
#!/usr/bin/env python
# (C) 2017 OpenEye Scientific Software Inc. All rights reserved.
#
# TERMS FOR USE OF SAMPLE CODE The software below ("Sample Code") is
# provided to current licensees or subscribers of OpenEye products or
# SaaS offerings (each a "Customer").
# Customer is hereby permitted to use, copy, and modify the Sample Code,
# subject to these terms. OpenEye claims no rights to Customer's
# modifications. Modification of Sample Code is at Customer's sole and
# exclusive risk. Sample Code may require Customer to have a then
# current license or subscription to the applicable OpenEye offering.
# THE SAMPLE CODE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
# EXPRESS OR IMPLIED. OPENEYE DISCLAIMS ALL WARRANTIES, INCLUDING, BUT
# NOT LIMITED TO, WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
# PARTICULAR PURPOSE AND NONINFRINGEMENT. In no event shall OpenEye be
# liable for any damages or liability in connection with the Sample Code
# or its use.
import sys
from openeye import oechem
from openeye import oedocking
def main(argv=[__name__]):
dockOpts = oedocking.OEDockOptions()
opts = oechem.OERefInputAppOptions(dockOpts, "DockMolecules", oechem.OEFileStringType_Mol3D,
oechem.OEFileStringType_Mol3D, oechem.OEFileStringType_DU, "-receptor")
if oechem.OEConfigureOpts(opts, argv, False) == oechem.OEOptsConfigureStatus_Help:
return 0
dockOpts.UpdateValues(opts)
ifs = oechem.oemolistream()
if not ifs.open(opts.GetInFile()):
oechem.OEThrow.Fatal("Unable to open %s for reading" % opts.GetInFile())
rfs = oechem.oeifstream()
if not rfs.open(opts.GetRefFile()):
oechem.OEThrow.Fatal("Unable to open %s for reading" % opts.GetRefFile())
ofs = oechem.oemolostream()
if not ofs.open(opts.GetOutFile()):
oechem.OEThrow.Fatal("Unable to open %s for writing" % opts.GetOutFile())
du = oechem.OEDesignUnit()
if not oechem.OEReadDesignUnit(rfs, du):
oechem.OEThrow.Fatal("Failed to read design unit")
if not du.HasReceptor():
oechem.OEThrow.Fatal("Design unit %s does not contain a receptor" % du.GetTitle())
dock = oedocking.OEDock(dockOpts)
dock.Initialize(du)
for mcmol in ifs.GetOEMols():
print("docking", mcmol.GetTitle())
dockedMol = oechem.OEGraphMol()
retCode = dock.DockMultiConformerMolecule(dockedMol, mcmol)
if (retCode != oedocking.OEDockingReturnCode_Success):
oechem.OEThrow.Fatal("Docking Failed with error code " + oedocking.OEDockingReturnCodeGetName(retCode))
sdtag = oedocking.OEDockMethodGetName(dockOpts.GetScoreMethod())
oedocking.OESetSDScore(dockedMol, dock, sdtag)
dock.AnnotatePose(dockedMol)
oechem.OEWriteMolecule(ofs, dockedMol)
return 0
if __name__ == "__main__":
sys.exit(main(sys.argv))
Download code
Application with Input and output only¶
Some applications do not have any addtionl option or parameter, and only requires
an input and output. The OESimpleAppOptions
class
has an overload that does not require an OEOptions
input argument.
The following code example is taken from OEQuacpac, and uses
the OEAssignCharges
method to assign charges in
a OEDesignUnit
. This example only configures an
input and output, and does not have any additional parameters to configure.
Listing 3: Application with input and output only (DesignUnit Charges)
#!/usr/bin/env python
# (C) 2021 OpenEye Scientific Software Inc. All rights reserved.
#
# TERMS FOR USE OF SAMPLE CODE The software below ("Sample Code") is
# provided to current licensees or subscribers of OpenEye products or
# SaaS offerings (each a "Customer").
# Customer is hereby permitted to use, copy, and modify the Sample Code,
# subject to these terms. OpenEye claims no rights to Customer's
# modifications. Modification of Sample Code is at Customer's sole and
# exclusive risk. Sample Code may require Customer to have a then
# current license or subscription to the applicable OpenEye offering.
# THE SAMPLE CODE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
# EXPRESS OR IMPLIED. OPENEYE DISCLAIMS ALL WARRANTIES, INCLUDING, BUT
# NOT LIMITED TO, WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
# PARTICULAR PURPOSE AND NONINFRINGEMENT. In no event shall OpenEye be
# liable for any damages or liability in connection with the Sample Code
# or its use.
#############################################################################
# This program demonstrates how to apply charges to an OEDesignUnit.
#############################################################################
import sys
from openeye import oechem
from openeye import oequacpac
def main(argv=[__name__]):
opts = oechem.OESimpleAppOptions("applycharges_du", oechem.OEFileStringType_DU,
oechem.OEFileStringType_DU)
if oechem.OEConfigureOpts(opts, argv, False) == oechem.OEOptsConfigureStatus_Help:
return 0
ifs = oechem.oeifstream()
if not ifs.open(opts.GetInFile()):
oechem.OEThrow.Fatal("Unable to open %s for reading" % opts.GetInFile())
ofs = oechem.oeofstream()
if not ofs.open(opts.GetOutFile()):
oechem.OEThrow.Fatal("Unable to open %s for writing" % opts.GetOutFile())
du = oechem.OEDesignUnit()
while oechem.OEReadDesignUnit(ifs, du):
charge_engine = oequacpac.OEDesignUnitCharges()
if charge_engine.ApplyCharges(du):
oechem.OEWriteDesignUnit(ofs, du)
else:
oechem.OEThrow.Warning("%s: %s" % (du.GetTitle(), "Failed to assign charges"))
return 0
if __name__ == "__main__":
sys.exit(main(sys.argv))
Download code
Adding custom parameters¶
Custom parameters can also be added to am application API when a built-in Options class does not contain all required parameters for the application.
The following code example is taken from OEDocking, and uses
the OEPosit
object to generate pose structures. In this example,
the OEPositOptions
is extended with an input, output,
and receptor (i.e., the reference system). However, the number of
poses to generate is not a built-in parameter into the OEPositOptions
.
This example shows how to add an additional parameter, for the number of poses,
to be configured through the command line.
Listing 4: Adding custom parameters (POSIT with Multiple Receptors)
#!/usr/bin/env python
# (C) 2021 OpenEye Scientific Software Inc. All rights reserved.
#
# TERMS FOR USE OF SAMPLE CODE The software below ("Sample Code") is
# provided to current licensees or subscribers of OpenEye products or
# SaaS offerings (each a "Customer").
# Customer is hereby permitted to use, copy, and modify the Sample Code,
# subject to these terms. OpenEye claims no rights to Customer's
# modifications. Modification of Sample Code is at Customer's sole and
# exclusive risk. Sample Code may require Customer to have a then
# current license or subscription to the applicable OpenEye offering.
# THE SAMPLE CODE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
# EXPRESS OR IMPLIED. OPENEYE DISCLAIMS ALL WARRANTIES, INCLUDING, BUT
# NOT LIMITED TO, WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
# PARTICULAR PURPOSE AND NONINFRINGEMENT. In no event shall OpenEye be
# liable for any damages or liability in connection with the Sample Code
# or its use.
import sys
from openeye import oechem
from openeye import oedocking
class MyOptions(oedocking.OEPositOptions):
def __init__(self):
oedocking.OEPositOptions.__init__(self)
param1 = oechem.OEUIntParameter("-numPoses", 1)
param1.AddLegalRange("1", "20")
param1.SetBrief("Number of poses to generate")
self._param1 = self.AddParameter(param1)
pass
def GetNumConfs(self):
if self._param1.GetHasValue():
return int(self._param1.GetStringValue())
return int(self._param1.GetStringDefault())
def main(argv=[__name__]):
positOpts = MyOptions()
opts = oechem.OERefInputAppOptions(positOpts, "PoseMolecules", oechem.OEFileStringType_Mol3D,
oechem.OEFileStringType_DU, oechem.OEFileStringType_DU, "-receptor")
if oechem.OEConfigureOpts(opts, argv, False) == oechem.OEOptsConfigureStatus_Help:
return 0
positOpts.UpdateValues(opts)
ifs = oechem.oemolistream()
if not ifs.open(opts.GetInFile()):
oechem.OEThrow.Fatal("Unable to open %s for reading" % opts.GetInFile())
rfs = oechem.oeifstream()
if not rfs.open(opts.GetRefFile()):
oechem.OEThrow.Fatal("Unable to open %s for reading" % opts.GetRefFile())
ofs = oechem.oeofstream()
if not ofs.open(opts.GetOutFile()):
oechem.OEThrow.Fatal("Unable to open %s for writing" % opts.GetOutFile())
poser = oedocking.OEPosit(positOpts)
du = oechem.OEDesignUnit()
count = 0
while oechem.OEReadDesignUnit(rfs, du):
if not du.HasReceptor():
oechem.OEThrow.Fatal("Design unit %s does not contain a receptor" % du.GetTitle())
poser.AddReceptor(du)
count += 1
if count == 0:
oechem.OEThrow.Fatal("Receptor input does not contain any design unit")
oechem.OEThrow.Info("Number of conformers: %d" % positOpts.GetNumConfs())
oechem.OEThrow.Info("Best Receptor pose flag: %s" % positOpts.GetBestReceptorPoseOnly())
for mcmol in ifs.GetOEMols():
oechem.OEThrow.Info("posing %s" % mcmol.GetTitle())
results = oedocking.OEPositResults()
ret_code = poser.Dock(results, mcmol, positOpts.GetNumConfs())
if ret_code == oedocking.OEDockingReturnCode_Success:
for result in results.GetSinglePoseResults():
posedDU = result.GetDesignUnit()
posedDU.SetDoubleData(poser.GetName(), result.GetProbability())
oechem.OEThrow.Info("Receptor used: %s pose probability: %f" % (posedDU.GetTitle(), result.GetProbability()))
oechem.OEWriteDesignUnit(ofs, posedDU)
else:
errMsg = oedocking.OEDockingReturnCodeGetName(ret_code)
oechem.OEThrow.Warning("%s: %s" % (mcmol.GetTitle(), errMsg))
return 0
if __name__ == "__main__":
sys.exit(main(sys.argv))
Download code
Defining new options class¶
Options classes, derived from OEOptions
, can also be defined
at the script level, and wrapped with the OESimpleAppOptions
or OERefInputAppOptions
, to build applications.
The following code example is taken from OEFF, and optimizes molecule conformations using a force field. In this example, a new Options class is defined to accept command line input for the force field.
Listing 5: Defining Options class (Optimize molecule)
#!/usr/bin/env python
# (C) 2017 OpenEye Scientific Software Inc. All rights reserved.
#
# TERMS FOR USE OF SAMPLE CODE The software below ("Sample Code") is
# provided to current licensees or subscribers of OpenEye products or
# SaaS offerings (each a "Customer").
# Customer is hereby permitted to use, copy, and modify the Sample Code,
# subject to these terms. OpenEye claims no rights to Customer's
# modifications. Modification of Sample Code is at Customer's sole and
# exclusive risk. Sample Code may require Customer to have a then
# current license or subscription to the applicable OpenEye offering.
# THE SAMPLE CODE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
# EXPRESS OR IMPLIED. OPENEYE DISCLAIMS ALL WARRANTIES, INCLUDING, BUT
# NOT LIMITED TO, WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
# PARTICULAR PURPOSE AND NONINFRINGEMENT. In no event shall OpenEye be
# liable for any damages or liability in connection with the Sample Code
# or its use.
import sys
from openeye import oechem
from openeye import oeff
# //////////////////////////////////////////////////////////////////////////
# The following example demonstrates how to perform ligand optimization //
# //////////////////////////////////////////////////////////////////////////
class FFOptions(oechem.OEOptions):
def __init__(self):
oechem.OEOptions.__init__(self, "FFOptions")
ffType = oechem.OEStringParameter("-ff", "parsley")
ffType.AddLegalValue("parsley")
ffType.AddLegalValue("mmff94")
ffType.AddLegalValue("mmff94s")
ffType.SetBrief("Fore field type")
self._fftype = self.AddParameter(ffType)
pass
def CreateCopy(self):
return self
def GetFF(self):
ff = self._fftype.GetStringValue()
if ff == "":
ff = self._fftype.GetStringDefault()
if ff == "mmff94":
return oeff.OEMMFF()
elif ff == "mmff94s":
return oeff.OEMMFF(oeff.OEMMFF94sParams())
else:
return oeff.OEParsley()
def main(argv=[__name__]):
ffOpts = FFOptions()
opts = oechem.OESimpleAppOptions(ffOpts, "FFOptimize", oechem.OEFileStringType_Mol3D,
oechem.OEFileStringType_Mol3D)
if oechem.OEConfigureOpts(opts, argv, False) == oechem.OEOptsConfigureStatus_Help:
return 0
ffOpts.UpdateValues(opts)
ifs = oechem.oemolistream()
if not ifs.open(opts.GetInFile()):
oechem.OEThrow.Fatal("Unable to open %s for reading" % opts.GetInFile())
ofs = oechem.oemolostream()
if not ofs.open(opts.GetOutFile()):
oechem.OEThrow.Fatal("Unable to open %s for writing" % opts.GetOutFile())
ff = ffOpts.GetFF()
for mol in ifs.GetOEMols():
print("Optimizing", mol.GetTitle())
if not ff.PrepMol(mol) or not ff.Setup(mol):
oechem.OEThrow.Warning("Unable to process molecule: title = '%s'" % mol.GetTitle())
oechem.OEWriteMolecule(ofs, mol)
continue
vecCoords = oechem.OEDoubleArray(3*mol.GetMaxAtomIdx())
for conf in mol.GetConfs():
oechem.OEThrow.Info("Molecule: %s Conformer: %d" % (mol.GetTitle(), conf.GetIdx()+1))
conf.GetCoords(vecCoords)
# Calculate energy
energy = ff(vecCoords)
oechem.OEThrow.Info("Initial energy: %0.2f kcal/mol" % energy)
# Optimize the ligand
optimizer = oeff.OEBFGSOpt()
energy = optimizer(ff, vecCoords, vecCoords)
oechem.OEThrow.Info("Optimized energy: %0.2f kcal/mol" % energy)
conf.SetCoords(vecCoords)
oechem.OEWriteMolecule(ofs, mol)
return 0
if __name__ == "__main__":
sys.exit(main(sys.argv))
Download code