8000 ENH: missingdata: Future-proof AssignNA and AssignMaskNA for later mu… · numpy/numpy@fe720c2 · GitHub
[go: up one dir, main page]

Skip to content

Commit fe720c2

Browse files
committed
ENH: missingdata: Future-proof AssignNA and AssignMaskNA for later multi-NA support
1 parent 934e50b commit fe720c2

File tree

7 files changed

+39
-30
lines changed

7 files changed

+39
-30
lines changed

numpy/core/src/multiarray/array_assign_array.c

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -404,7 +404,8 @@ PyArray_AssignArray(PyArrayObject *dst, PyArrayObject *src,
404404

405405
if (na != NULL) {
406406
/* TODO: With multi-NA, preservena must also be followed */
407-
int retcode = PyArray_AssignNA(dst, wheremask, na);
407+
int retcode = PyArray_AssignNA(dst, na, wheremask,
408+
preservena, preservewhichna);
408409
Py_DECREF(na);
409410
return retcode;
410411
}
@@ -608,7 +609,8 @@ PyArray_AssignArray(PyArrayObject *dst, PyArrayObject *src,
608609
goto finish;
609610
}
610611
else {
611-
if (PyArray_AssignMaskNA(dst, NULL, 1) < 0) {
612+
if (PyArray_AssignMaskNA(dst, 1, NULL,
613+
preservena, preservewhichna) < 0) {
612614
goto fail;
613615
}
614616
}
@@ -733,7 +735,8 @@ PyArray_AssignArray(PyArrayObject *dst, PyArrayObject *src,
733735
goto finish;
734736
}
735737
else {
736-
if (PyArray_AssignMaskNA(dst, wheremask, 1) < 0) {
738+
if (PyArray_AssignMaskNA(dst, 1, wheremask,
739+
preservena, preservewhichna) < 0) {
737740
goto fail;
738741
}
739742
}

numpy/core/src/multiarray/array_assign_scalar.c

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -405,7 +405,8 @@ PyArray_AssignRawScalar(PyArrayObject *dst,
405405
if (!preservena || !dst_has_maskna) {
406406
/* If assigning to an array with an NA mask, set to all exposed */
407407
if (dst_has_maskna) {
408-
if (PyArray_AssignMaskNA(dst, NULL, 1) < 0) {
408+
if (PyArray_AssignMaskNA(dst, 1, NULL,
409+
preservena, preservewhichna) < 0) {
409410
goto fail;
410411
}
411412
}
@@ -468,7 +469,8 @@ PyArray_AssignRawScalar(PyArrayObject *dst,
468469
* TODO: If the where mask has NA values, this part
469470
* changes too.
470471
*/
471-
if (PyArray_AssignMaskNA(dst, wheremask, 1) < 0) {
472+
if (PyArray_AssignMaskNA(dst, 1, wheremask,
473+
preservena, preservewhichna) < 0) {
472474
goto fail;
473475
}
474476
}

numpy/core/src/multiarray/arrayobject.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -210,7 +210,7 @@ PyArray_CopyObject(PyArrayObject *dest, PyObject *src_object)
210210
}
211211
/* Assigning NA affects the mask if it exists */
212212
else if (na != NULL) {
213-
if (PyArray_AssignNA(dest, NULL, na) < 0) {
213+
if (PyArray_AssignNA(dest, na, NULL, 0, NULL) < 0) {
214214
Py_DECREF(na);
215215
Py_DECREF(src_object);
216216
return -1;

numpy/core/src/multiarray/ctors.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2638,7 +2638,7 @@ PyArray_CopyAsFlat(PyArrayObject *dst, PyArrayObject *src, NPY_ORDER order)
26382638
* to be exposed, then proceed without worrying about the mask.
26392639
*/
26402640
else if (PyArray_HASMASKNA(dst)) {
2641-
if (PyArray_AssignMaskNA(dst, NULL, 1) < 0) {
2641+
if (PyArray_AssignMaskNA(dst, 1, NULL, 0, NULL) < 0) {
26422642
return -1;
26432643
}
26442644
baseflags |= NPY_ITER_IGNORE_MASKNA;

numpy/core/src/multiarray/na_mask.c

Lines changed: 26 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -228,11 +228,18 @@ fill_raw_byte_array(int ndim, npy_intp *shape,
228228
* If 'wheremask' isn't NULL, it should be a boolean mask which
229229
* specifies where to do the assignment.
230230
*
231+
* The parameters 'preservena' and 'preservewhichna' are NOT YET
232+
* SUPPORTED, but are in place to allow for future expansion to
233+
* multi-NA. 'preservewhichna' should be set to NULL, while
234+
* preservena has no effect for straight NPY_BOOL NA masks, because
235+
* different NAs are indistinguishable.
236+
*
231237
* Returns 0 on success, -1 on failure.
232238
*/
233239
NPY_NO_EXPORT int
234-
PyArray_AssignMaskNA(PyArrayObject *arr, PyArrayObject *wheremask,
235-
npy_mask maskvalue)
240+
PyArray_AssignMaskNA(PyArrayObject *arr, npy_mask maskvalue,
241+
PyArrayObject *wheremask,
242+
npy_bool preservena, npy_bool *preservewhichna)
236243
{
237244
PyArray_Descr *maskvalue_dtype;
238245
int retcode = 0;
@@ -245,6 +252,12 @@ PyArray_AssignMaskNA(PyArrayObject *arr, PyArrayObject *wheremask,
245252
return -1;
246253
}
247254

255+
if (preservewhichna != NULL) {
256+
PyErr_SetString(PyExc_RuntimeError,
257+
"multi-NA support is not yet implemented");
258+
return -1;
259+
}
260+
248261
/*
249262
* If the mask given has no payload, assign from boolean type, otherwise
250263
* assign from the mask type.
@@ -440,21 +453,22 @@ PyArray_AllocateMaskNA(PyArrayObject *arr,
440453
* In the future, when 'arr' has an NA dtype, will assign the
441454
* appropriate NA bitpatterns to the elements.
442455
*
456+
* The parameters 'preservena' and 'preservewhichna' are NOT YET
457+
* SUPPORTED, but are in place to allow for future expansion to
458+
* multi-NA. 'preservewhichna' should be set to NULL, while
459+
* preservena has no effect for straight NPY_BOOL NA masks, because
460+
* different NAs are indistinguishable.
461+
*
443462
* Returns -1 on failure, 0 on success.
444463
*/
445464
NPY_NO_EXPORT int
446-
PyArray_AssignNA(PyArrayObject *arr, PyArrayObject *wheremask, NpyNA *na)
465+
PyArray_AssignNA(PyArrayObject *arr, NpyNA *na,
466+
PyArrayObject *wheremask,
467+
npy_bool preservena, npy_bool *preservewhichna)
447468
{
448469
NpyNA_fields *fna = (NpyNA_fields *)na;
449470
char maskvalue;
450471

451-
if (!PyArray_HASMASKNA(arr)) {
452-
PyErr_SetString(PyExc_ValueError,
453-
"Cannot assign an NA to an "
454-
"array with no NA support");
455-
return -1;
456-
}
457-
458472
/* Turn the payload into a mask value */
459473
if (fna->payload == NPY_NA_NOPAYLOAD) {
460474
maskvalue = 0;
@@ -471,7 +485,8 @@ PyArray_AssignNA(PyArrayObject *arr, PyArrayObject *wheremask, NpyNA *na)
471485
maskvalue = (char)NpyMaskValue_Create(0, fna->payload);
472486
}
473487

474-
return PyArray_AssignMaskNA(arr, wheremask, maskvalue);
488+
return PyArray_AssignMaskNA(arr, maskvalue,
489+
wheremask, preservena, preservewhichna);
475490
}
476491

477492
/*

numpy/core/src/multiarray/na_mask.h

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3,17 +3,6 @@
33

44
#include "lowlevel_strided_loops.h"
55

6-
/*
7-
* Assigns the given NA value to all the elements in the array.
8-
*
9-
* If 'wheremask' isn't NULL, it specifies which elements to assign
10-
* NA to.
11-
*
12-
* Returns -1 on failure, 0 on success.
13-
*/
14-
NPY_NO_EXPORT int
15-
PyArray_AssignNA(PyArrayObject *arr, PyArrayObject *wheremask, NpyNA *na);
16-
176
/*
187
* A ufunc-like function, which returns a boolean or an array
198
* of booleans indicating which values are NA.

numpy/core/src/umath/ufunc_object.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1010,7 +1010,7 @@ static int get_ufunc_arguments(PyUFuncObject *ufunc,
10101010
else if (!(*out_use_maskna) && any_maskna_out) {
10111011
for (i = nin; i < nin+nout; ++i) {
10121012
if (PyArray_HASMASKNA(out_op[i])) {
1013-
if (PyArray_AssignMaskNA(out_op[i], NULL, 1) < 0) {
1013+
if (PyArray_AssignMaskNA(out_op[i], 1, NULL, 0, NULL) < 0) {
10141014
return -1;
10151015
}
10161016
}

0 commit comments

Comments
 (0)
0