summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMatti Picus <matti.picus@gmail.com>2020-05-13 08:45:05 +0300
committerGitHub <noreply@github.com>2020-05-13 08:45:05 +0300
commit0a222b87ab733955f34719a79c0dcb44a830a31f (patch)
tree2839fde947210cbdc7fb9f8c0f11d2bf4eeb9b29
parentbeb031d64b42f4643d1ba5186c091fb1328ac8c9 (diff)
parent9cc3af7abf8728534939d37dcda07c66d68381a3 (diff)
downloadnumpy-0a222b87ab733955f34719a79c0dcb44a830a31f.tar.gz
Merge pull request #16133 from seberg/maint-cast-error
MAINT: Unify casting error creation (outside the iterator)
-rw-r--r--numpy/core/src/multiarray/array_assign_array.c15
-rw-r--r--numpy/core/src/multiarray/array_assign_scalar.c15
-rw-r--r--numpy/core/src/multiarray/convert_datatype.c48
-rw-r--r--numpy/core/src/multiarray/convert_datatype.h8
-rw-r--r--numpy/core/src/multiarray/ctors.c38
-rw-r--r--numpy/core/src/multiarray/datetime.c2
-rw-r--r--numpy/core/src/multiarray/datetime_strings.c2
-rw-r--r--numpy/core/src/multiarray/methods.c33
-rw-r--r--numpy/core/src/multiarray/methods.h2
-rw-r--r--numpy/core/src/multiarray/nditer_constr.c42
-rw-r--r--numpy/core/src/umath/ufunc_type_resolution.c19
-rw-r--r--numpy/core/tests/test_api.py11
-rw-r--r--numpy/doc/structured_arrays.py2
13 files changed, 89 insertions, 148 deletions
diff --git a/numpy/core/src/multiarray/array_assign_array.c b/numpy/core/src/multiarray/array_assign_array.c
index e40b6c719..b8dc7d516 100644
--- a/numpy/core/src/multiarray/array_assign_array.c
+++ b/numpy/core/src/multiarray/array_assign_array.c
@@ -305,19 +305,8 @@ PyArray_AssignArray(PyArrayObject *dst, PyArrayObject *src,
/* Check the casting rule */
if (!PyArray_CanCastTypeTo(PyArray_DESCR(src),
PyArray_DESCR(dst), casting)) {
- PyObject *errmsg;
- errmsg = PyUString_FromString("Cannot cast scalar from ");
- PyUString_ConcatAndDel(&errmsg,
- PyObject_Repr((PyObject *)PyArray_DESCR(src)));
- PyUString_ConcatAndDel(&errmsg,
- PyUString_FromString(" to "));
- PyUString_ConcatAndDel(&errmsg,
- PyObject_Repr((PyObject *)PyArray_DESCR(dst)));
- PyUString_ConcatAndDel(&errmsg,
- PyUString_FromFormat(" according to the rule %s",
- npy_casting_to_string(casting)));
- PyErr_SetObject(PyExc_TypeError, errmsg);
- Py_DECREF(errmsg);
+ npy_set_invalid_cast_error(
+ PyArray_DESCR(src), PyArray_DESCR(dst), casting, NPY_FALSE);
goto fail;
}
diff --git a/numpy/core/src/multiarray/array_assign_scalar.c b/numpy/core/src/multiarray/array_assign_scalar.c
index 6bc9bcfee..41eb75f1c 100644
--- a/numpy/core/src/multiarray/array_assign_scalar.c
+++ b/numpy/core/src/multiarray/array_assign_scalar.c
@@ -203,19 +203,8 @@ PyArray_AssignRawScalar(PyArrayObject *dst,
/* Check the casting rule */
if (!can_cast_scalar_to(src_dtype, src_data,
PyArray_DESCR(dst), casting)) {
- PyObject *errmsg;
- errmsg = PyUString_FromString("Cannot cast scalar from ");
- PyUString_ConcatAndDel(&errmsg,
- PyObject_Repr((PyObject *)src_dtype));
- PyUString_ConcatAndDel(&errmsg,
- PyUString_FromString(" to "));
- PyUString_ConcatAndDel(&errmsg,
- PyObject_Repr((PyObject *)PyArray_DESCR(dst)));
- PyUString_ConcatAndDel(&errmsg,
- PyUString_FromFormat(" according to the rule %s",
- npy_casting_to_string(casting)));
- PyErr_SetObject(PyExc_TypeError, errmsg);
- Py_DECREF(errmsg);
+ npy_set_invalid_cast_error(
+ src_dtype, PyArray_DESCR(dst), casting, NPY_TRUE);
return -1;
}
diff --git a/numpy/core/src/multiarray/convert_datatype.c b/numpy/core/src/multiarray/convert_datatype.c
index d59a62ed8..0390c92fc 100644
--- a/numpy/core/src/multiarray/convert_datatype.c
+++ b/numpy/core/src/multiarray/convert_datatype.c
@@ -985,6 +985,54 @@ PyArray_CanCastArrayTo(PyArrayObject *arr, PyArray_Descr *to,
return PyArray_CanCastTypeTo(from, to, casting);
}
+
+NPY_NO_EXPORT const char *
+npy_casting_to_string(NPY_CASTING casting)
+{
+ switch (casting) {
+ case NPY_NO_CASTING:
+ return "'no'";
+ case NPY_EQUIV_CASTING:
+ return "'equiv'";
+ case NPY_SAFE_CASTING:
+ return "'safe'";
+ case NPY_SAME_KIND_CASTING:
+ return "'same_kind'";
+ case NPY_UNSAFE_CASTING:
+ return "'unsafe'";
+ default:
+ return "<unknown>";
+ }
+}
+
+
+/**
+ * Helper function to set a useful error when casting is not possible.
+ *
+ * @param src_dtype
+ * @param dst_dtype
+ * @param casting
+ * @param scalar Whether this was a "scalar" cast (includes 0-D array with
+ * PyArray_CanCastArrayTo result).
+ */
+NPY_NO_EXPORT void
+npy_set_invalid_cast_error(
+ PyArray_Descr *src_dtype, PyArray_Descr *dst_dtype,
+ NPY_CASTING casting, npy_bool scalar)
+{
+ char *msg;
+
+ if (!scalar) {
+ msg = "Cannot cast array data from %R to %R according to the rule %s";
+ }
+ else {
+ msg = "Cannot cast scalar from %R to %R according to the rule %s";
+ }
+ PyErr_Format(PyExc_TypeError,
+ msg, src_dtype, dst_dtype, npy_casting_to_string(casting));
+}
+
+
/*NUMPY_API
* See if array scalars can be cast.
*
diff --git a/numpy/core/src/multiarray/convert_datatype.h b/numpy/core/src/multiarray/convert_datatype.h
index 72867ead8..4a7d85187 100644
--- a/numpy/core/src/multiarray/convert_datatype.h
+++ b/numpy/core/src/multiarray/convert_datatype.h
@@ -22,6 +22,14 @@ NPY_NO_EXPORT int
should_use_min_scalar(npy_intp narrs, PyArrayObject **arr,
npy_intp ndtypes, PyArray_Descr **dtypes);
+NPY_NO_EXPORT const char *
+npy_casting_to_string(NPY_CASTING casting);
+
+NPY_NO_EXPORT void
+npy_set_invalid_cast_error(
+ PyArray_Descr *src_dtype, PyArray_Descr *dst_dtype,
+ NPY_CASTING casting, npy_bool scalar);
+
/*
* This function calls Py_DECREF on flex_dtype, and replaces it with
* a new dtype that has been adapted based on the values in data_dtype
diff --git a/numpy/core/src/multiarray/ctors.c b/numpy/core/src/multiarray/ctors.c
index 12bf9eace..df92544fd 100644
--- a/numpy/core/src/multiarray/ctors.c
+++ b/numpy/core/src/multiarray/ctors.c
@@ -21,7 +21,6 @@
#include "shape.h"
#include "npy_buffer.h"
#include "lowlevel_strided_loops.h"
-#include "methods.h"
#include "_datetime.h"
#include "datetime_strings.h"
#include "array_assign.h"
@@ -2181,42 +2180,9 @@ PyArray_FromArray(PyArrayObject *arr, PyArray_Descr *newtype, int flags)
/* Raise an error if the casting rule isn't followed */
if (!PyArray_CanCastArrayTo(arr, newtype, casting)) {
- PyObject *errmsg;
- PyArray_Descr *arr_descr = NULL;
- PyObject *arr_descr_repr = NULL;
- PyObject *newtype_repr = NULL;
-
PyErr_Clear();
- errmsg = PyUString_FromString("Cannot cast array data from ");
- arr_descr = PyArray_DESCR(arr);
- if (arr_descr == NULL) {
- Py_DECREF(newtype);
- Py_DECREF(errmsg);
- return NULL;
- }
- arr_descr_repr = PyObject_Repr((PyObject *)arr_descr);
- if (arr_descr_repr == NULL) {
- Py_DECREF(newtype);
- Py_DECREF(errmsg);
- return NULL;
- }
- PyUString_ConcatAndDel(&errmsg, arr_descr_repr);
- PyUString_ConcatAndDel(&errmsg,
- PyUString_FromString(" to "));
- newtype_repr = PyObject_Repr((PyObject *)newtype);
- if (newtype_repr == NULL) {
- Py_DECREF(newtype);
- Py_DECREF(errmsg);
- return NULL;
- }
- PyUString_ConcatAndDel(&errmsg, newtype_repr);
- PyUString_ConcatAndDel(&errmsg,
- PyUString_FromFormat(" according to the rule %s",
- npy_casting_to_string(casting)));
- PyErr_SetObject(PyExc_TypeError, errmsg);
- Py_DECREF(errmsg);
-
- Py_DECREF(newtype);
+ npy_set_invalid_cast_error(
+ PyArray_DESCR(arr), newtype, casting, PyArray_NDIM(arr) == 0);
return NULL;
}
diff --git a/numpy/core/src/multiarray/datetime.c b/numpy/core/src/multiarray/datetime.c
index 67ed3ca85..cfe801898 100644
--- a/numpy/core/src/multiarray/datetime.c
+++ b/numpy/core/src/multiarray/datetime.c
@@ -22,9 +22,9 @@
#include "common.h"
#include "numpy/arrayscalars.h"
-#include "methods.h"
#include "_datetime.h"
#include "datetime_strings.h"
+#include "convert_datatype.h"
/*
* Computes the python `ret, d = divmod(d, unit)`.
diff --git a/numpy/core/src/multiarray/datetime_strings.c b/numpy/core/src/multiarray/datetime_strings.c
index 4574c05d8..f847c7ea8 100644
--- a/numpy/core/src/multiarray/datetime_strings.c
+++ b/numpy/core/src/multiarray/datetime_strings.c
@@ -20,7 +20,7 @@
#include "npy_pycompat.h"
#include "numpy/arrayscalars.h"
-#include "methods.h"
+#include "convert_datatype.h"
#include "_datetime.h"
#include "datetime_strings.h"
diff --git a/numpy/core/src/multiarray/methods.c b/numpy/core/src/multiarray/methods.c
index 29ae49c18..e2026ec1c 100644
--- a/numpy/core/src/multiarray/methods.c
+++ b/numpy/core/src/multiarray/methods.c
@@ -789,24 +789,6 @@ array_setscalar(PyArrayObject *self, PyObject *args)
}
}
-NPY_NO_EXPORT const char *
-npy_casting_to_string(NPY_CASTING casting)
-{
- switch (casting) {
- case NPY_NO_CASTING:
- return "'no'";
- case NPY_EQUIV_CASTING:
- return "'equiv'";
- case NPY_SAFE_CASTING:
- return "'safe'";
- case NPY_SAME_KIND_CASTING:
- return "'same_kind'";
- case NPY_UNSAFE_CASTING:
- return "'unsafe'";
- default:
- return "<unknown>";
- }
-}
static PyObject *
array_astype(PyArrayObject *self, PyObject *args, PyObject *kwds)
@@ -876,19 +858,8 @@ array_astype(PyArrayObject *self, PyObject *args, PyObject *kwds)
return (PyObject *)ret;
}
else {
- PyObject *errmsg;
- errmsg = PyUString_FromString("Cannot cast array from ");
- PyUString_ConcatAndDel(&errmsg,
- PyObject_Repr((PyObject *)PyArray_DESCR(self)));
- PyUString_ConcatAndDel(&errmsg,
- PyUString_FromString(" to "));
- PyUString_ConcatAndDel(&errmsg,
- PyObject_Repr((PyObject *)dtype));
- PyUString_ConcatAndDel(&errmsg,
- PyUString_FromFormat(" according to the rule %s",
- npy_casting_to_string(casting)));
- PyErr_SetObject(PyExc_TypeError, errmsg);
- Py_DECREF(errmsg);
+ npy_set_invalid_cast_error(
+ PyArray_DESCR(self), dtype, casting, PyArray_NDIM(self) == 0);
Py_DECREF(dtype);
return NULL;
}
diff --git a/numpy/core/src/multiarray/methods.h b/numpy/core/src/multiarray/methods.h
index 7a9a24a00..c0de23c35 100644
--- a/numpy/core/src/multiarray/methods.h
+++ b/numpy/core/src/multiarray/methods.h
@@ -5,8 +5,6 @@
extern NPY_NO_EXPORT PyMethodDef array_methods[];
-NPY_NO_EXPORT const char *
-npy_casting_to_string(NPY_CASTING casting);
/*
* Pathlib support, takes a borrowed reference and returns a new one.
diff --git a/numpy/core/src/multiarray/nditer_constr.c b/numpy/core/src/multiarray/nditer_constr.c
index e40a2d594..620c7d593 100644
--- a/numpy/core/src/multiarray/nditer_constr.c
+++ b/numpy/core/src/multiarray/nditer_constr.c
@@ -1308,21 +1308,11 @@ npyiter_check_casting(int nop, PyArrayObject **op,
!PyArray_CanCastArrayTo(op[iop],
op_dtype[iop],
casting)) {
- PyObject *errmsg;
- errmsg = PyUString_FromFormat(
- "Iterator operand %d dtype could not be cast from ",
- iop);
- PyUString_ConcatAndDel(&errmsg,
- PyObject_Repr((PyObject *)PyArray_DESCR(op[iop])));
- PyUString_ConcatAndDel(&errmsg,
- PyUString_FromString(" to "));
- PyUString_ConcatAndDel(&errmsg,
- PyObject_Repr((PyObject *)op_dtype[iop]));
- PyUString_ConcatAndDel(&errmsg,
- PyUString_FromFormat(" according to the rule %s",
- npyiter_casting_to_string(casting)));
- PyErr_SetObject(PyExc_TypeError, errmsg);
- Py_DECREF(errmsg);
+ PyErr_Format(PyExc_TypeError,
+ "Iterator operand %d dtype could not be cast from "
+ "%R to %R according to the rule %s",
+ iop, PyArray_DESCR(op[iop]), op_dtype[iop],
+ npyiter_casting_to_string(casting));
return 0;
}
/* Check write (temp -> op) casting */
@@ -1330,22 +1320,12 @@ npyiter_check_casting(int nop, PyArrayObject **op,
!PyArray_CanCastTypeTo(op_dtype[iop],
PyArray_DESCR(op[iop]),
casting)) {
- PyObject *errmsg;
- errmsg = PyUString_FromString(
- "Iterator requested dtype could not be cast from ");
- PyUString_ConcatAndDel(&errmsg,
- PyObject_Repr((PyObject *)op_dtype[iop]));
- PyUString_ConcatAndDel(&errmsg,
- PyUString_FromString(" to "));
- PyUString_ConcatAndDel(&errmsg,
- PyObject_Repr((PyObject *)PyArray_DESCR(op[iop])));
- PyUString_ConcatAndDel(&errmsg,
- PyUString_FromFormat(", the operand %d dtype, "
- "according to the rule %s",
- iop,
- npyiter_casting_to_string(casting)));
- PyErr_SetObject(PyExc_TypeError, errmsg);
- Py_DECREF(errmsg);
+ PyErr_Format(PyExc_TypeError,
+ "Iterator requested dtype could not be cast from "
+ "%R to %R, the operand %d dtype, "
+ "according to the rule %s",
+ op_dtype[iop], PyArray_DESCR(op[iop]), iop,
+ npyiter_casting_to_string(casting));
return 0;
}
diff --git a/numpy/core/src/umath/ufunc_type_resolution.c b/numpy/core/src/umath/ufunc_type_resolution.c
index 2534ff78a..ea20bb24f 100644
--- a/numpy/core/src/umath/ufunc_type_resolution.c
+++ b/numpy/core/src/umath/ufunc_type_resolution.c
@@ -51,25 +51,6 @@ npy_casting_to_py_object(NPY_CASTING casting)
}
-static const char *
-npy_casting_to_string(NPY_CASTING casting)
-{
- switch (casting) {
- case NPY_NO_CASTING:
- return "'no'";
- case NPY_EQUIV_CASTING:
- return "'equiv'";
- case NPY_SAFE_CASTING:
- return "'safe'";
- case NPY_SAME_KIND_CASTING:
- return "'same_kind'";
- case NPY_UNSAFE_CASTING:
- return "'unsafe'";
- default:
- return "<unknown>";
- }
-}
-
/**
* Always returns -1 to indicate the exception was raised, for convenience
*/
diff --git a/numpy/core/tests/test_api.py b/numpy/core/tests/test_api.py
index b3f7cc88a..2600d409a 100644
--- a/numpy/core/tests/test_api.py
+++ b/numpy/core/tests/test_api.py
@@ -1,6 +1,7 @@
import sys
import numpy as np
+from numpy.core._rational_tests import rational
import pytest
from numpy.testing import (
assert_, assert_equal, assert_array_equal, assert_raises, assert_warns,
@@ -141,6 +142,16 @@ def test_array_array():
assert_equal(np.array([(1.0,) * 10] * 10, dtype=np.float64),
np.ones((10, 10), dtype=np.float64))
+@pytest.mark.parametrize("array", [True, False])
+def test_array_impossible_casts(array):
+ # All builtin types can forst cast as least theoretically
+ # but user dtypes cannot necessarily.
+ rt = rational(1, 2)
+ if array:
+ rt = np.array(rt)
+ with assert_raises(ValueError):
+ np.array(rt, dtype="M8")
+
def test_fastCopyAndTranspose():
# 0D array
diff --git a/numpy/doc/structured_arrays.py b/numpy/doc/structured_arrays.py
index 72990cf89..359d4f7f4 100644
--- a/numpy/doc/structured_arrays.py
+++ b/numpy/doc/structured_arrays.py
@@ -341,7 +341,7 @@ structured datatype has just a single field::
>>> nostruct[:] = twofield
Traceback (most recent call last):
...
- TypeError: Cannot cast scalar from dtype([('A', '<i4'), ('B', '<i4')]) to dtype('int32') according to the rule 'unsafe'
+ TypeError: Cannot cast array data from dtype([('A', '<i4'), ('B', '<i4')]) to dtype('int32') according to the rule 'unsafe'
Assignment from other Structured Arrays
```````````````````````````````````````