summaryrefslogtreecommitdiff
path: root/numpy
diff options
context:
space:
mode:
Diffstat (limited to 'numpy')
-rw-r--r--numpy/core/_dtype.py294
-rw-r--r--numpy/core/src/multiarray/descriptor.c473
-rw-r--r--numpy/core/src/multiarray/descriptor.h26
-rw-r--r--numpy/core/tests/test_dtype.py9
4 files changed, 328 insertions, 474 deletions
diff --git a/numpy/core/_dtype.py b/numpy/core/_dtype.py
new file mode 100644
index 000000000..ca2c1eaff
--- /dev/null
+++ b/numpy/core/_dtype.py
@@ -0,0 +1,294 @@
+"""
+A place for code to be called from the implementation of np.dtype
+
+String handling is much easier to do correctly in python.
+"""
+from __future__ import division, absolute_import, print_function
+
+import numpy as np
+
+
+def __str__(dtype):
+ if dtype.fields is not None:
+ return _struct_str(dtype, include_align=True)
+ elif dtype.subdtype:
+ return _subarray_str(dtype)
+ elif issubclass(dtype.type, np.flexible) or not dtype.isnative:
+ return dtype.str
+ else:
+ return dtype.name
+
+
+def __repr__(dtype):
+ if dtype.fields is not None:
+ return _struct_repr(dtype)
+ else:
+ return "dtype({})".format(_construction_repr(dtype, include_align=True))
+
+
+def _unpack_field(dtype, offset, title=None):
+ """
+ Helper function to normalize the items in dtype.fields.
+
+ Call as:
+
+ dtype, offset, title = _unpack_field(*dtype.fields[name])
+ """
+ return dtype, offset, title
+
+
+def _isunsized(dtype):
+ # PyDataType_ISUNSIZED
+ return dtype.itemsize == 0
+
+
+def _construction_repr(dtype, include_align=False, short=False):
+ """
+ Creates a string repr of the dtype, excluding the 'dtype()' part
+ surrounding the object. This object may be a string, a list, or
+ a dict depending on the nature of the dtype. This
+ is the object passed as the first parameter to the dtype
+ constructor, and if no additional constructor parameters are
+ given, will reproduce the exact memory layout.
+
+ Parameters
+ ----------
+ short : bool
+ If true, this creates a shorter repr using 'kind' and 'itemsize', instead
+ of the longer type name.
+
+ include_align : bool
+ If true, this includes the 'align=True' parameter
+ inside the struct dtype construction dict when needed. Use this flag
+ if you want a proper repr string without the 'dtype()' part around it.
+
+ If false, this does not preserve the
+ 'align=True' parameter or sticky NPY_ALIGNED_STRUCT flag for
+ struct arrays like the regular repr does, because the 'align'
+ flag is not part of first dtype constructor parameter. This
+ mode is intended for a full 'repr', where the 'align=True' is
+ provided as the second parameter.
+ """
+ if dtype.fields is not None:
+ return _struct_str(dtype, include_align=include_align)
+ elif dtype.subdtype:
+ return _subarray_str(dtype)
+
+
+ byteorder = _byte_order_str(dtype)
+
+ if dtype.type == np.bool_:
+ if short:
+ return "'?'"
+ else:
+ return "'bool'"
+
+ elif dtype.type == np.object_:
+ # The object reference may be different sizes on different
+ # platforms, so it should never include the itemsize here.
+ return "'O'"
+
+ elif dtype.type == np.string_:
+ if _isunsized(dtype):
+ return "'S'"
+ else:
+ return "'S%d'" % dtype.itemsize
+
+ elif dtype.type == np.unicode_:
+ if _isunsized(dtype):
+ return "'%sU'" % byteorder
+ else:
+ return "'%sU%d'" % (byteorder, dtype.itemsize / 4)
+
+ elif dtype.type == np.void:
+ if _isunsized(dtype):
+ return "'V'"
+ else:
+ return "'V%d'" % dtype.itemsize
+
+ elif dtype.type == np.datetime64:
+ return "'%sM8%s'" % (byteorder, _datetime_metadata_str(dtype))
+
+ elif dtype.type == np.timedelta64:
+ return "'%sm8%s'" % (byteorder, _datetime_metadata_str(dtype))
+
+ elif np.issubdtype(dtype, np.number):
+ # Short repr with endianness, like '<f8'
+ if short or dtype.byteorder not in ('=', '|'):
+ return "'%s%c%d'" % (byteorder, dtype.kind, dtype.itemsize)
+
+ # Longer repr, like 'float64'
+ else:
+ kindstrs = {
+ 'u': "uint",
+ 'i': "int",
+ 'f': "float",
+ 'c': "complex"
+ }
+ try:
+ kindstr = kindstrs[dtype.kind]
+ except KeyError:
+ raise RuntimeError(
+ "internal dtype repr error, unknown kind {!r}"
+ .format(dtype.kind)
+ )
+ return "'%s%d'" % (kindstr, 8*dtype.itemsize)
+
+ elif dtype.isbuiltin == 2:
+ return dtype.type.__name__
+
+ else:
+ raise RuntimeError(
+ "Internal error: NumPy dtype unrecognized type number")
+
+
+def _byte_order_str(dtype):
+ """ Normalize byteorder to '<' or '>' """
+ # hack to obtain the native and swapped byte order characters
+ swapped = np.dtype(int).newbyteorder('s')
+ native = swapped.newbyteorder('s')
+
+ byteorder = dtype.byteorder
+ if byteorder == '=':
+ return native.byteorder
+ if byteorder == 's':
+ # TODO: this path can never be reached
+ return swapped.byteorder
+ elif byteorder == '|':
+ return ''
+ else:
+ return byteorder
+
+
+def _datetime_metadata_str(dtype):
+ # This is a hack since the data is not exposed to python in any other way
+ return dtype.name[dtype.name.rfind('['):]
+
+
+def _struct_dict_str(dtype, includealignedflag):
+ # unpack the fields dictionary into ls
+ names = dtype.names
+ fld_dtypes = []
+ offsets = []
+ titles = []
+ for name in names:
+ fld_dtype, offset, title = _unpack_field(*dtype.fields[name])
+ fld_dtypes.append(fld_dtype)
+ offsets.append(offset)
+ titles.append(title)
+
+ # Build up a string to make the dictionary
+
+ # First, the names
+ ret = "{'names':["
+ ret += ",".join(repr(name) for name in names)
+
+ # Second, the formats
+ ret += "], 'formats':["
+ ret += ",".join(
+ _construction_repr(fld_dtype, short=True) for fld_dtype in fld_dtypes)
+
+ # Third, the offsets
+ ret += "], 'offsets':["
+ ret += ",".join("%d" % offset for offset in offsets)
+
+ # Fourth, the titles
+ if any(title is not None for title in titles):
+ ret += "], 'titles':["
+ ret += ",".join(repr(title) for title in titles)
+
+ # Fifth, the itemsize
+ ret += "], 'itemsize':%d" % dtype.itemsize
+
+ if (includealignedflag and dtype.isalignedstruct):
+ # Finally, the aligned flag
+ ret += ", 'aligned':True}"
+ else:
+ ret += "}"
+
+ return ret
+
+
+def _is_packed(dtype):
+ """
+ Checks whether the structured data type in 'dtype'
+ has a simple layout, where all the fields are in order,
+ and follow each other with no alignment padding.
+
+ When this returns true, the dtype can be reconstructed
+ from a list of the field names and dtypes with no additional
+ dtype parameters.
+
+ Duplicates the C `is_dtype_struct_simple_unaligned_layout` functio.
+ """
+ total_offset = 0
+ for name in dtype.names:
+ fld_dtype, fld_offset, title = _unpack_field(*dtype.fields[name])
+ if fld_offset != total_offset:
+ return False
+ total_offset += fld_dtype.itemsize
+ if total_offset != dtype.itemsize:
+ return False
+ return True
+
+
+def _struct_list_str(dtype):
+ items = []
+ for name in dtype.names:
+ fld_dtype, fld_offset, title = _unpack_field(*dtype.fields[name])
+
+ item = "("
+ if title is not None:
+ item += "({!r}, {!r}), ".format(title, name)
+ else:
+ item += "{!r}, ".format(name)
+ # Special case subarray handling here
+ if fld_dtype.subdtype is not None:
+ base, shape = fld_dtype.subdtype
+ item += "{}, {}".format(
+ _construction_repr(base, short=True),
+ shape
+ )
+ else:
+ item += _construction_repr(fld_dtype, short=True)
+
+ item += ")"
+ items.append(item)
+
+ return "[" + ", ".join(items) + "]"
+
+
+def _struct_str(dtype, include_align):
+ # The list str representation can't include the 'align=' flag,
+ # so if it is requested and the struct has the aligned flag set,
+ # we must use the dict str instead.
+ if not (include_align and dtype.isalignedstruct) and _is_packed(dtype):
+ sub = _struct_list_str(dtype)
+
+ else:
+ sub = _struct_dict_str(dtype, include_align)
+
+ # If the data type isn't the default, void, show it
+ if dtype.type != np.void:
+ return "({t.__module__}.{t.__name__}, {f})".format(t=dtype.type, f=sub)
+ else:
+ return sub
+
+
+def _subarray_str(dtype):
+ base, shape = dtype.subdtype
+ return "({}, {})".format(
+ _construction_repr(base, short=True),
+ shape
+ )
+
+
+def _struct_repr(dtype):
+ s = "dtype("
+ s += _struct_str(dtype, include_align=False)
+ if dtype.isalignedstruct:
+ s += ", align=True"
+ s += ")"
+ return s
+
+
diff --git a/numpy/core/src/multiarray/descriptor.c b/numpy/core/src/multiarray/descriptor.c
index 834a8282b..8c8c0b61c 100644
--- a/numpy/core/src/multiarray/descriptor.c
+++ b/numpy/core/src/multiarray/descriptor.c
@@ -3172,462 +3172,36 @@ is_dtype_struct_simple_unaligned_layout(PyArray_Descr *dtype)
}
/*
- * Returns a string representation of a structured array,
- * in a list format.
+ * The general dtype repr function.
*/
static PyObject *
-arraydescr_struct_list_str(PyArray_Descr *dtype)
+arraydescr_repr(PyArray_Descr *dtype)
{
- PyObject *names, *key, *fields, *ret, *tmp, *tup, *title;
- Py_ssize_t i, names_size;
- PyArray_Descr *fld_dtype;
- int fld_offset;
-
- names = dtype->names;
- names_size = PyTuple_GET_SIZE(names);
- fields = dtype->fields;
-
- /* Build up a string to make the list */
-
- /* Go through all the names */
- ret = PyUString_FromString("[");
- for (i = 0; i < names_size; ++i) {
- key = PyTuple_GET_ITEM(names, i);
- tup = PyDict_GetItem(fields, key);
- if (tup == NULL) {
- return 0;
- }
- title = NULL;
- if (!PyArg_ParseTuple(tup, "Oi|O", &fld_dtype, &fld_offset, &title)) {
- PyErr_Clear();
- return 0;
- }
- PyUString_ConcatAndDel(&ret, PyUString_FromString("("));
- /* Check for whether to do titles as well */
- if (title != NULL && title != Py_None) {
- PyUString_ConcatAndDel(&ret, PyUString_FromString("("));
- PyUString_ConcatAndDel(&ret, PyObject_Repr(title));
- PyUString_ConcatAndDel(&ret, PyUString_FromString(", "));
- PyUString_ConcatAndDel(&ret, PyObject_Repr(key));
- PyUString_ConcatAndDel(&ret, PyUString_FromString("), "));
- }
- else {
- PyUString_ConcatAndDel(&ret, PyObject_Repr(key));
- PyUString_ConcatAndDel(&ret, PyUString_FromString(", "));
- }
- /* Special case subarray handling here */
- if (PyDataType_HASSUBARRAY(fld_dtype)) {
- tmp = arraydescr_construction_repr(
- fld_dtype->subarray->base, 0, 1);
- PyUString_ConcatAndDel(&ret, tmp);
- PyUString_ConcatAndDel(&ret, PyUString_FromString(", "));
- PyUString_ConcatAndDel(&ret,
- PyObject_Str(fld_dtype->subarray->shape));
- }
- else {
- tmp = arraydescr_construction_repr(fld_dtype, 0, 1);
- PyUString_ConcatAndDel(&ret, tmp);
- }
- PyUString_ConcatAndDel(&ret, PyUString_FromString(")"));
- if (i != names_size - 1) {
- PyUString_ConcatAndDel(&ret, PyUString_FromString(", "));
- }
+ PyObject *_numpy_dtype;
+ PyObject *res;
+ _numpy_dtype = PyImport_ImportModule("numpy.core._dtype");
+ if (_numpy_dtype == NULL) {
+ return NULL;
}
- PyUString_ConcatAndDel(&ret, PyUString_FromString("]"));
-
- return ret;
+ res = PyObject_CallMethod(_numpy_dtype, "__repr__", "O", dtype);
+ Py_DECREF(_numpy_dtype);
+ return res;
}
-
/*
- * Returns a string representation of a structured array,
- * in a dict format.
+ * The general dtype str function.
*/
static PyObject *
-arraydescr_struct_dict_str(PyArray_Descr *dtype, int includealignedflag)
-{
- PyObject *names, *key, *fields, *ret, *tmp, *tup, *title;
- Py_ssize_t i, names_size;
- PyArray_Descr *fld_dtype;
- int fld_offset, has_titles;
-
- names = dtype->names;
- names_size = PyTuple_GET_SIZE(names);
- fields = dtype->fields;
- has_titles = 0;
-
- /* Build up a string to make the dictionary */
-
- /* First, the names */
- ret = PyUString_FromString("{'names':[");
- for (i = 0; i < names_size; ++i) {
- key = PyTuple_GET_ITEM(names, i);
- PyUString_ConcatAndDel(&ret, PyObject_Repr(key));
- if (i != names_size - 1) {
- PyUString_ConcatAndDel(&ret, PyUString_FromString(","));
- }
- }
- /* Second, the formats */
- PyUString_ConcatAndDel(&ret, PyUString_FromString("], 'formats':["));
- for (i = 0; i < names_size; ++i) {
- key = PyTuple_GET_ITEM(names, i);
- tup = PyDict_GetItem(fields, key);
- if (tup == NULL) {
- return 0;
- }
- title = NULL;
- if (!PyArg_ParseTuple(tup, "Oi|O", &fld_dtype, &fld_offset, &title)) {
- PyErr_Clear();
- return 0;
- }
- /* Check for whether to do titles as well */
- if (title != NULL && title != Py_None) {
- has_titles = 1;
- }
- tmp = arraydescr_construction_repr(fld_dtype, 0, 1);
- PyUString_ConcatAndDel(&ret, tmp);
- if (i != names_size - 1) {
- PyUString_ConcatAndDel(&ret, PyUString_FromString(","));
- }
- }
- /* Third, the offsets */
- PyUString_ConcatAndDel(&ret, PyUString_FromString("], 'offsets':["));
- for (i = 0; i < names_size; ++i) {
- key = PyTuple_GET_ITEM(names, i);
- tup = PyDict_GetItem(fields, key);
- if (tup == NULL) {
- return 0;
- }
- if (!PyArg_ParseTuple(tup, "Oi|O", &fld_dtype, &fld_offset, &title)) {
- PyErr_Clear();
- return 0;
- }
- PyUString_ConcatAndDel(&ret, PyUString_FromFormat("%d", fld_offset));
- if (i != names_size - 1) {
- PyUString_ConcatAndDel(&ret, PyUString_FromString(","));
- }
- }
- /* Fourth, the titles */
- if (has_titles) {
- PyUString_ConcatAndDel(&ret, PyUString_FromString("], 'titles':["));
- for (i = 0; i < names_size; ++i) {
- key = PyTuple_GET_ITEM(names, i);
- tup = PyDict_GetItem(fields, key);
- if (tup == NULL) {
- return 0;
- }
- title = Py_None;
- if (!PyArg_ParseTuple(tup, "Oi|O", &fld_dtype,
- &fld_offset, &title)) {
- PyErr_Clear();
- return 0;
- }
- PyUString_ConcatAndDel(&ret, PyObject_Repr(title));
- if (i != names_size - 1) {
- PyUString_ConcatAndDel(&ret, PyUString_FromString(","));
- }
- }
- }
- if (includealignedflag && (dtype->flags&NPY_ALIGNED_STRUCT)) {
- /* Finally, the itemsize/itemsize and aligned flag */
- PyUString_ConcatAndDel(&ret,
- PyUString_FromFormat("], 'itemsize':%d, 'aligned':True}",
- (int)dtype->elsize));
- }
- else {
- /* Finally, the itemsize/itemsize*/
- PyUString_ConcatAndDel(&ret,
- PyUString_FromFormat("], 'itemsize':%d}", (int)dtype->elsize));
- }
-
- return ret;
-}
-
-/* Produces a string representation for a structured dtype */
-static PyObject *
-arraydescr_struct_str(PyArray_Descr *dtype, int includealignflag)
-{
- PyObject *sub;
-
- /*
- * The list str representation can't include the 'align=' flag,
- * so if it is requested and the struct has the aligned flag set,
- * we must use the dict str instead.
- */
- if (!(includealignflag && (dtype->flags&NPY_ALIGNED_STRUCT)) &&
- is_dtype_struct_simple_unaligned_layout(dtype)) {
- sub = arraydescr_struct_list_str(dtype);
- }
- else {
- sub = arraydescr_struct_dict_str(dtype, includealignflag);
- }
-
- /* If the data type isn't the default, void, show it */
- if (dtype->typeobj != &PyVoidArrType_Type) {
- /*
- * Note: We cannot get the type name from dtype->typeobj->tp_name
- * because its value depends on whether the type is dynamically or
- * statically allocated. Instead use __name__ and __module__.
- * See https://docs.python.org/2/c-api/typeobj.html.
- */
-
- PyObject *str_name, *namestr, *str_module, *modulestr, *ret;
-
- str_name = PyUString_FromString("__name__");
- namestr = PyObject_GetAttr((PyObject*)(dtype->typeobj), str_name);
- Py_DECREF(str_name);
-
- if (namestr == NULL) {
- /* this should never happen since types always have __name__ */
- PyErr_Format(PyExc_RuntimeError,
- "dtype does not have a __name__ attribute");
- return NULL;
- }
-
- str_module = PyUString_FromString("__module__");
- modulestr = PyObject_GetAttr((PyObject*)(dtype->typeobj), str_module);
- Py_DECREF(str_module);
-
- ret = PyUString_FromString("(");
- if (modulestr != NULL) {
- /* Note: if modulestr == NULL, the type is unpicklable */
- PyUString_ConcatAndDel(&ret, modulestr);
- PyUString_ConcatAndDel(&ret, PyUString_FromString("."));
- }
- PyUString_ConcatAndDel(&ret, namestr);
- PyUString_ConcatAndDel(&ret, PyUString_FromString(", "));
- PyUString_ConcatAndDel(&ret, sub);
- PyUString_ConcatAndDel(&ret, PyUString_FromString(")"));
- return ret;
- }
- else {
- return sub;
- }
-}
-
-/* Produces a string representation for a subarray dtype */
-static PyObject *
-arraydescr_subarray_str(PyArray_Descr *dtype)
-{
- PyObject *p, *ret;
-
- ret = PyUString_FromString("(");
- p = arraydescr_construction_repr(dtype->subarray->base, 0, 1);
- PyUString_ConcatAndDel(&ret, p);
- PyUString_ConcatAndDel(&ret, PyUString_FromString(", "));
- PyUString_ConcatAndDel(&ret, PyObject_Str(dtype->subarray->shape));
- PyUString_ConcatAndDel(&ret, PyUString_FromString(")"));
-
- return ret;
-}
-
-static PyObject *
arraydescr_str(PyArray_Descr *dtype)
{
- PyObject *sub;
-
- if (PyDataType_HASFIELDS(dtype)) {
- sub = arraydescr_struct_str(dtype, 1);
- }
- else if (PyDataType_HASSUBARRAY(dtype)) {
- sub = arraydescr_subarray_str(dtype);
- }
- else if (PyDataType_ISFLEXIBLE(dtype) || !PyArray_ISNBO(dtype->byteorder)) {
- sub = arraydescr_protocol_typestr_get(dtype);
- }
- else {
- sub = arraydescr_typename_get(dtype);
- }
- return sub;
-}
-
-/*
- * The dtype repr function specifically for structured arrays.
- */
-static PyObject *
-arraydescr_struct_repr(PyArray_Descr *dtype)
-{
- PyObject *sub, *s;
-
- s = PyUString_FromString("dtype(");
- sub = arraydescr_struct_str(dtype, 0);
- if (sub == NULL) {
+ PyObject *_numpy_dtype;
+ PyObject *res;
+ _numpy_dtype = PyImport_ImportModule("numpy.core._dtype");
+ if (_numpy_dtype == NULL) {
return NULL;
}
-
- PyUString_ConcatAndDel(&s, sub);
-
- /* If it's an aligned structure, add the align=True parameter */
- if (dtype->flags&NPY_ALIGNED_STRUCT) {
- PyUString_ConcatAndDel(&s, PyUString_FromString(", align=True"));
- }
-
- PyUString_ConcatAndDel(&s, PyUString_FromString(")"));
- return s;
-}
-
-/* See descriptor.h for documentation */
-NPY_NO_EXPORT PyObject *
-arraydescr_construction_repr(PyArray_Descr *dtype, int includealignflag,
- int shortrepr)
-{
- PyObject *ret;
- PyArray_DatetimeMetaData *meta;
- char byteorder[2];
-
- if (PyDataType_HASFIELDS(dtype)) {
- return arraydescr_struct_str(dtype, includealignflag);
- }
- else if (PyDataType_HASSUBARRAY(dtype)) {
- return arraydescr_subarray_str(dtype);
- }
-
- /* Normalize byteorder to '<' or '>' */
- switch (dtype->byteorder) {
- case NPY_NATIVE:
- byteorder[0] = NPY_NATBYTE;
- break;
- case NPY_SWAP:
- byteorder[0] = NPY_OPPBYTE;
- break;
- case NPY_IGNORE:
- byteorder[0] = '\0';
- break;
- default:
- byteorder[0] = dtype->byteorder;
- break;
- }
- byteorder[1] = '\0';
-
- /* Handle booleans, numbers, and custom dtypes */
- if (dtype->type_num == NPY_BOOL) {
- if (shortrepr) {
- return PyUString_FromString("'?'");
- }
- else {
- return PyUString_FromString("'bool'");
- }
- }
- else if (PyTypeNum_ISNUMBER(dtype->type_num)) {
- /* Short repr with endianness, like '<f8' */
- if (shortrepr || (dtype->byteorder != NPY_NATIVE &&
- dtype->byteorder != NPY_IGNORE)) {
- return PyUString_FromFormat("'%s%c%d'", byteorder,
- (int)dtype->kind, dtype->elsize);
- }
- /* Longer repr, like 'float64' */
- else {
- char *kindstr;
- switch (dtype->kind) {
- case 'u':
- kindstr = "uint";
- break;
- case 'i':
- kindstr = "int";
- break;
- case 'f':
- kindstr = "float";
- break;
- case 'c':
- kindstr = "complex";
- break;
- default:
- PyErr_Format(PyExc_RuntimeError,
- "internal dtype repr error, unknown kind '%c'",
- (int)dtype->kind);
- return NULL;
- }
- return PyUString_FromFormat("'%s%d'", kindstr, 8*dtype->elsize);
- }
- }
- else if (PyTypeNum_ISUSERDEF(dtype->type_num)) {
- char *s = strrchr(dtype->typeobj->tp_name, '.');
- if (s == NULL) {
- return PyUString_FromString(dtype->typeobj->tp_name);
- }
- else {
- return PyUString_FromStringAndSize(s + 1, strlen(s) - 1);
- }
- }
-
- /* All the rest which don't fit in the same pattern */
- switch (dtype->type_num) {
- /*
- * The object reference may be different sizes on different
- * platforms, so it should never include the itemsize here.
- */
- case NPY_OBJECT:
- return PyUString_FromString("'O'");
-
- case NPY_STRING:
- if (PyDataType_ISUNSIZED(dtype)) {
- return PyUString_FromString("'S'");
- }
- else {
- return PyUString_FromFormat("'S%d'", (int)dtype->elsize);
- }
-
- case NPY_UNICODE:
- if (PyDataType_ISUNSIZED(dtype)) {
- return PyUString_FromFormat("'%sU'", byteorder);
- }
- else {
- return PyUString_FromFormat("'%sU%d'", byteorder,
- (int)dtype->elsize / 4);
- }
-
- case NPY_VOID:
- if (PyDataType_ISUNSIZED(dtype)) {
- return PyUString_FromString("'V'");
- }
- else {
- return PyUString_FromFormat("'V%d'", (int)dtype->elsize);
- }
-
- case NPY_DATETIME:
- meta = get_datetime_metadata_from_dtype(dtype);
- if (meta == NULL) {
- return NULL;
- }
- ret = PyUString_FromFormat("'%sM8", byteorder);
- ret = append_metastr_to_string(meta, 0, ret);
- PyUString_ConcatAndDel(&ret, PyUString_FromString("'"));
- return ret;
-
- case NPY_TIMEDELTA:
- meta = get_datetime_metadata_from_dtype(dtype);
- if (meta == NULL) {
- return NULL;
- }
- ret = PyUString_FromFormat("'%sm8", byteorder);
- ret = append_metastr_to_string(meta, 0, ret);
- PyUString_ConcatAndDel(&ret, PyUString_FromString("'"));
- return ret;
-
- default:
- PyErr_SetString(PyExc_RuntimeError, "Internal error: NumPy dtype "
- "unrecognized type number");
- return NULL;
- }
-}
-
-/*
- * The general dtype repr function.
- */
-static PyObject *
-arraydescr_repr(PyArray_Descr *dtype)
-{
- PyObject *ret;
-
- if (PyDataType_HASFIELDS(dtype)) {
- return arraydescr_struct_repr(dtype);
- }
- else {
- ret = PyUString_FromString("dtype(");
- PyUString_ConcatAndDel(&ret,
- arraydescr_construction_repr(dtype, 1, 0));
- PyUString_ConcatAndDel(&ret, PyUString_FromString(")"));
- return ret;
- }
+ res = PyObject_CallMethod(_numpy_dtype, "__str__", "O", dtype);
+ Py_DECREF(_numpy_dtype);
+ return res;
}
static PyObject *
@@ -3765,10 +3339,15 @@ _check_has_fields(PyArray_Descr *self)
{
if (!PyDataType_HASFIELDS(self)) {
PyObject *astr = arraydescr_str(self);
+ if (astr == NULL) {
+ return -1;
+ }
#if defined(NPY_PY3K)
- PyObject *bstr = PyUnicode_AsUnicodeEscapeString(astr);
- Py_DECREF(astr);
- astr = bstr;
+ {
+ PyObject *bstr = PyUnicode_AsUnicodeEscapeString(astr);
+ Py_DECREF(astr);
+ astr = bstr;
+ }
#endif
PyErr_Format(PyExc_KeyError,
"There are no fields in dtype %s.", PyBytes_AsString(astr));
diff --git a/numpy/core/src/multiarray/descriptor.h b/numpy/core/src/multiarray/descriptor.h
index f95041195..5a3e4b15f 100644
--- a/numpy/core/src/multiarray/descriptor.h
+++ b/numpy/core/src/multiarray/descriptor.h
@@ -14,32 +14,6 @@ _arraydescr_fromobj(PyObject *obj);
NPY_NO_EXPORT int
is_dtype_struct_simple_unaligned_layout(PyArray_Descr *dtype);
-/*
- * Creates a string repr of the dtype, excluding the 'dtype()' part
- * surrounding the object. This object may be a string, a list, or
- * a dict depending on the nature of the dtype. This
- * is the object passed as the first parameter to the dtype
- * constructor, and if no additional constructor parameters are
- * given, will reproduce the exact memory layout.
- *
- * If 'shortrepr' is non-zero, this creates a shorter repr using
- * 'kind' and 'itemsize', instead of the longer type name.
- *
- * If 'includealignflag' is true, this includes the 'align=True' parameter
- * inside the struct dtype construction dict when needed. Use this flag
- * if you want a proper repr string without the 'dtype()' part around it.
- *
- * If 'includealignflag' is false, this does not preserve the
- * 'align=True' parameter or sticky NPY_ALIGNED_STRUCT flag for
- * struct arrays like the regular repr does, because the 'align'
- * flag is not part of first dtype constructor parameter. This
- * mode is intended for a full 'repr', where the 'align=True' is
- * provided as the second parameter.
- */
-NPY_NO_EXPORT PyObject *
-arraydescr_construction_repr(PyArray_Descr *dtype, int includealignflag,
- int shortrepr);
-
extern NPY_NO_EXPORT char *_datetime_strings[];
#endif
diff --git a/numpy/core/tests/test_dtype.py b/numpy/core/tests/test_dtype.py
index e0205a467..deaf587d6 100644
--- a/numpy/core/tests/test_dtype.py
+++ b/numpy/core/tests/test_dtype.py
@@ -552,7 +552,7 @@ class TestString(object):
assert_equal(str(dt),
"[('a', '<m8[D]'), ('b', '<M8[us]')]")
- def test_complex_dtype_repr(self):
+ def test_repr_structured(self):
dt = np.dtype([('top', [('tiles', ('>f4', (64, 64)), (1,)),
('rtile', '>f4', (64, 36))], (3,)),
('bottom', [('bleft', ('>f4', (8, 64)), (1,)),
@@ -572,6 +572,7 @@ class TestString(object):
"(('Green pixel', 'g'), 'u1'), "
"(('Blue pixel', 'b'), 'u1')], align=True)")
+ def test_repr_structured_not_packed(self):
dt = np.dtype({'names': ['rgba', 'r', 'g', 'b'],
'formats': ['<u4', 'u1', 'u1', 'u1'],
'offsets': [0, 0, 1, 2],
@@ -596,10 +597,16 @@ class TestString(object):
"'titles':['Red pixel','Blue pixel'], "
"'itemsize':4})")
+ def test_repr_structured_datetime(self):
dt = np.dtype([('a', '<M8[D]'), ('b', '<m8[us]')])
assert_equal(repr(dt),
"dtype([('a', '<M8[D]'), ('b', '<m8[us]')])")
+ def test_repr_str_subarray(self):
+ dt = np.dtype(('<i2', (1,)))
+ assert_equal(repr(dt), "dtype(('<i2', (1,)))")
+ assert_equal(str(dt), "('<i2', (1,))")
+
@pytest.mark.skipif(sys.version_info[0] >= 3, reason="Python 2 only")
def test_dtype_str_with_long_in_shape(self):
# Pull request #376, should not error