From 127cf6b1a6fb0d5b73b038085db37679b3f40d05 Mon Sep 17 00:00:00 2001 From: Gian Marco Ghiandoni <30413455+ghiander@users.noreply.github.com> Date: Tue, 19 Mar 2024 12:34:39 +0000 Subject: [PATCH] Issue 382 (#401) * issue #339: implemented instance-specific logging formatting * NegativeLonePairsError exception; JazzyError exception handler for API; migrated utils.py into exception.py --- pyproject.toml | 2 +- src/jazzy/__main__.py | 2 +- src/jazzy/api.py | 8 ++++++- src/jazzy/core.py | 10 ++++++-- src/jazzy/exception.py | 32 +++++++++++++++++++++++++ src/jazzy/utils.py | 14 ----------- tests/test_api.py | 15 +++++++++++- tests/test_free_energy_contributions.py | 31 ++++++++++++++++++++++++ tests/test_kallisto.py | 2 +- 9 files changed, 95 insertions(+), 21 deletions(-) create mode 100644 src/jazzy/exception.py delete mode 100644 src/jazzy/utils.py diff --git a/pyproject.toml b/pyproject.toml index 55ce13f..a790221 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "jazzy" -version = "0.0.12" +version = "0.0.13" description = "Jazzy" authors = ["Gian Marco Ghiandoni ", "Eike Caldeweyher "] license = "Apache-2.0" diff --git a/src/jazzy/__main__.py b/src/jazzy/__main__.py index b9d0a9c..16ec42d 100644 --- a/src/jazzy/__main__.py +++ b/src/jazzy/__main__.py @@ -6,7 +6,7 @@ from jazzy.api import atomic_strength_vis_from_smiles from jazzy.api import molecular_vector_from_smiles from jazzy.config import Config -from jazzy.utils import JazzyError +from jazzy.exception import JazzyError pass_config = click.make_pass_decorator(Config, ensure=True) diff --git a/src/jazzy/api.py b/src/jazzy/api.py index 0b43811..09d4b5c 100644 --- a/src/jazzy/api.py +++ b/src/jazzy/api.py @@ -13,10 +13,11 @@ from jazzy.core import get_covalent_atom_idxs from jazzy.core import kallisto_molecule_from_rdkit_molecule from jazzy.core import rdkit_molecule_from_smiles +from jazzy.exception import exception_handling +from jazzy.exception import JazzyError from jazzy.helpers import condense_atomic_map from jazzy.helpers import convert_map_to_tuples from jazzy.helpers import sum_atomic_map -from jazzy.utils import JazzyError from jazzy.visualisation import depict_strengths @@ -37,6 +38,7 @@ def __smiles_to_molecule_objects(smiles, minimisation_method=MINIMISATION_METHOD return rdkit_mol, kallisto_mol +@exception_handling def molecular_vector_from_smiles( smiles: str, minimisation_method=MINIMISATION_METHOD, only_strengths=False ): @@ -92,6 +94,7 @@ def molecular_vector_from_smiles( return mol_vector +@exception_handling def deltag_from_smiles(smiles: str, minimisation_method=MINIMISATION_METHOD): """API route to calculate molecular free energy scalar. @@ -134,6 +137,7 @@ def deltag_from_smiles(smiles: str, minimisation_method=MINIMISATION_METHOD): return round(sum(dg.values()), ROUNDING_DIGITS) +@exception_handling def atomic_tuples_from_smiles(smiles: str, minimisation_method=MINIMISATION_METHOD): """API route to generate a tuple representation on the atomic map. @@ -160,6 +164,7 @@ def atomic_tuples_from_smiles(smiles: str, minimisation_method=MINIMISATION_METH return convert_map_to_tuples(atomic_map) +@exception_handling def atomic_map_from_smiles(smiles: str, minimisation_method=MINIMISATION_METHOD): """API route to generate a condensed representation on the atomic map. @@ -186,6 +191,7 @@ def atomic_map_from_smiles(smiles: str, minimisation_method=MINIMISATION_METHOD) return condense_atomic_map(atomic_map) +@exception_handling def atomic_strength_vis_from_smiles( smiles: str, minimisation_method=MINIMISATION_METHOD, diff --git a/src/jazzy/core.py b/src/jazzy/core.py index 557e080..fe0c3e8 100644 --- a/src/jazzy/core.py +++ b/src/jazzy/core.py @@ -14,8 +14,9 @@ from rdkit.Chem import rdMolDescriptors from jazzy.config import ROUNDING_DIGITS +from jazzy.exception import KallistoError +from jazzy.exception import NegativeLonePairsError from jazzy.logging import logger -from jazzy.utils import KallistoError def rdkit_molecule_from_smiles(smiles: str, minimisation_method=None): @@ -494,8 +495,13 @@ def calculate_delta_polar( sdi = sdi / nh # acceptor contribution - nlps = atom["num_lp"] sak = atom["sa"] + nlps = atom["num_lp"] + if nlps < 0: + raise NegativeLonePairsError( + "The input compound contains atoms with " + f"negative lone pairs (got {nlps} for atom at idx {idx})" + ) don += sdi * (nh**expd) acc += sak * (nlps**expa) diff --git a/src/jazzy/exception.py b/src/jazzy/exception.py new file mode 100644 index 0000000..20a47ef --- /dev/null +++ b/src/jazzy/exception.py @@ -0,0 +1,32 @@ +"""Anything about exceptions and their handling.""" +# src/jazzy/exception.py + + +class JazzyError(Exception): + """Raised when Jazzy cannot calculate results.""" + + pass + + +class KallistoError(Exception): + """Raised when something goes wrong inside kallisto.""" + + pass + + +class NegativeLonePairsError(Exception): + """Raised when a molecule contains negative lone pairs.""" + + pass + + +def exception_handling(func): + """Catches core exceptions and raises a JazzyError.""" + + def wrapper(*args, **kwargs): + try: + return func(*args, **kwargs) + except (NegativeLonePairsError, KallistoError) as e: + raise JazzyError(str(e)) + + return wrapper diff --git a/src/jazzy/utils.py b/src/jazzy/utils.py deleted file mode 100644 index 3ea9045..0000000 --- a/src/jazzy/utils.py +++ /dev/null @@ -1,14 +0,0 @@ -"""Anything else.""" -# src/jazzy/utils.py - - -class JazzyError(Exception): - """Raised when Jazzy cannot calculate results.""" - - pass - - -class KallistoError(Exception): - """Raised when something goes wrong inside kallisto.""" - - pass diff --git a/tests/test_api.py b/tests/test_api.py index 10bae18..7196531 100644 --- a/tests/test_api.py +++ b/tests/test_api.py @@ -9,7 +9,7 @@ from jazzy.api import molecular_vector_from_smiles from jazzy.config import Config from jazzy.config import ROUNDING_DIGITS -from jazzy.utils import JazzyError +from jazzy.exception import JazzyError # global jazzy config (parameter) config = Config() @@ -68,6 +68,19 @@ def test_api_molecular_vector_from_smiles_fails_for_empty_smiles(): assert error.value.args[0] == "An empty SMILES string was passed." +def test_api_molecular_vector_from_smiles_complex_numbers(): + """Exception for structure containing negative lone pairs.""" + smiles = "C12C3C4C5C1[Fe]23456789C%10C6C7C8C9%10" + minimisation_method = "MMFF94" + only_strengths = False + with pytest.raises(JazzyError) as error: + molecular_vector_from_smiles(smiles, minimisation_method, only_strengths) + assert ( + "The input compound contains atoms with negative lone pairs" + in error.value.args[0] + ) + + def test_deltag_from_smiles(): """Correcly calculates free energy scalar.""" smiles = "CC" diff --git a/tests/test_free_energy_contributions.py b/tests/test_free_energy_contributions.py index 2ad284b..02c1398 100644 --- a/tests/test_free_energy_contributions.py +++ b/tests/test_free_energy_contributions.py @@ -1,5 +1,6 @@ """Test cases for the free energy contributions.""" import numpy as np +import pytest from jazzy.core import any_hydrogen_neighbors from jazzy.core import calculate_delta_apolar @@ -11,6 +12,7 @@ from jazzy.core import interaction_strength from jazzy.core import kallisto_molecule_from_rdkit_molecule from jazzy.core import rdkit_molecule_from_smiles +from jazzy.exception import NegativeLonePairsError def test_calculate_delta_apolar(): @@ -87,6 +89,35 @@ def test_calculate_delta_polar(): assert np.isclose(got, want[idx], 3) +def test_negative_lone_pairs_delta_polar(): + """Exception calculating the polar free energy contribution.""" + smiles = "C12C3C4C5C1[Fe]23456789C%10C6C7C8C9%10" + # mock parameters + parameter = [0, 0, 0, 0] + rdkit_molecule = rdkit_molecule_from_smiles( + smiles=smiles, minimisation_method="MMFF94" + ) + kallisto_molecule = kallisto_molecule_from_rdkit_molecule( + rdkit_molecule=rdkit_molecule + ) + eeq = get_charges_from_kallisto_molecule(kallisto_molecule, 0) + aan = get_covalent_atom_idxs(rdkit_molecule) + mol_map = calculate_polar_strength_map(rdkit_molecule, kallisto_molecule, aan, eeq) + with pytest.raises(NegativeLonePairsError) as error: + calculate_delta_polar( + mol_map=mol_map, + atoms_and_nbrs=aan, + gd=parameter[0], + ga=parameter[1], + expd=parameter[2], + expa=parameter[3], + ) + assert ( + "The input compound contains atoms with negative lone pairs" + in error.value.args[0] + ) + + def test_correct_interaction_strength(): """Correctly calculates interaction strength.""" want = 4 diff --git a/tests/test_kallisto.py b/tests/test_kallisto.py index 4e65bf6..f19ddb2 100644 --- a/tests/test_kallisto.py +++ b/tests/test_kallisto.py @@ -9,7 +9,7 @@ from jazzy.core import get_charges_from_kallisto_molecule from jazzy.core import kallisto_molecule_from_rdkit_molecule from jazzy.core import rdkit_molecule_from_smiles -from jazzy.utils import KallistoError +from jazzy.exception import KallistoError def test_kallisto_charges_are_correct_from_molecule():