Skip to content

Commit

Permalink
fix: convert/smiles gives 200 response for invalid input - resolves #372
Browse files Browse the repository at this point in the history
  • Loading branch information
CS76 committed Sep 6, 2023
1 parent 981980d commit eea7510
Show file tree
Hide file tree
Showing 2 changed files with 85 additions and 108 deletions.
71 changes: 40 additions & 31 deletions app/modules/toolkits/openbabel_wrapper.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from openbabel import openbabel as ob
from openbabel import pybel
from app.exception_handlers import InvalidInputException


def getOBCanonicalSMILES(smiles: str) -> str:
Expand All @@ -12,9 +13,7 @@ def getOBCanonicalSMILES(smiles: str) -> str:
Returns:
str: Canonical SMILES string.
"""

if any(char.isspace() for char in smiles):
smiles = smiles.replace(" ", "+")
smiles = smiles.replace(" ", "+")

# Create an Open Babel molecule object
mol = ob.OBMol()
Expand All @@ -23,9 +22,12 @@ def getOBCanonicalSMILES(smiles: str) -> str:
conv.SetInAndOutFormats("smi", "can")
conv.ReadString(mol, smiles)

canSMILES = conv.WriteString(mol)
canSMILES = canSMILES.strip() # Remove leading/trailing whitespace
return canSMILES
if mol.NumAtoms() <= 0:
raise InvalidInputException(name="smiles", value=smiles)
else:
canSMILES = conv.WriteString(mol)
canSMILES = canSMILES.strip() # Remove leading/trailing whitespace
return canSMILES


def getOBInChI(smiles: str, InChIKey: bool = False) -> str:
Expand All @@ -40,8 +42,7 @@ def getOBInChI(smiles: str, InChIKey: bool = False) -> str:
str: InChI string or InChIKey string if InChIKey is True.
"""

if any(char.isspace() for char in smiles):
smiles = smiles.replace(" ", "+")
smiles = smiles.replace(" ", "+")

# Create an Open Babel molecule object
mol = ob.OBMol()
Expand All @@ -51,13 +52,16 @@ def getOBInChI(smiles: str, InChIKey: bool = False) -> str:
conv.SetInAndOutFormats("smi", "inchi")
conv.ReadString(mol, smiles)

inchi = conv.WriteString(mol)
inchi = inchi.strip() # Remove leading/trailing whitespace
if InChIKey:
conv.SetOptions("K", conv.OUTOPTIONS)
inchikey_ = conv.WriteString(mol).rstrip()
return inchikey_
return inchi
if mol.NumAtoms() <= 0:
raise InvalidInputException(name="smiles", value=smiles)
else:
inchi = conv.WriteString(mol)
inchi = inchi.strip() # Remove leading/trailing whitespace
if InChIKey:
conv.SetOptions("K", conv.OUTOPTIONS)
inchikey_ = conv.WriteString(mol).rstrip()
return inchikey_
return inchi


def getOBMol(smiles: str, threeD: bool = False, depict: bool = False) -> str:
Expand All @@ -72,20 +76,22 @@ def getOBMol(smiles: str, threeD: bool = False, depict: bool = False) -> str:
Returns:
str: Mol block (2D/3D).
"""
if any(char.isspace() for char in smiles):
smiles = smiles.replace(" ", "+")
smiles = smiles.replace(" ", "+")

if threeD:
mol = pybel.readstring("smi", smiles)
mol.addh()
mol.make3D()
gen3d = ob.OBOp.FindType("gen3D")
gen3d.Do(mol.OBMol, "--best")
if depict:
return mol.write("mol")
if mol.NumAtoms() <= 0:
raise InvalidInputException(name="smiles", value=smiles)
else:
mol.removeh()
return mol.write("mol")
mol.addh()
mol.make3D()
gen3d = ob.OBOp.FindType("gen3D")
gen3d.Do(mol.OBMol, "--best")
if depict:
return mol.write("mol")
else:
mol.removeh()
return mol.write("mol")

# Create an Open Babel molecule object
mol = ob.OBMol()
Expand All @@ -94,10 +100,13 @@ def getOBMol(smiles: str, threeD: bool = False, depict: bool = False) -> str:
conv.SetInAndOutFormats("smi", "mol")
conv.ReadString(mol, smiles)

# Generate 2D coordinates
obBuilder = ob.OBBuilder()
obBuilder.Build(mol)
if mol.NumAtoms() <= 0:
raise InvalidInputException(name="smiles", value=smiles)
else:
# Generate 2D coordinates
obBuilder = ob.OBBuilder()
obBuilder.Build(mol)

mol_block = conv.WriteString(mol)
mol_block = mol_block.strip() # Remove leading/trailing whitespace
return mol_block
mol_block = conv.WriteString(mol)
mol_block = mol_block.strip() # Remove leading/trailing whitespace
return mol_block
122 changes: 45 additions & 77 deletions app/routers/converters.py
Original file line number Diff line number Diff line change
Expand Up @@ -321,28 +321,15 @@ async def SMILES_canonicalise(
- ValueError: If an unsupported toolkit option is provided.
"""
try:
if toolkit == "cdk":
mol = parseInput(smiles, "cdk", False)
return str(getCanonSMILES(mol))
elif toolkit == "rdkit":
mol = parseInput(smiles, "rdkit", False)
if mol:
return str(Chem.MolToSmiles(mol, kekuleSmiles=True))
else:
raise HTTPException(
status_code=400,
detail="Error reading input text, please check again.",
)
elif toolkit == "openbabel":
return str(getOBCanonicalSMILES(smiles))
else:
raise HTTPException(
status_code=422,
detail="Error reading input text, please check again.",
)
except Exception as e:
raise HTTPException(status_code=422, detail=str(e))
if toolkit == "cdk":
mol = parseInput(smiles, "cdk", False)
return str(getCanonSMILES(mol))
elif toolkit == "rdkit":
mol = parseInput(smiles, "rdkit", False)
return str(Chem.MolToSmiles(mol, kekuleSmiles=True))
elif toolkit == "openbabel":
smiles = getOBCanonicalSMILES(smiles)
return smiles


@router.get(
Expand Down Expand Up @@ -396,19 +383,16 @@ async def SMILES_to_CXSMILES(
Note:
- CXSMILES is a Chemaxon Extended SMILES which is used for storing special features of the molecules after the SMILES string.
"""
try:
if toolkit == "cdk":
mol = parseInput(smiles, "cdk", False)
cxsmiles = getCXSMILES(mol)
if cxsmiles:
return str(cxsmiles)
else:
mol = parseInput(smiles, "rdkit", False)
cxsmiles = getRDKitCXSMILES(mol)
if cxsmiles:
return str(cxsmiles)
except Exception as e:
raise HTTPException(status_code=422, detail=str(e))
if toolkit == "cdk":
mol = parseInput(smiles, "cdk", False)
cxsmiles = getCXSMILES(mol)
if cxsmiles:
return str(cxsmiles)
else:
mol = parseInput(smiles, "rdkit", False)
cxsmiles = getRDKitCXSMILES(mol)
if cxsmiles:
return str(cxsmiles)


@router.get(
Expand Down Expand Up @@ -459,29 +443,21 @@ async def SMILES_to_InChI(
- ValueError: If an unsupported toolkit option is provided.
"""
try:
if toolkit == "cdk":
mol = parseInput(smiles, "cdk", False)
inchi = getInChI(mol)
if inchi:
return str(inchi)
elif toolkit == "rdkit":
mol = parseInput(smiles, "rdkit", False)
if mol:
inchi = Chem.inchi.MolToInchi(mol)
if inchi:
return str(inchi)
elif toolkit == "openbabel":
inchi = getOBInChI(smiles)
if toolkit == "cdk":
mol = parseInput(smiles, "cdk", False)
inchi = getInChI(mol)
if inchi:
return str(inchi)
elif toolkit == "rdkit":
mol = parseInput(smiles, "rdkit", False)
if mol:
inchi = Chem.inchi.MolToInchi(mol)
if inchi:
return str(inchi)
else:
raise HTTPException(
status_code=422,
detail="Error reading input text, please check again.",
)
except Exception as e:
raise HTTPException(status_code=422, detail=str(e))
elif toolkit == "openbabel":
inchi = getOBInChI(smiles)
if inchi:
return str(inchi)


@router.get(
Expand Down Expand Up @@ -532,30 +508,22 @@ async def SMILES_to_InChIKey(
- ValueError: If an unsupported toolkit option is provided.
"""
try:
if toolkit == "cdk":
mol = parseInput(smiles, "cdk", False)
inchikey = getInChI(mol, InChIKey=True)
if inchikey:
return str(inchikey)
if toolkit == "cdk":
mol = parseInput(smiles, "cdk", False)
inchikey = getInChI(mol, InChIKey=True)
if inchikey:
return str(inchikey)

elif toolkit == "rdkit":
mol = parseInput(smiles, "rdkit", False)
if mol:
inchikey = Chem.inchi.MolToInchiKey(mol)
if inchikey:
return str(inchikey)
elif toolkit == "openbabel":
inchikey = getOBInChI(smiles, InChIKey=True)
elif toolkit == "rdkit":
mol = parseInput(smiles, "rdkit", False)
if mol:
inchikey = Chem.inchi.MolToInchiKey(mol)
if inchikey:
return str(inchikey)
else:
raise HTTPException(
status_code=422,
detail="Error reading input text, please check again.",
)
except Exception as e:
raise HTTPException(status_code=422, detail=str(e))
elif toolkit == "openbabel":
inchikey = getOBInChI(smiles, InChIKey=True)
if inchikey:
return str(inchikey)


@router.get(
Expand Down

0 comments on commit eea7510

Please sign in to comment.