summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--numpy/core/include/numpy/ndarraytypes.h9
-rw-r--r--numpy/core/numerictypes.py5
-rw-r--r--numpy/core/src/multiarray/_datetime.h4
-rw-r--r--numpy/core/src/multiarray/arraytypes.c.src1
-rw-r--r--numpy/core/src/multiarray/convert_datatype.c1
-rw-r--r--numpy/core/src/multiarray/datetime.c115
-rw-r--r--numpy/core/src/multiarray/multiarraymodule.c63
-rw-r--r--numpy/core/tests/test_datetime.py7
-rw-r--r--numpy/lib/tests/test_type_check.py8
-rw-r--r--numpy/lib/type_check.py46
10 files changed, 126 insertions, 133 deletions
diff --git a/numpy/core/include/numpy/ndarraytypes.h b/numpy/core/include/numpy/ndarraytypes.h
index 2a21a779e..95bc78d47 100644
--- a/numpy/core/include/numpy/ndarraytypes.h
+++ b/numpy/core/include/numpy/ndarraytypes.h
@@ -676,10 +676,11 @@ typedef struct {
typedef struct {
NPY_DATETIMEUNIT base;
int num;
- int den; /*
- * Converted to 1 on input for now -- an
- * input-only mechanism
- */
+ /*
+ * 'den' is unused, kept here for ABI compatibility with 1.6.
+ * TODO: Remove for 2.0.
+ */
+ int den;
int events;
} PyArray_DatetimeMetaData;
diff --git a/numpy/core/numerictypes.py b/numpy/core/numerictypes.py
index 08907541a..5ab874ccb 100644
--- a/numpy/core/numerictypes.py
+++ b/numpy/core/numerictypes.py
@@ -91,9 +91,10 @@ Exported symbols include:
__all__ = ['sctypeDict', 'sctypeNA', 'typeDict', 'typeNA', 'sctypes',
'ScalarType', 'obj2sctype', 'cast', 'nbytes', 'sctype2char',
'maximum_sctype', 'issctype', 'typecodes', 'find_common_type',
- 'issubdtype']
+ 'issubdtype','datetime_data']
-from numpy.core.multiarray import typeinfo, ndarray, array, empty, dtype
+from numpy.core.multiarray import typeinfo, ndarray, array, \
+ empty, dtype, datetime_data
import types as _types
import sys
diff --git a/numpy/core/src/multiarray/_datetime.h b/numpy/core/src/multiarray/_datetime.h
index 331b02824..7f97fd416 100644
--- a/numpy/core/src/multiarray/_datetime.h
+++ b/numpy/core/src/multiarray/_datetime.h
@@ -58,7 +58,7 @@ parse_datetime_unit_from_string(char *str, Py_ssize_t len, char *metastr);
*/
NPY_NO_EXPORT int
convert_datetime_divisor_to_multiple(PyArray_DatetimeMetaData *meta,
- char *metastr);
+ int den, char *metastr);
/*
* Given an the CObject/Capsule datetime metadata object,
@@ -68,7 +68,7 @@ NPY_NO_EXPORT PyObject *
convert_datetime_metadata_to_tuple(PyArray_DatetimeMetaData *meta);
/*
- * Given a tuple representing datetime metadata tuple,
+ * Given a tuple representing datetime metadata,
* returns a CObject/Capsule datetime metadata object.
*/
NPY_NO_EXPORT PyObject *
diff --git a/numpy/core/src/multiarray/arraytypes.c.src b/numpy/core/src/multiarray/arraytypes.c.src
index fde95c4cb..6ca982345 100644
--- a/numpy/core/src/multiarray/arraytypes.c.src
+++ b/numpy/core/src/multiarray/arraytypes.c.src
@@ -3796,7 +3796,6 @@ _init_datetime_descr(PyArray_Descr *descr)
dt_data = _pya_malloc(sizeof(PyArray_DatetimeMetaData));
dt_data->base = NPY_FR_us;
dt_data->num = 1;
- dt_data->den = 1;
dt_data->events = 1;
/* FIXME
diff --git a/numpy/core/src/multiarray/convert_datatype.c b/numpy/core/src/multiarray/convert_datatype.c
index e20e8142d..b033e9587 100644
--- a/numpy/core/src/multiarray/convert_datatype.c
+++ b/numpy/core/src/multiarray/convert_datatype.c
@@ -738,7 +738,6 @@ PyArray_PromoteTypes(PyArray_Descr *type1, PyArray_Descr *type2)
if (meta1->base == meta2->base &&
meta1->num == meta2->num &&
- meta1->den == meta2->den &&
meta1->events == meta2->events) {
Py_INCREF(type1);
return type1;
diff --git a/numpy/core/src/multiarray/datetime.c b/numpy/core/src/multiarray/datetime.c
index 8c35235c3..eb35ce88e 100644
--- a/numpy/core/src/multiarray/datetime.c
+++ b/numpy/core/src/multiarray/datetime.c
@@ -47,27 +47,6 @@ NPY_NO_EXPORT char *_datetime_strings[] = {
NPY_STR_as
};
-static NPY_DATETIMEUNIT _multiples_table[16][4] = {
- {12, 52, 365}, /* NPY_FR_Y */
- {NPY_FR_M, NPY_FR_W, NPY_FR_D},
- {4, 30, 720}, /* NPY_FR_M */
- {NPY_FR_W, NPY_FR_D, NPY_FR_h},
- {5, 7, 168, 10080}, /* NPY_FR_W */
- {NPY_FR_B, NPY_FR_D, NPY_FR_h, NPY_FR_m},
- {24, 1440, 86400}, /* NPY_FR_B */
- {NPY_FR_h, NPY_FR_m, NPY_FR_s},
- {24, 1440, 86400}, /* NPY_FR_D */
- {NPY_FR_h, NPY_FR_m, NPY_FR_s},
- {60, 3600}, /* NPY_FR_h */
- {NPY_FR_m, NPY_FR_s},
- {60, 60000}, /* NPY_FR_m */
- {NPY_FR_s, NPY_FR_ms},
- {1000, 1000000}, /* >=NPY_FR_s */
- {0, 0}
-};
-
-
-
/*
====================================================
== Beginning of section borrowed from mx.DateTime ==
@@ -1006,6 +985,7 @@ parse_datetime_metacobj_from_metastr(char *metastr, Py_ssize_t len)
{
PyArray_DatetimeMetaData *dt_data;
char *substr = metastr, *substrend = NULL;
+ int den = 1;
dt_data = PyArray_malloc(sizeof(PyArray_DatetimeMetaData));
if (dt_data == NULL) {
@@ -1016,7 +996,6 @@ parse_datetime_metacobj_from_metastr(char *metastr, Py_ssize_t len)
if (len == 0) {
dt_data->num = 1;
dt_data->base = NPY_DATETIME_DEFAULTUNIT;
- dt_data->den = 1;
dt_data->events = 1;
}
else {
@@ -1051,7 +1030,7 @@ parse_datetime_metacobj_from_metastr(char *metastr, Py_ssize_t len)
/* Next comes an optional integer denominator */
if (*substr == '/') {
substr++;
- dt_data->den = (int)strtol(substr, &substrend, 10);
+ den = (int)strtol(substr, &substrend, 10);
/* If the '/' exists, there must be a number followed by ']' */
if (substr == substrend || *substrend != ']') {
goto bad_input;
@@ -1059,7 +1038,6 @@ parse_datetime_metacobj_from_metastr(char *metastr, Py_ssize_t len)
substr = substrend + 1;
}
else if (*substr == ']') {
- dt_data->den = 1;
substr++;
}
else {
@@ -1082,8 +1060,9 @@ parse_datetime_metacobj_from_metastr(char *metastr, Py_ssize_t len)
dt_data->events = 1;
}
- if (dt_data->den > 1) {
- if (convert_datetime_divisor_to_multiple(dt_data, metastr) < 0) {
+ if (den != 1) {
+ if (convert_datetime_divisor_to_multiple(
+ dt_data, den, metastr) < 0) {
goto error;
}
}
@@ -1199,6 +1178,26 @@ parse_dtype_from_datetime_typestr(char *typestr, Py_ssize_t len)
return dtype;
}
+static NPY_DATETIMEUNIT _multiples_table[16][4] = {
+ {12, 52, 365}, /* NPY_FR_Y */
+ {NPY_FR_M, NPY_FR_W, NPY_FR_D},
+ {4, 30, 720}, /* NPY_FR_M */
+ {NPY_FR_W, NPY_FR_D, NPY_FR_h},
+ {5, 7, 168, 10080}, /* NPY_FR_W */
+ {NPY_FR_B, NPY_FR_D, NPY_FR_h, NPY_FR_m},
+ {24, 1440, 86400}, /* NPY_FR_B */
+ {NPY_FR_h, NPY_FR_m, NPY_FR_s},
+ {24, 1440, 86400}, /* NPY_FR_D */
+ {NPY_FR_h, NPY_FR_m, NPY_FR_s},
+ {60, 3600}, /* NPY_FR_h */
+ {NPY_FR_m, NPY_FR_s},
+ {60, 60000}, /* NPY_FR_m */
+ {NPY_FR_s, NPY_FR_ms},
+ {1000, 1000000}, /* >=NPY_FR_s */
+ {0, 0}
+};
+
+
/*
* Translate divisors into multiples of smaller units.
@@ -1209,7 +1208,7 @@ parse_dtype_from_datetime_typestr(char *typestr, Py_ssize_t len)
*/
NPY_NO_EXPORT int
convert_datetime_divisor_to_multiple(PyArray_DatetimeMetaData *meta,
- char *metastr)
+ int den, char *metastr)
{
int i, num, ind;
NPY_DATETIMEUNIT *totry;
@@ -1242,8 +1241,8 @@ convert_datetime_divisor_to_multiple(PyArray_DatetimeMetaData *meta,
}
for (i = 0; i < num; i++) {
- q = totry[i] / meta->den;
- r = totry[i] % meta->den;
+ q = totry[i] / den;
+ r = totry[i] % den;
if (r == 0) {
break;
}
@@ -1252,17 +1251,16 @@ convert_datetime_divisor_to_multiple(PyArray_DatetimeMetaData *meta,
if (metastr == NULL) {
PyErr_Format(PyExc_ValueError,
"divisor (%d) is not a multiple of a lower-unit "
- "in datetime metadata", meta->den);
+ "in datetime metadata", den);
}
else {
PyErr_Format(PyExc_ValueError,
"divisor (%d) is not a multiple of a lower-unit "
- "in datetime metadata \"%s\"", meta->den, metastr);
+ "in datetime metadata \"%s\"", den, metastr);
}
return -1;
}
meta->base = baseunit[i];
- meta->den = 1;
meta->num *= q;
return 0;
@@ -1336,7 +1334,7 @@ convert_datetime_metadata_to_tuple(PyArray_DatetimeMetaData *meta)
{
PyObject *dt_tuple;
- dt_tuple = PyTuple_New(4);
+ dt_tuple = PyTuple_New(3);
if (dt_tuple == NULL) {
return NULL;
}
@@ -1346,8 +1344,6 @@ convert_datetime_metadata_to_tuple(PyArray_DatetimeMetaData *meta)
PyTuple_SET_ITEM(dt_tuple, 1,
PyInt_FromLong(meta->num));
PyTuple_SET_ITEM(dt_tuple, 2,
- PyInt_FromLong(meta->den));
- PyTuple_SET_ITEM(dt_tuple, 3,
PyInt_FromLong(meta->events));
return dt_tuple;
@@ -1358,7 +1354,22 @@ convert_datetime_metadata_tuple_to_metacobj(PyObject *tuple)
{
PyArray_DatetimeMetaData *dt_data;
char *basestr = NULL;
- Py_ssize_t len = 0;
+ Py_ssize_t len = 0, tuple_size;
+ int den = 1;
+
+ if (!PyTuple_Check(tuple)) {
+ PyErr_SetString(PyExc_TypeError,
+ "Require tuple for tuple->metacobj conversion");
+ return NULL;
+ }
+
+ tuple_size = PyTuple_GET_SIZE(tuple);
+ if (tuple_size < 3 || tuple_size > 4) {
+ PyErr_SetString(PyExc_TypeError,
+ "Require tuple of size 3 or 4 for "
+ "tuple->metacobj conversion");
+ return NULL;
+ }
if (PyBytes_AsStringAndSize(PyTuple_GET_ITEM(tuple, 0),
&basestr, &len) < 0) {
@@ -1372,13 +1383,26 @@ convert_datetime_metadata_tuple_to_metacobj(PyObject *tuple)
return NULL;
}
- /* Assumes other objects are Python integers */
- dt_data->num = PyInt_AS_LONG(PyTuple_GET_ITEM(tuple, 1));
- dt_data->den = PyInt_AS_LONG(PyTuple_GET_ITEM(tuple, 2));
- dt_data->events = PyInt_AS_LONG(PyTuple_GET_ITEM(tuple, 3));
+ /* Convert the values to longs */
+ dt_data->num = PyInt_AsLong(PyTuple_GET_ITEM(tuple, 1));
+ if (tuple_size == 3) {
+ dt_data->events = PyInt_AsLong(PyTuple_GET_ITEM(tuple, 2));
+ }
+ else {
+ den = PyInt_AsLong(PyTuple_GET_ITEM(tuple, 2));
+ dt_data->events = PyInt_AsLong(PyTuple_GET_ITEM(tuple, 3));
+ }
- if (dt_data->den > 1) {
- if (convert_datetime_divisor_to_multiple(dt_data, NULL) < 0) {
+ if (dt_data->num <= 0 || dt_data->events <= 0 || den <= 0) {
+ PyErr_SetString(PyExc_TypeError,
+ "Invalid tuple values for "
+ "tuple->metacobj conversion");
+ PyArray_free(dt_data);
+ return NULL;
+ }
+
+ if (den != 1) {
+ if (convert_datetime_divisor_to_multiple(dt_data, den, NULL) < 0) {
PyArray_free(dt_data);
return NULL;
}
@@ -1398,7 +1422,7 @@ append_metastr_to_datetime_typestr(PyArray_Descr *self, PyObject *ret)
{
PyObject *tmp;
PyObject *res;
- int num, den, events;
+ int num, events;
char *basestr;
PyArray_DatetimeMetaData *dt_data;
@@ -1409,7 +1433,6 @@ append_metastr_to_datetime_typestr(PyArray_Descr *self, PyObject *ret)
}
num = dt_data->num;
- den = dt_data->den;
events = dt_data->events;
basestr = _datetime_strings[dt_data->base];
@@ -1419,10 +1442,6 @@ append_metastr_to_datetime_typestr(PyArray_Descr *self, PyObject *ret)
else {
tmp = PyUString_FromFormat("%d%s", num, basestr);
}
- if (den != 1) {
- res = PyUString_FromFormat("/%d", den);
- PyUString_ConcatAndDel(&tmp, res);
- }
res = PyUString_FromString("[");
PyUString_ConcatAndDel(&res, tmp);
diff --git a/numpy/core/src/multiarray/multiarraymodule.c b/numpy/core/src/multiarray/multiarraymodule.c
index f121f6147..e7e26e56e 100644
--- a/numpy/core/src/multiarray/multiarraymodule.c
+++ b/numpy/core/src/multiarray/multiarraymodule.c
@@ -44,6 +44,7 @@ NPY_NO_EXPORT int NPY_NUMUSERTYPES = 0;
#include "numpymemoryview.h"
#include "convert_datatype.h"
#include "nditer_pywrap.h"
+#include "_datetime.h"
/* Only here for API compatibility */
NPY_NO_EXPORT PyTypeObject PyBigArray_Type;
@@ -1401,35 +1402,31 @@ _equivalent_fields(PyObject *field1, PyObject *field2) {
}
/*
- * compare the metadata for two date-times
+ * Compare the metadata for two date-times
* return 1 if they are the same
* or 0 if not
*/
static int
-_equivalent_units(PyObject *meta1, PyObject *meta2)
+_equivalent_datetime_units(PyArray_Descr *dtype1, PyArray_Descr *dtype2)
{
- PyObject *cobj1, *cobj2;
PyArray_DatetimeMetaData *data1, *data2;
- /* Same meta object */
- if (meta1 == meta2) {
- return 1;
+ data1 = get_datetime_metadata_from_dtype(dtype1);
+ data2 = get_datetime_metadata_from_dtype(dtype1);
+
+ /* If there's a metadata problem, it doesn't match */
+ if (data1 == NULL || data2 == NULL) {
+ PyErr_Clear();
+ return 0;
}
- cobj1 = PyDict_GetItemString(meta1, NPY_METADATA_DTSTR);
- cobj2 = PyDict_GetItemString(meta2, NPY_METADATA_DTSTR);
- if (cobj1 == cobj2) {
+ /* Same meta object */
+ if (data1 == data2) {
return 1;
}
-/* FIXME
- * There is no err handling here.
- */
- data1 = NpyCapsule_AsVoidPtr(cobj1);
- data2 = NpyCapsule_AsVoidPtr(cobj2);
return ((data1->base == data2->base)
&& (data1->num == data2->num)
- && (data1->den == data2->den)
&& (data1->events == data2->events));
}
@@ -1494,17 +1491,17 @@ PyArray_EquivTypes(PyArray_Descr *typ1, PyArray_Descr *typ2)
return ((typenum1 == typenum2)
&& _equivalent_subarrays(typ1->subarray, typ2->subarray));
}
- if (typenum1 == PyArray_VOID
- || typenum2 == PyArray_VOID) {
+ if (typenum1 == NPY_VOID
+ || typenum2 == NPY_VOID) {
return ((typenum1 == typenum2)
&& _equivalent_fields(typ1->fields, typ2->fields));
}
- if (typenum1 == PyArray_DATETIME
- || typenum1 == PyArray_DATETIME
- || typenum2 == PyArray_TIMEDELTA
- || typenum2 == PyArray_TIMEDELTA) {
+ if (typenum1 == NPY_DATETIME
+ || typenum1 == NPY_DATETIME
+ || typenum2 == NPY_TIMEDELTA
+ || typenum2 == NPY_TIMEDELTA) {
return ((typenum1 == typenum2)
- && _equivalent_units(typ1->metadata, typ2->metadata));
+ && _equivalent_datetime_units(typ1, typ2));
}
return typ1->kind == typ2->kind;
}
@@ -2844,6 +2841,25 @@ finish:
return ret;
}
+static PyObject *
+array_datetime_data(PyObject *NPY_UNUSED(dummy), PyObject *args)
+{
+ PyArray_Descr *dtype;
+ PyArray_DatetimeMetaData *meta;
+
+ if(!PyArg_ParseTuple(args, "O&:datetime_data",
+ PyArray_DescrConverter, &dtype)) {
+ return NULL;
+ }
+
+ meta = get_datetime_metadata_from_dtype(dtype);
+ if (meta == NULL) {
+ return NULL;
+ }
+
+ return convert_datetime_metadata_to_tuple(meta);
+}
+
#if !defined(NPY_PY3K)
static PyObject *
new_buffer(PyObject *NPY_UNUSED(dummy), PyObject *args)
@@ -3464,6 +3480,9 @@ static struct PyMethodDef array_module_methods[] = {
{"result_type",
(PyCFunction)array_result_type,
METH_VARARGS, NULL},
+ {"datetime_data",
+ (PyCFunction)array_datetime_data,
+ METH_VARARGS, NULL},
#if !defined(NPY_PY3K)
{"newbuffer",
(PyCFunction)new_buffer,
diff --git a/numpy/core/tests/test_datetime.py b/numpy/core/tests/test_datetime.py
index e8c1890e4..0728654ee 100644
--- a/numpy/core/tests/test_datetime.py
+++ b/numpy/core/tests/test_datetime.py
@@ -1,6 +1,7 @@
from os import path
import numpy as np
from numpy.testing import *
+from numpy.compat import asbytes
class TestDateTime(TestCase):
def test_creation(self):
@@ -92,5 +93,11 @@ class TestDateTime(TestCase):
assert_equal(x[0].astype(np.int64), 322689600000000000)
+class TestDateTimeData(TestCase):
+
+ def test_basic(self):
+ a = np.array(['1980-03-23'], dtype=np.datetime64)
+ assert_equal(np.datetime_data(a.dtype), (asbytes('us'), 1, 1))
+
if __name__ == "__main__":
run_module_suite()
diff --git a/numpy/lib/tests/test_type_check.py b/numpy/lib/tests/test_type_check.py
index c8bc87c6e..0f8927614 100644
--- a/numpy/lib/tests/test_type_check.py
+++ b/numpy/lib/tests/test_type_check.py
@@ -382,13 +382,5 @@ class TestArrayConversion(TestCase):
assert_equal(a.__class__,ndarray)
assert_(issubdtype(a.dtype,float))
-class TestDateTimeData(object):
-
- @dec.skipif(not _HAS_CTYPE, "ctypes not available on this python installation")
- def test_basic(self):
- a = array(['1980-03-23'], dtype=datetime64)
- assert_equal(datetime_data(a.dtype), (asbytes('us'), 1, 1, 1))
-
-
if __name__ == "__main__":
run_module_suite()
diff --git a/numpy/lib/type_check.py b/numpy/lib/type_check.py
index 0ce851fe4..edea02b62 100644
--- a/numpy/lib/type_check.py
+++ b/numpy/lib/type_check.py
@@ -3,7 +3,7 @@
__all__ = ['iscomplexobj','isrealobj','imag','iscomplex',
'isreal','nan_to_num','real','real_if_close',
'typename','asfarray','mintypecode','asscalar',
- 'common_type', 'datetime_data']
+ 'common_type']
import numpy.core.numeric as _nx
from numpy.core.numeric import asarray, asanyarray, array, isnan, \
@@ -601,47 +601,3 @@ def common_type(*arrays):
else:
return array_type[0][precision]
-def datetime_data(dtype):
- """Return (unit, numerator, denominator, events) from a datetime dtype
- """
- try:
- import ctypes
- except ImportError:
- raise RuntimeError("Cannot access date-time internals without ctypes installed")
-
- if dtype.kind not in ['m','M']:
- raise ValueError("Not a date-time dtype")
-
- obj = dtype.metadata[METADATA_DTSTR]
- class DATETIMEMETA(ctypes.Structure):
- _fields_ = [('base', ctypes.c_int),
- ('num', ctypes.c_int),
- ('den', ctypes.c_int),
- ('events', ctypes.c_int)]
-
- import sys
- if sys.version_info[:2] >= (3, 0):
- func = ctypes.pythonapi.PyCapsule_GetPointer
- func.argtypes = [ctypes.py_object, ctypes.c_char_p]
- func.restype = ctypes.c_void_p
- result = func(ctypes.py_object(obj), ctypes.c_char_p(None))
- else:
- func = ctypes.pythonapi.PyCObject_AsVoidPtr
- func.argtypes = [ctypes.py_object]
- func.restype = ctypes.c_void_p
- result = func(ctypes.py_object(obj))
- result = ctypes.cast(ctypes.c_void_p(result), ctypes.POINTER(DATETIMEMETA))
-
- struct = result[0]
- base = struct.base
-
- # FIXME: This needs to be kept consistent with enum in ndarrayobject.h
- from numpy.core.multiarray import DATETIMEUNITS
- obj = ctypes.py_object(DATETIMEUNITS)
- if sys.version_info[:2] >= (2,7):
- result = func(obj, ctypes.c_char_p(None))
- else:
- result = func(obj)
- _unitnum2name = ctypes.cast(ctypes.c_void_p(result), ctypes.POINTER(ctypes.c_char_p))
-
- return (_unitnum2name[base], struct.num, struct.den, struct.events)