""" Due to compatibility, numpy has a very large number of different naming conventions for the scalar types (those subclassing from `numpy.generic`). This file produces a convoluted set of dictionaries mapping names to types, and sometimes other mappings too. .. data:: allTypes A dictionary of names to types that will be exposed as attributes through ``np.core.numerictypes.*`` .. data:: sctypeDict Similar to `allTypes`, but maps a broader set of aliases to their types. .. data:: sctypeNA NumArray-compatible names for the scalar types. Contains not only ``name: type`` mappings, but ``char: name`` mappings too. .. deprecated:: 1.16 .. data:: sctypes A dictionary keyed by a "type group" string, providing a list of types under that group. """ import warnings import sys from numpy.compat import unicode from numpy._globals import VisibleDeprecationWarning from numpy.core._string_helpers import english_lower, english_capitalize from numpy.core.multiarray import typeinfo, dtype from numpy.core._dtype import _kind_name sctypeDict = {} # Contains all leaf-node scalar types with aliases class TypeNADict(dict): def __getitem__(self, key): # 2018-06-24, 1.16 warnings.warn('sctypeNA and typeNA will be removed in v1.18 ' 'of numpy', VisibleDeprecationWarning, stacklevel=2) return dict.__getitem__(self, key) def get(self, key, default=None): # 2018-06-24, 1.16 warnings.warn('sctypeNA and typeNA will be removed in v1.18 ' 'of numpy', VisibleDeprecationWarning, stacklevel=2) return dict.get(self, key, default) sctypeNA = TypeNADict() # Contails all leaf-node types -> numarray type equivalences allTypes = {} # Collect the types we will add to the module # 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(): raise ValueError("Cannot count the bits of an abstract type") # 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 base_capitalize = english_capitalize(base) if base == 'complex': na_name = '%s%d' % (base_capitalize, bit//2) elif base == 'bool': na_name = base_capitalize else: na_name = "%s%d" % (base_capitalize, bit) allTypes[myname] = info.type # add mapping for both the bit name and the numarray name sctypeDict[myname] = info.type sctypeDict[na_name] = info.type # add forward, reverse, and string mapping to numarray sctypeNA[na_name] = info.type sctypeNA[info.type] = na_name sctypeNA[info.char] = na_name sctypeDict[char] = info.type sctypeNA[char] = na_name _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, Intname in [ (i_info,'i%d' % (bits//8,), 'int%d' % bits, 'Int%d' % bits), (u_info,'u%d' % (bits//8,), 'uint%d' % bits, '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[Intname] = info.type sctypeDict[charname] = info.type sctypeNA[Intname] = info.type sctypeNA[charname] = info.type sctypeNA[info.type] = Intname sctypeNA[info.char] = Intname 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 = [('complex_', 'cdouble'), ('int0', 'intp'), ('uint0', 'uintp'), ('single', 'float'), ('csingle', 'cfloat'), ('singlecomplex', 'cfloat'), ('float_', 'double'), ('intc', 'int'), ('uintc', 'uint'), ('int_', 'long'), ('uint', 'ulong'), ('cfloat', 'cdouble'), ('longfloat', 'longdouble'), ('clongfloat', 'clongdouble'), ('longcomplex', 'clongdouble'), ('bool_', 'bool'), ('bytes_', 'string'), ('string_', 'string'), ('unicode_', 'unicode'), ('object_', 'object')] if sys.version_info[0] >= 3: type_pairs.extend([('str_', 'unicode')]) else: type_pairs.extend([('str_', 'string')]) for alias, t in type_pairs: allTypes[alias] = allTypes[t] sctypeDict[alias] = sctypeDict[t] # Remove aliases overriding python types and modules to_remove = ['ulong', 'object', 'int', 'float', 'complex', 'bool', 'string', 'datetime', 'timedelta'] if sys.version_info[0] >= 3: to_remove.extend(['bytes', 'str']) else: to_remove.extend(['unicode', 'long']) for t in to_remove: try: del allTypes[t] del sctypeDict[t] except KeyError: pass _set_up_aliases() sctypes = {'int': [], 'uint':[], 'float':[], 'complex':[], 'others':[bool, object, bytes, unicode, 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', 'complex', 'bool', 'object'] if sys.version_info[0] >= 3: _toadd.extend(['str', 'bytes', ('a', 'bytes_')]) else: _toadd.extend(['string', ('str', 'string_'), 'unicode', ('a', 'string_')]) for name in _toadd: if isinstance(name, tuple): sctypeDict[name[0]] = allTypes[name[1]] else: sctypeDict[name] = allTypes['%s_' % name] del _toadd, name