diff options
author | seberg <sebastian@sipsolutions.net> | 2016-11-01 10:39:01 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2016-11-01 10:39:01 +0100 |
commit | 19fc7ad7f758a57d23c07830a3a8d054e7a11089 (patch) | |
tree | 1d24d307936f03e558a4a661d7dd1560a07437cf | |
parent | 6ae842001332f532e0c76815d49336ecc2b88dde (diff) | |
parent | f685f1a83de2d8fc1e0f48167a204248b6656a63 (diff) | |
download | numpy-19fc7ad7f758a57d23c07830a3a8d054e7a11089.tar.gz |
Merge pull request #8083 from njase/enh_7949
ENH: Deprecation warnings for `/` integer division when running python -3.
-rw-r--r-- | .travis.yml | 2 | ||||
-rw-r--r-- | doc/release/1.12.0-notes.rst | 14 | ||||
-rw-r--r-- | numpy/core/code_generators/generate_umath.py | 2 | ||||
-rw-r--r-- | numpy/core/src/umath/ufunc_type_resolution.c | 36 | ||||
-rw-r--r-- | numpy/core/src/umath/ufunc_type_resolution.h | 122 | ||||
-rw-r--r-- | numpy/core/tests/test_deprecations.py | 21 | ||||
-rw-r--r-- | numpy/core/tests/test_multiarray.py | 4 | ||||
-rw-r--r-- | numpy/core/tests/test_regression.py | 4 | ||||
-rw-r--r-- | numpy/core/tests/test_scalarmath.py | 2 | ||||
-rw-r--r-- | numpy/ma/tests/test_subclassing.py | 2 | ||||
-rw-r--r-- | numpy/testing/nosetester.py | 15 | ||||
-rwxr-xr-x | tools/travis-test.sh | 5 |
12 files changed, 166 insertions, 63 deletions
diff --git a/.travis.yml b/.travis.yml index 5f5bf9757..ba226fcb2 100644 --- a/.travis.yml +++ b/.travis.yml @@ -38,6 +38,8 @@ python: matrix: include: - python: 2.7 + env: PY3_COMPATIBILITY_CHECK=1 + - python: 2.7 env: USE_CHROOT=1 ARCH=i386 DIST=trusty PYTHON=2.7 sudo: true dist: trusty diff --git a/doc/release/1.12.0-notes.rst b/doc/release/1.12.0-notes.rst index 0baa33049..4029abc48 100644 --- a/doc/release/1.12.0-notes.rst +++ b/doc/release/1.12.0-notes.rst @@ -351,6 +351,20 @@ distance metric that combines two vectors to produce a scalar could be vectorized with ``signature='(n),(n)->()'``. See ``np.vectorize`` for full details. +Emit py3kwarnings for division of integer arrays +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +To help people migrate their code bases from Python 2 to Python 3, the +python interpreter has a handy option -3, which issues warnings at runtime. +One of its warnings is for integer division: + $ python -3 -c "2/3" + + -c:1: DeprecationWarning: classic int division +In Python 3, the new integer division semantics also apply to numpy arrays. +With this version, numpy will emit a similar warning: + $ python -3 -c "import numpy as np; np.array(2)/np.array(3)" + + -c:1: DeprecationWarning: numpy: classic int division + Changes ======= diff --git a/numpy/core/code_generators/generate_umath.py b/numpy/core/code_generators/generate_umath.py index 21dab54c5..8357fc8da 100644 --- a/numpy/core/code_generators/generate_umath.py +++ b/numpy/core/code_generators/generate_umath.py @@ -292,7 +292,7 @@ defdict = { 'divide': Ufunc(2, 1, None, # One is only a unit to the right, not the left docstrings.get('numpy.core.umath.divide'), - 'PyUFunc_DivisionTypeResolver', + 'PyUFunc_MixedDivisionTypeResolver', TD(intfltcmplx), [TypeDescription('m', FullTypeDescr, 'mq', 'm'), TypeDescription('m', FullTypeDescr, 'md', 'm'), diff --git a/numpy/core/src/umath/ufunc_type_resolution.c b/numpy/core/src/umath/ufunc_type_resolution.c index ce9eec4b6..50e020386 100644 --- a/numpy/core/src/umath/ufunc_type_resolution.c +++ b/numpy/core/src/umath/ufunc_type_resolution.c @@ -1090,6 +1090,7 @@ type_reso_error: { } } + /* * This function applies the type resolution rules for division. * In particular, there are a number of special cases with datetime: @@ -1210,6 +1211,41 @@ type_reso_error: { } } +/* + * Function to check and report floor division warning when python2.x is + * invoked with -3 switch + * See PEP238 and #7949 for numpy + * This function will not be hit for py3 or when __future__ imports division. + * See generate_umath.py for reason +*/ +NPY_NO_EXPORT int +PyUFunc_MixedDivisionTypeResolver(PyUFuncObject *ufunc, + NPY_CASTING casting, + PyArrayObject **operands, + PyObject *type_tup, + PyArray_Descr **out_dtypes) +{ + /* Depreciation checks needed only on python 2 */ +#if !defined(NPY_PY3K) + int type_num1, type_num2; + + type_num1 = PyArray_DESCR(operands[0])->type_num; + type_num2 = PyArray_DESCR(operands[1])->type_num; + + /* If both types are integer, warn the user, same as python does */ + if (Py_DivisionWarningFlag && + (PyTypeNum_ISINTEGER(type_num1) || PyTypeNum_ISBOOL(type_num1)) && + (PyTypeNum_ISINTEGER(type_num2) || PyTypeNum_ISBOOL(type_num2))) + { + PyErr_Warn(PyExc_DeprecationWarning, "numpy: classic int division"); + } +#endif + + return PyUFunc_DivisionTypeResolver(ufunc, casting, operands, + type_tup, out_dtypes); +} + + static int find_userloop(PyUFuncObject *ufunc, PyArray_Descr **dtypes, diff --git a/numpy/core/src/umath/ufunc_type_resolution.h b/numpy/core/src/umath/ufunc_type_resolution.h index a1e28d75b..d20c1e85b 100644 --- a/numpy/core/src/umath/ufunc_type_resolution.h +++ b/numpy/core/src/umath/ufunc_type_resolution.h @@ -3,52 +3,52 @@ NPY_NO_EXPORT int PyUFunc_SimpleBinaryComparisonTypeResolver(PyUFuncObject *ufunc, - NPY_CASTING casting, - PyArrayObject **operands, - PyObject *type_tup, - PyArray_Descr **out_dtypes); + NPY_CASTING casting, + PyArrayObject **operands, + PyObject *type_tup, + PyArray_Descr **out_dtypes); NPY_NO_EXPORT int PyUFunc_SimpleUnaryOperationTypeResolver(PyUFuncObject *ufunc, - NPY_CASTING casting, - PyArrayObject **operands, - PyObject *type_tup, - PyArray_Descr **out_dtypes); + NPY_CASTING casting, + PyArrayObject **operands, + PyObject *type_tup, + PyArray_Descr **out_dtypes); NPY_NO_EXPORT int PyUFunc_NegativeTypeResolver(PyUFuncObject *ufunc, - NPY_CASTING casting, - PyArrayObject **operands, - PyObject *type_tup, - PyArray_Descr **out_dtypes); + NPY_CASTING casting, + PyArrayObject **operands, + PyObject *type_tup, + PyArray_Descr **out_dtypes); NPY_NO_EXPORT int PyUFunc_OnesLikeTypeResolver(PyUFuncObject *ufunc, - NPY_CASTING casting, - PyArrayObject **operands, - PyObject *type_tup, - PyArray_Descr **out_dtypes); + NPY_CASTING casting, + PyArrayObject **operands, + PyObject *type_tup, + PyArray_Descr **out_dtypes); NPY_NO_EXPORT int PyUFunc_SimpleBinaryOperationTypeResolver(PyUFuncObject *ufunc, - NPY_CASTING casting, - PyArrayObject **operands, - PyObject *type_tup, - PyArray_Descr **out_dtypes); + NPY_CASTING casting, + PyArrayObject **operands, + PyObject *type_tup, + PyArray_Descr **out_dtypes); NPY_NO_EXPORT int PyUFunc_AbsoluteTypeResolver(PyUFuncObject *ufunc, - NPY_CASTING casting, - PyArrayObject **operands, - PyObject *type_tup, - PyArray_Descr **out_dtypes); + NPY_CASTING casting, + PyArrayObject **operands, + PyObject *type_tup, + PyArray_Descr **out_dtypes); NPY_NO_EXPORT int PyUFunc_AdditionTypeResolver(PyUFuncObject *ufunc, - NPY_CASTING casting, - PyArrayObject **operands, - PyObject *type_tup, - PyArray_Descr **out_dtypes); + NPY_CASTING casting, + PyArrayObject **operands, + PyObject *type_tup, + PyArray_Descr **out_dtypes); NPY_NO_EXPORT int PyUFunc_SubtractionTypeResolver(PyUFuncObject *ufunc, @@ -59,17 +59,24 @@ PyUFunc_SubtractionTypeResolver(PyUFuncObject *ufunc, NPY_NO_EXPORT int PyUFunc_MultiplicationTypeResolver(PyUFuncObject *ufunc, - NPY_CASTING casting, - PyArrayObject **operands, - PyObject *type_tup, - PyArray_Descr **out_dtypes); + NPY_CASTING casting, + PyArrayObject **operands, + PyObject *type_tup, + PyArray_Descr **out_dtypes); + +NPY_NO_EXPORT int +PyUFunc_MixedDivisionTypeResolver(PyUFuncObject *ufunc, + NPY_CASTING casting, + PyArrayObject **operands, + PyObject *type_tup, + PyArray_Descr **out_dtypes); NPY_NO_EXPORT int PyUFunc_DivisionTypeResolver(PyUFuncObject *ufunc, - NPY_CASTING casting, - PyArrayObject **operands, - PyObject *type_tup, - PyArray_Descr **out_dtypes); + NPY_CASTING casting, + PyArrayObject **operands, + PyObject *type_tup, + PyArray_Descr **out_dtypes); /* * Does a linear search for the best inner loop of the ufunc. @@ -79,11 +86,11 @@ PyUFunc_DivisionTypeResolver(PyUFuncObject *ufunc, */ NPY_NO_EXPORT int linear_search_type_resolver(PyUFuncObject *self, - PyArrayObject **op, - NPY_CASTING input_casting, - NPY_CASTING output_casting, - int any_object, - PyArray_Descr **out_dtype); + PyArrayObject **op, + NPY_CASTING input_casting, + NPY_CASTING output_casting, + int any_object, + PyArray_Descr **out_dtype); /* * Does a linear search for the inner loop of the ufunc specified by type_tup. @@ -93,28 +100,29 @@ linear_search_type_resolver(PyUFuncObject *self, */ NPY_NO_EXPORT int type_tuple_type_resolver(PyUFuncObject *self, - PyObject *type_tup, - PyArrayObject **op, - NPY_CASTING casting, - int any_object, - PyArray_Descr **out_dtype); + PyObject *type_tup, + PyArrayObject **op, + NPY_CASTING casting, + int any_object, + PyArray_Descr **out_dtype); NPY_NO_EXPORT int PyUFunc_DefaultLegacyInnerLoopSelector(PyUFuncObject *ufunc, - PyArray_Descr **dtypes, - PyUFuncGenericFunction *out_innerloop, - void **out_innerloopdata, - int *out_needs_api); + PyArray_Descr **dtypes, + PyUFuncGenericFunction *out_innerloop, + void **out_innerloopdata, + int *out_needs_api); NPY_NO_EXPORT int PyUFunc_DefaultMaskedInnerLoopSelector(PyUFuncObject *ufunc, - PyArray_Descr **dtypes, - PyArray_Descr *mask_dtypes, - npy_intp *NPY_UNUSED(fixed_strides), - npy_intp NPY_UNUSED(fixed_mask_stride), - PyUFunc_MaskedStridedInnerLoopFunc **out_innerloop, - NpyAuxData **out_innerloopdata, - int *out_needs_api); + PyArray_Descr **dtypes, + PyArray_Descr *mask_dtypes, + npy_intp *NPY_UNUSED(fixed_strides), + npy_intp NPY_UNUSED(fixed_mask_stride), + PyUFunc_MaskedStridedInnerLoopFunc + **out_innerloop, + NpyAuxData **out_innerloopdata, + int *out_needs_api); #endif diff --git a/numpy/core/tests/test_deprecations.py b/numpy/core/tests/test_deprecations.py index fa68ee69e..8d3006ac9 100644 --- a/numpy/core/tests/test_deprecations.py +++ b/numpy/core/tests/test_deprecations.py @@ -655,6 +655,27 @@ class TestTestDeprecated(object): test_case_instance.assert_deprecated(foo) test_case_instance.tearDown() +class TestClassicIntDivision(_DeprecationTestCase): + """ + See #7949. Deprecate the numeric-style dtypes with -3 flag in python 2 + if used for division + List of data types: http://docs.scipy.org/doc/numpy/user/basics.types.html + """ + def test_int_dtypes(self): + #scramble types and do some mix and match testing + deprecated_types = [ + 'bool_', 'int_', 'intc', 'uint8', 'int8', 'uint64', 'int32', 'uint16', + 'intp', 'int64', 'uint32', 'int16' + ] + if sys.version_info[0] < 3 and sys.py3kwarning: + import operator as op + dt2 = 'bool_' + for dt1 in deprecated_types: + a = np.array([1,2,3], dtype=dt1) + b = np.array([1,2,3], dtype=dt2) + self.assert_deprecated(op.div, args=(a,b)) + dt2 = dt1 + if __name__ == "__main__": run_module_suite() diff --git a/numpy/core/tests/test_multiarray.py b/numpy/core/tests/test_multiarray.py index 7e3ffe28a..a6e039d50 100644 --- a/numpy/core/tests/test_multiarray.py +++ b/numpy/core/tests/test_multiarray.py @@ -6484,7 +6484,9 @@ class TestArrayPriority(TestCase): op.ge, op.lt, op.le, op.ne, op.eq ] - if sys.version_info[0] < 3: + # See #7949. Dont use "/" operator With -3 switch, since python reports it + # as a DeprecationWarning + if sys.version_info[0] < 3 and not sys.py3kwarning: binary_ops.append(op.div) class Foo(np.ndarray): diff --git a/numpy/core/tests/test_regression.py b/numpy/core/tests/test_regression.py index 040d35ce1..721a025de 100644 --- a/numpy/core/tests/test_regression.py +++ b/numpy/core/tests/test_regression.py @@ -2118,7 +2118,9 @@ class TestRegression(TestCase): for f in [op.lt, op.le, op.gt, op.ge]: if sys.version_info[0] >= 3: assert_raises(TypeError, f, lhs, rhs) - else: + elif not sys.py3kwarning: + # With -3 switch in python 2, DeprecationWarning is raised + # which we are not interested in f(lhs, rhs) assert_(not op.eq(lhs, rhs)) assert_(op.ne(lhs, rhs)) diff --git a/numpy/core/tests/test_scalarmath.py b/numpy/core/tests/test_scalarmath.py index 87b050bb9..592b1dbd5 100644 --- a/numpy/core/tests/test_scalarmath.py +++ b/numpy/core/tests/test_scalarmath.py @@ -83,7 +83,7 @@ class TestBaseMath(TestCase): assert_almost_equal(np.square(inp2), np.multiply(inp2, inp2), err_msg=msg) # skip true divide for ints - if dt != np.int32 or sys.version_info.major < 3: + if dt != np.int32 or (sys.version_info.major < 3 and not sys.py3kwarning): assert_almost_equal(np.reciprocal(inp2), np.divide(1, inp2), err_msg=msg) diff --git a/numpy/ma/tests/test_subclassing.py b/numpy/ma/tests/test_subclassing.py index 814ed5977..8198c9d35 100644 --- a/numpy/ma/tests/test_subclassing.py +++ b/numpy/ma/tests/test_subclassing.py @@ -176,7 +176,7 @@ class TestSubclassing(TestCase): # Test suite for masked subclasses of ndarray. def setUp(self): - x = np.arange(5) + x = np.arange(5, dtype='float') mx = mmatrix(x, mask=[0, 1, 0, 0, 0]) self.data = (x, mx) diff --git a/numpy/testing/nosetester.py b/numpy/testing/nosetester.py index c30c0eecd..c07d65642 100644 --- a/numpy/testing/nosetester.py +++ b/numpy/testing/nosetester.py @@ -411,7 +411,20 @@ class NoseTester(object): warnings.simplefilter("always") from ..distutils import cpuinfo sup.filter(category=UserWarning, module=cpuinfo) - + # See #7949: Filter out deprecation warnings due to the -3 flag to + # python 2 + if sys.version_info.major == 2 and sys.py3kwarning: + # This is very specific, so using the fragile module filter + # is fine + import threading + sup.filter(DeprecationWarning, + r"sys\.exc_clear\(\) not supported in 3\.x", + module=threading) + sup.filter(DeprecationWarning, message="in 3\.x, __setslice__") + sup.filter(DeprecationWarning, message="in 3\.x, __getslice__") + sup.filter(DeprecationWarning, message="buffer\(\) not supported in 3\.x") + sup.filter(DeprecationWarning, message="CObject type is not supported in 3\.x") + sup.filter(DeprecationWarning, message="comparing unequal types not supported in 3\.x") # Filter out some deprecation warnings inside nose 1.3.7 when run # on python 3.5b2. See # https://github.com/nose-devs/nose/issues/929 diff --git a/tools/travis-test.sh b/tools/travis-test.sh index 2eef17d41..91c871560 100755 --- a/tools/travis-test.sh +++ b/tools/travis-test.sh @@ -21,6 +21,11 @@ if [ -n "$PYTHON_OO" ]; then PYTHON="${PYTHON} -OO" fi + +if [ -n "$PY3_COMPATIBILITY_CHECK" ]; then + PYTHON="${PYTHON} -3" +fi + # make some warnings fatal, mostly to match windows compilers werrors="-Werror=declaration-after-statement -Werror=vla " werrors+="-Werror=nonnull -Werror=pointer-arith" |