diff --git a/numpy/core/_type_aliases.py b/numpy/core/_type_aliases.py index 7ed7d7b442fc..896e6535bbf4 100644 --- a/numpy/core/_type_aliases.py +++ b/numpy/core/_type_aliases.py @@ -17,217 +17,97 @@ """ -from numpy.core._string_helpers import english_lower +import numpy.core.multiarray as ma from numpy.core.multiarray import typeinfo, dtype -from numpy.core._dtype import _kind_name +###################################### +# Building `sctypeDict` and `allTypes` +###################################### -sctypeDict = {} # Contains all leaf-node scalar types with aliases -allTypes = {} # Collect the types we will add to the module +sctypeDict = {} +allTypes = {} +c_names_dict = {} +_abstract_type_names = { + "generic", "integer", "inexact", "floating", "number", + "flexible", "character", "complexfloating", "unsignedinteger", + "signedinteger" +} -# separate the actual type info from the abstract base classes -_abstract_types = {} -_concrete_typeinfo = {} -for k, v in typeinfo.items(): - # make all the keys lowercase too - k = english_lower(k) - if isinstance(v, type): - _abstract_types[k] = v - else: - _concrete_typeinfo[k] = v - -_concrete_types = {v.type for k, v in _concrete_typeinfo.items()} - - -def _bits_of(obj): - try: - info = next(v for v in _concrete_typeinfo.values() if v.type is obj) - except StopIteration: - if obj in _abstract_types.values(): - msg = "Cannot count the bits of an abstract type" - raise ValueError(msg) from None +for _abstract_type_name in _abstract_type_names: + allTypes[_abstract_type_name] = getattr(ma, _abstract_type_name) - # some third-party type - make a best-guess - return dtype(obj).itemsize * 8 - else: - return info.bits - - -def bitname(obj): - """Return a bit-width name for a given type object""" - bits = _bits_of(obj) - dt = dtype(obj) - char = dt.kind - base = _kind_name(dt) - - if base == 'object': - bits = 0 - - if bits != 0: - char = "%s%d" % (char, bits // 8) - - return base, bits, char - - -def _add_types(): - for name, info in _concrete_typeinfo.items(): - # define C-name and insert typenum and typechar references also - allTypes[name] = info.type - sctypeDict[name] = info.type - sctypeDict[info.char] = info.type - sctypeDict[info.num] = info.type - - for name, cls in _abstract_types.items(): - allTypes[name] = cls -_add_types() - -# This is the priority order used to assign the bit-sized NPY_INTxx names, which -# must match the order in npy_common.h in order for NPY_INTxx and np.intxx to be -# consistent. -# If two C types have the same size, then the earliest one in this list is used -# as the sized name. -_int_ctypes = ['long', 'longlong', 'int', 'short', 'byte'] -_uint_ctypes = list('u' + t for t in _int_ctypes) - -def _add_aliases(): - for name, info in _concrete_typeinfo.items(): - # these are handled by _add_integer_aliases - if name in _int_ctypes or name in _uint_ctypes: - continue - - # insert bit-width version for this class (if relevant) - base, bit, char = bitname(info.type) - - myname = "%s%d" % (base, bit) - - # ensure that (c)longdouble does not overwrite the aliases assigned to - # (c)double - if name in ('longdouble', 'clongdouble') and myname in allTypes: - continue - - if bit != 0 and base != "bool": - # add to the main namespace - allTypes[myname] = info.type - # add mapping for both the bit name - sctypeDict[myname] = info.type - - # add forward, reverse, and string mapping to numarray - sctypeDict[char] = info.type - -_add_aliases() - -def _add_integer_aliases(): - seen_bits = set() - for i_ctype, u_ctype in zip(_int_ctypes, _uint_ctypes): - i_info = _concrete_typeinfo[i_ctype] - u_info = _concrete_typeinfo[u_ctype] - bits = i_info.bits # same for both - - for info, charname, intname in [ - (i_info,'i%d' % (bits//8,), 'int%d' % bits), - (u_info,'u%d' % (bits//8,), 'uint%d' % bits)]: - if bits not in seen_bits: - # sometimes two different types have the same number of bits - # if so, the one iterated over first takes precedence - allTypes[intname] = info.type - sctypeDict[intname] = info.type - sctypeDict[charname] = info.type - - seen_bits.add(bits) - -_add_integer_aliases() - -# We use these later -void = allTypes['void'] - -# -# Rework the Python names (so that float and complex and int are consistent -# with Python usage) -# -def _set_up_aliases(): - type_pairs = [('single', 'float'), - ('csingle', 'cfloat'), - ('intc', 'int'), - ('uintc', 'uint'), - ('int_', 'long'), - ('uint', 'ulong'), - ('bool_', 'bool'), - ('bytes_', 'string'), - ('str_', 'unicode'), - ('object_', 'object'), - ('cfloat', 'cdouble')] - for alias, t in type_pairs: - allTypes[alias] = allTypes[t] - sctypeDict[alias] = sctypeDict[t] - # Remove aliases overriding python types and modules - to_remove = ['object', 'int', 'float', 'complex', 'bool', - 'string', 'datetime', 'timedelta', 'bytes', 'str'] - - for t in to_remove: - try: - del allTypes[t] - del sctypeDict[t] - except KeyError: - pass - - # Additional aliases in sctypeDict that should not be exposed as attributes - attrs_to_remove = ['ulong', 'long', 'unicode', 'cfloat'] - - for t in attrs_to_remove: - try: - del allTypes[t] - except KeyError: - pass -_set_up_aliases() - - -sctypes = {'int': [], - 'uint': [], - 'float': [], - 'complex': [], - 'others': [bool, object, bytes, str, void]} - - -def _add_array_type(typename, bits): - try: - t = allTypes['%s%d' % (typename, bits)] - except KeyError: - pass - else: - sctypes[typename].append(t) - -def _set_array_types(): - ibytes = [1, 2, 4, 8, 16, 32, 64] - fbytes = [2, 4, 8, 10, 12, 16, 32, 64] - for bytes in ibytes: - bits = 8*bytes - _add_array_type('int', bits) - _add_array_type('uint', bits) - for bytes in fbytes: - bits = 8*bytes - _add_array_type('float', bits) - _add_array_type('complex', 2*bits) - _gi = dtype('p') - if _gi.type not in sctypes['int']: - indx = 0 - sz = _gi.itemsize - _lst = sctypes['int'] - while (indx < len(_lst) and sz >= _lst[indx](0).itemsize): - indx += 1 - sctypes['int'].insert(indx, _gi.type) - sctypes['uint'].insert(indx, dtype('P').type) -_set_array_types() - - -# Add additional strings to the sctypeDict -_toadd = ['int', ('float', 'double'), ('complex', 'cdouble'), - 'bool', 'object', 'str', 'bytes'] - -for name in _toadd: - if isinstance(name, tuple): - sctypeDict[name[0]] = allTypes[name[1]] +for k, v in typeinfo.items(): + if k.startswith("NPY_") and v not in c_names_dict: + c_names_dict[k[4:]] = v else: - sctypeDict[name] = allTypes['%s_' % name] - -del _toadd, name + concrete_type = v.type + allTypes[k] = concrete_type + sctypeDict[k] = concrete_type + +_aliases = { + "double": "float64", + "cdouble": "complex128", + "single": "float32", + "csingle": "complex64", + "half": "float16" +} + +for k, v in _aliases.items(): + sctypeDict[k] = allTypes[v] + allTypes[k] = allTypes[v] + +# extra aliases are added only to `sctypeDict` +# to support dtype name access, such as`np.dtype("float")` +_extra_aliases = { + "bool": "bool_", + "float": "float64", + "complex": "complex128", + "object": "object_", + "bytes": "bytes_", + "int": "int_", + "long": "int_", + "ulong": "uint", + "str": "str_", +} + +for k, v in _extra_aliases.items(): + sctypeDict[k] = allTypes[v] + +# include extended precision sized aliases +for is_complex, full_name in [(False, "longdouble"), (True, "clongdouble")]: + longdouble_type: type = allTypes[full_name] + + bits: int = dtype(longdouble_type).itemsize * 8 + base_name: str = "complex" if is_complex else "float" + extended_prec_name: str = f"{base_name}{bits}" + if extended_prec_name not in allTypes: + sctypeDict[extended_prec_name] = longdouble_type + allTypes[extended_prec_name] = longdouble_type + + +#################### +# Building `sctypes` +#################### + +sctypes = {"int": [], "uint": [], "float": [], "complex": [], "others": []} + +for type_info in set(typeinfo.values()): + if type_info.kind in ["M", "m"]: # exclude timedelta and datetime + continue + + concrete_type = type_info.type + + # find proper group for each concrete type + for type_group, abstract_type in [ + ("int", ma.signedinteger), ("uint", ma.unsignedinteger), + ("float", ma.floating), ("complex", ma.complexfloating), + ("others", ma.generic) + ]: + if issubclass(concrete_type, abstract_type): + sctypes[type_group].append(concrete_type) + break + +# sort sctype groups by bitsize +for sctype_list in sctypes.values(): + sctype_list.sort(key=lambda x: dtype(x).itemsize) diff --git a/numpy/core/meson.build b/numpy/core/meson.build index 3fc940cdc02b..97b200aeab2f 100644 --- a/numpy/core/meson.build +++ b/numpy/core/meson.build @@ -1040,7 +1040,6 @@ src_multiarray = multiarray_gen_headers + [ 'src/multiarray/scalarapi.c', 'src/multiarray/strfuncs.c', 'src/multiarray/temp_elide.c', - 'src/multiarray/typeinfo.c', 'src/multiarray/usertypes.c', 'src/multiarray/vdot.c', 'src/npysort/quicksort.cpp', diff --git a/numpy/core/numerictypes.py b/numpy/core/numerictypes.py index a817e656d57b..4f356bfa2f0d 100644 --- a/numpy/core/numerictypes.py +++ b/numpy/core/numerictypes.py @@ -99,13 +99,7 @@ ) from ._type_aliases import ( - sctypeDict, - allTypes, - bitname, - sctypes, - _concrete_types, - _concrete_typeinfo, - _bits_of, + sctypeDict, allTypes, sctypes ) from ._dtype import _kind_name @@ -431,34 +425,6 @@ def issubdtype(arg1, arg2): return issubclass(arg1, arg2) -# This dictionary allows look up based on any alias for an array data-type -class _typedict(dict): - """ - Base object for a dictionary for look-up with any alias for an array dtype. - - Instances of `_typedict` can not be used as dictionaries directly, - first they have to be populated. - - """ - - def __getitem__(self, obj): - return dict.__getitem__(self, obj2sctype(obj)) - -_maxvals = _typedict() -_minvals = _typedict() -def _construct_lookups(): - for info in _concrete_typeinfo.values(): - obj = info.type - if len(info) > 5: - _maxvals[obj] = info.max - _minvals[obj] = info.min - else: - _maxvals[obj] = None - _minvals[obj] = None - -_construct_lookups() - - @set_module('numpy') def sctype2char(sctype): """ @@ -506,7 +472,7 @@ def sctype2char(sctype): sctype = obj2sctype(sctype) if sctype is None: raise ValueError("unrecognized type") - if sctype not in _concrete_types: + if sctype not in sctypeDict.values(): # for compatibility raise KeyError(sctype) return dtype(sctype).char @@ -519,7 +485,7 @@ def _scalar_type_key(typ): ScalarType = [int, float, complex, bool, bytes, str, memoryview] -ScalarType += sorted(_concrete_types, key=_scalar_type_key) +ScalarType += sorted(set(sctypeDict.values()), key=_scalar_type_key) ScalarType = tuple(ScalarType) diff --git a/numpy/core/numerictypes.pyi b/numpy/core/numerictypes.pyi index 1e3a39d958d5..aa5b8dada475 100644 --- a/numpy/core/numerictypes.pyi +++ b/numpy/core/numerictypes.pyi @@ -65,9 +65,6 @@ class _TypeCodes(TypedDict): Datetime: L['Mm'] All: L['?bhilqpBHILQPefdgFDGSUVOMm'] -class _typedict(dict[type[generic], _T]): - def __getitem__(self, key: DTypeLike) -> _T: ... - if sys.version_info >= (3, 10): _TypeTuple = ( type[Any] @@ -116,7 +113,6 @@ def issubdtype(arg1: DTypeLike, arg2: DTypeLike) -> bool: ... def sctype2char(sctype: DTypeLike) -> str: ... -cast: _typedict[_CastFunc] typecodes: _TypeCodes ScalarType: tuple[ type[int], diff --git a/numpy/core/src/multiarray/arraytypes.c.src b/numpy/core/src/multiarray/arraytypes.c.src index e852edb57848..51ea6d29168f 100644 --- a/numpy/core/src/multiarray/arraytypes.c.src +++ b/numpy/core/src/multiarray/arraytypes.c.src @@ -28,7 +28,6 @@ #include "_datetime.h" #include "arrayobject.h" #include "alloc.h" -#include "typeinfo.h" #include "npy_longdouble.h" #include "numpyos.h" @@ -4586,7 +4585,7 @@ PyArray_DescrFromType(int type) NPY_NO_EXPORT int set_typeinfo(PyObject *dict) { - PyObject *infodict, *s; + PyObject *infodict = NULL; int i; PyArray_Descr *dtype; @@ -4754,196 +4753,88 @@ set_typeinfo(PyObject *dict) int ret; /**begin repeat * - * #name = BOOL, + * #NAME = BOOL, + * HALF, FLOAT, DOUBLE, LONGDOUBLE, + * CFLOAT, CDOUBLE, CLONGDOUBLE, + * STRING, UNICODE, VOID, OBJECT, + * DATETIME, TIMEDELTA, * BYTE, UBYTE, SHORT, USHORT, INT, UINT, - * INTP, UINTP, * LONG, ULONG, LONGLONG, ULONGLONG# - * #uname = BOOL, - * BYTE*2, SHORT*2, INT*2, - * INTP*2, - * LONG*2, LONGLONG*2# * #Name = Bool, + * Half, Float, Double, LongDouble, + * CFloat, CDouble, CLongDouble, + * Bytes, Str, Void, Object, + * DateTime64, TimeDelta64, * Byte, UByte, Short, UShort, Int, UInt, - * Intp, UIntp, * Long, ULong, LongLong, ULongLong# - * #type = npy_bool, - * npy_byte, npy_ubyte, npy_short, npy_ushort, npy_int, npy_uint, - * npy_intp, npy_uintp, - * npy_long, npy_ulong, npy_longlong, npy_ulonglong# - * #max= 1, - * NPY_MAX_BYTE, NPY_MAX_UBYTE, NPY_MAX_SHORT, - * NPY_MAX_USHORT, NPY_MAX_INT, PyLong_FromUnsignedLong(NPY_MAX_UINT), - * PyLong_FromLongLong((npy_longlong) NPY_MAX_INTP), - * PyLong_FromUnsignedLongLong((npy_ulonglong) NPY_MAX_UINTP), - * NPY_MAX_LONG, - * PyLong_FromUnsignedLong((npy_ulong) NPY_MAX_ULONG), - * PyLong_FromLongLong((npy_longlong) NPY_MAX_LONGLONG), - * PyLong_FromUnsignedLongLong((npy_ulonglong) NPY_MAX_ULONGLONG)# - * #min = 0, NPY_MIN_BYTE, 0, NPY_MIN_SHORT, 0, NPY_MIN_INT, 0, - * PyLong_FromLongLong((npy_longlong) NPY_MIN_INTP), - * 0, NPY_MIN_LONG, 0, - * PyLong_FromLongLong((npy_longlong) NPY_MIN_LONGLONG), 0# - * #cx = i*6, N, N, N, l, N, N, N# - * #cn = i*7, N, i, l, i, N, i# */ - s = PyArray_typeinforanged( - NPY_@name@LTR, NPY_@name@, NPY_BITSOF_@uname@, NPY_ALIGNOF(@type@), - Py_BuildValue("@cx@", @max@), - Py_BuildValue("@cn@", @min@), - &Py@Name@ArrType_Type - ); - if (s == NULL) { - Py_DECREF(infodict); - return -1; + /* + * Add the scalar dtypes with their names and aliases (integers have them) + * to the dict to populate the namespace in Python. + * Note that we do lose one piece of information due to intp/uintp since + * they are strict aliases and we do not add the "p" and "P" character + * codes for them. + */ + dtype = PyArray_DescrFromType(NPY_@NAME@); + ret = PyDict_SetItemString(infodict, NPY_@NAME@_name, (PyObject *)dtype); + Py_DECREF(dtype); + if (ret < 0) { + goto error; } - ret = PyDict_SetItemString(infodict, "@name@", s); - Py_DECREF(s); +#ifdef NPY_@NAME@_alias + dtype = PyArray_DescrFromType(NPY_@NAME@); + ret = PyDict_SetItemString(infodict, NPY_@NAME@_alias, (PyObject *)dtype); + Py_DECREF(dtype); if (ret < 0) { - Py_DECREF(infodict); - return -1; + goto error; } +#endif - - /**end repeat**/ - - - /**begin repeat - * - * #type = npy_half, npy_float, npy_double, npy_longdouble, - * npy_cfloat, npy_cdouble, npy_clongdouble# - * #name = HALF, FLOAT, DOUBLE, LONGDOUBLE, - * CFLOAT, CDOUBLE, CLONGDOUBLE# - * #Name = Half, Float, Double, LongDouble, - * CFloat, CDouble, CLongDouble# - */ - s = PyArray_typeinfo( - NPY_@name@LTR, NPY_@name@, NPY_BITSOF_@name@, - NPY_ALIGNOF(@type@), &Py@Name@ArrType_Type - ); - if (s == NULL) { - Py_DECREF(infodict); - return -1; - } - ret = PyDict_SetItemString(infodict, "@name@", s); - Py_DECREF(s); + dtype = PyArray_DescrFromType(NPY_@NAME@); + ret = PyDict_SetItemString(infodict, "NPY_@NAME@", (PyObject *)dtype); + Py_DECREF(dtype); if (ret < 0) { - Py_DECREF(infodict); - return -1; + goto error; } /**end repeat**/ - s = PyArray_typeinfo( - NPY_OBJECTLTR, NPY_OBJECT, sizeof(PyObject *) * CHAR_BIT, - NPY_ALIGNOF(PyObject *), - &PyObjectArrType_Type - ); - if (s == NULL) { - Py_DECREF(infodict); - return -1; - } - ret = PyDict_SetItemString(infodict, "OBJECT", s); - Py_DECREF(s); + /* Intp and UIntp are an additional alias */ + dtype = PyArray_DescrFromType(NPY_INTP); + ret = PyDict_SetItemString(infodict, "intp", (PyObject *)dtype); + Py_DECREF(dtype); if (ret < 0) { - Py_DECREF(infodict); - return -1; - } - s = PyArray_typeinfo( - NPY_STRINGLTR, NPY_STRING, 0, NPY_ALIGNOF(char), - &PyStringArrType_Type - ); - if (s == NULL) { - Py_DECREF(infodict); - return -1; - } - ret = PyDict_SetItemString(infodict, "STRING", s); - Py_DECREF(s); - if (ret < 0) { - Py_DECREF(infodict); - return -1; - } - s = PyArray_typeinfo( - NPY_UNICODELTR, NPY_UNICODE, 0, NPY_ALIGNOF(npy_ucs4), - &PyUnicodeArrType_Type - ); - if (s == NULL) { - Py_DECREF(infodict); - return -1; - } - ret = PyDict_SetItemString(infodict, "UNICODE", s); - Py_DECREF(s); - if (ret < 0) { - Py_DECREF(infodict); - return -1; - } - s = PyArray_typeinfo( - NPY_VOIDLTR, NPY_VOID, 0, NPY_ALIGNOF(char), - &PyVoidArrType_Type - ); - if (s == NULL) { - Py_DECREF(infodict); - return -1; - } - ret = PyDict_SetItemString(infodict, "VOID", s); - Py_DECREF(s); - if (ret < 0) { - Py_DECREF(infodict); - return -1; - } - s = PyArray_typeinforanged( - NPY_DATETIMELTR, NPY_DATETIME, NPY_BITSOF_DATETIME, - NPY_ALIGNOF(npy_datetime), - MyPyLong_FromInt64(NPY_MAX_DATETIME), - MyPyLong_FromInt64(NPY_MIN_DATETIME), - &PyDatetimeArrType_Type - ); - if (s == NULL) { - Py_DECREF(infodict); - return -1; - } - ret = PyDict_SetItemString(infodict, "DATETIME", s); - Py_DECREF(s); - if (ret < 0) { - Py_DECREF(infodict); - return -1; - } - s = PyArray_typeinforanged( - NPY_TIMEDELTALTR, NPY_TIMEDELTA, NPY_BITSOF_TIMEDELTA, - NPY_ALIGNOF(npy_timedelta), - MyPyLong_FromInt64(NPY_MAX_TIMEDELTA), - MyPyLong_FromInt64(NPY_MIN_TIMEDELTA), - &PyTimedeltaArrType_Type - ); - if (s == NULL) { - Py_DECREF(infodict); - return -1; + goto error; } - ret = PyDict_SetItemString(infodict, "TIMEDELTA", s); - Py_DECREF(s); + dtype = PyArray_DescrFromType(NPY_UINTP); + ret = PyDict_SetItemString(infodict, "uintp", (PyObject *)dtype); + Py_DECREF(dtype); if (ret < 0) { - Py_DECREF(infodict); - return -1; - } - -#define SETTYPE(name) \ - Py_INCREF(&Py##name##ArrType_Type); \ - if (PyDict_SetItemString(infodict, #name, \ - (PyObject *)&Py##name##ArrType_Type) < 0) { \ - Py_DECREF(infodict); \ - return -1; \ + goto error; } - SETTYPE(Generic); - SETTYPE(Number); - SETTYPE(Integer); - SETTYPE(Inexact); - SETTYPE(SignedInteger); - SETTYPE(UnsignedInteger); - SETTYPE(Floating); - SETTYPE(ComplexFloating); - SETTYPE(Flexible); - SETTYPE(Character); + /* + * Add the abstract scalar types to the `_multiarray_umath` namespace. + * (duplicates making the name lowercase) + */ +#define SETTYPE(Name, name) \ + Py_INCREF(&Py##Name##ArrType_Type); \ + if (PyDict_SetItemString(dict, #name, \ + (PyObject *)&Py##Name##ArrType_Type) < 0) { \ + goto error; \ + } + + SETTYPE(Generic, generic); + SETTYPE(Number, number); + SETTYPE(Integer, integer); + SETTYPE(Inexact, inexact); + SETTYPE(SignedInteger, signedinteger); + SETTYPE(UnsignedInteger, unsignedinteger); + SETTYPE(Floating, floating); + SETTYPE(ComplexFloating, complexfloating); + SETTYPE(Flexible, flexible); + SETTYPE(Character, character); #undef SETTYPE @@ -4953,6 +4844,10 @@ set_typeinfo(PyObject *dict) return -1; } return 0; + + error: + Py_XDECREF(infodict); + return -1; } #undef _MAX_LETTER diff --git a/numpy/core/src/multiarray/multiarraymodule.c b/numpy/core/src/multiarray/multiarraymodule.c index 3711cea8977f..851eb1fc45b3 100644 --- a/numpy/core/src/multiarray/multiarraymodule.c +++ b/numpy/core/src/multiarray/multiarraymodule.c @@ -67,7 +67,6 @@ NPY_NO_EXPORT int NPY_NUMUSERTYPES = 0; #include "templ_common.h" /* for npy_mul_sizes_with_overflow */ #include "compiled_base.h" #include "mem_overlap.h" -#include "typeinfo.h" #include "convert.h" /* for PyArray_AssignZero */ #include "lowlevel_strided_loops.h" #include "dtype_transfer.h" @@ -5109,11 +5108,7 @@ PyMODINIT_FUNC PyInit__multiarray_umath(void) { (PyObject *)&NpyBusDayCalendar_Type); set_flaginfo(d); - /* Create the typeinfo types */ - if (typeinfo_init_structsequences(d) < 0) { - goto err; - } - + /* Finalize scalar types and expose them via namespace or typeinfo dict */ if (set_typeinfo(d) != 0) { goto err; } diff --git a/numpy/core/src/multiarray/typeinfo.c b/numpy/core/src/multiarray/typeinfo.c deleted file mode 100644 index 18179f7e7b61..000000000000 --- a/numpy/core/src/multiarray/typeinfo.c +++ /dev/null @@ -1,117 +0,0 @@ -/* - * Provides namedtuples for numpy.core.multiarray.typeinfo - * Unfortunately, we need two different types to cover the cases where min/max - * do and do not appear in the tuple. - */ -#define NPY_NO_DEPRECATED_API NPY_API_VERSION -#define _MULTIARRAYMODULE - -#include "npy_pycompat.h" -#include "typeinfo.h" - - -static PyTypeObject PyArray_typeinfoType; -static PyTypeObject PyArray_typeinforangedType; - -static PyStructSequence_Field typeinfo_fields[] = { - {"char", "The character used to represent the type"}, - {"num", "The numeric id assigned to the type"}, - {"bits", "The number of bits in the type"}, - {"alignment", "The alignment of the type in bytes"}, - {"type", "The python type object this info is about"}, - {NULL, NULL,} -}; - -static PyStructSequence_Field typeinforanged_fields[] = { - {"char", "The character used to represent the type"}, - {"num", "The numeric id assigned to the type"}, - {"bits", "The number of bits in the type"}, - {"alignment", "The alignment of the type in bytes"}, - {"max", "The maximum value of this type"}, - {"min", "The minimum value of this type"}, - {"type", "The python type object this info is about"}, - {NULL, NULL,} -}; - -static PyStructSequence_Desc typeinfo_desc = { - "numpy.core.multiarray.typeinfo", /* name */ - "Information about a scalar numpy type", /* doc */ - typeinfo_fields, /* fields */ - 5, /* n_in_sequence */ -}; - -static PyStructSequence_Desc typeinforanged_desc = { - "numpy.core.multiarray.typeinforanged", /* name */ - "Information about a scalar numpy type with a range", /* doc */ - typeinforanged_fields, /* fields */ - 7, /* n_in_sequence */ -}; - -NPY_NO_EXPORT PyObject * -PyArray_typeinfo( - char typechar, int typenum, int nbits, int align, - PyTypeObject *type_obj) -{ - PyObject *entry = PyStructSequence_New(&PyArray_typeinfoType); - if (entry == NULL) - return NULL; - PyStructSequence_SET_ITEM(entry, 0, Py_BuildValue("C", typechar)); - PyStructSequence_SET_ITEM(entry, 1, Py_BuildValue("i", typenum)); - PyStructSequence_SET_ITEM(entry, 2, Py_BuildValue("i", nbits)); - PyStructSequence_SET_ITEM(entry, 3, Py_BuildValue("i", align)); - PyStructSequence_SET_ITEM(entry, 4, Py_BuildValue("O", (PyObject *) type_obj)); - - if (PyErr_Occurred()) { - Py_DECREF(entry); - return NULL; - } - - return entry; -} - -NPY_NO_EXPORT PyObject * -PyArray_typeinforanged( - char typechar, int typenum, int nbits, int align, - PyObject *max, PyObject *min, PyTypeObject *type_obj) -{ - PyObject *entry = PyStructSequence_New(&PyArray_typeinforangedType); - if (entry == NULL) - return NULL; - PyStructSequence_SET_ITEM(entry, 0, Py_BuildValue("C", typechar)); - PyStructSequence_SET_ITEM(entry, 1, Py_BuildValue("i", typenum)); - PyStructSequence_SET_ITEM(entry, 2, Py_BuildValue("i", nbits)); - PyStructSequence_SET_ITEM(entry, 3, Py_BuildValue("i", align)); - PyStructSequence_SET_ITEM(entry, 4, max); - PyStructSequence_SET_ITEM(entry, 5, min); - PyStructSequence_SET_ITEM(entry, 6, Py_BuildValue("O", (PyObject *) type_obj)); - - if (PyErr_Occurred()) { - Py_DECREF(entry); - return NULL; - } - - return entry; -} - - -NPY_NO_EXPORT int -typeinfo_init_structsequences(PyObject *multiarray_dict) -{ - if (PyStructSequence_InitType2( - &PyArray_typeinfoType, &typeinfo_desc) < 0) { - return -1; - } - if (PyStructSequence_InitType2( - &PyArray_typeinforangedType, &typeinforanged_desc) < 0) { - return -1; - } - if (PyDict_SetItemString(multiarray_dict, - "typeinfo", (PyObject *)&PyArray_typeinfoType) < 0) { - return -1; - } - if (PyDict_SetItemString(multiarray_dict, - "typeinforanged", (PyObject *)&PyArray_typeinforangedType) < 0) { - return -1; - } - return 0; -} diff --git a/numpy/core/src/multiarray/typeinfo.h b/numpy/core/src/multiarray/typeinfo.h deleted file mode 100644 index af4637fc92df..000000000000 --- a/numpy/core/src/multiarray/typeinfo.h +++ /dev/null @@ -1,21 +0,0 @@ -#ifndef NUMPY_CORE_SRC_MULTIARRAY_TYPEINFO_H_ -#define NUMPY_CORE_SRC_MULTIARRAY_TYPEINFO_H_ - -#define PY_SSIZE_T_CLEAN -#include -#include "npy_config.h" - -NPY_VISIBILITY_HIDDEN int -typeinfo_init_structsequences(PyObject *multiarray_dict); - -NPY_VISIBILITY_HIDDEN PyObject * -PyArray_typeinfo( - char typechar, int typenum, int nbits, int align, - PyTypeObject *type_obj); - -NPY_VISIBILITY_HIDDEN PyObject * -PyArray_typeinforanged( - char typechar, int typenum, int nbits, int align, - PyObject *max, PyObject *min, PyTypeObject *type_obj); - -#endif /* NUMPY_CORE_SRC_MULTIARRAY_TYPEINFO_H_ */ diff --git a/numpy/core/tests/test_numerictypes.py b/numpy/core/tests/test_numerictypes.py index 2d9307ceeaa6..bbf1cbc93f07 100644 --- a/numpy/core/tests/test_numerictypes.py +++ b/numpy/core/tests/test_numerictypes.py @@ -416,8 +416,8 @@ def test_nondtype_nonscalartype(self): class TestSctypeDict: def test_longdouble(self): - assert_(np.core.sctypeDict['f8'] is not np.longdouble) - assert_(np.core.sctypeDict['c16'] is not np.clongdouble) + assert_(np.core.sctypeDict['float64'] is not np.longdouble) + assert_(np.core.sctypeDict['complex128'] is not np.clongdouble) def test_ulong(self): # Test that 'ulong' behaves like 'long'. np.core.sctypeDict['long'] @@ -429,11 +429,6 @@ def test_ulong(self): assert not hasattr(np, 'ulong') -class TestBitName: - def test_abstract(self): - assert_raises(ValueError, np.core.numerictypes.bitname, np.floating) - - @pytest.mark.filterwarnings("ignore:.*maximum_sctype.*:DeprecationWarning") class TestMaximumSctype: diff --git a/numpy/f2py/tests/test_array_from_pyobj.py b/numpy/f2py/tests/test_array_from_pyobj.py index 2b8c8defca5a..2a9938dca1d3 100644 --- a/numpy/f2py/tests/test_array_from_pyobj.py +++ b/numpy/f2py/tests/test_array_from_pyobj.py @@ -7,16 +7,16 @@ import numpy as np from numpy.testing import assert_, assert_equal -from numpy.core.multiarray import typeinfo as _typeinfo +from numpy.core._type_aliases import c_names_dict as _c_names_dict from . import util wrap = None # Extend core typeinfo with CHARACTER to test dtype('c') -_ti = _typeinfo['STRING'] -typeinfo = dict( - CHARACTER=type(_ti)(('c', _ti.num, 8, _ti.alignment, _ti.type)), - **_typeinfo) +c_names_dict = dict( + CHARACTER=np.dtype("c"), + **_c_names_dict +) def setup_module(): @@ -185,7 +185,7 @@ def __new__(cls, name): if isinstance(name, np.dtype): dtype0 = name name = None - for n, i in typeinfo.items(): + for n, i in c_names_dict.items(): if not isinstance(i, type) and dtype0.type is i.type: name = n break @@ -201,19 +201,19 @@ def _init(self, name): self.NAME = name.upper() if self.NAME == 'CHARACTER': - info = typeinfo[self.NAME] + info = c_names_dict[self.NAME] self.type_num = getattr(wrap, 'NPY_STRING') self.elsize = 1 self.dtype = np.dtype('c') elif self.NAME.startswith('STRING'): - info = typeinfo[self.NAME[:6]] + info = c_names_dict[self.NAME[:6]] self.type_num = getattr(wrap, 'NPY_STRING') self.elsize = int(self.NAME[6:] or 0) self.dtype = np.dtype(f'S{self.elsize}') else: - info = typeinfo[self.NAME] + info = c_names_dict[self.NAME] self.type_num = getattr(wrap, 'NPY_' + self.NAME) - self.elsize = info.bits // 8 + self.elsize = info.itemsize self.dtype = np.dtype(info.type) assert self.type_num == info.num @@ -233,28 +233,28 @@ def all_types(self): return [self.__class__(_m) for _m in _type_names] def smaller_types(self): - bits = typeinfo[self.NAME].alignment + bits = c_names_dict[self.NAME].alignment types = [] for name in _type_names: - if typeinfo[name].alignment < bits: + if c_names_dict[name].alignment < bits: types.append(Type(name)) return types def equal_types(self): - bits = typeinfo[self.NAME].alignment + bits = c_names_dict[self.NAME].alignment types = [] for name in _type_names: if name == self.NAME: continue - if typeinfo[name].alignment == bits: + if c_names_dict[name].alignment == bits: types.append(Type(name)) return types def larger_types(self): - bits = typeinfo[self.NAME].alignment + bits = c_names_dict[self.NAME].alignment types = [] for name in _type_names: - if typeinfo[name].alignment > bits: + if c_names_dict[name].alignment > bits: types.append(Type(name)) return types diff --git a/numpy/ma/core.py b/numpy/ma/core.py index caf0d02c6636..6c1456987944 100644 --- a/numpy/ma/core.py +++ b/numpy/ma/core.py @@ -27,13 +27,14 @@ import textwrap import re from functools import reduce +from typing import Dict import numpy as np import numpy.core.umath as umath import numpy.core.numerictypes as ntypes from numpy.core import multiarray as mu from numpy import ndarray, amax, amin, iscomplexobj, bool_, _NoValue, angle -from numpy import array as narray, expand_dims +from numpy import array as narray, expand_dims, iinfo, finfo from numpy.core.numeric import normalize_axis_tuple from numpy._utils._inspect import getargspec, formatargspec @@ -182,11 +183,35 @@ class MaskError(MAError): float_types_list = [np.half, np.single, np.double, np.longdouble, np.csingle, np.cdouble, np.clongdouble] -max_filler = ntypes._minvals + +_minvals: Dict[type, int] = {} +_maxvals: Dict[type, int] = {} + +for sctype in ntypes.sctypeDict.values(): + scalar_dtype = np.dtype(sctype) + + if scalar_dtype.kind in "Mm": + info = np.iinfo(np.int64) + min_val, max_val = info.min, info.max + elif np.issubdtype(scalar_dtype, np.integer): + info = np.iinfo(sctype) + min_val, max_val = info.min, info.max + elif np.issubdtype(scalar_dtype, np.floating): + info = np.finfo(sctype) + min_val, max_val = info.min, info.max + elif scalar_dtype.kind == "b": + min_val, max_val = 0, 1 + else: + min_val, max_val = None, None + + _minvals[sctype] = min_val + _maxvals[sctype] = max_val + +max_filler = _minvals max_filler.update([(k, -np.inf) for k in float_types_list[:4]]) max_filler.update([(k, complex(-np.inf, -np.inf)) for k in float_types_list[-3:]]) -min_filler = ntypes._maxvals +min_filler = _maxvals min_filler.update([(k, +np.inf) for k in float_types_list[:4]]) min_filler.update([(k, complex(+np.inf, +np.inf)) for k in float_types_list[-3:]]) @@ -282,7 +307,7 @@ def _extremum_fill_value(obj, extremum, extremum_name): def _scalar_fill_value(dtype): try: - return extremum[dtype] + return extremum[dtype.type] except KeyError as e: raise TypeError( f"Unsuitable type {dtype} for calculating {extremum_name}." diff --git a/numpy/typing/tests/data/reveal/numerictypes.pyi b/numpy/typing/tests/data/reveal/numerictypes.pyi index 79c4ef5f26f3..b11d6a8acede 100644 --- a/numpy/typing/tests/data/reveal/numerictypes.pyi +++ b/numpy/typing/tests/data/reveal/numerictypes.pyi @@ -8,10 +8,6 @@ if sys.version_info >= (3, 11): else: from typing_extensions import assert_type -assert_type(np.cast[int], np.core.numerictypes._CastFunc) -assert_type(np.cast["i8"], np.core.numerictypes._CastFunc) -assert_type(np.cast[np.int64], np.core.numerictypes._CastFunc) - assert_type( np.ScalarType, tuple[