Skip to content

Commit b7cc20a

Browse files
mwiebeMark Wiebe
authored andcommitted
ENH: core: Deprecating direct access to the PyArrayObject fields
NOTE: WIP, code doesn't build
1 parent c625ee0 commit b7cc20a

File tree

8 files changed

+421
-258
lines changed

8 files changed

+421
-258
lines changed

doc/neps/missing-data.rst

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -711,7 +711,7 @@ This gives us the following additions to the PyArrayObject::
711711
PyArray_Descr *maskna_descr;
712712
/*
713713
* Raw data buffer for mask. If the array has the flag
714-
* NPY_ARRAY_OWNNAMASK enabled, it owns this memory and
714+
* NPY_ARRAY_OWNMASKNA enabled, it owns this memory and
715715
* must call PyArray_free on it when destroyed.
716716
*/
717717
npy_mask *maskna_data;
@@ -724,10 +724,10 @@ This gives us the following additions to the PyArrayObject::
724724

725725
There are 2 (or 3) flags which must be added to the array flags::
726726

727-
NPY_ARRAY_HASNAMASK
728-
NPY_ARRAY_OWNNAMASK
727+
NPY_ARRAY_HASMASKNA
728+
NPY_ARRAY_OWNMASKNA
729729
/* To possibly add in a later revision */
730-
NPY_ARRAY_HARDNAMASK
730+
NPY_ARRAY_HARDMASKNA
731731

732732
To allow the easy detection of NA support, and whether an array
733733
has any missing values, we add the following functions:
@@ -817,7 +817,7 @@ NPY_ITER_ARRAYMASK
817817
can be only one such mask, and there cannot also be a virtual
818818
mask.
819819

820-
As a special case, if the flag NPY_ITER_USE_NAMASK is specified
820+
As a special case, if the flag NPY_ITER_USE_MASKNA is specified
821821
at the same time, the mask for the operand is used instead
822822
of the operand itself. If the operand has no mask but is
823823
based on an NA dtype, that mask exposed by the iterator converts
@@ -837,14 +837,14 @@ Iterator NA-array Features
837837

838838
We add several new per-operand flags:
839839

840-
NPY_ITER_USE_NAMASK
840+
NPY_ITER_USE_MASKNA
841841
If the operand has an NA dtype, an NA mask, or both, this adds a new
842842
virtual operand to the end of the operand list which iterates
843843
over the mask of the particular operand.
844844

845-
NPY_ITER_IGNORE_NAMASK
845+
NPY_ITER_IGNORE_MASKNA
846846
If an operand has an NA mask, by default the iterator will raise
847-
an exception unless NPY_ITER_USE_NAMASK is specified. This flag
847+
an exception unless NPY_ITER_USE_MASKNA is specified. This flag
848848
disables that check, and is intended for cases where one has first
849849
checked that all the elements in the array are not NA using the
850850
PyArray_ContainsNA function.

numpy/core/code_generators/generate_numpy_api.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -220,7 +220,9 @@ def do_generate_api(targets, sources):
220220
for name, index in types_api.items():
221221
multiarray_api_dict[name] = TypeApi(name, index, 'PyTypeObject', api_name)
222222

223-
assert len(multiarray_api_dict) == len(multiarray_api_index)
223+
if len(multiarray_api_dict) != len(multiarray_api_index):
224+
raise AssertionError, "Multiarray API size mismatch %d %d" % \
225+
(len(multiarray_api_dict), len(multiarray_api_index))
224226

225227
extension_list = []
226228
for name, index in genapi.order_dict(multiarray_api_index):

numpy/core/code_generators/numpy_api.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -318,6 +318,7 @@
318318
# End 1.6 API
319319
'PyArray_MaskedCopyInto': 281,
320320
'PyArray_MaskedMoveInto': 282,
321+
'PyArray_SetBase': 283,
321322
}
322323

323324
ufunc_types_api = {

numpy/core/include/numpy/ndarraytypes.h

Lines changed: 215 additions & 131 deletions
Large diffs are not rendered by default.

numpy/core/include/numpy/npy_deprecated_api.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,4 +89,10 @@
8989
*/
9090
#define fortran fortran_
9191

92+
/*
93+
* Direct access to PyArrayObject fields is deprecated as of NumPy 1.7,
94+
* but enabled here through this typedef.
95+
*/
96+
typedef PyArrayObject_fieldaccess PyArrayObject;
97+
9298
#endif

numpy/core/src/multiarray/arrayobject.c

Lines changed: 31 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,35 @@ PyArray_Size(PyObject *op)
6565
}
6666
}
6767

68+
/*NUMPY_API
69+
* Sets the 'base' attribute of the array.
70+
*
71+
* Returns 0 on success, -1 on failure.
72+
*/
73+
NPY_NO_EXPORT int
74+
PyArray_SetBase(PyArrayObject *arr, PyObject *obj)
75+
{
76+
/*
77+
* Don't allow chains of views, always set the base
78+
* to the owner of the data
79+
*/
80+
while (PyArray_Check(obj) &&
81+
(PyObject *)arr != obj &&
82+
PyArray_BASE(obj) != NULL) {
83+
obj = PyArray_BASE(obj);
84+
}
85+
/* Disallow circular references */
86+
if ((PyObject *)arr == obj) {
87+
PyErr_SetString(PyExc_ValueError,
88+
"Cannot create a circular NumPy array 'base' dependency");
89+
return -1;
90+
}
91+
((PyArrayObject_fieldaccess *)arr)->base = obj;
92+
93+
return 0;
94+
}
95+
96+
6897
/*NUMPY_API*/
6998
NPY_NO_EXPORT int
7099
PyArray_CopyObject(PyArrayObject *dest, PyObject *src_object)
@@ -1370,7 +1399,7 @@ array_alloc(PyTypeObject *type, Py_ssize_t NPY_UNUSED(nitems))
13701399
{
13711400
PyObject *obj;
13721401
/* nitems will always be 0 */
1373-
obj = (PyObject *)_pya_malloc(sizeof(PyArrayObject));
1402+
obj = (PyObject *)_pya_malloc(NPY_SIZEOF_PYARRAYOBJECT);
13741403
PyObject_Init(obj, type);
13751404
return obj;
13761405
}
@@ -1384,7 +1413,7 @@ NPY_NO_EXPORT PyTypeObject PyArray_Type = {
13841413
0, /* ob_size */
13851414
#endif
13861415
"numpy.ndarray", /* tp_name */
1387-
sizeof(PyArrayObject), /* tp_basicsize */
1416+
NPY_SIZEOF_PYARRAYOBJECT, /* tp_basicsize */
13881417
0, /* tp_itemsize */
13891418
/* methods */
13901419
(destructor)array_dealloc, /* tp_dealloc */

0 commit comments

Comments
 (0)