Skip to content

Commit

Permalink
fix: apply suggestion from code review + improve Exception management
Browse files Browse the repository at this point in the history
  • Loading branch information
MrtinoRG committed Jan 20, 2025
1 parent e7518c9 commit 6365350
Show file tree
Hide file tree
Showing 2 changed files with 149 additions and 41 deletions.
152 changes: 128 additions & 24 deletions src/chemenv/modal_app.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,66 +52,170 @@ def get_element_info(*args, **kwargs):


@app.function(image=_converters_image)
async def get_iupac_name(smiles: str) -> str:
converter = _Smiles2Name(smiles)
name = await converter.get_name()
if name is None:
return ""
return name
async def get_iupac_name(smiles: str, timeout: int = 10) -> str:
"""
Get the IUPAC name of a molecule from its SMILES string.
Args:
smiles (str): The SMILES string of the molecule.
timeout (int): The timeout in seconds for the request.
Returns:
str: The IUPAC name of the molecule.
Raises:
ValueError: If the conversion fails.
"""
converter = _Smiles2Name(smiles, timeout)
try:
name = await converter.get_name()
return name
except Exception as e:
raise ValueError(f"Error: {e}") from e


@app.function(image=_converters_image)
async def get_smiles_from_name(name: str) -> str:
converter = _Name2Smiles(name)
smiles = await converter.get_smiles()
if smiles is None:
return ""
return smiles
async def get_smiles_from_name(name: str, timeout: int = 10) -> str:
"""
Get the SMILES string of a molecule from its IUPAC name.
Args:
name (str): The IUPAC name of the molecule.
timeout (int): The timeout in seconds for the request.
Returns:
str: The SMILES string of the molecule.
Raises:
ValueError: If the conversion fails.
"""
converter = _Name2Smiles(name, timeout)
try:
smiles = await converter.get_smiles()
return smiles
except Exception as e:
raise ValueError(f"Error converting name to SMILES: {e}") from e


@app.function(image=_converters_image)
def convert_to_selfies(smiles: str) -> str:
"""Convert SMILES to SELFIES encoding."""
"""
Convert SMILES to SELFIES encoding.
Args:
smiles (str): The SMILES string to convert.
Returns:
str: The SELFIES encoding of the molecule.
"""
return _smiles_to_selfies(smiles)


@app.function(image=_converters_image)
def convert_to_deepsmiles(smiles: str) -> str:
"""Convert SMILES to DeepSMILES encoding."""
"""
Convert SMILES to DeepSMILES encoding.
Args:
smiles (str): The SMILES string to convert.
Returns:
str: The DeepSMILES encoding of the molecule.
"""
return _smiles_to_deepsmiles(smiles)


@app.function(image=_converters_image)
def convert_to_inchi(smiles: str) -> str:
"""Convert SMILES to InChI."""
return _smiles_to_inchi(smiles)
"""
Convert SMILES to InChI.
Args:
smiles (str): The SMILES string to convert.
Returns:
str: The InChI encoding of the molecule.
"""
try:
return _smiles_to_inchi(smiles)
except Exception as e:
raise ValueError(f"Error converting SMILES to InChI: {e}") from e


@app.function(image=_converters_image)
def convert_to_inchikey(smiles: str) -> str:
"""Convert SMILES to InChIKey."""
return _smiles_to_inchikey(smiles)
"""
Convert SMILES to InChIKey.
Args:
smiles (str): The SMILES string to convert.
Returns:
str: The InChIKey encoding of the molecule.
"""
try:
return _smiles_to_inchikey(smiles)
except Exception as e:
raise ValueError(f"Error converting SMILES to InChIKey: {e}") from e


@app.function(image=_safe_image)
def convert_to_safe(smiles: str) -> str:
"""Convert SMILES to SAFE encoding."""
"""
Convert SMILES to SAFE encoding.
Args:
smiles (str): The SMILES string to convert.
Returns:
str: The SAFE encoding of the molecule.
"""
return _smiles_to_safe(smiles)


@app.function(image=_converters_image)
def selfies_to_smiles(selfies: str) -> str:
"""Convert SELFIES to SMILES."""
"""
Convert SELFIES to SMILES.
Args:
selfies (str): The SELFIES encoding to convert.
Returns:
str: The SMILES string of the molecule.
"""
return _selfies_to_smiles(selfies)


@app.function(image=_converters_image)
def inchi_to_smiles(inchi: str) -> str:
"""Convert InChI to SMILES."""
return _inchi_to_smiles(inchi)
"""
Convert InChI to SMILES.
Args:
inchi (str): The InChI encoding to convert.
Returns:
str: The SMILES string of the molecule.
"""
try:
return _inchi_to_smiles(inchi)
except Exception as e:
raise ValueError(f"Error converting InChI to SMILES: {e}") from e


@app.function(image=_converters_image)
def deepsmiles_to_smiles(deepsmiles: str) -> str:
"""Convert DeepSMILES to SMILES."""
return _deepsmiles_to_smiles(deepsmiles)
"""
Convert DeepSMILES to SMILES.
Args:
deepsmiles (str): The DeepSMILES encoding to convert.
Returns:
str: The SMILES string of the molecule.
"""
try:
return _deepsmiles_to_smiles(deepsmiles)
except Exception as e:
raise ValueError(f"Error converting DeepSMILES to SMILES: {e}") from e
38 changes: 21 additions & 17 deletions src/chemenv/tools/converters.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,17 +38,19 @@ class _Name2Smiles:
result is found.
Args:
name: The chemical compound name to convert to SMILES notation.
name (str): The chemical compound name to convert to SMILES notation.
timeout (int): The timeout for API requests in seconds.
Raises:
ValueError: If the name cannot be URL-encoded or contains invalid characters.
"""

def __init__(self, name: str):
def __init__(self, name: str, timeout: int):
"""Initialize converter with chemical name.
Args:
name: Chemical compound name to convert
name (str): Chemical compound name to convert
timeout (int): Timeout for API requests in seconds
Raises:
ValueError: If name cannot be URL-encoded
Expand All @@ -57,15 +59,15 @@ def __init__(self, name: str):
# Basic usage with IUPAC name
>>> converter = Name2Smiles("2-propanone")
>>> await converter.get_smiles()
'CC(=O)C'
'CC(=O)C'
"""
try:
self.name = quote(name)
except Exception as e:
logger.error(f"Error encoding name: {e}")
raise ValueError(f"Invalid chemical name: {name}")

self.timeout = 10 # seconds
self.timeout = timeout # seconds

@backoff.on_exception(
backoff.expo,
Expand Down Expand Up @@ -158,7 +160,7 @@ async def pubchem(self) -> Optional[str]:
except Exception as e:
raise e

async def get_smiles(self) -> Optional[str]:
async def get_smiles(self) -> str:
"""Query all APIs in parallel until a valid SMILES is found.
Attempts to convert name to SMILES using multiple APIs concurrently,
Expand Down Expand Up @@ -197,12 +199,13 @@ class _Smiles2Name:
Args:
smiles (str): The SMILES string representing the chemical compound.
timeout (int): The timeout for API requests in seconds.
Raises:
ValueError: If the SMILES string is invalid or cannot be encoded.
"""

def __init__(self, smiles):
def __init__(self, smiles: str, timeout: int):
"""Initialize Name2Smiles converter with a chemical compound name.
Takes a chemical compound name and prepares it for API queries by URL-encoding.
Expand All @@ -211,6 +214,7 @@ def __init__(self, smiles):
Args:
name (str): Chemical compound name to convert to SMILES notation.
Should be a valid IUPAC or common chemical name.
timeout (int): Timeout for API requests in seconds.
Raises:
ValueError: If the name cannot be URL-encoded or contains invalid characters.
Expand All @@ -225,7 +229,7 @@ def __init__(self, smiles):
raise ValueError(f"Invalid SMILES: {smiles}")

self.smiles = smiles
self.timeout = 10 # seconds
self.timeout = timeout # seconds

@backoff.on_exception(
backoff.expo,
Expand Down Expand Up @@ -286,7 +290,7 @@ async def cactus(self) -> Optional[str]:
except Exception as e:
raise e

async def get_name(self) -> Optional[str]:
async def get_name(self) -> str:
"""
Query multiple chemical APIs in parallel to get IUPAC name.
Expand Down Expand Up @@ -321,7 +325,7 @@ def _smiles_to_selfies(smiles: str) -> str:
Takes a SMILES and return the SELFIES encoding.
Args:
smiles: SMILES string
smiles (str): SMILES string
Returns:
str: SELFIES of the input SMILES
Expand All @@ -335,7 +339,7 @@ def _smiles_to_deepsmiles(smiles: str) -> str:
Takes a SMILES and return the DeepSMILES encoding.
Args:
smiles: SMILES string
smiles (str): SMILES string
Returns:
str: DeepSMILES of the input SMILES
Expand All @@ -349,7 +353,7 @@ def _smiles_to_inchi(smiles: str) -> str:
Takes a SMILES and return the InChI.
Args:
smiles: SMILES string
smiles (str): SMILES string
Returns:
str: InChI of the input SMILES
Expand All @@ -368,7 +372,7 @@ def _smiles_to_inchikey(smiles: str) -> str:
Takes a SMILES and return the InChIKey.
Args:
smiles: SMILES string
smiles (str): SMILES string
Returns:
str: InChIKey of the input SMILES
Expand All @@ -387,7 +391,7 @@ def _smiles_to_safe(smiles: str) -> str:
Takes a SMILES and return the SAFE (https://github.com/datamol-io/safe).
Args:
smiles: SMILES string
smiles (str): SMILES string
Returns:
str: SAFE of the input SMILES
Expand All @@ -400,7 +404,7 @@ def _selfies_to_smiles(_selfies: str) -> str:
Takes a SELFIES and return the SMILES.
Args:
selfies: SELFIES string
selfies (str): SELFIES string
Returns:
str: SMILES of the input SELFIES
Expand All @@ -413,7 +417,7 @@ def _inchi_to_smiles(inchi: str) -> str:
Takes an InChI and return the SMILES.
Args:
inchi: InChI string
inchi (str): InChI string
Returns:
str: SMILES of the input InChI
Expand All @@ -432,7 +436,7 @@ def _deepsmiles_to_smiles(_deepsmiles: str) -> str:
Takes a DeepSMILES and return the SMILES.
Args:
deepsmiles: DeepSMILES string
deepsmiles (str): DeepSMILES string
Returns:
str: SMILES of the input DeepSMILES
Expand Down

0 comments on commit 6365350

Please sign in to comment.