diff options
author | David Cournapeau <cournape@gmail.com> | 2009-04-30 08:40:24 +0000 |
---|---|---|
committer | David Cournapeau <cournape@gmail.com> | 2009-04-30 08:40:24 +0000 |
commit | 3d730002b1428cce568bcf6fcda0e0df76c5d960 (patch) | |
tree | 4311ca1159f0f891a1907be2d3027229fd39476b /numpy | |
parent | 14b9b242818b5e5ab58ec5b2c688410d60b9c918 (diff) | |
download | numpy-3d730002b1428cce568bcf6fcda0e0df76c5d960.tar.gz |
Put more type convertion code into array descriptor file.
Diffstat (limited to 'numpy')
-rw-r--r-- | numpy/core/src/arrayconvert_datatype.c | 127 | ||||
-rw-r--r-- | numpy/core/src/arraydescr.c | 981 | ||||
-rw-r--r-- | numpy/core/src/arraydescr.h | 3 | ||||
-rw-r--r-- | numpy/core/src/multiarraymodule.c | 1107 |
4 files changed, 1112 insertions, 1106 deletions
diff --git a/numpy/core/src/arrayconvert_datatype.c b/numpy/core/src/arrayconvert_datatype.c index ca29e313a..921bb1a4e 100644 --- a/numpy/core/src/arrayconvert_datatype.c +++ b/numpy/core/src/arrayconvert_datatype.c @@ -811,3 +811,130 @@ PyArray_ObjectType(PyObject *op, int minimum_type) Py_XDECREF(intype); return ret; } + +/* Raises error when len(op) == 0 */ + +/*NUMPY_API*/ +NPY_NO_EXPORT PyArrayObject ** +PyArray_ConvertToCommonType(PyObject *op, int *retn) +{ + int i, n, allscalars = 0; + PyArrayObject **mps = NULL; + PyObject *otmp; + PyArray_Descr *intype = NULL, *stype = NULL; + PyArray_Descr *newtype = NULL; + NPY_SCALARKIND scalarkind = NPY_NOSCALAR, intypekind = NPY_NOSCALAR; + + *retn = n = PySequence_Length(op); + if (n == 0) { + PyErr_SetString(PyExc_ValueError, "0-length sequence."); + } + if (PyErr_Occurred()) { + *retn = 0; + return NULL; + } + mps = (PyArrayObject **)PyDataMem_NEW(n*sizeof(PyArrayObject *)); + if (mps == NULL) { + *retn = 0; + return (void*)PyErr_NoMemory(); + } + + if (PyArray_Check(op)) { + for (i = 0; i < n; i++) { + mps[i] = (PyArrayObject *) array_big_item((PyArrayObject *)op, i); + } + if (!PyArray_ISCARRAY(op)) { + for (i = 0; i < n; i++) { + PyObject *obj; + obj = PyArray_NewCopy(mps[i], NPY_CORDER); + Py_DECREF(mps[i]); + mps[i] = (PyArrayObject *)obj; + } + } + return mps; + } + + for (i = 0; i < n; i++) { + otmp = PySequence_GetItem(op, i); + if (!PyArray_CheckAnyScalar(otmp)) { + newtype = PyArray_DescrFromObject(otmp, intype); + Py_XDECREF(intype); + intype = newtype; + mps[i] = NULL; + intypekind = PyArray_ScalarKind(intype->type_num, NULL); + } + else { + newtype = PyArray_DescrFromObject(otmp, stype); + Py_XDECREF(stype); + stype = newtype; + scalarkind = PyArray_ScalarKind(newtype->type_num, NULL); + mps[i] = (PyArrayObject *)Py_None; + Py_INCREF(Py_None); + } + Py_XDECREF(otmp); + } + if (intype==NULL) { + /* all scalars */ + allscalars = 1; + intype = stype; + Py_INCREF(intype); + for (i = 0; i < n; i++) { + Py_XDECREF(mps[i]); + mps[i] = NULL; + } + } + else if ((stype != NULL) && (intypekind != scalarkind)) { + /* + * we need to upconvert to type that + * handles both intype and stype + * also don't forcecast the scalars. + */ + if (!PyArray_CanCoerceScalar(stype->type_num, + intype->type_num, + scalarkind)) { + newtype = _array_small_type(intype, stype); + Py_XDECREF(intype); + intype = newtype; + } + for (i = 0; i < n; i++) { + Py_XDECREF(mps[i]); + mps[i] = NULL; + } + } + + + /* Make sure all arrays are actual array objects. */ + for (i = 0; i < n; i++) { + int flags = CARRAY; + + if ((otmp = PySequence_GetItem(op, i)) == NULL) { + goto fail; + } + if (!allscalars && ((PyObject *)(mps[i]) == Py_None)) { + /* forcecast scalars */ + flags |= FORCECAST; + Py_DECREF(Py_None); + } + Py_INCREF(intype); + mps[i] = (PyArrayObject*) + PyArray_FromAny(otmp, intype, 0, 0, flags, NULL); + Py_DECREF(otmp); + if (mps[i] == NULL) { + goto fail; + } + } + Py_DECREF(intype); + Py_XDECREF(stype); + return mps; + + fail: + Py_XDECREF(intype); + Py_XDECREF(stype); + *retn = 0; + for (i = 0; i < n; i++) { + Py_XDECREF(mps[i]); + } + PyDataMem_FREE(mps); + return NULL; +} + diff --git a/numpy/core/src/arraydescr.c b/numpy/core/src/arraydescr.c index f9e41adb4..a36640cb3 100644 --- a/numpy/core/src/arraydescr.c +++ b/numpy/core/src/arraydescr.c @@ -11,6 +11,685 @@ #include "arrayobject.h" +#define _chk_byteorder(arg) (arg == '>' || arg == '<' || \ + arg == '|' || arg == '=') + +static PyObject *typeDict = NULL; /* Must be explicitly loaded */ + +static PyArray_Descr * +_use_inherit(PyArray_Descr *type, PyObject *newobj, int *errflag); + +NPY_NO_EXPORT PyObject * +array_set_typeDict(PyObject *NPY_UNUSED(ignored), PyObject *args) +{ + PyObject *dict; + + if (!PyArg_ParseTuple(args, "O", &dict)) { + return NULL; + } + /* Decrement old reference (if any)*/ + Py_XDECREF(typeDict); + typeDict = dict; + /* Create an internal reference to it */ + Py_INCREF(dict); + Py_INCREF(Py_None); + return Py_None; +} + +static int +_check_for_commastring(char *type, int len) +{ + int i; + + /* Check for ints at start of string */ + if ((type[0] >= '0' && type[0] <= '9') || + ((len > 1) && _chk_byteorder(type[0]) && + (type[1] >= '0' && type[1] <= '9'))) { + return 1; + } + /* Check for empty tuple */ + if (((len > 1) && (type[0] == '(' && type[1] == ')')) || + ((len > 3) && _chk_byteorder(type[0]) && + (type[1] == '(' && type[2] == ')'))) { + return 1; + } + /* Check for presence of commas */ + for (i = 1; i < len; i++) { + if (type[i] == ',') { + return 1; + } + } + return 0; +} + +#undef _chk_byteorder + +static PyArray_Descr * +_convert_from_tuple(PyObject *obj) +{ + PyArray_Descr *type, *res; + PyObject *val; + int errflag; + + if (PyTuple_GET_SIZE(obj) != 2) { + return NULL; + } + if (!PyArray_DescrConverter(PyTuple_GET_ITEM(obj,0), &type)) { + return NULL; + } + val = PyTuple_GET_ITEM(obj,1); + /* try to interpret next item as a type */ + res = _use_inherit(type, val, &errflag); + if (res || errflag) { + Py_DECREF(type); + if (res) { + return res; + } + else { + return NULL; + } + } + PyErr_Clear(); + /* + * We get here if res was NULL but errflag wasn't set + * --- i.e. the conversion to a data-descr failed in _use_inherit + */ + if (type->elsize == 0) { + /* interpret next item as a typesize */ + int itemsize = PyArray_PyIntAsInt(PyTuple_GET_ITEM(obj,1)); + + if (error_converting(itemsize)) { + PyErr_SetString(PyExc_ValueError, + "invalid itemsize in generic type "\ + "tuple"); + goto fail; + } + PyArray_DESCR_REPLACE(type); + if (type->type_num == PyArray_UNICODE) { + type->elsize = itemsize << 2; + } + else { + type->elsize = itemsize; + } + } + else { + /* + * interpret next item as shape (if it's a tuple) + * and reset the type to PyArray_VOID with + * a new fields attribute. + */ + PyArray_Dims shape = {NULL, -1}; + PyArray_Descr *newdescr; + + if (!(PyArray_IntpConverter(val, &shape)) + || (shape.len > MAX_DIMS)) { + PyDimMem_FREE(shape.ptr); + PyErr_SetString(PyExc_ValueError, + "invalid shape in fixed-type tuple."); + goto fail; + } + /* If (type, 1) was given, it is equivalent to type... + or (type, ()) was given it is equivalent to type... */ + if ((shape.len == 1 && shape.ptr[0] == 1 && PyNumber_Check(val)) + || (shape.len == 0 && PyTuple_Check(val))) { + PyDimMem_FREE(shape.ptr); + return type; + } + newdescr = PyArray_DescrNewFromType(PyArray_VOID); + if (newdescr == NULL) { + PyDimMem_FREE(shape.ptr); + goto fail; + } + newdescr->elsize = type->elsize; + newdescr->elsize *= PyArray_MultiplyList(shape.ptr, shape.len); + PyDimMem_FREE(shape.ptr); + newdescr->subarray = _pya_malloc(sizeof(PyArray_ArrayDescr)); + newdescr->subarray->base = type; + newdescr->hasobject = type->hasobject; + Py_INCREF(val); + newdescr->subarray->shape = val; + Py_XDECREF(newdescr->fields); + Py_XDECREF(newdescr->names); + newdescr->fields = NULL; + newdescr->names = NULL; + type = newdescr; + } + return type; + + fail: + Py_XDECREF(type); + return NULL; +} + +/* + * obj is a list. Each item is a tuple with + * + * (field-name, data-type (either a list or a string), and an optional + * shape parameter). + */ +static PyArray_Descr * +_convert_from_array_descr(PyObject *obj, int align) +{ + int n, i, totalsize; + int ret; + PyObject *fields, *item, *newobj; + PyObject *name, *tup, *title; + PyObject *nameslist; + PyArray_Descr *new; + PyArray_Descr *conv; + int dtypeflags = 0; + int maxalign = 0; + + + n = PyList_GET_SIZE(obj); + nameslist = PyTuple_New(n); + if (!nameslist) { + return NULL; + } + totalsize = 0; + fields = PyDict_New(); + for (i = 0; i < n; i++) { + item = PyList_GET_ITEM(obj, i); + if (!PyTuple_Check(item) || (PyTuple_GET_SIZE(item) < 2)) { + goto fail; + } + name = PyTuple_GET_ITEM(item, 0); + if (PyString_Check(name)) { + title = NULL; + } + else if (PyTuple_Check(name)) { + if (PyTuple_GET_SIZE(name) != 2) { + goto fail; + } + title = PyTuple_GET_ITEM(name, 0); + name = PyTuple_GET_ITEM(name, 1); + if (!PyString_Check(name)) { + goto fail; + } + } + else { + goto fail; + } + if (PyString_GET_SIZE(name)==0) { + if (title == NULL) { + name = PyString_FromFormat("f%d", i); + } + else { + name = title; + Py_INCREF(name); + } + } + else { + Py_INCREF(name); + } + PyTuple_SET_ITEM(nameslist, i, name); + if (PyTuple_GET_SIZE(item) == 2) { + ret = PyArray_DescrConverter(PyTuple_GET_ITEM(item, 1), &conv); + if (ret == PY_FAIL) { + PyObject_Print(PyTuple_GET_ITEM(item,1), stderr, 0); + } + } + else if (PyTuple_GET_SIZE(item) == 3) { + newobj = PyTuple_GetSlice(item, 1, 3); + ret = PyArray_DescrConverter(newobj, &conv); + Py_DECREF(newobj); + } + else { + goto fail; + } + if (ret == PY_FAIL) { + goto fail; + } + if ((PyDict_GetItem(fields, name) != NULL) || + (title && + (PyString_Check(title) || PyUnicode_Check(title)) && + (PyDict_GetItem(fields, title) != NULL))) { + PyErr_SetString(PyExc_ValueError, + "two fields with the same name"); + goto fail; + } + dtypeflags |= (conv->hasobject & NPY_FROM_FIELDS); + tup = PyTuple_New((title == NULL ? 2 : 3)); + PyTuple_SET_ITEM(tup, 0, (PyObject *)conv); + if (align) { + int _align; + + _align = conv->alignment; + if (_align > 1) { + totalsize = ((totalsize + _align - 1)/_align)*_align; + } + maxalign = MAX(maxalign, _align); + } + PyTuple_SET_ITEM(tup, 1, PyInt_FromLong((long) totalsize)); + + /* + * Title can be "meta-data". Only insert it + * into the fields dictionary if it is a string + */ + if (title != NULL) { + Py_INCREF(title); + PyTuple_SET_ITEM(tup, 2, title); + if (PyString_Check(title) || PyUnicode_Check(title)) { + PyDict_SetItem(fields, title, tup); + } + } + PyDict_SetItem(fields, name, tup); + totalsize += conv->elsize; + Py_DECREF(tup); + } + new = PyArray_DescrNewFromType(PyArray_VOID); + new->fields = fields; + new->names = nameslist; + new->elsize = totalsize; + new->hasobject=dtypeflags; + if (maxalign > 1) { + totalsize = ((totalsize+maxalign-1)/maxalign)*maxalign; + } + if (align) { + new->alignment = maxalign; + } + return new; + + fail: + Py_DECREF(fields); + Py_DECREF(nameslist); + return NULL; + +} + +/* + * a list specifying a data-type can just be + * a list of formats. The names for the fields + * will default to f0, f1, f2, and so forth. + */ +static PyArray_Descr * +_convert_from_list(PyObject *obj, int align) +{ + int n, i; + int totalsize; + PyObject *fields; + PyArray_Descr *conv = NULL; + PyArray_Descr *new; + PyObject *key, *tup; + PyObject *nameslist = NULL; + int ret; + int maxalign = 0; + int dtypeflags = 0; + + n = PyList_GET_SIZE(obj); + /* + * Ignore any empty string at end which _internal._commastring + * can produce + */ + key = PyList_GET_ITEM(obj, n-1); + if (PyString_Check(key) && PyString_GET_SIZE(key) == 0) { + n = n - 1; + } + /* End ignore code.*/ + totalsize = 0; + if (n == 0) { + return NULL; + } + nameslist = PyTuple_New(n); + if (!nameslist) { + return NULL; + } + fields = PyDict_New(); + for (i = 0; i < n; i++) { + tup = PyTuple_New(2); + key = PyString_FromFormat("f%d", i); + ret = PyArray_DescrConverter(PyList_GET_ITEM(obj, i), &conv); + if (ret == PY_FAIL) { + Py_DECREF(tup); + Py_DECREF(key); + goto fail; + } + dtypeflags |= (conv->hasobject & NPY_FROM_FIELDS); + PyTuple_SET_ITEM(tup, 0, (PyObject *)conv); + if (align) { + int _align; + + _align = conv->alignment; + if (_align > 1) { + totalsize = ((totalsize + _align - 1)/_align)*_align; + } + maxalign = MAX(maxalign, _align); + } + PyTuple_SET_ITEM(tup, 1, PyInt_FromLong((long) totalsize)); + PyDict_SetItem(fields, key, tup); + Py_DECREF(tup); + PyTuple_SET_ITEM(nameslist, i, key); + totalsize += conv->elsize; + } + new = PyArray_DescrNewFromType(PyArray_VOID); + new->fields = fields; + new->names = nameslist; + new->hasobject=dtypeflags; + if (maxalign > 1) { + totalsize = ((totalsize+maxalign-1)/maxalign)*maxalign; + } + if (align) { + new->alignment = maxalign; + } + new->elsize = totalsize; + return new; + + fail: + Py_DECREF(nameslist); + Py_DECREF(fields); + return NULL; +} + + +/* + * comma-separated string + * this is the format developed by the numarray records module + * and implemented by the format parser in that module + * this is an alternative implementation found in the _internal.py + * file patterned after that one -- the approach is to try to convert + * to a list (with tuples if any repeat information is present) + * and then call the _convert_from_list) + */ +static PyArray_Descr * +_convert_from_commastring(PyObject *obj, int align) +{ + PyObject *listobj; + PyArray_Descr *res; + PyObject *_numpy_internal; + + if (!PyString_Check(obj)) { + return NULL; + } + _numpy_internal = PyImport_ImportModule("numpy.core._internal"); + if (_numpy_internal == NULL) { + return NULL; + } + listobj = PyObject_CallMethod(_numpy_internal, "_commastring", "O", obj); + Py_DECREF(_numpy_internal); + if (!listobj) { + return NULL; + } + if (!PyList_Check(listobj) || PyList_GET_SIZE(listobj)<1) { + PyErr_SetString(PyExc_RuntimeError, "_commastring is " \ + "not returning a list with len >= 1"); + return NULL; + } + if (PyList_GET_SIZE(listobj) == 1) { + if (PyArray_DescrConverter(PyList_GET_ITEM(listobj, 0), + &res) == NPY_FAIL) { + res = NULL; + } + } + else { + res = _convert_from_list(listobj, align); + } + Py_DECREF(listobj); + if (!res && !PyErr_Occurred()) { + PyErr_SetString(PyExc_ValueError, "invalid data-type"); + return NULL; + } + return res; +} + +/* + * A tuple type would be either (generic typeobject, typesize) + * or (fixed-length data-type, shape) + * + * or (inheriting data-type, new-data-type) + * The new data-type must have the same itemsize as the inheriting data-type + * unless the latter is 0 + * + * Thus (int32, {'real':(int16,0),'imag',(int16,2)}) + * + * is one way to specify a descriptor that will give + * a['real'] and a['imag'] to an int32 array. + * + * leave type reference alone + */ +static PyArray_Descr * +_use_inherit(PyArray_Descr *type, PyObject *newobj, int *errflag) +{ + PyArray_Descr *new; + PyArray_Descr *conv; + + *errflag = 0; + if (!PyArray_DescrConverter(newobj, &conv)) { + return NULL; + } + *errflag = 1; + new = PyArray_DescrNew(type); + if (new == NULL) { + goto fail; + } + if (new->elsize && new->elsize != conv->elsize) { + PyErr_SetString(PyExc_ValueError, + "mismatch in size of old "\ + "and new data-descriptor"); + goto fail; + } + new->elsize = conv->elsize; + if (conv->names) { + new->fields = conv->fields; + Py_XINCREF(new->fields); + new->names = conv->names; + Py_XINCREF(new->names); + } + new->hasobject = conv->hasobject; + Py_DECREF(conv); + *errflag = 0; + return new; + + fail: + Py_DECREF(conv); + return NULL; +} + +/* + * a dictionary specifying a data-type + * must have at least two and up to four + * keys These must all be sequences of the same length. + * + * "names" --- field names + * "formats" --- the data-type descriptors for the field. + * + * Optional: + * + * "offsets" --- integers indicating the offset into the + * record of the start of the field. + * if not given, then "consecutive offsets" + * will be assumed and placed in the dictionary. + * + * "titles" --- Allows the use of an additional key + * for the fields dictionary.(if these are strings + * or unicode objects) or + * this can also be meta-data to + * be passed around with the field description. + * + * Attribute-lookup-based field names merely has to query the fields + * dictionary of the data-descriptor. Any result present can be used + * to return the correct field. + * + * So, the notion of what is a name and what is a title is really quite + * arbitrary. + * + * What does distinguish a title, however, is that if it is not None, + * it will be placed at the end of the tuple inserted into the + * fields dictionary.and can therefore be used to carry meta-data around. + * + * If the dictionary does not have "names" and "formats" entries, + * then it will be checked for conformity and used directly. + */ +static PyArray_Descr * +_use_fields_dict(PyObject *obj, int align) +{ + PyObject *_numpy_internal; + PyArray_Descr *res; + + _numpy_internal = PyImport_ImportModule("numpy.core._internal"); + if (_numpy_internal == NULL) { + return NULL; + } + res = (PyArray_Descr *)PyObject_CallMethod(_numpy_internal, + "_usefields", + "Oi", obj, align); + Py_DECREF(_numpy_internal); + return res; +} + +static PyArray_Descr * +_convert_from_dict(PyObject *obj, int align) +{ + PyArray_Descr *new; + PyObject *fields = NULL; + PyObject *names, *offsets, *descrs, *titles; + int n, i; + int totalsize; + int maxalign = 0; + int dtypeflags = 0; + + fields = PyDict_New(); + if (fields == NULL) { + return (PyArray_Descr *)PyErr_NoMemory(); + } + names = PyDict_GetItemString(obj, "names"); + descrs = PyDict_GetItemString(obj, "formats"); + if (!names || !descrs) { + Py_DECREF(fields); + return _use_fields_dict(obj, align); + } + n = PyObject_Length(names); + offsets = PyDict_GetItemString(obj, "offsets"); + titles = PyDict_GetItemString(obj, "titles"); + if ((n > PyObject_Length(descrs)) + || (offsets && (n > PyObject_Length(offsets))) + || (titles && (n > PyObject_Length(titles)))) { + PyErr_SetString(PyExc_ValueError, + "all items in the dictionary must have" \ + " the same length."); + goto fail; + } + + totalsize = 0; + for (i = 0; i < n; i++) { + PyObject *tup, *descr, *index, *item, *name, *off; + int len, ret, _align = 1; + PyArray_Descr *newdescr; + + /* Build item to insert (descr, offset, [title])*/ + len = 2; + item = NULL; + index = PyInt_FromLong(i); + if (titles) { + item=PyObject_GetItem(titles, index); + if (item && item != Py_None) { + len = 3; + } + else { + Py_XDECREF(item); + } + PyErr_Clear(); + } + tup = PyTuple_New(len); + descr = PyObject_GetItem(descrs, index); + ret = PyArray_DescrConverter(descr, &newdescr); + Py_DECREF(descr); + if (ret == PY_FAIL) { + Py_DECREF(tup); + Py_DECREF(index); + goto fail; + } + PyTuple_SET_ITEM(tup, 0, (PyObject *)newdescr); + if (align) { + _align = newdescr->alignment; + maxalign = MAX(maxalign,_align); + } + if (offsets) { + long offset; + off = PyObject_GetItem(offsets, index); + offset = PyInt_AsLong(off); + PyTuple_SET_ITEM(tup, 1, off); + if (offset < totalsize) { + PyErr_SetString(PyExc_ValueError, + "invalid offset (must be "\ + "ordered)"); + ret = PY_FAIL; + } + if (offset > totalsize) totalsize = offset; + } + else { + if (align && _align > 1) { + totalsize = ((totalsize + _align - 1)/_align)*_align; + } + PyTuple_SET_ITEM(tup, 1, PyInt_FromLong(totalsize)); + } + if (len == 3) { + PyTuple_SET_ITEM(tup, 2, item); + } + name = PyObject_GetItem(names, index); + Py_DECREF(index); + if (!(PyString_Check(name) || PyUnicode_Check(name))) { + PyErr_SetString(PyExc_ValueError, + "field names must be strings"); + ret = PY_FAIL; + } + + /* Insert into dictionary */ + if (PyDict_GetItem(fields, name) != NULL) { + PyErr_SetString(PyExc_ValueError, + "name already used as a name or "\ + "title"); + ret = PY_FAIL; + } + PyDict_SetItem(fields, name, tup); + Py_DECREF(name); + if (len == 3) { + if ((PyString_Check(item) || PyUnicode_Check(item)) + && PyDict_GetItem(fields, item) != NULL) { + PyErr_SetString(PyExc_ValueError, + "title already used as a "\ + "name or title."); + ret=PY_FAIL; + } + else { + PyDict_SetItem(fields, item, tup); + } + } + Py_DECREF(tup); + if ((ret == PY_FAIL) || (newdescr->elsize == 0)) { + goto fail; + } + dtypeflags |= (newdescr->hasobject & NPY_FROM_FIELDS); + totalsize += newdescr->elsize; + } + + new = PyArray_DescrNewFromType(PyArray_VOID); + if (new == NULL) { + goto fail; + } + if (maxalign > 1) { + totalsize = ((totalsize + maxalign - 1)/maxalign)*maxalign; + } + if (align) { + new->alignment = maxalign; + } + new->elsize = totalsize; + if (!PyTuple_Check(names)) { + names = PySequence_Tuple(names); + } + else { + Py_INCREF(names); + } + new->names = names; + new->fields = fields; + new->hasobject = dtypeflags; + return new; + + fail: + Py_XDECREF(fields); + return NULL; +} + + /*NUMPY_API*/ NPY_NO_EXPORT PyArray_Descr * PyArray_DescrNewFromType(int type_num) @@ -24,6 +703,242 @@ PyArray_DescrNewFromType(int type_num) return new; } +/*NUMPY_API + * Get typenum from an object -- None goes to NULL + */ +NPY_NO_EXPORT int +PyArray_DescrConverter2(PyObject *obj, PyArray_Descr **at) +{ + if (obj == Py_None) { + *at = NULL; + return PY_SUCCEED; + } + else { + return PyArray_DescrConverter(obj, at); + } +} + +/*NUMPY_API + * Get typenum from an object -- None goes to PyArray_DEFAULT + * This function takes a Python object representing a type and converts it + * to a the correct PyArray_Descr * structure to describe the type. + * + * Many objects can be used to represent a data-type which in NumPy is + * quite a flexible concept. + * + * This is the central code that converts Python objects to + * Type-descriptor objects that are used throughout numpy. + * new reference in *at + */ +NPY_NO_EXPORT int +PyArray_DescrConverter(PyObject *obj, PyArray_Descr **at) +{ + char *type; + int check_num = PyArray_NOTYPE + 10; + int len; + PyObject *item; + int elsize = 0; + char endian = '='; + + *at = NULL; + /* default */ + if (obj == Py_None) { + *at = PyArray_DescrFromType(PyArray_DEFAULT); + return PY_SUCCEED; + } + if (PyArray_DescrCheck(obj)) { + *at = (PyArray_Descr *)obj; + Py_INCREF(*at); + return PY_SUCCEED; + } + + if (PyType_Check(obj)) { + if (PyType_IsSubtype((PyTypeObject *)obj, + &PyGenericArrType_Type)) { + *at = PyArray_DescrFromTypeObject(obj); + if (*at) { + return PY_SUCCEED; + } + else { + return PY_FAIL; + } + } + check_num = PyArray_OBJECT; + if (obj == (PyObject *)(&PyInt_Type)) { + check_num = PyArray_LONG; + } + else if (obj == (PyObject *)(&PyLong_Type)) { + check_num = PyArray_LONGLONG; + } + else if (obj == (PyObject *)(&PyFloat_Type)) { + check_num = PyArray_DOUBLE; + } + else if (obj == (PyObject *)(&PyComplex_Type)) { + check_num = PyArray_CDOUBLE; + } + else if (obj == (PyObject *)(&PyBool_Type)) { + check_num = PyArray_BOOL; + } + else if (obj == (PyObject *)(&PyString_Type)) { + check_num = PyArray_STRING; + } + else if (obj == (PyObject *)(&PyUnicode_Type)) { + check_num = PyArray_UNICODE; + } + else if (obj == (PyObject *)(&PyBuffer_Type)) { + check_num = PyArray_VOID; + } + else { + *at = _arraydescr_fromobj(obj); + if (*at) { + return PY_SUCCEED; + } + } + goto finish; + } + + /* or a typecode string */ + if (PyString_Check(obj)) { + /* Check for a string typecode. */ + type = PyString_AS_STRING(obj); + len = PyString_GET_SIZE(obj); + if (len <= 0) { + goto fail; + } + /* check for commas present or first (or second) element a digit */ + if (_check_for_commastring(type, len)) { + *at = _convert_from_commastring(obj, 0); + if (*at) { + return PY_SUCCEED; + } + return PY_FAIL; + } + check_num = (int) type[0]; + if ((char) check_num == '>' || (char) check_num == '<' + || (char) check_num == '|' || (char) check_num == '=') { + if (len <= 1) { + goto fail; + } + endian = (char) check_num; + type++; len--; + check_num = (int) type[0]; + if (endian == '|') { + endian = '='; + } + } + if (len > 1) { + elsize = atoi(type + 1); + if (elsize == 0) { + check_num = PyArray_NOTYPE+10; + } + /* + * When specifying length of UNICODE + * the number of characters is given to match + * the STRING interface. Each character can be + * more than one byte and itemsize must be + * the number of bytes. + */ + else if (check_num == PyArray_UNICODELTR) { + elsize <<= 2; + } + /* Support for generic processing c4, i4, f8, etc...*/ + else if ((check_num != PyArray_STRINGLTR) + && (check_num != PyArray_VOIDLTR) + && (check_num != PyArray_STRINGLTR2)) { + check_num = PyArray_TypestrConvert(elsize, check_num); + if (check_num == PyArray_NOTYPE) { + check_num += 10; + } + elsize = 0; + } + } + } + else if (PyTuple_Check(obj)) { + /* or a tuple */ + *at = _convert_from_tuple(obj); + if (*at == NULL){ + if (PyErr_Occurred()) { + return PY_FAIL; + } + goto fail; + } + return PY_SUCCEED; + } + else if (PyList_Check(obj)) { + /* or a list */ + *at = _convert_from_array_descr(obj,0); + if (*at == NULL) { + if (PyErr_Occurred()) { + return PY_FAIL; + } + goto fail; + } + return PY_SUCCEED; + } + else if (PyDict_Check(obj)) { + /* or a dictionary */ + *at = _convert_from_dict(obj,0); + if (*at == NULL) { + if (PyErr_Occurred()) { + return PY_FAIL; + } + goto fail; + } + return PY_SUCCEED; + } + else if (PyArray_Check(obj)) { + goto fail; + } + else { + *at = _arraydescr_fromobj(obj); + if (*at) { + return PY_SUCCEED; + } + if (PyErr_Occurred()) { + return PY_FAIL; + } + goto fail; + } + if (PyErr_Occurred()) { + goto fail; + } + /* + if (check_num == PyArray_NOTYPE) return PY_FAIL; + */ + + finish: + if ((check_num == PyArray_NOTYPE + 10) + || (*at = PyArray_DescrFromType(check_num)) == NULL) { + /* Now check to see if the object is registered in typeDict */ + if (typeDict != NULL) { + item = PyDict_GetItem(typeDict, obj); + if (item) { + return PyArray_DescrConverter(item, at); + } + } + goto fail; + } + + if (((*at)->elsize == 0) && (elsize != 0)) { + PyArray_DESCR_REPLACE(*at); + (*at)->elsize = elsize; + } + if (endian != '=' && PyArray_ISNBO(endian)) { + endian = '='; + } + if (endian != '=' && (*at)->byteorder != '|' + && (*at)->byteorder != endian) { + PyArray_DESCR_REPLACE(*at); + (*at)->byteorder = endian; + } + return PY_SUCCEED; + + fail: + PyErr_SetString(PyExc_TypeError, "data type not understood"); + *at = NULL; + return PY_FAIL; +} + /** Array Descr Objects for dynamic types **/ /* @@ -733,6 +1648,72 @@ arraydescr_setstate(PyArray_Descr *self, PyObject *args) return Py_None; } +/*NUMPY_API + * Get type-descriptor from an object forcing alignment if possible + * None goes to DEFAULT type. + * + * any object with the .fields attribute and/or .itemsize attribute (if the + *.fields attribute does not give the total size -- i.e. a partial record + * naming). If itemsize is given it must be >= size computed from fields + * + * The .fields attribute must return a convertible dictionary if present. + * Result inherits from PyArray_VOID. +*/ +NPY_NO_EXPORT int +PyArray_DescrAlignConverter(PyObject *obj, PyArray_Descr **at) +{ + if PyDict_Check(obj) { + *at = _convert_from_dict(obj, 1); + } + else if PyString_Check(obj) { + *at = _convert_from_commastring(obj, 1); + } + else if PyList_Check(obj) { + *at = _convert_from_array_descr(obj, 1); + } + else { + return PyArray_DescrConverter(obj, at); + } + if (*at == NULL) { + if (!PyErr_Occurred()) { + PyErr_SetString(PyExc_ValueError, + "data-type-descriptor not understood"); + } + return PY_FAIL; + } + return PY_SUCCEED; +} + +/*NUMPY_API + * Get type-descriptor from an object forcing alignment if possible + * None goes to NULL. + */ +NPY_NO_EXPORT int +PyArray_DescrAlignConverter2(PyObject *obj, PyArray_Descr **at) +{ + if PyDict_Check(obj) { + *at = _convert_from_dict(obj, 1); + } + else if PyString_Check(obj) { + *at = _convert_from_commastring(obj, 1); + } + else if PyList_Check(obj) { + *at = _convert_from_array_descr(obj, 1); + } + else { + return PyArray_DescrConverter2(obj, at); + } + if (*at == NULL) { + if (!PyErr_Occurred()) { + PyErr_SetString(PyExc_ValueError, + "data-type-descriptor not understood"); + } + return PY_FAIL; + } + return PY_SUCCEED; +} + + /*NUMPY_API * returns a copy of the PyArray_Descr structure with the byteorder diff --git a/numpy/core/src/arraydescr.h b/numpy/core/src/arraydescr.h index 34c05a3d5..005f55aa1 100644 --- a/numpy/core/src/arraydescr.h +++ b/numpy/core/src/arraydescr.h @@ -4,4 +4,7 @@ NPY_NO_EXPORT PyObject *arraydescr_protocol_typestr_get(PyArray_Descr *); NPY_NO_EXPORT PyObject *arraydescr_protocol_descr_get(PyArray_Descr *self); +NPY_NO_EXPORT PyObject * +array_set_typeDict(PyObject *NPY_UNUSED(ignored), PyObject *args); + #endif diff --git a/numpy/core/src/multiarraymodule.c b/numpy/core/src/multiarraymodule.c index 3eb09187e..0ec8c4485 100644 --- a/numpy/core/src/multiarraymodule.c +++ b/numpy/core/src/multiarraymodule.c @@ -30,11 +30,10 @@ /* Internal APIs */ #include "arrayobject.h" #include "hashdescr.h" +#include "arraydescr.h" NPY_NO_EXPORT int NPY_NUMUSERTYPES = 0; -static PyObject *typeDict = NULL; /* Must be explicitly loaded */ - NPY_NO_EXPORT PyArray_Descr * _arraydescr_fromobj(PyObject *obj) { @@ -1465,132 +1464,6 @@ PyArray_CanCoerceScalar(int thistype, int neededtype, } } -/* Raises error when len(op) == 0 */ - -/*NUMPY_API*/ -NPY_NO_EXPORT PyArrayObject ** -PyArray_ConvertToCommonType(PyObject *op, int *retn) -{ - int i, n, allscalars = 0; - PyArrayObject **mps = NULL; - PyObject *otmp; - PyArray_Descr *intype = NULL, *stype = NULL; - PyArray_Descr *newtype = NULL; - NPY_SCALARKIND scalarkind = NPY_NOSCALAR, intypekind = NPY_NOSCALAR; - - *retn = n = PySequence_Length(op); - if (n == 0) { - PyErr_SetString(PyExc_ValueError, "0-length sequence."); - } - if (PyErr_Occurred()) { - *retn = 0; - return NULL; - } - mps = (PyArrayObject **)PyDataMem_NEW(n*sizeof(PyArrayObject *)); - if (mps == NULL) { - *retn = 0; - return (void*)PyErr_NoMemory(); - } - - if (PyArray_Check(op)) { - for (i = 0; i < n; i++) { - mps[i] = (PyArrayObject *) array_big_item((PyArrayObject *)op, i); - } - if (!PyArray_ISCARRAY(op)) { - for (i = 0; i < n; i++) { - PyObject *obj; - obj = PyArray_NewCopy(mps[i], NPY_CORDER); - Py_DECREF(mps[i]); - mps[i] = (PyArrayObject *)obj; - } - } - return mps; - } - - for (i = 0; i < n; i++) { - otmp = PySequence_GetItem(op, i); - if (!PyArray_CheckAnyScalar(otmp)) { - newtype = PyArray_DescrFromObject(otmp, intype); - Py_XDECREF(intype); - intype = newtype; - mps[i] = NULL; - intypekind = PyArray_ScalarKind(intype->type_num, NULL); - } - else { - newtype = PyArray_DescrFromObject(otmp, stype); - Py_XDECREF(stype); - stype = newtype; - scalarkind = PyArray_ScalarKind(newtype->type_num, NULL); - mps[i] = (PyArrayObject *)Py_None; - Py_INCREF(Py_None); - } - Py_XDECREF(otmp); - } - if (intype==NULL) { - /* all scalars */ - allscalars = 1; - intype = stype; - Py_INCREF(intype); - for (i = 0; i < n; i++) { - Py_XDECREF(mps[i]); - mps[i] = NULL; - } - } - else if ((stype != NULL) && (intypekind != scalarkind)) { - /* - * we need to upconvert to type that - * handles both intype and stype - * also don't forcecast the scalars. - */ - if (!PyArray_CanCoerceScalar(stype->type_num, - intype->type_num, - scalarkind)) { - newtype = _array_small_type(intype, stype); - Py_XDECREF(intype); - intype = newtype; - } - for (i = 0; i < n; i++) { - Py_XDECREF(mps[i]); - mps[i] = NULL; - } - } - - - /* Make sure all arrays are actual array objects. */ - for (i = 0; i < n; i++) { - int flags = CARRAY; - - if ((otmp = PySequence_GetItem(op, i)) == NULL) { - goto fail; - } - if (!allscalars && ((PyObject *)(mps[i]) == Py_None)) { - /* forcecast scalars */ - flags |= FORCECAST; - Py_DECREF(Py_None); - } - Py_INCREF(intype); - mps[i] = (PyArrayObject*) - PyArray_FromAny(otmp, intype, 0, 0, flags, NULL); - Py_DECREF(otmp); - if (mps[i] == NULL) { - goto fail; - } - } - Py_DECREF(intype); - Py_XDECREF(stype); - return mps; - - fail: - Py_XDECREF(intype); - Py_XDECREF(stype); - *retn = 0; - for (i = 0; i < n; i++) { - Py_XDECREF(mps[i]); - } - PyDataMem_FREE(mps); - return NULL; -} - /* * Make a new empty array, of the passed size, of a type that takes the * priority of ap1 and ap2 into account. @@ -2671,966 +2544,6 @@ PyArray_IntpConverter(PyObject *obj, PyArray_Dims *seq) } -/* - * A tuple type would be either (generic typeobject, typesize) - * or (fixed-length data-type, shape) - * - * or (inheriting data-type, new-data-type) - * The new data-type must have the same itemsize as the inheriting data-type - * unless the latter is 0 - * - * Thus (int32, {'real':(int16,0),'imag',(int16,2)}) - * - * is one way to specify a descriptor that will give - * a['real'] and a['imag'] to an int32 array. - * - * leave type reference alone - */ -static PyArray_Descr * -_use_inherit(PyArray_Descr *type, PyObject *newobj, int *errflag) -{ - PyArray_Descr *new; - PyArray_Descr *conv; - - *errflag = 0; - if (!PyArray_DescrConverter(newobj, &conv)) { - return NULL; - } - *errflag = 1; - new = PyArray_DescrNew(type); - if (new == NULL) { - goto fail; - } - if (new->elsize && new->elsize != conv->elsize) { - PyErr_SetString(PyExc_ValueError, - "mismatch in size of old "\ - "and new data-descriptor"); - goto fail; - } - new->elsize = conv->elsize; - if (conv->names) { - new->fields = conv->fields; - Py_XINCREF(new->fields); - new->names = conv->names; - Py_XINCREF(new->names); - } - new->hasobject = conv->hasobject; - Py_DECREF(conv); - *errflag = 0; - return new; - - fail: - Py_DECREF(conv); - return NULL; -} - -static PyArray_Descr * -_convert_from_tuple(PyObject *obj) -{ - PyArray_Descr *type, *res; - PyObject *val; - int errflag; - - if (PyTuple_GET_SIZE(obj) != 2) { - return NULL; - } - if (!PyArray_DescrConverter(PyTuple_GET_ITEM(obj,0), &type)) { - return NULL; - } - val = PyTuple_GET_ITEM(obj,1); - /* try to interpret next item as a type */ - res = _use_inherit(type, val, &errflag); - if (res || errflag) { - Py_DECREF(type); - if (res) { - return res; - } - else { - return NULL; - } - } - PyErr_Clear(); - /* - * We get here if res was NULL but errflag wasn't set - * --- i.e. the conversion to a data-descr failed in _use_inherit - */ - if (type->elsize == 0) { - /* interpret next item as a typesize */ - int itemsize = PyArray_PyIntAsInt(PyTuple_GET_ITEM(obj,1)); - - if (error_converting(itemsize)) { - PyErr_SetString(PyExc_ValueError, - "invalid itemsize in generic type "\ - "tuple"); - goto fail; - } - PyArray_DESCR_REPLACE(type); - if (type->type_num == PyArray_UNICODE) { - type->elsize = itemsize << 2; - } - else { - type->elsize = itemsize; - } - } - else { - /* - * interpret next item as shape (if it's a tuple) - * and reset the type to PyArray_VOID with - * a new fields attribute. - */ - PyArray_Dims shape = {NULL, -1}; - PyArray_Descr *newdescr; - - if (!(PyArray_IntpConverter(val, &shape)) - || (shape.len > MAX_DIMS)) { - PyDimMem_FREE(shape.ptr); - PyErr_SetString(PyExc_ValueError, - "invalid shape in fixed-type tuple."); - goto fail; - } - /* If (type, 1) was given, it is equivalent to type... - or (type, ()) was given it is equivalent to type... */ - if ((shape.len == 1 && shape.ptr[0] == 1 && PyNumber_Check(val)) - || (shape.len == 0 && PyTuple_Check(val))) { - PyDimMem_FREE(shape.ptr); - return type; - } - newdescr = PyArray_DescrNewFromType(PyArray_VOID); - if (newdescr == NULL) { - PyDimMem_FREE(shape.ptr); - goto fail; - } - newdescr->elsize = type->elsize; - newdescr->elsize *= PyArray_MultiplyList(shape.ptr, shape.len); - PyDimMem_FREE(shape.ptr); - newdescr->subarray = _pya_malloc(sizeof(PyArray_ArrayDescr)); - newdescr->subarray->base = type; - newdescr->hasobject = type->hasobject; - Py_INCREF(val); - newdescr->subarray->shape = val; - Py_XDECREF(newdescr->fields); - Py_XDECREF(newdescr->names); - newdescr->fields = NULL; - newdescr->names = NULL; - type = newdescr; - } - return type; - - fail: - Py_XDECREF(type); - return NULL; -} - -/* - * obj is a list. Each item is a tuple with - * - * (field-name, data-type (either a list or a string), and an optional - * shape parameter). - */ -static PyArray_Descr * -_convert_from_array_descr(PyObject *obj, int align) -{ - int n, i, totalsize; - int ret; - PyObject *fields, *item, *newobj; - PyObject *name, *tup, *title; - PyObject *nameslist; - PyArray_Descr *new; - PyArray_Descr *conv; - int dtypeflags = 0; - int maxalign = 0; - - - n = PyList_GET_SIZE(obj); - nameslist = PyTuple_New(n); - if (!nameslist) { - return NULL; - } - totalsize = 0; - fields = PyDict_New(); - for (i = 0; i < n; i++) { - item = PyList_GET_ITEM(obj, i); - if (!PyTuple_Check(item) || (PyTuple_GET_SIZE(item) < 2)) { - goto fail; - } - name = PyTuple_GET_ITEM(item, 0); - if (PyString_Check(name)) { - title = NULL; - } - else if (PyTuple_Check(name)) { - if (PyTuple_GET_SIZE(name) != 2) { - goto fail; - } - title = PyTuple_GET_ITEM(name, 0); - name = PyTuple_GET_ITEM(name, 1); - if (!PyString_Check(name)) { - goto fail; - } - } - else { - goto fail; - } - if (PyString_GET_SIZE(name)==0) { - if (title == NULL) { - name = PyString_FromFormat("f%d", i); - } - else { - name = title; - Py_INCREF(name); - } - } - else { - Py_INCREF(name); - } - PyTuple_SET_ITEM(nameslist, i, name); - if (PyTuple_GET_SIZE(item) == 2) { - ret = PyArray_DescrConverter(PyTuple_GET_ITEM(item, 1), &conv); - if (ret == PY_FAIL) { - PyObject_Print(PyTuple_GET_ITEM(item,1), stderr, 0); - } - } - else if (PyTuple_GET_SIZE(item) == 3) { - newobj = PyTuple_GetSlice(item, 1, 3); - ret = PyArray_DescrConverter(newobj, &conv); - Py_DECREF(newobj); - } - else { - goto fail; - } - if (ret == PY_FAIL) { - goto fail; - } - if ((PyDict_GetItem(fields, name) != NULL) || - (title && - (PyString_Check(title) || PyUnicode_Check(title)) && - (PyDict_GetItem(fields, title) != NULL))) { - PyErr_SetString(PyExc_ValueError, - "two fields with the same name"); - goto fail; - } - dtypeflags |= (conv->hasobject & NPY_FROM_FIELDS); - tup = PyTuple_New((title == NULL ? 2 : 3)); - PyTuple_SET_ITEM(tup, 0, (PyObject *)conv); - if (align) { - int _align; - - _align = conv->alignment; - if (_align > 1) { - totalsize = ((totalsize + _align - 1)/_align)*_align; - } - maxalign = MAX(maxalign, _align); - } - PyTuple_SET_ITEM(tup, 1, PyInt_FromLong((long) totalsize)); - - /* - * Title can be "meta-data". Only insert it - * into the fields dictionary if it is a string - */ - if (title != NULL) { - Py_INCREF(title); - PyTuple_SET_ITEM(tup, 2, title); - if (PyString_Check(title) || PyUnicode_Check(title)) { - PyDict_SetItem(fields, title, tup); - } - } - PyDict_SetItem(fields, name, tup); - totalsize += conv->elsize; - Py_DECREF(tup); - } - new = PyArray_DescrNewFromType(PyArray_VOID); - new->fields = fields; - new->names = nameslist; - new->elsize = totalsize; - new->hasobject=dtypeflags; - if (maxalign > 1) { - totalsize = ((totalsize+maxalign-1)/maxalign)*maxalign; - } - if (align) { - new->alignment = maxalign; - } - return new; - - fail: - Py_DECREF(fields); - Py_DECREF(nameslist); - return NULL; - -} - -/* - * a list specifying a data-type can just be - * a list of formats. The names for the fields - * will default to f0, f1, f2, and so forth. - */ -static PyArray_Descr * -_convert_from_list(PyObject *obj, int align) -{ - int n, i; - int totalsize; - PyObject *fields; - PyArray_Descr *conv = NULL; - PyArray_Descr *new; - PyObject *key, *tup; - PyObject *nameslist = NULL; - int ret; - int maxalign = 0; - int dtypeflags = 0; - - n = PyList_GET_SIZE(obj); - /* - * Ignore any empty string at end which _internal._commastring - * can produce - */ - key = PyList_GET_ITEM(obj, n-1); - if (PyString_Check(key) && PyString_GET_SIZE(key) == 0) { - n = n - 1; - } - /* End ignore code.*/ - totalsize = 0; - if (n == 0) { - return NULL; - } - nameslist = PyTuple_New(n); - if (!nameslist) { - return NULL; - } - fields = PyDict_New(); - for (i = 0; i < n; i++) { - tup = PyTuple_New(2); - key = PyString_FromFormat("f%d", i); - ret = PyArray_DescrConverter(PyList_GET_ITEM(obj, i), &conv); - if (ret == PY_FAIL) { - Py_DECREF(tup); - Py_DECREF(key); - goto fail; - } - dtypeflags |= (conv->hasobject & NPY_FROM_FIELDS); - PyTuple_SET_ITEM(tup, 0, (PyObject *)conv); - if (align) { - int _align; - - _align = conv->alignment; - if (_align > 1) { - totalsize = ((totalsize + _align - 1)/_align)*_align; - } - maxalign = MAX(maxalign, _align); - } - PyTuple_SET_ITEM(tup, 1, PyInt_FromLong((long) totalsize)); - PyDict_SetItem(fields, key, tup); - Py_DECREF(tup); - PyTuple_SET_ITEM(nameslist, i, key); - totalsize += conv->elsize; - } - new = PyArray_DescrNewFromType(PyArray_VOID); - new->fields = fields; - new->names = nameslist; - new->hasobject=dtypeflags; - if (maxalign > 1) { - totalsize = ((totalsize+maxalign-1)/maxalign)*maxalign; - } - if (align) { - new->alignment = maxalign; - } - new->elsize = totalsize; - return new; - - fail: - Py_DECREF(nameslist); - Py_DECREF(fields); - return NULL; -} - - -/* - * comma-separated string - * this is the format developed by the numarray records module - * and implemented by the format parser in that module - * this is an alternative implementation found in the _internal.py - * file patterned after that one -- the approach is to try to convert - * to a list (with tuples if any repeat information is present) - * and then call the _convert_from_list) - */ -static PyArray_Descr * -_convert_from_commastring(PyObject *obj, int align) -{ - PyObject *listobj; - PyArray_Descr *res; - PyObject *_numpy_internal; - - if (!PyString_Check(obj)) { - return NULL; - } - _numpy_internal = PyImport_ImportModule("numpy.core._internal"); - if (_numpy_internal == NULL) { - return NULL; - } - listobj = PyObject_CallMethod(_numpy_internal, "_commastring", "O", obj); - Py_DECREF(_numpy_internal); - if (!listobj) { - return NULL; - } - if (!PyList_Check(listobj) || PyList_GET_SIZE(listobj)<1) { - PyErr_SetString(PyExc_RuntimeError, "_commastring is " \ - "not returning a list with len >= 1"); - return NULL; - } - if (PyList_GET_SIZE(listobj) == 1) { - if (PyArray_DescrConverter(PyList_GET_ITEM(listobj, 0), - &res) == NPY_FAIL) { - res = NULL; - } - } - else { - res = _convert_from_list(listobj, align); - } - Py_DECREF(listobj); - if (!res && !PyErr_Occurred()) { - PyErr_SetString(PyExc_ValueError, "invalid data-type"); - return NULL; - } - return res; -} - - - -/* - * a dictionary specifying a data-type - * must have at least two and up to four - * keys These must all be sequences of the same length. - * - * "names" --- field names - * "formats" --- the data-type descriptors for the field. - * - * Optional: - * - * "offsets" --- integers indicating the offset into the - * record of the start of the field. - * if not given, then "consecutive offsets" - * will be assumed and placed in the dictionary. - * - * "titles" --- Allows the use of an additional key - * for the fields dictionary.(if these are strings - * or unicode objects) or - * this can also be meta-data to - * be passed around with the field description. - * - * Attribute-lookup-based field names merely has to query the fields - * dictionary of the data-descriptor. Any result present can be used - * to return the correct field. - * - * So, the notion of what is a name and what is a title is really quite - * arbitrary. - * - * What does distinguish a title, however, is that if it is not None, - * it will be placed at the end of the tuple inserted into the - * fields dictionary.and can therefore be used to carry meta-data around. - * - * If the dictionary does not have "names" and "formats" entries, - * then it will be checked for conformity and used directly. - */ -static PyArray_Descr * -_use_fields_dict(PyObject *obj, int align) -{ - PyObject *_numpy_internal; - PyArray_Descr *res; - - _numpy_internal = PyImport_ImportModule("numpy.core._internal"); - if (_numpy_internal == NULL) { - return NULL; - } - res = (PyArray_Descr *)PyObject_CallMethod(_numpy_internal, - "_usefields", - "Oi", obj, align); - Py_DECREF(_numpy_internal); - return res; -} - -static PyArray_Descr * -_convert_from_dict(PyObject *obj, int align) -{ - PyArray_Descr *new; - PyObject *fields = NULL; - PyObject *names, *offsets, *descrs, *titles; - int n, i; - int totalsize; - int maxalign = 0; - int dtypeflags = 0; - - fields = PyDict_New(); - if (fields == NULL) { - return (PyArray_Descr *)PyErr_NoMemory(); - } - names = PyDict_GetItemString(obj, "names"); - descrs = PyDict_GetItemString(obj, "formats"); - if (!names || !descrs) { - Py_DECREF(fields); - return _use_fields_dict(obj, align); - } - n = PyObject_Length(names); - offsets = PyDict_GetItemString(obj, "offsets"); - titles = PyDict_GetItemString(obj, "titles"); - if ((n > PyObject_Length(descrs)) - || (offsets && (n > PyObject_Length(offsets))) - || (titles && (n > PyObject_Length(titles)))) { - PyErr_SetString(PyExc_ValueError, - "all items in the dictionary must have" \ - " the same length."); - goto fail; - } - - totalsize = 0; - for (i = 0; i < n; i++) { - PyObject *tup, *descr, *index, *item, *name, *off; - int len, ret, _align = 1; - PyArray_Descr *newdescr; - - /* Build item to insert (descr, offset, [title])*/ - len = 2; - item = NULL; - index = PyInt_FromLong(i); - if (titles) { - item=PyObject_GetItem(titles, index); - if (item && item != Py_None) { - len = 3; - } - else { - Py_XDECREF(item); - } - PyErr_Clear(); - } - tup = PyTuple_New(len); - descr = PyObject_GetItem(descrs, index); - ret = PyArray_DescrConverter(descr, &newdescr); - Py_DECREF(descr); - if (ret == PY_FAIL) { - Py_DECREF(tup); - Py_DECREF(index); - goto fail; - } - PyTuple_SET_ITEM(tup, 0, (PyObject *)newdescr); - if (align) { - _align = newdescr->alignment; - maxalign = MAX(maxalign,_align); - } - if (offsets) { - long offset; - off = PyObject_GetItem(offsets, index); - offset = PyInt_AsLong(off); - PyTuple_SET_ITEM(tup, 1, off); - if (offset < totalsize) { - PyErr_SetString(PyExc_ValueError, - "invalid offset (must be "\ - "ordered)"); - ret = PY_FAIL; - } - if (offset > totalsize) totalsize = offset; - } - else { - if (align && _align > 1) { - totalsize = ((totalsize + _align - 1)/_align)*_align; - } - PyTuple_SET_ITEM(tup, 1, PyInt_FromLong(totalsize)); - } - if (len == 3) { - PyTuple_SET_ITEM(tup, 2, item); - } - name = PyObject_GetItem(names, index); - Py_DECREF(index); - if (!(PyString_Check(name) || PyUnicode_Check(name))) { - PyErr_SetString(PyExc_ValueError, - "field names must be strings"); - ret = PY_FAIL; - } - - /* Insert into dictionary */ - if (PyDict_GetItem(fields, name) != NULL) { - PyErr_SetString(PyExc_ValueError, - "name already used as a name or "\ - "title"); - ret = PY_FAIL; - } - PyDict_SetItem(fields, name, tup); - Py_DECREF(name); - if (len == 3) { - if ((PyString_Check(item) || PyUnicode_Check(item)) - && PyDict_GetItem(fields, item) != NULL) { - PyErr_SetString(PyExc_ValueError, - "title already used as a "\ - "name or title."); - ret=PY_FAIL; - } - else { - PyDict_SetItem(fields, item, tup); - } - } - Py_DECREF(tup); - if ((ret == PY_FAIL) || (newdescr->elsize == 0)) { - goto fail; - } - dtypeflags |= (newdescr->hasobject & NPY_FROM_FIELDS); - totalsize += newdescr->elsize; - } - - new = PyArray_DescrNewFromType(PyArray_VOID); - if (new == NULL) { - goto fail; - } - if (maxalign > 1) { - totalsize = ((totalsize + maxalign - 1)/maxalign)*maxalign; - } - if (align) { - new->alignment = maxalign; - } - new->elsize = totalsize; - if (!PyTuple_Check(names)) { - names = PySequence_Tuple(names); - } - else { - Py_INCREF(names); - } - new->names = names; - new->fields = fields; - new->hasobject = dtypeflags; - return new; - - fail: - Py_XDECREF(fields); - return NULL; -} - -#define _chk_byteorder(arg) (arg == '>' || arg == '<' || \ - arg == '|' || arg == '=') - -static int -_check_for_commastring(char *type, int len) -{ - int i; - - /* Check for ints at start of string */ - if ((type[0] >= '0' && type[0] <= '9') || - ((len > 1) && _chk_byteorder(type[0]) && - (type[1] >= '0' && type[1] <= '9'))) { - return 1; - } - /* Check for empty tuple */ - if (((len > 1) && (type[0] == '(' && type[1] == ')')) || - ((len > 3) && _chk_byteorder(type[0]) && - (type[1] == '(' && type[2] == ')'))) { - return 1; - } - /* Check for presence of commas */ - for (i = 1; i < len; i++) { - if (type[i] == ',') { - return 1; - } - } - return 0; -} - -#undef _chk_byteorder - -/*NUMPY_API - * Get type-descriptor from an object forcing alignment if possible - * None goes to DEFAULT type. - * - * any object with the .fields attribute and/or .itemsize attribute (if the - *.fields attribute does not give the total size -- i.e. a partial record - * naming). If itemsize is given it must be >= size computed from fields - * - * The .fields attribute must return a convertible dictionary if present. - * Result inherits from PyArray_VOID. -*/ -NPY_NO_EXPORT int -PyArray_DescrAlignConverter(PyObject *obj, PyArray_Descr **at) -{ - if PyDict_Check(obj) { - *at = _convert_from_dict(obj, 1); - } - else if PyString_Check(obj) { - *at = _convert_from_commastring(obj, 1); - } - else if PyList_Check(obj) { - *at = _convert_from_array_descr(obj, 1); - } - else { - return PyArray_DescrConverter(obj, at); - } - if (*at == NULL) { - if (!PyErr_Occurred()) { - PyErr_SetString(PyExc_ValueError, - "data-type-descriptor not understood"); - } - return PY_FAIL; - } - return PY_SUCCEED; -} - -/*NUMPY_API - * Get type-descriptor from an object forcing alignment if possible - * None goes to NULL. - */ -NPY_NO_EXPORT int -PyArray_DescrAlignConverter2(PyObject *obj, PyArray_Descr **at) -{ - if PyDict_Check(obj) { - *at = _convert_from_dict(obj, 1); - } - else if PyString_Check(obj) { - *at = _convert_from_commastring(obj, 1); - } - else if PyList_Check(obj) { - *at = _convert_from_array_descr(obj, 1); - } - else { - return PyArray_DescrConverter2(obj, at); - } - if (*at == NULL) { - if (!PyErr_Occurred()) { - PyErr_SetString(PyExc_ValueError, - "data-type-descriptor not understood"); - } - return PY_FAIL; - } - return PY_SUCCEED; -} - - -/*NUMPY_API - * Get typenum from an object -- None goes to NULL - */ -NPY_NO_EXPORT int -PyArray_DescrConverter2(PyObject *obj, PyArray_Descr **at) -{ - if (obj == Py_None) { - *at = NULL; - return PY_SUCCEED; - } - else { - return PyArray_DescrConverter(obj, at); - } -} - -/*NUMPY_API - * Get typenum from an object -- None goes to PyArray_DEFAULT - * This function takes a Python object representing a type and converts it - * to a the correct PyArray_Descr * structure to describe the type. - * - * Many objects can be used to represent a data-type which in NumPy is - * quite a flexible concept. - * - * This is the central code that converts Python objects to - * Type-descriptor objects that are used throughout numpy. - * new reference in *at - */ -NPY_NO_EXPORT int -PyArray_DescrConverter(PyObject *obj, PyArray_Descr **at) -{ - char *type; - int check_num = PyArray_NOTYPE + 10; - int len; - PyObject *item; - int elsize = 0; - char endian = '='; - - *at = NULL; - /* default */ - if (obj == Py_None) { - *at = PyArray_DescrFromType(PyArray_DEFAULT); - return PY_SUCCEED; - } - if (PyArray_DescrCheck(obj)) { - *at = (PyArray_Descr *)obj; - Py_INCREF(*at); - return PY_SUCCEED; - } - - if (PyType_Check(obj)) { - if (PyType_IsSubtype((PyTypeObject *)obj, - &PyGenericArrType_Type)) { - *at = PyArray_DescrFromTypeObject(obj); - if (*at) { - return PY_SUCCEED; - } - else { - return PY_FAIL; - } - } - check_num = PyArray_OBJECT; - if (obj == (PyObject *)(&PyInt_Type)) { - check_num = PyArray_LONG; - } - else if (obj == (PyObject *)(&PyLong_Type)) { - check_num = PyArray_LONGLONG; - } - else if (obj == (PyObject *)(&PyFloat_Type)) { - check_num = PyArray_DOUBLE; - } - else if (obj == (PyObject *)(&PyComplex_Type)) { - check_num = PyArray_CDOUBLE; - } - else if (obj == (PyObject *)(&PyBool_Type)) { - check_num = PyArray_BOOL; - } - else if (obj == (PyObject *)(&PyString_Type)) { - check_num = PyArray_STRING; - } - else if (obj == (PyObject *)(&PyUnicode_Type)) { - check_num = PyArray_UNICODE; - } - else if (obj == (PyObject *)(&PyBuffer_Type)) { - check_num = PyArray_VOID; - } - else { - *at = _arraydescr_fromobj(obj); - if (*at) { - return PY_SUCCEED; - } - } - goto finish; - } - - /* or a typecode string */ - if (PyString_Check(obj)) { - /* Check for a string typecode. */ - type = PyString_AS_STRING(obj); - len = PyString_GET_SIZE(obj); - if (len <= 0) { - goto fail; - } - /* check for commas present or first (or second) element a digit */ - if (_check_for_commastring(type, len)) { - *at = _convert_from_commastring(obj, 0); - if (*at) { - return PY_SUCCEED; - } - return PY_FAIL; - } - check_num = (int) type[0]; - if ((char) check_num == '>' || (char) check_num == '<' - || (char) check_num == '|' || (char) check_num == '=') { - if (len <= 1) { - goto fail; - } - endian = (char) check_num; - type++; len--; - check_num = (int) type[0]; - if (endian == '|') { - endian = '='; - } - } - if (len > 1) { - elsize = atoi(type + 1); - if (elsize == 0) { - check_num = PyArray_NOTYPE+10; - } - /* - * When specifying length of UNICODE - * the number of characters is given to match - * the STRING interface. Each character can be - * more than one byte and itemsize must be - * the number of bytes. - */ - else if (check_num == PyArray_UNICODELTR) { - elsize <<= 2; - } - /* Support for generic processing c4, i4, f8, etc...*/ - else if ((check_num != PyArray_STRINGLTR) - && (check_num != PyArray_VOIDLTR) - && (check_num != PyArray_STRINGLTR2)) { - check_num = PyArray_TypestrConvert(elsize, check_num); - if (check_num == PyArray_NOTYPE) { - check_num += 10; - } - elsize = 0; - } - } - } - else if (PyTuple_Check(obj)) { - /* or a tuple */ - *at = _convert_from_tuple(obj); - if (*at == NULL){ - if (PyErr_Occurred()) { - return PY_FAIL; - } - goto fail; - } - return PY_SUCCEED; - } - else if (PyList_Check(obj)) { - /* or a list */ - *at = _convert_from_array_descr(obj,0); - if (*at == NULL) { - if (PyErr_Occurred()) { - return PY_FAIL; - } - goto fail; - } - return PY_SUCCEED; - } - else if (PyDict_Check(obj)) { - /* or a dictionary */ - *at = _convert_from_dict(obj,0); - if (*at == NULL) { - if (PyErr_Occurred()) { - return PY_FAIL; - } - goto fail; - } - return PY_SUCCEED; - } - else if (PyArray_Check(obj)) { - goto fail; - } - else { - *at = _arraydescr_fromobj(obj); - if (*at) { - return PY_SUCCEED; - } - if (PyErr_Occurred()) { - return PY_FAIL; - } - goto fail; - } - if (PyErr_Occurred()) { - goto fail; - } - /* - if (check_num == PyArray_NOTYPE) return PY_FAIL; - */ - - finish: - if ((check_num == PyArray_NOTYPE + 10) - || (*at = PyArray_DescrFromType(check_num)) == NULL) { - /* Now check to see if the object is registered in typeDict */ - if (typeDict != NULL) { - item = PyDict_GetItem(typeDict, obj); - if (item) { - return PyArray_DescrConverter(item, at); - } - } - goto fail; - } - - if (((*at)->elsize == 0) && (elsize != 0)) { - PyArray_DESCR_REPLACE(*at); - (*at)->elsize = elsize; - } - if (endian != '=' && PyArray_ISNBO(endian)) { - endian = '='; - } - if (endian != '=' && (*at)->byteorder != '|' - && (*at)->byteorder != endian) { - PyArray_DESCR_REPLACE(*at); - (*at)->byteorder = endian; - } - return PY_SUCCEED; - - fail: - PyErr_SetString(PyExc_TypeError, "data type not understood"); - *at = NULL; - return PY_FAIL; -} - /*NUMPY_API * Convert object to endian */ @@ -4065,24 +2978,6 @@ array_zeros(PyObject *NPY_UNUSED(ignored), PyObject *args, PyObject *kwds) } static PyObject * -array_set_typeDict(PyObject *NPY_UNUSED(ignored), PyObject *args) -{ - PyObject *dict; - - if (!PyArg_ParseTuple(args, "O", &dict)) { - return NULL; - } - /* Decrement old reference (if any)*/ - Py_XDECREF(typeDict); - typeDict = dict; - /* Create an internal reference to it */ - Py_INCREF(dict); - Py_INCREF(Py_None); - return Py_None; -} - - -static PyObject * array_fromstring(PyObject *NPY_UNUSED(ignored), PyObject *args, PyObject *keywds) { char *data; |