Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Replace lit.error by raise LoadError #348

Merged
merged 5 commits into from
Jun 22, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 15 additions & 2 deletions CONTRIBUTING.rst
Original file line number Diff line number Diff line change
Expand Up @@ -153,9 +153,22 @@ If necessary, you can *push back* the line for later reading with ``lit.back(lin
lit.back(line)
break

When you encounter a file format error while reading the file, call ``lit.error(msg)``,
where ``msg`` is a short message describing the problem.
When you encounter a file format error while reading the file, raise a ``LoadError`` exception:

.. code-block:: python

from ..utils import LoadError

@document_load_one(...)
def load_one(lit: LineIterator) -> dict:
...
if something_wrong:
raise LoadError("Describe the problem in a sentence.", lit)

The error that appears in the terminal will automatically include the file name and line number.
If your code has already read the full file and encounters an error when processing the data,
you can use ``raise LoadError("Describe problem in a sentence.", lit.filename)`` instead.
This way, no line number is included in the error message.


``dump_one`` functions: writing a single IOData object to a file
Expand Down
8 changes: 4 additions & 4 deletions iodata/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -154,10 +154,10 @@ def load_one(filename: str, fmt: Optional[str] = None, **kwargs) -> IOData:
iodata = IOData(**format_module.load_one(lit, **kwargs))
except LoadError:
raise
except StopIteration:
lit.error("File ended before all data was read.")
except StopIteration as exc:
raise LoadError("File ended before all data was read.", lit) from exc
except Exception as exc:
raise LoadError(f"{filename}: Uncaught exception while loading file.") from exc
raise LoadError("Uncaught exception while loading file.", lit) from exc
return iodata


Expand Down Expand Up @@ -194,7 +194,7 @@ def load_many(filename: str, fmt: Optional[str] = None, **kwargs) -> Iterator[IO
except LoadError:
raise
except Exception as exc:
raise LoadError(f"{filename}: Uncaught exception while loading file.") from exc
raise LoadError("Uncaught exception while loading file.", lit) from exc


def _check_required(iodata: IOData, dump_func: Callable):
Expand Down
10 changes: 6 additions & 4 deletions iodata/formats/charmm.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@
import numpy as np

from ..docstrings import document_load_one
from ..utils import LineIterator, amu, angstrom
from ..utils import LineIterator, LoadError, amu, angstrom

__all__ = []

Expand All @@ -48,8 +48,10 @@ def load_one(lit: LineIterator) -> dict:
while True:
try:
line = next(lit)
except StopIteration:
lit.error("Title section of CRD has no ending marker (missing bare *).")
except StopIteration as exc:
raise LoadError(
"Title section of CRD has no ending marker (missing bare *).", lit
) from exc
# Get title from crd file.
if line.startswith("*"):
text = line[1:]
Expand Down Expand Up @@ -84,7 +86,7 @@ def _helper_read_crd(lit: LineIterator) -> tuple:
# Read the line for number of atoms.
natom = next(lit)
if natom is None or not natom.strip().isdigit():
lit.error("The number of atoms must be an integer.")
raise LoadError("The number of atoms must be an integer.", lit)
natom = int(natom)
# Read the atom lines
resnums = []
Expand Down
9 changes: 4 additions & 5 deletions iodata/formats/cp2klog.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
from ..docstrings import document_load_one
from ..orbitals import MolecularOrbitals
from ..overlap import factorial2
from ..utils import LineIterator
from ..utils import LineIterator, LoadError

__all__ = []

Expand Down Expand Up @@ -185,8 +185,7 @@ def _read_cp2k_obasis(lit: LineIterator) -> dict:
" ********************* Uncontracted Gaussian Type Orbitals *********************\n"
):
return _read_cp2k_uncontracted_obasis(lit)
lit.error("Could not find basis set in CP2K ATOM output.")
return None
raise LoadError("Could not find basis set in CP2K ATOM output.", lit)


def _read_cp2k_occupations_energies(
Expand Down Expand Up @@ -436,13 +435,13 @@ def load_one(lit: LineIterator) -> dict:
" Atomic orbital expansion coefficients [Alpha]\n",
" Atomic orbital expansion coefficients []\n",
]:
lit.error("Could not find orbital coefficients in CP2K ATOM output.")
raise LoadError("Could not find orbital coefficients in CP2K ATOM output.", lit)
coeffs_alpha = _read_cp2k_orbital_coeffs(lit, oe_alpha)

if not restricted:
line = next(lit)
if line != " Atomic orbital expansion coefficients [Beta]\n":
lit.error("Could not find beta orbital coefficient in CP2K ATOM output.")
raise LoadError("Could not find beta orbital coefficient in CP2K ATOM output.", lit)
coeffs_beta = _read_cp2k_orbital_coeffs(lit, oe_beta)

# Turn orbital data into a MolecularOrbitals object.
Expand Down
20 changes: 10 additions & 10 deletions iodata/formats/fchk.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
from ..docstrings import document_dump_one, document_load_many, document_load_one
from ..iodata import IOData
from ..orbitals import MolecularOrbitals
from ..utils import DumpError, LineIterator, PrepareDumpError, amu
from ..utils import DumpError, LineIterator, LoadError, PrepareDumpError, amu

__all__ = []

Expand Down Expand Up @@ -219,9 +219,9 @@ def load_one(lit: LineIterator) -> dict:
nalpha = fchk["Number of alpha electrons"]
nbeta = fchk["Number of beta electrons"]
if nalpha < 0 or nbeta < 0 or nalpha + nbeta <= 0:
lit.error("The number of electrons is not positive.")
raise LoadError("The number of electrons is not positive.", lit)
if nalpha < nbeta:
lit.error(f"n_alpha={nalpha} < n_beta={nbeta} is not valid!")
raise LoadError(f"n_alpha={nalpha} < n_beta={nbeta} is invalid.", lit)

norba = fchk["Alpha Orbital Energies"].shape[0]
mo_coeffs = np.copy(fchk["Alpha MO coefficients"].reshape(norba, nbasis).T)
Expand Down Expand Up @@ -323,7 +323,7 @@ def load_many(lit: LineIterator) -> Iterator[dict]:
prefix = "Opt point"
nsteps = fchk["Optimization Number of geometries"]
else:
lit.error("Could not find IRC or Optimization trajectory in FCHK file.")
raise LoadError("Cannot find IRC or Optimization trajectory in FCHK file.", lit)

natom = fchk["Atomic numbers"].size
for ipoint, nstep in enumerate(nsteps):
Expand Down Expand Up @@ -382,7 +382,7 @@ def _load_fchk_low(lit: LineIterator, label_patterns: Optional[list[str]] = None
elif len(words) == 2:
result["command"], result["lot"] = words
else:
lit.error("The second line of the FCHK file should contain two or three words.")
raise LoadError("The second line of the FCHK file should contain two or three words.", lit)

while True:
try:
Expand Down Expand Up @@ -434,11 +434,11 @@ def _load_fchk_field(lit: LineIterator, label_patterns: list[str]) -> tuple[str,
if len(words) == 2:
try:
return label, datatype(words[1])
except ValueError:
lit.error(f"Could not interpret: {words[1]}")
except ValueError as exc:
raise LoadError(f"Could not interpret as {datatype}: {words[1]}", lit) from exc
elif len(words) == 3:
if words[1] != "N=":
lit.error("Expected N= not found.")
raise LoadError("Expected N= not found.", lit)
length = int(words[2])
value = np.zeros(length, datatype)
counter = 0
Expand All @@ -449,8 +449,8 @@ def _load_fchk_field(lit: LineIterator, label_patterns: list[str]) -> tuple[str,
word = words.pop(0)
try:
value[counter] = datatype(word)
except (ValueError, OverflowError):
lit.error(f"Could not interpret: {word}")
except (ValueError, OverflowError) as exc:
raise LoadError(f"Could not interpret as {datatype}: {word}", lit) from exc
counter += 1
return label, value

Expand Down
8 changes: 5 additions & 3 deletions iodata/formats/fcidump.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@

from ..docstrings import document_dump_one, document_load_one
from ..iodata import IOData
from ..utils import LineIterator, set_four_index_element
from ..utils import LineIterator, LoadError, set_four_index_element

__all__ = []

Expand All @@ -50,7 +50,7 @@ def load_one(lit: LineIterator) -> dict:
# check header
line = next(lit)
if not line.startswith(" &FCI NORB="):
lit.error("Incorrect file header")
raise LoadError(f"Incorrect file header: {line.strip()}", lit)

# read info from header
words = line[5:].split(",")
Expand All @@ -77,7 +77,9 @@ def load_one(lit: LineIterator) -> dict:
for line in lit:
words = line.split()
if len(words) != 5:
lit.error("Expecting 5 fields on each data line in FCIDUMP")
raise LoadError(
f"Expecting 5 fields on each data line in FCIDUMP, got {len(words)}.", lit
)
value = float(words[0])
if words[3] != "0":
ii = int(words[1]) - 1
Expand Down
8 changes: 5 additions & 3 deletions iodata/formats/gamess.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
from numpy.typing import NDArray

from ..docstrings import document_load_one
from ..utils import LineIterator, angstrom
from ..utils import LineIterator, LoadError, angstrom

__all__ = []

Expand All @@ -37,7 +37,7 @@ def _read_data(lit: LineIterator) -> tuple[str, str, list[str]]:
# The dat file only contains symmetry-unique atoms, so we would be incapable of
# supporting non-C1 symmetry without significant additional coding.
if symmetry != "C1":
lit.error(f"Only C1 symmetry is supported. Got {symmetry}")
raise LoadError(f"Only C1 symmetry is supported, got {symmetry}.", lit)
symbols = []
line = True
while line != " $END \n":
Expand Down Expand Up @@ -86,7 +86,9 @@ def _read_hessian(lit: LineIterator, result: dict[str]) -> NDArray[float]:
"""Extract ``hessian`` from the punch file."""
# check that $HESS is not already parsed
if "athessian" in result:
lit.error("Cannot parse $HESS twice! Make sure approximate hessian is not being parsed!")
raise LoadError(
"Cannot parse $HESS twice. Make sure approximate hessian is not being parsed."
)
next(lit)
natom = len(result["symbols"])
hessian = np.zeros((3 * natom, 3 * natom), float)
Expand Down
4 changes: 2 additions & 2 deletions iodata/formats/gaussianinput.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@

from ..docstrings import document_load_one
from ..periodic import sym2num
from ..utils import LineIterator, angstrom
from ..utils import LineIterator, LoadError, angstrom

__all__ = []

Expand Down Expand Up @@ -68,7 +68,7 @@ def load_one(lit: LineIterator):
if not contents:
break
if len(contents) != 4:
lit.error("No Cartesian Structure is detected")
raise LoadError("No Cartesian Structure is detected.", lit)
numbers.append(sym2num[contents[0]])
coor = list(map(float, contents[1:]))
coordinates.append(coor)
Expand Down
39 changes: 18 additions & 21 deletions iodata/formats/gromacs.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,27 +41,24 @@
@document_load_one("GRO", ["atcoords", "atffparams", "cellvecs", "extra", "title"])
def load_one(lit: LineIterator) -> dict:
"""Do not edit this docstring. It will be overwritten."""
while True:
data = _helper_read_frame(lit)
title = data[0]
time = data[1]
resnums = np.array(data[2])
resnames = np.array(data[3])
attypes = np.array(data[4])
atcoords = data[5]
velocities = data[6]
cellvecs = data[7]
atffparams = {"attypes": attypes, "resnames": resnames, "resnums": resnums}
extra = {"time": time, "velocities": velocities}
tovrstra marked this conversation as resolved.
Show resolved Hide resolved
return {
"atcoords": atcoords,
"atffparams": atffparams,
"cellvecs": cellvecs,
"extra": extra,
"title": title,
}
lit.error("Gromacs gro file could not be read.")
return None
data = _helper_read_frame(lit)
title = data[0]
time = data[1]
resnums = np.array(data[2])
resnames = np.array(data[3])
attypes = np.array(data[4])
atcoords = data[5]
velocities = data[6]
cellvecs = data[7]
atffparams = {"attypes": attypes, "resnames": resnames, "resnums": resnums}
extra = {"time": time, "velocities": velocities}
return {
"atcoords": atcoords,
"atffparams": atffparams,
"cellvecs": cellvecs,
"extra": extra,
"title": title,
}


@document_load_many("GRO", ["atcoords", "atffparams", "cellvecs", "extra", "title"])
Expand Down
Loading