[Numpy-svn] r3361 - in trunk/numpy/core: . include/numpy src

numpy-svn at scipy.org numpy-svn at scipy.org
Wed Oct 18 19:13:51 CDT 2006


Author: oliphant
Date: 2006-10-18 19:13:48 -0500 (Wed, 18 Oct 2006)
New Revision: 3361

Modified:
   trunk/numpy/core/include/numpy/ndarrayobject.h
   trunk/numpy/core/include/numpy/ufuncobject.h
   trunk/numpy/core/numeric.py
   trunk/numpy/core/src/scalarmathmodule.c.src
   trunk/numpy/core/src/ufuncobject.c
   trunk/numpy/core/src/umathmodule.c.src
Log:
Add print and log facilities to error handling and change the default error mode to divide='print', over='print', invalid='print', and under='ignore'

Modified: trunk/numpy/core/include/numpy/ndarrayobject.h
===================================================================
--- trunk/numpy/core/include/numpy/ndarrayobject.h	2006-10-18 22:52:29 UTC (rev 3360)
+++ trunk/numpy/core/include/numpy/ndarrayobject.h	2006-10-19 00:13:48 UTC (rev 3361)
@@ -30,7 +30,7 @@
 #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.

Modified: trunk/numpy/core/include/numpy/ufuncobject.h
===================================================================
--- trunk/numpy/core/include/numpy/ufuncobject.h	2006-10-18 22:52:29 UTC (rev 3360)
+++ trunk/numpy/core/include/numpy/ufuncobject.h	2006-10-19 00:13:48 UTC (rev 3361)
@@ -27,18 +27,20 @@
 #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,8 +51,14 @@
 #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 {
 	/* Multi-iterator portion --- needs to be present in this order
@@ -70,8 +78,9 @@
 	/* 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 @@
 	/* The error handling */
 	int errormask;
 	PyObject *errobj;
+        int first;
 
         PyUFuncGenericFunction function;
         void *funcdata;
@@ -201,12 +211,13 @@
 #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 */

Modified: trunk/numpy/core/numeric.py
===================================================================
--- trunk/numpy/core/numeric.py	2006-10-18 22:52:29 UTC (rev 3360)
+++ trunk/numpy/core/numeric.py	2006-10-19 00:13:48 UTC (rev 3361)
@@ -633,7 +633,9 @@
 _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 @@
 
     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 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 @@
     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 @@
         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

Modified: trunk/numpy/core/src/scalarmathmodule.c.src
===================================================================
--- trunk/numpy/core/src/scalarmathmodule.c.src	2006-10-18 22:52:29 UTC (rev 3360)
+++ trunk/numpy/core/src/scalarmathmodule.c.src	2006-10-19 00:13:48 UTC (rev 3361)
@@ -550,6 +550,7 @@
 
 #if @fperr@
     int retstatus;
+    int first;
 #endif
 
     switch(_ at name@_convert2_to_ctypes(a, &arg1, b, &arg2)) {
@@ -584,7 +585,8 @@
 	if (PyUFunc_GetPyValues("@name at _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 @@
     PyObject *ret;
     @name@ arg1, arg2;
     int retstatus;
+    int first;
 
 #if @cmplx@
     @name@ out = {0,0};
@@ -678,7 +681,8 @@
 	if (PyUFunc_GetPyValues("@name at _scalars", &bufsize, &errmask,
 				&errobj) < 0)
 	    return NULL;
-	if (PyUFunc_handlefperr(errmask, errobj, retstatus))
+        first = 1;
+	if (PyUFunc_handlefperr(errmask, errobj, retstatus, &first))
 	    return NULL;
     }
 

Modified: trunk/numpy/core/src/ufuncobject.c
===================================================================
--- trunk/numpy/core/src/ufuncobject.c	2006-10-18 22:52:29 UTC (rev 3360)
+++ trunk/numpy/core/src/ufuncobject.c	2006-10-19 00:13:48 UTC (rev 3361)
@@ -473,7 +473,7 @@
 */
 
 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 @@
 		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 @@
 			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 @@
 
 /*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 @@
 			     *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 @@
         }
 	loop->errobj = NULL;
         loop->notimplemented = 0;
+        loop->first = 1;
 
         name = self->name ? self->name : "";
 
@@ -2057,6 +2088,7 @@
 	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];

Modified: trunk/numpy/core/src/umathmodule.c.src
===================================================================
--- trunk/numpy/core/src/umathmodule.c.src	2006-10-18 22:52:29 UTC (rev 3360)
+++ trunk/numpy/core/src/umathmodule.c.src	2006-10-19 00:13:48 UTC (rev 3361)
@@ -2181,7 +2181,10 @@
         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);



More information about the Numpy-svn mailing list