1import sys 2import itertools 3 4import pytest 5import numpy as np 6from numpy.testing import assert_, assert_equal, assert_raises, IS_PYPY 7 8# This is the structure of the table used for plain objects: 9# 10# +-+-+-+ 11# |x|y|z| 12# +-+-+-+ 13 14# Structure of a plain array description: 15Pdescr = [ 16 ('x', 'i4', (2,)), 17 ('y', 'f8', (2, 2)), 18 ('z', 'u1')] 19 20# A plain list of tuples with values for testing: 21PbufferT = [ 22 # x y z 23 ([3, 2], [[6., 4.], [6., 4.]], 8), 24 ([4, 3], [[7., 5.], [7., 5.]], 9), 25 ] 26 27 28# This is the structure of the table used for nested objects (DON'T PANIC!): 29# 30# +-+---------------------------------+-----+----------+-+-+ 31# |x|Info |color|info |y|z| 32# | +-----+--+----------------+----+--+ +----+-----+ | | 33# | |value|y2|Info2 |name|z2| |Name|Value| | | 34# | | | +----+-----+--+--+ | | | | | | | 35# | | | |name|value|y3|z3| | | | | | | | 36# +-+-----+--+----+-----+--+--+----+--+-----+----+-----+-+-+ 37# 38 39# The corresponding nested array description: 40Ndescr = [ 41 ('x', 'i4', (2,)), 42 ('Info', [ 43 ('value', 'c16'), 44 ('y2', 'f8'), 45 ('Info2', [ 46 ('name', 'S2'), 47 ('value', 'c16', (2,)), 48 ('y3', 'f8', (2,)), 49 ('z3', 'u4', (2,))]), 50 ('name', 'S2'), 51 ('z2', 'b1')]), 52 ('color', 'S2'), 53 ('info', [ 54 ('Name', 'U8'), 55 ('Value', 'c16')]), 56 ('y', 'f8', (2, 2)), 57 ('z', 'u1')] 58 59NbufferT = [ 60 # x Info color info y z 61 # value y2 Info2 name z2 Name Value 62 # name value y3 z3 63 ([3, 2], (6j, 6., (b'nn', [6j, 4j], [6., 4.], [1, 2]), b'NN', True), b'cc', (u'NN', 6j), [[6., 4.], [6., 4.]], 8), 64 ([4, 3], (7j, 7., (b'oo', [7j, 5j], [7., 5.], [2, 1]), b'OO', False), b'dd', (u'OO', 7j), [[7., 5.], [7., 5.]], 9), 65 ] 66 67 68byteorder = {'little':'<', 'big':'>'}[sys.byteorder] 69 70def normalize_descr(descr): 71 "Normalize a description adding the platform byteorder." 72 73 out = [] 74 for item in descr: 75 dtype = item[1] 76 if isinstance(dtype, str): 77 if dtype[0] not in ['|', '<', '>']: 78 onebyte = dtype[1:] == "1" 79 if onebyte or dtype[0] in ['S', 'V', 'b']: 80 dtype = "|" + dtype 81 else: 82 dtype = byteorder + dtype 83 if len(item) > 2 and np.prod(item[2]) > 1: 84 nitem = (item[0], dtype, item[2]) 85 else: 86 nitem = (item[0], dtype) 87 out.append(nitem) 88 elif isinstance(dtype, list): 89 l = normalize_descr(dtype) 90 out.append((item[0], l)) 91 else: 92 raise ValueError("Expected a str or list and got %s" % 93 (type(item))) 94 return out 95 96 97############################################################ 98# Creation tests 99############################################################ 100 101class CreateZeros: 102 """Check the creation of heterogeneous arrays zero-valued""" 103 104 def test_zeros0D(self): 105 """Check creation of 0-dimensional objects""" 106 h = np.zeros((), dtype=self._descr) 107 assert_(normalize_descr(self._descr) == h.dtype.descr) 108 assert_(h.dtype.fields['x'][0].name[:4] == 'void') 109 assert_(h.dtype.fields['x'][0].char == 'V') 110 assert_(h.dtype.fields['x'][0].type == np.void) 111 # A small check that data is ok 112 assert_equal(h['z'], np.zeros((), dtype='u1')) 113 114 def test_zerosSD(self): 115 """Check creation of single-dimensional objects""" 116 h = np.zeros((2,), dtype=self._descr) 117 assert_(normalize_descr(self._descr) == h.dtype.descr) 118 assert_(h.dtype['y'].name[:4] == 'void') 119 assert_(h.dtype['y'].char == 'V') 120 assert_(h.dtype['y'].type == np.void) 121 # A small check that data is ok 122 assert_equal(h['z'], np.zeros((2,), dtype='u1')) 123 124 def test_zerosMD(self): 125 """Check creation of multi-dimensional objects""" 126 h = np.zeros((2, 3), dtype=self._descr) 127 assert_(normalize_descr(self._descr) == h.dtype.descr) 128 assert_(h.dtype['z'].name == 'uint8') 129 assert_(h.dtype['z'].char == 'B') 130 assert_(h.dtype['z'].type == np.uint8) 131 # A small check that data is ok 132 assert_equal(h['z'], np.zeros((2, 3), dtype='u1')) 133 134 135class TestCreateZerosPlain(CreateZeros): 136 """Check the creation of heterogeneous arrays zero-valued (plain)""" 137 _descr = Pdescr 138 139class TestCreateZerosNested(CreateZeros): 140 """Check the creation of heterogeneous arrays zero-valued (nested)""" 141 _descr = Ndescr 142 143 144class CreateValues: 145 """Check the creation of heterogeneous arrays with values""" 146 147 def test_tuple(self): 148 """Check creation from tuples""" 149 h = np.array(self._buffer, dtype=self._descr) 150 assert_(normalize_descr(self._descr) == h.dtype.descr) 151 if self.multiple_rows: 152 assert_(h.shape == (2,)) 153 else: 154 assert_(h.shape == ()) 155 156 def test_list_of_tuple(self): 157 """Check creation from list of tuples""" 158 h = np.array([self._buffer], dtype=self._descr) 159 assert_(normalize_descr(self._descr) == h.dtype.descr) 160 if self.multiple_rows: 161 assert_(h.shape == (1, 2)) 162 else: 163 assert_(h.shape == (1,)) 164 165 def test_list_of_list_of_tuple(self): 166 """Check creation from list of list of tuples""" 167 h = np.array([[self._buffer]], dtype=self._descr) 168 assert_(normalize_descr(self._descr) == h.dtype.descr) 169 if self.multiple_rows: 170 assert_(h.shape == (1, 1, 2)) 171 else: 172 assert_(h.shape == (1, 1)) 173 174 175class TestCreateValuesPlainSingle(CreateValues): 176 """Check the creation of heterogeneous arrays (plain, single row)""" 177 _descr = Pdescr 178 multiple_rows = 0 179 _buffer = PbufferT[0] 180 181class TestCreateValuesPlainMultiple(CreateValues): 182 """Check the creation of heterogeneous arrays (plain, multiple rows)""" 183 _descr = Pdescr 184 multiple_rows = 1 185 _buffer = PbufferT 186 187class TestCreateValuesNestedSingle(CreateValues): 188 """Check the creation of heterogeneous arrays (nested, single row)""" 189 _descr = Ndescr 190 multiple_rows = 0 191 _buffer = NbufferT[0] 192 193class TestCreateValuesNestedMultiple(CreateValues): 194 """Check the creation of heterogeneous arrays (nested, multiple rows)""" 195 _descr = Ndescr 196 multiple_rows = 1 197 _buffer = NbufferT 198 199 200############################################################ 201# Reading tests 202############################################################ 203 204class ReadValuesPlain: 205 """Check the reading of values in heterogeneous arrays (plain)""" 206 207 def test_access_fields(self): 208 h = np.array(self._buffer, dtype=self._descr) 209 if not self.multiple_rows: 210 assert_(h.shape == ()) 211 assert_equal(h['x'], np.array(self._buffer[0], dtype='i4')) 212 assert_equal(h['y'], np.array(self._buffer[1], dtype='f8')) 213 assert_equal(h['z'], np.array(self._buffer[2], dtype='u1')) 214 else: 215 assert_(len(h) == 2) 216 assert_equal(h['x'], np.array([self._buffer[0][0], 217 self._buffer[1][0]], dtype='i4')) 218 assert_equal(h['y'], np.array([self._buffer[0][1], 219 self._buffer[1][1]], dtype='f8')) 220 assert_equal(h['z'], np.array([self._buffer[0][2], 221 self._buffer[1][2]], dtype='u1')) 222 223 224class TestReadValuesPlainSingle(ReadValuesPlain): 225 """Check the creation of heterogeneous arrays (plain, single row)""" 226 _descr = Pdescr 227 multiple_rows = 0 228 _buffer = PbufferT[0] 229 230class TestReadValuesPlainMultiple(ReadValuesPlain): 231 """Check the values of heterogeneous arrays (plain, multiple rows)""" 232 _descr = Pdescr 233 multiple_rows = 1 234 _buffer = PbufferT 235 236class ReadValuesNested: 237 """Check the reading of values in heterogeneous arrays (nested)""" 238 239 def test_access_top_fields(self): 240 """Check reading the top fields of a nested array""" 241 h = np.array(self._buffer, dtype=self._descr) 242 if not self.multiple_rows: 243 assert_(h.shape == ()) 244 assert_equal(h['x'], np.array(self._buffer[0], dtype='i4')) 245 assert_equal(h['y'], np.array(self._buffer[4], dtype='f8')) 246 assert_equal(h['z'], np.array(self._buffer[5], dtype='u1')) 247 else: 248 assert_(len(h) == 2) 249 assert_equal(h['x'], np.array([self._buffer[0][0], 250 self._buffer[1][0]], dtype='i4')) 251 assert_equal(h['y'], np.array([self._buffer[0][4], 252 self._buffer[1][4]], dtype='f8')) 253 assert_equal(h['z'], np.array([self._buffer[0][5], 254 self._buffer[1][5]], dtype='u1')) 255 256 def test_nested1_acessors(self): 257 """Check reading the nested fields of a nested array (1st level)""" 258 h = np.array(self._buffer, dtype=self._descr) 259 if not self.multiple_rows: 260 assert_equal(h['Info']['value'], 261 np.array(self._buffer[1][0], dtype='c16')) 262 assert_equal(h['Info']['y2'], 263 np.array(self._buffer[1][1], dtype='f8')) 264 assert_equal(h['info']['Name'], 265 np.array(self._buffer[3][0], dtype='U2')) 266 assert_equal(h['info']['Value'], 267 np.array(self._buffer[3][1], dtype='c16')) 268 else: 269 assert_equal(h['Info']['value'], 270 np.array([self._buffer[0][1][0], 271 self._buffer[1][1][0]], 272 dtype='c16')) 273 assert_equal(h['Info']['y2'], 274 np.array([self._buffer[0][1][1], 275 self._buffer[1][1][1]], 276 dtype='f8')) 277 assert_equal(h['info']['Name'], 278 np.array([self._buffer[0][3][0], 279 self._buffer[1][3][0]], 280 dtype='U2')) 281 assert_equal(h['info']['Value'], 282 np.array([self._buffer[0][3][1], 283 self._buffer[1][3][1]], 284 dtype='c16')) 285 286 def test_nested2_acessors(self): 287 """Check reading the nested fields of a nested array (2nd level)""" 288 h = np.array(self._buffer, dtype=self._descr) 289 if not self.multiple_rows: 290 assert_equal(h['Info']['Info2']['value'], 291 np.array(self._buffer[1][2][1], dtype='c16')) 292 assert_equal(h['Info']['Info2']['z3'], 293 np.array(self._buffer[1][2][3], dtype='u4')) 294 else: 295 assert_equal(h['Info']['Info2']['value'], 296 np.array([self._buffer[0][1][2][1], 297 self._buffer[1][1][2][1]], 298 dtype='c16')) 299 assert_equal(h['Info']['Info2']['z3'], 300 np.array([self._buffer[0][1][2][3], 301 self._buffer[1][1][2][3]], 302 dtype='u4')) 303 304 def test_nested1_descriptor(self): 305 """Check access nested descriptors of a nested array (1st level)""" 306 h = np.array(self._buffer, dtype=self._descr) 307 assert_(h.dtype['Info']['value'].name == 'complex128') 308 assert_(h.dtype['Info']['y2'].name == 'float64') 309 assert_(h.dtype['info']['Name'].name == 'str256') 310 assert_(h.dtype['info']['Value'].name == 'complex128') 311 312 def test_nested2_descriptor(self): 313 """Check access nested descriptors of a nested array (2nd level)""" 314 h = np.array(self._buffer, dtype=self._descr) 315 assert_(h.dtype['Info']['Info2']['value'].name == 'void256') 316 assert_(h.dtype['Info']['Info2']['z3'].name == 'void64') 317 318 319class TestReadValuesNestedSingle(ReadValuesNested): 320 """Check the values of heterogeneous arrays (nested, single row)""" 321 _descr = Ndescr 322 multiple_rows = False 323 _buffer = NbufferT[0] 324 325class TestReadValuesNestedMultiple(ReadValuesNested): 326 """Check the values of heterogeneous arrays (nested, multiple rows)""" 327 _descr = Ndescr 328 multiple_rows = True 329 _buffer = NbufferT 330 331class TestEmptyField: 332 def test_assign(self): 333 a = np.arange(10, dtype=np.float32) 334 a.dtype = [("int", "<0i4"), ("float", "<2f4")] 335 assert_(a['int'].shape == (5, 0)) 336 assert_(a['float'].shape == (5, 2)) 337 338class TestCommonType: 339 def test_scalar_loses1(self): 340 res = np.find_common_type(['f4', 'f4', 'i2'], ['f8']) 341 assert_(res == 'f4') 342 343 def test_scalar_loses2(self): 344 res = np.find_common_type(['f4', 'f4'], ['i8']) 345 assert_(res == 'f4') 346 347 def test_scalar_wins(self): 348 res = np.find_common_type(['f4', 'f4', 'i2'], ['c8']) 349 assert_(res == 'c8') 350 351 def test_scalar_wins2(self): 352 res = np.find_common_type(['u4', 'i4', 'i4'], ['f4']) 353 assert_(res == 'f8') 354 355 def test_scalar_wins3(self): # doesn't go up to 'f16' on purpose 356 res = np.find_common_type(['u8', 'i8', 'i8'], ['f8']) 357 assert_(res == 'f8') 358 359class TestMultipleFields: 360 def setup(self): 361 self.ary = np.array([(1, 2, 3, 4), (5, 6, 7, 8)], dtype='i4,f4,i2,c8') 362 363 def _bad_call(self): 364 return self.ary['f0', 'f1'] 365 366 def test_no_tuple(self): 367 assert_raises(IndexError, self._bad_call) 368 369 def test_return(self): 370 res = self.ary[['f0', 'f2']].tolist() 371 assert_(res == [(1, 3), (5, 7)]) 372 373 374class TestIsSubDType: 375 # scalar types can be promoted into dtypes 376 wrappers = [np.dtype, lambda x: x] 377 378 def test_both_abstract(self): 379 assert_(np.issubdtype(np.floating, np.inexact)) 380 assert_(not np.issubdtype(np.inexact, np.floating)) 381 382 def test_same(self): 383 for cls in (np.float32, np.int32): 384 for w1, w2 in itertools.product(self.wrappers, repeat=2): 385 assert_(np.issubdtype(w1(cls), w2(cls))) 386 387 def test_subclass(self): 388 # note we cannot promote floating to a dtype, as it would turn into a 389 # concrete type 390 for w in self.wrappers: 391 assert_(np.issubdtype(w(np.float32), np.floating)) 392 assert_(np.issubdtype(w(np.float64), np.floating)) 393 394 def test_subclass_backwards(self): 395 for w in self.wrappers: 396 assert_(not np.issubdtype(np.floating, w(np.float32))) 397 assert_(not np.issubdtype(np.floating, w(np.float64))) 398 399 def test_sibling_class(self): 400 for w1, w2 in itertools.product(self.wrappers, repeat=2): 401 assert_(not np.issubdtype(w1(np.float32), w2(np.float64))) 402 assert_(not np.issubdtype(w1(np.float64), w2(np.float32))) 403 404 def test_nondtype_nonscalartype(self): 405 # See gh-14619 and gh-9505 which introduced the deprecation to fix 406 # this. These tests are directly taken from gh-9505 407 assert not np.issubdtype(np.float32, 'float64') 408 assert not np.issubdtype(np.float32, 'f8') 409 assert not np.issubdtype(np.int32, str) 410 assert not np.issubdtype(np.int32, 'int64') 411 assert not np.issubdtype(np.str_, 'void') 412 # for the following the correct spellings are 413 # np.integer, np.floating, or np.complexfloating respectively: 414 assert not np.issubdtype(np.int8, int) # np.int8 is never np.int_ 415 assert not np.issubdtype(np.float32, float) 416 assert not np.issubdtype(np.complex64, complex) 417 assert not np.issubdtype(np.float32, "float") 418 assert not np.issubdtype(np.float64, "f") 419 420 # Test the same for the correct first datatype and abstract one 421 # in the case of int, float, complex: 422 assert np.issubdtype(np.float64, 'float64') 423 assert np.issubdtype(np.float64, 'f8') 424 assert np.issubdtype(np.str_, str) 425 assert np.issubdtype(np.int64, 'int64') 426 assert np.issubdtype(np.void, 'void') 427 assert np.issubdtype(np.int8, np.integer) 428 assert np.issubdtype(np.float32, np.floating) 429 assert np.issubdtype(np.complex64, np.complexfloating) 430 assert np.issubdtype(np.float64, "float") 431 assert np.issubdtype(np.float32, "f") 432 433 434class TestSctypeDict: 435 def test_longdouble(self): 436 assert_(np.sctypeDict['f8'] is not np.longdouble) 437 assert_(np.sctypeDict['c16'] is not np.clongdouble) 438 439 440class TestBitName: 441 def test_abstract(self): 442 assert_raises(ValueError, np.core.numerictypes.bitname, np.floating) 443 444 445class TestMaximumSctype: 446 447 # note that parametrizing with sctype['int'] and similar would skip types 448 # with the same size (gh-11923) 449 450 @pytest.mark.parametrize('t', [np.byte, np.short, np.intc, np.int_, np.longlong]) 451 def test_int(self, t): 452 assert_equal(np.maximum_sctype(t), np.sctypes['int'][-1]) 453 454 @pytest.mark.parametrize('t', [np.ubyte, np.ushort, np.uintc, np.uint, np.ulonglong]) 455 def test_uint(self, t): 456 assert_equal(np.maximum_sctype(t), np.sctypes['uint'][-1]) 457 458 @pytest.mark.parametrize('t', [np.half, np.single, np.double, np.longdouble]) 459 def test_float(self, t): 460 assert_equal(np.maximum_sctype(t), np.sctypes['float'][-1]) 461 462 @pytest.mark.parametrize('t', [np.csingle, np.cdouble, np.clongdouble]) 463 def test_complex(self, t): 464 assert_equal(np.maximum_sctype(t), np.sctypes['complex'][-1]) 465 466 @pytest.mark.parametrize('t', [np.bool_, np.object_, np.unicode_, np.bytes_, np.void]) 467 def test_other(self, t): 468 assert_equal(np.maximum_sctype(t), t) 469 470 471class Test_sctype2char: 472 # This function is old enough that we're really just documenting the quirks 473 # at this point. 474 475 def test_scalar_type(self): 476 assert_equal(np.sctype2char(np.double), 'd') 477 assert_equal(np.sctype2char(np.int_), 'l') 478 assert_equal(np.sctype2char(np.unicode_), 'U') 479 assert_equal(np.sctype2char(np.bytes_), 'S') 480 481 def test_other_type(self): 482 assert_equal(np.sctype2char(float), 'd') 483 assert_equal(np.sctype2char(list), 'O') 484 assert_equal(np.sctype2char(np.ndarray), 'O') 485 486 def test_third_party_scalar_type(self): 487 from numpy.core._rational_tests import rational 488 assert_raises(KeyError, np.sctype2char, rational) 489 assert_raises(KeyError, np.sctype2char, rational(1)) 490 491 def test_array_instance(self): 492 assert_equal(np.sctype2char(np.array([1.0, 2.0])), 'd') 493 494 def test_abstract_type(self): 495 assert_raises(KeyError, np.sctype2char, np.floating) 496 497 def test_non_type(self): 498 assert_raises(ValueError, np.sctype2char, 1) 499 500@pytest.mark.parametrize("rep, expected", [ 501 (np.int32, True), 502 (list, False), 503 (1.1, False), 504 (str, True), 505 (np.dtype(np.float64), True), 506 (np.dtype((np.int16, (3, 4))), True), 507 (np.dtype([('a', np.int8)]), True), 508 ]) 509def test_issctype(rep, expected): 510 # ensure proper identification of scalar 511 # data-types by issctype() 512 actual = np.issctype(rep) 513 assert_equal(actual, expected) 514 515 516@pytest.mark.skipif(sys.flags.optimize > 1, 517 reason="no docstrings present to inspect when PYTHONOPTIMIZE/Py_OptimizeFlag > 1") 518@pytest.mark.xfail(IS_PYPY, 519 reason="PyPy cannot modify tp_doc after PyType_Ready") 520class TestDocStrings: 521 def test_platform_dependent_aliases(self): 522 if np.int64 is np.int_: 523 assert_('int64' in np.int_.__doc__) 524 elif np.int64 is np.longlong: 525 assert_('int64' in np.longlong.__doc__) 526 527 528class TestScalarTypeNames: 529 # gh-9799 530 531 numeric_types = [ 532 np.byte, np.short, np.intc, np.int_, np.longlong, 533 np.ubyte, np.ushort, np.uintc, np.uint, np.ulonglong, 534 np.half, np.single, np.double, np.longdouble, 535 np.csingle, np.cdouble, np.clongdouble, 536 ] 537 538 def test_names_are_unique(self): 539 # none of the above may be aliases for each other 540 assert len(set(self.numeric_types)) == len(self.numeric_types) 541 542 # names must be unique 543 names = [t.__name__ for t in self.numeric_types] 544 assert len(set(names)) == len(names) 545 546 @pytest.mark.parametrize('t', numeric_types) 547 def test_names_reflect_attributes(self, t): 548 """ Test that names correspond to where the type is under ``np.`` """ 549 assert getattr(np, t.__name__) is t 550 551 @pytest.mark.parametrize('t', numeric_types) 552 def test_names_are_undersood_by_dtype(self, t): 553 """ Test the dtype constructor maps names back to the type """ 554 assert np.dtype(t.__name__).type is t 555