summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--numpy/core/_internal.py3
-rw-r--r--numpy/core/include/numpy/ndarraytypes.h37
-rw-r--r--numpy/core/include/numpy/npy_deprecated_api.h24
-rw-r--r--numpy/core/src/multiarray/_datetime.h30
-rw-r--r--numpy/core/src/multiarray/arraytypes.c.src89
-rw-r--r--numpy/core/src/multiarray/datetime.c310
-rw-r--r--numpy/core/src/multiarray/datetime_strings.c5
-rw-r--r--numpy/core/src/multiarray/datetime_strings.h2
-rw-r--r--numpy/core/src/multiarray/descriptor.c111
-rw-r--r--numpy/core/src/multiarray/multiarraymodule.c4
-rw-r--r--numpy/core/src/multiarray/scalarapi.c32
-rw-r--r--numpy/core/src/umath/ufunc_type_resolution.c57
-rw-r--r--numpy/core/tests/test_datetime.py18
-rw-r--r--numpy/lib/type_check.py1
14 files changed, 245 insertions, 478 deletions
diff --git a/numpy/core/_internal.py b/numpy/core/_internal.py
index 3d6702095..309b53c44 100644
--- a/numpy/core/_internal.py
+++ b/numpy/core/_internal.py
@@ -80,7 +80,6 @@ def _usefields(adict, align):
# a simple typestring
def _array_descr(descriptor):
- from multiarray import METADATA_DTSTR
fields = descriptor.fields
if fields is None:
subdtype = descriptor.subdtype
@@ -89,8 +88,6 @@ def _array_descr(descriptor):
return descriptor.str
else:
new = descriptor.metadata.copy()
- # Eliminate any key related to internal implementation
- new.pop(METADATA_DTSTR, None)
if new:
return (descriptor.str, new)
else:
diff --git a/numpy/core/include/numpy/ndarraytypes.h b/numpy/core/include/numpy/ndarraytypes.h
index 31a4bbfef..6c36cccdd 100644
--- a/numpy/core/include/numpy/ndarraytypes.h
+++ b/numpy/core/include/numpy/ndarraytypes.h
@@ -85,8 +85,6 @@ enum NPY_TYPES { NPY_BOOL=0,
NPY_NTYPES_ABI_COMPATIBLE=21
};
-#define NPY_METADATA_DTSTR "__timeunit__"
-
/* basetype array priority */
#define NPY_PRIORITY 0.0
@@ -215,6 +213,7 @@ typedef enum {
/* The special not-a-time (NaT) value */
#define NPY_DATETIME_NAT NPY_MIN_INT64
+
/*
* Upper bound on the length of a DATETIME ISO 8601 string
* YEAR: 21 (64-bit year)
@@ -249,20 +248,6 @@ typedef enum {
#define NPY_DATETIME_NUMUNITS (NPY_FR_GENERIC + 1)
#define NPY_DATETIME_DEFAULTUNIT NPY_FR_GENERIC
-#define NPY_STR_Y "Y"
-#define NPY_STR_M "M"
-#define NPY_STR_W "W"
-#define NPY_STR_D "D"
-#define NPY_STR_h "h"
-#define NPY_STR_m "m"
-#define NPY_STR_s "s"
-#define NPY_STR_ms "ms"
-#define NPY_STR_us "us"
-#define NPY_STR_ns "ns"
-#define NPY_STR_ps "ps"
-#define NPY_STR_fs "fs"
-#define NPY_STR_as "as"
-
/*
* Business day conventions for mapping invalid business
* days to valid business days.
@@ -775,20 +760,16 @@ typedef struct {
int flags;
} PyArray_Chunk;
-
typedef struct {
- NPY_DATETIMEUNIT base;
- int num;
- /*
- * 'den' and 'events are unused, kept here for ABI
- * compatibility with 1.6.
- *
- * TODO: Remove for 2.0.
- */
- int den;
- int events;
+ NPY_DATETIMEUNIT base;
+ int num;
} PyArray_DatetimeMetaData;
+typedef struct {
+ NpyAuxData base;
+ PyArray_DatetimeMetaData meta;
+} PyArray_DatetimeDTypeMetaData;
+
/*
* This structure contains an exploded view of a date-time value.
* NaT is represented by year == NPY_DATETIME_NAT.
@@ -798,7 +779,7 @@ typedef struct {
npy_int32 month, day, hour, min, sec, us, ps, as;
} npy_datetimestruct;
-/* TO BE REMOVED - NOT USED INTERNALLY. */
+/* This is not used internally. */
typedef struct {
npy_int64 day;
npy_int32 sec, us, ps, as;
diff --git a/numpy/core/include/numpy/npy_deprecated_api.h b/numpy/core/include/numpy/npy_deprecated_api.h
index 2fab2cd0d..f082d0827 100644
--- a/numpy/core/include/numpy/npy_deprecated_api.h
+++ b/numpy/core/include/numpy/npy_deprecated_api.h
@@ -95,6 +95,30 @@
*/
#define FORTRAN_IF PyArray_FORTRAN_IF
+/* Deprecated as of NumPy 1.7, datetime64 uses c_metadata instead */
+#define NPY_METADATA_DTSTR "__timeunit__"
+
+/*
+ * Deprecated as of NumPy 1.7.
+ * The reasoning:
+ * - These are for datetime, but there's no datetime "namespace".
+ * - They just turn NPY_STR_<x> into "<x>", which is just
+ * making something simple be indirected.
+ */
+#define NPY_STR_Y "Y"
+#define NPY_STR_M "M"
+#define NPY_STR_W "W"
+#define NPY_STR_D "D"
+#define NPY_STR_h "h"
+#define NPY_STR_m "m"
+#define NPY_STR_s "s"
+#define NPY_STR_ms "ms"
+#define NPY_STR_us "us"
+#define NPY_STR_ns "ns"
+#define NPY_STR_ps "ps"
+#define NPY_STR_fs "fs"
+#define NPY_STR_as "as"
+
/*
* The macros in old_defines.h are Deprecated as of NumPy 1.7 and will be
* removed in the next major release.
diff --git a/numpy/core/src/multiarray/_datetime.h b/numpy/core/src/multiarray/_datetime.h
index 3c216d856..b359a9f17 100644
--- a/numpy/core/src/multiarray/_datetime.h
+++ b/numpy/core/src/multiarray/_datetime.h
@@ -33,13 +33,6 @@ NPY_NO_EXPORT PyArray_Descr *
create_datetime_dtype_with_unit(int type_num, NPY_DATETIMEUNIT unit);
/*
- * This function returns the a new reference to the
- * capsule with the datetime metadata.
- */
-NPY_NO_EXPORT PyObject *
-get_datetime_metacobj_from_dtype(PyArray_Descr *dtype);
-
-/*
* This function returns a pointer to the DateTimeMetaData
* contained within the provided datetime dtype.
*/
@@ -158,20 +151,6 @@ can_cast_timedelta64_metadata(PyArray_DatetimeMetaData *src_meta,
NPY_CASTING casting);
/*
- * Computes the GCD of the two date-time metadata values. Raises
- * an exception if there is no reasonable GCD, such as with
- * years and days.
- *
- * Returns a capsule with the GCD metadata.
- */
-NPY_NO_EXPORT PyObject *
-compute_datetime_metadata_greatest_common_divisor_capsule(
- PyArray_Descr *type1,
- PyArray_Descr *type2,
- int strict_with_nonlinear_units1,
- int strict_with_nonlinear_units2);
-
-/*
* Computes the conversion factor to convert data with 'src_meta' metadata
* into data with 'dst_meta' metadata.
*
@@ -184,7 +163,7 @@ get_datetime_conversion_factor(PyArray_DatetimeMetaData *src_meta,
npy_int64 *out_num, npy_int64 *out_denom);
/*
- * Given an the capsule datetime metadata object,
+ * Given a pointer to datetime metadata,
* returns a tuple for pickling and other purposes.
*/
NPY_NO_EXPORT PyObject *
@@ -200,13 +179,6 @@ convert_datetime_metadata_tuple_to_datetime_metadata(PyObject *tuple,
PyArray_DatetimeMetaData *out_meta);
/*
- * Given a tuple representing datetime metadata,
- * returns a capsule datetime metadata object.
- */
-NPY_NO_EXPORT PyObject *
-convert_datetime_metadata_tuple_to_metacobj(PyObject *tuple);
-
-/*
* Gets a tzoffset in minutes by calling the fromutc() function on
* the Python datetime.tzinfo object.
*/
diff --git a/numpy/core/src/multiarray/arraytypes.c.src b/numpy/core/src/multiarray/arraytypes.c.src
index d9e461a15..6dcc7d8e9 100644
--- a/numpy/core/src/multiarray/arraytypes.c.src
+++ b/numpy/core/src/multiarray/arraytypes.c.src
@@ -3871,27 +3871,6 @@ NPY_NO_EXPORT PyArray_Descr @from@_Descr = {
/**end repeat**/
-static void
-_init_datetime_descr(PyArray_Descr *descr)
-{
- PyArray_DatetimeMetaData *dt_data;
- PyObject *cobj;
-
- dt_data = PyArray_malloc(sizeof(PyArray_DatetimeMetaData));
- dt_data->base = NPY_DATETIME_DEFAULTUNIT;
- dt_data->num = 1;
-
-/* FIXME
- * There is no error check here and no way to indicate an error
- * until the metadata turns up NULL.
- */
- cobj = NpyCapsule_FromVoidPtr((void *)dt_data, simple_capsule_dtor);
- descr->metadata = PyDict_New();
- PyDict_SetItemString(descr->metadata, NPY_METADATA_DTSTR, cobj);
- Py_DECREF(cobj);
-
-}
-
#define _MAX_LETTER 128
static char _letter_to_num[_MAX_LETTER];
@@ -3973,16 +3952,64 @@ PyArray_DescrFromType(int type)
Py_INCREF(ret);
}
- /* Make sure dtype metadata is initialized for DATETIME */
- if (PyTypeNum_ISDATETIME(type)) {
- if (ret->metadata == NULL) {
- _init_datetime_descr(ret);
- }
+ return ret;
+}
+
+/* A clone function for the datetime dtype metadata */
+static NpyAuxData *
+datetime_dtype_metadata_clone(NpyAuxData *data)
+{
+ PyArray_DatetimeDTypeMetaData *newdata =
+ (PyArray_DatetimeDTypeMetaData *)PyArray_malloc(
+ sizeof(PyArray_DatetimeDTypeMetaData));
+ if (newdata == NULL) {
+ return NULL;
}
- return ret;
+ memcpy(newdata, data, sizeof(PyArray_DatetimeDTypeMetaData));
+
+ return (NpyAuxData *)newdata;
}
+/*
+ * Initializes the c_metadata field for the _builtin_descrs DATETIME
+ * and TIMEDELTA.
+ */
+int
+initialize_builtin_datetime_metadata(void)
+{
+ PyArray_DatetimeDTypeMetaData *data1, *data2;
+
+ /* Allocate memory for the metadata */
+ data1 = PyArray_malloc(sizeof(PyArray_DatetimeDTypeMetaData));
+ if (data1 == NULL) {
+ return -1;
+ }
+ data2 = PyArray_malloc(sizeof(PyArray_DatetimeDTypeMetaData));
+ if (data2 == NULL) {
+ PyArray_free(data1);
+ return -1;
+ }
+
+ /* Initialize the base aux data */
+ memset(data1, 0, sizeof(PyArray_DatetimeDTypeMetaData));
+ memset(data2, 0, sizeof(PyArray_DatetimeDTypeMetaData));
+ data1->base.free = (NpyAuxData_FreeFunc *)PyArray_free;
+ data2->base.free = (NpyAuxData_FreeFunc *)PyArray_free;
+ data1->base.clone = datetime_dtype_metadata_clone;
+ data2->base.clone = datetime_dtype_metadata_clone;
+
+ /* Set to the default metadata */
+ data1->meta.base = NPY_DATETIME_DEFAULTUNIT;
+ data1->meta.num = 1;
+ data2->meta.base = NPY_DATETIME_DEFAULTUNIT;
+ data2->meta.num = 1;
+
+ _builtin_descrs[NPY_DATETIME]->c_metadata = (NpyAuxData *)data1;
+ _builtin_descrs[NPY_TIMEDELTA]->c_metadata = (NpyAuxData *)data1;
+
+ return 0;
+}
/*
*****************************************************************************
@@ -3991,6 +4018,10 @@ PyArray_DescrFromType(int type)
*/
+/*
+ * This function is called during numpy module initialization,
+ * and is used to initialize internal dtype tables.
+ */
NPY_NO_EXPORT int
set_typeinfo(PyObject *dict)
{
@@ -4048,6 +4079,10 @@ set_typeinfo(PyObject *dict)
/**end repeat**/
+ if (initialize_builtin_datetime_metadata() < 0) {
+ return -1;
+ }
+
for (i = 0; i < _MAX_LETTER; i++) {
_letter_to_num[i] = NPY_NTYPES;
}
diff --git a/numpy/core/src/multiarray/datetime.c b/numpy/core/src/multiarray/datetime.c
index 08cbb9e04..6a209635f 100644
--- a/numpy/core/src/multiarray/datetime.c
+++ b/numpy/core/src/multiarray/datetime.c
@@ -31,26 +31,26 @@
* This is called during module initialization
*/
NPY_NO_EXPORT void
-numpy_pydatetime_import()
+numpy_pydatetime_import(void)
{
PyDateTime_IMPORT;
}
/* Exported as DATETIMEUNITS in multiarraymodule.c */
NPY_NO_EXPORT char *_datetime_strings[NPY_DATETIME_NUMUNITS] = {
- NPY_STR_Y,
- NPY_STR_M,
- NPY_STR_W,
- NPY_STR_D,
- NPY_STR_h,
- NPY_STR_m,
- NPY_STR_s,
- NPY_STR_ms,
- NPY_STR_us,
- NPY_STR_ns,
- NPY_STR_ps,
- NPY_STR_fs,
- NPY_STR_as,
+ "Y",
+ "M",
+ "W",
+ "D",
+ "h",
+ "m",
+ "s",
+ "ms",
+ "us",
+ "ns",
+ "ps",
+ "fs",
+ "as",
"generic"
};
@@ -227,7 +227,7 @@ set_datetimestruct_days(npy_int64 days, npy_datetimestruct *dts)
for (i = 0; i < 12; ++i) {
if (days < month_lengths[i]) {
dts->month = i + 1;
- dts->day = days + 1;
+ dts->day = (int)days + 1;
return;
}
else {
@@ -480,7 +480,7 @@ convert_datetime_to_datetimestruct(PyArray_DatetimeMetaData *meta,
set_datetimestruct_days((dt - (perday-1)) / perday, out);
dt = (perday-1) + (dt + 1) % perday;
}
- out->hour = dt;
+ out->hour = (int)dt;
break;
case NPY_FR_m:
@@ -494,8 +494,8 @@ convert_datetime_to_datetimestruct(PyArray_DatetimeMetaData *meta,
set_datetimestruct_days((dt - (perday-1)) / perday, out);
dt = (perday-1) + (dt + 1) % perday;
}
- out->hour = dt / 60;
- out->min = dt % 60;
+ out->hour = (int)(dt / 60);
+ out->min = (int)(dt % 60);
break;
case NPY_FR_s:
@@ -509,9 +509,9 @@ convert_datetime_to_datetimestruct(PyArray_DatetimeMetaData *meta,
set_datetimestruct_days((dt - (perday-1)) / perday, out);
dt = (perday-1) + (dt + 1) % perday;
}
- out->hour = dt / (60*60);
- out->min = (dt / 60) % 60;
- out->sec = dt % 60;
+ out->hour = (int)(dt / (60*60));
+ out->min = (int)((dt / 60) % 60);
+ out->sec = (int)(dt % 60);
break;
case NPY_FR_ms:
@@ -525,10 +525,10 @@ convert_datetime_to_datetimestruct(PyArray_DatetimeMetaData *meta,
set_datetimestruct_days((dt - (perday-1)) / perday, out);
dt = (perday-1) + (dt + 1) % perday;
}
- out->hour = dt / (60*60*1000LL);
- out->min = (dt / (60*1000LL)) % 60;
- out->sec = (dt / 1000LL) % 60;
- out->us = (dt % 1000LL) * 1000;
+ out->hour = (int)(dt / (60*60*1000LL));
+ out->min = (int)((dt / (60*1000LL)) % 60);
+ out->sec = (int)((dt / 1000LL) % 60);
+ out->us = (int)((dt % 1000LL) * 1000);
break;
case NPY_FR_us:
@@ -542,10 +542,10 @@ convert_datetime_to_datetimestruct(PyArray_DatetimeMetaData *meta,
set_datetimestruct_days((dt - (perday-1)) / perday, out);
dt = (perday-1) + (dt + 1) % perday;
}
- out->hour = dt / (60*60*1000000LL);
- out->min = (dt / (60*1000000LL)) % 60;
- out->sec = (dt / 1000000LL) % 60;
- out->us = dt % 1000000LL;
+ out->hour = (int)(dt / (60*60*1000000LL));
+ out->min = (int)((dt / (60*1000000LL)) % 60);
+ out->sec = (int)((dt / 1000000LL) % 60);
+ out->us = (int)(dt % 1000000LL);
break;
case NPY_FR_ns:
@@ -559,11 +559,11 @@ convert_datetime_to_datetimestruct(PyArray_DatetimeMetaData *meta,
set_datetimestruct_days((dt - (perday-1)) / perday, out);
dt = (perday-1) + (dt + 1) % perday;
}
- out->hour = dt / (60*60*1000000000LL);
- out->min = (dt / (60*1000000000LL)) % 60;
- out->sec = (dt / 1000000000LL) % 60;
- out->us = (dt / 1000LL) % 1000000LL;
- out->ps = (dt % 1000LL) * 1000;
+ out->hour = (int)(dt / (60*60*1000000000LL));
+ out->min = (int)((dt / (60*1000000000LL)) % 60);
+ out->sec = (int)((dt / 1000000000LL) % 60);
+ out->us = (int)((dt / 1000LL) % 1000000LL);
+ out->ps = (int)((dt % 1000LL) * 1000);
break;
case NPY_FR_ps:
@@ -577,22 +577,22 @@ convert_datetime_to_datetimestruct(PyArray_DatetimeMetaData *meta,
set_datetimestruct_days((dt - (perday-1)) / perday, out);
dt = (perday-1) + (dt + 1) % perday;
}
- out->hour = dt / (60*60*1000000000000LL);
- out->min = (dt / (60*1000000000000LL)) % 60;
- out->sec = (dt / 1000000000000LL) % 60;
- out->us = (dt / 1000000LL) % 1000000LL;
- out->ps = dt % 1000000LL;
+ out->hour = (int)(dt / (60*60*1000000000000LL));
+ out->min = (int)((dt / (60*1000000000000LL)) % 60);
+ out->sec = (int)((dt / 1000000000000LL) % 60);
+ out->us = (int)((dt / 1000000LL) % 1000000LL);
+ out->ps = (int)(dt % 1000000LL);
break;
case NPY_FR_fs:
/* entire range is only +- 2.6 hours */
if (dt >= 0) {
- out->hour = dt / (60*60*1000000000000000LL);
- out->min = (dt / (60*1000000000000000LL)) % 60;
- out->sec = (dt / 1000000000000000LL) % 60;
- out->us = (dt / 1000000000LL) % 1000000LL;
- out->ps = (dt / 1000LL) % 1000000LL;
- out->as = (dt % 1000LL) * 1000;
+ out->hour = (int)(dt / (60*60*1000000000000000LL));
+ out->min = (int)((dt / (60*1000000000000000LL)) % 60);
+ out->sec = (int)((dt / 1000000000000000LL) % 60);
+ out->us = (int)((dt / 1000000000LL) % 1000000LL);
+ out->ps = (int)((dt / 1000LL) % 1000000LL);
+ out->as = (int)((dt % 1000LL) * 1000);
}
else {
npy_datetime minutes;
@@ -605,20 +605,20 @@ convert_datetime_to_datetimestruct(PyArray_DatetimeMetaData *meta,
}
/* Offset the negative minutes */
add_minutes_to_datetimestruct(out, minutes);
- out->sec = (dt / 1000000000000000LL) % 60;
- out->us = (dt / 1000000000LL) % 1000000LL;
- out->ps = (dt / 1000LL) % 1000000LL;
- out->as = (dt % 1000LL) * 1000;
+ out->sec = (int)((dt / 1000000000000000LL) % 60);
+ out->us = (int)((dt / 1000000000LL) % 1000000LL);
+ out->ps = (int)((dt / 1000LL) % 1000000LL);
+ out->as = (int)((dt % 1000LL) * 1000);
}
break;
case NPY_FR_as:
/* entire range is only +- 9.2 seconds */
if (dt >= 0) {
- out->sec = (dt / 1000000000000000000LL) % 60;
- out->us = (dt / 1000000000000LL) % 1000000LL;
- out->ps = (dt / 1000000LL) % 1000000LL;
- out->as = dt % 1000000LL;
+ out->sec = (int)((dt / 1000000000000000000LL) % 60);
+ out->us = (int)((dt / 1000000000000LL) % 1000000LL);
+ out->ps = (int)((dt / 1000000LL) % 1000000LL);
+ out->as = (int)(dt % 1000000LL);
}
else {
npy_datetime seconds;
@@ -631,9 +631,9 @@ convert_datetime_to_datetimestruct(PyArray_DatetimeMetaData *meta,
}
/* Offset the negative seconds */
add_seconds_to_datetimestruct(out, seconds);
- out->us = (dt / 1000000000000LL) % 1000000LL;
- out->ps = (dt / 1000000LL) % 1000000LL;
- out->as = dt % 1000000LL;
+ out->us = (int)((dt / 1000000000000LL) % 1000000LL);
+ out->ps = (int)((dt / 1000000LL) % 1000000LL);
+ out->as = (int)(dt % 1000000LL);
}
break;
@@ -692,7 +692,6 @@ create_datetime_dtype(int type_num, PyArray_DatetimeMetaData *meta)
{
PyArray_Descr *dtype = NULL;
PyArray_DatetimeMetaData *dt_data;
- PyObject *metacobj = NULL;
/* Create a default datetime or timedelta */
if (type_num == NPY_DATETIME || type_num == NPY_TIMEDELTA) {
@@ -709,44 +708,11 @@ create_datetime_dtype(int type_num, PyArray_DatetimeMetaData *meta)
return NULL;
}
- /*
- * Remove any reference to old metadata dictionary
- * And create a new one for this new dtype
- */
- Py_XDECREF(dtype->metadata);
- dtype->metadata = PyDict_New();
- if (dtype->metadata == NULL) {
- Py_DECREF(dtype);
- return NULL;
- }
-
- /* Create a metadata capsule to copy the provided metadata */
- dt_data = PyArray_malloc(sizeof(PyArray_DatetimeMetaData));
- if (dt_data == NULL) {
- Py_DECREF(dtype);
- PyErr_NoMemory();
- return NULL;
- }
+ dt_data = &(((PyArray_DatetimeDTypeMetaData *)dtype->c_metadata)->meta);
/* Copy the metadata */
*dt_data = *meta;
- /* Allocate a capsule for it (this claims ownership of dt_data) */
- metacobj = NpyCapsule_FromVoidPtr((void *)dt_data, simple_capsule_dtor);
- if (metacobj == NULL) {
- Py_DECREF(dtype);
- return NULL;
- }
-
- /* Set the metadata object in the dictionary. */
- if (PyDict_SetItemString(dtype->metadata, NPY_METADATA_DTSTR,
- metacobj) < 0) {
- Py_DECREF(dtype);
- Py_DECREF(metacobj);
- return NULL;
- }
- Py_DECREF(metacobj);
-
return dtype;
}
@@ -763,58 +729,19 @@ create_datetime_dtype_with_unit(int type_num, NPY_DATETIMEUNIT unit)
}
/*
- * This function returns the a new reference to the
- * capsule with the datetime metadata.
- */
-NPY_NO_EXPORT PyObject *
-get_datetime_metacobj_from_dtype(PyArray_Descr *dtype)
-{
- PyObject *metacobj;
-
- /* Check that the dtype has metadata */
- if (dtype->metadata == NULL) {
- PyErr_SetString(PyExc_TypeError,
- "Datetime type object is invalid, lacks metadata");
- return NULL;
- }
-
- /* Check that the dtype has unit metadata */
- metacobj = PyDict_GetItemString(dtype->metadata, NPY_METADATA_DTSTR);
- if (metacobj == NULL) {
- PyErr_SetString(PyExc_TypeError,
- "Datetime type object is invalid, lacks unit metadata");
- return NULL;
- }
-
- Py_INCREF(metacobj);
- return metacobj;
-}
-
-/*
* This function returns a pointer to the DateTimeMetaData
* contained within the provided datetime dtype.
*/
NPY_NO_EXPORT PyArray_DatetimeMetaData *
get_datetime_metadata_from_dtype(PyArray_Descr *dtype)
{
- PyObject *metacobj;
- PyArray_DatetimeMetaData *meta = NULL;
-
- metacobj = get_datetime_metacobj_from_dtype(dtype);
- if (metacobj == NULL) {
- return NULL;
- }
-
- /* Check that the dtype has an NpyCapsule for the metadata */
- meta = (PyArray_DatetimeMetaData *)NpyCapsule_AsVoidPtr(metacobj);
- Py_DECREF(metacobj);
- if (meta == NULL) {
+ if (!PyDataType_ISDATETIME(dtype)) {
PyErr_SetString(PyExc_TypeError,
- "Datetime type object is invalid, unit metadata is corrupt");
+ "cannot get datetime metadata from non-datetime type");
return NULL;
}
- return meta;
+ return &(((PyArray_DatetimeDTypeMetaData *)dtype->c_metadata)->meta);
}
/*
@@ -1741,57 +1668,6 @@ units_overflow: {
}
/*
- * Computes the GCD of the two date-time metadata values. Raises
- * an exception if there is no reasonable GCD, such as with
- * years and days.
- *
- * Returns a capsule with the GCD metadata.
- */
-NPY_NO_EXPORT PyObject *
-compute_datetime_metadata_greatest_common_divisor_capsule(
- PyArray_Descr *type1,
- PyArray_Descr *type2,
- int strict_with_nonlinear_units1,
- int strict_with_nonlinear_units2)
-{
- PyArray_DatetimeMetaData *meta1, *meta2, *dt_data;
-
- if ((type1->type_num != NPY_DATETIME &&
- type1->type_num != NPY_TIMEDELTA) ||
- (type2->type_num != NPY_DATETIME &&
- type2->type_num != NPY_TIMEDELTA)) {
- PyErr_SetString(PyExc_TypeError,
- "Require datetime types for metadata "
- "greatest common divisor operation");
- return NULL;
- }
-
- meta1 = get_datetime_metadata_from_dtype(type1);
- if (meta1 == NULL) {
- return NULL;
- }
- meta2 = get_datetime_metadata_from_dtype(type2);
- if (meta2 == NULL) {
- return NULL;
- }
-
- /* Create and return the metadata capsule */
- dt_data = PyArray_malloc(sizeof(PyArray_DatetimeMetaData));
- if (dt_data == NULL) {
- return PyErr_NoMemory();
- }
-
- if (compute_datetime_metadata_greatest_common_divisor(meta1, meta2,
- dt_data, strict_with_nonlinear_units1,
- strict_with_nonlinear_units2) < 0) {
- PyArray_free(dt_data);
- return NULL;
- }
-
- return NpyCapsule_FromVoidPtr((void *)dt_data, simple_capsule_dtor);
-}
-
-/*
* Both type1 and type2 must be either NPY_DATETIME or NPY_TIMEDELTA.
* Applies the type promotion rules between the two types, returning
* the promoted type.
@@ -1800,7 +1676,6 @@ NPY_NO_EXPORT PyArray_Descr *
datetime_type_promotion(PyArray_Descr *type1, PyArray_Descr *type2)
{
int type_num1, type_num2;
- PyObject *gcdmeta;
PyArray_Descr *dtype;
int is_datetime;
@@ -1809,50 +1684,28 @@ datetime_type_promotion(PyArray_Descr *type1, PyArray_Descr *type2)
is_datetime = (type_num1 == NPY_DATETIME || type_num2 == NPY_DATETIME);
- /*
- * Get the metadata GCD, being strict about nonlinear units for
- * timedelta and relaxed for datetime.
- */
- gcdmeta = compute_datetime_metadata_greatest_common_divisor_capsule(
- type1, type2,
- type_num1 == NPY_TIMEDELTA,
- type_num2 == NPY_TIMEDELTA);
- if (gcdmeta == NULL) {
- return NULL;
- }
-
/* Create a DATETIME or TIMEDELTA dtype */
dtype = PyArray_DescrNewFromType(is_datetime ? NPY_DATETIME :
NPY_TIMEDELTA);
if (dtype == NULL) {
- Py_DECREF(gcdmeta);
return NULL;
}
- /* Replace the metadata dictionary */
- Py_XDECREF(dtype->metadata);
- dtype->metadata = PyDict_New();
- if (dtype->metadata == NULL) {
- Py_DECREF(dtype);
- Py_DECREF(gcdmeta);
- return NULL;
- }
-
- /* Set the metadata object in the dictionary. */
- if (PyDict_SetItemString(dtype->metadata, NPY_METADATA_DTSTR,
- gcdmeta) < 0) {
+ /*
+ * Get the metadata GCD, being strict about nonlinear units for
+ * timedelta and relaxed for datetime.
+ */
+ if (compute_datetime_metadata_greatest_common_divisor(
+ get_datetime_metadata_from_dtype(type1),
+ get_datetime_metadata_from_dtype(type2),
+ get_datetime_metadata_from_dtype(dtype),
+ type_num1 == NPY_TIMEDELTA,
+ type_num2 == NPY_TIMEDELTA) < 0) {
Py_DECREF(dtype);
- Py_DECREF(gcdmeta);
return NULL;
}
- Py_DECREF(gcdmeta);
return dtype;
-
-
- PyErr_SetString(PyExc_RuntimeError,
- "Called datetime_type_promotion on non-datetype type");
- return NULL;
}
/*
@@ -2021,25 +1874,6 @@ convert_datetime_metadata_tuple_to_datetime_metadata(PyObject *tuple,
}
/*
- * Converts a metadata tuple into a datetime metadata capsule.
- */
-NPY_NO_EXPORT PyObject *
-convert_datetime_metadata_tuple_to_metacobj(PyObject *tuple)
-{
- PyArray_DatetimeMetaData *dt_data;
-
- dt_data = PyArray_malloc(sizeof(PyArray_DatetimeMetaData));
-
- if (convert_datetime_metadata_tuple_to_datetime_metadata(
- tuple, dt_data) < 0) {
- PyArray_free(dt_data);
- return NULL;
- }
-
- return NpyCapsule_FromVoidPtr((void *)dt_data, simple_capsule_dtor);
-}
-
-/*
* Converts an input object into datetime metadata. The input
* may be either a string or a tuple.
*
@@ -2485,8 +2319,8 @@ get_tzoffset_from_pytzinfo(PyObject *timezone_obj, npy_datetimestruct *dts)
Py_DECREF(loc_dt);
/* Calculate the tzoffset as the difference between the datetimes */
- return get_datetimestruct_minutes(&loc_dts) -
- get_datetimestruct_minutes(dts);
+ return (int)(get_datetimestruct_minutes(&loc_dts) -
+ get_datetimestruct_minutes(dts));
}
/*
diff --git a/numpy/core/src/multiarray/datetime_strings.c b/numpy/core/src/multiarray/datetime_strings.c
index e9e344ae2..cfeabc783 100644
--- a/numpy/core/src/multiarray/datetime_strings.c
+++ b/numpy/core/src/multiarray/datetime_strings.c
@@ -328,7 +328,7 @@ convert_datetimestruct_local_to_utc(npy_datetimestruct *out_dts_utc,
* Returns 0 on success, -1 on failure.
*/
NPY_NO_EXPORT int
-parse_iso_8601_datetime(char *str, int len,
+parse_iso_8601_datetime(char *str, Py_ssize_t len,
NPY_DATETIMEUNIT unit,
NPY_CASTING casting,
npy_datetimestruct *out,
@@ -338,7 +338,8 @@ parse_iso_8601_datetime(char *str, int len,
{
int year_leap = 0;
int i, numdigits;
- char *substr, sublen;
+ char *substr;
+ Py_ssize_t sublen;
NPY_DATETIMEUNIT bestunit;
/* Initialize the output to all zeros */
diff --git a/numpy/core/src/multiarray/datetime_strings.h b/numpy/core/src/multiarray/datetime_strings.h
index f27856b89..4280f6de4 100644
--- a/numpy/core/src/multiarray/datetime_strings.h
+++ b/numpy/core/src/multiarray/datetime_strings.h
@@ -37,7 +37,7 @@
* Returns 0 on success, -1 on failure.
*/
NPY_NO_EXPORT int
-parse_iso_8601_datetime(char *str, int len,
+parse_iso_8601_datetime(char *str, Py_ssize_t len,
NPY_DATETIMEUNIT unit,
NPY_CASTING casting,
npy_datetimestruct *out,
diff --git a/numpy/core/src/multiarray/descriptor.c b/numpy/core/src/multiarray/descriptor.c
index e58b268c3..2d5efc437 100644
--- a/numpy/core/src/multiarray/descriptor.c
+++ b/numpy/core/src/multiarray/descriptor.c
@@ -1482,7 +1482,7 @@ error:
* If a mistake is made in reference counting, deallocation on these
* builtins will be attempted leading to problems.
*
- * This let's us deal with all PyArray_Descr objects using reference
+ * This lets us deal with all PyArray_Descr objects using reference
* counting (regardless of whether they are statically or dynamically
* allocated).
*/
@@ -1554,6 +1554,8 @@ arraydescr_dealloc(PyArray_Descr *self)
PyArray_free(self->subarray);
}
Py_XDECREF(self->metadata);
+ NPY_AUXDATA_FREE(self->c_metadata);
+ self->c_metadata = NULL;
Py_TYPE(self)->tp_free((PyObject *)self);
}
@@ -1989,23 +1991,6 @@ static PyGetSetDef arraydescr_getsets[] = {
{NULL, NULL, NULL, NULL, NULL},
};
-static int
-_invalid_metadata_check(PyObject *metadata)
-{
- PyObject *res;
-
- /* borrowed reference */
- res = PyDict_GetItemString(metadata, NPY_METADATA_DTSTR);
- if (res == NULL) {
- return 0;
- }
- else {
- PyErr_SetString(PyExc_ValueError,
- "cannot set " NPY_METADATA_DTSTR "in dtype metadata");
- return 1;
- }
-}
-
static PyObject *
arraydescr_new(PyTypeObject *NPY_UNUSED(subtype),
PyObject *args, PyObject *kwds)
@@ -2026,10 +2011,6 @@ arraydescr_new(PyTypeObject *NPY_UNUSED(subtype),
return NULL;
}
- if ((metadata != NULL) && (_invalid_metadata_check(metadata))) {
- return NULL;
- }
-
if (align) {
if (!PyArray_DescrAlignConverter(odescr, &conv)) {
return NULL;
@@ -2105,14 +2086,14 @@ _get_pickleabletype_from_datetime_metadata(PyArray_Descr *dtype)
return NULL;
}
- /* Make a cleaned copy of the metadata dictionary */
- newdict = PyDict_Copy(dtype->metadata);
- if (newdict == NULL) {
- Py_DECREF(ret);
- return NULL;
+ /* Store the metadata dictionary */
+ if (dtype->metadata != NULL) {
+ Py_INCREF(dtype->metadata);
+ PyTuple_SET_ITEM(ret, 0, dtype->metadata);
+ } else {
+ Py_INCREF(Py_None);
+ PyTuple_SET_ITEM(ret, 0, Py_None);
}
- PyDict_DelItemString(newdict, NPY_METADATA_DTSTR);
- PyTuple_SET_ITEM(ret, 0, newdict);
/* Convert the datetime metadata into a tuple */
meta = get_datetime_metadata_from_dtype(dtype);
@@ -2193,28 +2174,27 @@ arraydescr_reduce(PyArray_Descr *self, PyObject *NPY_UNUSED(args))
endian = '>';
}
}
- if (self->metadata) {
+ if (PyDataType_ISDATETIME(self)) {
+ PyObject *newobj;
state = PyTuple_New(9);
PyTuple_SET_ITEM(state, 0, PyInt_FromLong(version));
- if (PyDataType_ISDATETIME(self)) {
- PyObject *newobj;
- /* Handle CObject in NPY_METADATA_DTSTR key separately */
- /*
- * newobj is a tuple of cleaned metadata dictionary
- * and tuple of date_time info (str, num)
- */
- newobj = _get_pickleabletype_from_datetime_metadata(self);
- if (newobj == NULL) {
- Py_DECREF(state);
- Py_DECREF(ret);
- return NULL;
- }
- PyTuple_SET_ITEM(state, 8, newobj);
- }
- else {
- Py_INCREF(self->metadata);
- PyTuple_SET_ITEM(state, 8, self->metadata);
+ /*
+ * newobj is a tuple of the Python metadata dictionary
+ * and tuple of date_time info (str, num)
+ */
+ newobj = _get_pickleabletype_from_datetime_metadata(self);
+ if (newobj == NULL) {
+ Py_DECREF(state);
+ Py_DECREF(ret);
+ return NULL;
}
+ PyTuple_SET_ITEM(state, 8, newobj);
+ }
+ else if (self->metadata) {
+ state = PyTuple_New(9);
+ PyTuple_SET_ITEM(state, 0, PyInt_FromLong(version));
+ Py_INCREF(self->metadata);
+ PyTuple_SET_ITEM(state, 8, self->metadata);
}
else { /* Use version 3 pickle format */
state = PyTuple_New(8);
@@ -2526,29 +2506,30 @@ arraydescr_setstate(PyArray_Descr *self, PyObject *args)
self->flags = _descr_find_object(self);
}
+ /*
+ * We have a borrowed reference to metadata so no need
+ * to alter reference count when throwing away Py_None.
+ */
+ if (metadata == Py_None) {
+ metadata = NULL;
+ }
+
Py_XDECREF(self->metadata);
- if (PyDataType_ISDATETIME(self)
- && (metadata != Py_None)
- && (metadata != NULL)) {
- PyObject *cobj;
+ if (PyDataType_ISDATETIME(self) && (metadata != NULL)) {
+ PyArray_DatetimeMetaData *dt_data;
+
+ /* The Python metadata */
self->metadata = PyTuple_GET_ITEM(metadata, 0);
- Py_INCREF(self->metadata);
- cobj = convert_datetime_metadata_tuple_to_metacobj(
- PyTuple_GET_ITEM(metadata, 1));
- if (cobj == NULL) {
+
+ /* The datetime metadata */
+ dt_data = &(((PyArray_DatetimeDTypeMetaData *)self->c_metadata)->meta);
+ if (convert_datetime_metadata_tuple_to_datetime_metadata(
+ PyTuple_GET_ITEM(metadata, 1),
+ dt_data) < 0) {
return NULL;
}
- PyDict_SetItemString(self->metadata, NPY_METADATA_DTSTR, cobj);
- Py_DECREF(cobj);
}
else {
- /*
- * We have a borrowed reference to metadata so no need
- * to alter reference count
- */
- if (metadata == Py_None) {
- metadata = NULL;
- }
self->metadata = metadata;
Py_XINCREF(metadata);
}
diff --git a/numpy/core/src/multiarray/multiarraymodule.c b/numpy/core/src/multiarray/multiarraymodule.c
index 6cbdf2eb9..7a657d8b9 100644
--- a/numpy/core/src/multiarray/multiarraymodule.c
+++ b/numpy/core/src/multiarray/multiarraymodule.c
@@ -4132,10 +4132,6 @@ PyMODINIT_FUNC initmultiarray(void) {
PyDict_SetItemString(d, "__version__", s);
Py_DECREF(s);
- s = PyUString_InternFromString(NPY_METADATA_DTSTR);
- PyDict_SetItemString(d, "METADATA_DTSTR", s);
- Py_DECREF(s);
-
/* FIXME
* There is no error handling here
*/
diff --git a/numpy/core/src/multiarray/scalarapi.c b/numpy/core/src/multiarray/scalarapi.c
index f3b2eb16e..8b61c797d 100644
--- a/numpy/core/src/multiarray/scalarapi.c
+++ b/numpy/core/src/multiarray/scalarapi.c
@@ -532,38 +532,19 @@ PyArray_DescrFromScalar(PyObject *sc)
}
if (PyArray_IsScalar(sc, Datetime) || PyArray_IsScalar(sc, Timedelta)) {
- PyObject *cobj;
PyArray_DatetimeMetaData *dt_data;
- dt_data = PyArray_malloc(sizeof(PyArray_DatetimeMetaData));
if (PyArray_IsScalar(sc, Datetime)) {
descr = PyArray_DescrNewFromType(NPY_DATETIME);
- memcpy(dt_data, &((PyDatetimeScalarObject *)sc)->obmeta,
- sizeof(PyArray_DatetimeMetaData));
}
else {
/* Timedelta */
descr = PyArray_DescrNewFromType(NPY_TIMEDELTA);
- memcpy(dt_data, &((PyTimedeltaScalarObject *)sc)->obmeta,
- sizeof(PyArray_DatetimeMetaData));
- }
- cobj = NpyCapsule_FromVoidPtr((void *)dt_data, simple_capsule_dtor);
-
- /* Add correct meta-data to the data-type */
- if (descr == NULL) {
- Py_DECREF(cobj);
- return NULL;
- }
- Py_XDECREF(descr->metadata);
- if ((descr->metadata = PyDict_New()) == NULL) {
- Py_DECREF(descr);
- Py_DECREF(cobj);
- return NULL;
}
+ dt_data = &(((PyArray_DatetimeDTypeMetaData *)descr->c_metadata)->meta);
+ memcpy(dt_data, &((PyDatetimeScalarObject *)sc)->obmeta,
+ sizeof(PyArray_DatetimeMetaData));
- /* Assume this sets a new reference to cobj */
- PyDict_SetItemString(descr->metadata, NPY_METADATA_DTSTR, cobj);
- Py_DECREF(cobj);
return descr;
}
@@ -676,14 +657,9 @@ PyArray_Scalar(void *data, PyArray_Descr *descr, PyObject *base)
* We need to copy the resolution information over to the scalar
* Get the void * from the metadata dictionary
*/
- PyObject *cobj;
PyArray_DatetimeMetaData *dt_data;
- cobj = PyDict_GetItemString(descr->metadata, NPY_METADATA_DTSTR);
-/* FIXME
- * There is no error handling here.
- */
- dt_data = NpyCapsule_AsVoidPtr(cobj);
+ dt_data = &(((PyArray_DatetimeDTypeMetaData *)descr->c_metadata)->meta);
memcpy(&(((PyDatetimeScalarObject *)obj)->obmeta), dt_data,
sizeof(PyArray_DatetimeMetaData));
}
diff --git a/numpy/core/src/umath/ufunc_type_resolution.c b/numpy/core/src/umath/ufunc_type_resolution.c
index 83703328a..3c697f1ee 100644
--- a/numpy/core/src/umath/ufunc_type_resolution.c
+++ b/numpy/core/src/umath/ufunc_type_resolution.c
@@ -508,38 +508,6 @@ PyUFunc_AbsoluteTypeResolver(PyUFuncObject *ufunc,
}
}
-
-/*
- * This function returns the a new reference to the
- * capsule with the datetime metadata.
- *
- * NOTE: This function is copied from datetime.c in multiarray,
- * because umath and multiarray are not linked together.
- */
-static PyObject *
-get_datetime_metacobj_from_dtype(PyArray_Descr *dtype)
-{
- PyObject *metacobj;
-
- /* Check that the dtype has metadata */
- if (dtype->metadata == NULL) {
- PyErr_SetString(PyExc_TypeError,
- "Datetime type object is invalid, lacks metadata");
- return NULL;
- }
-
- /* Check that the dtype has unit metadata */
- metacobj = PyDict_GetItemString(dtype->metadata, NPY_METADATA_DTSTR);
- if (metacobj == NULL) {
- PyErr_SetString(PyExc_TypeError,
- "Datetime type object is invalid, lacks unit metadata");
- return NULL;
- }
-
- Py_INCREF(metacobj);
- return metacobj;
-}
-
/*
* Creates a new NPY_TIMEDELTA dtype, copying the datetime metadata
* from the given dtype.
@@ -551,31 +519,20 @@ static PyArray_Descr *
timedelta_dtype_with_copied_meta(PyArray_Descr *dtype)
{
PyArray_Descr *ret;
- PyObject *metacobj;
+ PyArray_DatetimeMetaData *dst, *src;
+ PyArray_DatetimeDTypeMetaData *dst_dtmd, *src_dtmd;
ret = PyArray_DescrNewFromType(NPY_TIMEDELTA);
if (ret == NULL) {
return NULL;
}
- Py_XDECREF(ret->metadata);
- ret->metadata = PyDict_New();
- if (ret->metadata == NULL) {
- Py_DECREF(ret);
- return NULL;
- }
- metacobj = get_datetime_metacobj_from_dtype(dtype);
- if (metacobj == NULL) {
- Py_DECREF(ret);
- return NULL;
- }
+ src_dtmd = ((PyArray_DatetimeDTypeMetaData *)dtype->c_metadata);
+ dst_dtmd = ((PyArray_DatetimeDTypeMetaData *)ret->c_metadata);
+ src = &(src_dtmd->meta);
+ dst = &(dst_dtmd->meta);
- if (PyDict_SetItemString(ret->metadata, NPY_METADATA_DTSTR,
- metacobj) < 0) {
- Py_DECREF(metacobj);
- Py_DECREF(ret);
- return NULL;
- }
+ *dst = *src;
return ret;
}
diff --git a/numpy/core/tests/test_datetime.py b/numpy/core/tests/test_datetime.py
index f062645d2..aaafce012 100644
--- a/numpy/core/tests/test_datetime.py
+++ b/numpy/core/tests/test_datetime.py
@@ -529,9 +529,23 @@ class TestDateTime(TestCase):
def test_pickle(self):
# Check that pickle roundtripping works
dt = np.dtype('M8[7D]')
- assert_equal(dt, pickle.loads(pickle.dumps(dt)))
+ assert_equal(pickle.loads(pickle.dumps(dt)), dt)
dt = np.dtype('M8[W]')
- assert_equal(dt, pickle.loads(pickle.dumps(dt)))
+ assert_equal(pickle.loads(pickle.dumps(dt)), dt)
+
+ # Check that loading pickles from 1.6 works
+ pkl = "cnumpy\ndtype\np0\n(S'M8'\np1\nI0\nI1\ntp2\nRp3\n" + \
+ "(I4\nS'<'\np4\nNNNI-1\nI-1\nI0\n((dp5\n(S'D'\np6\n" + \
+ "I7\nI1\nI1\ntp7\ntp8\ntp9\nb."
+ assert_equal(pickle.loads(pkl), np.dtype('<M8[7D]'))
+ pkl = "cnumpy\ndtype\np0\n(S'M8'\np1\nI0\nI1\ntp2\nRp3\n" + \
+ "(I4\nS'<'\np4\nNNNI-1\nI-1\nI0\n((dp5\n(S'W'\np6\n" + \
+ "I1\nI1\nI1\ntp7\ntp8\ntp9\nb."
+ assert_equal(pickle.loads(pkl), np.dtype('<M8[W]'))
+ pkl = "cnumpy\ndtype\np0\n(S'M8'\np1\nI0\nI1\ntp2\nRp3\n" + \
+ "(I4\nS'>'\np4\nNNNI-1\nI-1\nI0\n((dp5\n(S'us'\np6\n" + \
+ "I1\nI1\nI1\ntp7\ntp8\ntp9\nb."
+ assert_equal(pickle.loads(pkl), np.dtype('>M8[us]'))
def test_dtype_promotion(self):
# datetime <op> datetime computes the metadata gcd
diff --git a/numpy/lib/type_check.py b/numpy/lib/type_check.py
index edea02b62..c116c7e4a 100644
--- a/numpy/lib/type_check.py
+++ b/numpy/lib/type_check.py
@@ -8,7 +8,6 @@ __all__ = ['iscomplexobj','isrealobj','imag','iscomplex',
import numpy.core.numeric as _nx
from numpy.core.numeric import asarray, asanyarray, array, isnan, \
obj2sctype, zeros
-from numpy.core.multiarray import METADATA_DTSTR
from ufunclike import isneginf, isposinf
_typecodes_by_elsize = 'GDFgdfQqLlIiHhBb?'