summaryrefslogtreecommitdiff
path: root/numpy/core
diff options
context:
space:
mode:
Diffstat (limited to 'numpy/core')
-rw-r--r--numpy/core/src/multiarray/_datetime.h39
-rw-r--r--numpy/core/src/multiarray/datetime.c338
-rw-r--r--numpy/core/src/multiarray/scalartypes.c.src81
3 files changed, 338 insertions, 120 deletions
diff --git a/numpy/core/src/multiarray/_datetime.h b/numpy/core/src/multiarray/_datetime.h
index 48903ebcf..4c28c7840 100644
--- a/numpy/core/src/multiarray/_datetime.h
+++ b/numpy/core/src/multiarray/_datetime.h
@@ -50,6 +50,16 @@ convert_datetimestruct_to_datetime(PyArray_DatetimeMetaData *meta,
npy_datetime *out);
/*
+ * Parses the metadata string into the metadata C structure.
+ *
+ * Returns 0 on success, -1 on failure.
+ */
+NPY_NO_EXPORT int
+parse_datetime_metadata_from_metastr(char *metastr, Py_ssize_t len,
+ PyArray_DatetimeMetaData *out_meta);
+
+
+/*
* This function returns a reference to a capsule
* which contains the datetime metadata parsed from a metadata
* string. 'metastr' should be NULL-terminated, and len should
@@ -141,6 +151,15 @@ NPY_NO_EXPORT PyObject *
convert_datetime_metadata_to_tuple(PyArray_DatetimeMetaData *meta);
/*
+ * Converts a metadata tuple into a datetime metadata C struct.
+ *
+ * Returns 0 on success, -1 on failure.
+ */
+NPY_NO_EXPORT int
+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.
*/
@@ -148,6 +167,16 @@ NPY_NO_EXPORT PyObject *
convert_datetime_metadata_tuple_to_metacobj(PyObject *tuple);
/*
+ * Converts an input object into datetime metadata. The input
+ * may be either a string or a tuple.
+ *
+ * Returns 0 on success, -1 on failure.
+ */
+NPY_NO_EXPORT int
+convert_pyobject_to_datetime_metadata(PyObject *obj,
+ PyArray_DatetimeMetaData *out_meta);
+
+/*
* 'ret' is a PyUString containing the datetime string, and this
* function appends the metadata string to it.
*
@@ -193,6 +222,16 @@ convert_pyobject_to_datetime(PyArray_DatetimeMetaData *meta, PyObject *obj,
npy_datetime *out);
/*
+ * Converts a PyObject * into a timedelta, in any of the forms supported
+ *
+ * Returns -1 on error, 0 on success.
+ */
+NPY_NO_EXPORT int
+convert_pyobject_to_timedelta(PyArray_DatetimeMetaData *meta, PyObject *obj,
+ npy_timedelta *out);
+
+
+/*
* Converts a datetime into a PyObject *.
*
* For days or coarser, returns a datetime.date.
diff --git a/numpy/core/src/multiarray/datetime.c b/numpy/core/src/multiarray/datetime.c
index 40c696593..9dd1e0a38 100644
--- a/numpy/core/src/multiarray/datetime.c
+++ b/numpy/core/src/multiarray/datetime.c
@@ -1064,95 +1064,86 @@ get_datetime_metadata_from_dtype(PyArray_Descr *dtype)
return meta;
}
-NPY_NO_EXPORT PyObject *
-parse_datetime_metacobj_from_metastr(char *metastr, Py_ssize_t len)
+/*
+ * Parses the metadata string into the metadata C structure.
+ *
+ * Returns 0 on success, -1 on failure.
+ */
+NPY_NO_EXPORT int
+parse_datetime_metadata_from_metastr(char *metastr, Py_ssize_t len,
+ PyArray_DatetimeMetaData *out_meta)
{
- PyArray_DatetimeMetaData *dt_data;
char *substr = metastr, *substrend = NULL;
int den = 1;
- dt_data = PyArray_malloc(sizeof(PyArray_DatetimeMetaData));
- if (dt_data == NULL) {
- return PyErr_NoMemory();
+ /* The metadata string must start with a '[' */
+ if (len < 3 || *substr++ != '[') {
+ goto bad_input;
}
- /* If there's no metastr, use the default */
- if (len == 0) {
- dt_data->num = 1;
- dt_data->base = NPY_DATETIME_DEFAULTUNIT;
- dt_data->events = 1;
+ /* First comes an optional integer multiplier */
+ out_meta->num = (int)strtol(substr, &substrend, 10);
+ if (substr == substrend) {
+ out_meta->num = 1;
}
- else {
-
- /* The metadata string must start with a '[' */
- if (len < 3 || *substr++ != '[') {
- goto bad_input;
- }
-
- /* First comes an optional integer multiplier */
- dt_data->num = (int)strtol(substr, &substrend, 10);
- if (substr == substrend) {
- dt_data->num = 1;
- }
- substr = substrend;
+ substr = substrend;
- /* Next comes the unit itself, followed by either '/' or ']' */
- substrend = substr;
- while (*substrend != '\0' && *substrend != '/' && *substrend != ']') {
- ++substrend;
- }
- if (*substrend == '\0') {
- goto bad_input;
- }
- dt_data->base = parse_datetime_unit_from_string(substr,
- substrend-substr, metastr);
- if (dt_data->base == -1) {
- goto error;
- }
- substr = substrend;
+ /* Next comes the unit itself, followed by either '/' or ']' */
+ substrend = substr;
+ while (*substrend != '\0' && *substrend != '/' && *substrend != ']') {
+ ++substrend;
+ }
+ if (*substrend == '\0') {
+ goto bad_input;
+ }
+ out_meta->base = parse_datetime_unit_from_string(substr,
+ substrend-substr, metastr);
+ if (out_meta->base == -1) {
+ return -1;
+ }
+ substr = substrend;
- /* Next comes an optional integer denominator */
- if (*substr == '/') {
- substr++;
- den = (int)strtol(substr, &substrend, 10);
- /* If the '/' exists, there must be a number followed by ']' */
- if (substr == substrend || *substrend != ']') {
- goto bad_input;
- }
- substr = substrend + 1;
- }
- else if (*substr == ']') {
- substr++;
- }
- else {
+ /* Next comes an optional integer denominator */
+ if (*substr == '/') {
+ substr++;
+ den = (int)strtol(substr, &substrend, 10);
+ /* If the '/' exists, there must be a number followed by ']' */
+ if (substr == substrend || *substrend != ']') {
goto bad_input;
}
+ substr = substrend + 1;
+ }
+ else if (*substr == ']') {
+ substr++;
+ }
+ else {
+ goto bad_input;
+ }
- /* Finally comes an optional number of events */
- if (substr[0] == '/' && substr[1] == '/') {
- substr += 2;
+ /* Finally comes an optional number of events */
+ if (substr[0] == '/' && substr[1] == '/') {
+ substr += 2;
- dt_data->events = (int)strtol(substr, &substrend, 10);
- if (substr == substrend || *substrend != '\0') {
- goto bad_input;
- }
- }
- else if (*substr != '\0') {
+ out_meta->events = (int)strtol(substr, &substrend, 10);
+ if (substr == substrend || *substrend != '\0') {
goto bad_input;
}
- else {
- dt_data->events = 1;
- }
+ }
+ else if (*substr != '\0') {
+ goto bad_input;
+ }
+ else {
+ out_meta->events = 1;
+ }
- if (den != 1) {
- if (convert_datetime_divisor_to_multiple(
- dt_data, den, metastr) < 0) {
- goto error;
- }
+ if (den != 1) {
+ if (convert_datetime_divisor_to_multiple(
+ out_meta, den, metastr) < 0) {
+ return -1;
}
}
- return NpyCapsule_FromVoidPtr((void *)dt_data, simple_capsule_dtor);
+ return 0;
bad_input:
if (substr != metastr) {
@@ -1165,9 +1156,34 @@ bad_input:
"Invalid datetime metadata string \"%s\"",
metastr);
}
-error:
- PyArray_free(dt_data);
- return NULL;
+
+ return -1;
+}
+
+NPY_NO_EXPORT PyObject *
+parse_datetime_metacobj_from_metastr(char *metastr, Py_ssize_t len)
+{
+ PyArray_DatetimeMetaData *dt_data;
+
+ dt_data = PyArray_malloc(sizeof(PyArray_DatetimeMetaData));
+ if (dt_data == NULL) {
+ return PyErr_NoMemory();
+ }
+
+ /* If there's no metastr, use the default */
+ if (len == 0) {
+ dt_data->num = 1;
+ dt_data->base = NPY_DATETIME_DEFAULTUNIT;
+ dt_data->events = 1;
+ }
+ else {
+ if (parse_datetime_metadata_from_metastr(metastr, len, dt_data) < 0) {
+ PyArray_free(dt_data);
+ return NULL;
+ }
+ }
+
+ return NpyCapsule_FromVoidPtr((void *)dt_data, simple_capsule_dtor);
}
/*
@@ -1960,8 +1976,9 @@ parse_datetime_unit_from_string(char *str, Py_ssize_t len, char *metastr)
/* If nothing matched, it's an error */
if (metastr == NULL) {
- PyErr_SetString(PyExc_TypeError,
- "Invalid datetime unit in metadata");
+ PyErr_Format(PyExc_TypeError,
+ "Invalid datetime unit \"%s\" in metadata",
+ str);
}
else {
PyErr_Format(PyExc_TypeError,
@@ -1992,10 +2009,15 @@ convert_datetime_metadata_to_tuple(PyArray_DatetimeMetaData *meta)
return dt_tuple;
}
-NPY_NO_EXPORT PyObject *
-convert_datetime_metadata_tuple_to_metacobj(PyObject *tuple)
+/*
+ * Converts a metadata tuple into a datetime metadata C struct.
+ *
+ * Returns 0 on success, -1 on failure.
+ */
+NPY_NO_EXPORT int
+convert_datetime_metadata_tuple_to_datetime_metadata(PyObject *tuple,
+ PyArray_DatetimeMetaData *out_meta)
{
- PyArray_DatetimeMetaData *dt_data;
char *basestr = NULL;
Py_ssize_t len = 0, tuple_size;
int den = 1;
@@ -2003,76 +2025,147 @@ convert_datetime_metadata_tuple_to_metacobj(PyObject *tuple)
if (!PyTuple_Check(tuple)) {
PyObject_Print(tuple, stderr, 0);
PyErr_SetString(PyExc_TypeError,
- "Require tuple for tuple->metacobj conversion");
- return NULL;
+ "Require tuple for tuple to NumPy datetime "
+ "metadata conversion");
+ return -1;
}
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;
+ "tuple to NumPy datetime metadata conversion");
+ return -1;
}
if (PyBytes_AsStringAndSize(PyTuple_GET_ITEM(tuple, 0),
&basestr, &len) < 0) {
- return NULL;
+ return -1;
}
- dt_data = PyArray_malloc(sizeof(PyArray_DatetimeMetaData));
- dt_data->base = parse_datetime_unit_from_string(basestr, len, NULL);
- if (dt_data->base == -1) {
- PyArray_free(dt_data);
- return NULL;
+ out_meta->base = parse_datetime_unit_from_string(basestr, len, NULL);
+ if (out_meta->base == -1) {
+ return -1;
}
/* Convert the values to longs */
- dt_data->num = PyInt_AsLong(PyTuple_GET_ITEM(tuple, 1));
- if (dt_data->num == -1 && PyErr_Occurred()) {
- PyArray_free(dt_data);
- return NULL;
+ out_meta->num = PyInt_AsLong(PyTuple_GET_ITEM(tuple, 1));
+ if (out_meta->num == -1 && PyErr_Occurred()) {
+ return -1;
}
if (tuple_size == 3) {
- dt_data->events = PyInt_AsLong(PyTuple_GET_ITEM(tuple, 2));
- if (dt_data->events == -1 && PyErr_Occurred()) {
- PyArray_free(dt_data);
- return NULL;
+ out_meta->events = PyInt_AsLong(PyTuple_GET_ITEM(tuple, 2));
+ if (out_meta->events == -1 && PyErr_Occurred()) {
+ return -1;
}
}
else {
den = PyInt_AsLong(PyTuple_GET_ITEM(tuple, 2));
if (den == -1 && PyErr_Occurred()) {
- PyArray_free(dt_data);
- return NULL;
+ return -1;
}
- dt_data->events = PyInt_AsLong(PyTuple_GET_ITEM(tuple, 3));
- if (dt_data->events == -1 && PyErr_Occurred()) {
- PyArray_free(dt_data);
- return NULL;
+ out_meta->events = PyInt_AsLong(PyTuple_GET_ITEM(tuple, 3));
+ if (out_meta->events == -1 && PyErr_Occurred()) {
+ return -1;
}
}
- if (dt_data->num <= 0 || dt_data->events <= 0 || den <= 0) {
+ if (out_meta->num <= 0 || out_meta->events <= 0 || den <= 0) {
PyErr_SetString(PyExc_TypeError,
"Invalid tuple values for "
- "tuple->metacobj conversion");
- PyArray_free(dt_data);
- return NULL;
+ "tuple to NumPy datetime metadata conversion");
+ return -1;
}
if (den != 1) {
- if (convert_datetime_divisor_to_multiple(dt_data, den, NULL) < 0) {
- PyArray_free(dt_data);
- return NULL;
+ if (convert_datetime_divisor_to_multiple(out_meta, den, NULL) < 0) {
+ return -1;
}
}
+ return 0;
+}
+
+/*
+ * 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.
+ *
+ * Returns 0 on success, -1 on failure.
+ */
+NPY_NO_EXPORT int
+convert_pyobject_to_datetime_metadata(PyObject *obj,
+ PyArray_DatetimeMetaData *out_meta)
+{
+ PyObject *ascii = NULL;
+ char *str = NULL;
+ Py_ssize_t len = 0;
+ NPY_DATETIMEUNIT unit;
+
+ if (PyTuple_Check(obj)) {
+ return convert_datetime_metadata_tuple_to_datetime_metadata(obj,
+ out_meta);
+ }
+
+ /* Get an ASCII string */
+ if (PyUnicode_Check(obj)) {
+ /* Allow unicode format strings: convert to bytes */
+ ascii = PyUnicode_AsASCIIString(obj);
+ if (ascii == NULL) {
+ return -1;
+ }
+ }
+ else if (PyBytes_Check(obj)) {
+ ascii = obj;
+ Py_INCREF(ascii);
+ }
+ else {
+ PyErr_SetString(PyExc_TypeError,
+ "Invalid object for specifying NumPy datetime metadata");
+ return -1;
+ }
+
+ if (PyBytes_AsStringAndSize(ascii, &str, &len) < 0) {
+ return -1;
+ }
+
+ /* First try for just the base unit */
+ unit = parse_datetime_unit_from_string(str, len, NULL);
+ if (unit != -1) {
+ out_meta->num = 1;
+ out_meta->base = unit;
+ out_meta->events = 1;
+
+ return 0;
+ }
+ /* If it failed, clear the error and use the main metastr parser */
+ else {
+ PyErr_Clear();
+ }
+
+ return parse_datetime_metadata_from_metastr(str, len, out_meta);
+}
+
+/*
* 'ret' is a PyUString containing the datetime string, and this
* function appends the metadata string to it.
*
@@ -2929,7 +3022,7 @@ convert_pyobject_to_datetime(PyArray_DatetimeMetaData *meta, PyObject *obj,
return 0;
}
- /* TODO datetime64 scalars require conversion
+ /* TODO
else if (PyArray_IsScalar(op, Datetime)) {
}
*/
@@ -2957,6 +3050,31 @@ convert_pyobject_to_datetime(PyArray_DatetimeMetaData *meta, PyObject *obj,
}
/*
+ * Converts a PyObject * into a timedelta, in any of the forms supported
+ *
+ * Returns -1 on error, 0 on success.
+ */
+NPY_NO_EXPORT int
+convert_pyobject_to_timedelta(PyArray_DatetimeMetaData *meta, PyObject *obj,
+ npy_timedelta *out)
+{
+ /* Do no conversion on raw integers */
+ if (PyInt_Check(obj)) {
+ *out = PyInt_AS_LONG(obj);
+ return 0;
+ }
+ else if (PyLong_Check(obj)) {
+ *out = PyLong_AsLongLong(obj);
+ return 0;
+ }
+ /* TODO: Finish this function */
+
+ PyErr_SetString(PyExc_ValueError,
+ "Could not convert object to NumPy timedelta");
+ return -1;
+}
+
+/*
* Converts a datetime into a PyObject *.
*
* Not-a-time is returned as the string "NaT".
diff --git a/numpy/core/src/multiarray/scalartypes.c.src b/numpy/core/src/multiarray/scalartypes.c.src
index 34962b744..b753609ba 100644
--- a/numpy/core/src/multiarray/scalartypes.c.src
+++ b/numpy/core/src/multiarray/scalartypes.c.src
@@ -21,6 +21,7 @@
#include "numpyos.h"
#include "common.h"
#include "scalartypes.h"
+#include "_datetime.h"
NPY_NO_EXPORT PyBoolScalarObject _PyArrayScalar_BoolValues[] = {
{PyObject_HEAD_INIT(&PyBoolArrType_Type) 0},
@@ -2212,12 +2213,15 @@ object_arrtype_dealloc(PyObject *v)
/**begin repeat
* #name = byte, short, int, long, longlong, ubyte, ushort, uint, ulong,
* ulonglong, half, float, double, longdouble, cfloat, cdouble,
- * clongdouble, string, unicode, object, datetime, timedelta#
+ * clongdouble, string, unicode, object#
+ * #Name = Byte, Short, Int, Long, LongLong, UByte, UShort, UInt, ULong,
+ * ULongLong, Half, Float, Double, LongDouble, CFloat, CDouble,
+ * CLongDouble, String, Unicode, Object#
* #TYPE = BYTE, SHORT, INT, LONG, LONGLONG, UBYTE, USHORT, UINT, ULONG,
* ULONGLONG, HALF, FLOAT, DOUBLE, LONGDOUBLE, CFLOAT, CDOUBLE,
- * CLONGDOUBLE, STRING, UNICODE, OBJECT, DATETIME, TIMEDELTA#
- * #work = 0,0,1,1,1,0,0,0,0,0,0,0,1,0,0,0,0,z,z,0,0,0#
- * #default = 0*17,1*2,2,0*2#
+ * CLONGDOUBLE, STRING, UNICODE, OBJECT#
+ * #work = 0,0,1,1,1,0,0,0,0,0,0,0,1,0,0,0,0,z,z,0#
+ * #default = 0*17,1*2,2#
*/
#define _NPY_UNUSED2_1
@@ -2248,18 +2252,22 @@ static PyObject *
if (!PyArg_ParseTuple(args, "|O", &obj)) {
return NULL;
}
- typecode = PyArray_DescrFromType(PyArray_@TYPE@);
+ typecode = PyArray_DescrFromType(NPY_@TYPE@);
+ if (typecode == NULL) {
+ return NULL;
+ }
/*
* typecode is new reference and stolen by
* PyArray_FromAny but not PyArray_Scalar
*/
if (obj == NULL) {
#if @default@ == 0
- char *mem = malloc(sizeof(npy_@name@));
-
- memset(mem, 0, sizeof(npy_@name@));
- robj = PyArray_Scalar(mem, typecode, NULL);
- free(mem);
+ robj = PyArray_Scalar(NULL, typecode, NULL);
+ if (robj == NULL) {
+ Py_DECREF(typecode);
+ return NULL;
+ }
+ memset(&((Py@Name@ScalarObject *)robj)->obval, 0, sizeof(npy_@name@));
#elif @default@ == 1
robj = PyArray_Scalar(NULL, typecode, NULL);
#elif @default@ == 2
@@ -2339,6 +2347,59 @@ finish:
#undef _WORK0
#undef _WORK
+/**begin repeat
+ * #name = datetime, timedelta#
+ * #Name = Datetime, Timedelta#
+ * #TYPE = DATETIME, TIMEDELTA#
+ */
+
+static PyObject *
+@name@_arrtype_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
+{
+ PyObject *obj = NULL, *meta_obj = NULL;
+ Py@Name@ScalarObject *ret;
+
+ if (!PyArg_ParseTuple(args, "|OO", &obj, &meta_obj)) {
+ return NULL;
+ }
+
+ /* Allocate the return scalar */
+ ret = (Py@Name@ScalarObject *)Py@Name@ArrType_Type.tp_alloc(
+ &Py@Name@ArrType_Type, 0);
+ if (ret == NULL) {
+ return NULL;
+ }
+
+ /* Incorporate the metadata if its provided */
+ if (meta_obj != NULL) {
+ /* Parse the provided metadata input */
+ if (convert_pyobject_to_datetime_metadata(meta_obj, &ret->obmeta)
+ < 0) {
+ Py_DECREF(ret);
+ return NULL;
+ }
+ }
+ else {
+ ret->obmeta.base = NPY_DATETIME_DEFAULTUNIT;
+ ret->obmeta.num = 1;
+ ret->obmeta.events = 1;
+ }
+
+ if (obj == NULL) {
+ ret->obval = 0;
+ }
+ else {
+ if (convert_pyobject_to_@name@(&ret->obmeta, obj, &ret->obval)
+ < 0) {
+ Py_DECREF(ret);
+ return NULL;
+ }
+ }
+
+ return (PyObject *)ret;
+}
+/**end repeat**/
+
/* bool->tp_new only returns Py_True or Py_False */
static PyObject *
bool_arrtype_new(PyTypeObject *NPY_UNUSED(type), PyObject *args, PyObject *NPY_UNUSED(kwds))