Skip to content

Commit

Permalink
Refactor exceptions (duartegroup#144)
Browse files Browse the repository at this point in the history
* Add base exception

* Fix typo
  • Loading branch information
t-young31 authored May 22, 2022
1 parent 191c2a1 commit 8898967
Show file tree
Hide file tree
Showing 11 changed files with 101 additions and 85 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ tests/__pycache__/

tests/*.xyz

**/tmp.xyz

autode/conformers/__pycache__/

autode/transition_states/__pycache__/
Expand Down
2 changes: 1 addition & 1 deletion autode/calculation.py
Original file line number Diff line number Diff line change
Expand Up @@ -500,7 +500,7 @@ def generate_input(self) -> None:
if not hasattr(keyword, self.method.name):
err_str = (f'Keyword: {keyword} is not supported set '
f'{repr(keyword)}.{self.method.name} as a string')
raise ex.UnsuppportedCalculationInput(err_str)
raise ex.UnsupportedCalculationInput(err_str)

self.method.generate_input(self, self.molecule)

Expand Down
135 changes: 68 additions & 67 deletions autode/exceptions.py
Original file line number Diff line number Diff line change
@@ -1,124 +1,125 @@
class CalculationException(Exception):
pass
class AutodeException(Exception):
"""Base autodE exception"""


class AtomsNotFound(CalculationException):
pass


class NoAtomsInMolecule(Exception):
pass

# --------------------- Calculation exceptions --------------------------------
class CalculationException(AutodeException):
"""Base calculation exception when an external autodE calculation fails"""

class NoConformers(Exception):
pass

class AtomsNotFound(CalculationException):
"""Exception for atomic coordinates/identities being found"""

class FitFailed(Exception):
pass

class MethodUnavailable(CalculationException):
"""Exception for an autodE wrapped method not being available"""

class NoInputError(Exception):
pass

class UnsupportedCalculationInput(CalculationException):
"""Exception for an autodE calculation input not being valid"""
def __init__(self, message='Parameters not supported'):
super().__init__(message)

class MethodUnavailable(CalculationException):
pass

class NoInputError(CalculationException):
"""Exception for a autodE calculation having no input e.g atoms"""

class SolventUnavailable(Exception):
pass

class NoCalculationOutput(CalculationException):
"""Exception for a calculation file that should exist not existing"""

class UnbalancedReaction(Exception):
pass

class CouldNotGetProperty(CalculationException):
"""Exception for where a property e.g. energy cannot be found in a
calculation output file"""

class UnsuppportedCalculationInput(CalculationException):
def __init__(self, message='Parameters not supported'):
super().__init__(message)
def __init__(self, *args, name=None):
if name is not None:
super().__init__(f'Could not get {name}')

else:
super().__init__(*args)

class SolventNotFound(Exception):
pass

# -----------------------------------------------------------------------------
class NoAtomsInMolecule(AutodeException):
"""Exception for no atoms existing in a molecule"""

class SolventsDontMatch(Exception):
pass

class NoConformers(AutodeException):
"""Exception for no conformers being present in a molecule"""

class BondsInSMILESAndGraphDontMatch(Exception):
pass

class SolventUnavailable(AutodeException):
"""Exception for a solvent not being available for a calculation"""

class XYZfileDidNotExist(Exception):
pass

class UnbalancedReaction(AutodeException):
"""Exception for an autodE reaction not being balanced in e.g. N_atoms"""

class XYZfileWrongFormat(Exception):
pass

class SolventNotFound(AutodeException):
"""Exception for a solvent not being in the list of available solvents"""

class ReactionFormationFailed(Exception):
pass

class SolventsDontMatch(AutodeException):
"""Exception for where the solvent in reactants is different to products"""

class NoClosestSpecies(Exception):
pass

class BondsInSMILESAndGraphDontMatch(AutodeException):
"""Exception for a partially disjoint set of bonds in SMILES and a graph"""

class NoMapping(Exception):
pass

class XYZfileDidNotExist(AutodeException, FileNotFoundError):
"""Exception for an xyz file not existing"""

class NoNormalModesFound(CalculationException):
pass

class XYZfileWrongFormat(AutodeException):
"""Exception for an xyz being the wrong format"""

class NoMolecularGraph(Exception):
pass

class ReactionFormationFailed(AutodeException):
"""Exception for where a reaction cannot be built. e.g. if there are no
reactants"""

class NoCalculationOutput(CalculationException):
pass

class NoMapping(AutodeException):
"""Exception for where there is no mapping/bijection between two graphs"""

class RDKitFailed(Exception):
pass

class NoMolecularGraph(AutodeException):
"""Exception for a molecule not having a set graph"""

class InvalidSmilesString(Exception):
pass

class RDKitFailed(AutodeException):
"""Exception for where RDKit fails to generate conformers"""

class SMILESBuildFailed(Exception):
pass

class InvalidSmilesString(AutodeException):
"""Exception for a SMILES string being invalid"""

class FailedToSetRotationIdxs(Exception):
pass

class SMILESBuildFailed(AutodeException):
"""Exception for where building an example 3D structure cannot be built
from a SMILES string"""

class FailedToAdjustAngles(Exception):
pass

class FailedToSetRotationIdxs(AutodeException):
"""Exception for the atoms that need to be rotating in 3D building not
being found"""

class CouldNotGetProperty(CalculationException):
def __init__(self, *args, name=None):
if name is not None:
super().__init__(f'Could not get {name}')

else:
super().__init__(*args)
class FailedToAdjustAngles(AutodeException):
"""Exception for when the internal angles in a ring cannot be adjusted"""


class CannotSplitAcrossBond(Exception):
class CannotSplitAcrossBond(AutodeException):
"""A molecule cannot be partitioned by deleting one bond"""


class CouldNotPlotSmoothProfile(Exception):
pass
class CouldNotPlotSmoothProfile(AutodeException):
"""A smooth reaction profile cannot be plotted"""


class TemplateLoadingFailed(Exception):
pass
class TemplateLoadingFailed(AutodeException):
"""A template file was not in the correct format"""
6 changes: 3 additions & 3 deletions autode/wrappers/MOPAC.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
from autode.atoms import Atom
from autode.config import Config
from autode.constants import Constants
from autode.exceptions import UnsuppportedCalculationInput
from autode.exceptions import UnsupportedCalculationInput
from autode.geom import get_atoms_linear_interp
from autode.log import logger
from autode.utils import work_in_tmp_dir
Expand Down Expand Up @@ -44,7 +44,7 @@ def get_keywords(calc_input, molecule):
if molecule.solvent.dielectric is None:
err_str = (f'Could not use solvent {molecule.solvent} for MOPAC '
f'calculation, a dielectric constant was not defined')
raise UnsuppportedCalculationInput(message=err_str)
raise UnsupportedCalculationInput(message=err_str)

keywords.append(f'EPS={molecule.solvent.dielectric}')

Expand All @@ -58,7 +58,7 @@ def get_keywords(calc_input, molecule):
keywords.append('OPEN(2,2)')
else:
logger.critical('Unsupported spin multiplicity')
raise UnsuppportedCalculationInput
raise UnsupportedCalculationInput

return keywords

Expand Down
4 changes: 2 additions & 2 deletions autode/wrappers/NWChem.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
from autode.atoms import Atom
from autode.geom import symm_matrix_from_ltril
from autode.config import Config
from autode.exceptions import UnsuppportedCalculationInput, CouldNotGetProperty
from autode.exceptions import UnsupportedCalculationInput, CouldNotGetProperty
from autode.log import logger
from autode.constants import Constants
from autode.utils import work_in_tmp_dir
Expand Down Expand Up @@ -51,7 +51,7 @@ def get_keywords(calc_input, molecule):

if 'scf' in keyword.lower():
if molecule.solvent is not None:
raise UnsuppportedCalculationInput('NWChem only supports '
raise UnsupportedCalculationInput('NWChem only supports '
'solvent for DFT calcs')

if isinstance(keyword, kws.Functional):
Expand Down
6 changes: 3 additions & 3 deletions autode/wrappers/ORCA.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
from autode.config import Config
from autode.utils import work_in_tmp_dir
from autode.log import logger
from autode.exceptions import (UnsuppportedCalculationInput,
from autode.exceptions import (UnsupportedCalculationInput,
CouldNotGetProperty,
NoCalculationOutput,
XYZfileWrongFormat,
Expand Down Expand Up @@ -517,7 +517,7 @@ def add_solvent_keyword(self, molecule, keywords):
"""Add a keyword to the input file based on the solvent"""

if self.implicit_solvation_type.lower() not in ['smd', 'cpcm']:
raise UnsuppportedCalculationInput('Implicit solvent type must be '
raise UnsupportedCalculationInput('Implicit solvent type must be '
'either SMD or CPCM')

if (self.use_vdw_gaussian_solvent(keywords)
Expand All @@ -526,7 +526,7 @@ def add_solvent_keyword(self, molecule, keywords):
f'{molecule.solvent.name}. Available solvents are '
f'{vdw_gaussian_solvent_dict.keys()}')

raise UnsuppportedCalculationInput(message=err)
raise UnsupportedCalculationInput(message=err)

solv_name = vdw_gaussian_solvent_dict[molecule.solvent.orca]
keywords.append(f'CPCM({solv_name})')
Expand Down
4 changes: 2 additions & 2 deletions autode/wrappers/QChem.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
from autode.log import logger
from autode.atoms import Atom
from autode.constants import Constants
from autode.exceptions import CouldNotGetProperty, UnsuppportedCalculationInput
from autode.exceptions import CouldNotGetProperty, UnsupportedCalculationInput
from autode.wrappers.base import ElectronicStructureMethod
from autode.utils import run_external, work_in_tmp_dir

Expand Down Expand Up @@ -513,7 +513,7 @@ def _write_keywords(self, keywords, molecule) -> None:

if word.lower() != 'smd':
err = f'Only SMD solvent is supported. Had: {word}'
raise UnsuppportedCalculationInput(err)
raise UnsupportedCalculationInput(err)

self.write('solvent_method smd')

Expand Down
15 changes: 14 additions & 1 deletion doc/changelog.rst
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,20 @@ Changelog
--------
----------

Bugfix release.
Minor functionality improvements and bugfixes.


Usability improvements/Changes
******************************
- All exceptions now inherit from a base :code:`autode.exceptions.AutodeException`
- Fixes a typo in :code:`autode.exceptions.UnsupoportedCalculationInput`
- Adds documentation explaining the intention of each exception in :code:`autode.exceptions`


Functionality improvements
**************************

-


Bug Fixes
Expand Down
2 changes: 1 addition & 1 deletion tests/test_calculation.py
Original file line number Diff line number Diff line change
Expand Up @@ -264,7 +264,7 @@ def test_input_gen():
method=xtb,
keywords=SinglePointKeywords([unsupported_func]))

with pytest.raises(ex.UnsuppportedCalculationInput):
with pytest.raises(ex.UnsupportedCalculationInput):
calc_kwds.generate_input()


Expand Down
6 changes: 3 additions & 3 deletions tests/test_mopac_calc.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from autode.wrappers.MOPAC import MOPAC
from autode.wrappers.MOPAC import get_keywords
from autode.exceptions import CouldNotGetProperty, UnsuppportedCalculationInput
from autode.exceptions import CouldNotGetProperty, UnsupportedCalculationInput
from autode.calculation import Calculation, CalculationInput
from autode.species.molecule import Molecule
from autode.solvent import ImplicitSolvent
Expand Down Expand Up @@ -107,7 +107,7 @@ def test_other_spin_states():
h_quin = Molecule(atoms=[Atom('H')], mult=5)
h_quin.name = 'molecule'

with pytest.raises(UnsuppportedCalculationInput):
with pytest.raises(UnsupportedCalculationInput):
calc = Calculation(name='h',
molecule=h_quin,
method=method,
Expand Down Expand Up @@ -264,7 +264,7 @@ def test_mopac_solvent_no_dielectric():

# Cannot generate an input if the solvent does not have a defined
# dielectric constant in the dictionary
with pytest.raises(UnsuppportedCalculationInput):
with pytest.raises(UnsupportedCalculationInput):
calc.generate_input()

if os.path.exists('tmp_mopac.mop'):
Expand Down
4 changes: 2 additions & 2 deletions tests/test_orca_calc.py
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,7 @@ def test_solvation():
methane = Molecule(name='solvated_methane', smiles='C',
solvent_name='water')

with pytest.raises(ex.UnsuppportedCalculationInput):
with pytest.raises(ex.UnsupportedCalculationInput):

# Should raise on unsupported calculation type
method.implicit_solvation_type = 'xxx'
Expand Down Expand Up @@ -278,7 +278,7 @@ def test_keyword_setting():
assert any('B3LYP' in line for line in inp_lines)

# With a keyword without ORCA defined then raise an exception
with pytest.raises(ex.UnsuppportedCalculationInput):
with pytest.raises(ex.UnsupportedCalculationInput):
orca.keywords.sp.functional = Functional(name='B3LYP', g09='B3LYP')
calc = Calculation(name='tmp',
molecule=test_mol.copy(),
Expand Down

0 comments on commit 8898967

Please sign in to comment.