1
#define _UMATHMODULE
2
#define _MULTIARRAYMODULE
3
#define NPY_NO_DEPRECATED_API NPY_API_VERSION
4

5
#include <Python.h>
6

7
#include "npy_config.h"
8

9
#include "npy_pycompat.h"
10

11
#include "extobj.h"
12
#include "numpy/ufuncobject.h"
13

14
#include "ufunc_object.h"  /* for npy_um_str_pyvals_name */
15
#include "common.h"
16

17
#if USE_USE_DEFAULTS==1
18
static int PyUFunc_NUM_NODEFAULTS = 0;
19

20
/*
21
 * This is a strategy to buy a little speed up and avoid the dictionary
22
 * look-up in the default case.  It should work in the presence of
23
 * threads.  If it is deemed too complicated or it doesn't actually work
24
 * it could be taken out.
25
 */
26
NPY_NO_EXPORT int
27 1
ufunc_update_use_defaults(void)
28
{
29 1
    PyObject *errobj = NULL;
30
    int errmask, bufsize;
31
    int res;
32

33 1
    PyUFunc_NUM_NODEFAULTS += 1;
34 1
    res = PyUFunc_GetPyValues("test", &bufsize, &errmask, &errobj);
35 1
    PyUFunc_NUM_NODEFAULTS -= 1;
36 1
    if (res < 0) {
37 0
        Py_XDECREF(errobj);
38
        return -1;
39
    }
40 1
    if ((errmask != UFUNC_ERR_DEFAULT) || (bufsize != NPY_BUFSIZE)
41 1
            || (PyTuple_GET_ITEM(errobj, 1) != Py_None)) {
42 1
        PyUFunc_NUM_NODEFAULTS += 1;
43
    }
44 1
    else if (PyUFunc_NUM_NODEFAULTS > 0) {
45 1
        PyUFunc_NUM_NODEFAULTS -= 1;
46
    }
47 1
    Py_XDECREF(errobj);
48
    return 0;
49
}
50
#endif
51

52
/*
53
 * fpstatus is the ufunc_formatted hardware status
54
 * errmask is the handling mask specified by the user.
55
 * errobj is a Python object with (string, callable object or None)
56
 * or NULL
57
 */
58

59
/*
60
 * 2. for each of the flags
61
 * determine whether to ignore, warn, raise error, or call Python function.
62
 * If ignore, do nothing
63
 * If warn, print a warning and continue
64
 * If raise return an error
65
 * If call, call a user-defined function with string
66
 */
67

68
NPY_NO_EXPORT int
69 1
_error_handler(int method, PyObject *errobj, char *errtype, int retstatus, int *first)
70
{
71
    PyObject *pyfunc, *ret, *args;
72 1
    char *name = PyBytes_AS_STRING(PyTuple_GET_ITEM(errobj,0));
73
    char msg[100];
74

75
    NPY_ALLOW_C_API_DEF
76

77
    /* don't need C API for a simple ignore */
78 1
    if (method == UFUNC_ERR_IGNORE) {
79
        return 0;
80
    }
81

82
    /* don't need C API for a simple print */
83 1
    if (method == UFUNC_ERR_PRINT) {
84 0
        if (*first) {
85 0
            fprintf(stderr, "Warning: %s encountered in %s\n", errtype, name);
86 0
            *first = 0;
87
        }
88
        return 0;
89
    }
90

91 1
    NPY_ALLOW_C_API;
92 1
    switch(method) {
93 1
    case UFUNC_ERR_WARN:
94 1
        PyOS_snprintf(msg, sizeof(msg), "%s encountered in %s", errtype, name);
95 1
        if (PyErr_Warn(PyExc_RuntimeWarning, msg) < 0) {
96
            goto fail;
97
        }
98
        break;
99 1
    case UFUNC_ERR_RAISE:
100 1
        PyErr_Format(PyExc_FloatingPointError, "%s encountered in %s",
101
                errtype, name);
102 1
        goto fail;
103 1
    case UFUNC_ERR_CALL:
104 1
        pyfunc = PyTuple_GET_ITEM(errobj, 1);
105 1
        if (pyfunc == Py_None) {
106 0
            PyErr_Format(PyExc_NameError,
107
                    "python callback specified for %s (in " \
108
                    " %s) but no function found.",
109
                    errtype, name);
110 0
            goto fail;
111
        }
112 1
        args = Py_BuildValue("NN", PyUnicode_FromString(errtype),
113
                PyLong_FromLong((long) retstatus));
114 1
        if (args == NULL) {
115
            goto fail;
116
        }
117 1
        ret = PyObject_CallObject(pyfunc, args);
118 1
        Py_DECREF(args);
119 1
        if (ret == NULL) {
120
            goto fail;
121
        }
122 1
        Py_DECREF(ret);
123
        break;
124 0
    case UFUNC_ERR_LOG:
125 0
        if (first) {
126 0
            *first = 0;
127 0
            pyfunc = PyTuple_GET_ITEM(errobj, 1);
128 0
            if (pyfunc == Py_None) {
129 0
                PyErr_Format(PyExc_NameError,
130
                        "log specified for %s (in %s) but no " \
131
                        "object with write method found.",
132
                        errtype, name);
133 0
                goto fail;
134
            }
135 0
            PyOS_snprintf(msg, sizeof(msg),
136
                    "Warning: %s encountered in %s\n", errtype, name);
137 0
            ret = PyObject_CallMethod(pyfunc, "write", "s", msg);
138 0
            if (ret == NULL) {
139
                goto fail;
140
            }
141 0
            Py_DECREF(ret);
142
        }
143
        break;
144
    }
145 1
    NPY_DISABLE_C_API;
146 1
    return 0;
147

148 1
fail:
149 1
    NPY_DISABLE_C_API;
150 1
    return -1;
151
}
152

153

154

155
NPY_NO_EXPORT PyObject *
156 1
get_global_ext_obj(void)
157
{
158
    PyObject *thedict;
159 1
    PyObject *ref = NULL;
160

161
#if USE_USE_DEFAULTS==1
162 1
    if (PyUFunc_NUM_NODEFAULTS != 0) {
163
#endif
164 1
        thedict = PyThreadState_GetDict();
165 1
        if (thedict == NULL) {
166 0
            thedict = PyEval_GetBuiltins();
167
        }
168 1
        ref = PyDict_GetItemWithError(thedict, npy_um_str_pyvals_name);
169
#if USE_USE_DEFAULTS==1
170
    }
171
#endif
172

173 1
    return ref;
174
}
175

176

177
/*
178
 * Extracts some values from the global pyvals tuple.
179
 * all destinations may be NULL, in which case they are not retrieved
180
 * ref - should hold the global tuple
181
 * name - is the name of the ufunc (ufuncobj->name)
182
 *
183
 * bufsize - receives the buffer size to use
184
 * errmask - receives the bitmask for error handling
185
 * errobj - receives the python object to call with the error,
186
 *          if an error handling method is 'call'
187
 */
188
NPY_NO_EXPORT int
189 1
_extract_pyvals(PyObject *ref, const char *name, int *bufsize,
190
                int *errmask, PyObject **errobj)
191
{
192
    PyObject *retval;
193

194
    /* default errobj case, skips dictionary lookup */
195 1
    if (ref == NULL) {
196 1
        if (errmask) {
197 1
            *errmask = UFUNC_ERR_DEFAULT;
198
        }
199 1
        if (errobj) {
200 1
            *errobj = Py_BuildValue("NO", PyBytes_FromString(name), Py_None);
201
        }
202 1
        if (bufsize) {
203 1
            *bufsize = NPY_BUFSIZE;
204
        }
205
        return 0;
206
    }
207

208 1
    if (!PyList_Check(ref) || (PyList_GET_SIZE(ref)!=3)) {
209 0
        PyErr_Format(PyExc_TypeError,
210
                "%s must be a length 3 list.", UFUNC_PYVALS_NAME);
211 0
        return -1;
212
    }
213

214 1
    if (bufsize != NULL) {
215 1
        *bufsize = PyLong_AsLong(PyList_GET_ITEM(ref, 0));
216 1
        if (error_converting(*bufsize)) {
217
            return -1;
218
        }
219 1
        if ((*bufsize < NPY_MIN_BUFSIZE) ||
220 1
                (*bufsize > NPY_MAX_BUFSIZE) ||
221 1
                (*bufsize % 16 != 0)) {
222 0
            PyErr_Format(PyExc_ValueError,
223
                    "buffer size (%d) is not in range "
224
                    "(%"NPY_INTP_FMT" - %"NPY_INTP_FMT") or not a multiple of 16",
225
                    *bufsize, (npy_intp) NPY_MIN_BUFSIZE,
226
                    (npy_intp) NPY_MAX_BUFSIZE);
227 0
            return -1;
228
        }
229
    }
230

231 1
    if (errmask != NULL) {
232 1
        *errmask = PyLong_AsLong(PyList_GET_ITEM(ref, 1));
233 1
        if (*errmask < 0) {
234 0
            if (PyErr_Occurred()) {
235
                return -1;
236
            }
237 0
            PyErr_Format(PyExc_ValueError,
238
                         "invalid error mask (%d)",
239
                         *errmask);
240 0
            return -1;
241
        }
242
    }
243

244 1
    if (errobj != NULL) {
245 1
        *errobj = NULL;
246 1
        retval = PyList_GET_ITEM(ref, 2);
247 1
        if (retval != Py_None && !PyCallable_Check(retval)) {
248
            PyObject *temp;
249 0
            temp = PyObject_GetAttrString(retval, "write");
250 0
            if (temp == NULL || !PyCallable_Check(temp)) {
251 0
                PyErr_SetString(PyExc_TypeError,
252
                                "python object must be callable or have " \
253
                                "a callable write method");
254 0
                Py_XDECREF(temp);
255
                return -1;
256
            }
257 0
            Py_DECREF(temp);
258
        }
259

260 1
        *errobj = Py_BuildValue("NO", PyBytes_FromString(name), retval);
261 1
        if (*errobj == NULL) {
262
            return -1;
263
        }
264
    }
265
    return 0;
266
}
267

268
/*
269
 * check the floating point status
270
 *  - errmask: mask of status to check
271
 *  - extobj: ufunc pyvals object
272
 *            may be null, in which case the thread global one is fetched
273
 *  - ufunc_name: name of ufunc
274
 */
275
NPY_NO_EXPORT int
276 1
_check_ufunc_fperr(int errmask, PyObject *extobj, const char *ufunc_name) {
277
    int fperr;
278 1
    PyObject *errobj = NULL;
279
    int ret;
280 1
    int first = 1;
281

282 1
    if (!errmask) {
283
        return 0;
284
    }
285 1
    fperr = npy_get_floatstatus_barrier((char*)extobj);
286 1
    if (!fperr) {
287
        return 0;
288
    }
289

290
    /* Get error object globals */
291 1
    if (extobj == NULL) {
292 1
        extobj = get_global_ext_obj();
293 1
        if (extobj == NULL && PyErr_Occurred()) {
294
            return -1;
295
        }
296
    }
297 1
    if (_extract_pyvals(extobj, ufunc_name,
298
                        NULL, NULL, &errobj) < 0) {
299 0
        Py_XDECREF(errobj);
300
        return -1;
301
    }
302

303 1
    ret = PyUFunc_handlefperr(errmask, errobj, fperr, &first);
304 1
    Py_XDECREF(errobj);
305

306
    return ret;
307
}
308

309

310
NPY_NO_EXPORT int
311 1
_get_bufsize_errmask(PyObject * extobj, const char *ufunc_name,
312
                     int *buffersize, int *errormask)
313
{
314
    /* Get the buffersize and errormask */
315 1
    if (extobj == NULL) {
316 1
        extobj = get_global_ext_obj();
317 1
        if (extobj == NULL && PyErr_Occurred()) {
318
            return -1;
319
        }
320
    }
321 1
    if (_extract_pyvals(extobj, ufunc_name,
322
                        buffersize, errormask, NULL) < 0) {
323
        return -1;
324
    }
325

326 1
    return 0;
327
}

Read our documentation on viewing source code .

Loading