-
-
Notifications
You must be signed in to change notification settings - Fork 10.8k
MAINT,API: Make metadata, c_metadata, fields, and names only exist on old-style dtypes #25802
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
439bc0f
7329d7e
c82245a
ba10883
873d3ec
87d9d95
8e7cc23
b58c790
03b4277
70409c4
0910b58
a8f4618
5a3eafa
80beb25
80b6d6e
b37cbf7
82ac0ba
56194f0
31e5d47
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -407,6 +407,17 @@ to adapt your code and achieve compatibility with both 1.x and 2.x. | |
(`gh-25792 <https://github.com/numpy/numpy/pull/25792>`__) | ||
|
||
|
||
Structured dtype information access through functions | ||
----------------------------------------------------- | ||
The dtype structures fields `c_metadata``, ``names``, | ||
``fields``, and ``subarray`` must now be accessed through new | ||
functions following the same names, such as ``PyDataType_NAMES``. | ||
Direct access of the fields is not valid as they do not exist for | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Here, you write |
||
all ``PyArray_Descr`` instances. | ||
The ``metadata`` field is kept, but the macro version should also be preferred. | ||
|
||
(`gh-25802 <https://github.com/numpy/numpy/pull/25802>`__) | ||
|
||
NumPy 2.0 C API removals | ||
======================== | ||
|
||
|
@@ -487,6 +498,12 @@ NumPy 2.0 C API removals | |
|
||
(`gh-25292 <https://github.com/numpy/numpy/pull/25292>`__) | ||
|
||
|
||
* ``PyDataType_GetDatetimeMetaData`` has been removed, it did not actually | ||
do anything since at least NumPy 1.7. | ||
|
||
(`gh-25802 <https://github.com/numpy/numpy/pull/25802>`__) | ||
|
||
``PyArray_GetCastFunc`` was removed | ||
----------------------------------- | ||
Note that custom legacy user dtypes can still provide a castfunc | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -573,6 +573,10 @@ typedef struct { | |
NPY_ITEM_IS_POINTER | NPY_ITEM_REFCOUNT | \ | ||
NPY_NEEDS_INIT | NPY_NEEDS_PYAPI) | ||
|
||
#if !(defined(NPY_INTERNAL_BUILD) && NPY_INTERNAL_BUILD) | ||
/* | ||
* Public version of the Descriptor struct | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm confused - why does the public version still have those things like There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. No, you are not: The point is that I am splitting this into multiple PRs and this one doesn't actually change anything. The only reason I added the release note here, was because Nathan asked for it, and I agreed it might be easier to reason about it here than in a PR that breaks more things. |
||
*/ | ||
typedef struct _PyArray_Descr { | ||
PyObject_HEAD | ||
/* | ||
|
@@ -633,6 +637,55 @@ typedef struct _PyArray_Descr { | |
|
||
} PyArray_Descr; | ||
|
||
#else /* internal build */ | ||
|
||
// TODO: This split definition only exists for piece-meal transitioning | ||
// as it allows change internal use without worrying about public API. | ||
typedef struct _PyArray_Descr { | ||
PyObject_HEAD | ||
PyTypeObject *typeobj; | ||
char kind; | ||
char type; | ||
char byteorder; | ||
char flags; | ||
int type_num; | ||
int elsize; | ||
int alignment; | ||
/* except hash, the below fields will be legacy descriptor specific */ | ||
struct _arr_descr *unreachable_subarray; | ||
PyObject *unreachable_fields; | ||
PyObject *unreachable_names; | ||
PyArray_ArrFuncs *_former_f; | ||
PyObject *metadata; | ||
NpyAuxData *unreachable_c_metadata; | ||
npy_hash_t hash; | ||
} PyArray_Descr; | ||
|
||
#endif /* internal build */ | ||
|
||
|
||
/* | ||
* Semi-private struct with additional field of legacy descriptors (must | ||
* check NPY_DT_is_legacy before casting/accessing). | ||
ngoldbaum marked this conversation as resolved.
Show resolved
Hide resolved
|
||
*/ | ||
typedef struct { | ||
PyObject_HEAD | ||
PyTypeObject *typeobj; | ||
char kind; | ||
char type; | ||
char byteorder; | ||
char flags; | ||
int type_num; | ||
int elsize; | ||
int alignment; | ||
struct _arr_descr *subarray; | ||
PyObject *fields; | ||
PyObject *names; | ||
PyArray_ArrFuncs *_former_f; | ||
PyObject *metadata; | ||
NpyAuxData *c_metadata; | ||
npy_hash_t hash; | ||
} _PyArray_LegacyDescr; | ||
|
||
|
||
/* | ||
|
@@ -1620,6 +1673,7 @@ PyArray_CLEARFLAGS(PyArrayObject *arr, int flags) | |
#define PyTypeNum_ISOBJECT(type) ((type) == NPY_OBJECT) | ||
|
||
|
||
#define PyDataType_ISLEGACY(dtype) ((dtype)->type_num < NPY_VSTRING && ((dtype)->type_num >= 0)) | ||
#define PyDataType_ISBOOL(obj) PyTypeNum_ISBOOL(((PyArray_Descr*)(obj))->type_num) | ||
#define PyDataType_ISUNSIGNED(obj) PyTypeNum_ISUNSIGNED(((PyArray_Descr*)(obj))->type_num) | ||
#define PyDataType_ISSIGNED(obj) PyTypeNum_ISSIGNED(((PyArray_Descr*)(obj))->type_num) | ||
|
@@ -1633,8 +1687,8 @@ PyArray_CLEARFLAGS(PyArrayObject *arr, int flags) | |
#define PyDataType_ISUSERDEF(obj) PyTypeNum_ISUSERDEF(((PyArray_Descr*)(obj))->type_num) | ||
#define PyDataType_ISEXTENDED(obj) PyTypeNum_ISEXTENDED(((PyArray_Descr*)(obj))->type_num) | ||
#define PyDataType_ISOBJECT(obj) PyTypeNum_ISOBJECT(((PyArray_Descr*)(obj))->type_num) | ||
#define PyDataType_HASFIELDS(obj) (((PyArray_Descr *)(obj))->names != NULL) | ||
#define PyDataType_HASSUBARRAY(dtype) ((dtype)->subarray != NULL) | ||
#define PyDataType_HASFIELDS(obj) (PyDataType_ISLEGACY((PyArray_Descr*)(obj)) && ((_PyArray_LegacyDescr *)(obj))->names != NULL) | ||
#define PyDataType_HASSUBARRAY(dtype) (PyDataType_ISLEGACY(dtype) && ((_PyArray_LegacyDescr *)dtype)->subarray != NULL) | ||
#define PyDataType_ISUNSIZED(dtype) ((dtype)->elsize == 0 && \ | ||
!PyDataType_HASFIELDS(dtype)) | ||
#define PyDataType_MAKEUNSIZED(dtype) ((dtype)->elsize = 0) | ||
|
@@ -1643,6 +1697,33 @@ PyArray_CLEARFLAGS(PyArrayObject *arr, int flags) | |
* npy_2_compat.h and are not defined here. | ||
*/ | ||
|
||
/* | ||
* Access inline functions for legacy fields. Except metadata these fields are | ||
* specific to structured arrays (names, fields) or datetime (c_metadata). | ||
* Although technically they may be used (but normally ignored) on non-struct | ||
* dtypes as well. | ||
* For structured dtypes, new ways to define and access fields make sense. | ||
*/ | ||
static inline PyArray_ArrayDescr * | ||
PyDataType_SUBARRAY(PyArray_Descr *dtype) { | ||
return !PyDataType_ISLEGACY(dtype) ? NULL : ((_PyArray_LegacyDescr *)dtype)->subarray; | ||
} | ||
|
||
static inline PyObject * | ||
PyDataType_NAMES(PyArray_Descr *dtype) { | ||
return !PyDataType_ISLEGACY(dtype) ? NULL : ((_PyArray_LegacyDescr *)dtype)->names; | ||
} | ||
|
||
static inline PyObject * | ||
PyDataType_FIELDS(PyArray_Descr *dtype) { | ||
return !PyDataType_ISLEGACY(dtype) ? NULL : ((_PyArray_LegacyDescr *)dtype)->fields; | ||
} | ||
|
||
static inline NpyAuxData * | ||
PyDataType_C_METADATA(PyArray_Descr *dtype) { | ||
return !PyDataType_ISLEGACY(dtype) ? NULL : ((_PyArray_LegacyDescr *)dtype)->c_metadata; | ||
} | ||
|
||
#define PyArray_ISBOOL(obj) PyTypeNum_ISBOOL(PyArray_TYPE(obj)) | ||
#define PyArray_ISUNSIGNED(obj) PyTypeNum_ISUNSIGNED(PyArray_TYPE(obj)) | ||
#define PyArray_ISSIGNED(obj) PyTypeNum_ISSIGNED(PyArray_TYPE(obj)) | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -126,6 +126,8 @@ PyArray_ImportNumPyAPI() | |
/* Aliases of 2.x names to 1.x only equivalent names */ | ||
#define NPY_NTYPES NPY_NTYPES_LEGACY | ||
#define PyArray_DescrProto PyArray_Descr | ||
/* NumPy 2 definition always works, but add it for 1.x only */ | ||
#define PyDataType_ISLEGACY(dtype) (1) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Technically not true because of the experimental dtype flag but it's probably a weird thing to do that across the numpy 1.0/2.0 boundary so this is fine IMO. |
||
#else | ||
#define NPY_DEFAULT_INT \ | ||
(PyArray_RUNTIME_VERSION >= NPY_2_0_API_VERSION ? NPY_INTP : NPY_LONG) | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -496,7 +496,7 @@ static PyObject * | |
create_custom_field_dtype(PyObject *NPY_UNUSED(mod), PyObject *args) | ||
{ | ||
PyArray_DescrProto proto; | ||
PyArray_Descr *dtype; | ||
_PyArray_LegacyDescr *dtype; /* Is checked for void, so legacy is OK */ | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'd tend to go the other way around, and just recast or define a new variable when you need the legacy one. But this is fine as is too. |
||
PyTypeObject *scalar_type; | ||
int error_path; | ||
|
||
|
@@ -510,7 +510,7 @@ create_custom_field_dtype(PyObject *NPY_UNUSED(mod), PyObject *args) | |
if (dtype->type_num != NPY_VOID || dtype->fields == NULL || | ||
!PyDict_CheckExact(dtype->fields) || | ||
PyTuple_Size(dtype->names) != 1 || | ||
!PyDataType_REFCHK(dtype) || | ||
!PyDataType_REFCHK((PyArray_Descr *)dtype) || | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Basically feel one should avoid recasting a legacy type into a "real" one (but really am nitpicking here) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. That gets annoying since you cannot assign using the macros. Having both around is reasonable. It would be nice to just define some of these internally in a way that supports the subclass |
||
dtype->elsize != sizeof(PyObject *)) { | ||
PyErr_SetString(PyExc_ValueError, | ||
"Bad dtype passed to test function, must be an object " | ||
|
@@ -531,7 +531,7 @@ create_custom_field_dtype(PyObject *NPY_UNUSED(mod), PyObject *args) | |
proto.subarray = dtype->subarray; | ||
proto.fields = dtype->fields; | ||
proto.names = dtype->names; | ||
proto.f = PyDataType_GetArrFuncs(dtype); | ||
proto.f = PyDataType_GetArrFuncs((PyArray_Descr *)dtype); | ||
proto.metadata = dtype->metadata; | ||
proto.c_metadata = dtype->c_metadata; | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -598,11 +598,9 @@ _void_compare(PyArrayObject *self, PyArrayObject *other, int cmp_op) | |
return NULL; | ||
} | ||
if (PyArray_HASFIELDS(self) && PyArray_HASFIELDS(other)) { | ||
PyArray_Descr *self_descr = PyArray_DESCR(self); | ||
PyArray_Descr *other_descr = PyArray_DESCR(other); | ||
|
||
/* Use promotion to decide whether the comparison is valid */ | ||
PyArray_Descr *promoted = PyArray_PromoteTypes(self_descr, other_descr); | ||
PyArray_Descr *promoted = PyArray_PromoteTypes( | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Maybe do this promotion check before even defining There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah, probably a bit nicer, changed it. |
||
PyArray_DESCR(self), PyArray_DESCR(other)); | ||
if (promoted == NULL) { | ||
PyErr_SetString(PyExc_TypeError, | ||
"Cannot compare structured arrays unless they have a " | ||
|
@@ -612,6 +610,9 @@ _void_compare(PyArrayObject *self, PyArrayObject *other, int cmp_op) | |
} | ||
Py_DECREF(promoted); | ||
|
||
_PyArray_LegacyDescr *self_descr = (_PyArray_LegacyDescr *)PyArray_DESCR(self); | ||
_PyArray_LegacyDescr *other_descr = (_PyArray_LegacyDescr *)PyArray_DESCR(other); | ||
|
||
npy_intp result_ndim = PyArray_NDIM(self) > PyArray_NDIM(other) ? | ||
PyArray_NDIM(self) : PyArray_NDIM(other); | ||
|
||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Missing backtick on
c_metadata