Skip to content
This repository
Browse code

ENH: missingdata: Future-proof AssignNA and AssignMaskNA for later mu…

…lti-NA support
  • Loading branch information...
commit c9764c13eb0e1eef23345025c75577600b472ab3 1 parent 6282b55
Mark authored charris committed
9  numpy/core/src/multiarray/array_assign_array.c
@@ -404,7 +404,8 @@ PyArray_AssignArray(PyArrayObject *dst, PyArrayObject *src,
404 404
 
405 405
             if (na != NULL) {
406 406
                 /* 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);
408 409
                 Py_DECREF(na);
409 410
                 return retcode;
410 411
             }
@@ -608,7 +609,8 @@ PyArray_AssignArray(PyArrayObject *dst, PyArrayObject *src,
608 609
                     goto finish;
609 610
                 }
610 611
                 else {
611  
-                    if (PyArray_AssignMaskNA(dst, NULL, 1) < 0) {
  612
+                    if (PyArray_AssignMaskNA(dst, 1, NULL,
  613
+                                        preservena, preservewhichna) < 0) {
612 614
                         goto fail;
613 615
                     }
614 616
                 }
@@ -733,7 +735,8 @@ PyArray_AssignArray(PyArrayObject *dst, PyArrayObject *src,
733 735
                     goto finish;
734 736
                 }
735 737
                 else {
736  
-                    if (PyArray_AssignMaskNA(dst, wheremask, 1) < 0) {
  738
+                    if (PyArray_AssignMaskNA(dst, 1, wheremask,
  739
+                                        preservena, preservewhichna) < 0) {
737 740
                         goto fail;
738 741
                     }
739 742
                 }
6  numpy/core/src/multiarray/array_assign_scalar.c
@@ -405,7 +405,8 @@ PyArray_AssignRawScalar(PyArrayObject *dst,
405 405
         if (!preservena || !dst_has_maskna) {
406 406
             /* If assigning to an array with an NA mask, set to all exposed */
407 407
             if (dst_has_maskna) {
408  
-                if (PyArray_AssignMaskNA(dst, NULL, 1) < 0) {
  408
+                if (PyArray_AssignMaskNA(dst, 1, NULL,
  409
+                                    preservena, preservewhichna) < 0) {
409 410
                     goto fail;
410 411
                 }
411 412
             }
@@ -468,7 +469,8 @@ PyArray_AssignRawScalar(PyArrayObject *dst,
468 469
                  * TODO: If the where mask has NA values, this part
469 470
                  *       changes too.
470 471
                  */
471  
-                if (PyArray_AssignMaskNA(dst, wheremask, 1) < 0) {
  472
+                if (PyArray_AssignMaskNA(dst, 1, wheremask,
  473
+                                    preservena, preservewhichna) < 0) {
472 474
                     goto fail;
473 475
                 }
474 476
             }
2  numpy/core/src/multiarray/arrayobject.c
@@ -210,7 +210,7 @@ PyArray_CopyObject(PyArrayObject *dest, PyObject *src_object)
210 210
             }
211 211
             /* Assigning NA affects the mask if it exists */
212 212
             else if (na != NULL) {
213  
-                if (PyArray_AssignNA(dest, NULL, na) < 0) {
  213
+                if (PyArray_AssignNA(dest, na, NULL, 0, NULL) < 0) {
214 214
                     Py_DECREF(na);
215 215
                     Py_DECREF(src_object);
216 216
                     return -1;
2  numpy/core/src/multiarray/ctors.c
@@ -2638,7 +2638,7 @@ PyArray_CopyAsFlat(PyArrayObject *dst, PyArrayObject *src, NPY_ORDER order)
2638 2638
      * to be exposed, then proceed without worrying about the mask.
2639 2639
      */
2640 2640
     else if (PyArray_HASMASKNA(dst)) {
2641  
-        if (PyArray_AssignMaskNA(dst, NULL, 1) < 0) {
  2641
+        if (PyArray_AssignMaskNA(dst, 1, NULL, 0, NULL) < 0) {
2642 2642
             return -1;
2643 2643
         }
2644 2644
         baseflags |= NPY_ITER_IGNORE_MASKNA;
37  numpy/core/src/multiarray/na_mask.c
@@ -228,11 +228,18 @@ fill_raw_byte_array(int ndim, npy_intp *shape,
228 228
  * If 'wheremask' isn't NULL, it should be a boolean mask which
229 229
  * specifies where to do the assignment.
230 230
  *
  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
+ *
231 237
  * Returns 0 on success, -1 on failure.
232 238
  */
233 239
 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)
236 243
 {
237 244
     PyArray_Descr *maskvalue_dtype;
238 245
     int retcode = 0;
@@ -245,6 +252,12 @@ PyArray_AssignMaskNA(PyArrayObject *arr, PyArrayObject *wheremask,
245 252
         return -1;
246 253
     }
247 254
 
  255
+    if (preservewhichna != NULL) {
  256
+        PyErr_SetString(PyExc_RuntimeError,
  257
+                "multi-NA support is not yet implemented");
  258
+        return -1;
  259
+    }
  260
+
248 261
     /*
249 262
      * If the mask given has no payload, assign from boolean type, otherwise
250 263
      * assign from the mask type.
@@ -440,21 +453,22 @@ PyArray_AllocateMaskNA(PyArrayObject *arr,
440 453
  * In the future, when 'arr' has an NA dtype, will assign the
441 454
  * appropriate NA bitpatterns to the elements.
442 455
  *
  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
+ *
443 462
  * Returns -1 on failure, 0 on success.
444 463
  */
445 464
 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)
447 468
 {
448 469
     NpyNA_fields *fna = (NpyNA_fields *)na;
449 470
     char maskvalue;
450 471
 
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  
-
458 472
     /* Turn the payload into a mask value */
459 473
     if (fna->payload == NPY_NA_NOPAYLOAD) {
460 474
         maskvalue = 0;
@@ -471,7 +485,8 @@ PyArray_AssignNA(PyArrayObject *arr, PyArrayObject *wheremask, NpyNA *na)
471 485
         maskvalue = (char)NpyMaskValue_Create(0, fna->payload);
472 486
     }
473 487
 
474  
-    return PyArray_AssignMaskNA(arr, wheremask, maskvalue);
  488
+    return PyArray_AssignMaskNA(arr, maskvalue,
  489
+                        wheremask, preservena, preservewhichna);
475 490
 }
476 491
 
477 492
 /*
11  numpy/core/src/multiarray/na_mask.h
@@ -4,17 +4,6 @@
4 4
 #include "lowlevel_strided_loops.h"
5 5
 
6 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  
-
17  
-/*
18 7
  * A ufunc-like function, which returns a boolean or an array
19 8
  * of booleans indicating which values are NA.
20 9
  */
2  numpy/core/src/umath/ufunc_object.c
@@ -1010,7 +1010,7 @@ static int get_ufunc_arguments(PyUFuncObject *ufunc,
1010 1010
     else if (!(*out_use_maskna) && any_maskna_out) {
1011 1011
         for (i = nin; i < nin+nout; ++i) {
1012 1012
             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) {
1014 1014
                     return -1;
1015 1015
                 }
1016 1016
             }

0 notes on commit c9764c1

Please sign in to comment.
Something went wrong with that request. Please try again.