summaryrefslogtreecommitdiff
path: root/numpy/core
diff options
context:
space:
mode:
Diffstat (limited to 'numpy/core')
-rw-r--r--numpy/core/code_generators/numpy_api.py2
-rw-r--r--numpy/core/include/numpy/ndarraytypes.h9
-rw-r--r--numpy/core/src/multiarray/common.c14
-rw-r--r--numpy/core/src/multiarray/convert_datatype.c29
-rw-r--r--numpy/core/tests/test_ufunc.py18
5 files changed, 68 insertions, 4 deletions
diff --git a/numpy/core/code_generators/numpy_api.py b/numpy/core/code_generators/numpy_api.py
index c49c3c346..cb598880b 100644
--- a/numpy/core/code_generators/numpy_api.py
+++ b/numpy/core/code_generators/numpy_api.py
@@ -14,10 +14,12 @@ exception, so it should hopefully not get unnoticed).
multiarray_global_vars = {
'NPY_NUMUSERTYPES': 7,
+ 'NPY_DEFAULT_ASSIGN_CASTING': 292,
}
multiarray_global_vars_types = {
'NPY_NUMUSERTYPES': 'int',
+ 'NPY_DEFAULT_ASSIGN_CASTING': 'NPY_CASTING',
}
multiarray_scalar_bool_values = {
diff --git a/numpy/core/include/numpy/ndarraytypes.h b/numpy/core/include/numpy/ndarraytypes.h
index 954303352..523601570 100644
--- a/numpy/core/include/numpy/ndarraytypes.h
+++ b/numpy/core/include/numpy/ndarraytypes.h
@@ -199,11 +199,12 @@ typedef enum {
/* Allow safe casts or casts within the same kind */
NPY_SAME_KIND_CASTING=3,
/* Allow any casts */
- NPY_UNSAFE_CASTING=4
-} NPY_CASTING;
+ NPY_UNSAFE_CASTING=4,
-/* The default casting to use for typical assignment operations */
-#define NPY_DEFAULT_ASSIGN_CASTING NPY_SAME_KIND_CASTING
+ /* Temporary internal definition only, will be removed in upcoming
+ release, see below */
+ NPY_INTERNAL_UNSAFE_CASTING_BUT_WARN_UNLESS_SAME_KIND = 100,
+} NPY_CASTING;
typedef enum {
NPY_CLIP=0,
diff --git a/numpy/core/src/multiarray/common.c b/numpy/core/src/multiarray/common.c
index 5ab8f92bc..917946b48 100644
--- a/numpy/core/src/multiarray/common.c
+++ b/numpy/core/src/multiarray/common.c
@@ -13,6 +13,20 @@
#include "common.h"
#include "buffer.h"
+/* The casting to use for implicit assignment operations resulting from
+ * in-place operations (like +=) and out= arguments. (Notice that this
+ * variable is misnamed, but it's part of the public API so I'm not sure we
+ * can just change it. Maybe someone should try and see if anyone notices.
+ */
+/* In numpy 1.6 and earlier, this was NPY_UNSAFE_CASTING. In a future
+ * release, it will become NPY_SAME_KIND_CASTING. Right now, during the
+ * transitional period, we continue to follow the NPY_UNSAFE_CASTING rules (to
+ * avoid breaking people's code), but we also check for whether the cast would
+ * be allowed under the NPY_SAME_KIND_CASTING rules, and if not we issue a
+ * warning (that people's code will be broken in a future release.)
+ */
+NPY_NO_EXPORT NPY_CASTING NPY_DEFAULT_ASSIGN_CASTING = NPY_INTERNAL_UNSAFE_CASTING_BUT_WARN_UNLESS_SAME_KIND;
+
NPY_NO_EXPORT PyArray_Descr *
_array_find_python_scalar_type(PyObject *op)
diff --git a/numpy/core/src/multiarray/convert_datatype.c b/numpy/core/src/multiarray/convert_datatype.c
index de7468c51..b4f20c000 100644
--- a/numpy/core/src/multiarray/convert_datatype.c
+++ b/numpy/core/src/multiarray/convert_datatype.c
@@ -503,12 +503,41 @@ type_num_unsigned_to_signed(int type_num)
}
}
+/* NOTE: once the UNSAFE_CASTING -> SAME_KIND_CASTING transition is over,
+ * we should remove NPY_INTERNAL_UNSAFE_CASTING_BUT_WARN_UNLESS_SAME_KIND
+ * and PyArray_CanCastTypeTo_impl should be renamed back to
+ * PyArray_CanCastTypeTo.
+ */
+static npy_bool
+PyArray_CanCastTypeTo_impl(PyArray_Descr *from, PyArray_Descr *to,
+ NPY_CASTING casting);
+
/*NUMPY_API
* Returns true if data of type 'from' may be cast to data of type
* 'to' according to the rule 'casting'.
*/
NPY_NO_EXPORT npy_bool
PyArray_CanCastTypeTo(PyArray_Descr *from, PyArray_Descr *to,
+ NPY_CASTING casting)
+{
+ if (casting == NPY_INTERNAL_UNSAFE_CASTING_BUT_WARN_UNLESS_SAME_KIND) {
+ npy_bool unsafe_ok, same_kind_ok;
+ unsafe_ok = PyArray_CanCastTypeTo_impl(from, to, NPY_UNSAFE_CASTING);
+ same_kind_ok = PyArray_CanCastTypeTo_impl(from, to,
+ NPY_SAME_KIND_CASTING);
+ if (unsafe_ok && !same_kind_ok) {
+ DEPRECATE("Implicitly casting between incompatible kinds. In "
+ "a future numpy release, this will become an error. "
+ "Use casting=\"unsafe\" if this is intentional.");
+ }
+ return unsafe_ok;
+ } else {
+ return PyArray_CanCastTypeTo_impl(from, to, casting);
+ }
+}
+
+static npy_bool
+PyArray_CanCastTypeTo_impl(PyArray_Descr *from, PyArray_Descr *to,
NPY_CASTING casting)
{
/* If unsafe casts are allowed */
diff --git a/numpy/core/tests/test_ufunc.py b/numpy/core/tests/test_ufunc.py
index 53928129f..fb6b586be 100644
--- a/numpy/core/tests/test_ufunc.py
+++ b/numpy/core/tests/test_ufunc.py
@@ -742,5 +742,23 @@ class TestUfunc(TestCase):
uf.accumulate(np.zeros((30, 30)), axis=0)
uf.accumulate(np.zeros((0, 0)), axis=0)
+ def test_safe_casting(self):
+ # In old numpy's, any casting was allowed for in-place operations. In
+ # future numpy's, only same_kind casting will be allowed by
+ # default.
+ a = np.array([1, 2, 3], dtype=int)
+ # Non-in-place addition is fine
+ assert_array_equal(assert_no_warnings(np.add, a, 1.1),
+ [2.1, 3.1, 4.1])
+ assert_warns(DeprecationWarning, np.add, a, 1.1, out=a)
+ assert_array_equal(a, [2, 3, 4])
+ def add_inplace(a, b):
+ a += b
+ assert_warns(DeprecationWarning, add_inplace, a, 1.1)
+ assert_array_equal(a, [3, 4, 5])
+ # Make sure that explicitly overriding the warning is allowed:
+ assert_no_warnings(np.add, a, 1.1, out=a, casting="unsafe")
+ assert_array_equal(a, [4, 5, 6])
+
if __name__ == "__main__":
run_module_suite()