* Assign a single element in an array from a python value. * * The dtypes SETITEM should only be trusted to generally do the right * thing if something is known to be a scalar *and* is of a python type known * to the DType (which should include all basic Python math types), but in * general a cast may be necessary. * This function handles the cast, which is for example hit when assigning *
| 464 | * @return 0 on success -1 on failure. |
| 465 | */ |
| 466 | NPY_NO_EXPORT int |
| 467 | PyArray_Pack(PyArray_Descr *descr, char *item, PyObject *value) |
| 468 | { |
| 469 | PyArrayObject_fields arr_fields = { |
| 470 | .flags = NPY_ARRAY_WRITEABLE, /* assume array is not behaved. */ |
| 471 | }; |
| 472 | Py_SET_TYPE(&arr_fields, &PyArray_Type); |
| 473 | Py_SET_REFCNT(&arr_fields, 1); |
| 474 | |
| 475 | if (NPY_UNLIKELY(descr->type_num == NPY_OBJECT)) { |
| 476 | /* |
| 477 | * We always have store objects directly, casting will lose some |
| 478 | * type information. Any other dtype discards the type information. |
| 479 | * TODO: For a Categorical[object] this path may be necessary? |
| 480 | */ |
| 481 | arr_fields.descr = descr; |
| 482 | return descr->f->setitem(value, item, &arr_fields); |
| 483 | } |
| 484 | |
| 485 | /* discover_dtype_from_pyobject includes a check for is_known_scalar_type */ |
| 486 | PyArray_DTypeMeta *DType = discover_dtype_from_pyobject( |
| 487 | value, NULL, NPY_DTYPE(descr)); |
| 488 | if (DType == NULL) { |
| 489 | return -1; |
| 490 | } |
| 491 | if (DType == (PyArray_DTypeMeta *)Py_None && PyArray_CheckExact(value) |
| 492 | && PyArray_NDIM((PyArrayObject *)value) == 0) { |
| 493 | /* |
| 494 | * WARNING: Do NOT relax the above `PyArray_CheckExact`, unless you |
| 495 | * read the function doc NOTE carefully and understood it. |
| 496 | * |
| 497 | * NOTE: The ndim == 0 check should probably be an error, but |
| 498 | * unfortunately. `arr.__float__()` works for 1 element arrays |
| 499 | * so in some contexts we need to let it handled like a scalar. |
| 500 | * (If we manage to deprecate the above, we can do that.) |
| 501 | */ |
| 502 | Py_DECREF(DType); |
| 503 | |
| 504 | PyArrayObject *arr = (PyArrayObject *)value; |
| 505 | if (PyArray_DESCR(arr) == descr && !PyDataType_REFCHK(descr)) { |
| 506 | /* light-weight fast-path for when the descrs obviously matches */ |
| 507 | memcpy(item, PyArray_BYTES(arr), descr->elsize); |
| 508 | return 0; /* success (it was an array-like) */ |
| 509 | } |
| 510 | return cast_raw_scalar_item( |
| 511 | PyArray_DESCR(arr), PyArray_BYTES(arr), descr, item); |
| 512 | |
| 513 | } |
| 514 | if (DType == NPY_DTYPE(descr) || DType == (PyArray_DTypeMeta *)Py_None) { |
| 515 | /* We can set the element directly (or at least will try to) */ |
| 516 | Py_XDECREF(DType); |
| 517 | arr_fields.descr = descr; |
| 518 | return descr->f->setitem(value, item, &arr_fields); |
| 519 | } |
| 520 | PyArray_Descr *tmp_descr; |
| 521 | tmp_descr = NPY_DT_CALL_discover_descr_from_pyobject(DType, value); |
| 522 | Py_DECREF(DType); |
| 523 | if (tmp_descr == NULL) { |
no test coverage detected