Repository URL to install this package:
|
Version:
1.10.0 ▾
|
#ifndef __UFUNC_OVERRIDE_H
#define __UFUNC_OVERRIDE_H
#include <npy_config.h>
#include "numpy/arrayobject.h"
#include "common.h"
#include <string.h>
#include "numpy/ufuncobject.h"
static void
normalize___call___args(PyUFuncObject *ufunc, PyObject *args,
PyObject **normal_args, PyObject **normal_kwds,
int nin)
{
/* ufunc.__call__(*args, **kwds) */
int nargs = PyTuple_GET_SIZE(args);
PyObject *obj = PyDict_GetItemString(*normal_kwds, "sig");
/* ufuncs accept 'sig' or 'signature' normalize to 'signature' */
if (obj != NULL) {
Py_INCREF(obj);
PyDict_SetItemString(*normal_kwds, "signature", obj);
PyDict_DelItemString(*normal_kwds, "sig");
}
*normal_args = PyTuple_GetSlice(args, 0, nin);
/* If we have more args than nin, they must be the output variables.*/
if (nargs > nin) {
if ((nargs - nin) == 1) {
obj = PyTuple_GET_ITEM(args, nargs - 1);
PyDict_SetItemString(*normal_kwds, "out", obj);
}
else {
obj = PyTuple_GetSlice(args, nin, nargs);
PyDict_SetItemString(*normal_kwds, "out", obj);
Py_DECREF(obj);
}
}
}
static void
normalize_reduce_args(PyUFuncObject *ufunc, PyObject *args,
PyObject **normal_args, PyObject **normal_kwds)
{
/* ufunc.reduce(a[, axis, dtype, out, keepdims]) */
int nargs = PyTuple_GET_SIZE(args);
int i;
PyObject *obj;
for (i = 0; i < nargs; i++) {
obj = PyTuple_GET_ITEM(args, i);
if (i == 0) {
*normal_args = PyTuple_GetSlice(args, 0, 1);
}
else if (i == 1) {
/* axis */
PyDict_SetItemString(*normal_kwds, "axis", obj);
}
else if (i == 2) {
/* dtype */
PyDict_SetItemString(*normal_kwds, "dtype", obj);
}
else if (i == 3) {
/* out */
PyDict_SetItemString(*normal_kwds, "out", obj);
}
else {
/* keepdims */
PyDict_SetItemString(*normal_kwds, "keepdims", obj);
}
}
return;
}
static void
normalize_accumulate_args(PyUFuncObject *ufunc, PyObject *args,
PyObject **normal_args, PyObject **normal_kwds)
{
/* ufunc.accumulate(a[, axis, dtype, out]) */
int nargs = PyTuple_GET_SIZE(args);
int i;
PyObject *obj;
for (i = 0; i < nargs; i++) {
obj = PyTuple_GET_ITEM(args, i);
if (i == 0) {
*normal_args = PyTuple_GetSlice(args, 0, 1);
}
else if (i == 1) {
/* axis */
PyDict_SetItemString(*normal_kwds, "axis", obj);
}
else if (i == 2) {
/* dtype */
PyDict_SetItemString(*normal_kwds, "dtype", obj);
}
else {
/* out */
PyDict_SetItemString(*normal_kwds, "out", obj);
}
}
return;
}
static void
normalize_reduceat_args(PyUFuncObject *ufunc, PyObject *args,
PyObject **normal_args, PyObject **normal_kwds)
{
/* ufunc.reduceat(a, indicies[, axis, dtype, out]) */
int i;
int nargs = PyTuple_GET_SIZE(args);
PyObject *obj;
for (i = 0; i < nargs; i++) {
obj = PyTuple_GET_ITEM(args, i);
if (i == 0) {
/* a and indicies */
*normal_args = PyTuple_GetSlice(args, 0, 2);
}
else if (i == 1) {
/* Handled above, when i == 0. */
continue;
}
else if (i == 2) {
/* axis */
PyDict_SetItemString(*normal_kwds, "axis", obj);
}
else if (i == 3) {
/* dtype */
PyDict_SetItemString(*normal_kwds, "dtype", obj);
}
else {
/* out */
PyDict_SetItemString(*normal_kwds, "out", obj);
}
}
return;
}
static void
normalize_outer_args(PyUFuncObject *ufunc, PyObject *args,
PyObject **normal_args, PyObject **normal_kwds)
{
/* ufunc.outer(A, B)
* This has no kwds so we don't need to do any kwd stuff.
*/
*normal_args = PyTuple_GetSlice(args, 0, 2);
return;
}
static void
normalize_at_args(PyUFuncObject *ufunc, PyObject *args,
PyObject **normal_args, PyObject **normal_kwds)
{
/* ufunc.at(a, indices[, b]) */
int nargs = PyTuple_GET_SIZE(args);
*normal_args = PyTuple_GetSlice(args, 0, nargs);
return;
}
/*
* Check a set of args for the `__numpy_ufunc__` method. If more than one of
* the input arguments implements `__numpy_ufunc__`, they are tried in the
* order: subclasses before superclasses, otherwise left to right. The first
* routine returning something other than `NotImplemented` determines the
* result. If all of the `__numpy_ufunc__` operations returns `NotImplemented`,
* a `TypeError` is raised.
*
* Returns 0 on success and 1 on exception. On success, *result contains the
* result of the operation, if any. If *result is NULL, there is no override.
*/
static int
PyUFunc_CheckOverride(PyUFuncObject *ufunc, char *method,
PyObject *args, PyObject *kwds,
PyObject **result,
int nin)
{
int i;
int override_pos; /* Position of override in args.*/
int j;
int nargs = PyTuple_GET_SIZE(args);
int noa = 0; /* Number of overriding args.*/
PyObject *obj;
PyObject *other_obj;
PyObject *method_name = NULL;
PyObject *normal_args = NULL; /* normal_* holds normalized arguments. */
PyObject *normal_kwds = NULL;
PyObject *with_override[NPY_MAXARGS];
/* Pos of each override in args */
int with_override_pos[NPY_MAXARGS];
/****************************************************************
* Temporarily disable this functionality for the 1.10 release.
* See gh-5844.
****************************************************************/
*result = NULL;
return 0;
/****************************************************************
* Actual implementation follows:
****************************************************************/
/* disabled until remaining issues are fixed */
*result = NULL;
return 0;
/*
* Check inputs
*/
if (!PyTuple_Check(args)) {
PyErr_SetString(PyExc_ValueError,
"Internal Numpy error: call to PyUFunc_CheckOverride "
"with non-tuple");
goto fail;
}
if (PyTuple_GET_SIZE(args) > NPY_MAXARGS) {
PyErr_SetString(PyExc_ValueError,
"Internal Numpy error: too many arguments in call "
"to PyUFunc_CheckOverride");
goto fail;
}
for (i = 0; i < nargs; ++i) {
obj = PyTuple_GET_ITEM(args, i);
/*
* TODO: could use PyArray_GetAttrString_SuppressException if it
* weren't private to multiarray.so
*/
if (PyArray_CheckExact(obj) || PyArray_IsScalar(obj, Generic) ||
_is_basic_python_type(obj)) {
continue;
}
if (PyObject_HasAttrString(obj, "__numpy_ufunc__")) {
with_override[noa] = obj;
with_override_pos[noa] = i;
++noa;
}
}
/* No overrides, bail out.*/
if (noa == 0) {
*result = NULL;
return 0;
}
method_name = PyUString_FromString(method);
if (method_name == NULL) {
goto fail;
}
/*
* Normalize ufunc arguments.
*/
/* Build new kwds */
if (kwds && PyDict_CheckExact(kwds)) {
normal_kwds = PyDict_Copy(kwds);
}
else {
normal_kwds = PyDict_New();
}
if (normal_kwds == NULL) {
goto fail;
}
/* decide what to do based on the method. */
/* ufunc.__call__ */
if (strcmp(method, "__call__") == 0) {
normalize___call___args(ufunc, args, &normal_args, &normal_kwds, nin);
}
/* ufunc.reduce */
else if (strcmp(method, "reduce") == 0) {
normalize_reduce_args(ufunc, args, &normal_args, &normal_kwds);
}
/* ufunc.accumulate */
else if (strcmp(method, "accumulate") == 0) {
normalize_accumulate_args(ufunc, args, &normal_args, &normal_kwds);
}
/* ufunc.reduceat */
else if (strcmp(method, "reduceat") == 0) {
normalize_reduceat_args(ufunc, args, &normal_args, &normal_kwds);
}
/* ufunc.outer */
else if (strcmp(method, "outer") == 0) {
normalize_outer_args(ufunc, args, &normal_args, &normal_kwds);
}
/* ufunc.at */
else if (strcmp(method, "at") == 0) {
normalize_at_args(ufunc, args, &normal_args, &normal_kwds);
}
if (normal_args == NULL) {
goto fail;
}
/*
* Call __numpy_ufunc__ functions in correct order
*/
while (1) {
PyObject *numpy_ufunc;
PyObject *override_args;
PyObject *override_obj;
override_obj = NULL;
*result = NULL;
/* Choose an overriding argument */
for (i = 0; i < noa; i++) {
obj = with_override[i];
if (obj == NULL) {
continue;
}
/* Get the first instance of an overriding arg.*/
override_pos = with_override_pos[i];
override_obj = obj;
/* Check for sub-types to the right of obj. */
for (j = i + 1; j < noa; j++) {
other_obj = with_override[j];
if (PyObject_Type(other_obj) != PyObject_Type(obj) &&
PyObject_IsInstance(other_obj,
PyObject_Type(override_obj))) {
override_obj = NULL;
break;
}
}
/* override_obj had no subtypes to the right. */
if (override_obj) {
with_override[i] = NULL; /* We won't call this one again */
break;
}
}
/* Check if there is a method left to call */
if (!override_obj) {
/* No acceptable override found. */
PyErr_SetString(PyExc_TypeError,
"__numpy_ufunc__ not implemented for this type.");
goto fail;
}
/* Call the override */
numpy_ufunc = PyObject_GetAttrString(override_obj,
"__numpy_ufunc__");
if (numpy_ufunc == NULL) {
goto fail;
}
override_args = Py_BuildValue("OOiO", ufunc, method_name,
override_pos, normal_args);
if (override_args == NULL) {
Py_DECREF(numpy_ufunc);
goto fail;
}
*result = PyObject_Call(numpy_ufunc, override_args, normal_kwds);
Py_DECREF(numpy_ufunc);
Py_DECREF(override_args);
if (*result == NULL) {
/* Exception occurred */
goto fail;
}
else if (*result == Py_NotImplemented) {
/* Try the next one */
Py_DECREF(*result);
continue;
}
else {
/* Good result. */
break;
}
}
/* Override found, return it. */
Py_XDECREF(method_name);
Py_XDECREF(normal_args);
Py_XDECREF(normal_kwds);
return 0;
fail:
Py_XDECREF(method_name);
Py_XDECREF(normal_args);
Py_XDECREF(normal_kwds);
return 1;
}
#endif