summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCharles Harris <charlesr.harris@gmail.com>2017-08-06 11:36:11 -0500
committerGitHub <noreply@github.com>2017-08-06 11:36:11 -0500
commitf307cec3962926558b6387ebb4ab8d3f4ea3aa34 (patch)
treeb902a845cb2b7a64f78aae7a10776c3daeb16e50
parentd6539868b353e211b4aaa3a683101e094b3ee1df (diff)
parent091b8c3b16d39d18f6921f9a17d06c1652b40dca (diff)
downloadnumpy-f307cec3962926558b6387ebb4ab8d3f4ea3aa34.tar.gz
Merge pull request #9505 from eric-wieser/fix-issubdtype
BUG: issubdtype is inconsistent on types and dtypes
-rw-r--r--doc/release/1.14.0-notes.rst11
-rw-r--r--numpy/core/function_base.py2
-rw-r--r--numpy/core/numeric.py3
-rw-r--r--numpy/core/numerictypes.py45
-rw-r--r--numpy/core/tests/test_numerictypes.py32
-rw-r--r--numpy/doc/basics.py4
-rw-r--r--numpy/lib/_iotools.py2
-rw-r--r--numpy/lib/tests/test_function_base.py8
-rw-r--r--numpy/lib/tests/test_index_tricks.py2
-rw-r--r--numpy/lib/tests/test_type_check.py2
-rw-r--r--numpy/matrixlib/defmatrix.py2
-rw-r--r--numpy/matrixlib/tests/test_defmatrix.py6
12 files changed, 97 insertions, 22 deletions
diff --git a/doc/release/1.14.0-notes.rst b/doc/release/1.14.0-notes.rst
index 5e12b9f4a..7a4087dd9 100644
--- a/doc/release/1.14.0-notes.rst
+++ b/doc/release/1.14.0-notes.rst
@@ -25,6 +25,17 @@ Deprecations
Future Changes
==============
+``np.issubdtype`` will stop downcasting dtype-like arguments
+------------------------------------------------------------
+It would be expected that ``issubdtype(np.float32, 'float64')`` and
+``issubdtype(np.float32, np.float64)`` mean the same thing - however, there
+was an undocumented special case that translated the former into
+``issubdtype(np.float32, np.floating)``, giving the surprising result of True.
+
+This translation now gives a warning explaining what translation is occuring.
+In future, the translation will be disabled, and the first example will be made
+equivalent to the second.
+
Build System Changes
====================
diff --git a/numpy/core/function_base.py b/numpy/core/function_base.py
index 7098b8b91..0415e16ac 100644
--- a/numpy/core/function_base.py
+++ b/numpy/core/function_base.py
@@ -339,7 +339,7 @@ def geomspace(start, stop, num=50, endpoint=True, dtype=None):
# complex and another is negative and log would produce NaN otherwise
start = start + (stop - stop)
stop = stop + (start - start)
- if _nx.issubdtype(dtype, complex):
+ if _nx.issubdtype(dtype, _nx.complexfloating):
start = start + 0j
stop = stop + 0j
diff --git a/numpy/core/numeric.py b/numpy/core/numeric.py
index 13a99505c..7d53f2b68 100644
--- a/numpy/core/numeric.py
+++ b/numpy/core/numeric.py
@@ -436,8 +436,7 @@ def count_nonzero(a, axis=None):
if issubdtype(a.dtype, np.number):
return (a != 0).sum(axis=axis, dtype=np.intp)
- if (issubdtype(a.dtype, np.string_) or
- issubdtype(a.dtype, np.unicode_)):
+ if issubdtype(a.dtype, np.character):
nullstr = a.dtype.type('')
return (a != nullstr).sum(axis=axis, dtype=np.intp)
diff --git a/numpy/core/numerictypes.py b/numpy/core/numerictypes.py
index 5a8d9abe0..2cb66aab4 100644
--- a/numpy/core/numerictypes.py
+++ b/numpy/core/numerictypes.py
@@ -85,6 +85,7 @@ from __future__ import division, absolute_import, print_function
import types as _types
import sys
import numbers
+import warnings
from numpy.compat import bytes, long
from numpy.core.multiarray import (
@@ -739,20 +740,46 @@ def issubdtype(arg1, arg2):
Examples
--------
- >>> np.issubdtype('S1', str)
+ >>> np.issubdtype('S1', np.string_)
True
>>> np.issubdtype(np.float64, np.float32)
False
"""
- if issubclass_(arg2, generic):
- return issubclass(dtype(arg1).type, arg2)
- mro = dtype(arg2).type.mro()
- if len(mro) > 1:
- val = mro[1]
- else:
- val = mro[0]
- return issubclass(dtype(arg1).type, val)
+ if not issubclass_(arg1, generic):
+ arg1 = dtype(arg1).type
+ if not issubclass_(arg2, generic):
+ arg2_orig = arg2
+ arg2 = dtype(arg2).type
+ if not isinstance(arg2_orig, dtype):
+ # weird deprecated behaviour, that tried to infer np.floating from
+ # float, and similar less obvious things, such as np.generic from
+ # basestring
+ mro = arg2.mro()
+ arg2 = mro[1] if len(mro) > 1 else mro[0]
+
+ def type_repr(x):
+ """ Helper to produce clear error messages """
+ if not isinstance(x, type):
+ return repr(x)
+ elif issubclass(x, generic):
+ return "np.{}".format(x.__name__)
+ else:
+ return x.__name__
+
+ # 1.14, 2017-08-01
+ warnings.warn(
+ "Conversion of the second argument of issubdtype from `{raw}` "
+ "to `{abstract}` is deprecated. In future, it will be treated "
+ "as `{concrete} == np.dtype({raw}).type`.".format(
+ raw=type_repr(arg2_orig),
+ abstract=type_repr(arg2),
+ concrete=type_repr(dtype(arg2_orig).type)
+ ),
+ FutureWarning, stacklevel=2
+ )
+
+ return issubclass(arg1, arg2)
# This dictionary allows look up based on any alias for an array data-type
diff --git a/numpy/core/tests/test_numerictypes.py b/numpy/core/tests/test_numerictypes.py
index f912e3944..8831cd1bb 100644
--- a/numpy/core/tests/test_numerictypes.py
+++ b/numpy/core/tests/test_numerictypes.py
@@ -1,6 +1,7 @@
from __future__ import division, absolute_import, print_function
import sys
+import itertools
import numpy as np
from numpy.testing import (
@@ -377,5 +378,36 @@ class TestMultipleFields(object):
res = self.ary[['f0', 'f2']].tolist()
assert_(res == [(1, 3), (5, 7)])
+
+class TestIsSubDType(object):
+ # scalar types can be promoted into dtypes
+ wrappers = [np.dtype, lambda x: x]
+
+ def test_both_abstract(self):
+ assert_(np.issubdtype(np.floating, np.inexact))
+ assert_(not np.issubdtype(np.inexact, np.floating))
+
+ def test_same(self):
+ for cls in (np.float32, np.int32):
+ for w1, w2 in itertools.product(self.wrappers, repeat=2):
+ assert_(np.issubdtype(w1(cls), w2(cls)))
+
+ def test_subclass(self):
+ # note we cannot promote floating to a dtype, as it would turn into a
+ # concrete type
+ for w in self.wrappers:
+ assert_(np.issubdtype(w(np.float32), np.floating))
+ assert_(np.issubdtype(w(np.float64), np.floating))
+
+ def test_subclass_backwards(self):
+ for w in self.wrappers:
+ assert_(not np.issubdtype(np.floating, w(np.float32)))
+ assert_(not np.issubdtype(np.floating, w(np.float64)))
+
+ def test_sibling_class(self):
+ for w1, w2 in itertools.product(self.wrappers, repeat=2):
+ assert_(not np.issubdtype(w1(np.float32), w2(np.float64)))
+ assert_(not np.issubdtype(w1(np.float64), w2(np.float32)))
+
if __name__ == "__main__":
run_module_suite()
diff --git a/numpy/doc/basics.py b/numpy/doc/basics.py
index 083d55a84..10d7248c1 100644
--- a/numpy/doc/basics.py
+++ b/numpy/doc/basics.py
@@ -114,10 +114,10 @@ properties of the type, such as whether it is an integer::
>>> d
dtype('int32')
- >>> np.issubdtype(d, int)
+ >>> np.issubdtype(d, np.integer)
True
- >>> np.issubdtype(d, float)
+ >>> np.issubdtype(d, np.floating)
False
diff --git a/numpy/lib/_iotools.py b/numpy/lib/_iotools.py
index 304bba3d3..1874c2e97 100644
--- a/numpy/lib/_iotools.py
+++ b/numpy/lib/_iotools.py
@@ -527,7 +527,7 @@ class StringConverter(object):
_mapper.append((nx.int64, int, -1))
_mapper.extend([(nx.floating, float, nx.nan),
- (complex, _bytes_to_complex, nx.nan + 0j),
+ (nx.complexfloating, _bytes_to_complex, nx.nan + 0j),
(nx.longdouble, nx.longdouble, nx.nan),
(nx.string_, bytes, b'???')])
diff --git a/numpy/lib/tests/test_function_base.py b/numpy/lib/tests/test_function_base.py
index ad840f8ef..151c20a4b 100644
--- a/numpy/lib/tests/test_function_base.py
+++ b/numpy/lib/tests/test_function_base.py
@@ -1711,16 +1711,16 @@ class TestHistogram(object):
# Check the type of the returned histogram
a = np.arange(10) + .5
h, b = histogram(a)
- assert_(np.issubdtype(h.dtype, int))
+ assert_(np.issubdtype(h.dtype, np.integer))
h, b = histogram(a, normed=True)
- assert_(np.issubdtype(h.dtype, float))
+ assert_(np.issubdtype(h.dtype, np.floating))
h, b = histogram(a, weights=np.ones(10, int))
- assert_(np.issubdtype(h.dtype, int))
+ assert_(np.issubdtype(h.dtype, np.integer))
h, b = histogram(a, weights=np.ones(10, float))
- assert_(np.issubdtype(h.dtype, float))
+ assert_(np.issubdtype(h.dtype, np.floating))
def test_f32_rounding(self):
# gh-4799, check that the rounding of the edges works with float32
diff --git a/numpy/lib/tests/test_index_tricks.py b/numpy/lib/tests/test_index_tricks.py
index f06406c9e..452b3d6a2 100644
--- a/numpy/lib/tests/test_index_tricks.py
+++ b/numpy/lib/tests/test_index_tricks.py
@@ -243,7 +243,7 @@ class TestIx_(object):
for k, (a, sz) in enumerate(zip(arrays, sizes)):
assert_equal(a.shape[k], sz)
assert_(all(sh == 1 for j, sh in enumerate(a.shape) if j != k))
- assert_(np.issubdtype(a.dtype, int))
+ assert_(np.issubdtype(a.dtype, np.integer))
def test_bool(self):
bool_a = [True, False, True, True]
diff --git a/numpy/lib/tests/test_type_check.py b/numpy/lib/tests/test_type_check.py
index d863e5924..e05079981 100644
--- a/numpy/lib/tests/test_type_check.py
+++ b/numpy/lib/tests/test_type_check.py
@@ -420,7 +420,7 @@ class TestArrayConversion(object):
def test_asfarray(self):
a = asfarray(np.array([1, 2, 3]))
assert_equal(a.__class__, np.ndarray)
- assert_(np.issubdtype(a.dtype, float))
+ assert_(np.issubdtype(a.dtype, np.floating))
if __name__ == "__main__":
run_module_suite()
diff --git a/numpy/matrixlib/defmatrix.py b/numpy/matrixlib/defmatrix.py
index 2aed3ebde..e016b5f4c 100644
--- a/numpy/matrixlib/defmatrix.py
+++ b/numpy/matrixlib/defmatrix.py
@@ -137,7 +137,7 @@ def matrix_power(M, n):
M = asanyarray(M)
if M.ndim != 2 or M.shape[0] != M.shape[1]:
raise ValueError("input must be a square array")
- if not issubdtype(type(n), int):
+ if not issubdtype(type(n), N.integer):
raise TypeError("exponent must be an integer")
from numpy.linalg import inv
diff --git a/numpy/matrixlib/tests/test_defmatrix.py b/numpy/matrixlib/tests/test_defmatrix.py
index e4c3c49fb..77f262031 100644
--- a/numpy/matrixlib/tests/test_defmatrix.py
+++ b/numpy/matrixlib/tests/test_defmatrix.py
@@ -249,6 +249,12 @@ class TestAlgebra(object):
assert_array_almost_equal(m4, np.dot(m2, m2))
assert_array_almost_equal(np.dot(mi, m), np.eye(2))
+ def test_scalar_type_pow(self):
+ m = matrix([[1, 2], [3, 4]])
+ for scalar_t in [np.int8, np.uint8]:
+ two = scalar_t(2)
+ assert_array_almost_equal(m ** 2, m ** two)
+
def test_notimplemented(self):
'''Check that 'not implemented' operations produce a failure.'''
A = matrix([[1., 2.],