| File: | numpy/core/src/multiarray/arrayfunction_override.c | 
| Warning: | line 407, column 16 PyObject ownership leak with reference count of 1  | 
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
| 1 | #define NPY_NO_DEPRECATED_API0x0000000E NPY_API_VERSION0x0000000E | ||||
| 2 | #define _MULTIARRAYMODULE | ||||
| 3 | |||||
| 4 | #include "npy_pycompat.h" | ||||
| 5 | #include "get_attr_string.h" | ||||
| 6 | #include "npy_import.h" | ||||
| 7 | #include "multiarraymodule.h" | ||||
| 8 | |||||
| 9 | |||||
| 10 | /* Return the ndarray.__array_function__ method. */ | ||||
| 11 | static PyObject * | ||||
| 12 | get_ndarray_array_function(void) | ||||
| 13 | { | ||||
| 14 | PyObject* method = PyObject_GetAttrString((PyObject *)&PyArray_Type, | ||||
| 15 | "__array_function__"); | ||||
| 16 | assert(method != NULL)((void) (0)); | ||||
| 17 | return method; | ||||
| 18 | } | ||||
| 19 | |||||
| 20 | |||||
| 21 | /* | ||||
| 22 | * Get an object's __array_function__ method in the fastest way possible. | ||||
| 23 | * Never raises an exception. Returns NULL if the method doesn't exist. | ||||
| 24 | */ | ||||
| 25 | static PyObject * | ||||
| 26 | get_array_function(PyObject *obj) | ||||
| 27 | { | ||||
| 28 | static PyObject *ndarray_array_function = NULL((void*)0); | ||||
| 29 | |||||
| 30 | if (ndarray_array_function == NULL((void*)0)) { | ||||
| 31 | ndarray_array_function = get_ndarray_array_function(); | ||||
| 32 | } | ||||
| 33 | |||||
| 34 | /* Fast return for ndarray */ | ||||
| 35 | if (PyArray_CheckExact(obj)(((PyObject*)(obj))->ob_type == &PyArray_Type)) { | ||||
| 36 | Py_INCREF(ndarray_array_function)_Py_INCREF(((PyObject*)(ndarray_array_function))); | ||||
| 37 | return ndarray_array_function; | ||||
| 38 | } | ||||
| 39 | |||||
| 40 | PyObject *array_function = PyArray_LookupSpecial(obj, "__array_function__"); | ||||
| 41 | if (array_function == NULL((void*)0) && PyErr_Occurred()) { | ||||
| 42 | PyErr_Clear(); /* TODO[gh-14801]: propagate crashes during attribute access? */ | ||||
| 43 | } | ||||
| 44 | |||||
| 45 | return array_function; | ||||
| 46 | } | ||||
| 47 | |||||
| 48 | |||||
| 49 | /* | ||||
| 50 | * Like list.insert(), but for C arrays of PyObject*. Skips error checking. | ||||
| 51 | */ | ||||
| 52 | static void | ||||
| 53 | pyobject_array_insert(PyObject **array, int length, int index, PyObject *item) | ||||
| 54 | { | ||||
| 55 | for (int j = length; j > index; j--) { | ||||
| 56 | array[j] = array[j - 1]; | ||||
| 57 | } | ||||
| 58 | array[index] = item; | ||||
| 59 | } | ||||
| 60 | |||||
| 61 | |||||
| 62 | /* | ||||
| 63 | * Collects arguments with __array_function__ and their corresponding methods | ||||
| 64 | * in the order in which they should be tried (i.e., skipping redundant types). | ||||
| 65 | * `relevant_args` is expected to have been produced by PySequence_Fast. | ||||
| 66 | * Returns the number of arguments, or -1 on failure. | ||||
| 67 | */ | ||||
| 68 | static int | ||||
| 69 | get_implementing_args_and_methods(PyObject *relevant_args, | ||||
| 70 | PyObject **implementing_args, | ||||
| 71 | PyObject **methods) | ||||
| 72 | { | ||||
| 73 | int num_implementing_args = 0; | ||||
| 74 | |||||
| 75 |     PyObject **items = PySequence_Fast_ITEMS(relevant_args)(((((((PyObject*)(relevant_args))->ob_type))->tp_flags & ((1UL << 25))) != 0) ? ((PyListObject *)(relevant_args ))->ob_item : ((PyTupleObject *)(relevant_args))->ob_item );  | ||||
| 76 |     Py_ssize_t length = PySequence_Fast_GET_SIZE(relevant_args)(((((((PyObject*)(relevant_args))->ob_type))->tp_flags & ((1UL << 25))) != 0) ? (((void) (0)), (((PyVarObject*) (relevant_args))->ob_size)) : (((PyVarObject*)((((void) (0 )), (PyTupleObject *)(relevant_args))))->ob_size));  | ||||
| 77 | |||||
| 78 | for (Py_ssize_t i = 0; i < length; i++) { | ||||
| 79 | int new_class = 1; | ||||
| 80 | PyObject *argument = items[i]; | ||||
| 81 | |||||
| 82 | /* Have we seen this type before? */ | ||||
| 83 | for (int j = 0; j < num_implementing_args; j++) { | ||||
| 84 | if (Py_TYPE(argument)(((PyObject*)(argument))->ob_type) == Py_TYPE(implementing_args[j])(((PyObject*)(implementing_args[j]))->ob_type)) { | ||||
| 85 | new_class = 0; | ||||
| 86 | break; | ||||
| 87 | } | ||||
| 88 | } | ||||
| 89 | if (new_class) { | ||||
| 90 | PyObject *method = get_array_function(argument); | ||||
| 91 | |||||
| 92 | if (method != NULL((void*)0)) { | ||||
| 93 | int arg_index; | ||||
| 94 | |||||
| 95 | if (num_implementing_args >= NPY_MAXARGS32) { | ||||
| 96 | PyErr_Format( | ||||
| 97 | PyExc_TypeError, | ||||
| 98 | "maximum number (%d) of distinct argument types " \ | ||||
| 99 | "implementing __array_function__ exceeded", | ||||
| 100 | NPY_MAXARGS32); | ||||
| 101 | Py_DECREF(method)_Py_DECREF(((PyObject*)(method))); | ||||
| 102 | goto fail; | ||||
| 103 | } | ||||
| 104 | |||||
| 105 | /* "subclasses before superclasses, otherwise left to right" */ | ||||
| 106 | arg_index = num_implementing_args; | ||||
| 107 | for (int j = 0; j < num_implementing_args; j++) { | ||||
| 108 | PyObject *other_type; | ||||
| 109 | other_type = (PyObject *)Py_TYPE(implementing_args[j])(((PyObject*)(implementing_args[j]))->ob_type); | ||||
| 110 | if (PyObject_IsInstance(argument, other_type)) { | ||||
| 111 | arg_index = j; | ||||
| 112 | break; | ||||
| 113 | } | ||||
| 114 | } | ||||
| 115 | Py_INCREF(argument)_Py_INCREF(((PyObject*)(argument))); | ||||
| 116 | pyobject_array_insert(implementing_args, num_implementing_args, | ||||
| 117 | arg_index, argument); | ||||
| 118 | pyobject_array_insert(methods, num_implementing_args, | ||||
| 119 | arg_index, method); | ||||
| 120 | ++num_implementing_args; | ||||
| 121 | } | ||||
| 122 | } | ||||
| 123 | } | ||||
| 124 | return num_implementing_args; | ||||
| 125 | |||||
| 126 | fail: | ||||
| 127 | for (int j = 0; j < num_implementing_args; j++) { | ||||
| 128 | Py_DECREF(implementing_args[j])_Py_DECREF(((PyObject*)(implementing_args[j]))); | ||||
| 129 | Py_DECREF(methods[j])_Py_DECREF(((PyObject*)(methods[j]))); | ||||
| 130 | } | ||||
| 131 | return -1; | ||||
| 132 | } | ||||
| 133 | |||||
| 134 | |||||
| 135 | /* | ||||
| 136 | * Is this object ndarray.__array_function__? | ||||
| 137 | */ | ||||
| 138 | static int | ||||
| 139 | is_default_array_function(PyObject *obj) | ||||
| 140 | { | ||||
| 141 | static PyObject *ndarray_array_function = NULL((void*)0); | ||||
| 142 | |||||
| 143 | if (ndarray_array_function == NULL((void*)0)) { | ||||
| 144 | ndarray_array_function = get_ndarray_array_function(); | ||||
| 145 | } | ||||
| 146 | return obj == ndarray_array_function; | ||||
| 147 | } | ||||
| 148 | |||||
| 149 | |||||
| 150 | /* | ||||
| 151 | * Core implementation of ndarray.__array_function__. This is exposed | ||||
| 152 | * separately so we can avoid the overhead of a Python method call from | ||||
| 153 | * within `implement_array_function`. | ||||
| 154 | */ | ||||
| 155 | NPY_NO_EXPORT__attribute__((visibility("hidden"))) PyObject * | ||||
| 156 | array_function_method_impl(PyObject *func, PyObject *types, PyObject *args, | ||||
| 157 | PyObject *kwargs) | ||||
| 158 | { | ||||
| 159 |     PyObject **items = PySequence_Fast_ITEMS(types)(((((((PyObject*)(types))->ob_type))->tp_flags & (( 1UL << 25))) != 0) ? ((PyListObject *)(types))->ob_item : ((PyTupleObject *)(types))->ob_item);  | ||||
| 160 |     Py_ssize_t length = PySequence_Fast_GET_SIZE(types)(((((((PyObject*)(types))->ob_type))->tp_flags & (( 1UL << 25))) != 0) ? (((void) (0)), (((PyVarObject*)(types ))->ob_size)) : (((PyVarObject*)((((void) (0)), (PyTupleObject *)(types))))->ob_size));  | ||||
| 161 | |||||
| 162 | for (Py_ssize_t j = 0; j < length; j++) { | ||||
| 163 | int is_subclass = PyObject_IsSubclass( | ||||
| 164 | items[j], (PyObject *)&PyArray_Type); | ||||
| 165 | if (is_subclass == -1) { | ||||
| 166 | return NULL((void*)0); | ||||
| 167 | } | ||||
| 168 | if (!is_subclass) { | ||||
| 169 | Py_INCREF(Py_NotImplemented)_Py_INCREF(((PyObject*)((&_Py_NotImplementedStruct)))); | ||||
| 170 | return Py_NotImplemented(&_Py_NotImplementedStruct); | ||||
| 171 | } | ||||
| 172 | } | ||||
| 173 | |||||
| 174 | PyObject *implementation = PyObject_GetAttr(func, npy_ma_str_implementation); | ||||
| 175 | if (implementation == NULL((void*)0)) { | ||||
| 176 | return NULL((void*)0); | ||||
| 177 | } | ||||
| 178 | PyObject *result = PyObject_Call(implementation, args, kwargs); | ||||
| 179 | Py_DECREF(implementation)_Py_DECREF(((PyObject*)(implementation))); | ||||
| 180 | return result; | ||||
| 181 | } | ||||
| 182 | |||||
| 183 | |||||
| 184 | /* | ||||
| 185 | * Calls __array_function__ on the provided argument, with a fast-path for | ||||
| 186 | * ndarray. | ||||
| 187 | */ | ||||
| 188 | static PyObject * | ||||
| 189 | call_array_function(PyObject* argument, PyObject* method, | ||||
| 190 | PyObject* public_api, PyObject* types, | ||||
| 191 | PyObject* args, PyObject* kwargs) | ||||
| 192 | { | ||||
| 193 | if (is_default_array_function(method)) { | ||||
| 194 | return array_function_method_impl(public_api, types, args, kwargs); | ||||
| 195 | } | ||||
| 196 | else { | ||||
| 197 | return PyObject_CallFunctionObjArgs( | ||||
| 198 | method, argument, public_api, types, args, kwargs, NULL((void*)0)); | ||||
| 199 | } | ||||
| 200 | } | ||||
| 201 | |||||
| 202 | |||||
| 203 | /** | ||||
| 204 | * Internal handler for the array-function dispatching. The helper returns | ||||
| 205 | * either the result, or NotImplemented (as a borrowed reference). | ||||
| 206 | * | ||||
| 207 | * @param public_api The public API symbol used for dispatching | ||||
| 208 | * @param relevant_args Arguments which may implement __array_function__ | ||||
| 209 | * @param args Original arguments | ||||
| 210 | * @param kwargs Original keyword arguments | ||||
| 211 | * | ||||
| 212 | * @returns The result of the dispatched version, or a borrowed reference | ||||
| 213 | * to NotImplemented to indicate the default implementation should | ||||
| 214 | * be used. | ||||
| 215 | */ | ||||
| 216 | static PyObject * | ||||
| 217 | array_implement_array_function_internal( | ||||
| 218 | PyObject *public_api, PyObject *relevant_args, | ||||
| 219 | PyObject *args, PyObject *kwargs) | ||||
| 220 | { | ||||
| 221 | PyObject *implementing_args[NPY_MAXARGS32]; | ||||
| 222 | PyObject *array_function_methods[NPY_MAXARGS32]; | ||||
| 223 | PyObject *types = NULL((void*)0); | ||||
| 224 | |||||
| 225 | PyObject *result = NULL((void*)0); | ||||
| 226 | |||||
| 227 | static PyObject *errmsg_formatter = NULL((void*)0); | ||||
| 228 | |||||
| 229 | relevant_args = PySequence_Fast( | ||||
| 230 | relevant_args, | ||||
| 231 | "dispatcher for __array_function__ did not return an iterable"); | ||||
| 232 | if (relevant_args == NULL((void*)0)) { | ||||
| 233 | return NULL((void*)0); | ||||
| 234 | } | ||||
| 235 | |||||
| 236 | /* Collect __array_function__ implementations */ | ||||
| 237 | int num_implementing_args = get_implementing_args_and_methods( | ||||
| 238 | relevant_args, implementing_args, array_function_methods); | ||||
| 239 | if (num_implementing_args == -1) { | ||||
| 240 | goto cleanup; | ||||
| 241 | } | ||||
| 242 | |||||
| 243 | /* | ||||
| 244 | * Handle the typical case of no overrides. This is merely an optimization | ||||
| 245 | * if some arguments are ndarray objects, but is also necessary if no | ||||
| 246 | * arguments implement __array_function__ at all (e.g., if they are all | ||||
| 247 | * built-in types). | ||||
| 248 | */ | ||||
| 249 | int any_overrides = 0; | ||||
| 250 | for (int j = 0; j < num_implementing_args; j++) { | ||||
| 251 | if (!is_default_array_function(array_function_methods[j])) { | ||||
| 252 | any_overrides = 1; | ||||
| 253 | break; | ||||
| 254 | } | ||||
| 255 | } | ||||
| 256 | if (!any_overrides) { | ||||
| 257 | /* | ||||
| 258 | * When the default implementation should be called, return | ||||
| 259 | * `Py_NotImplemented` to indicate this. | ||||
| 260 | */ | ||||
| 261 | result = Py_NotImplemented(&_Py_NotImplementedStruct); | ||||
| 262 | goto cleanup; | ||||
| 263 | } | ||||
| 264 | |||||
| 265 | /* | ||||
| 266 | * Create a Python object for types. | ||||
| 267 | * We use a tuple, because it's the fastest Python collection to create | ||||
| 268 | * and has the bonus of being immutable. | ||||
| 269 | */ | ||||
| 270 | types = PyTuple_New(num_implementing_args); | ||||
| 271 | if (types == NULL((void*)0)) { | ||||
| 272 | goto cleanup; | ||||
| 273 | } | ||||
| 274 | for (int j = 0; j < num_implementing_args; j++) { | ||||
| 275 | PyObject *arg_type = (PyObject *)Py_TYPE(implementing_args[j])(((PyObject*)(implementing_args[j]))->ob_type); | ||||
| 276 | Py_INCREF(arg_type)_Py_INCREF(((PyObject*)(arg_type))); | ||||
| 277 | PyTuple_SET_ITEM(types, j, arg_type)PyTuple_SetItem(types, j, arg_type); | ||||
| 278 | } | ||||
| 279 | |||||
| 280 | /* Call __array_function__ methods */ | ||||
| 281 | for (int j = 0; j < num_implementing_args; j++) { | ||||
| 282 | PyObject *argument = implementing_args[j]; | ||||
| 283 | PyObject *method = array_function_methods[j]; | ||||
| 284 | |||||
| 285 | /* | ||||
| 286 | * We use `public_api` instead of `implementation` here so | ||||
| 287 | * __array_function__ implementations can do equality/identity | ||||
| 288 | * comparisons. | ||||
| 289 | */ | ||||
| 290 | result = call_array_function( | ||||
| 291 | argument, method, public_api, types, args, kwargs); | ||||
| 292 | |||||
| 293 | if (result == Py_NotImplemented(&_Py_NotImplementedStruct)) { | ||||
| 294 | /* Try the next one */ | ||||
| 295 | Py_DECREF(result)_Py_DECREF(((PyObject*)(result))); | ||||
| 296 | result = NULL((void*)0); | ||||
| 297 | } | ||||
| 298 | else { | ||||
| 299 | /* Either a good result, or an exception was raised. */ | ||||
| 300 | goto cleanup; | ||||
| 301 | } | ||||
| 302 | } | ||||
| 303 | |||||
| 304 | /* No acceptable override found, raise TypeError. */ | ||||
| 305 | npy_cache_import("numpy.core._internal", | ||||
| 306 | "array_function_errmsg_formatter", | ||||
| 307 | &errmsg_formatter); | ||||
| 308 | if (errmsg_formatter != NULL((void*)0)) { | ||||
| 309 | PyObject *errmsg = PyObject_CallFunctionObjArgs( | ||||
| 310 | errmsg_formatter, public_api, types, NULL((void*)0)); | ||||
| 311 | if (errmsg != NULL((void*)0)) { | ||||
| 312 | PyErr_SetObject(PyExc_TypeError, errmsg); | ||||
| 313 | Py_DECREF(errmsg)_Py_DECREF(((PyObject*)(errmsg))); | ||||
| 314 | } | ||||
| 315 | } | ||||
| 316 | |||||
| 317 | cleanup: | ||||
| 318 | for (int j = 0; j < num_implementing_args; j++) { | ||||
| 319 | Py_DECREF(implementing_args[j])_Py_DECREF(((PyObject*)(implementing_args[j]))); | ||||
| 320 | Py_DECREF(array_function_methods[j])_Py_DECREF(((PyObject*)(array_function_methods[j]))); | ||||
| 321 | } | ||||
| 322 | Py_XDECREF(types)_Py_XDECREF(((PyObject*)(types))); | ||||
| 323 | Py_DECREF(relevant_args)_Py_DECREF(((PyObject*)(relevant_args))); | ||||
| 324 | return result; | ||||
| 325 | } | ||||
| 326 | |||||
| 327 | |||||
| 328 | /* | ||||
| 329 | * Implements the __array_function__ protocol for a Python function, as described in | ||||
| 330 | * in NEP-18. See numpy.core.overrides for a full docstring. | ||||
| 331 | */ | ||||
| 332 | NPY_NO_EXPORT__attribute__((visibility("hidden"))) PyObject * | ||||
| 333 | array_implement_array_function( | ||||
| 334 | PyObject *NPY_UNUSED(dummy)(__NPY_UNUSED_TAGGEDdummy) __attribute__ ((__unused__)), PyObject *positional_args) | ||||
| 335 | { | ||||
| 336 | PyObject *implementation, *public_api, *relevant_args, *args, *kwargs; | ||||
| 337 | |||||
| 338 | if (!PyArg_UnpackTuple( | ||||
| 339 | positional_args, "implement_array_function", 5, 5, | ||||
| 340 | &implementation, &public_api, &relevant_args, &args, &kwargs)) { | ||||
| 341 | return NULL((void*)0); | ||||
| 342 | } | ||||
| 343 | |||||
| 344 | /* | ||||
| 345 | * Remove `like=` kwarg, which is NumPy-exclusive and thus not present | ||||
| 346 | * in downstream libraries. If `like=` is specified but doesn't | ||||
| 347 | * implement `__array_function__`, raise a `TypeError`. | ||||
| 348 | */ | ||||
| 349 | if (kwargs != NULL((void*)0) && PyDict_Contains(kwargs, npy_ma_str_like)) { | ||||
| 350 | PyObject *like_arg = PyDict_GetItem(kwargs, npy_ma_str_like); | ||||
| 351 | if (like_arg != NULL((void*)0)) { | ||||
| 352 | PyObject *tmp_has_override = get_array_function(like_arg); | ||||
| 353 | if (tmp_has_override == NULL((void*)0)) { | ||||
| 354 | return PyErr_Format(PyExc_TypeError, | ||||
| 355 | "The `like` argument must be an array-like that " | ||||
| 356 | "implements the `__array_function__` protocol."); | ||||
| 357 | } | ||||
| 358 | Py_DECREF(tmp_has_override)_Py_DECREF(((PyObject*)(tmp_has_override))); | ||||
| 359 | PyDict_DelItem(kwargs, npy_ma_str_like); | ||||
| 360 | } | ||||
| 361 | } | ||||
| 362 | |||||
| 363 | PyObject *res = array_implement_array_function_internal( | ||||
| 364 | public_api, relevant_args, args, kwargs); | ||||
| 365 | |||||
| 366 | if (res == Py_NotImplemented(&_Py_NotImplementedStruct)) { | ||||
| 367 | return PyObject_Call(implementation, args, kwargs); | ||||
| 368 | } | ||||
| 369 | return res; | ||||
| 370 | } | ||||
| 371 | |||||
| 372 | /* | ||||
| 373 | * Implements the __array_function__ protocol for C array creation functions | ||||
| 374 | * only. Added as an extension to NEP-18 in an effort to bring NEP-35 to | ||||
| 375 | * life with minimal dispatch overhead. | ||||
| 376 | * | ||||
| 377 | * The caller must ensure that `like != NULL`. | ||||
| 378 | */ | ||||
| 379 | NPY_NO_EXPORT__attribute__((visibility("hidden"))) PyObject * | ||||
| 380 | array_implement_c_array_function_creation( | ||||
| 381 | const char *function_name, PyObject *like, | ||||
| 382 | PyObject *args, PyObject *kwargs, | ||||
| 383 | PyObject *const *fast_args, Py_ssize_t len_args, PyObject *kwnames) | ||||
| 384 | { | ||||
| 385 | PyObject *relevant_args = NULL((void*)0); | ||||
| 386 | PyObject *numpy_module = NULL((void*)0); | ||||
| 387 | PyObject *public_api = NULL((void*)0); | ||||
| 388 | PyObject *result = NULL((void*)0); | ||||
| 389 | |||||
| 390 | /* If `like` doesn't implement `__array_function__`, raise a `TypeError` */ | ||||
| 391 | PyObject *tmp_has_override = get_array_function(like); | ||||
| 392 |     if (tmp_has_override
 
  | ||||
  | |||||
| 393 | return PyErr_Format(PyExc_TypeError, | ||||
| 394 | "The `like` argument must be an array-like that " | ||||
| 395 | "implements the `__array_function__` protocol."); | ||||
| 396 | } | ||||
| 397 | Py_DECREF(tmp_has_override)_Py_DECREF(((PyObject*)(tmp_has_override))); | ||||
| 398 | |||||
| 399 | if (fast_args != NULL((void*)0)) { | ||||
| 400 | /* | ||||
| 401 | * Convert from vectorcall convention, since the protocol requires | ||||
| 402 | * the normal convention. We have to do this late to ensure the | ||||
| 403 | * normal path where NotImplemented is returned is fast. | ||||
| 404 | */ | ||||
| 405 | assert(args == NULL)((void) (0)); | ||||
| 406 | assert(kwargs == NULL)((void) (0)); | ||||
| 407 | args = PyTuple_New(len_args); | ||||
  | |||||
| 408 | if (args == NULL((void*)0)) { | ||||
| 409 | return NULL((void*)0); | ||||
| 410 | } | ||||
| 411 | for (Py_ssize_t i = 0; i < len_args; i++) { | ||||
| 412 | Py_INCREF(fast_args[i])_Py_INCREF(((PyObject*)(fast_args[i]))); | ||||
| 413 | PyTuple_SET_ITEM(args, i, fast_args[i])PyTuple_SetItem(args, i, fast_args[i]); | ||||
| 414 | } | ||||
| 415 | if (kwnames != NULL((void*)0)) { | ||||
| 416 | kwargs = PyDict_New(); | ||||
| 417 | if (kwargs == NULL((void*)0)) { | ||||
| 418 | Py_DECREF(args)_Py_DECREF(((PyObject*)(args))); | ||||
| 419 | return NULL((void*)0); | ||||
| 420 | } | ||||
| 421 |             Py_ssize_t nkwargs = PyTuple_GET_SIZE(kwnames)(((PyVarObject*)((((void) (0)), (PyTupleObject *)(kwnames)))) ->ob_size);  | ||||
| 422 | for (Py_ssize_t i = 0; i < nkwargs; i++) { | ||||
| 423 | PyObject *key = PyTuple_GET_ITEM(kwnames, i)((((void) (0)), (PyTupleObject *)(kwnames))->ob_item[i]); | ||||
| 424 | PyObject *value = fast_args[i+len_args]; | ||||
| 425 | if (PyDict_SetItem(kwargs, key, value) < 0) { | ||||
| 426 | Py_DECREF(args)_Py_DECREF(((PyObject*)(args))); | ||||
| 427 | Py_DECREF(kwargs)_Py_DECREF(((PyObject*)(kwargs))); | ||||
| 428 | return NULL((void*)0); | ||||
| 429 | } | ||||
| 430 | } | ||||
| 431 | } | ||||
| 432 | } | ||||
| 433 | |||||
| 434 | relevant_args = PyTuple_Pack(1, like); | ||||
| 435 | if (relevant_args == NULL((void*)0)) { | ||||
| 436 | goto finish; | ||||
| 437 | } | ||||
| 438 | /* The like argument must be present in the keyword arguments, remove it */ | ||||
| 439 | if (PyDict_DelItem(kwargs, npy_ma_str_like) < 0) { | ||||
| 440 | goto finish; | ||||
| 441 | } | ||||
| 442 | |||||
| 443 | numpy_module = PyImport_Import(npy_ma_str_numpy); | ||||
| 444 | if (numpy_module == NULL((void*)0)) { | ||||
| 445 | goto finish; | ||||
| 446 | } | ||||
| 447 | |||||
| 448 | public_api = PyObject_GetAttrString(numpy_module, function_name); | ||||
| 449 | Py_DECREF(numpy_module)_Py_DECREF(((PyObject*)(numpy_module))); | ||||
| 450 | if (public_api == NULL((void*)0)) { | ||||
| 451 | goto finish; | ||||
| 452 | } | ||||
| 453 | if (!PyCallable_Check(public_api)) { | ||||
| 454 | PyErr_Format(PyExc_RuntimeError, | ||||
| 455 | "numpy.%s is not callable.", function_name); | ||||
| 456 | goto finish; | ||||
| 457 | } | ||||
| 458 | |||||
| 459 | result = array_implement_array_function_internal( | ||||
| 460 | public_api, relevant_args, args, kwargs); | ||||
| 461 | |||||
| 462 | finish: | ||||
| 463 |     if (kwnames
 
  | ||||
| 464 | /* args and kwargs were converted from vectorcall convention */ | ||||
| 465 | Py_XDECREF(args)_Py_XDECREF(((PyObject*)(args))); | ||||
| 466 | Py_XDECREF(kwargs)_Py_XDECREF(((PyObject*)(kwargs))); | ||||
| 467 | } | ||||
| 468 | Py_XDECREF(relevant_args)_Py_XDECREF(((PyObject*)(relevant_args))); | ||||
| 469 | Py_XDECREF(public_api)_Py_XDECREF(((PyObject*)(public_api))); | ||||
| 470 | return result; | ||||
| 471 | } | ||||
| 472 | |||||
| 473 | |||||
| 474 | /* | ||||
| 475 | * Python wrapper for get_implementing_args_and_methods, for testing purposes. | ||||
| 476 | */ | ||||
| 477 | NPY_NO_EXPORT__attribute__((visibility("hidden"))) PyObject * | ||||
| 478 | array__get_implementing_args( | ||||
| 479 | PyObject *NPY_UNUSED(dummy)(__NPY_UNUSED_TAGGEDdummy) __attribute__ ((__unused__)), PyObject *positional_args) | ||||
| 480 | { | ||||
| 481 | PyObject *relevant_args; | ||||
| 482 | PyObject *implementing_args[NPY_MAXARGS32]; | ||||
| 483 | PyObject *array_function_methods[NPY_MAXARGS32]; | ||||
| 484 | PyObject *result = NULL((void*)0); | ||||
| 485 | |||||
| 486 | if (!PyArg_ParseTuple(positional_args, "O:array__get_implementing_args", | ||||
| 487 | &relevant_args)) { | ||||
| 488 | return NULL((void*)0); | ||||
| 489 | } | ||||
| 490 | |||||
| 491 | relevant_args = PySequence_Fast( | ||||
| 492 | relevant_args, | ||||
| 493 | "dispatcher for __array_function__ did not return an iterable"); | ||||
| 494 | if (relevant_args == NULL((void*)0)) { | ||||
| 495 | return NULL((void*)0); | ||||
| 496 | } | ||||
| 497 | |||||
| 498 | int num_implementing_args = get_implementing_args_and_methods( | ||||
| 499 | relevant_args, implementing_args, array_function_methods); | ||||
| 500 | if (num_implementing_args == -1) { | ||||
| 501 | goto cleanup; | ||||
| 502 | } | ||||
| 503 | |||||
| 504 | /* create a Python object for implementing_args */ | ||||
| 505 | result = PyList_New(num_implementing_args); | ||||
| 506 | if (result == NULL((void*)0)) { | ||||
| 507 | goto cleanup; | ||||
| 508 | } | ||||
| 509 | for (int j = 0; j < num_implementing_args; j++) { | ||||
| 510 | PyObject *argument = implementing_args[j]; | ||||
| 511 | Py_INCREF(argument)_Py_INCREF(((PyObject*)(argument))); | ||||
| 512 | PyList_SET_ITEM(result, j, argument)PyList_SetItem(result, j, argument); | ||||
| 513 | } | ||||
| 514 | |||||
| 515 | cleanup: | ||||
| 516 | for (int j = 0; j < num_implementing_args; j++) { | ||||
| 517 | Py_DECREF(implementing_args[j])_Py_DECREF(((PyObject*)(implementing_args[j]))); | ||||
| 518 | Py_DECREF(array_function_methods[j])_Py_DECREF(((PyObject*)(array_function_methods[j]))); | ||||
| 519 | } | ||||
| 520 | Py_DECREF(relevant_args)_Py_DECREF(((PyObject*)(relevant_args))); | ||||
| 521 | return result; | ||||
| 522 | } | 
| 1 | #ifndef PyTuple_New | 
| 2 | struct _object; | 
| 3 | typedef struct _object PyObject; | 
| 4 | PyObject* clang_analyzer_PyObject_New_Reference(); | 
| 5 | PyObject* PyTuple_New(Py_ssize_t len) { | 
| 6 | return clang_analyzer_PyObject_New_Reference(); | 
| 7 | } | 
| 8 | #else | 
| 9 | #warning "API PyTuple_New is defined as a macro." | 
| 10 | #endif |