diff options
author | Travis Oliphant <oliphant@enthought.com> | 2006-10-19 00:13:48 +0000 |
---|---|---|
committer | Travis Oliphant <oliphant@enthought.com> | 2006-10-19 00:13:48 +0000 |
commit | 448f3851e99f4667faaae813bd0cd6df2b666c29 (patch) | |
tree | fae63622aef344f337d2e7d5640ab3e30802314b | |
parent | 42ec0613463dd5a1e583370d5f7fd8fddbedced8 (diff) | |
download | numpy-448f3851e99f4667faaae813bd0cd6df2b666c29.tar.gz |
Add print and log facilities to error handling and change the default error mode to divide='print', over='print', invalid='print', and under='ignore'
-rw-r--r-- | numpy/core/include/numpy/ndarrayobject.h | 2 | ||||
-rw-r--r-- | numpy/core/include/numpy/ufuncobject.h | 41 | ||||
-rw-r--r-- | numpy/core/numeric.py | 16 | ||||
-rw-r--r-- | numpy/core/src/scalarmathmodule.c.src | 8 | ||||
-rw-r--r-- | numpy/core/src/ufuncobject.c | 52 | ||||
-rw-r--r-- | numpy/core/src/umathmodule.c.src | 3 |
6 files changed, 88 insertions, 34 deletions
diff --git a/numpy/core/include/numpy/ndarrayobject.h b/numpy/core/include/numpy/ndarrayobject.h index e06eb91df..05781e457 100644 --- a/numpy/core/include/numpy/ndarrayobject.h +++ b/numpy/core/include/numpy/ndarrayobject.h @@ -30,7 +30,7 @@ extern "C" CONFUSE_EMACS #define NPY_SUCCEED 1 /* Helpful to distinguish what is installed */ -#define NPY_VERSION 0x01000008 +#define NPY_VERSION 0x01000009 /* Some platforms don't define bool, long long, or long double. Handle that here. diff --git a/numpy/core/include/numpy/ufuncobject.h b/numpy/core/include/numpy/ufuncobject.h index f3a6bd943..ebddf6f74 100644 --- a/numpy/core/include/numpy/ufuncobject.h +++ b/numpy/core/include/numpy/ufuncobject.h @@ -27,18 +27,20 @@ typedef struct { #define UFUNC_ERR_WARN 1 #define UFUNC_ERR_RAISE 2 #define UFUNC_ERR_CALL 3 +#define UFUNC_ERR_PRINT 4 +#define UFUNC_ERR_LOG 5 /* Python side integer mask */ -#define UFUNC_MASK_DIVIDEBYZERO 0x03 -#define UFUNC_MASK_OVERFLOW 0x0c -#define UFUNC_MASK_UNDERFLOW 0x30 -#define UFUNC_MASK_INVALID 0xc0 +#define UFUNC_MASK_DIVIDEBYZERO 0x07 +#define UFUNC_MASK_OVERFLOW 0x3f +#define UFUNC_MASK_UNDERFLOW 0x1ff +#define UFUNC_MASK_INVALID 0xfff #define UFUNC_SHIFT_DIVIDEBYZERO 0 -#define UFUNC_SHIFT_OVERFLOW 2 -#define UFUNC_SHIFT_UNDERFLOW 4 -#define UFUNC_SHIFT_INVALID 6 +#define UFUNC_SHIFT_OVERFLOW 3 +#define UFUNC_SHIFT_UNDERFLOW 6 +#define UFUNC_SHIFT_INVALID 9 /* platform-dependent code translates floating point @@ -49,7 +51,13 @@ typedef struct { #define UFUNC_FPE_UNDERFLOW 4 #define UFUNC_FPE_INVALID 8 -#define UFUNC_ERR_DEFAULT 0 /* Default error mode */ +#define UFUNC_ERR_DEFAULT 0 /* Error mode that avoids look-up (no checking) */ + + /* Default user error mode */ +#define UFUNC_ERR_DEFAULT2 \ + (UFUNC_ERR_PRINT << UFUNC_SHIFT_DIVIDEBYZERO) + \ + (UFUNC_ERR_PRINT << UFUNC_SHIFT_OVERFLOW) + \ + (UFUNC_ERR_PRINT << UFUNC_SHIFT_INVALID) /* Only internal -- not exported, yet*/ typedef struct { @@ -70,8 +78,9 @@ typedef struct { /* The error handling */ int errormask; /* Integer showing desired error handling */ PyObject *errobj; /* currently a tuple with - (string, func or None) + (string, func or obj with write method or None) */ + int first; /* Specific function and data to use */ PyUFuncGenericFunction function; @@ -134,6 +143,7 @@ typedef struct { /* The error handling */ int errormask; PyObject *errobj; + int first; PyUFuncGenericFunction function; void *funcdata; @@ -201,12 +211,13 @@ typedef struct _loop1d_info { #include "__ufunc_api.h" #define UFUNC_PYVALS_NAME "UFUNC_PYVALS" - -#define UFUNC_CHECK_ERROR(arg) \ - if (((arg)->obj && PyErr_Occurred()) || \ - ((arg)->errormask && \ - PyUFunc_checkfperr((arg)->errormask, \ - (arg)->errobj))) \ + +#define UFUNC_CHECK_ERROR(arg) \ + if (((arg)->obj && PyErr_Occurred()) || \ + ((arg)->errormask && \ + PyUFunc_checkfperr((arg)->errormask, \ + (arg)->errobj, \ + &(arg)->first))) \ goto fail /* This code checks the IEEE status flags in a platform-dependent way */ diff --git a/numpy/core/numeric.py b/numpy/core/numeric.py index 8356227de..8ac6ff726 100644 --- a/numpy/core/numeric.py +++ b/numpy/core/numeric.py @@ -633,7 +633,9 @@ def array_equiv(a1, a2): _errdict = {"ignore":ERR_IGNORE, "warn":ERR_WARN, "raise":ERR_RAISE, - "call":ERR_CALL} + "call":ERR_CALL, + "print":ERR_PRINT, + "log":ERR_LOG} _errdict_rev = {} for key in _errdict.keys(): @@ -690,10 +692,10 @@ def geterr(): Returns a dictionary with entries "divide", "over", "under", and "invalid", whose values are from the strings - "ignore", "warn", "raise", and "call". + "ignore", "print", "log", "warn", "raise", and "call". """ maskvalue = umath.geterrobj()[1] - mask = 3 + mask = 7 res = {} val = (maskvalue >> SHIFT_DIVIDEBYZERO) & mask res['divide'] = _errdict_rev[val] @@ -728,7 +730,8 @@ def getbufsize(): def seterrcall(func): """Set the callback function used when a floating-point error handler - is set to 'call'. + is set to 'call' or the object with a write method for use when + the floating-point error handler is set to 'log' 'func' should be a function that takes two arguments. The first is type of error ("divide", "over", "under", or "invalid"), and the second @@ -737,7 +740,8 @@ def seterrcall(func): Returns the old handler. """ if func is not None and not callable(func): - raise ValueError, "Only callable can be used as callback" + if not hasattr(func, 'write') or not callable(func.write): + raise ValueError, "Only callable can be used as callback" pyvals = umath.geterrobj() old = geterrcall() pyvals[2] = func @@ -784,7 +788,7 @@ class errstate(object): seterr(**self.oldstate) def _setdef(): - defval = [UFUNC_BUFSIZE_DEFAULT, ERR_DEFAULT, None] + defval = [UFUNC_BUFSIZE_DEFAULT, ERR_DEFAULT2, None] umath.seterrobj(defval) # set the default values diff --git a/numpy/core/src/scalarmathmodule.c.src b/numpy/core/src/scalarmathmodule.c.src index 1f2591d01..153a0f389 100644 --- a/numpy/core/src/scalarmathmodule.c.src +++ b/numpy/core/src/scalarmathmodule.c.src @@ -550,6 +550,7 @@ static PyObject * #if @fperr@ int retstatus; + int first; #endif switch(_@name@_convert2_to_ctypes(a, &arg1, b, &arg2)) { @@ -584,7 +585,8 @@ static PyObject * if (PyUFunc_GetPyValues("@name@_scalars", &bufsize, &errmask, &errobj) < 0) return NULL; - if (PyUFunc_handlefperr(errmask, errobj, retstatus)) + first = 1; + if (PyUFunc_handlefperr(errmask, errobj, retstatus, &first)) return NULL; } #endif @@ -625,6 +627,7 @@ static PyObject * PyObject *ret; @name@ arg1, arg2; int retstatus; + int first; #if @cmplx@ @name@ out = {0,0}; @@ -678,7 +681,8 @@ static PyObject * if (PyUFunc_GetPyValues("@name@_scalars", &bufsize, &errmask, &errobj) < 0) return NULL; - if (PyUFunc_handlefperr(errmask, errobj, retstatus)) + first = 1; + if (PyUFunc_handlefperr(errmask, errobj, retstatus, &first)) return NULL; } diff --git a/numpy/core/src/ufuncobject.c b/numpy/core/src/ufuncobject.c index 878ebde53..32ff5308b 100644 --- a/numpy/core/src/ufuncobject.c +++ b/numpy/core/src/ufuncobject.c @@ -473,7 +473,7 @@ PyUFunc_On_Om(char **args, intp *dimensions, intp *steps, void *func) */ static int -_error_handler(int method, PyObject *errobj, char *errtype, int retstatus) +_error_handler(int method, PyObject *errobj, char *errtype, int retstatus, int *first) { PyObject *pyfunc, *ret, *args; char *name=PyString_AS_STRING(PyTuple_GET_ITEM(errobj,0)); @@ -512,6 +512,29 @@ _error_handler(int method, PyObject *errobj, char *errtype, int retstatus) Py_DECREF(ret); break; + case UFUNC_ERR_PRINT: + if (*first) { + fprintf(stderr, "Warning: %s encountered in %s\n", errtype, name); + *first = 0; + } + break; + case UFUNC_ERR_LOG: + if (first) { + *first = 0; + pyfunc = PyTuple_GET_ITEM(errobj, 1); + if (pyfunc == Py_None) { + PyErr_Format(PyExc_NameError, + "log specified for %s (in %s) but no " \ + "object with write method found.", + errtype, name); + goto fail; + } + snprintf(msg, 100, "Warning: %s encountered in %s\n", errtype, name); + ret = PyObject_CallMethod(pyfunc, "write", "s", msg); + if (ret == NULL) goto fail; + Py_DECREF(ret); + } + break; } DISABLE_C_API return 0; @@ -535,13 +558,13 @@ PyUFunc_getfperr(void) handle = errmask & UFUNC_MASK_##NAME;\ if (handle && \ _error_handler(handle >> UFUNC_SHIFT_##NAME, \ - errobj, str, retstatus) < 0) \ + errobj, str, retstatus, first) < 0) \ return -1; \ }} /*UFUNC_API*/ static int -PyUFunc_handlefperr(int errmask, PyObject *errobj, int retstatus) +PyUFunc_handlefperr(int errmask, PyObject *errobj, int retstatus, int *first) { int handle; if (errmask && retstatus) { @@ -558,13 +581,13 @@ PyUFunc_handlefperr(int errmask, PyObject *errobj, int retstatus) /*UFUNC_API*/ static int -PyUFunc_checkfperr(int errmask, PyObject *errobj) +PyUFunc_checkfperr(int errmask, PyObject *errobj, int *first) { int retstatus; /* 1. check hardware flag --- this is platform dependent code */ retstatus = PyUFunc_getfperr(); - return PyUFunc_handlefperr(errmask, errobj, retstatus); + return PyUFunc_handlefperr(errmask, errobj, retstatus, first); } @@ -958,14 +981,21 @@ _extract_pyvals(PyObject *ref, char *name, int *bufsize, *errmask); return -1; } - + retval = PyList_GET_ITEM(ref, 2); if (retval != Py_None && !PyCallable_Check(retval)) { - PyErr_SetString(PyExc_TypeError, - "callback function must be callable"); - return -1; + PyObject *temp; + temp = PyObject_GetAttrString(retval, "write"); + if (temp == NULL || !PyCallable_Check(temp)) { + PyErr_SetString(PyExc_TypeError, + "python object must be callable or have " \ + "a callable write method"); + Py_XDECREF(temp); + return -1; + } + Py_DECREF(temp); } - + *errobj = Py_BuildValue("NO", PyString_FromString(name), retval); @@ -1571,6 +1601,7 @@ construct_loop(PyUFuncObject *self, PyObject *args, PyObject *kwds, PyArrayObjec } loop->errobj = NULL; loop->notimplemented = 0; + loop->first = 1; name = self->name ? self->name : ""; @@ -2057,6 +2088,7 @@ construct_reduce(PyUFuncObject *self, PyArrayObject **arr, PyArrayObject *out, loop->it = NULL; loop->rit = NULL; loop->errobj = NULL; + loop->first = 1; loop->decref=NULL; loop->N = (*arr)->dimensions[axis]; loop->instrides = (*arr)->strides[axis]; diff --git a/numpy/core/src/umathmodule.c.src b/numpy/core/src/umathmodule.c.src index fa7cd678b..ba1521aeb 100644 --- a/numpy/core/src/umathmodule.c.src +++ b/numpy/core/src/umathmodule.c.src @@ -2181,7 +2181,10 @@ PyMODINIT_FUNC initumath(void) { ADDCONST(ERR_WARN); ADDCONST(ERR_CALL); ADDCONST(ERR_RAISE); + ADDCONST(ERR_PRINT); + ADDCONST(ERR_LOG); ADDCONST(ERR_DEFAULT); + ADDCONST(ERR_DEFAULT2); ADDCONST(SHIFT_DIVIDEBYZERO); ADDCONST(SHIFT_OVERFLOW); |