diff options
Diffstat (limited to 'numpy/core')
-rw-r--r-- | numpy/core/code_generators/numpy_api.py | 2 | ||||
-rw-r--r-- | numpy/core/include/numpy/ndarraytypes.h | 9 | ||||
-rw-r--r-- | numpy/core/src/multiarray/common.c | 14 | ||||
-rw-r--r-- | numpy/core/src/multiarray/convert_datatype.c | 29 | ||||
-rw-r--r-- | numpy/core/tests/test_ufunc.py | 18 |
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() |