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 |