summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTravis Oliphant <oliphant@enthought.com>2006-10-19 00:13:48 +0000
committerTravis Oliphant <oliphant@enthought.com>2006-10-19 00:13:48 +0000
commit448f3851e99f4667faaae813bd0cd6df2b666c29 (patch)
treefae63622aef344f337d2e7d5640ab3e30802314b
parent42ec0613463dd5a1e583370d5f7fd8fddbedced8 (diff)
downloadnumpy-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.h2
-rw-r--r--numpy/core/include/numpy/ufuncobject.h41
-rw-r--r--numpy/core/numeric.py16
-rw-r--r--numpy/core/src/scalarmathmodule.c.src8
-rw-r--r--numpy/core/src/ufuncobject.c52
-rw-r--r--numpy/core/src/umathmodule.c.src3
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);