Skip to content

Commit

Permalink
Cleaned up errors and made them more maintainable. (#929)
Browse files Browse the repository at this point in the history
Cleaned up errors and made them more maintainable
* Removed duplicated code
* Use switch on enum to ensure that compiler warnings if not all places in
  the code are updated when a new error code is added.
* Added NameError, PermissionError and InvalidMetadataError.
* Renamed dliteSearchError to dliteLookupError for better correspondance
  with python.
* Added deprecation warning for DLiteSearchError
  • Loading branch information
jesper-friis authored Aug 17, 2024
1 parent 53778e6 commit 6f38fb4
Show file tree
Hide file tree
Showing 14 changed files with 151 additions and 115 deletions.
2 changes: 1 addition & 1 deletion bindings/python/dlite-collection-python.i
Original file line number Diff line number Diff line change
Expand Up @@ -361,7 +361,7 @@ class Collection(Instance):

Raises:
DLiteTypeError: Not exactly two of `s`, `p` and `o` are None.
DLiteSearchError: No match can be found or more that one match
DLiteLookupError: No match can be found or more that one match
if `any` is true.
"""
return _dlite._collection_value(self, s, p, o, d, default, any)
Expand Down
8 changes: 4 additions & 4 deletions bindings/python/dlite-entity-python.i
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ from uuid import UUID
import numpy as np


class InvalidMetadataError:
"""Malformed or invalid metadata."""
#class InvalidMetadataError:
# """Malformed or invalid metadata."""


class Metadata(Instance):
Expand Down Expand Up @@ -91,7 +91,7 @@ class Metadata(Instance):
def getprop(self, name):
"""Returns the metadata property object with the given name."""
if "properties" not in self.properties:
raise InvalidMetadataError(
raise _dlite.DLiteInvalidMetadataError(
'self.properties on metadata must contain a "properties" item'
)
lst = [p for p in self.properties["properties"] if p.name == name]
Expand All @@ -109,7 +109,7 @@ class Metadata(Instance):
def propnames(self):
"""Returns a list of all property names in this metadata."""
if "properties" not in self.properties:
raise InvalidMetadataError(
raise _dlite.DLiteInvalidMetadataError(
'self.properties on metadata must contain a "properties" item'
)
return [p.name for p in self.properties['properties']]
Expand Down
6 changes: 5 additions & 1 deletion bindings/python/dlite-misc-python.i
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,11 @@ def deprecation_warning(version_removed, descr):
return
_deprecation_warning_record.add(descr)

warnings.warn(descr, DeprecationWarning, stacklevel=2)
warnings.warn(
f"{descr}\nIt will be removed in v{version_removed}",
DeprecationWarning,
stacklevel=2,
)

dlite_version = get_version()
if chk_semver(version_removed) < 0:
Expand Down
10 changes: 10 additions & 0 deletions bindings/python/dlite-python.i
Original file line number Diff line number Diff line change
Expand Up @@ -1413,4 +1413,14 @@ def instance_cast(inst, newtype=None):
inst.__class__ = Metadata
return inst


# Deprecated exceptions
class DLiteSearchError(_dlite.DLiteLookupError):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
deprecation_warning(
"0.7.0",
"DLiteSearchError has been renamed to DLiteLookupError."
)

%}
6 changes: 3 additions & 3 deletions bindings/python/tests/test_collection.py
Original file line number Diff line number Diff line change
Expand Up @@ -178,13 +178,13 @@
with raises(dlite.DLiteTypeError):
coll.value()

with raises(dlite.DLiteSearchError):
with raises(dlite.DLiteLookupError):
coll.value(s="dog", p="x")

with raises(dlite.DLiteSearchError):
with raises(dlite.DLiteLookupError):
coll.value(p="_is-a", o="Instance")

with raises(dlite.DLiteSearchError):
with raises(dlite.DLiteLookupError):
coll.value(s="meta", p="_has-uuid", d="xsd:int")


Expand Down
14 changes: 10 additions & 4 deletions src/dlite-errors.c
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ const char *dlite_errname(DLiteErrCode code)
case dliteRuntimeError: return "DLiteRuntime";
case dliteIndexError: return "DLiteIndex";
case dliteTypeError: return "DLiteType";
case dliteDivisionByZero: return "DLiteDivisionByZero";
case dliteDivisionByZeroError: return "DLiteDivisionByZero";
case dliteOverflowError: return "DLiteOverflow";
case dliteSyntaxError: return "DLiteSyntax";
case dliteValueError: return "DLiteValue";
Expand All @@ -28,12 +28,15 @@ const char *dlite_errname(DLiteErrCode code)

case dliteOSError: return "DLiteOS";
case dliteKeyError: return "DLiteKey";
case dliteSearchError: return "DLiteSearch";
case dliteNameError: return "DLiteName";
case dliteLookupError: return "DLiteLookup";
case dliteParseError: return "DLiteParse";
case dlitePermissionError: return "DLitePermission";
case dliteSerialiseError: return "DLiteSerialise";
case dliteUnsupportedError: return "DLiteUnsupported";
case dliteVerifyError: return "DLiteVerify";
case dliteInconsistentDataError: return "DLiteInconsistentData";
case dliteInvalidMetadataError: return "DLiteInvalidMetadata";
case dliteStorageOpenError: return "DLiteStorageOpen";
case dliteStorageLoadError: return "DLiteStorageLoad";
case dliteStorageSaveError: return "DLiteStorageSave";
Expand Down Expand Up @@ -63,7 +66,7 @@ const char *dlite_errdescr(DLiteErrCode code)
case dliteRuntimeError: return "Unspecified run-time error";
case dliteIndexError: return "Index out of range";
case dliteTypeError: return "Inappropriate argument type";
case dliteDivisionByZero: return "Division by zero";
case dliteDivisionByZeroError: return "Division by zero";
case dliteOverflowError: return "Result too large to be represented";
case dliteSyntaxError: return "Invalid syntax";
case dliteValueError: return "Inappropriate argument value (of correct type)";
Expand All @@ -74,12 +77,15 @@ const char *dlite_errdescr(DLiteErrCode code)

case dliteOSError: return "Error calling a system function";
case dliteKeyError: return "Mapping key is not found";
case dliteSearchError: return "Error in search";
case dliteNameError: return "Name not found";
case dliteLookupError: return "Error looking up item";
case dliteParseError: return "Cannot parse input";
case dlitePermissionError: return "Not enough permissions";
case dliteSerialiseError: return "Cannot serialise output";
case dliteUnsupportedError: return "Feature is not implemented/supported";
case dliteVerifyError: return "Object cannot be verified";
case dliteInconsistentDataError: return "Inconsistent data";
case dliteInvalidMetadataError: return "Invalid metadata";
case dliteStorageOpenError: return "Cannot open storage plugin";
case dliteStorageLoadError: return "Cannot load storage plugin";
case dliteStorageSaveError: return "Cannot save storage plugin";
Expand Down
63 changes: 33 additions & 30 deletions src/dlite-errors.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,42 +5,45 @@
/** DLite error codes */
typedef enum {
/* Error codes copied form SWIG */
dliteSuccess=0, /*!< Success */
dliteUnknownError=-1, /*!< Generic unknown error */
dliteIOError=-2, /*!< File input/output error */
dliteRuntimeError=-3, /*!< Unspecified run-time error */
dliteIndexError=-4, /*!< Index out of range. Ex: int x[]={1,2,3}; x[7]; */
dliteTypeError=-5, /*!< Inappropriate argument type */
dliteDivisionByZero=-6, /*!< Division by zero */
dliteOverflowError=-7, /*!< Result too large to be represented */
dliteSyntaxError=-8, /*!< Invalid syntax */
dliteValueError=-9, /*!< Inappropriate argument value */
dliteSystemError=-10, /*!< Internal error in DLite. Please report this */
dliteAttributeError=-11,/*!< Attribute or variable not found */
dliteMemoryError=-12, /*!< Out of memory */
dliteNullReferenceError=-13, /*!< Unexpected NULL argument */
dliteSuccess=0, /*!< Success */
dliteUnknownError=-1, /*!< Generic unknown error */
dliteIOError=-2, /*!< File input/output error */
dliteRuntimeError=-3, /*!< Unspecified run-time error */
dliteIndexError=-4, /*!< Index out of range. Ex: int x[]={1,2,3}; x[7]; */
dliteTypeError=-5, /*!< Inappropriate argument type */
dliteDivisionByZeroError=-6, /*!< Division by zero */
dliteOverflowError=-7, /*!< Result too large to be represented */
dliteSyntaxError=-8, /*!< Invalid syntax */
dliteValueError=-9, /*!< Inappropriate argument value */
dliteSystemError=-10, /*!< Internal error in DLite. Please report this */
dliteAttributeError=-11, /*!< Attribute or variable not found */
dliteMemoryError=-12, /*!< Out of memory */
dliteNullReferenceError=-13, /*!< Unexpected NULL argument */

/* Additional DLite-specific errors */
dliteOSError=-14, /*!< Error calling a system function */
dliteKeyError=-15, /*!< Mapping key not found */
dliteSearchError=-16, /*!< Error in search */
dliteParseError=-17, /*!< Cannot parse input */
dliteSerialiseError=-18, /*!< Cannot serialise output */
dliteUnsupportedError=-19, /*!< Feature is not implemented/supported */
dliteVerifyError=-20, /*!< Object cannot be verified */
dliteInconsistentDataError=-21,/*!< Inconsistent data */
dliteStorageOpenError=-22, /*!< Cannot open storage plugin */
dliteStorageLoadError=-23, /*!< Cannot load storage plugin */
dliteStorageSaveError=-24, /*!< Cannot save storage plugin */
dliteOptionError=-25, /*!< Invalid storage plugin option */
dliteMissingInstanceError=-26, /*!< No instance with given id can be found */
dliteMissingMetadataError=-27, /*!< No metadata with given id can be found */
dliteMetadataExistError=-28, /*!< Metadata with given id already exists */
dliteMappingError=-29, /*!< Error in instance mappings */
dlitePythonError=-30, /*!< Error calling Python API */
dliteNameError=-16, /*!< Name not found */
dliteLookupError=-17, /*!< Error looking up item */
dliteParseError=-18, /*!< Cannot parse input */
dlitePermissionError=-19, /*!< Not enough permissions */
dliteSerialiseError=-20, /*!< Cannot serialise output */
dliteUnsupportedError=-21, /*!< Feature is not implemented/supported */
dliteVerifyError=-22, /*!< Object cannot be verified */
dliteInconsistentDataError=-23,/*!< Inconsistent data */
dliteInvalidMetadataError=-24, /*!< Invalid metadata */
dliteStorageOpenError=-25, /*!< Cannot open storage plugin */
dliteStorageLoadError=-26, /*!< Cannot load storage plugin */
dliteStorageSaveError=-27, /*!< Cannot save storage plugin */
dliteOptionError=-28, /*!< Invalid storage plugin option */
dliteMissingInstanceError=-29, /*!< No instance with given id can be found */
dliteMissingMetadataError=-30, /*!< No metadata with given id can be found */
dliteMetadataExistError=-31, /*!< Metadata with given id already exists */
dliteMappingError=-32, /*!< Error in instance mappings */
dlitePythonError=-33, /*!< Error calling Python API */

/* Should always be the last error */
dliteLastError=-31
dliteLastError=-34
} DLiteErrCode;


Expand Down
15 changes: 13 additions & 2 deletions src/dlite-misc.c
Original file line number Diff line number Diff line change
Expand Up @@ -540,11 +540,22 @@ void dlite_globals_set(DLiteGlobals *globals_handler)
}


/* Error handler for DLite. */
/* Error handler for DLite.
Since errors
Print warnings, but not errors unless DLITE_PYDEBUG is set.
*/
static void dlite_err_handler(const ErrRecord *record)
{
if (!dlite_err_ignored_get(record->eval) && getenv("DLITE_PYDEBUG"))
#ifdef WITH_PYTHON
if (record->level != errLevelError ||
!getenv("DLITE_PYDEBUG") ||
!dlite_err_ignored_get(record->eval))
err_default_handler(record);
#else /* WITH_PYTHON */
if (!dlite_err_ignored_get(record->eval))
err_default_handler(record);
#endif
}


Expand Down
97 changes: 64 additions & 33 deletions src/pyembed/dlite-pyembed.c
Original file line number Diff line number Diff line change
Expand Up @@ -52,30 +52,77 @@ static PyembedGlobals *get_globals(void)
return g;
}


/*
Return Python exception class corresponding to given DLite error code.
Returns NULL if `code` is zero.
*/
PyObject *dlite_pyembed_exception(DLiteErrCode code)
{
switch (code) {
case dliteSuccess: return NULL;
case dliteUnknownError: break;
case dliteIOError: return PyExc_IOError;
case dliteRuntimeError: return PyExc_RuntimeError;
case dliteIndexError: return PyExc_IndexError;
case dliteTypeError: return PyExc_TypeError;
case dliteDivisionByZeroError: return PyExc_ZeroDivisionError;
case dliteOverflowError: return PyExc_OverflowError;
case dliteSyntaxError: return PyExc_SyntaxError;
case dliteValueError: return PyExc_ValueError;
case dliteSystemError: return PyExc_SystemError;
case dliteAttributeError: return PyExc_AttributeError;
case dliteMemoryError: return PyExc_MemoryError;
case dliteNullReferenceError: break;

case dliteOSError: return PyExc_OSError;
case dliteKeyError: return PyExc_KeyError;
case dliteNameError: return PyExc_NameError;
case dliteLookupError: return PyExc_LookupError;
case dliteParseError: return PyExc_IOError; // dup
case dlitePermissionError: return PyExc_PermissionError;
case dliteSerialiseError: return PyExc_IOError; // dup
case dliteUnsupportedError: break;
case dliteVerifyError: break;
case dliteInconsistentDataError: return PyExc_ValueError; // dup
case dliteInvalidMetadataError: return PyExc_ValueError; // dup
case dliteStorageOpenError: return PyExc_IOError; // dup
case dliteStorageLoadError: return PyExc_IOError; // dup
case dliteStorageSaveError: return PyExc_IOError; // dup
case dliteOptionError: return PyExc_ValueError; // dup
case dliteMissingInstanceError: return PyExc_LookupError; // dup
case dliteMissingMetadataError: return PyExc_LookupError; // dup
case dliteMetadataExistError: break;
case dliteMappingError: break;
case dlitePythonError: break;
case dliteLastError: break;
}
return PyExc_Exception;
}


/* Help function returning a constant pointer to a NULL-terminated
array of ErrorCorrelation records. */
static const ErrorCorrelation *error_correlations(void)
{
PyembedGlobals *g = get_globals();
if (!g->errcorr) {
ErrorCorrelation corr[] = {
{PyExc_KeyError, dliteKeyError},
{PyExc_MemoryError, dliteMemoryError},
{PyExc_AttributeError, dliteAttributeError},
{PyExc_SystemError, dliteSystemError},
{PyExc_ValueError, dliteValueError},
{PyExc_SyntaxError, dliteSyntaxError},
{PyExc_OverflowError, dliteOverflowError},
{PyExc_ZeroDivisionError, dliteDivisionByZero},
{PyExc_TypeError, dliteTypeError},
{PyExc_IndexError, dliteIndexError},
{PyExc_RuntimeError, dliteRuntimeError},
{PyExc_IOError, dliteIOError},
{NULL, 0}
};
if (!(g->errcorr = malloc(sizeof(corr))))
int i, code, n=1;
for (code=-1; code>dliteLastError; code--)
if (dlite_pyembed_exception(code) != PyExc_Exception) n++;

if (!(g->errcorr = calloc(n, sizeof(ErrorCorrelation))))
return dlite_err(dliteMemoryError, "allocation failure"), NULL;
memcpy(g->errcorr, corr, sizeof(corr));

for (code=-1, i=0; code>dliteLastError; code--) {
PyObject *exc;
if ((exc = dlite_pyembed_exception(code)) != PyExc_Exception) {
g->errcorr[i].exc = exc;
g->errcorr[i].errcode = code;
i++;
}
}
assert(i == n-1);
}
return g->errcorr;
}
Expand Down Expand Up @@ -207,22 +254,6 @@ DLiteErrCode dlite_pyembed_errcode(PyObject *type)
return dliteUnknownError;
}

/*
Return Python exception class corresponding to given DLite error code.
Returns NULL if `code` is zero.
*/
PyObject *dlite_pyembed_exception(DLiteErrCode code)
{
const ErrorCorrelation *corr = error_correlations();
if (!code) return NULL;
while (corr->exc) {
if (code == corr->errcode) return corr->exc;
corr++;
}
return PyExc_Exception;
}


/*
Writes Python error message to `errmsg` (of length `len`) if an
Python error has occured.
Expand Down
31 changes: 1 addition & 30 deletions src/pyembed/dlite-python-singletons.c
Original file line number Diff line number Diff line change
Expand Up @@ -122,35 +122,6 @@ PyObject *dlite_python_module_class(const char *classname)
}


/*
Help function returning builtin Python exception corresponding to
error code or NULL, if no such built-in exception exists in Python.
*/
static PyObject *_python_exc(DLiteErrCode code)
{
switch (code) {
case dliteIOError: return PyExc_IOError;
case dliteRuntimeError: return PyExc_RuntimeError;
case dliteIndexError: return PyExc_IndexError;
case dliteTypeError: return PyExc_TypeError;
case dliteDivisionByZero: return PyExc_ZeroDivisionError;
case dliteOverflowError: return PyExc_OverflowError;
case dliteSyntaxError: return PyExc_SyntaxError;
case dliteValueError: return PyExc_ValueError;
case dliteSystemError: return PyExc_SystemError;
case dliteAttributeError: return PyExc_AttributeError;
case dliteMemoryError: return PyExc_MemoryError;

case dliteOSError: return PyExc_OSError;
case dliteKeyError: return PyExc_KeyError;
case dliteUnsupportedError: return PyExc_NotImplementedError;
case dliteStorageOpenError: return PyExc_ConnectionError;

default: return NULL;
}
}


/*
Returns a borrowed reference to singleton Python exception object
for the given DLite error code.
Expand Down Expand Up @@ -199,7 +170,7 @@ PyObject *dlite_python_module_error(DLiteErrCode code)
if ((exc = PyDict_GetItemString(dict, errname))) return exc;

/* Base exceptions */
if ((pyexc = _python_exc(code))) {
if ((pyexc = dlite_pyembed_exception(code)) && pyexc != PyExc_Exception) {
if (!(base = Py_BuildValue("(O,O)", dliteError, pyexc)))
FAILCODE(dlitePythonError, "cannot build dlite exception base");
} else {
Expand Down
Loading

0 comments on commit 6f38fb4

Please sign in to comment.