diff options
author | Eric Wieser <wieser.eric@gmail.com> | 2017-04-28 21:54:34 +0100 |
---|---|---|
committer | Eric Wieser <wieser.eric@gmail.com> | 2017-06-02 11:09:00 +0100 |
commit | 32436eaa195db9930f1d5e46381afa4594881019 (patch) | |
tree | 774ae1bce75ded76549c665988a2c35912b7881a /numpy/core | |
parent | 090d46e76fbda7f7fc73751c221d0c58b9d889af (diff) | |
download | numpy-32436eaa195db9930f1d5e46381afa4594881019.tar.gz |
MAINT: Move functions handling ufunc extobj
This makes it visible inside other files, like reduction.c
Apart from the includes, everything here is just a direct move - there are no code changes
Diffstat (limited to 'numpy/core')
-rw-r--r-- | numpy/core/setup.py | 1 | ||||
-rw-r--r-- | numpy/core/src/umath/extobj.c | 317 | ||||
-rw-r--r-- | numpy/core/src/umath/extobj.h | 32 | ||||
-rw-r--r-- | numpy/core/src/umath/ufunc_object.c | 313 |
4 files changed, 351 insertions, 312 deletions
diff --git a/numpy/core/setup.py b/numpy/core/setup.py index f268258ee..a5643ed3e 100644 --- a/numpy/core/setup.py +++ b/numpy/core/setup.py @@ -874,6 +874,7 @@ def configuration(parent_package='',top_path=None): join('src', 'umath', 'loops.h.src'), join('src', 'umath', 'loops.c.src'), join('src', 'umath', 'ufunc_object.c'), + join('src', 'umath', 'extobj.c'), join('src', 'umath', 'scalarmath.c.src'), join('src', 'umath', 'ufunc_type_resolution.c'), join('src', 'umath', 'override.c'), diff --git a/numpy/core/src/umath/extobj.c b/numpy/core/src/umath/extobj.c new file mode 100644 index 000000000..644f29f0c --- /dev/null +++ b/numpy/core/src/umath/extobj.c @@ -0,0 +1,317 @@ +#define _UMATHMODULE +#define NPY_NO_DEPRECATED_API NPY_API_VERSION + +#include <Python.h> + +#include "npy_config.h" + +#define PY_ARRAY_UNIQUE_SYMBOL _npy_umathmodule_ARRAY_API +#define NO_IMPORT_ARRAY + +#include "npy_pycompat.h" + +#include "extobj.h" +#include "numpy/ufuncobject.h" + +#include "ufunc_object.h" /* for npy_um_str_pyvals_name */ + +#if USE_USE_DEFAULTS==1 +static int PyUFunc_NUM_NODEFAULTS = 0; + +/* + * This is a strategy to buy a little speed up and avoid the dictionary + * look-up in the default case. It should work in the presence of + * threads. If it is deemed too complicated or it doesn't actually work + * it could be taken out. + */ +NPY_NO_EXPORT int +ufunc_update_use_defaults(void) +{ + PyObject *errobj = NULL; + int errmask, bufsize; + int res; + + PyUFunc_NUM_NODEFAULTS += 1; + res = PyUFunc_GetPyValues("test", &bufsize, &errmask, &errobj); + PyUFunc_NUM_NODEFAULTS -= 1; + if (res < 0) { + Py_XDECREF(errobj); + return -1; + } + if ((errmask != UFUNC_ERR_DEFAULT) || (bufsize != NPY_BUFSIZE) + || (PyTuple_GET_ITEM(errobj, 1) != Py_None)) { + PyUFunc_NUM_NODEFAULTS += 1; + } + else if (PyUFunc_NUM_NODEFAULTS > 0) { + PyUFunc_NUM_NODEFAULTS -= 1; + } + Py_XDECREF(errobj); + return 0; +} +#endif + +/* + * fpstatus is the ufunc_formatted hardware status + * errmask is the handling mask specified by the user. + * errobj is a Python object with (string, callable object or None) + * or NULL + */ + +/* + * 2. for each of the flags + * determine whether to ignore, warn, raise error, or call Python function. + * If ignore, do nothing + * If warn, print a warning and continue + * If raise return an error + * If call, call a user-defined function with string + */ + +NPY_NO_EXPORT int +_error_handler(int method, PyObject *errobj, char *errtype, int retstatus, int *first) +{ + PyObject *pyfunc, *ret, *args; + char *name = PyBytes_AS_STRING(PyTuple_GET_ITEM(errobj,0)); + char msg[100]; + + NPY_ALLOW_C_API_DEF + + /* don't need C API for a simple print */ + if (method == UFUNC_ERR_PRINT) { + if (*first) { + fprintf(stderr, "Warning: %s encountered in %s\n", errtype, name); + *first = 0; + } + return 0; + } + + NPY_ALLOW_C_API; + switch(method) { + case UFUNC_ERR_WARN: + PyOS_snprintf(msg, sizeof(msg), "%s encountered in %s", errtype, name); + if (PyErr_Warn(PyExc_RuntimeWarning, msg) < 0) { + goto fail; + } + break; + case UFUNC_ERR_RAISE: + PyErr_Format(PyExc_FloatingPointError, "%s encountered in %s", + errtype, name); + goto fail; + case UFUNC_ERR_CALL: + pyfunc = PyTuple_GET_ITEM(errobj, 1); + if (pyfunc == Py_None) { + PyErr_Format(PyExc_NameError, + "python callback specified for %s (in " \ + " %s) but no function found.", + errtype, name); + goto fail; + } + args = Py_BuildValue("NN", PyUString_FromString(errtype), + PyInt_FromLong((long) retstatus)); + if (args == NULL) { + goto fail; + } + ret = PyObject_CallObject(pyfunc, args); + Py_DECREF(args); + if (ret == NULL) { + goto fail; + } + Py_DECREF(ret); + 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; + } + PyOS_snprintf(msg, sizeof(msg), + "Warning: %s encountered in %s\n", errtype, name); + ret = PyObject_CallMethod(pyfunc, "write", "s", msg); + if (ret == NULL) { + goto fail; + } + Py_DECREF(ret); + } + break; + } + NPY_DISABLE_C_API; + return 0; + +fail: + NPY_DISABLE_C_API; + return -1; +} + + + +NPY_NO_EXPORT PyObject * +get_global_ext_obj(void) +{ + PyObject *thedict; + PyObject *ref = NULL; + +#if USE_USE_DEFAULTS==1 + if (PyUFunc_NUM_NODEFAULTS != 0) { +#endif + thedict = PyThreadState_GetDict(); + if (thedict == NULL) { + thedict = PyEval_GetBuiltins(); + } + ref = PyDict_GetItem(thedict, npy_um_str_pyvals_name); +#if USE_USE_DEFAULTS==1 + } +#endif + + return ref; +} + + +/* + * Extracts some values from the global pyvals tuple. + * all destinations may be NULL, in which case they are not retrieved + * ref - should hold the global tuple + * name - is the name of the ufunc (ufuncobj->name) + * + * bufsize - receives the buffer size to use + * errmask - receives the bitmask for error handling + * errobj - receives the python object to call with the error, + * if an error handling method is 'call' + */ +NPY_NO_EXPORT int +_extract_pyvals(PyObject *ref, const char *name, int *bufsize, + int *errmask, PyObject **errobj) +{ + PyObject *retval; + + /* default errobj case, skips dictionary lookup */ + if (ref == NULL) { + if (errmask) { + *errmask = UFUNC_ERR_DEFAULT; + } + if (errobj) { + *errobj = Py_BuildValue("NO", PyBytes_FromString(name), Py_None); + } + if (bufsize) { + *bufsize = NPY_BUFSIZE; + } + return 0; + } + + if (!PyList_Check(ref) || (PyList_GET_SIZE(ref)!=3)) { + PyErr_Format(PyExc_TypeError, + "%s must be a length 3 list.", UFUNC_PYVALS_NAME); + return -1; + } + + if (bufsize != NULL) { + *bufsize = PyInt_AsLong(PyList_GET_ITEM(ref, 0)); + if ((*bufsize == -1) && PyErr_Occurred()) { + return -1; + } + if ((*bufsize < NPY_MIN_BUFSIZE) || + (*bufsize > NPY_MAX_BUFSIZE) || + (*bufsize % 16 != 0)) { + PyErr_Format(PyExc_ValueError, + "buffer size (%d) is not in range " + "(%"NPY_INTP_FMT" - %"NPY_INTP_FMT") or not a multiple of 16", + *bufsize, (npy_intp) NPY_MIN_BUFSIZE, + (npy_intp) NPY_MAX_BUFSIZE); + return -1; + } + } + + if (errmask != NULL) { + *errmask = PyInt_AsLong(PyList_GET_ITEM(ref, 1)); + if (*errmask < 0) { + if (PyErr_Occurred()) { + return -1; + } + PyErr_Format(PyExc_ValueError, + "invalid error mask (%d)", + *errmask); + return -1; + } + } + + if (errobj != NULL) { + *errobj = NULL; + retval = PyList_GET_ITEM(ref, 2); + if (retval != Py_None && !PyCallable_Check(retval)) { + 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", PyBytes_FromString(name), retval); + if (*errobj == NULL) { + return -1; + } + } + return 0; +} + +/* + * check the floating point status + * - errmask: mask of status to check + * - extobj: ufunc pyvals object + * may be null, in which case the thread global one is fetched + * - ufunc_name: name of ufunc + */ +NPY_NO_EXPORT int +_check_ufunc_fperr(int errmask, PyObject *extobj, const char *ufunc_name) { + int fperr; + PyObject *errobj = NULL; + int ret; + int first = 1; + + if (!errmask) { + return 0; + } + fperr = PyUFunc_getfperr(); + if (!fperr) { + return 0; + } + + /* Get error object globals */ + if (extobj == NULL) { + extobj = get_global_ext_obj(); + } + if (_extract_pyvals(extobj, ufunc_name, + NULL, NULL, &errobj) < 0) { + Py_XDECREF(errobj); + return -1; + } + + ret = PyUFunc_handlefperr(errmask, errobj, fperr, &first); + Py_XDECREF(errobj); + + return ret; +} + + +NPY_NO_EXPORT int +_get_bufsize_errmask(PyObject * extobj, const char *ufunc_name, + int *buffersize, int *errormask) +{ + /* Get the buffersize and errormask */ + if (extobj == NULL) { + extobj = get_global_ext_obj(); + } + if (_extract_pyvals(extobj, ufunc_name, + buffersize, errormask, NULL) < 0) { + return -1; + } + + return 0; +} diff --git a/numpy/core/src/umath/extobj.h b/numpy/core/src/umath/extobj.h new file mode 100644 index 000000000..1a569dfbd --- /dev/null +++ b/numpy/core/src/umath/extobj.h @@ -0,0 +1,32 @@ +#ifndef _NPY_PRIVATE__EXTOBJ_H_ +#define _NPY_PRIVATE__EXTOBJ_H_ + +#include <numpy/ndarraytypes.h> /* for NPY_NO_EXPORT */ + +NPY_NO_EXPORT int +_error_handler(int method, PyObject *errobj, char *errtype, int retstatus, int *first); + +NPY_NO_EXPORT PyObject * +get_global_ext_obj(void); + +NPY_NO_EXPORT int +_extract_pyvals(PyObject *ref, const char *name, int *bufsize, + int *errmask, PyObject **errobj); + +NPY_NO_EXPORT int +_check_ufunc_fperr(int errmask, PyObject *extobj, const char *ufunc_name); + +NPY_NO_EXPORT int +_get_bufsize_errmask(PyObject * extobj, const char *ufunc_name, + int *buffersize, int *errormask); + +/********************/ +#define USE_USE_DEFAULTS 1 +/********************/ + +#if USE_USE_DEFAULTS==1 +NPY_NO_EXPORT int +ufunc_update_use_defaults(void); +#endif + +#endif diff --git a/numpy/core/src/umath/ufunc_object.c b/numpy/core/src/umath/ufunc_object.c index c5ba15fa3..67e5cd0f3 100644 --- a/numpy/core/src/umath/ufunc_object.c +++ b/numpy/core/src/umath/ufunc_object.c @@ -46,6 +46,7 @@ #include "ufunc_object.h" #include "override.h" #include "npy_import.h" +#include "extobj.h" /********** PRINTF DEBUG TRACING **************/ #define NPY_UF_DBG_TRACING 0 @@ -63,21 +64,12 @@ #endif /**********************************************/ - -/********************/ -#define USE_USE_DEFAULTS 1 -/********************/ - /* ---------------------------------------------------------------- */ static int _does_loop_use_arrays(void *data); static int -_extract_pyvals(PyObject *ref, const char *name, int *bufsize, - int *errmask, PyObject **errobj); - -static int assign_reduce_identity_zero(PyArrayObject *result, void *data); static int @@ -87,103 +79,6 @@ static int assign_reduce_identity_one(PyArrayObject *result, void *data); -/* - * fpstatus is the ufunc_formatted hardware status - * errmask is the handling mask specified by the user. - * errobj is a Python object with (string, callable object or None) - * or NULL - */ - -/* - * 2. for each of the flags - * determine whether to ignore, warn, raise error, or call Python function. - * If ignore, do nothing - * If warn, print a warning and continue - * If raise return an error - * If call, call a user-defined function with string - */ - -static int -_error_handler(int method, PyObject *errobj, char *errtype, int retstatus, int *first) -{ - PyObject *pyfunc, *ret, *args; - char *name = PyBytes_AS_STRING(PyTuple_GET_ITEM(errobj,0)); - char msg[100]; - - NPY_ALLOW_C_API_DEF - - /* don't need C API for a simple print */ - if (method == UFUNC_ERR_PRINT) { - if (*first) { - fprintf(stderr, "Warning: %s encountered in %s\n", errtype, name); - *first = 0; - } - return 0; - } - - NPY_ALLOW_C_API; - switch(method) { - case UFUNC_ERR_WARN: - PyOS_snprintf(msg, sizeof(msg), "%s encountered in %s", errtype, name); - if (PyErr_Warn(PyExc_RuntimeWarning, msg) < 0) { - goto fail; - } - break; - case UFUNC_ERR_RAISE: - PyErr_Format(PyExc_FloatingPointError, "%s encountered in %s", - errtype, name); - goto fail; - case UFUNC_ERR_CALL: - pyfunc = PyTuple_GET_ITEM(errobj, 1); - if (pyfunc == Py_None) { - PyErr_Format(PyExc_NameError, - "python callback specified for %s (in " \ - " %s) but no function found.", - errtype, name); - goto fail; - } - args = Py_BuildValue("NN", PyUString_FromString(errtype), - PyInt_FromLong((long) retstatus)); - if (args == NULL) { - goto fail; - } - ret = PyObject_CallObject(pyfunc, args); - Py_DECREF(args); - if (ret == NULL) { - goto fail; - } - Py_DECREF(ret); - 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; - } - PyOS_snprintf(msg, sizeof(msg), - "Warning: %s encountered in %s\n", errtype, name); - ret = PyObject_CallMethod(pyfunc, "write", "s", msg); - if (ret == NULL) { - goto fail; - } - Py_DECREF(ret); - } - break; - } - NPY_DISABLE_C_API; - return 0; - -fail: - NPY_DISABLE_C_API; - return -1; -} - - /*UFUNC_API*/ NPY_NO_EXPORT int PyUFunc_getfperr(void) @@ -239,49 +134,6 @@ PyUFunc_clearfperr() npy_clear_floatstatus(); } - -#if USE_USE_DEFAULTS==1 -static int PyUFunc_NUM_NODEFAULTS = 0; -#endif - -static PyObject * -get_global_ext_obj(void) -{ - PyObject *thedict; - PyObject *ref = NULL; - -#if USE_USE_DEFAULTS==1 - if (PyUFunc_NUM_NODEFAULTS != 0) { -#endif - thedict = PyThreadState_GetDict(); - if (thedict == NULL) { - thedict = PyEval_GetBuiltins(); - } - ref = PyDict_GetItem(thedict, npy_um_str_pyvals_name); -#if USE_USE_DEFAULTS==1 - } -#endif - - return ref; -} - - -static int -_get_bufsize_errmask(PyObject * extobj, const char *ufunc_name, - int *buffersize, int *errormask) -{ - /* Get the buffersize and errormask */ - if (extobj == NULL) { - extobj = get_global_ext_obj(); - } - if (_extract_pyvals(extobj, ufunc_name, - buffersize, errormask, NULL) < 0) { - return -1; - } - - return 0; -} - /* * This function analyzes the input arguments * and determines an appropriate __array_prepare__ function to call @@ -426,97 +278,6 @@ _find_array_prepare(PyObject *args, PyObject *kwds, return; } -/* - * Extracts some values from the global pyvals tuple. - * all destinations may be NULL, in which case they are not retrieved - * ref - should hold the global tuple - * name - is the name of the ufunc (ufuncobj->name) - * - * bufsize - receives the buffer size to use - * errmask - receives the bitmask for error handling - * errobj - receives the python object to call with the error, - * if an error handling method is 'call' - */ -static int -_extract_pyvals(PyObject *ref, const char *name, int *bufsize, - int *errmask, PyObject **errobj) -{ - PyObject *retval; - - /* default errobj case, skips dictionary lookup */ - if (ref == NULL) { - if (errmask) { - *errmask = UFUNC_ERR_DEFAULT; - } - if (errobj) { - *errobj = Py_BuildValue("NO", PyBytes_FromString(name), Py_None); - } - if (bufsize) { - *bufsize = NPY_BUFSIZE; - } - return 0; - } - - if (!PyList_Check(ref) || (PyList_GET_SIZE(ref)!=3)) { - PyErr_Format(PyExc_TypeError, - "%s must be a length 3 list.", UFUNC_PYVALS_NAME); - return -1; - } - - if (bufsize != NULL) { - *bufsize = PyInt_AsLong(PyList_GET_ITEM(ref, 0)); - if ((*bufsize == -1) && PyErr_Occurred()) { - return -1; - } - if ((*bufsize < NPY_MIN_BUFSIZE) || - (*bufsize > NPY_MAX_BUFSIZE) || - (*bufsize % 16 != 0)) { - PyErr_Format(PyExc_ValueError, - "buffer size (%d) is not in range " - "(%"NPY_INTP_FMT" - %"NPY_INTP_FMT") or not a multiple of 16", - *bufsize, (npy_intp) NPY_MIN_BUFSIZE, - (npy_intp) NPY_MAX_BUFSIZE); - return -1; - } - } - - if (errmask != NULL) { - *errmask = PyInt_AsLong(PyList_GET_ITEM(ref, 1)); - if (*errmask < 0) { - if (PyErr_Occurred()) { - return -1; - } - PyErr_Format(PyExc_ValueError, - "invalid error mask (%d)", - *errmask); - return -1; - } - } - - if (errobj != NULL) { - *errobj = NULL; - retval = PyList_GET_ITEM(ref, 2); - if (retval != Py_None && !PyCallable_Check(retval)) { - 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", PyBytes_FromString(name), retval); - if (*errobj == NULL) { - return -1; - } - } - return 0; -} - /*UFUNC_API * @@ -1954,44 +1715,6 @@ make_arr_prep_args(npy_intp nin, PyObject *args, PyObject *kwds) } /* - * check the floating point status - * - errmask: mask of status to check - * - extobj: ufunc pyvals object - * may be null, in which case the thread global one is fetched - * - ufunc_name: name of ufunc - */ -static int -_check_ufunc_fperr(int errmask, PyObject *extobj, const char *ufunc_name) { - int fperr; - PyObject *errobj = NULL; - int ret; - int first = 1; - - if (!errmask) { - return 0; - } - fperr = PyUFunc_getfperr(); - if (!fperr) { - return 0; - } - - /* Get error object globals */ - if (extobj == NULL) { - extobj = get_global_ext_obj(); - } - if (_extract_pyvals(extobj, ufunc_name, - NULL, NULL, &errobj) < 0) { - Py_XDECREF(errobj); - return -1; - } - - ret = PyUFunc_handlefperr(errmask, errobj, fperr, &first); - Py_XDECREF(errobj); - - return ret; -} - -/* * Validate the core dimensions of all the operands, and collect all of * the labelled core dimensions into 'core_dim_sizes'. * @@ -2108,7 +1831,6 @@ _get_coredim_sizes(PyUFuncObject *ufunc, PyArrayObject **op, return 0; } - static int PyUFunc_GeneralizedFunction(PyUFuncObject *ufunc, PyObject *args, PyObject *kwds, @@ -4510,39 +4232,6 @@ ufunc_geterr(PyObject *NPY_UNUSED(dummy), PyObject *args) return res; } -#if USE_USE_DEFAULTS==1 -/* - * This is a strategy to buy a little speed up and avoid the dictionary - * look-up in the default case. It should work in the presence of - * threads. If it is deemed too complicated or it doesn't actually work - * it could be taken out. - */ -static int -ufunc_update_use_defaults(void) -{ - PyObject *errobj = NULL; - int errmask, bufsize; - int res; - - PyUFunc_NUM_NODEFAULTS += 1; - res = PyUFunc_GetPyValues("test", &bufsize, &errmask, &errobj); - PyUFunc_NUM_NODEFAULTS -= 1; - if (res < 0) { - Py_XDECREF(errobj); - return -1; - } - if ((errmask != UFUNC_ERR_DEFAULT) || (bufsize != NPY_BUFSIZE) - || (PyTuple_GET_ITEM(errobj, 1) != Py_None)) { - PyUFunc_NUM_NODEFAULTS += 1; - } - else if (PyUFunc_NUM_NODEFAULTS > 0) { - PyUFunc_NUM_NODEFAULTS -= 1; - } - Py_XDECREF(errobj); - return 0; -} -#endif - NPY_NO_EXPORT PyObject * ufunc_seterr(PyObject *NPY_UNUSED(dummy), PyObject *args) { |