BUG: Fix PyType_FastSubclass() check for numpy.int_ and Py3k inheritance by zyv · Pull Request #3526 · numpy/numpy
The tp_flags change sounds correct, but the py3 issue is a doc bug --
np.int_ is not intended to inherit from int on py3, because on py3 int
is not longer a fixed-width integer type.
On Tue, Jul 16, 2013 at 2:40 PM, Yury V. Zaytsev
notifications@github.com wrote:
Quote from the documentation at
http://docs.scipy.org/doc/numpy/reference/arrays.scalars.html :Five of the scalar types are essentially equivalent to fundamental Python
types and therefore inherit from them as well as from the generic array
scalar type <...>However, presently, the code deviates from this document in two ways:
- For numpy.int_ type, the correct tp_flags are not set, which means that
if one uses specialized fast-path Python C-API macro PyInt_Check on its
instances to check whether the object is a subclass of a Python builtin, the
result will be different (False) as compared to PyObject_TypeCheck (True).This results in a different behavior of seemingly the same logic run through
the Python interpreter using its MRO facilities and hand-written or
generated modules, using optimized C-API calls directly.
- If one is using Py3k, then the code is expanded only to contain
SINGLE_INHERIT macros, which means that numpy.int_ is not a subclass of int
under Py3k at all.My patch fixes these two issues by (a) introducing new macro
DUAL_INHERIT_INT, which expands to DUAL_INHERIT(XXX, Long, XXX) under Py3k
and DUAL_INHERIT(XXX, Int, XXX) otherwise and (b) setting tp_flags correctly
from within this macro.In order to test my changes, you will need the following minimal Cython
program that generates code using optimized C-API calls:def inspect(x):
print("My MRO: {0}".format(type.mro(type(x))))
if isinstance(x, int):
print("I'm an normal integer number")
elif isinstance(x, long):
print("I'm an < Py3k long integer number")
elif isinstance(x, float):
print("I'm a floating point number")
else:
print("I don't know who I am")Test output on the x86_64 machine:
Python 2.7, without patch
In [1]: import bt
In [2]: import numpy as np
In [3]: type.mro(type(np.int_(0)))
Out[3]: [numpy.int64, numpy.signedinteger, numpy.integer, numpy.number,
numpy.generic, int, object]In [4]: type.mro(type(np.int32(0)))
Out[4]: [numpy.int32, numpy.signedinteger, numpy.integer, numpy.number,
numpy.generic, object]In [5]: type.mro(type(np.int64(0)))
Out[5]: [numpy.int64, numpy.signedinteger, numpy.integer, numpy.number,
numpy.generic, int, object]In [6]: bt.inspect(np.int_(0))
My MRO: [<type 'numpy.int64'>, <type 'numpy.signedinteger'>, <type
'numpy.integer'>, <type 'numpy.number'>, <type 'numpy.generic'>, <type
'int'>, <type 'object'>]
I don't know who I am <--- WRONG!In [7]: bt.inspect(np.int32(0))
My MRO: [<type 'numpy.int32'>, <type 'numpy.signedinteger'>, <type
'numpy.integer'>, <type 'numpy.number'>, <type 'numpy.generic'>, <type
'object'>]
I don't know who I amIn [8]: bt.inspect(np.int64(0))
My MRO: [<type 'numpy.int64'>, <type 'numpy.signedinteger'>, <type
'numpy.integer'>, <type 'numpy.number'>, <type 'numpy.generic'>, <type
'int'>, <type 'object'>]
I don't know who I am <--- WRONG!Python 3.2, without patch
In [1]: import bt
In [2]: import numpy as np
In [3]: type.mro(type(np.int_(0)))
Out[3]: [numpy.int64, numpy.signedinteger, numpy.integer, numpy.number,
numpy.generic, builtins.object]
^^^^ WRONG!
In [4]: type.mro(type(np.int32(0)))
Out[4]: [numpy.int32, numpy.signedinteger, numpy.integer, numpy.number,
numpy.generic, builtins.object]In [5]: type.mro(type(np.int64(0)))
Out[5]: [numpy.int64, numpy.signedinteger, numpy.integer, numpy.number,
numpy.generic, builtins.object]
^^^^ WRONG!
In [6]: bt.inspect(np.int_(0))
My MRO: [<class 'numpy.int64'>, <class 'numpy.signedinteger'>, <class
'numpy.integer'>, <class 'numpy.number'>, <class 'numpy.generic'>, <class
'object'>]
I don't know who I am
^^^^ WRONG!
In [7]: bt.inspect(np.int32(0))
My MRO: [<class 'numpy.int32'>, <class 'numpy.signedinteger'>, <class
'numpy.integer'>, <class 'numpy.number'>, <class 'numpy.generic'>, <class
'object'>]
I don't know who I amIn [8]: bt.inspect(np.int64(0))
My MRO: [<class 'numpy.int64'>, <class 'numpy.signedinteger'>, <class
'numpy.integer'>, <class 'numpy.number'>, <class 'numpy.generic'>, <class
'object'>]
I don't know who I am
^^^^ WRONG!Python 2.7, with patch
In [1]: import bt
In [2]: import numpy as np
In [3]: type.mro(type(np.int_(0)))
Out[3]: [numpy.int64, numpy.signedinteger, numpy.integer, numpy.number,
numpy.generic, int, object]In [4]: type.mro(type(np.int32(0)))
Out[4]: [numpy.int32, numpy.signedinteger, numpy.integer, numpy.number,
numpy.generic, object]In [5]: type.mro(type(np.int64(0)))
Out[5]: [numpy.int64, numpy.signedinteger, numpy.integer, numpy.number,
numpy.generic, int, object]In [6]: bt.inspect(np.int_(0))
My MRO: [<type 'numpy.int64'>, <type 'numpy.signedinteger'>, <type
'numpy.integer'>, <type 'numpy.number'>, <type 'numpy.generic'>, <type
'int'>, <type 'object'>]
I'm an normal integer number
^^^^ FIXED!
In [7]: bt.inspect(np.int32(0))
My MRO: [<type 'numpy.int32'>, <type 'numpy.signedinteger'>, <type
'numpy.integer'>, <type 'numpy.number'>, <type 'numpy.generic'>, <type
'object'>]
I don't know who I amIn [8]: bt.inspect(np.int64(0))
My MRO: [<type 'numpy.int64'>, <type 'numpy.signedinteger'>, <type
'numpy.integer'>, <type 'numpy.number'>, <type 'numpy.generic'>, <type
'int'>, <type 'object'>]
I'm an normal integer number
^^^^ FIXED!Python 3.2, with patch
In [1]: import bt
In [2]: import numpy as np
In [3]: type.mro(type(np.int_(0)))
Out[3]: [numpy.int64, numpy.signedinteger, numpy.integer, numpy.number,
numpy.generic, builtins.int, builtins.object]
^^^^ FIXED!
In [4]: type.mro(type(np.int32(0)))
Out[4]: [numpy.int32, numpy.signedinteger, numpy.integer, numpy.number,
numpy.generic, builtins.object]In [5]: type.mro(type(np.int64(0)))
Out[5]: [numpy.int64, numpy.signedinteger, numpy.integer, numpy.number,
numpy.generic, builtins.int, builtins.object]
^^^^ FIXED!
In [6]: bt.inspect(np.int_(0))
My MRO: [<class 'numpy.int64'>, <class 'numpy.signedinteger'>, <class
'numpy.integer'>, <class 'numpy.number'>, <class 'numpy.generic'>, <class
'int'>, <class 'object'>]
I'm an normal integer number
^^^^ FIXED!
In [7]: bt.inspect(np.int32(0))
My MRO: [<class 'numpy.int32'>, <class 'numpy.signedinteger'>, <class
'numpy.integer'>, <class 'numpy.number'>, <class 'numpy.generic'>, <class
'object'>]
I don't know who I amIn [8]: bt.inspect(np.int64(0))
My MRO: [<class 'numpy.int64'>, <class 'numpy.signedinteger'>, <class
'numpy.integer'>, <class 'numpy.number'>, <class 'numpy.generic'>, <class
'int'>, <class 'object'>]
I'm an normal integer number
^^^^ FIXED!Thank you for considering my bugfix for inclusion in NumPy,
--Yury.
You can merge this Pull Request by running
git pull https://github.com/zyv/numpy fix_int_inheritance
Or view, comment on, or merge it at:
Commit Summary
BUG: Fix PyType_FastSubclass() check for numpy.int_ and Py3k inheritance
File Changes
M numpy/core/src/multiarray/multiarraymodule.c (34)
Patch Links:
https://github.com/numpy/numpy/pull/3526.patch
https://github.com/numpy/numpy/pull/3526.diff