1# 2# The ndarray object from _testbuffer.c is a complete implementation of 3# a PEP-3118 buffer provider. It is independent from NumPy's ndarray 4# and the tests don't require NumPy. 5# 6# If NumPy is present, some tests check both ndarray implementations 7# against each other. 8# 9# Most ndarray tests also check that memoryview(ndarray) behaves in 10# the same way as the original. Thus, a substantial part of the 11# memoryview tests is now in this module. 12# 13# Written and designed by Stefan Krah for Python 3.3. 14# 15 16import contextlib 17import unittest 18from test import support 19from test.support import os_helper 20import inspect 21from itertools import permutations, product 22from random import randrange, sample, choice 23import warnings 24import sys, array, io, os 25from decimal import Decimal 26from fractions import Fraction 27from test.support import warnings_helper 28 29try: 30 from _testbuffer import * 31except ImportError: 32 ndarray = None 33 34try: 35 import struct 36except ImportError: 37 struct = None 38 39try: 40 import ctypes 41except ImportError: 42 ctypes = None 43 44try: 45 with os_helper.EnvironmentVarGuard() as os.environ, \ 46 warnings.catch_warnings(): 47 from numpy import ndarray as numpy_array 48except ImportError: 49 numpy_array = None 50 51try: 52 import _testcapi 53except ImportError: 54 _testcapi = None 55 56 57SHORT_TEST = True 58 59 60# ====================================================================== 61# Random lists by format specifier 62# ====================================================================== 63 64# Native format chars and their ranges. 65NATIVE = { 66 '?':0, 'c':0, 'b':0, 'B':0, 67 'h':0, 'H':0, 'i':0, 'I':0, 68 'l':0, 'L':0, 'n':0, 'N':0, 69 'e':0, 'f':0, 'd':0, 'P':0 70} 71 72# NumPy does not have 'n' or 'N': 73if numpy_array: 74 del NATIVE['n'] 75 del NATIVE['N'] 76 77if struct: 78 try: 79 # Add "qQ" if present in native mode. 80 struct.pack('Q', 2**64-1) 81 NATIVE['q'] = 0 82 NATIVE['Q'] = 0 83 except struct.error: 84 pass 85 86# Standard format chars and their ranges. 87STANDARD = { 88 '?':(0, 2), 'c':(0, 1<<8), 89 'b':(-(1<<7), 1<<7), 'B':(0, 1<<8), 90 'h':(-(1<<15), 1<<15), 'H':(0, 1<<16), 91 'i':(-(1<<31), 1<<31), 'I':(0, 1<<32), 92 'l':(-(1<<31), 1<<31), 'L':(0, 1<<32), 93 'q':(-(1<<63), 1<<63), 'Q':(0, 1<<64), 94 'e':(-65519, 65520), 'f':(-(1<<63), 1<<63), 95 'd':(-(1<<1023), 1<<1023) 96} 97 98def native_type_range(fmt): 99 """Return range of a native type.""" 100 if fmt == 'c': 101 lh = (0, 256) 102 elif fmt == '?': 103 lh = (0, 2) 104 elif fmt == 'e': 105 lh = (-65519, 65520) 106 elif fmt == 'f': 107 lh = (-(1<<63), 1<<63) 108 elif fmt == 'd': 109 lh = (-(1<<1023), 1<<1023) 110 else: 111 for exp in (128, 127, 64, 63, 32, 31, 16, 15, 8, 7): 112 try: 113 struct.pack(fmt, (1<<exp)-1) 114 break 115 except struct.error: 116 pass 117 lh = (-(1<<exp), 1<<exp) if exp & 1 else (0, 1<<exp) 118 return lh 119 120fmtdict = { 121 '':NATIVE, 122 '@':NATIVE, 123 '<':STANDARD, 124 '>':STANDARD, 125 '=':STANDARD, 126 '!':STANDARD 127} 128 129if struct: 130 for fmt in fmtdict['@']: 131 fmtdict['@'][fmt] = native_type_range(fmt) 132 133# Format codes suppported by the memoryview object 134MEMORYVIEW = NATIVE.copy() 135 136# Format codes suppported by array.array 137ARRAY = NATIVE.copy() 138for k in NATIVE: 139 if not k in "bBhHiIlLfd": 140 del ARRAY[k] 141 142BYTEFMT = NATIVE.copy() 143for k in NATIVE: 144 if not k in "Bbc": 145 del BYTEFMT[k] 146 147fmtdict['m'] = MEMORYVIEW 148fmtdict['@m'] = MEMORYVIEW 149fmtdict['a'] = ARRAY 150fmtdict['b'] = BYTEFMT 151fmtdict['@b'] = BYTEFMT 152 153# Capabilities of the test objects: 154MODE = 0 155MULT = 1 156cap = { # format chars # multiplier 157 'ndarray': (['', '@', '<', '>', '=', '!'], ['', '1', '2', '3']), 158 'array': (['a'], ['']), 159 'numpy': ([''], ['']), 160 'memoryview': (['@m', 'm'], ['']), 161 'bytefmt': (['@b', 'b'], ['']), 162} 163 164def randrange_fmt(mode, char, obj): 165 """Return random item for a type specified by a mode and a single 166 format character.""" 167 x = randrange(*fmtdict[mode][char]) 168 if char == 'c': 169 x = bytes([x]) 170 if obj == 'numpy' and x == b'\x00': 171 # http://projects.scipy.org/numpy/ticket/1925 172 x = b'\x01' 173 if char == '?': 174 x = bool(x) 175 if char in 'efd': 176 x = struct.pack(char, x) 177 x = struct.unpack(char, x)[0] 178 return x 179 180def gen_item(fmt, obj): 181 """Return single random item.""" 182 mode, chars = fmt.split('#') 183 x = [] 184 for c in chars: 185 x.append(randrange_fmt(mode, c, obj)) 186 return x[0] if len(x) == 1 else tuple(x) 187 188def gen_items(n, fmt, obj): 189 """Return a list of random items (or a scalar).""" 190 if n == 0: 191 return gen_item(fmt, obj) 192 lst = [0] * n 193 for i in range(n): 194 lst[i] = gen_item(fmt, obj) 195 return lst 196 197def struct_items(n, obj): 198 mode = choice(cap[obj][MODE]) 199 xfmt = mode + '#' 200 fmt = mode.strip('amb') 201 nmemb = randrange(2, 10) # number of struct members 202 for _ in range(nmemb): 203 char = choice(tuple(fmtdict[mode])) 204 multiplier = choice(cap[obj][MULT]) 205 xfmt += (char * int(multiplier if multiplier else 1)) 206 fmt += (multiplier + char) 207 items = gen_items(n, xfmt, obj) 208 item = gen_item(xfmt, obj) 209 return fmt, items, item 210 211def randitems(n, obj='ndarray', mode=None, char=None): 212 """Return random format, items, item.""" 213 if mode is None: 214 mode = choice(cap[obj][MODE]) 215 if char is None: 216 char = choice(tuple(fmtdict[mode])) 217 multiplier = choice(cap[obj][MULT]) 218 fmt = mode + '#' + char * int(multiplier if multiplier else 1) 219 items = gen_items(n, fmt, obj) 220 item = gen_item(fmt, obj) 221 fmt = mode.strip('amb') + multiplier + char 222 return fmt, items, item 223 224def iter_mode(n, obj='ndarray'): 225 """Iterate through supported mode/char combinations.""" 226 for mode in cap[obj][MODE]: 227 for char in fmtdict[mode]: 228 yield randitems(n, obj, mode, char) 229 230def iter_format(nitems, testobj='ndarray'): 231 """Yield (format, items, item) for all possible modes and format 232 characters plus one random compound format string.""" 233 for t in iter_mode(nitems, testobj): 234 yield t 235 if testobj != 'ndarray': 236 return 237 yield struct_items(nitems, testobj) 238 239 240def is_byte_format(fmt): 241 return 'c' in fmt or 'b' in fmt or 'B' in fmt 242 243def is_memoryview_format(fmt): 244 """format suitable for memoryview""" 245 x = len(fmt) 246 return ((x == 1 or (x == 2 and fmt[0] == '@')) and 247 fmt[x-1] in MEMORYVIEW) 248 249NON_BYTE_FORMAT = [c for c in fmtdict['@'] if not is_byte_format(c)] 250 251 252# ====================================================================== 253# Multi-dimensional tolist(), slicing and slice assignments 254# ====================================================================== 255 256def atomp(lst): 257 """Tuple items (representing structs) are regarded as atoms.""" 258 return not isinstance(lst, list) 259 260def listp(lst): 261 return isinstance(lst, list) 262 263def prod(lst): 264 """Product of list elements.""" 265 if len(lst) == 0: 266 return 0 267 x = lst[0] 268 for v in lst[1:]: 269 x *= v 270 return x 271 272def strides_from_shape(ndim, shape, itemsize, layout): 273 """Calculate strides of a contiguous array. Layout is 'C' or 274 'F' (Fortran).""" 275 if ndim == 0: 276 return () 277 if layout == 'C': 278 strides = list(shape[1:]) + [itemsize] 279 for i in range(ndim-2, -1, -1): 280 strides[i] *= strides[i+1] 281 else: 282 strides = [itemsize] + list(shape[:-1]) 283 for i in range(1, ndim): 284 strides[i] *= strides[i-1] 285 return strides 286 287def _ca(items, s): 288 """Convert flat item list to the nested list representation of a 289 multidimensional C array with shape 's'.""" 290 if atomp(items): 291 return items 292 if len(s) == 0: 293 return items[0] 294 lst = [0] * s[0] 295 stride = len(items) // s[0] if s[0] else 0 296 for i in range(s[0]): 297 start = i*stride 298 lst[i] = _ca(items[start:start+stride], s[1:]) 299 return lst 300 301def _fa(items, s): 302 """Convert flat item list to the nested list representation of a 303 multidimensional Fortran array with shape 's'.""" 304 if atomp(items): 305 return items 306 if len(s) == 0: 307 return items[0] 308 lst = [0] * s[0] 309 stride = s[0] 310 for i in range(s[0]): 311 lst[i] = _fa(items[i::stride], s[1:]) 312 return lst 313 314def carray(items, shape): 315 if listp(items) and not 0 in shape and prod(shape) != len(items): 316 raise ValueError("prod(shape) != len(items)") 317 return _ca(items, shape) 318 319def farray(items, shape): 320 if listp(items) and not 0 in shape and prod(shape) != len(items): 321 raise ValueError("prod(shape) != len(items)") 322 return _fa(items, shape) 323 324def indices(shape): 325 """Generate all possible tuples of indices.""" 326 iterables = [range(v) for v in shape] 327 return product(*iterables) 328 329def getindex(ndim, ind, strides): 330 """Convert multi-dimensional index to the position in the flat list.""" 331 ret = 0 332 for i in range(ndim): 333 ret += strides[i] * ind[i] 334 return ret 335 336def transpose(src, shape): 337 """Transpose flat item list that is regarded as a multi-dimensional 338 matrix defined by shape: dest...[k][j][i] = src[i][j][k]... """ 339 if not shape: 340 return src 341 ndim = len(shape) 342 sstrides = strides_from_shape(ndim, shape, 1, 'C') 343 dstrides = strides_from_shape(ndim, shape[::-1], 1, 'C') 344 dest = [0] * len(src) 345 for ind in indices(shape): 346 fr = getindex(ndim, ind, sstrides) 347 to = getindex(ndim, ind[::-1], dstrides) 348 dest[to] = src[fr] 349 return dest 350 351def _flatten(lst): 352 """flatten list""" 353 if lst == []: 354 return lst 355 if atomp(lst): 356 return [lst] 357 return _flatten(lst[0]) + _flatten(lst[1:]) 358 359def flatten(lst): 360 """flatten list or return scalar""" 361 if atomp(lst): # scalar 362 return lst 363 return _flatten(lst) 364 365def slice_shape(lst, slices): 366 """Get the shape of lst after slicing: slices is a list of slice 367 objects.""" 368 if atomp(lst): 369 return [] 370 return [len(lst[slices[0]])] + slice_shape(lst[0], slices[1:]) 371 372def multislice(lst, slices): 373 """Multi-dimensional slicing: slices is a list of slice objects.""" 374 if atomp(lst): 375 return lst 376 return [multislice(sublst, slices[1:]) for sublst in lst[slices[0]]] 377 378def m_assign(llst, rlst, lslices, rslices): 379 """Multi-dimensional slice assignment: llst and rlst are the operands, 380 lslices and rslices are lists of slice objects. llst and rlst must 381 have the same structure. 382 383 For a two-dimensional example, this is not implemented in Python: 384 385 llst[0:3:2, 0:3:2] = rlst[1:3:1, 1:3:1] 386 387 Instead we write: 388 389 lslices = [slice(0,3,2), slice(0,3,2)] 390 rslices = [slice(1,3,1), slice(1,3,1)] 391 multislice_assign(llst, rlst, lslices, rslices) 392 """ 393 if atomp(rlst): 394 return rlst 395 rlst = [m_assign(l, r, lslices[1:], rslices[1:]) 396 for l, r in zip(llst[lslices[0]], rlst[rslices[0]])] 397 llst[lslices[0]] = rlst 398 return llst 399 400def cmp_structure(llst, rlst, lslices, rslices): 401 """Compare the structure of llst[lslices] and rlst[rslices].""" 402 lshape = slice_shape(llst, lslices) 403 rshape = slice_shape(rlst, rslices) 404 if (len(lshape) != len(rshape)): 405 return -1 406 for i in range(len(lshape)): 407 if lshape[i] != rshape[i]: 408 return -1 409 if lshape[i] == 0: 410 return 0 411 return 0 412 413def multislice_assign(llst, rlst, lslices, rslices): 414 """Return llst after assigning: llst[lslices] = rlst[rslices]""" 415 if cmp_structure(llst, rlst, lslices, rslices) < 0: 416 raise ValueError("lvalue and rvalue have different structures") 417 return m_assign(llst, rlst, lslices, rslices) 418 419 420# ====================================================================== 421# Random structures 422# ====================================================================== 423 424# 425# PEP-3118 is very permissive with respect to the contents of a 426# Py_buffer. In particular: 427# 428# - shape can be zero 429# - strides can be any integer, including zero 430# - offset can point to any location in the underlying 431# memory block, provided that it is a multiple of 432# itemsize. 433# 434# The functions in this section test and verify random structures 435# in full generality. A structure is valid iff it fits in the 436# underlying memory block. 437# 438# The structure 't' (short for 'tuple') is fully defined by: 439# 440# t = (memlen, itemsize, ndim, shape, strides, offset) 441# 442 443def verify_structure(memlen, itemsize, ndim, shape, strides, offset): 444 """Verify that the parameters represent a valid array within 445 the bounds of the allocated memory: 446 char *mem: start of the physical memory block 447 memlen: length of the physical memory block 448 offset: (char *)buf - mem 449 """ 450 if offset % itemsize: 451 return False 452 if offset < 0 or offset+itemsize > memlen: 453 return False 454 if any(v % itemsize for v in strides): 455 return False 456 457 if ndim <= 0: 458 return ndim == 0 and not shape and not strides 459 if 0 in shape: 460 return True 461 462 imin = sum(strides[j]*(shape[j]-1) for j in range(ndim) 463 if strides[j] <= 0) 464 imax = sum(strides[j]*(shape[j]-1) for j in range(ndim) 465 if strides[j] > 0) 466 467 return 0 <= offset+imin and offset+imax+itemsize <= memlen 468 469def get_item(lst, indices): 470 for i in indices: 471 lst = lst[i] 472 return lst 473 474def memory_index(indices, t): 475 """Location of an item in the underlying memory.""" 476 memlen, itemsize, ndim, shape, strides, offset = t 477 p = offset 478 for i in range(ndim): 479 p += strides[i]*indices[i] 480 return p 481 482def is_overlapping(t): 483 """The structure 't' is overlapping if at least one memory location 484 is visited twice while iterating through all possible tuples of 485 indices.""" 486 memlen, itemsize, ndim, shape, strides, offset = t 487 visited = 1<<memlen 488 for ind in indices(shape): 489 i = memory_index(ind, t) 490 bit = 1<<i 491 if visited & bit: 492 return True 493 visited |= bit 494 return False 495 496def rand_structure(itemsize, valid, maxdim=5, maxshape=16, shape=()): 497 """Return random structure: 498 (memlen, itemsize, ndim, shape, strides, offset) 499 If 'valid' is true, the returned structure is valid, otherwise invalid. 500 If 'shape' is given, use that instead of creating a random shape. 501 """ 502 if not shape: 503 ndim = randrange(maxdim+1) 504 if (ndim == 0): 505 if valid: 506 return itemsize, itemsize, ndim, (), (), 0 507 else: 508 nitems = randrange(1, 16+1) 509 memlen = nitems * itemsize 510 offset = -itemsize if randrange(2) == 0 else memlen 511 return memlen, itemsize, ndim, (), (), offset 512 513 minshape = 2 514 n = randrange(100) 515 if n >= 95 and valid: 516 minshape = 0 517 elif n >= 90: 518 minshape = 1 519 shape = [0] * ndim 520 521 for i in range(ndim): 522 shape[i] = randrange(minshape, maxshape+1) 523 else: 524 ndim = len(shape) 525 526 maxstride = 5 527 n = randrange(100) 528 zero_stride = True if n >= 95 and n & 1 else False 529 530 strides = [0] * ndim 531 strides[ndim-1] = itemsize * randrange(-maxstride, maxstride+1) 532 if not zero_stride and strides[ndim-1] == 0: 533 strides[ndim-1] = itemsize 534 535 for i in range(ndim-2, -1, -1): 536 maxstride *= shape[i+1] if shape[i+1] else 1 537 if zero_stride: 538 strides[i] = itemsize * randrange(-maxstride, maxstride+1) 539 else: 540 strides[i] = ((1,-1)[randrange(2)] * 541 itemsize * randrange(1, maxstride+1)) 542 543 imin = imax = 0 544 if not 0 in shape: 545 imin = sum(strides[j]*(shape[j]-1) for j in range(ndim) 546 if strides[j] <= 0) 547 imax = sum(strides[j]*(shape[j]-1) for j in range(ndim) 548 if strides[j] > 0) 549 550 nitems = imax - imin 551 if valid: 552 offset = -imin * itemsize 553 memlen = offset + (imax+1) * itemsize 554 else: 555 memlen = (-imin + imax) * itemsize 556 offset = -imin-itemsize if randrange(2) == 0 else memlen 557 return memlen, itemsize, ndim, shape, strides, offset 558 559def randslice_from_slicelen(slicelen, listlen): 560 """Create a random slice of len slicelen that fits into listlen.""" 561 maxstart = listlen - slicelen 562 start = randrange(maxstart+1) 563 maxstep = (listlen - start) // slicelen if slicelen else 1 564 step = randrange(1, maxstep+1) 565 stop = start + slicelen * step 566 s = slice(start, stop, step) 567 _, _, _, control = slice_indices(s, listlen) 568 if control != slicelen: 569 raise RuntimeError 570 return s 571 572def randslice_from_shape(ndim, shape): 573 """Create two sets of slices for an array x with shape 'shape' 574 such that shapeof(x[lslices]) == shapeof(x[rslices]).""" 575 lslices = [0] * ndim 576 rslices = [0] * ndim 577 for n in range(ndim): 578 l = shape[n] 579 slicelen = randrange(1, l+1) if l > 0 else 0 580 lslices[n] = randslice_from_slicelen(slicelen, l) 581 rslices[n] = randslice_from_slicelen(slicelen, l) 582 return tuple(lslices), tuple(rslices) 583 584def rand_aligned_slices(maxdim=5, maxshape=16): 585 """Create (lshape, rshape, tuple(lslices), tuple(rslices)) such that 586 shapeof(x[lslices]) == shapeof(y[rslices]), where x is an array 587 with shape 'lshape' and y is an array with shape 'rshape'.""" 588 ndim = randrange(1, maxdim+1) 589 minshape = 2 590 n = randrange(100) 591 if n >= 95: 592 minshape = 0 593 elif n >= 90: 594 minshape = 1 595 all_random = True if randrange(100) >= 80 else False 596 lshape = [0]*ndim; rshape = [0]*ndim 597 lslices = [0]*ndim; rslices = [0]*ndim 598 599 for n in range(ndim): 600 small = randrange(minshape, maxshape+1) 601 big = randrange(minshape, maxshape+1) 602 if big < small: 603 big, small = small, big 604 605 # Create a slice that fits the smaller value. 606 if all_random: 607 start = randrange(-small, small+1) 608 stop = randrange(-small, small+1) 609 step = (1,-1)[randrange(2)] * randrange(1, small+2) 610 s_small = slice(start, stop, step) 611 _, _, _, slicelen = slice_indices(s_small, small) 612 else: 613 slicelen = randrange(1, small+1) if small > 0 else 0 614 s_small = randslice_from_slicelen(slicelen, small) 615 616 # Create a slice of the same length for the bigger value. 617 s_big = randslice_from_slicelen(slicelen, big) 618 if randrange(2) == 0: 619 rshape[n], lshape[n] = big, small 620 rslices[n], lslices[n] = s_big, s_small 621 else: 622 rshape[n], lshape[n] = small, big 623 rslices[n], lslices[n] = s_small, s_big 624 625 return lshape, rshape, tuple(lslices), tuple(rslices) 626 627def randitems_from_structure(fmt, t): 628 """Return a list of random items for structure 't' with format 629 'fmtchar'.""" 630 memlen, itemsize, _, _, _, _ = t 631 return gen_items(memlen//itemsize, '#'+fmt, 'numpy') 632 633def ndarray_from_structure(items, fmt, t, flags=0): 634 """Return ndarray from the tuple returned by rand_structure()""" 635 memlen, itemsize, ndim, shape, strides, offset = t 636 return ndarray(items, shape=shape, strides=strides, format=fmt, 637 offset=offset, flags=ND_WRITABLE|flags) 638 639def numpy_array_from_structure(items, fmt, t): 640 """Return numpy_array from the tuple returned by rand_structure()""" 641 memlen, itemsize, ndim, shape, strides, offset = t 642 buf = bytearray(memlen) 643 for j, v in enumerate(items): 644 struct.pack_into(fmt, buf, j*itemsize, v) 645 return numpy_array(buffer=buf, shape=shape, strides=strides, 646 dtype=fmt, offset=offset) 647 648 649# ====================================================================== 650# memoryview casts 651# ====================================================================== 652 653def cast_items(exporter, fmt, itemsize, shape=None): 654 """Interpret the raw memory of 'exporter' as a list of items with 655 size 'itemsize'. If shape=None, the new structure is assumed to 656 be 1-D with n * itemsize = bytelen. If shape is given, the usual 657 constraint for contiguous arrays prod(shape) * itemsize = bytelen 658 applies. On success, return (items, shape). If the constraints 659 cannot be met, return (None, None). If a chunk of bytes is interpreted 660 as NaN as a result of float conversion, return ('nan', None).""" 661 bytelen = exporter.nbytes 662 if shape: 663 if prod(shape) * itemsize != bytelen: 664 return None, shape 665 elif shape == []: 666 if exporter.ndim == 0 or itemsize != bytelen: 667 return None, shape 668 else: 669 n, r = divmod(bytelen, itemsize) 670 shape = [n] 671 if r != 0: 672 return None, shape 673 674 mem = exporter.tobytes() 675 byteitems = [mem[i:i+itemsize] for i in range(0, len(mem), itemsize)] 676 677 items = [] 678 for v in byteitems: 679 item = struct.unpack(fmt, v)[0] 680 if item != item: 681 return 'nan', shape 682 items.append(item) 683 684 return (items, shape) if shape != [] else (items[0], shape) 685 686def gencastshapes(): 687 """Generate shapes to test casting.""" 688 for n in range(32): 689 yield [n] 690 ndim = randrange(4, 6) 691 minshape = 1 if randrange(100) > 80 else 2 692 yield [randrange(minshape, 5) for _ in range(ndim)] 693 ndim = randrange(2, 4) 694 minshape = 1 if randrange(100) > 80 else 2 695 yield [randrange(minshape, 5) for _ in range(ndim)] 696 697 698# ====================================================================== 699# Actual tests 700# ====================================================================== 701 702def genslices(n): 703 """Generate all possible slices for a single dimension.""" 704 return product(range(-n, n+1), range(-n, n+1), range(-n, n+1)) 705 706def genslices_ndim(ndim, shape): 707 """Generate all possible slice tuples for 'shape'.""" 708 iterables = [genslices(shape[n]) for n in range(ndim)] 709 return product(*iterables) 710 711def rslice(n, allow_empty=False): 712 """Generate random slice for a single dimension of length n. 713 If zero=True, the slices may be empty, otherwise they will 714 be non-empty.""" 715 minlen = 0 if allow_empty or n == 0 else 1 716 slicelen = randrange(minlen, n+1) 717 return randslice_from_slicelen(slicelen, n) 718 719def rslices(n, allow_empty=False): 720 """Generate random slices for a single dimension.""" 721 for _ in range(5): 722 yield rslice(n, allow_empty) 723 724def rslices_ndim(ndim, shape, iterations=5): 725 """Generate random slice tuples for 'shape'.""" 726 # non-empty slices 727 for _ in range(iterations): 728 yield tuple(rslice(shape[n]) for n in range(ndim)) 729 # possibly empty slices 730 for _ in range(iterations): 731 yield tuple(rslice(shape[n], allow_empty=True) for n in range(ndim)) 732 # invalid slices 733 yield tuple(slice(0,1,0) for _ in range(ndim)) 734 735def rpermutation(iterable, r=None): 736 pool = tuple(iterable) 737 r = len(pool) if r is None else r 738 yield tuple(sample(pool, r)) 739 740def ndarray_print(nd): 741 """Print ndarray for debugging.""" 742 try: 743 x = nd.tolist() 744 except (TypeError, NotImplementedError): 745 x = nd.tobytes() 746 if isinstance(nd, ndarray): 747 offset = nd.offset 748 flags = nd.flags 749 else: 750 offset = 'unknown' 751 flags = 'unknown' 752 print("ndarray(%s, shape=%s, strides=%s, suboffsets=%s, offset=%s, " 753 "format='%s', itemsize=%s, flags=%s)" % 754 (x, nd.shape, nd.strides, nd.suboffsets, offset, 755 nd.format, nd.itemsize, flags)) 756 sys.stdout.flush() 757 758 759ITERATIONS = 100 760MAXDIM = 5 761MAXSHAPE = 10 762 763if SHORT_TEST: 764 ITERATIONS = 10 765 MAXDIM = 3 766 MAXSHAPE = 4 767 genslices = rslices 768 genslices_ndim = rslices_ndim 769 permutations = rpermutation 770 771 772@unittest.skipUnless(struct, 'struct module required for this test.') 773@unittest.skipUnless(ndarray, 'ndarray object required for this test') 774class TestBufferProtocol(unittest.TestCase): 775 776 def setUp(self): 777 # The suboffsets tests need sizeof(void *). 778 self.sizeof_void_p = get_sizeof_void_p() 779 780 def verify(self, result, *, obj, 781 itemsize, fmt, readonly, 782 ndim, shape, strides, 783 lst, sliced=False, cast=False): 784 # Verify buffer contents against expected values. 785 if shape: 786 expected_len = prod(shape)*itemsize 787 else: 788 if not fmt: # array has been implicitly cast to unsigned bytes 789 expected_len = len(lst) 790 else: # ndim = 0 791 expected_len = itemsize 792 793 # Reconstruct suboffsets from strides. Support for slicing 794 # could be added, but is currently only needed for test_getbuf(). 795 suboffsets = () 796 if result.suboffsets: 797 self.assertGreater(ndim, 0) 798 799 suboffset0 = 0 800 for n in range(1, ndim): 801 if shape[n] == 0: 802 break 803 if strides[n] <= 0: 804 suboffset0 += -strides[n] * (shape[n]-1) 805 806 suboffsets = [suboffset0] + [-1 for v in range(ndim-1)] 807 808 # Not correct if slicing has occurred in the first dimension. 809 stride0 = self.sizeof_void_p 810 if strides[0] < 0: 811 stride0 = -stride0 812 strides = [stride0] + list(strides[1:]) 813 814 self.assertIs(result.obj, obj) 815 self.assertEqual(result.nbytes, expected_len) 816 self.assertEqual(result.itemsize, itemsize) 817 self.assertEqual(result.format, fmt) 818 self.assertIs(result.readonly, readonly) 819 self.assertEqual(result.ndim, ndim) 820 self.assertEqual(result.shape, tuple(shape)) 821 if not (sliced and suboffsets): 822 self.assertEqual(result.strides, tuple(strides)) 823 self.assertEqual(result.suboffsets, tuple(suboffsets)) 824 825 if isinstance(result, ndarray) or is_memoryview_format(fmt): 826 rep = result.tolist() if fmt else result.tobytes() 827 self.assertEqual(rep, lst) 828 829 if not fmt: # array has been cast to unsigned bytes, 830 return # the remaining tests won't work. 831 832 # PyBuffer_GetPointer() is the definition how to access an item. 833 # If PyBuffer_GetPointer(indices) is correct for all possible 834 # combinations of indices, the buffer is correct. 835 # 836 # Also test tobytes() against the flattened 'lst', with all items 837 # packed to bytes. 838 if not cast: # casts chop up 'lst' in different ways 839 b = bytearray() 840 buf_err = None 841 for ind in indices(shape): 842 try: 843 item1 = get_pointer(result, ind) 844 item2 = get_item(lst, ind) 845 if isinstance(item2, tuple): 846 x = struct.pack(fmt, *item2) 847 else: 848 x = struct.pack(fmt, item2) 849 b.extend(x) 850 except BufferError: 851 buf_err = True # re-exporter does not provide full buffer 852 break 853 self.assertEqual(item1, item2) 854 855 if not buf_err: 856 # test tobytes() 857 self.assertEqual(result.tobytes(), b) 858 859 # test hex() 860 m = memoryview(result) 861 h = "".join("%02x" % c for c in b) 862 self.assertEqual(m.hex(), h) 863 864 # lst := expected multi-dimensional logical representation 865 # flatten(lst) := elements in C-order 866 ff = fmt if fmt else 'B' 867 flattened = flatten(lst) 868 869 # Rules for 'A': if the array is already contiguous, return 870 # the array unaltered. Otherwise, return a contiguous 'C' 871 # representation. 872 for order in ['C', 'F', 'A']: 873 expected = result 874 if order == 'F': 875 if not is_contiguous(result, 'A') or \ 876 is_contiguous(result, 'C'): 877 # For constructing the ndarray, convert the 878 # flattened logical representation to Fortran order. 879 trans = transpose(flattened, shape) 880 expected = ndarray(trans, shape=shape, format=ff, 881 flags=ND_FORTRAN) 882 else: # 'C', 'A' 883 if not is_contiguous(result, 'A') or \ 884 is_contiguous(result, 'F') and order == 'C': 885 # The flattened list is already in C-order. 886 expected = ndarray(flattened, shape=shape, format=ff) 887 888 contig = get_contiguous(result, PyBUF_READ, order) 889 self.assertEqual(contig.tobytes(), b) 890 self.assertTrue(cmp_contig(contig, expected)) 891 892 if ndim == 0: 893 continue 894 895 nmemb = len(flattened) 896 ro = 0 if readonly else ND_WRITABLE 897 898 ### See comment in test_py_buffer_to_contiguous for an 899 ### explanation why these tests are valid. 900 901 # To 'C' 902 contig = py_buffer_to_contiguous(result, 'C', PyBUF_FULL_RO) 903 self.assertEqual(len(contig), nmemb * itemsize) 904 initlst = [struct.unpack_from(fmt, contig, n*itemsize) 905 for n in range(nmemb)] 906 if len(initlst[0]) == 1: 907 initlst = [v[0] for v in initlst] 908 909 y = ndarray(initlst, shape=shape, flags=ro, format=fmt) 910 self.assertEqual(memoryview(y), memoryview(result)) 911 912 contig_bytes = memoryview(result).tobytes() 913 self.assertEqual(contig_bytes, contig) 914 915 contig_bytes = memoryview(result).tobytes(order=None) 916 self.assertEqual(contig_bytes, contig) 917 918 contig_bytes = memoryview(result).tobytes(order='C') 919 self.assertEqual(contig_bytes, contig) 920 921 # To 'F' 922 contig = py_buffer_to_contiguous(result, 'F', PyBUF_FULL_RO) 923 self.assertEqual(len(contig), nmemb * itemsize) 924 initlst = [struct.unpack_from(fmt, contig, n*itemsize) 925 for n in range(nmemb)] 926 if len(initlst[0]) == 1: 927 initlst = [v[0] for v in initlst] 928 929 y = ndarray(initlst, shape=shape, flags=ro|ND_FORTRAN, 930 format=fmt) 931 self.assertEqual(memoryview(y), memoryview(result)) 932 933 contig_bytes = memoryview(result).tobytes(order='F') 934 self.assertEqual(contig_bytes, contig) 935 936 # To 'A' 937 contig = py_buffer_to_contiguous(result, 'A', PyBUF_FULL_RO) 938 self.assertEqual(len(contig), nmemb * itemsize) 939 initlst = [struct.unpack_from(fmt, contig, n*itemsize) 940 for n in range(nmemb)] 941 if len(initlst[0]) == 1: 942 initlst = [v[0] for v in initlst] 943 944 f = ND_FORTRAN if is_contiguous(result, 'F') else 0 945 y = ndarray(initlst, shape=shape, flags=f|ro, format=fmt) 946 self.assertEqual(memoryview(y), memoryview(result)) 947 948 contig_bytes = memoryview(result).tobytes(order='A') 949 self.assertEqual(contig_bytes, contig) 950 951 if is_memoryview_format(fmt): 952 try: 953 m = memoryview(result) 954 except BufferError: # re-exporter does not provide full information 955 return 956 ex = result.obj if isinstance(result, memoryview) else result 957 958 def check_memoryview(m, expected_readonly=readonly): 959 self.assertIs(m.obj, ex) 960 self.assertEqual(m.nbytes, expected_len) 961 self.assertEqual(m.itemsize, itemsize) 962 self.assertEqual(m.format, fmt) 963 self.assertEqual(m.readonly, expected_readonly) 964 self.assertEqual(m.ndim, ndim) 965 self.assertEqual(m.shape, tuple(shape)) 966 if not (sliced and suboffsets): 967 self.assertEqual(m.strides, tuple(strides)) 968 self.assertEqual(m.suboffsets, tuple(suboffsets)) 969 970 if ndim == 0: 971 self.assertRaises(TypeError, len, m) 972 else: 973 self.assertEqual(len(m), len(lst)) 974 975 rep = result.tolist() if fmt else result.tobytes() 976 self.assertEqual(rep, lst) 977 self.assertEqual(m, result) 978 979 check_memoryview(m) 980 with m.toreadonly() as mm: 981 check_memoryview(mm, expected_readonly=True) 982 m.tobytes() # Releasing mm didn't release m 983 984 def verify_getbuf(self, orig_ex, ex, req, sliced=False): 985 def match(req, flag): 986 return ((req&flag) == flag) 987 988 if (# writable request to read-only exporter 989 (ex.readonly and match(req, PyBUF_WRITABLE)) or 990 # cannot match explicit contiguity request 991 (match(req, PyBUF_C_CONTIGUOUS) and not ex.c_contiguous) or 992 (match(req, PyBUF_F_CONTIGUOUS) and not ex.f_contiguous) or 993 (match(req, PyBUF_ANY_CONTIGUOUS) and not ex.contiguous) or 994 # buffer needs suboffsets 995 (not match(req, PyBUF_INDIRECT) and ex.suboffsets) or 996 # buffer without strides must be C-contiguous 997 (not match(req, PyBUF_STRIDES) and not ex.c_contiguous) or 998 # PyBUF_SIMPLE|PyBUF_FORMAT and PyBUF_WRITABLE|PyBUF_FORMAT 999 (not match(req, PyBUF_ND) and match(req, PyBUF_FORMAT))): 1000 1001 self.assertRaises(BufferError, ndarray, ex, getbuf=req) 1002 return 1003 1004 if isinstance(ex, ndarray) or is_memoryview_format(ex.format): 1005 lst = ex.tolist() 1006 else: 1007 nd = ndarray(ex, getbuf=PyBUF_FULL_RO) 1008 lst = nd.tolist() 1009 1010 # The consumer may have requested default values or a NULL format. 1011 ro = False if match(req, PyBUF_WRITABLE) else ex.readonly 1012 fmt = ex.format 1013 itemsize = ex.itemsize 1014 ndim = ex.ndim 1015 if not match(req, PyBUF_FORMAT): 1016 # itemsize refers to the original itemsize before the cast. 1017 # The equality product(shape) * itemsize = len still holds. 1018 # The equality calcsize(format) = itemsize does _not_ hold. 1019 fmt = '' 1020 lst = orig_ex.tobytes() # Issue 12834 1021 if not match(req, PyBUF_ND): 1022 ndim = 1 1023 shape = orig_ex.shape if match(req, PyBUF_ND) else () 1024 strides = orig_ex.strides if match(req, PyBUF_STRIDES) else () 1025 1026 nd = ndarray(ex, getbuf=req) 1027 self.verify(nd, obj=ex, 1028 itemsize=itemsize, fmt=fmt, readonly=ro, 1029 ndim=ndim, shape=shape, strides=strides, 1030 lst=lst, sliced=sliced) 1031 1032 @support.requires_resource('cpu') 1033 def test_ndarray_getbuf(self): 1034 requests = ( 1035 # distinct flags 1036 PyBUF_INDIRECT, PyBUF_STRIDES, PyBUF_ND, PyBUF_SIMPLE, 1037 PyBUF_C_CONTIGUOUS, PyBUF_F_CONTIGUOUS, PyBUF_ANY_CONTIGUOUS, 1038 # compound requests 1039 PyBUF_FULL, PyBUF_FULL_RO, 1040 PyBUF_RECORDS, PyBUF_RECORDS_RO, 1041 PyBUF_STRIDED, PyBUF_STRIDED_RO, 1042 PyBUF_CONTIG, PyBUF_CONTIG_RO, 1043 ) 1044 # items and format 1045 items_fmt = ( 1046 ([True if x % 2 else False for x in range(12)], '?'), 1047 ([1,2,3,4,5,6,7,8,9,10,11,12], 'b'), 1048 ([1,2,3,4,5,6,7,8,9,10,11,12], 'B'), 1049 ([(2**31-x) if x % 2 else (-2**31+x) for x in range(12)], 'l') 1050 ) 1051 # shape, strides, offset 1052 structure = ( 1053 ([], [], 0), 1054 ([1,3,1], [], 0), 1055 ([12], [], 0), 1056 ([12], [-1], 11), 1057 ([6], [2], 0), 1058 ([6], [-2], 11), 1059 ([3, 4], [], 0), 1060 ([3, 4], [-4, -1], 11), 1061 ([2, 2], [4, 1], 4), 1062 ([2, 2], [-4, -1], 8) 1063 ) 1064 # ndarray creation flags 1065 ndflags = ( 1066 0, ND_WRITABLE, ND_FORTRAN, ND_FORTRAN|ND_WRITABLE, 1067 ND_PIL, ND_PIL|ND_WRITABLE 1068 ) 1069 # flags that can actually be used as flags 1070 real_flags = (0, PyBUF_WRITABLE, PyBUF_FORMAT, 1071 PyBUF_WRITABLE|PyBUF_FORMAT) 1072 1073 for items, fmt in items_fmt: 1074 itemsize = struct.calcsize(fmt) 1075 for shape, strides, offset in structure: 1076 strides = [v * itemsize for v in strides] 1077 offset *= itemsize 1078 for flags in ndflags: 1079 1080 if strides and (flags&ND_FORTRAN): 1081 continue 1082 if not shape and (flags&ND_PIL): 1083 continue 1084 1085 _items = items if shape else items[0] 1086 ex1 = ndarray(_items, format=fmt, flags=flags, 1087 shape=shape, strides=strides, offset=offset) 1088 ex2 = ex1[::-2] if shape else None 1089 1090 m1 = memoryview(ex1) 1091 if ex2: 1092 m2 = memoryview(ex2) 1093 if ex1.ndim == 0 or (ex1.ndim == 1 and shape and strides): 1094 self.assertEqual(m1, ex1) 1095 if ex2 and ex2.ndim == 1 and shape and strides: 1096 self.assertEqual(m2, ex2) 1097 1098 for req in requests: 1099 for bits in real_flags: 1100 self.verify_getbuf(ex1, ex1, req|bits) 1101 self.verify_getbuf(ex1, m1, req|bits) 1102 if ex2: 1103 self.verify_getbuf(ex2, ex2, req|bits, 1104 sliced=True) 1105 self.verify_getbuf(ex2, m2, req|bits, 1106 sliced=True) 1107 1108 items = [1,2,3,4,5,6,7,8,9,10,11,12] 1109 1110 # ND_GETBUF_FAIL 1111 ex = ndarray(items, shape=[12], flags=ND_GETBUF_FAIL) 1112 self.assertRaises(BufferError, ndarray, ex) 1113 1114 # Request complex structure from a simple exporter. In this 1115 # particular case the test object is not PEP-3118 compliant. 1116 base = ndarray([9], [1]) 1117 ex = ndarray(base, getbuf=PyBUF_SIMPLE) 1118 self.assertRaises(BufferError, ndarray, ex, getbuf=PyBUF_WRITABLE) 1119 self.assertRaises(BufferError, ndarray, ex, getbuf=PyBUF_ND) 1120 self.assertRaises(BufferError, ndarray, ex, getbuf=PyBUF_STRIDES) 1121 self.assertRaises(BufferError, ndarray, ex, getbuf=PyBUF_C_CONTIGUOUS) 1122 self.assertRaises(BufferError, ndarray, ex, getbuf=PyBUF_F_CONTIGUOUS) 1123 self.assertRaises(BufferError, ndarray, ex, getbuf=PyBUF_ANY_CONTIGUOUS) 1124 nd = ndarray(ex, getbuf=PyBUF_SIMPLE) 1125 1126 # Issue #22445: New precise contiguity definition. 1127 for shape in [1,12,1], [7,0,7]: 1128 for order in 0, ND_FORTRAN: 1129 ex = ndarray(items, shape=shape, flags=order|ND_WRITABLE) 1130 self.assertTrue(is_contiguous(ex, 'F')) 1131 self.assertTrue(is_contiguous(ex, 'C')) 1132 1133 for flags in requests: 1134 nd = ndarray(ex, getbuf=flags) 1135 self.assertTrue(is_contiguous(nd, 'F')) 1136 self.assertTrue(is_contiguous(nd, 'C')) 1137 1138 def test_ndarray_exceptions(self): 1139 nd = ndarray([9], [1]) 1140 ndm = ndarray([9], [1], flags=ND_VAREXPORT) 1141 1142 # Initialization of a new ndarray or mutation of an existing array. 1143 for c in (ndarray, nd.push, ndm.push): 1144 # Invalid types. 1145 self.assertRaises(TypeError, c, {1,2,3}) 1146 self.assertRaises(TypeError, c, [1,2,'3']) 1147 self.assertRaises(TypeError, c, [1,2,(3,4)]) 1148 self.assertRaises(TypeError, c, [1,2,3], shape={3}) 1149 self.assertRaises(TypeError, c, [1,2,3], shape=[3], strides={1}) 1150 self.assertRaises(TypeError, c, [1,2,3], shape=[3], offset=[]) 1151 self.assertRaises(TypeError, c, [1], shape=[1], format={}) 1152 self.assertRaises(TypeError, c, [1], shape=[1], flags={}) 1153 self.assertRaises(TypeError, c, [1], shape=[1], getbuf={}) 1154 1155 # ND_FORTRAN flag is only valid without strides. 1156 self.assertRaises(TypeError, c, [1], shape=[1], strides=[1], 1157 flags=ND_FORTRAN) 1158 1159 # ND_PIL flag is only valid with ndim > 0. 1160 self.assertRaises(TypeError, c, [1], shape=[], flags=ND_PIL) 1161 1162 # Invalid items. 1163 self.assertRaises(ValueError, c, [], shape=[1]) 1164 self.assertRaises(ValueError, c, ['XXX'], shape=[1], format="L") 1165 # Invalid combination of items and format. 1166 self.assertRaises(struct.error, c, [1000], shape=[1], format="B") 1167 self.assertRaises(ValueError, c, [1,(2,3)], shape=[2], format="B") 1168 self.assertRaises(ValueError, c, [1,2,3], shape=[3], format="QL") 1169 1170 # Invalid ndim. 1171 n = ND_MAX_NDIM+1 1172 self.assertRaises(ValueError, c, [1]*n, shape=[1]*n) 1173 1174 # Invalid shape. 1175 self.assertRaises(ValueError, c, [1], shape=[-1]) 1176 self.assertRaises(ValueError, c, [1,2,3], shape=['3']) 1177 self.assertRaises(OverflowError, c, [1], shape=[2**128]) 1178 # prod(shape) * itemsize != len(items) 1179 self.assertRaises(ValueError, c, [1,2,3,4,5], shape=[2,2], offset=3) 1180 1181 # Invalid strides. 1182 self.assertRaises(ValueError, c, [1,2,3], shape=[3], strides=['1']) 1183 self.assertRaises(OverflowError, c, [1], shape=[1], 1184 strides=[2**128]) 1185 1186 # Invalid combination of strides and shape. 1187 self.assertRaises(ValueError, c, [1,2], shape=[2,1], strides=[1]) 1188 # Invalid combination of strides and format. 1189 self.assertRaises(ValueError, c, [1,2,3,4], shape=[2], strides=[3], 1190 format="L") 1191 1192 # Invalid offset. 1193 self.assertRaises(ValueError, c, [1,2,3], shape=[3], offset=4) 1194 self.assertRaises(ValueError, c, [1,2,3], shape=[1], offset=3, 1195 format="L") 1196 1197 # Invalid format. 1198 self.assertRaises(ValueError, c, [1,2,3], shape=[3], format="") 1199 self.assertRaises(struct.error, c, [(1,2,3)], shape=[1], 1200 format="@#$") 1201 1202 # Striding out of the memory bounds. 1203 items = [1,2,3,4,5,6,7,8,9,10] 1204 self.assertRaises(ValueError, c, items, shape=[2,3], 1205 strides=[-3, -2], offset=5) 1206 1207 # Constructing consumer: format argument invalid. 1208 self.assertRaises(TypeError, c, bytearray(), format="Q") 1209 1210 # Constructing original base object: getbuf argument invalid. 1211 self.assertRaises(TypeError, c, [1], shape=[1], getbuf=PyBUF_FULL) 1212 1213 # Shape argument is mandatory for original base objects. 1214 self.assertRaises(TypeError, c, [1]) 1215 1216 1217 # PyBUF_WRITABLE request to read-only provider. 1218 self.assertRaises(BufferError, ndarray, b'123', getbuf=PyBUF_WRITABLE) 1219 1220 # ND_VAREXPORT can only be specified during construction. 1221 nd = ndarray([9], [1], flags=ND_VAREXPORT) 1222 self.assertRaises(ValueError, nd.push, [1], [1], flags=ND_VAREXPORT) 1223 1224 # Invalid operation for consumers: push/pop 1225 nd = ndarray(b'123') 1226 self.assertRaises(BufferError, nd.push, [1], [1]) 1227 self.assertRaises(BufferError, nd.pop) 1228 1229 # ND_VAREXPORT not set: push/pop fail with exported buffers 1230 nd = ndarray([9], [1]) 1231 nd.push([1], [1]) 1232 m = memoryview(nd) 1233 self.assertRaises(BufferError, nd.push, [1], [1]) 1234 self.assertRaises(BufferError, nd.pop) 1235 m.release() 1236 nd.pop() 1237 1238 # Single remaining buffer: pop fails 1239 self.assertRaises(BufferError, nd.pop) 1240 del nd 1241 1242 # get_pointer() 1243 self.assertRaises(TypeError, get_pointer, {}, [1,2,3]) 1244 self.assertRaises(TypeError, get_pointer, b'123', {}) 1245 1246 nd = ndarray(list(range(100)), shape=[1]*100) 1247 self.assertRaises(ValueError, get_pointer, nd, [5]) 1248 1249 nd = ndarray(list(range(12)), shape=[3,4]) 1250 self.assertRaises(ValueError, get_pointer, nd, [2,3,4]) 1251 self.assertRaises(ValueError, get_pointer, nd, [3,3]) 1252 self.assertRaises(ValueError, get_pointer, nd, [-3,3]) 1253 self.assertRaises(OverflowError, get_pointer, nd, [1<<64,3]) 1254 1255 # tolist() needs format 1256 ex = ndarray([1,2,3], shape=[3], format='L') 1257 nd = ndarray(ex, getbuf=PyBUF_SIMPLE) 1258 self.assertRaises(ValueError, nd.tolist) 1259 1260 # memoryview_from_buffer() 1261 ex1 = ndarray([1,2,3], shape=[3], format='L') 1262 ex2 = ndarray(ex1) 1263 nd = ndarray(ex2) 1264 self.assertRaises(TypeError, nd.memoryview_from_buffer) 1265 1266 nd = ndarray([(1,)*200], shape=[1], format='L'*200) 1267 self.assertRaises(TypeError, nd.memoryview_from_buffer) 1268 1269 n = ND_MAX_NDIM 1270 nd = ndarray(list(range(n)), shape=[1]*n) 1271 self.assertRaises(ValueError, nd.memoryview_from_buffer) 1272 1273 # get_contiguous() 1274 nd = ndarray([1], shape=[1]) 1275 self.assertRaises(TypeError, get_contiguous, 1, 2, 3, 4, 5) 1276 self.assertRaises(TypeError, get_contiguous, nd, "xyz", 'C') 1277 self.assertRaises(OverflowError, get_contiguous, nd, 2**64, 'C') 1278 self.assertRaises(TypeError, get_contiguous, nd, PyBUF_READ, 961) 1279 self.assertRaises(UnicodeEncodeError, get_contiguous, nd, PyBUF_READ, 1280 '\u2007') 1281 self.assertRaises(ValueError, get_contiguous, nd, PyBUF_READ, 'Z') 1282 self.assertRaises(ValueError, get_contiguous, nd, 255, 'A') 1283 1284 # cmp_contig() 1285 nd = ndarray([1], shape=[1]) 1286 self.assertRaises(TypeError, cmp_contig, 1, 2, 3, 4, 5) 1287 self.assertRaises(TypeError, cmp_contig, {}, nd) 1288 self.assertRaises(TypeError, cmp_contig, nd, {}) 1289 1290 # is_contiguous() 1291 nd = ndarray([1], shape=[1]) 1292 self.assertRaises(TypeError, is_contiguous, 1, 2, 3, 4, 5) 1293 self.assertRaises(TypeError, is_contiguous, {}, 'A') 1294 self.assertRaises(TypeError, is_contiguous, nd, 201) 1295 1296 def test_ndarray_linked_list(self): 1297 for perm in permutations(range(5)): 1298 m = [0]*5 1299 nd = ndarray([1,2,3], shape=[3], flags=ND_VAREXPORT) 1300 m[0] = memoryview(nd) 1301 1302 for i in range(1, 5): 1303 nd.push([1,2,3], shape=[3]) 1304 m[i] = memoryview(nd) 1305 1306 for i in range(5): 1307 m[perm[i]].release() 1308 1309 self.assertRaises(BufferError, nd.pop) 1310 del nd 1311 1312 def test_ndarray_format_scalar(self): 1313 # ndim = 0: scalar 1314 for fmt, scalar, _ in iter_format(0): 1315 itemsize = struct.calcsize(fmt) 1316 nd = ndarray(scalar, shape=(), format=fmt) 1317 self.verify(nd, obj=None, 1318 itemsize=itemsize, fmt=fmt, readonly=True, 1319 ndim=0, shape=(), strides=(), 1320 lst=scalar) 1321 1322 def test_ndarray_format_shape(self): 1323 # ndim = 1, shape = [n] 1324 nitems = randrange(1, 10) 1325 for fmt, items, _ in iter_format(nitems): 1326 itemsize = struct.calcsize(fmt) 1327 for flags in (0, ND_PIL): 1328 nd = ndarray(items, shape=[nitems], format=fmt, flags=flags) 1329 self.verify(nd, obj=None, 1330 itemsize=itemsize, fmt=fmt, readonly=True, 1331 ndim=1, shape=(nitems,), strides=(itemsize,), 1332 lst=items) 1333 1334 def test_ndarray_format_strides(self): 1335 # ndim = 1, strides 1336 nitems = randrange(1, 30) 1337 for fmt, items, _ in iter_format(nitems): 1338 itemsize = struct.calcsize(fmt) 1339 for step in range(-5, 5): 1340 if step == 0: 1341 continue 1342 1343 shape = [len(items[::step])] 1344 strides = [step*itemsize] 1345 offset = itemsize*(nitems-1) if step < 0 else 0 1346 1347 for flags in (0, ND_PIL): 1348 nd = ndarray(items, shape=shape, strides=strides, 1349 format=fmt, offset=offset, flags=flags) 1350 self.verify(nd, obj=None, 1351 itemsize=itemsize, fmt=fmt, readonly=True, 1352 ndim=1, shape=shape, strides=strides, 1353 lst=items[::step]) 1354 1355 def test_ndarray_fortran(self): 1356 items = [1,2,3,4,5,6,7,8,9,10,11,12] 1357 ex = ndarray(items, shape=(3, 4), strides=(1, 3)) 1358 nd = ndarray(ex, getbuf=PyBUF_F_CONTIGUOUS|PyBUF_FORMAT) 1359 self.assertEqual(nd.tolist(), farray(items, (3, 4))) 1360 1361 def test_ndarray_multidim(self): 1362 for ndim in range(5): 1363 shape_t = [randrange(2, 10) for _ in range(ndim)] 1364 nitems = prod(shape_t) 1365 for shape in permutations(shape_t): 1366 1367 fmt, items, _ = randitems(nitems) 1368 itemsize = struct.calcsize(fmt) 1369 1370 for flags in (0, ND_PIL): 1371 if ndim == 0 and flags == ND_PIL: 1372 continue 1373 1374 # C array 1375 nd = ndarray(items, shape=shape, format=fmt, flags=flags) 1376 1377 strides = strides_from_shape(ndim, shape, itemsize, 'C') 1378 lst = carray(items, shape) 1379 self.verify(nd, obj=None, 1380 itemsize=itemsize, fmt=fmt, readonly=True, 1381 ndim=ndim, shape=shape, strides=strides, 1382 lst=lst) 1383 1384 if is_memoryview_format(fmt): 1385 # memoryview: reconstruct strides 1386 ex = ndarray(items, shape=shape, format=fmt) 1387 nd = ndarray(ex, getbuf=PyBUF_CONTIG_RO|PyBUF_FORMAT) 1388 self.assertTrue(nd.strides == ()) 1389 mv = nd.memoryview_from_buffer() 1390 self.verify(mv, obj=None, 1391 itemsize=itemsize, fmt=fmt, readonly=True, 1392 ndim=ndim, shape=shape, strides=strides, 1393 lst=lst) 1394 1395 # Fortran array 1396 nd = ndarray(items, shape=shape, format=fmt, 1397 flags=flags|ND_FORTRAN) 1398 1399 strides = strides_from_shape(ndim, shape, itemsize, 'F') 1400 lst = farray(items, shape) 1401 self.verify(nd, obj=None, 1402 itemsize=itemsize, fmt=fmt, readonly=True, 1403 ndim=ndim, shape=shape, strides=strides, 1404 lst=lst) 1405 1406 def test_ndarray_index_invalid(self): 1407 # not writable 1408 nd = ndarray([1], shape=[1]) 1409 self.assertRaises(TypeError, nd.__setitem__, 1, 8) 1410 mv = memoryview(nd) 1411 self.assertEqual(mv, nd) 1412 self.assertRaises(TypeError, mv.__setitem__, 1, 8) 1413 1414 # cannot be deleted 1415 nd = ndarray([1], shape=[1], flags=ND_WRITABLE) 1416 self.assertRaises(TypeError, nd.__delitem__, 1) 1417 mv = memoryview(nd) 1418 self.assertEqual(mv, nd) 1419 self.assertRaises(TypeError, mv.__delitem__, 1) 1420 1421 # overflow 1422 nd = ndarray([1], shape=[1], flags=ND_WRITABLE) 1423 self.assertRaises(OverflowError, nd.__getitem__, 1<<64) 1424 self.assertRaises(OverflowError, nd.__setitem__, 1<<64, 8) 1425 mv = memoryview(nd) 1426 self.assertEqual(mv, nd) 1427 self.assertRaises(IndexError, mv.__getitem__, 1<<64) 1428 self.assertRaises(IndexError, mv.__setitem__, 1<<64, 8) 1429 1430 # format 1431 items = [1,2,3,4,5,6,7,8] 1432 nd = ndarray(items, shape=[len(items)], format="B", flags=ND_WRITABLE) 1433 self.assertRaises(struct.error, nd.__setitem__, 2, 300) 1434 self.assertRaises(ValueError, nd.__setitem__, 1, (100, 200)) 1435 mv = memoryview(nd) 1436 self.assertEqual(mv, nd) 1437 self.assertRaises(ValueError, mv.__setitem__, 2, 300) 1438 self.assertRaises(TypeError, mv.__setitem__, 1, (100, 200)) 1439 1440 items = [(1,2), (3,4), (5,6)] 1441 nd = ndarray(items, shape=[len(items)], format="LQ", flags=ND_WRITABLE) 1442 self.assertRaises(ValueError, nd.__setitem__, 2, 300) 1443 self.assertRaises(struct.error, nd.__setitem__, 1, (b'\x001', 200)) 1444 1445 def test_ndarray_index_scalar(self): 1446 # scalar 1447 nd = ndarray(1, shape=(), flags=ND_WRITABLE) 1448 mv = memoryview(nd) 1449 self.assertEqual(mv, nd) 1450 1451 x = nd[()]; self.assertEqual(x, 1) 1452 x = nd[...]; self.assertEqual(x.tolist(), nd.tolist()) 1453 1454 x = mv[()]; self.assertEqual(x, 1) 1455 x = mv[...]; self.assertEqual(x.tolist(), nd.tolist()) 1456 1457 self.assertRaises(TypeError, nd.__getitem__, 0) 1458 self.assertRaises(TypeError, mv.__getitem__, 0) 1459 self.assertRaises(TypeError, nd.__setitem__, 0, 8) 1460 self.assertRaises(TypeError, mv.__setitem__, 0, 8) 1461 1462 self.assertEqual(nd.tolist(), 1) 1463 self.assertEqual(mv.tolist(), 1) 1464 1465 nd[()] = 9; self.assertEqual(nd.tolist(), 9) 1466 mv[()] = 9; self.assertEqual(mv.tolist(), 9) 1467 1468 nd[...] = 5; self.assertEqual(nd.tolist(), 5) 1469 mv[...] = 5; self.assertEqual(mv.tolist(), 5) 1470 1471 def test_ndarray_index_null_strides(self): 1472 ex = ndarray(list(range(2*4)), shape=[2, 4], flags=ND_WRITABLE) 1473 nd = ndarray(ex, getbuf=PyBUF_CONTIG) 1474 1475 # Sub-views are only possible for full exporters. 1476 self.assertRaises(BufferError, nd.__getitem__, 1) 1477 # Same for slices. 1478 self.assertRaises(BufferError, nd.__getitem__, slice(3,5,1)) 1479 1480 def test_ndarray_index_getitem_single(self): 1481 # getitem 1482 for fmt, items, _ in iter_format(5): 1483 nd = ndarray(items, shape=[5], format=fmt) 1484 for i in range(-5, 5): 1485 self.assertEqual(nd[i], items[i]) 1486 1487 self.assertRaises(IndexError, nd.__getitem__, -6) 1488 self.assertRaises(IndexError, nd.__getitem__, 5) 1489 1490 if is_memoryview_format(fmt): 1491 mv = memoryview(nd) 1492 self.assertEqual(mv, nd) 1493 for i in range(-5, 5): 1494 self.assertEqual(mv[i], items[i]) 1495 1496 self.assertRaises(IndexError, mv.__getitem__, -6) 1497 self.assertRaises(IndexError, mv.__getitem__, 5) 1498 1499 # getitem with null strides 1500 for fmt, items, _ in iter_format(5): 1501 ex = ndarray(items, shape=[5], flags=ND_WRITABLE, format=fmt) 1502 nd = ndarray(ex, getbuf=PyBUF_CONTIG|PyBUF_FORMAT) 1503 1504 for i in range(-5, 5): 1505 self.assertEqual(nd[i], items[i]) 1506 1507 if is_memoryview_format(fmt): 1508 mv = nd.memoryview_from_buffer() 1509 self.assertIs(mv.__eq__(nd), NotImplemented) 1510 for i in range(-5, 5): 1511 self.assertEqual(mv[i], items[i]) 1512 1513 # getitem with null format 1514 items = [1,2,3,4,5] 1515 ex = ndarray(items, shape=[5]) 1516 nd = ndarray(ex, getbuf=PyBUF_CONTIG_RO) 1517 for i in range(-5, 5): 1518 self.assertEqual(nd[i], items[i]) 1519 1520 # getitem with null shape/strides/format 1521 items = [1,2,3,4,5] 1522 ex = ndarray(items, shape=[5]) 1523 nd = ndarray(ex, getbuf=PyBUF_SIMPLE) 1524 1525 for i in range(-5, 5): 1526 self.assertEqual(nd[i], items[i]) 1527 1528 def test_ndarray_index_setitem_single(self): 1529 # assign single value 1530 for fmt, items, single_item in iter_format(5): 1531 nd = ndarray(items, shape=[5], format=fmt, flags=ND_WRITABLE) 1532 for i in range(5): 1533 items[i] = single_item 1534 nd[i] = single_item 1535 self.assertEqual(nd.tolist(), items) 1536 1537 self.assertRaises(IndexError, nd.__setitem__, -6, single_item) 1538 self.assertRaises(IndexError, nd.__setitem__, 5, single_item) 1539 1540 if not is_memoryview_format(fmt): 1541 continue 1542 1543 nd = ndarray(items, shape=[5], format=fmt, flags=ND_WRITABLE) 1544 mv = memoryview(nd) 1545 self.assertEqual(mv, nd) 1546 for i in range(5): 1547 items[i] = single_item 1548 mv[i] = single_item 1549 self.assertEqual(mv.tolist(), items) 1550 1551 self.assertRaises(IndexError, mv.__setitem__, -6, single_item) 1552 self.assertRaises(IndexError, mv.__setitem__, 5, single_item) 1553 1554 1555 # assign single value: lobject = robject 1556 for fmt, items, single_item in iter_format(5): 1557 nd = ndarray(items, shape=[5], format=fmt, flags=ND_WRITABLE) 1558 for i in range(-5, 4): 1559 items[i] = items[i+1] 1560 nd[i] = nd[i+1] 1561 self.assertEqual(nd.tolist(), items) 1562 1563 if not is_memoryview_format(fmt): 1564 continue 1565 1566 nd = ndarray(items, shape=[5], format=fmt, flags=ND_WRITABLE) 1567 mv = memoryview(nd) 1568 self.assertEqual(mv, nd) 1569 for i in range(-5, 4): 1570 items[i] = items[i+1] 1571 mv[i] = mv[i+1] 1572 self.assertEqual(mv.tolist(), items) 1573 1574 def test_ndarray_index_getitem_multidim(self): 1575 shape_t = (2, 3, 5) 1576 nitems = prod(shape_t) 1577 for shape in permutations(shape_t): 1578 1579 fmt, items, _ = randitems(nitems) 1580 1581 for flags in (0, ND_PIL): 1582 # C array 1583 nd = ndarray(items, shape=shape, format=fmt, flags=flags) 1584 lst = carray(items, shape) 1585 1586 for i in range(-shape[0], shape[0]): 1587 self.assertEqual(lst[i], nd[i].tolist()) 1588 for j in range(-shape[1], shape[1]): 1589 self.assertEqual(lst[i][j], nd[i][j].tolist()) 1590 for k in range(-shape[2], shape[2]): 1591 self.assertEqual(lst[i][j][k], nd[i][j][k]) 1592 1593 # Fortran array 1594 nd = ndarray(items, shape=shape, format=fmt, 1595 flags=flags|ND_FORTRAN) 1596 lst = farray(items, shape) 1597 1598 for i in range(-shape[0], shape[0]): 1599 self.assertEqual(lst[i], nd[i].tolist()) 1600 for j in range(-shape[1], shape[1]): 1601 self.assertEqual(lst[i][j], nd[i][j].tolist()) 1602 for k in range(shape[2], shape[2]): 1603 self.assertEqual(lst[i][j][k], nd[i][j][k]) 1604 1605 def test_ndarray_sequence(self): 1606 nd = ndarray(1, shape=()) 1607 self.assertRaises(TypeError, eval, "1 in nd", locals()) 1608 mv = memoryview(nd) 1609 self.assertEqual(mv, nd) 1610 self.assertRaises(TypeError, eval, "1 in mv", locals()) 1611 1612 for fmt, items, _ in iter_format(5): 1613 nd = ndarray(items, shape=[5], format=fmt) 1614 for i, v in enumerate(nd): 1615 self.assertEqual(v, items[i]) 1616 self.assertTrue(v in nd) 1617 1618 if is_memoryview_format(fmt): 1619 mv = memoryview(nd) 1620 for i, v in enumerate(mv): 1621 self.assertEqual(v, items[i]) 1622 self.assertTrue(v in mv) 1623 1624 def test_ndarray_slice_invalid(self): 1625 items = [1,2,3,4,5,6,7,8] 1626 1627 # rvalue is not an exporter 1628 xl = ndarray(items, shape=[8], flags=ND_WRITABLE) 1629 ml = memoryview(xl) 1630 self.assertRaises(TypeError, xl.__setitem__, slice(0,8,1), items) 1631 self.assertRaises(TypeError, ml.__setitem__, slice(0,8,1), items) 1632 1633 # rvalue is not a full exporter 1634 xl = ndarray(items, shape=[8], flags=ND_WRITABLE) 1635 ex = ndarray(items, shape=[8], flags=ND_WRITABLE) 1636 xr = ndarray(ex, getbuf=PyBUF_ND) 1637 self.assertRaises(BufferError, xl.__setitem__, slice(0,8,1), xr) 1638 1639 # zero step 1640 nd = ndarray(items, shape=[8], format="L", flags=ND_WRITABLE) 1641 mv = memoryview(nd) 1642 self.assertRaises(ValueError, nd.__getitem__, slice(0,1,0)) 1643 self.assertRaises(ValueError, mv.__getitem__, slice(0,1,0)) 1644 1645 nd = ndarray(items, shape=[2,4], format="L", flags=ND_WRITABLE) 1646 mv = memoryview(nd) 1647 1648 self.assertRaises(ValueError, nd.__getitem__, 1649 (slice(0,1,1), slice(0,1,0))) 1650 self.assertRaises(ValueError, nd.__getitem__, 1651 (slice(0,1,0), slice(0,1,1))) 1652 self.assertRaises(TypeError, nd.__getitem__, "@%$") 1653 self.assertRaises(TypeError, nd.__getitem__, ("@%$", slice(0,1,1))) 1654 self.assertRaises(TypeError, nd.__getitem__, (slice(0,1,1), {})) 1655 1656 # memoryview: not implemented 1657 self.assertRaises(NotImplementedError, mv.__getitem__, 1658 (slice(0,1,1), slice(0,1,0))) 1659 self.assertRaises(TypeError, mv.__getitem__, "@%$") 1660 1661 # differing format 1662 xl = ndarray(items, shape=[8], format="B", flags=ND_WRITABLE) 1663 xr = ndarray(items, shape=[8], format="b") 1664 ml = memoryview(xl) 1665 mr = memoryview(xr) 1666 self.assertRaises(ValueError, xl.__setitem__, slice(0,1,1), xr[7:8]) 1667 self.assertEqual(xl.tolist(), items) 1668 self.assertRaises(ValueError, ml.__setitem__, slice(0,1,1), mr[7:8]) 1669 self.assertEqual(ml.tolist(), items) 1670 1671 # differing itemsize 1672 xl = ndarray(items, shape=[8], format="B", flags=ND_WRITABLE) 1673 yr = ndarray(items, shape=[8], format="L") 1674 ml = memoryview(xl) 1675 mr = memoryview(xr) 1676 self.assertRaises(ValueError, xl.__setitem__, slice(0,1,1), xr[7:8]) 1677 self.assertEqual(xl.tolist(), items) 1678 self.assertRaises(ValueError, ml.__setitem__, slice(0,1,1), mr[7:8]) 1679 self.assertEqual(ml.tolist(), items) 1680 1681 # differing ndim 1682 xl = ndarray(items, shape=[2, 4], format="b", flags=ND_WRITABLE) 1683 xr = ndarray(items, shape=[8], format="b") 1684 ml = memoryview(xl) 1685 mr = memoryview(xr) 1686 self.assertRaises(ValueError, xl.__setitem__, slice(0,1,1), xr[7:8]) 1687 self.assertEqual(xl.tolist(), [[1,2,3,4], [5,6,7,8]]) 1688 self.assertRaises(NotImplementedError, ml.__setitem__, slice(0,1,1), 1689 mr[7:8]) 1690 1691 # differing shape 1692 xl = ndarray(items, shape=[8], format="b", flags=ND_WRITABLE) 1693 xr = ndarray(items, shape=[8], format="b") 1694 ml = memoryview(xl) 1695 mr = memoryview(xr) 1696 self.assertRaises(ValueError, xl.__setitem__, slice(0,2,1), xr[7:8]) 1697 self.assertEqual(xl.tolist(), items) 1698 self.assertRaises(ValueError, ml.__setitem__, slice(0,2,1), mr[7:8]) 1699 self.assertEqual(ml.tolist(), items) 1700 1701 # _testbuffer.c module functions 1702 self.assertRaises(TypeError, slice_indices, slice(0,1,2), {}) 1703 self.assertRaises(TypeError, slice_indices, "###########", 1) 1704 self.assertRaises(ValueError, slice_indices, slice(0,1,0), 4) 1705 1706 x = ndarray(items, shape=[8], format="b", flags=ND_PIL) 1707 self.assertRaises(TypeError, x.add_suboffsets) 1708 1709 ex = ndarray(items, shape=[8], format="B") 1710 x = ndarray(ex, getbuf=PyBUF_SIMPLE) 1711 self.assertRaises(TypeError, x.add_suboffsets) 1712 1713 def test_ndarray_slice_zero_shape(self): 1714 items = [1,2,3,4,5,6,7,8,9,10,11,12] 1715 1716 x = ndarray(items, shape=[12], format="L", flags=ND_WRITABLE) 1717 y = ndarray(items, shape=[12], format="L") 1718 x[4:4] = y[9:9] 1719 self.assertEqual(x.tolist(), items) 1720 1721 ml = memoryview(x) 1722 mr = memoryview(y) 1723 self.assertEqual(ml, x) 1724 self.assertEqual(ml, y) 1725 ml[4:4] = mr[9:9] 1726 self.assertEqual(ml.tolist(), items) 1727 1728 x = ndarray(items, shape=[3, 4], format="L", flags=ND_WRITABLE) 1729 y = ndarray(items, shape=[4, 3], format="L") 1730 x[1:2, 2:2] = y[1:2, 3:3] 1731 self.assertEqual(x.tolist(), carray(items, [3, 4])) 1732 1733 def test_ndarray_slice_multidim(self): 1734 shape_t = (2, 3, 5) 1735 ndim = len(shape_t) 1736 nitems = prod(shape_t) 1737 for shape in permutations(shape_t): 1738 1739 fmt, items, _ = randitems(nitems) 1740 itemsize = struct.calcsize(fmt) 1741 1742 for flags in (0, ND_PIL): 1743 nd = ndarray(items, shape=shape, format=fmt, flags=flags) 1744 lst = carray(items, shape) 1745 1746 for slices in rslices_ndim(ndim, shape): 1747 1748 listerr = None 1749 try: 1750 sliced = multislice(lst, slices) 1751 except Exception as e: 1752 listerr = e.__class__ 1753 1754 nderr = None 1755 try: 1756 ndsliced = nd[slices] 1757 except Exception as e: 1758 nderr = e.__class__ 1759 1760 if nderr or listerr: 1761 self.assertIs(nderr, listerr) 1762 else: 1763 self.assertEqual(ndsliced.tolist(), sliced) 1764 1765 def test_ndarray_slice_redundant_suboffsets(self): 1766 shape_t = (2, 3, 5, 2) 1767 ndim = len(shape_t) 1768 nitems = prod(shape_t) 1769 for shape in permutations(shape_t): 1770 1771 fmt, items, _ = randitems(nitems) 1772 itemsize = struct.calcsize(fmt) 1773 1774 nd = ndarray(items, shape=shape, format=fmt) 1775 nd.add_suboffsets() 1776 ex = ndarray(items, shape=shape, format=fmt) 1777 ex.add_suboffsets() 1778 mv = memoryview(ex) 1779 lst = carray(items, shape) 1780 1781 for slices in rslices_ndim(ndim, shape): 1782 1783 listerr = None 1784 try: 1785 sliced = multislice(lst, slices) 1786 except Exception as e: 1787 listerr = e.__class__ 1788 1789 nderr = None 1790 try: 1791 ndsliced = nd[slices] 1792 except Exception as e: 1793 nderr = e.__class__ 1794 1795 if nderr or listerr: 1796 self.assertIs(nderr, listerr) 1797 else: 1798 self.assertEqual(ndsliced.tolist(), sliced) 1799 1800 def test_ndarray_slice_assign_single(self): 1801 for fmt, items, _ in iter_format(5): 1802 for lslice in genslices(5): 1803 for rslice in genslices(5): 1804 for flags in (0, ND_PIL): 1805 1806 f = flags|ND_WRITABLE 1807 nd = ndarray(items, shape=[5], format=fmt, flags=f) 1808 ex = ndarray(items, shape=[5], format=fmt, flags=f) 1809 mv = memoryview(ex) 1810 1811 lsterr = None 1812 diff_structure = None 1813 lst = items[:] 1814 try: 1815 lval = lst[lslice] 1816 rval = lst[rslice] 1817 lst[lslice] = lst[rslice] 1818 diff_structure = len(lval) != len(rval) 1819 except Exception as e: 1820 lsterr = e.__class__ 1821 1822 nderr = None 1823 try: 1824 nd[lslice] = nd[rslice] 1825 except Exception as e: 1826 nderr = e.__class__ 1827 1828 if diff_structure: # ndarray cannot change shape 1829 self.assertIs(nderr, ValueError) 1830 else: 1831 self.assertEqual(nd.tolist(), lst) 1832 self.assertIs(nderr, lsterr) 1833 1834 if not is_memoryview_format(fmt): 1835 continue 1836 1837 mverr = None 1838 try: 1839 mv[lslice] = mv[rslice] 1840 except Exception as e: 1841 mverr = e.__class__ 1842 1843 if diff_structure: # memoryview cannot change shape 1844 self.assertIs(mverr, ValueError) 1845 else: 1846 self.assertEqual(mv.tolist(), lst) 1847 self.assertEqual(mv, nd) 1848 self.assertIs(mverr, lsterr) 1849 self.verify(mv, obj=ex, 1850 itemsize=nd.itemsize, fmt=fmt, readonly=False, 1851 ndim=nd.ndim, shape=nd.shape, strides=nd.strides, 1852 lst=nd.tolist()) 1853 1854 def test_ndarray_slice_assign_multidim(self): 1855 shape_t = (2, 3, 5) 1856 ndim = len(shape_t) 1857 nitems = prod(shape_t) 1858 for shape in permutations(shape_t): 1859 1860 fmt, items, _ = randitems(nitems) 1861 1862 for flags in (0, ND_PIL): 1863 for _ in range(ITERATIONS): 1864 lslices, rslices = randslice_from_shape(ndim, shape) 1865 1866 nd = ndarray(items, shape=shape, format=fmt, 1867 flags=flags|ND_WRITABLE) 1868 lst = carray(items, shape) 1869 1870 listerr = None 1871 try: 1872 result = multislice_assign(lst, lst, lslices, rslices) 1873 except Exception as e: 1874 listerr = e.__class__ 1875 1876 nderr = None 1877 try: 1878 nd[lslices] = nd[rslices] 1879 except Exception as e: 1880 nderr = e.__class__ 1881 1882 if nderr or listerr: 1883 self.assertIs(nderr, listerr) 1884 else: 1885 self.assertEqual(nd.tolist(), result) 1886 1887 def test_ndarray_random(self): 1888 # construction of valid arrays 1889 for _ in range(ITERATIONS): 1890 for fmt in fmtdict['@']: 1891 itemsize = struct.calcsize(fmt) 1892 1893 t = rand_structure(itemsize, True, maxdim=MAXDIM, 1894 maxshape=MAXSHAPE) 1895 self.assertTrue(verify_structure(*t)) 1896 items = randitems_from_structure(fmt, t) 1897 1898 x = ndarray_from_structure(items, fmt, t) 1899 xlist = x.tolist() 1900 1901 mv = memoryview(x) 1902 if is_memoryview_format(fmt): 1903 mvlist = mv.tolist() 1904 self.assertEqual(mvlist, xlist) 1905 1906 if t[2] > 0: 1907 # ndim > 0: test against suboffsets representation. 1908 y = ndarray_from_structure(items, fmt, t, flags=ND_PIL) 1909 ylist = y.tolist() 1910 self.assertEqual(xlist, ylist) 1911 1912 mv = memoryview(y) 1913 if is_memoryview_format(fmt): 1914 self.assertEqual(mv, y) 1915 mvlist = mv.tolist() 1916 self.assertEqual(mvlist, ylist) 1917 1918 if numpy_array: 1919 shape = t[3] 1920 if 0 in shape: 1921 continue # http://projects.scipy.org/numpy/ticket/1910 1922 z = numpy_array_from_structure(items, fmt, t) 1923 self.verify(x, obj=None, 1924 itemsize=z.itemsize, fmt=fmt, readonly=False, 1925 ndim=z.ndim, shape=z.shape, strides=z.strides, 1926 lst=z.tolist()) 1927 1928 def test_ndarray_random_invalid(self): 1929 # exceptions during construction of invalid arrays 1930 for _ in range(ITERATIONS): 1931 for fmt in fmtdict['@']: 1932 itemsize = struct.calcsize(fmt) 1933 1934 t = rand_structure(itemsize, False, maxdim=MAXDIM, 1935 maxshape=MAXSHAPE) 1936 self.assertFalse(verify_structure(*t)) 1937 items = randitems_from_structure(fmt, t) 1938 1939 nderr = False 1940 try: 1941 x = ndarray_from_structure(items, fmt, t) 1942 except Exception as e: 1943 nderr = e.__class__ 1944 self.assertTrue(nderr) 1945 1946 if numpy_array: 1947 numpy_err = False 1948 try: 1949 y = numpy_array_from_structure(items, fmt, t) 1950 except Exception as e: 1951 numpy_err = e.__class__ 1952 1953 if 0: # http://projects.scipy.org/numpy/ticket/1910 1954 self.assertTrue(numpy_err) 1955 1956 def test_ndarray_random_slice_assign(self): 1957 # valid slice assignments 1958 for _ in range(ITERATIONS): 1959 for fmt in fmtdict['@']: 1960 itemsize = struct.calcsize(fmt) 1961 1962 lshape, rshape, lslices, rslices = \ 1963 rand_aligned_slices(maxdim=MAXDIM, maxshape=MAXSHAPE) 1964 tl = rand_structure(itemsize, True, shape=lshape) 1965 tr = rand_structure(itemsize, True, shape=rshape) 1966 self.assertTrue(verify_structure(*tl)) 1967 self.assertTrue(verify_structure(*tr)) 1968 litems = randitems_from_structure(fmt, tl) 1969 ritems = randitems_from_structure(fmt, tr) 1970 1971 xl = ndarray_from_structure(litems, fmt, tl) 1972 xr = ndarray_from_structure(ritems, fmt, tr) 1973 xl[lslices] = xr[rslices] 1974 xllist = xl.tolist() 1975 xrlist = xr.tolist() 1976 1977 ml = memoryview(xl) 1978 mr = memoryview(xr) 1979 self.assertEqual(ml.tolist(), xllist) 1980 self.assertEqual(mr.tolist(), xrlist) 1981 1982 if tl[2] > 0 and tr[2] > 0: 1983 # ndim > 0: test against suboffsets representation. 1984 yl = ndarray_from_structure(litems, fmt, tl, flags=ND_PIL) 1985 yr = ndarray_from_structure(ritems, fmt, tr, flags=ND_PIL) 1986 yl[lslices] = yr[rslices] 1987 yllist = yl.tolist() 1988 yrlist = yr.tolist() 1989 self.assertEqual(xllist, yllist) 1990 self.assertEqual(xrlist, yrlist) 1991 1992 ml = memoryview(yl) 1993 mr = memoryview(yr) 1994 self.assertEqual(ml.tolist(), yllist) 1995 self.assertEqual(mr.tolist(), yrlist) 1996 1997 if numpy_array: 1998 if 0 in lshape or 0 in rshape: 1999 continue # http://projects.scipy.org/numpy/ticket/1910 2000 2001 zl = numpy_array_from_structure(litems, fmt, tl) 2002 zr = numpy_array_from_structure(ritems, fmt, tr) 2003 zl[lslices] = zr[rslices] 2004 2005 if not is_overlapping(tl) and not is_overlapping(tr): 2006 # Slice assignment of overlapping structures 2007 # is undefined in NumPy. 2008 self.verify(xl, obj=None, 2009 itemsize=zl.itemsize, fmt=fmt, readonly=False, 2010 ndim=zl.ndim, shape=zl.shape, 2011 strides=zl.strides, lst=zl.tolist()) 2012 2013 self.verify(xr, obj=None, 2014 itemsize=zr.itemsize, fmt=fmt, readonly=False, 2015 ndim=zr.ndim, shape=zr.shape, 2016 strides=zr.strides, lst=zr.tolist()) 2017 2018 def test_ndarray_re_export(self): 2019 items = [1,2,3,4,5,6,7,8,9,10,11,12] 2020 2021 nd = ndarray(items, shape=[3,4], flags=ND_PIL) 2022 ex = ndarray(nd) 2023 2024 self.assertTrue(ex.flags & ND_PIL) 2025 self.assertIs(ex.obj, nd) 2026 self.assertEqual(ex.suboffsets, (0, -1)) 2027 self.assertFalse(ex.c_contiguous) 2028 self.assertFalse(ex.f_contiguous) 2029 self.assertFalse(ex.contiguous) 2030 2031 def test_ndarray_zero_shape(self): 2032 # zeros in shape 2033 for flags in (0, ND_PIL): 2034 nd = ndarray([1,2,3], shape=[0], flags=flags) 2035 mv = memoryview(nd) 2036 self.assertEqual(mv, nd) 2037 self.assertEqual(nd.tolist(), []) 2038 self.assertEqual(mv.tolist(), []) 2039 2040 nd = ndarray([1,2,3], shape=[0,3,3], flags=flags) 2041 self.assertEqual(nd.tolist(), []) 2042 2043 nd = ndarray([1,2,3], shape=[3,0,3], flags=flags) 2044 self.assertEqual(nd.tolist(), [[], [], []]) 2045 2046 nd = ndarray([1,2,3], shape=[3,3,0], flags=flags) 2047 self.assertEqual(nd.tolist(), 2048 [[[], [], []], [[], [], []], [[], [], []]]) 2049 2050 def test_ndarray_zero_strides(self): 2051 # zero strides 2052 for flags in (0, ND_PIL): 2053 nd = ndarray([1], shape=[5], strides=[0], flags=flags) 2054 mv = memoryview(nd) 2055 self.assertEqual(mv, nd) 2056 self.assertEqual(nd.tolist(), [1, 1, 1, 1, 1]) 2057 self.assertEqual(mv.tolist(), [1, 1, 1, 1, 1]) 2058 2059 def test_ndarray_offset(self): 2060 nd = ndarray(list(range(20)), shape=[3], offset=7) 2061 self.assertEqual(nd.offset, 7) 2062 self.assertEqual(nd.tolist(), [7,8,9]) 2063 2064 def test_ndarray_memoryview_from_buffer(self): 2065 for flags in (0, ND_PIL): 2066 nd = ndarray(list(range(3)), shape=[3], flags=flags) 2067 m = nd.memoryview_from_buffer() 2068 self.assertEqual(m, nd) 2069 2070 def test_ndarray_get_pointer(self): 2071 for flags in (0, ND_PIL): 2072 nd = ndarray(list(range(3)), shape=[3], flags=flags) 2073 for i in range(3): 2074 self.assertEqual(nd[i], get_pointer(nd, [i])) 2075 2076 def test_ndarray_tolist_null_strides(self): 2077 ex = ndarray(list(range(20)), shape=[2,2,5]) 2078 2079 nd = ndarray(ex, getbuf=PyBUF_ND|PyBUF_FORMAT) 2080 self.assertEqual(nd.tolist(), ex.tolist()) 2081 2082 m = memoryview(ex) 2083 self.assertEqual(m.tolist(), ex.tolist()) 2084 2085 def test_ndarray_cmp_contig(self): 2086 2087 self.assertFalse(cmp_contig(b"123", b"456")) 2088 2089 x = ndarray(list(range(12)), shape=[3,4]) 2090 y = ndarray(list(range(12)), shape=[4,3]) 2091 self.assertFalse(cmp_contig(x, y)) 2092 2093 x = ndarray([1], shape=[1], format="B") 2094 self.assertTrue(cmp_contig(x, b'\x01')) 2095 self.assertTrue(cmp_contig(b'\x01', x)) 2096 2097 def test_ndarray_hash(self): 2098 2099 a = array.array('L', [1,2,3]) 2100 nd = ndarray(a) 2101 self.assertRaises(ValueError, hash, nd) 2102 2103 # one-dimensional 2104 b = bytes(list(range(12))) 2105 2106 nd = ndarray(list(range(12)), shape=[12]) 2107 self.assertEqual(hash(nd), hash(b)) 2108 2109 # C-contiguous 2110 nd = ndarray(list(range(12)), shape=[3,4]) 2111 self.assertEqual(hash(nd), hash(b)) 2112 2113 nd = ndarray(list(range(12)), shape=[3,2,2]) 2114 self.assertEqual(hash(nd), hash(b)) 2115 2116 # Fortran contiguous 2117 b = bytes(transpose(list(range(12)), shape=[4,3])) 2118 nd = ndarray(list(range(12)), shape=[3,4], flags=ND_FORTRAN) 2119 self.assertEqual(hash(nd), hash(b)) 2120 2121 b = bytes(transpose(list(range(12)), shape=[2,3,2])) 2122 nd = ndarray(list(range(12)), shape=[2,3,2], flags=ND_FORTRAN) 2123 self.assertEqual(hash(nd), hash(b)) 2124 2125 # suboffsets 2126 b = bytes(list(range(12))) 2127 nd = ndarray(list(range(12)), shape=[2,2,3], flags=ND_PIL) 2128 self.assertEqual(hash(nd), hash(b)) 2129 2130 # non-byte formats 2131 nd = ndarray(list(range(12)), shape=[2,2,3], format='L') 2132 self.assertEqual(hash(nd), hash(nd.tobytes())) 2133 2134 def test_py_buffer_to_contiguous(self): 2135 2136 # The requests are used in _testbuffer.c:py_buffer_to_contiguous 2137 # to generate buffers without full information for testing. 2138 requests = ( 2139 # distinct flags 2140 PyBUF_INDIRECT, PyBUF_STRIDES, PyBUF_ND, PyBUF_SIMPLE, 2141 # compound requests 2142 PyBUF_FULL, PyBUF_FULL_RO, 2143 PyBUF_RECORDS, PyBUF_RECORDS_RO, 2144 PyBUF_STRIDED, PyBUF_STRIDED_RO, 2145 PyBUF_CONTIG, PyBUF_CONTIG_RO, 2146 ) 2147 2148 # no buffer interface 2149 self.assertRaises(TypeError, py_buffer_to_contiguous, {}, 'F', 2150 PyBUF_FULL_RO) 2151 2152 # scalar, read-only request 2153 nd = ndarray(9, shape=(), format="L", flags=ND_WRITABLE) 2154 for order in ['C', 'F', 'A']: 2155 for request in requests: 2156 b = py_buffer_to_contiguous(nd, order, request) 2157 self.assertEqual(b, nd.tobytes()) 2158 2159 # zeros in shape 2160 nd = ndarray([1], shape=[0], format="L", flags=ND_WRITABLE) 2161 for order in ['C', 'F', 'A']: 2162 for request in requests: 2163 b = py_buffer_to_contiguous(nd, order, request) 2164 self.assertEqual(b, b'') 2165 2166 nd = ndarray(list(range(8)), shape=[2, 0, 7], format="L", 2167 flags=ND_WRITABLE) 2168 for order in ['C', 'F', 'A']: 2169 for request in requests: 2170 b = py_buffer_to_contiguous(nd, order, request) 2171 self.assertEqual(b, b'') 2172 2173 ### One-dimensional arrays are trivial, since Fortran and C order 2174 ### are the same. 2175 2176 # one-dimensional 2177 for f in [0, ND_FORTRAN]: 2178 nd = ndarray([1], shape=[1], format="h", flags=f|ND_WRITABLE) 2179 ndbytes = nd.tobytes() 2180 for order in ['C', 'F', 'A']: 2181 for request in requests: 2182 b = py_buffer_to_contiguous(nd, order, request) 2183 self.assertEqual(b, ndbytes) 2184 2185 nd = ndarray([1, 2, 3], shape=[3], format="b", flags=f|ND_WRITABLE) 2186 ndbytes = nd.tobytes() 2187 for order in ['C', 'F', 'A']: 2188 for request in requests: 2189 b = py_buffer_to_contiguous(nd, order, request) 2190 self.assertEqual(b, ndbytes) 2191 2192 # one-dimensional, non-contiguous input 2193 nd = ndarray([1, 2, 3], shape=[2], strides=[2], flags=ND_WRITABLE) 2194 ndbytes = nd.tobytes() 2195 for order in ['C', 'F', 'A']: 2196 for request in [PyBUF_STRIDES, PyBUF_FULL]: 2197 b = py_buffer_to_contiguous(nd, order, request) 2198 self.assertEqual(b, ndbytes) 2199 2200 nd = nd[::-1] 2201 ndbytes = nd.tobytes() 2202 for order in ['C', 'F', 'A']: 2203 for request in requests: 2204 try: 2205 b = py_buffer_to_contiguous(nd, order, request) 2206 except BufferError: 2207 continue 2208 self.assertEqual(b, ndbytes) 2209 2210 ### 2211 ### Multi-dimensional arrays: 2212 ### 2213 ### The goal here is to preserve the logical representation of the 2214 ### input array but change the physical representation if necessary. 2215 ### 2216 ### _testbuffer example: 2217 ### ==================== 2218 ### 2219 ### C input array: 2220 ### -------------- 2221 ### >>> nd = ndarray(list(range(12)), shape=[3, 4]) 2222 ### >>> nd.tolist() 2223 ### [[0, 1, 2, 3], 2224 ### [4, 5, 6, 7], 2225 ### [8, 9, 10, 11]] 2226 ### 2227 ### Fortran output: 2228 ### --------------- 2229 ### >>> py_buffer_to_contiguous(nd, 'F', PyBUF_FULL_RO) 2230 ### >>> b'\x00\x04\x08\x01\x05\t\x02\x06\n\x03\x07\x0b' 2231 ### 2232 ### The return value corresponds to this input list for 2233 ### _testbuffer's ndarray: 2234 ### >>> nd = ndarray([0,4,8,1,5,9,2,6,10,3,7,11], shape=[3,4], 2235 ### flags=ND_FORTRAN) 2236 ### >>> nd.tolist() 2237 ### [[0, 1, 2, 3], 2238 ### [4, 5, 6, 7], 2239 ### [8, 9, 10, 11]] 2240 ### 2241 ### The logical array is the same, but the values in memory are now 2242 ### in Fortran order. 2243 ### 2244 ### NumPy example: 2245 ### ============== 2246 ### _testbuffer's ndarray takes lists to initialize the memory. 2247 ### Here's the same sequence in NumPy: 2248 ### 2249 ### C input: 2250 ### -------- 2251 ### >>> nd = ndarray(buffer=bytearray(list(range(12))), 2252 ### shape=[3, 4], dtype='B') 2253 ### >>> nd 2254 ### array([[ 0, 1, 2, 3], 2255 ### [ 4, 5, 6, 7], 2256 ### [ 8, 9, 10, 11]], dtype=uint8) 2257 ### 2258 ### Fortran output: 2259 ### --------------- 2260 ### >>> fortran_buf = nd.tobytes(order='F') 2261 ### >>> fortran_buf 2262 ### b'\x00\x04\x08\x01\x05\t\x02\x06\n\x03\x07\x0b' 2263 ### 2264 ### >>> nd = ndarray(buffer=fortran_buf, shape=[3, 4], 2265 ### dtype='B', order='F') 2266 ### 2267 ### >>> nd 2268 ### array([[ 0, 1, 2, 3], 2269 ### [ 4, 5, 6, 7], 2270 ### [ 8, 9, 10, 11]], dtype=uint8) 2271 ### 2272 2273 # multi-dimensional, contiguous input 2274 lst = list(range(12)) 2275 for f in [0, ND_FORTRAN]: 2276 nd = ndarray(lst, shape=[3, 4], flags=f|ND_WRITABLE) 2277 if numpy_array: 2278 na = numpy_array(buffer=bytearray(lst), 2279 shape=[3, 4], dtype='B', 2280 order='C' if f == 0 else 'F') 2281 2282 # 'C' request 2283 if f == ND_FORTRAN: # 'F' to 'C' 2284 x = ndarray(transpose(lst, [4, 3]), shape=[3, 4], 2285 flags=ND_WRITABLE) 2286 expected = x.tobytes() 2287 else: 2288 expected = nd.tobytes() 2289 for request in requests: 2290 try: 2291 b = py_buffer_to_contiguous(nd, 'C', request) 2292 except BufferError: 2293 continue 2294 2295 self.assertEqual(b, expected) 2296 2297 # Check that output can be used as the basis for constructing 2298 # a C array that is logically identical to the input array. 2299 y = ndarray([v for v in b], shape=[3, 4], flags=ND_WRITABLE) 2300 self.assertEqual(memoryview(y), memoryview(nd)) 2301 2302 if numpy_array: 2303 self.assertEqual(b, na.tobytes(order='C')) 2304 2305 # 'F' request 2306 if f == 0: # 'C' to 'F' 2307 x = ndarray(transpose(lst, [3, 4]), shape=[4, 3], 2308 flags=ND_WRITABLE) 2309 else: 2310 x = ndarray(lst, shape=[3, 4], flags=ND_WRITABLE) 2311 expected = x.tobytes() 2312 for request in [PyBUF_FULL, PyBUF_FULL_RO, PyBUF_INDIRECT, 2313 PyBUF_STRIDES, PyBUF_ND]: 2314 try: 2315 b = py_buffer_to_contiguous(nd, 'F', request) 2316 except BufferError: 2317 continue 2318 self.assertEqual(b, expected) 2319 2320 # Check that output can be used as the basis for constructing 2321 # a Fortran array that is logically identical to the input array. 2322 y = ndarray([v for v in b], shape=[3, 4], flags=ND_FORTRAN|ND_WRITABLE) 2323 self.assertEqual(memoryview(y), memoryview(nd)) 2324 2325 if numpy_array: 2326 self.assertEqual(b, na.tobytes(order='F')) 2327 2328 # 'A' request 2329 if f == ND_FORTRAN: 2330 x = ndarray(lst, shape=[3, 4], flags=ND_WRITABLE) 2331 expected = x.tobytes() 2332 else: 2333 expected = nd.tobytes() 2334 for request in [PyBUF_FULL, PyBUF_FULL_RO, PyBUF_INDIRECT, 2335 PyBUF_STRIDES, PyBUF_ND]: 2336 try: 2337 b = py_buffer_to_contiguous(nd, 'A', request) 2338 except BufferError: 2339 continue 2340 2341 self.assertEqual(b, expected) 2342 2343 # Check that output can be used as the basis for constructing 2344 # an array with order=f that is logically identical to the input 2345 # array. 2346 y = ndarray([v for v in b], shape=[3, 4], flags=f|ND_WRITABLE) 2347 self.assertEqual(memoryview(y), memoryview(nd)) 2348 2349 if numpy_array: 2350 self.assertEqual(b, na.tobytes(order='A')) 2351 2352 # multi-dimensional, non-contiguous input 2353 nd = ndarray(list(range(12)), shape=[3, 4], flags=ND_WRITABLE|ND_PIL) 2354 2355 # 'C' 2356 b = py_buffer_to_contiguous(nd, 'C', PyBUF_FULL_RO) 2357 self.assertEqual(b, nd.tobytes()) 2358 y = ndarray([v for v in b], shape=[3, 4], flags=ND_WRITABLE) 2359 self.assertEqual(memoryview(y), memoryview(nd)) 2360 2361 # 'F' 2362 b = py_buffer_to_contiguous(nd, 'F', PyBUF_FULL_RO) 2363 x = ndarray(transpose(lst, [3, 4]), shape=[4, 3], flags=ND_WRITABLE) 2364 self.assertEqual(b, x.tobytes()) 2365 y = ndarray([v for v in b], shape=[3, 4], flags=ND_FORTRAN|ND_WRITABLE) 2366 self.assertEqual(memoryview(y), memoryview(nd)) 2367 2368 # 'A' 2369 b = py_buffer_to_contiguous(nd, 'A', PyBUF_FULL_RO) 2370 self.assertEqual(b, nd.tobytes()) 2371 y = ndarray([v for v in b], shape=[3, 4], flags=ND_WRITABLE) 2372 self.assertEqual(memoryview(y), memoryview(nd)) 2373 2374 def test_memoryview_construction(self): 2375 2376 items_shape = [(9, []), ([1,2,3], [3]), (list(range(2*3*5)), [2,3,5])] 2377 2378 # NumPy style, C-contiguous: 2379 for items, shape in items_shape: 2380 2381 # From PEP-3118 compliant exporter: 2382 ex = ndarray(items, shape=shape) 2383 m = memoryview(ex) 2384 self.assertTrue(m.c_contiguous) 2385 self.assertTrue(m.contiguous) 2386 2387 ndim = len(shape) 2388 strides = strides_from_shape(ndim, shape, 1, 'C') 2389 lst = carray(items, shape) 2390 2391 self.verify(m, obj=ex, 2392 itemsize=1, fmt='B', readonly=True, 2393 ndim=ndim, shape=shape, strides=strides, 2394 lst=lst) 2395 2396 # From memoryview: 2397 m2 = memoryview(m) 2398 self.verify(m2, obj=ex, 2399 itemsize=1, fmt='B', readonly=True, 2400 ndim=ndim, shape=shape, strides=strides, 2401 lst=lst) 2402 2403 # PyMemoryView_FromBuffer(): no strides 2404 nd = ndarray(ex, getbuf=PyBUF_CONTIG_RO|PyBUF_FORMAT) 2405 self.assertEqual(nd.strides, ()) 2406 m = nd.memoryview_from_buffer() 2407 self.verify(m, obj=None, 2408 itemsize=1, fmt='B', readonly=True, 2409 ndim=ndim, shape=shape, strides=strides, 2410 lst=lst) 2411 2412 # PyMemoryView_FromBuffer(): no format, shape, strides 2413 nd = ndarray(ex, getbuf=PyBUF_SIMPLE) 2414 self.assertEqual(nd.format, '') 2415 self.assertEqual(nd.shape, ()) 2416 self.assertEqual(nd.strides, ()) 2417 m = nd.memoryview_from_buffer() 2418 2419 lst = [items] if ndim == 0 else items 2420 self.verify(m, obj=None, 2421 itemsize=1, fmt='B', readonly=True, 2422 ndim=1, shape=[ex.nbytes], strides=(1,), 2423 lst=lst) 2424 2425 # NumPy style, Fortran contiguous: 2426 for items, shape in items_shape: 2427 2428 # From PEP-3118 compliant exporter: 2429 ex = ndarray(items, shape=shape, flags=ND_FORTRAN) 2430 m = memoryview(ex) 2431 self.assertTrue(m.f_contiguous) 2432 self.assertTrue(m.contiguous) 2433 2434 ndim = len(shape) 2435 strides = strides_from_shape(ndim, shape, 1, 'F') 2436 lst = farray(items, shape) 2437 2438 self.verify(m, obj=ex, 2439 itemsize=1, fmt='B', readonly=True, 2440 ndim=ndim, shape=shape, strides=strides, 2441 lst=lst) 2442 2443 # From memoryview: 2444 m2 = memoryview(m) 2445 self.verify(m2, obj=ex, 2446 itemsize=1, fmt='B', readonly=True, 2447 ndim=ndim, shape=shape, strides=strides, 2448 lst=lst) 2449 2450 # PIL style: 2451 for items, shape in items_shape[1:]: 2452 2453 # From PEP-3118 compliant exporter: 2454 ex = ndarray(items, shape=shape, flags=ND_PIL) 2455 m = memoryview(ex) 2456 2457 ndim = len(shape) 2458 lst = carray(items, shape) 2459 2460 self.verify(m, obj=ex, 2461 itemsize=1, fmt='B', readonly=True, 2462 ndim=ndim, shape=shape, strides=ex.strides, 2463 lst=lst) 2464 2465 # From memoryview: 2466 m2 = memoryview(m) 2467 self.verify(m2, obj=ex, 2468 itemsize=1, fmt='B', readonly=True, 2469 ndim=ndim, shape=shape, strides=ex.strides, 2470 lst=lst) 2471 2472 # Invalid number of arguments: 2473 self.assertRaises(TypeError, memoryview, b'9', 'x') 2474 # Not a buffer provider: 2475 self.assertRaises(TypeError, memoryview, {}) 2476 # Non-compliant buffer provider: 2477 ex = ndarray([1,2,3], shape=[3]) 2478 nd = ndarray(ex, getbuf=PyBUF_SIMPLE) 2479 self.assertRaises(BufferError, memoryview, nd) 2480 nd = ndarray(ex, getbuf=PyBUF_CONTIG_RO|PyBUF_FORMAT) 2481 self.assertRaises(BufferError, memoryview, nd) 2482 2483 # ndim > 64 2484 nd = ndarray([1]*128, shape=[1]*128, format='L') 2485 self.assertRaises(ValueError, memoryview, nd) 2486 self.assertRaises(ValueError, nd.memoryview_from_buffer) 2487 self.assertRaises(ValueError, get_contiguous, nd, PyBUF_READ, 'C') 2488 self.assertRaises(ValueError, get_contiguous, nd, PyBUF_READ, 'F') 2489 self.assertRaises(ValueError, get_contiguous, nd[::-1], PyBUF_READ, 'C') 2490 2491 def test_memoryview_cast_zero_shape(self): 2492 # Casts are undefined if buffer is multidimensional and shape 2493 # contains zeros. These arrays are regarded as C-contiguous by 2494 # Numpy and PyBuffer_GetContiguous(), so they are not caught by 2495 # the test for C-contiguity in memory_cast(). 2496 items = [1,2,3] 2497 for shape in ([0,3,3], [3,0,3], [0,3,3]): 2498 ex = ndarray(items, shape=shape) 2499 self.assertTrue(ex.c_contiguous) 2500 msrc = memoryview(ex) 2501 self.assertRaises(TypeError, msrc.cast, 'c') 2502 # Monodimensional empty view can be cast (issue #19014). 2503 for fmt, _, _ in iter_format(1, 'memoryview'): 2504 msrc = memoryview(b'') 2505 m = msrc.cast(fmt) 2506 self.assertEqual(m.tobytes(), b'') 2507 self.assertEqual(m.tolist(), []) 2508 2509 check_sizeof = support.check_sizeof 2510 2511 def test_memoryview_sizeof(self): 2512 check = self.check_sizeof 2513 vsize = support.calcvobjsize 2514 base_struct = 'Pnin 2P2n2i5P P' 2515 per_dim = '3n' 2516 2517 items = list(range(8)) 2518 check(memoryview(b''), vsize(base_struct + 1 * per_dim)) 2519 a = ndarray(items, shape=[2, 4], format="b") 2520 check(memoryview(a), vsize(base_struct + 2 * per_dim)) 2521 a = ndarray(items, shape=[2, 2, 2], format="b") 2522 check(memoryview(a), vsize(base_struct + 3 * per_dim)) 2523 2524 def test_memoryview_struct_module(self): 2525 2526 class INT(object): 2527 def __init__(self, val): 2528 self.val = val 2529 def __int__(self): 2530 return self.val 2531 2532 class IDX(object): 2533 def __init__(self, val): 2534 self.val = val 2535 def __index__(self): 2536 return self.val 2537 2538 def f(): return 7 2539 2540 values = [INT(9), IDX(9), 2541 2.2+3j, Decimal("-21.1"), 12.2, Fraction(5, 2), 2542 [1,2,3], {4,5,6}, {7:8}, (), (9,), 2543 True, False, None, Ellipsis, 2544 b'a', b'abc', bytearray(b'a'), bytearray(b'abc'), 2545 'a', 'abc', r'a', r'abc', 2546 f, lambda x: x] 2547 2548 for fmt, items, item in iter_format(10, 'memoryview'): 2549 ex = ndarray(items, shape=[10], format=fmt, flags=ND_WRITABLE) 2550 nd = ndarray(items, shape=[10], format=fmt, flags=ND_WRITABLE) 2551 m = memoryview(ex) 2552 2553 struct.pack_into(fmt, nd, 0, item) 2554 m[0] = item 2555 self.assertEqual(m[0], nd[0]) 2556 2557 itemsize = struct.calcsize(fmt) 2558 if 'P' in fmt: 2559 continue 2560 2561 for v in values: 2562 struct_err = None 2563 try: 2564 struct.pack_into(fmt, nd, itemsize, v) 2565 except struct.error: 2566 struct_err = struct.error 2567 2568 mv_err = None 2569 try: 2570 m[1] = v 2571 except (TypeError, ValueError) as e: 2572 mv_err = e.__class__ 2573 2574 if struct_err or mv_err: 2575 self.assertIsNot(struct_err, None) 2576 self.assertIsNot(mv_err, None) 2577 else: 2578 self.assertEqual(m[1], nd[1]) 2579 2580 def test_memoryview_cast_zero_strides(self): 2581 # Casts are undefined if strides contains zeros. These arrays are 2582 # (sometimes!) regarded as C-contiguous by Numpy, but not by 2583 # PyBuffer_GetContiguous(). 2584 ex = ndarray([1,2,3], shape=[3], strides=[0]) 2585 self.assertFalse(ex.c_contiguous) 2586 msrc = memoryview(ex) 2587 self.assertRaises(TypeError, msrc.cast, 'c') 2588 2589 def test_memoryview_cast_invalid(self): 2590 # invalid format 2591 for sfmt in NON_BYTE_FORMAT: 2592 sformat = '@' + sfmt if randrange(2) else sfmt 2593 ssize = struct.calcsize(sformat) 2594 for dfmt in NON_BYTE_FORMAT: 2595 dformat = '@' + dfmt if randrange(2) else dfmt 2596 dsize = struct.calcsize(dformat) 2597 ex = ndarray(list(range(32)), shape=[32//ssize], format=sformat) 2598 msrc = memoryview(ex) 2599 self.assertRaises(TypeError, msrc.cast, dfmt, [32//dsize]) 2600 2601 for sfmt, sitems, _ in iter_format(1): 2602 ex = ndarray(sitems, shape=[1], format=sfmt) 2603 msrc = memoryview(ex) 2604 for dfmt, _, _ in iter_format(1): 2605 if not is_memoryview_format(dfmt): 2606 self.assertRaises(ValueError, msrc.cast, dfmt, 2607 [32//dsize]) 2608 else: 2609 if not is_byte_format(sfmt) and not is_byte_format(dfmt): 2610 self.assertRaises(TypeError, msrc.cast, dfmt, 2611 [32//dsize]) 2612 2613 # invalid shape 2614 size_h = struct.calcsize('h') 2615 size_d = struct.calcsize('d') 2616 ex = ndarray(list(range(2*2*size_d)), shape=[2,2,size_d], format='h') 2617 msrc = memoryview(ex) 2618 self.assertRaises(TypeError, msrc.cast, shape=[2,2,size_h], format='d') 2619 2620 ex = ndarray(list(range(120)), shape=[1,2,3,4,5]) 2621 m = memoryview(ex) 2622 2623 # incorrect number of args 2624 self.assertRaises(TypeError, m.cast) 2625 self.assertRaises(TypeError, m.cast, 1, 2, 3) 2626 2627 # incorrect dest format type 2628 self.assertRaises(TypeError, m.cast, {}) 2629 2630 # incorrect dest format 2631 self.assertRaises(ValueError, m.cast, "X") 2632 self.assertRaises(ValueError, m.cast, "@X") 2633 self.assertRaises(ValueError, m.cast, "@XY") 2634 2635 # dest format not implemented 2636 self.assertRaises(ValueError, m.cast, "=B") 2637 self.assertRaises(ValueError, m.cast, "!L") 2638 self.assertRaises(ValueError, m.cast, "<P") 2639 self.assertRaises(ValueError, m.cast, ">l") 2640 self.assertRaises(ValueError, m.cast, "BI") 2641 self.assertRaises(ValueError, m.cast, "xBI") 2642 2643 # src format not implemented 2644 ex = ndarray([(1,2), (3,4)], shape=[2], format="II") 2645 m = memoryview(ex) 2646 self.assertRaises(NotImplementedError, m.__getitem__, 0) 2647 self.assertRaises(NotImplementedError, m.__setitem__, 0, 8) 2648 self.assertRaises(NotImplementedError, m.tolist) 2649 2650 # incorrect shape type 2651 ex = ndarray(list(range(120)), shape=[1,2,3,4,5]) 2652 m = memoryview(ex) 2653 self.assertRaises(TypeError, m.cast, "B", shape={}) 2654 2655 # incorrect shape elements 2656 ex = ndarray(list(range(120)), shape=[2*3*4*5]) 2657 m = memoryview(ex) 2658 self.assertRaises(OverflowError, m.cast, "B", shape=[2**64]) 2659 self.assertRaises(ValueError, m.cast, "B", shape=[-1]) 2660 self.assertRaises(ValueError, m.cast, "B", shape=[2,3,4,5,6,7,-1]) 2661 self.assertRaises(ValueError, m.cast, "B", shape=[2,3,4,5,6,7,0]) 2662 self.assertRaises(TypeError, m.cast, "B", shape=[2,3,4,5,6,7,'x']) 2663 2664 # N-D -> N-D cast 2665 ex = ndarray(list([9 for _ in range(3*5*7*11)]), shape=[3,5,7,11]) 2666 m = memoryview(ex) 2667 self.assertRaises(TypeError, m.cast, "I", shape=[2,3,4,5]) 2668 2669 # cast with ndim > 64 2670 nd = ndarray(list(range(128)), shape=[128], format='I') 2671 m = memoryview(nd) 2672 self.assertRaises(ValueError, m.cast, 'I', [1]*128) 2673 2674 # view->len not a multiple of itemsize 2675 ex = ndarray(list([9 for _ in range(3*5*7*11)]), shape=[3*5*7*11]) 2676 m = memoryview(ex) 2677 self.assertRaises(TypeError, m.cast, "I", shape=[2,3,4,5]) 2678 2679 # product(shape) * itemsize != buffer size 2680 ex = ndarray(list([9 for _ in range(3*5*7*11)]), shape=[3*5*7*11]) 2681 m = memoryview(ex) 2682 self.assertRaises(TypeError, m.cast, "B", shape=[2,3,4,5]) 2683 2684 # product(shape) * itemsize overflow 2685 nd = ndarray(list(range(128)), shape=[128], format='I') 2686 m1 = memoryview(nd) 2687 nd = ndarray(list(range(128)), shape=[128], format='B') 2688 m2 = memoryview(nd) 2689 if sys.maxsize == 2**63-1: 2690 self.assertRaises(TypeError, m1.cast, 'B', 2691 [7, 7, 73, 127, 337, 92737, 649657]) 2692 self.assertRaises(ValueError, m1.cast, 'B', 2693 [2**20, 2**20, 2**10, 2**10, 2**3]) 2694 self.assertRaises(ValueError, m2.cast, 'I', 2695 [2**20, 2**20, 2**10, 2**10, 2**1]) 2696 else: 2697 self.assertRaises(TypeError, m1.cast, 'B', 2698 [1, 2147483647]) 2699 self.assertRaises(ValueError, m1.cast, 'B', 2700 [2**10, 2**10, 2**5, 2**5, 2**1]) 2701 self.assertRaises(ValueError, m2.cast, 'I', 2702 [2**10, 2**10, 2**5, 2**3, 2**1]) 2703 2704 def test_memoryview_cast(self): 2705 bytespec = ( 2706 ('B', lambda ex: list(ex.tobytes())), 2707 ('b', lambda ex: [x-256 if x > 127 else x for x in list(ex.tobytes())]), 2708 ('c', lambda ex: [bytes(chr(x), 'latin-1') for x in list(ex.tobytes())]), 2709 ) 2710 2711 def iter_roundtrip(ex, m, items, fmt): 2712 srcsize = struct.calcsize(fmt) 2713 for bytefmt, to_bytelist in bytespec: 2714 2715 m2 = m.cast(bytefmt) 2716 lst = to_bytelist(ex) 2717 self.verify(m2, obj=ex, 2718 itemsize=1, fmt=bytefmt, readonly=False, 2719 ndim=1, shape=[31*srcsize], strides=(1,), 2720 lst=lst, cast=True) 2721 2722 m3 = m2.cast(fmt) 2723 self.assertEqual(m3, ex) 2724 lst = ex.tolist() 2725 self.verify(m3, obj=ex, 2726 itemsize=srcsize, fmt=fmt, readonly=False, 2727 ndim=1, shape=[31], strides=(srcsize,), 2728 lst=lst, cast=True) 2729 2730 # cast from ndim = 0 to ndim = 1 2731 srcsize = struct.calcsize('I') 2732 ex = ndarray(9, shape=[], format='I') 2733 destitems, destshape = cast_items(ex, 'B', 1) 2734 m = memoryview(ex) 2735 m2 = m.cast('B') 2736 self.verify(m2, obj=ex, 2737 itemsize=1, fmt='B', readonly=True, 2738 ndim=1, shape=destshape, strides=(1,), 2739 lst=destitems, cast=True) 2740 2741 # cast from ndim = 1 to ndim = 0 2742 destsize = struct.calcsize('I') 2743 ex = ndarray([9]*destsize, shape=[destsize], format='B') 2744 destitems, destshape = cast_items(ex, 'I', destsize, shape=[]) 2745 m = memoryview(ex) 2746 m2 = m.cast('I', shape=[]) 2747 self.verify(m2, obj=ex, 2748 itemsize=destsize, fmt='I', readonly=True, 2749 ndim=0, shape=(), strides=(), 2750 lst=destitems, cast=True) 2751 2752 # array.array: roundtrip to/from bytes 2753 for fmt, items, _ in iter_format(31, 'array'): 2754 ex = array.array(fmt, items) 2755 m = memoryview(ex) 2756 iter_roundtrip(ex, m, items, fmt) 2757 2758 # ndarray: roundtrip to/from bytes 2759 for fmt, items, _ in iter_format(31, 'memoryview'): 2760 ex = ndarray(items, shape=[31], format=fmt, flags=ND_WRITABLE) 2761 m = memoryview(ex) 2762 iter_roundtrip(ex, m, items, fmt) 2763 2764 @support.requires_resource('cpu') 2765 def test_memoryview_cast_1D_ND(self): 2766 # Cast between C-contiguous buffers. At least one buffer must 2767 # be 1D, at least one format must be 'c', 'b' or 'B'. 2768 for _tshape in gencastshapes(): 2769 for char in fmtdict['@']: 2770 # Casts to _Bool are undefined if the source contains values 2771 # other than 0 or 1. 2772 if char == "?": 2773 continue 2774 tfmt = ('', '@')[randrange(2)] + char 2775 tsize = struct.calcsize(tfmt) 2776 n = prod(_tshape) * tsize 2777 obj = 'memoryview' if is_byte_format(tfmt) else 'bytefmt' 2778 for fmt, items, _ in iter_format(n, obj): 2779 size = struct.calcsize(fmt) 2780 shape = [n] if n > 0 else [] 2781 tshape = _tshape + [size] 2782 2783 ex = ndarray(items, shape=shape, format=fmt) 2784 m = memoryview(ex) 2785 2786 titems, tshape = cast_items(ex, tfmt, tsize, shape=tshape) 2787 2788 if titems is None: 2789 self.assertRaises(TypeError, m.cast, tfmt, tshape) 2790 continue 2791 if titems == 'nan': 2792 continue # NaNs in lists are a recipe for trouble. 2793 2794 # 1D -> ND 2795 nd = ndarray(titems, shape=tshape, format=tfmt) 2796 2797 m2 = m.cast(tfmt, shape=tshape) 2798 ndim = len(tshape) 2799 strides = nd.strides 2800 lst = nd.tolist() 2801 self.verify(m2, obj=ex, 2802 itemsize=tsize, fmt=tfmt, readonly=True, 2803 ndim=ndim, shape=tshape, strides=strides, 2804 lst=lst, cast=True) 2805 2806 # ND -> 1D 2807 m3 = m2.cast(fmt) 2808 m4 = m2.cast(fmt, shape=shape) 2809 ndim = len(shape) 2810 strides = ex.strides 2811 lst = ex.tolist() 2812 2813 self.verify(m3, obj=ex, 2814 itemsize=size, fmt=fmt, readonly=True, 2815 ndim=ndim, shape=shape, strides=strides, 2816 lst=lst, cast=True) 2817 2818 self.verify(m4, obj=ex, 2819 itemsize=size, fmt=fmt, readonly=True, 2820 ndim=ndim, shape=shape, strides=strides, 2821 lst=lst, cast=True) 2822 2823 if ctypes: 2824 # format: "T{>l:x:>d:y:}" 2825 class BEPoint(ctypes.BigEndianStructure): 2826 _fields_ = [("x", ctypes.c_long), ("y", ctypes.c_double)] 2827 point = BEPoint(100, 200.1) 2828 m1 = memoryview(point) 2829 m2 = m1.cast('B') 2830 self.assertEqual(m2.obj, point) 2831 self.assertEqual(m2.itemsize, 1) 2832 self.assertIs(m2.readonly, False) 2833 self.assertEqual(m2.ndim, 1) 2834 self.assertEqual(m2.shape, (m2.nbytes,)) 2835 self.assertEqual(m2.strides, (1,)) 2836 self.assertEqual(m2.suboffsets, ()) 2837 2838 x = ctypes.c_double(1.2) 2839 m1 = memoryview(x) 2840 m2 = m1.cast('c') 2841 self.assertEqual(m2.obj, x) 2842 self.assertEqual(m2.itemsize, 1) 2843 self.assertIs(m2.readonly, False) 2844 self.assertEqual(m2.ndim, 1) 2845 self.assertEqual(m2.shape, (m2.nbytes,)) 2846 self.assertEqual(m2.strides, (1,)) 2847 self.assertEqual(m2.suboffsets, ()) 2848 2849 def test_memoryview_tolist(self): 2850 2851 # Most tolist() tests are in self.verify() etc. 2852 2853 a = array.array('h', list(range(-6, 6))) 2854 m = memoryview(a) 2855 self.assertEqual(m, a) 2856 self.assertEqual(m.tolist(), a.tolist()) 2857 2858 a = a[2::3] 2859 m = m[2::3] 2860 self.assertEqual(m, a) 2861 self.assertEqual(m.tolist(), a.tolist()) 2862 2863 ex = ndarray(list(range(2*3*5*7*11)), shape=[11,2,7,3,5], format='L') 2864 m = memoryview(ex) 2865 self.assertEqual(m.tolist(), ex.tolist()) 2866 2867 ex = ndarray([(2, 5), (7, 11)], shape=[2], format='lh') 2868 m = memoryview(ex) 2869 self.assertRaises(NotImplementedError, m.tolist) 2870 2871 ex = ndarray([b'12345'], shape=[1], format="s") 2872 m = memoryview(ex) 2873 self.assertRaises(NotImplementedError, m.tolist) 2874 2875 ex = ndarray([b"a",b"b",b"c",b"d",b"e",b"f"], shape=[2,3], format='s') 2876 m = memoryview(ex) 2877 self.assertRaises(NotImplementedError, m.tolist) 2878 2879 def test_memoryview_repr(self): 2880 m = memoryview(bytearray(9)) 2881 r = m.__repr__() 2882 self.assertTrue(r.startswith("<memory")) 2883 2884 m.release() 2885 r = m.__repr__() 2886 self.assertTrue(r.startswith("<released")) 2887 2888 def test_memoryview_sequence(self): 2889 2890 for fmt in ('d', 'f'): 2891 inf = float(3e400) 2892 ex = array.array(fmt, [1.0, inf, 3.0]) 2893 m = memoryview(ex) 2894 self.assertIn(1.0, m) 2895 self.assertIn(5e700, m) 2896 self.assertIn(3.0, m) 2897 2898 ex = ndarray(9.0, [], format='f') 2899 m = memoryview(ex) 2900 self.assertRaises(TypeError, eval, "9.0 in m", locals()) 2901 2902 @contextlib.contextmanager 2903 def assert_out_of_bounds_error(self, dim): 2904 with self.assertRaises(IndexError) as cm: 2905 yield 2906 self.assertEqual(str(cm.exception), 2907 "index out of bounds on dimension %d" % (dim,)) 2908 2909 def test_memoryview_index(self): 2910 2911 # ndim = 0 2912 ex = ndarray(12.5, shape=[], format='d') 2913 m = memoryview(ex) 2914 self.assertEqual(m[()], 12.5) 2915 self.assertEqual(m[...], m) 2916 self.assertEqual(m[...], ex) 2917 self.assertRaises(TypeError, m.__getitem__, 0) 2918 2919 ex = ndarray((1,2,3), shape=[], format='iii') 2920 m = memoryview(ex) 2921 self.assertRaises(NotImplementedError, m.__getitem__, ()) 2922 2923 # range 2924 ex = ndarray(list(range(7)), shape=[7], flags=ND_WRITABLE) 2925 m = memoryview(ex) 2926 2927 self.assertRaises(IndexError, m.__getitem__, 2**64) 2928 self.assertRaises(TypeError, m.__getitem__, 2.0) 2929 self.assertRaises(TypeError, m.__getitem__, 0.0) 2930 2931 # out of bounds 2932 self.assertRaises(IndexError, m.__getitem__, -8) 2933 self.assertRaises(IndexError, m.__getitem__, 8) 2934 2935 # multi-dimensional 2936 ex = ndarray(list(range(12)), shape=[3,4], flags=ND_WRITABLE) 2937 m = memoryview(ex) 2938 2939 self.assertEqual(m[0, 0], 0) 2940 self.assertEqual(m[2, 0], 8) 2941 self.assertEqual(m[2, 3], 11) 2942 self.assertEqual(m[-1, -1], 11) 2943 self.assertEqual(m[-3, -4], 0) 2944 2945 # out of bounds 2946 for index in (3, -4): 2947 with self.assert_out_of_bounds_error(dim=1): 2948 m[index, 0] 2949 for index in (4, -5): 2950 with self.assert_out_of_bounds_error(dim=2): 2951 m[0, index] 2952 self.assertRaises(IndexError, m.__getitem__, (2**64, 0)) 2953 self.assertRaises(IndexError, m.__getitem__, (0, 2**64)) 2954 2955 self.assertRaises(TypeError, m.__getitem__, (0, 0, 0)) 2956 self.assertRaises(TypeError, m.__getitem__, (0.0, 0.0)) 2957 2958 # Not implemented: multidimensional sub-views 2959 self.assertRaises(NotImplementedError, m.__getitem__, ()) 2960 self.assertRaises(NotImplementedError, m.__getitem__, 0) 2961 2962 def test_memoryview_assign(self): 2963 2964 # ndim = 0 2965 ex = ndarray(12.5, shape=[], format='f', flags=ND_WRITABLE) 2966 m = memoryview(ex) 2967 m[()] = 22.5 2968 self.assertEqual(m[()], 22.5) 2969 m[...] = 23.5 2970 self.assertEqual(m[()], 23.5) 2971 self.assertRaises(TypeError, m.__setitem__, 0, 24.7) 2972 2973 # read-only 2974 ex = ndarray(list(range(7)), shape=[7]) 2975 m = memoryview(ex) 2976 self.assertRaises(TypeError, m.__setitem__, 2, 10) 2977 2978 # range 2979 ex = ndarray(list(range(7)), shape=[7], flags=ND_WRITABLE) 2980 m = memoryview(ex) 2981 2982 self.assertRaises(IndexError, m.__setitem__, 2**64, 9) 2983 self.assertRaises(TypeError, m.__setitem__, 2.0, 10) 2984 self.assertRaises(TypeError, m.__setitem__, 0.0, 11) 2985 2986 # out of bounds 2987 self.assertRaises(IndexError, m.__setitem__, -8, 20) 2988 self.assertRaises(IndexError, m.__setitem__, 8, 25) 2989 2990 # pack_single() success: 2991 for fmt in fmtdict['@']: 2992 if fmt == 'c' or fmt == '?': 2993 continue 2994 ex = ndarray([1,2,3], shape=[3], format=fmt, flags=ND_WRITABLE) 2995 m = memoryview(ex) 2996 i = randrange(-3, 3) 2997 m[i] = 8 2998 self.assertEqual(m[i], 8) 2999 self.assertEqual(m[i], ex[i]) 3000 3001 ex = ndarray([b'1', b'2', b'3'], shape=[3], format='c', 3002 flags=ND_WRITABLE) 3003 m = memoryview(ex) 3004 m[2] = b'9' 3005 self.assertEqual(m[2], b'9') 3006 3007 ex = ndarray([True, False, True], shape=[3], format='?', 3008 flags=ND_WRITABLE) 3009 m = memoryview(ex) 3010 m[1] = True 3011 self.assertIs(m[1], True) 3012 3013 # pack_single() exceptions: 3014 nd = ndarray([b'x'], shape=[1], format='c', flags=ND_WRITABLE) 3015 m = memoryview(nd) 3016 self.assertRaises(TypeError, m.__setitem__, 0, 100) 3017 3018 ex = ndarray(list(range(120)), shape=[1,2,3,4,5], flags=ND_WRITABLE) 3019 m1 = memoryview(ex) 3020 3021 for fmt, _range in fmtdict['@'].items(): 3022 if (fmt == '?'): # PyObject_IsTrue() accepts anything 3023 continue 3024 if fmt == 'c': # special case tested above 3025 continue 3026 m2 = m1.cast(fmt) 3027 lo, hi = _range 3028 if fmt == 'd' or fmt == 'f': 3029 lo, hi = -2**1024, 2**1024 3030 if fmt != 'P': # PyLong_AsVoidPtr() accepts negative numbers 3031 self.assertRaises(ValueError, m2.__setitem__, 0, lo-1) 3032 self.assertRaises(TypeError, m2.__setitem__, 0, "xyz") 3033 self.assertRaises(ValueError, m2.__setitem__, 0, hi) 3034 3035 # invalid item 3036 m2 = m1.cast('c') 3037 self.assertRaises(ValueError, m2.__setitem__, 0, b'\xff\xff') 3038 3039 # format not implemented 3040 ex = ndarray(list(range(1)), shape=[1], format="xL", flags=ND_WRITABLE) 3041 m = memoryview(ex) 3042 self.assertRaises(NotImplementedError, m.__setitem__, 0, 1) 3043 3044 ex = ndarray([b'12345'], shape=[1], format="s", flags=ND_WRITABLE) 3045 m = memoryview(ex) 3046 self.assertRaises(NotImplementedError, m.__setitem__, 0, 1) 3047 3048 # multi-dimensional 3049 ex = ndarray(list(range(12)), shape=[3,4], flags=ND_WRITABLE) 3050 m = memoryview(ex) 3051 m[0,1] = 42 3052 self.assertEqual(ex[0][1], 42) 3053 m[-1,-1] = 43 3054 self.assertEqual(ex[2][3], 43) 3055 # errors 3056 for index in (3, -4): 3057 with self.assert_out_of_bounds_error(dim=1): 3058 m[index, 0] = 0 3059 for index in (4, -5): 3060 with self.assert_out_of_bounds_error(dim=2): 3061 m[0, index] = 0 3062 self.assertRaises(IndexError, m.__setitem__, (2**64, 0), 0) 3063 self.assertRaises(IndexError, m.__setitem__, (0, 2**64), 0) 3064 3065 self.assertRaises(TypeError, m.__setitem__, (0, 0, 0), 0) 3066 self.assertRaises(TypeError, m.__setitem__, (0.0, 0.0), 0) 3067 3068 # Not implemented: multidimensional sub-views 3069 self.assertRaises(NotImplementedError, m.__setitem__, 0, [2, 3]) 3070 3071 def test_memoryview_slice(self): 3072 3073 ex = ndarray(list(range(12)), shape=[12], flags=ND_WRITABLE) 3074 m = memoryview(ex) 3075 3076 # zero step 3077 self.assertRaises(ValueError, m.__getitem__, slice(0,2,0)) 3078 self.assertRaises(ValueError, m.__setitem__, slice(0,2,0), 3079 bytearray([1,2])) 3080 3081 # 0-dim slicing (identity function) 3082 self.assertRaises(NotImplementedError, m.__getitem__, ()) 3083 3084 # multidimensional slices 3085 ex = ndarray(list(range(12)), shape=[12], flags=ND_WRITABLE) 3086 m = memoryview(ex) 3087 3088 self.assertRaises(NotImplementedError, m.__getitem__, 3089 (slice(0,2,1), slice(0,2,1))) 3090 self.assertRaises(NotImplementedError, m.__setitem__, 3091 (slice(0,2,1), slice(0,2,1)), bytearray([1,2])) 3092 3093 # invalid slice tuple 3094 self.assertRaises(TypeError, m.__getitem__, (slice(0,2,1), {})) 3095 self.assertRaises(TypeError, m.__setitem__, (slice(0,2,1), {}), 3096 bytearray([1,2])) 3097 3098 # rvalue is not an exporter 3099 self.assertRaises(TypeError, m.__setitem__, slice(0,1,1), [1]) 3100 3101 # non-contiguous slice assignment 3102 for flags in (0, ND_PIL): 3103 ex1 = ndarray(list(range(12)), shape=[12], strides=[-1], offset=11, 3104 flags=ND_WRITABLE|flags) 3105 ex2 = ndarray(list(range(24)), shape=[12], strides=[2], flags=flags) 3106 m1 = memoryview(ex1) 3107 m2 = memoryview(ex2) 3108 3109 ex1[2:5] = ex1[2:5] 3110 m1[2:5] = m2[2:5] 3111 3112 self.assertEqual(m1, ex1) 3113 self.assertEqual(m2, ex2) 3114 3115 ex1[1:3][::-1] = ex2[0:2][::1] 3116 m1[1:3][::-1] = m2[0:2][::1] 3117 3118 self.assertEqual(m1, ex1) 3119 self.assertEqual(m2, ex2) 3120 3121 ex1[4:1:-2][::-1] = ex1[1:4:2][::1] 3122 m1[4:1:-2][::-1] = m1[1:4:2][::1] 3123 3124 self.assertEqual(m1, ex1) 3125 self.assertEqual(m2, ex2) 3126 3127 def test_memoryview_array(self): 3128 3129 def cmptest(testcase, a, b, m, singleitem): 3130 for i, _ in enumerate(a): 3131 ai = a[i] 3132 mi = m[i] 3133 testcase.assertEqual(ai, mi) 3134 a[i] = singleitem 3135 if singleitem != ai: 3136 testcase.assertNotEqual(a, m) 3137 testcase.assertNotEqual(a, b) 3138 else: 3139 testcase.assertEqual(a, m) 3140 testcase.assertEqual(a, b) 3141 m[i] = singleitem 3142 testcase.assertEqual(a, m) 3143 testcase.assertEqual(b, m) 3144 a[i] = ai 3145 m[i] = mi 3146 3147 for n in range(1, 5): 3148 for fmt, items, singleitem in iter_format(n, 'array'): 3149 for lslice in genslices(n): 3150 for rslice in genslices(n): 3151 3152 a = array.array(fmt, items) 3153 b = array.array(fmt, items) 3154 m = memoryview(b) 3155 3156 self.assertEqual(m, a) 3157 self.assertEqual(m.tolist(), a.tolist()) 3158 self.assertEqual(m.tobytes(), a.tobytes()) 3159 self.assertEqual(len(m), len(a)) 3160 3161 cmptest(self, a, b, m, singleitem) 3162 3163 array_err = None 3164 have_resize = None 3165 try: 3166 al = a[lslice] 3167 ar = a[rslice] 3168 a[lslice] = a[rslice] 3169 have_resize = len(al) != len(ar) 3170 except Exception as e: 3171 array_err = e.__class__ 3172 3173 m_err = None 3174 try: 3175 m[lslice] = m[rslice] 3176 except Exception as e: 3177 m_err = e.__class__ 3178 3179 if have_resize: # memoryview cannot change shape 3180 self.assertIs(m_err, ValueError) 3181 elif m_err or array_err: 3182 self.assertIs(m_err, array_err) 3183 else: 3184 self.assertEqual(m, a) 3185 self.assertEqual(m.tolist(), a.tolist()) 3186 self.assertEqual(m.tobytes(), a.tobytes()) 3187 cmptest(self, a, b, m, singleitem) 3188 3189 def test_memoryview_compare_special_cases(self): 3190 3191 a = array.array('L', [1, 2, 3]) 3192 b = array.array('L', [1, 2, 7]) 3193 3194 # Ordering comparisons raise: 3195 v = memoryview(a) 3196 w = memoryview(b) 3197 for attr in ('__lt__', '__le__', '__gt__', '__ge__'): 3198 self.assertIs(getattr(v, attr)(w), NotImplemented) 3199 self.assertIs(getattr(a, attr)(v), NotImplemented) 3200 3201 # Released views compare equal to themselves: 3202 v = memoryview(a) 3203 v.release() 3204 self.assertEqual(v, v) 3205 self.assertNotEqual(v, a) 3206 self.assertNotEqual(a, v) 3207 3208 v = memoryview(a) 3209 w = memoryview(a) 3210 w.release() 3211 self.assertNotEqual(v, w) 3212 self.assertNotEqual(w, v) 3213 3214 # Operand does not implement the buffer protocol: 3215 v = memoryview(a) 3216 self.assertNotEqual(v, [1, 2, 3]) 3217 3218 # NaNs 3219 nd = ndarray([(0, 0)], shape=[1], format='l x d x', flags=ND_WRITABLE) 3220 nd[0] = (-1, float('nan')) 3221 self.assertNotEqual(memoryview(nd), nd) 3222 3223 # Some ctypes format strings are unknown to the struct module. 3224 if ctypes: 3225 # format: "T{>l:x:>l:y:}" 3226 class BEPoint(ctypes.BigEndianStructure): 3227 _fields_ = [("x", ctypes.c_long), ("y", ctypes.c_long)] 3228 point = BEPoint(100, 200) 3229 a = memoryview(point) 3230 b = memoryview(point) 3231 self.assertNotEqual(a, b) 3232 self.assertNotEqual(a, point) 3233 self.assertNotEqual(point, a) 3234 self.assertRaises(NotImplementedError, a.tolist) 3235 3236 @warnings_helper.ignore_warnings(category=DeprecationWarning) # gh-80480 array('u') 3237 def test_memoryview_compare_special_cases_deprecated_u_type_code(self): 3238 3239 # Depends on issue #15625: the struct module does not understand 'u'. 3240 a = array.array('u', 'xyz') 3241 v = memoryview(a) 3242 self.assertNotEqual(a, v) 3243 self.assertNotEqual(v, a) 3244 3245 def test_memoryview_compare_ndim_zero(self): 3246 3247 nd1 = ndarray(1729, shape=[], format='@L') 3248 nd2 = ndarray(1729, shape=[], format='L', flags=ND_WRITABLE) 3249 v = memoryview(nd1) 3250 w = memoryview(nd2) 3251 self.assertEqual(v, w) 3252 self.assertEqual(w, v) 3253 self.assertEqual(v, nd2) 3254 self.assertEqual(nd2, v) 3255 self.assertEqual(w, nd1) 3256 self.assertEqual(nd1, w) 3257 3258 self.assertFalse(v.__ne__(w)) 3259 self.assertFalse(w.__ne__(v)) 3260 3261 w[()] = 1728 3262 self.assertNotEqual(v, w) 3263 self.assertNotEqual(w, v) 3264 self.assertNotEqual(v, nd2) 3265 self.assertNotEqual(nd2, v) 3266 self.assertNotEqual(w, nd1) 3267 self.assertNotEqual(nd1, w) 3268 3269 self.assertFalse(v.__eq__(w)) 3270 self.assertFalse(w.__eq__(v)) 3271 3272 nd = ndarray(list(range(12)), shape=[12], flags=ND_WRITABLE|ND_PIL) 3273 ex = ndarray(list(range(12)), shape=[12], flags=ND_WRITABLE|ND_PIL) 3274 m = memoryview(ex) 3275 3276 self.assertEqual(m, nd) 3277 m[9] = 100 3278 self.assertNotEqual(m, nd) 3279 3280 # struct module: equal 3281 nd1 = ndarray((1729, 1.2, b'12345'), shape=[], format='Lf5s') 3282 nd2 = ndarray((1729, 1.2, b'12345'), shape=[], format='hf5s', 3283 flags=ND_WRITABLE) 3284 v = memoryview(nd1) 3285 w = memoryview(nd2) 3286 self.assertEqual(v, w) 3287 self.assertEqual(w, v) 3288 self.assertEqual(v, nd2) 3289 self.assertEqual(nd2, v) 3290 self.assertEqual(w, nd1) 3291 self.assertEqual(nd1, w) 3292 3293 # struct module: not equal 3294 nd1 = ndarray((1729, 1.2, b'12345'), shape=[], format='Lf5s') 3295 nd2 = ndarray((-1729, 1.2, b'12345'), shape=[], format='hf5s', 3296 flags=ND_WRITABLE) 3297 v = memoryview(nd1) 3298 w = memoryview(nd2) 3299 self.assertNotEqual(v, w) 3300 self.assertNotEqual(w, v) 3301 self.assertNotEqual(v, nd2) 3302 self.assertNotEqual(nd2, v) 3303 self.assertNotEqual(w, nd1) 3304 self.assertNotEqual(nd1, w) 3305 self.assertEqual(v, nd1) 3306 self.assertEqual(w, nd2) 3307 3308 def test_memoryview_compare_ndim_one(self): 3309 3310 # contiguous 3311 nd1 = ndarray([-529, 576, -625, 676, -729], shape=[5], format='@h') 3312 nd2 = ndarray([-529, 576, -625, 676, 729], shape=[5], format='@h') 3313 v = memoryview(nd1) 3314 w = memoryview(nd2) 3315 3316 self.assertEqual(v, nd1) 3317 self.assertEqual(w, nd2) 3318 self.assertNotEqual(v, nd2) 3319 self.assertNotEqual(w, nd1) 3320 self.assertNotEqual(v, w) 3321 3322 # contiguous, struct module 3323 nd1 = ndarray([-529, 576, -625, 676, -729], shape=[5], format='<i') 3324 nd2 = ndarray([-529, 576, -625, 676, 729], shape=[5], format='>h') 3325 v = memoryview(nd1) 3326 w = memoryview(nd2) 3327 3328 self.assertEqual(v, nd1) 3329 self.assertEqual(w, nd2) 3330 self.assertNotEqual(v, nd2) 3331 self.assertNotEqual(w, nd1) 3332 self.assertNotEqual(v, w) 3333 3334 # non-contiguous 3335 nd1 = ndarray([-529, -625, -729], shape=[3], format='@h') 3336 nd2 = ndarray([-529, 576, -625, 676, -729], shape=[5], format='@h') 3337 v = memoryview(nd1) 3338 w = memoryview(nd2) 3339 3340 self.assertEqual(v, nd2[::2]) 3341 self.assertEqual(w[::2], nd1) 3342 self.assertEqual(v, w[::2]) 3343 self.assertEqual(v[::-1], w[::-2]) 3344 3345 # non-contiguous, struct module 3346 nd1 = ndarray([-529, -625, -729], shape=[3], format='!h') 3347 nd2 = ndarray([-529, 576, -625, 676, -729], shape=[5], format='<l') 3348 v = memoryview(nd1) 3349 w = memoryview(nd2) 3350 3351 self.assertEqual(v, nd2[::2]) 3352 self.assertEqual(w[::2], nd1) 3353 self.assertEqual(v, w[::2]) 3354 self.assertEqual(v[::-1], w[::-2]) 3355 3356 # non-contiguous, suboffsets 3357 nd1 = ndarray([-529, -625, -729], shape=[3], format='@h') 3358 nd2 = ndarray([-529, 576, -625, 676, -729], shape=[5], format='@h', 3359 flags=ND_PIL) 3360 v = memoryview(nd1) 3361 w = memoryview(nd2) 3362 3363 self.assertEqual(v, nd2[::2]) 3364 self.assertEqual(w[::2], nd1) 3365 self.assertEqual(v, w[::2]) 3366 self.assertEqual(v[::-1], w[::-2]) 3367 3368 # non-contiguous, suboffsets, struct module 3369 nd1 = ndarray([-529, -625, -729], shape=[3], format='h 0c') 3370 nd2 = ndarray([-529, 576, -625, 676, -729], shape=[5], format='> h', 3371 flags=ND_PIL) 3372 v = memoryview(nd1) 3373 w = memoryview(nd2) 3374 3375 self.assertEqual(v, nd2[::2]) 3376 self.assertEqual(w[::2], nd1) 3377 self.assertEqual(v, w[::2]) 3378 self.assertEqual(v[::-1], w[::-2]) 3379 3380 def test_memoryview_compare_zero_shape(self): 3381 3382 # zeros in shape 3383 nd1 = ndarray([900, 961], shape=[0], format='@h') 3384 nd2 = ndarray([-900, -961], shape=[0], format='@h') 3385 v = memoryview(nd1) 3386 w = memoryview(nd2) 3387 3388 self.assertEqual(v, nd1) 3389 self.assertEqual(w, nd2) 3390 self.assertEqual(v, nd2) 3391 self.assertEqual(w, nd1) 3392 self.assertEqual(v, w) 3393 3394 # zeros in shape, struct module 3395 nd1 = ndarray([900, 961], shape=[0], format='= h0c') 3396 nd2 = ndarray([-900, -961], shape=[0], format='@ i') 3397 v = memoryview(nd1) 3398 w = memoryview(nd2) 3399 3400 self.assertEqual(v, nd1) 3401 self.assertEqual(w, nd2) 3402 self.assertEqual(v, nd2) 3403 self.assertEqual(w, nd1) 3404 self.assertEqual(v, w) 3405 3406 def test_memoryview_compare_zero_strides(self): 3407 3408 # zero strides 3409 nd1 = ndarray([900, 900, 900, 900], shape=[4], format='@L') 3410 nd2 = ndarray([900], shape=[4], strides=[0], format='L') 3411 v = memoryview(nd1) 3412 w = memoryview(nd2) 3413 3414 self.assertEqual(v, nd1) 3415 self.assertEqual(w, nd2) 3416 self.assertEqual(v, nd2) 3417 self.assertEqual(w, nd1) 3418 self.assertEqual(v, w) 3419 3420 # zero strides, struct module 3421 nd1 = ndarray([(900, 900)]*4, shape=[4], format='@ Li') 3422 nd2 = ndarray([(900, 900)], shape=[4], strides=[0], format='!L h') 3423 v = memoryview(nd1) 3424 w = memoryview(nd2) 3425 3426 self.assertEqual(v, nd1) 3427 self.assertEqual(w, nd2) 3428 self.assertEqual(v, nd2) 3429 self.assertEqual(w, nd1) 3430 self.assertEqual(v, w) 3431 3432 def test_memoryview_compare_random_formats(self): 3433 3434 # random single character native formats 3435 n = 10 3436 for char in fmtdict['@m']: 3437 fmt, items, singleitem = randitems(n, 'memoryview', '@', char) 3438 for flags in (0, ND_PIL): 3439 nd = ndarray(items, shape=[n], format=fmt, flags=flags) 3440 m = memoryview(nd) 3441 self.assertEqual(m, nd) 3442 3443 nd = nd[::-3] 3444 m = memoryview(nd) 3445 self.assertEqual(m, nd) 3446 3447 # random formats 3448 n = 10 3449 for _ in range(100): 3450 fmt, items, singleitem = randitems(n) 3451 for flags in (0, ND_PIL): 3452 nd = ndarray(items, shape=[n], format=fmt, flags=flags) 3453 m = memoryview(nd) 3454 self.assertEqual(m, nd) 3455 3456 nd = nd[::-3] 3457 m = memoryview(nd) 3458 self.assertEqual(m, nd) 3459 3460 def test_memoryview_compare_multidim_c(self): 3461 3462 # C-contiguous, different values 3463 nd1 = ndarray(list(range(-15, 15)), shape=[3, 2, 5], format='@h') 3464 nd2 = ndarray(list(range(0, 30)), shape=[3, 2, 5], format='@h') 3465 v = memoryview(nd1) 3466 w = memoryview(nd2) 3467 3468 self.assertEqual(v, nd1) 3469 self.assertEqual(w, nd2) 3470 self.assertNotEqual(v, nd2) 3471 self.assertNotEqual(w, nd1) 3472 self.assertNotEqual(v, w) 3473 3474 # C-contiguous, different values, struct module 3475 nd1 = ndarray([(0, 1, 2)]*30, shape=[3, 2, 5], format='=f q xxL') 3476 nd2 = ndarray([(-1.2, 1, 2)]*30, shape=[3, 2, 5], format='< f 2Q') 3477 v = memoryview(nd1) 3478 w = memoryview(nd2) 3479 3480 self.assertEqual(v, nd1) 3481 self.assertEqual(w, nd2) 3482 self.assertNotEqual(v, nd2) 3483 self.assertNotEqual(w, nd1) 3484 self.assertNotEqual(v, w) 3485 3486 # C-contiguous, different shape 3487 nd1 = ndarray(list(range(30)), shape=[2, 3, 5], format='L') 3488 nd2 = ndarray(list(range(30)), shape=[3, 2, 5], format='L') 3489 v = memoryview(nd1) 3490 w = memoryview(nd2) 3491 3492 self.assertEqual(v, nd1) 3493 self.assertEqual(w, nd2) 3494 self.assertNotEqual(v, nd2) 3495 self.assertNotEqual(w, nd1) 3496 self.assertNotEqual(v, w) 3497 3498 # C-contiguous, different shape, struct module 3499 nd1 = ndarray([(0, 1, 2)]*21, shape=[3, 7], format='! b B xL') 3500 nd2 = ndarray([(0, 1, 2)]*21, shape=[7, 3], format='= Qx l xxL') 3501 v = memoryview(nd1) 3502 w = memoryview(nd2) 3503 3504 self.assertEqual(v, nd1) 3505 self.assertEqual(w, nd2) 3506 self.assertNotEqual(v, nd2) 3507 self.assertNotEqual(w, nd1) 3508 self.assertNotEqual(v, w) 3509 3510 # C-contiguous, different format, struct module 3511 nd1 = ndarray(list(range(30)), shape=[2, 3, 5], format='L') 3512 nd2 = ndarray(list(range(30)), shape=[2, 3, 5], format='l') 3513 v = memoryview(nd1) 3514 w = memoryview(nd2) 3515 3516 self.assertEqual(v, nd1) 3517 self.assertEqual(w, nd2) 3518 self.assertEqual(v, nd2) 3519 self.assertEqual(w, nd1) 3520 self.assertEqual(v, w) 3521 3522 def test_memoryview_compare_multidim_fortran(self): 3523 3524 # Fortran-contiguous, different values 3525 nd1 = ndarray(list(range(-15, 15)), shape=[5, 2, 3], format='@h', 3526 flags=ND_FORTRAN) 3527 nd2 = ndarray(list(range(0, 30)), shape=[5, 2, 3], format='@h', 3528 flags=ND_FORTRAN) 3529 v = memoryview(nd1) 3530 w = memoryview(nd2) 3531 3532 self.assertEqual(v, nd1) 3533 self.assertEqual(w, nd2) 3534 self.assertNotEqual(v, nd2) 3535 self.assertNotEqual(w, nd1) 3536 self.assertNotEqual(v, w) 3537 3538 # Fortran-contiguous, different values, struct module 3539 nd1 = ndarray([(2**64-1, -1)]*6, shape=[2, 3], format='=Qq', 3540 flags=ND_FORTRAN) 3541 nd2 = ndarray([(-1, 2**64-1)]*6, shape=[2, 3], format='=qQ', 3542 flags=ND_FORTRAN) 3543 v = memoryview(nd1) 3544 w = memoryview(nd2) 3545 3546 self.assertEqual(v, nd1) 3547 self.assertEqual(w, nd2) 3548 self.assertNotEqual(v, nd2) 3549 self.assertNotEqual(w, nd1) 3550 self.assertNotEqual(v, w) 3551 3552 # Fortran-contiguous, different shape 3553 nd1 = ndarray(list(range(-15, 15)), shape=[2, 3, 5], format='l', 3554 flags=ND_FORTRAN) 3555 nd2 = ndarray(list(range(-15, 15)), shape=[3, 2, 5], format='l', 3556 flags=ND_FORTRAN) 3557 v = memoryview(nd1) 3558 w = memoryview(nd2) 3559 3560 self.assertEqual(v, nd1) 3561 self.assertEqual(w, nd2) 3562 self.assertNotEqual(v, nd2) 3563 self.assertNotEqual(w, nd1) 3564 self.assertNotEqual(v, w) 3565 3566 # Fortran-contiguous, different shape, struct module 3567 nd1 = ndarray(list(range(-15, 15)), shape=[2, 3, 5], format='0ll', 3568 flags=ND_FORTRAN) 3569 nd2 = ndarray(list(range(-15, 15)), shape=[3, 2, 5], format='l', 3570 flags=ND_FORTRAN) 3571 v = memoryview(nd1) 3572 w = memoryview(nd2) 3573 3574 self.assertEqual(v, nd1) 3575 self.assertEqual(w, nd2) 3576 self.assertNotEqual(v, nd2) 3577 self.assertNotEqual(w, nd1) 3578 self.assertNotEqual(v, w) 3579 3580 # Fortran-contiguous, different format, struct module 3581 nd1 = ndarray(list(range(30)), shape=[5, 2, 3], format='@h', 3582 flags=ND_FORTRAN) 3583 nd2 = ndarray(list(range(30)), shape=[5, 2, 3], format='@b', 3584 flags=ND_FORTRAN) 3585 v = memoryview(nd1) 3586 w = memoryview(nd2) 3587 3588 self.assertEqual(v, nd1) 3589 self.assertEqual(w, nd2) 3590 self.assertEqual(v, nd2) 3591 self.assertEqual(w, nd1) 3592 self.assertEqual(v, w) 3593 3594 def test_memoryview_compare_multidim_mixed(self): 3595 3596 # mixed C/Fortran contiguous 3597 lst1 = list(range(-15, 15)) 3598 lst2 = transpose(lst1, [3, 2, 5]) 3599 nd1 = ndarray(lst1, shape=[3, 2, 5], format='@l') 3600 nd2 = ndarray(lst2, shape=[3, 2, 5], format='l', flags=ND_FORTRAN) 3601 v = memoryview(nd1) 3602 w = memoryview(nd2) 3603 3604 self.assertEqual(v, nd1) 3605 self.assertEqual(w, nd2) 3606 self.assertEqual(v, w) 3607 3608 # mixed C/Fortran contiguous, struct module 3609 lst1 = [(-3.3, -22, b'x')]*30 3610 lst1[5] = (-2.2, -22, b'x') 3611 lst2 = transpose(lst1, [3, 2, 5]) 3612 nd1 = ndarray(lst1, shape=[3, 2, 5], format='d b c') 3613 nd2 = ndarray(lst2, shape=[3, 2, 5], format='d h c', flags=ND_FORTRAN) 3614 v = memoryview(nd1) 3615 w = memoryview(nd2) 3616 3617 self.assertEqual(v, nd1) 3618 self.assertEqual(w, nd2) 3619 self.assertEqual(v, w) 3620 3621 # different values, non-contiguous 3622 ex1 = ndarray(list(range(40)), shape=[5, 8], format='@I') 3623 nd1 = ex1[3:1:-1, ::-2] 3624 ex2 = ndarray(list(range(40)), shape=[5, 8], format='I') 3625 nd2 = ex2[1:3:1, ::-2] 3626 v = memoryview(nd1) 3627 w = memoryview(nd2) 3628 3629 self.assertEqual(v, nd1) 3630 self.assertEqual(w, nd2) 3631 self.assertNotEqual(v, nd2) 3632 self.assertNotEqual(w, nd1) 3633 self.assertNotEqual(v, w) 3634 3635 # same values, non-contiguous, struct module 3636 ex1 = ndarray([(2**31-1, -2**31)]*22, shape=[11, 2], format='=ii') 3637 nd1 = ex1[3:1:-1, ::-2] 3638 ex2 = ndarray([(2**31-1, -2**31)]*22, shape=[11, 2], format='>ii') 3639 nd2 = ex2[1:3:1, ::-2] 3640 v = memoryview(nd1) 3641 w = memoryview(nd2) 3642 3643 self.assertEqual(v, nd1) 3644 self.assertEqual(w, nd2) 3645 self.assertEqual(v, nd2) 3646 self.assertEqual(w, nd1) 3647 self.assertEqual(v, w) 3648 3649 # different shape 3650 ex1 = ndarray(list(range(30)), shape=[2, 3, 5], format='b') 3651 nd1 = ex1[1:3:, ::-2] 3652 nd2 = ndarray(list(range(30)), shape=[3, 2, 5], format='b') 3653 nd2 = ex2[1:3:, ::-2] 3654 v = memoryview(nd1) 3655 w = memoryview(nd2) 3656 3657 self.assertEqual(v, nd1) 3658 self.assertEqual(w, nd2) 3659 self.assertNotEqual(v, nd2) 3660 self.assertNotEqual(w, nd1) 3661 self.assertNotEqual(v, w) 3662 3663 # different shape, struct module 3664 ex1 = ndarray(list(range(30)), shape=[2, 3, 5], format='B') 3665 nd1 = ex1[1:3:, ::-2] 3666 nd2 = ndarray(list(range(30)), shape=[3, 2, 5], format='b') 3667 nd2 = ex2[1:3:, ::-2] 3668 v = memoryview(nd1) 3669 w = memoryview(nd2) 3670 3671 self.assertEqual(v, nd1) 3672 self.assertEqual(w, nd2) 3673 self.assertNotEqual(v, nd2) 3674 self.assertNotEqual(w, nd1) 3675 self.assertNotEqual(v, w) 3676 3677 # different format, struct module 3678 ex1 = ndarray([(2, b'123')]*30, shape=[5, 3, 2], format='b3s') 3679 nd1 = ex1[1:3:, ::-2] 3680 nd2 = ndarray([(2, b'123')]*30, shape=[5, 3, 2], format='i3s') 3681 nd2 = ex2[1:3:, ::-2] 3682 v = memoryview(nd1) 3683 w = memoryview(nd2) 3684 3685 self.assertEqual(v, nd1) 3686 self.assertEqual(w, nd2) 3687 self.assertNotEqual(v, nd2) 3688 self.assertNotEqual(w, nd1) 3689 self.assertNotEqual(v, w) 3690 3691 def test_memoryview_compare_multidim_zero_shape(self): 3692 3693 # zeros in shape 3694 nd1 = ndarray(list(range(30)), shape=[0, 3, 2], format='i') 3695 nd2 = ndarray(list(range(30)), shape=[5, 0, 2], format='@i') 3696 v = memoryview(nd1) 3697 w = memoryview(nd2) 3698 3699 self.assertEqual(v, nd1) 3700 self.assertEqual(w, nd2) 3701 self.assertNotEqual(v, nd2) 3702 self.assertNotEqual(w, nd1) 3703 self.assertNotEqual(v, w) 3704 3705 # zeros in shape, struct module 3706 nd1 = ndarray(list(range(30)), shape=[0, 3, 2], format='i') 3707 nd2 = ndarray(list(range(30)), shape=[5, 0, 2], format='@i') 3708 v = memoryview(nd1) 3709 w = memoryview(nd2) 3710 3711 self.assertEqual(v, nd1) 3712 self.assertEqual(w, nd2) 3713 self.assertNotEqual(v, nd2) 3714 self.assertNotEqual(w, nd1) 3715 self.assertNotEqual(v, w) 3716 3717 def test_memoryview_compare_multidim_zero_strides(self): 3718 3719 # zero strides 3720 nd1 = ndarray([900]*80, shape=[4, 5, 4], format='@L') 3721 nd2 = ndarray([900], shape=[4, 5, 4], strides=[0, 0, 0], format='L') 3722 v = memoryview(nd1) 3723 w = memoryview(nd2) 3724 3725 self.assertEqual(v, nd1) 3726 self.assertEqual(w, nd2) 3727 self.assertEqual(v, nd2) 3728 self.assertEqual(w, nd1) 3729 self.assertEqual(v, w) 3730 self.assertEqual(v.tolist(), w.tolist()) 3731 3732 # zero strides, struct module 3733 nd1 = ndarray([(1, 2)]*10, shape=[2, 5], format='=lQ') 3734 nd2 = ndarray([(1, 2)], shape=[2, 5], strides=[0, 0], format='<lQ') 3735 v = memoryview(nd1) 3736 w = memoryview(nd2) 3737 3738 self.assertEqual(v, nd1) 3739 self.assertEqual(w, nd2) 3740 self.assertEqual(v, nd2) 3741 self.assertEqual(w, nd1) 3742 self.assertEqual(v, w) 3743 3744 def test_memoryview_compare_multidim_suboffsets(self): 3745 3746 # suboffsets 3747 ex1 = ndarray(list(range(40)), shape=[5, 8], format='@I') 3748 nd1 = ex1[3:1:-1, ::-2] 3749 ex2 = ndarray(list(range(40)), shape=[5, 8], format='I', flags=ND_PIL) 3750 nd2 = ex2[1:3:1, ::-2] 3751 v = memoryview(nd1) 3752 w = memoryview(nd2) 3753 3754 self.assertEqual(v, nd1) 3755 self.assertEqual(w, nd2) 3756 self.assertNotEqual(v, nd2) 3757 self.assertNotEqual(w, nd1) 3758 self.assertNotEqual(v, w) 3759 3760 # suboffsets, struct module 3761 ex1 = ndarray([(2**64-1, -1)]*40, shape=[5, 8], format='=Qq', 3762 flags=ND_WRITABLE) 3763 ex1[2][7] = (1, -2) 3764 nd1 = ex1[3:1:-1, ::-2] 3765 3766 ex2 = ndarray([(2**64-1, -1)]*40, shape=[5, 8], format='>Qq', 3767 flags=ND_PIL|ND_WRITABLE) 3768 ex2[2][7] = (1, -2) 3769 nd2 = ex2[1:3:1, ::-2] 3770 3771 v = memoryview(nd1) 3772 w = memoryview(nd2) 3773 3774 self.assertEqual(v, nd1) 3775 self.assertEqual(w, nd2) 3776 self.assertEqual(v, nd2) 3777 self.assertEqual(w, nd1) 3778 self.assertEqual(v, w) 3779 3780 # suboffsets, different shape 3781 ex1 = ndarray(list(range(30)), shape=[2, 3, 5], format='b', 3782 flags=ND_PIL) 3783 nd1 = ex1[1:3:, ::-2] 3784 nd2 = ndarray(list(range(30)), shape=[3, 2, 5], format='b') 3785 nd2 = ex2[1:3:, ::-2] 3786 v = memoryview(nd1) 3787 w = memoryview(nd2) 3788 3789 self.assertEqual(v, nd1) 3790 self.assertEqual(w, nd2) 3791 self.assertNotEqual(v, nd2) 3792 self.assertNotEqual(w, nd1) 3793 self.assertNotEqual(v, w) 3794 3795 # suboffsets, different shape, struct module 3796 ex1 = ndarray([(2**8-1, -1)]*40, shape=[2, 3, 5], format='Bb', 3797 flags=ND_PIL|ND_WRITABLE) 3798 nd1 = ex1[1:2:, ::-2] 3799 3800 ex2 = ndarray([(2**8-1, -1)]*40, shape=[3, 2, 5], format='Bb') 3801 nd2 = ex2[1:2:, ::-2] 3802 3803 v = memoryview(nd1) 3804 w = memoryview(nd2) 3805 3806 self.assertEqual(v, nd1) 3807 self.assertEqual(w, nd2) 3808 self.assertNotEqual(v, nd2) 3809 self.assertNotEqual(w, nd1) 3810 self.assertNotEqual(v, w) 3811 3812 # suboffsets, different format 3813 ex1 = ndarray(list(range(30)), shape=[5, 3, 2], format='i', flags=ND_PIL) 3814 nd1 = ex1[1:3:, ::-2] 3815 ex2 = ndarray(list(range(30)), shape=[5, 3, 2], format='@I', flags=ND_PIL) 3816 nd2 = ex2[1:3:, ::-2] 3817 v = memoryview(nd1) 3818 w = memoryview(nd2) 3819 3820 self.assertEqual(v, nd1) 3821 self.assertEqual(w, nd2) 3822 self.assertEqual(v, nd2) 3823 self.assertEqual(w, nd1) 3824 self.assertEqual(v, w) 3825 3826 # suboffsets, different format, struct module 3827 ex1 = ndarray([(b'hello', b'', 1)]*27, shape=[3, 3, 3], format='5s0sP', 3828 flags=ND_PIL|ND_WRITABLE) 3829 ex1[1][2][2] = (b'sushi', b'', 1) 3830 nd1 = ex1[1:3:, ::-2] 3831 3832 ex2 = ndarray([(b'hello', b'', 1)]*27, shape=[3, 3, 3], format='5s0sP', 3833 flags=ND_PIL|ND_WRITABLE) 3834 ex1[1][2][2] = (b'sushi', b'', 1) 3835 nd2 = ex2[1:3:, ::-2] 3836 3837 v = memoryview(nd1) 3838 w = memoryview(nd2) 3839 3840 self.assertEqual(v, nd1) 3841 self.assertEqual(w, nd2) 3842 self.assertNotEqual(v, nd2) 3843 self.assertNotEqual(w, nd1) 3844 self.assertNotEqual(v, w) 3845 3846 # initialize mixed C/Fortran + suboffsets 3847 lst1 = list(range(-15, 15)) 3848 lst2 = transpose(lst1, [3, 2, 5]) 3849 nd1 = ndarray(lst1, shape=[3, 2, 5], format='@l', flags=ND_PIL) 3850 nd2 = ndarray(lst2, shape=[3, 2, 5], format='l', flags=ND_FORTRAN|ND_PIL) 3851 v = memoryview(nd1) 3852 w = memoryview(nd2) 3853 3854 self.assertEqual(v, nd1) 3855 self.assertEqual(w, nd2) 3856 self.assertEqual(v, w) 3857 3858 # initialize mixed C/Fortran + suboffsets, struct module 3859 lst1 = [(b'sashimi', b'sliced', 20.05)]*30 3860 lst1[11] = (b'ramen', b'spicy', 9.45) 3861 lst2 = transpose(lst1, [3, 2, 5]) 3862 3863 nd1 = ndarray(lst1, shape=[3, 2, 5], format='< 10p 9p d', flags=ND_PIL) 3864 nd2 = ndarray(lst2, shape=[3, 2, 5], format='> 10p 9p d', 3865 flags=ND_FORTRAN|ND_PIL) 3866 v = memoryview(nd1) 3867 w = memoryview(nd2) 3868 3869 self.assertEqual(v, nd1) 3870 self.assertEqual(w, nd2) 3871 self.assertEqual(v, w) 3872 3873 def test_memoryview_compare_not_equal(self): 3874 3875 # items not equal 3876 for byteorder in ['=', '<', '>', '!']: 3877 x = ndarray([2**63]*120, shape=[3,5,2,2,2], format=byteorder+'Q') 3878 y = ndarray([2**63]*120, shape=[3,5,2,2,2], format=byteorder+'Q', 3879 flags=ND_WRITABLE|ND_FORTRAN) 3880 y[2][3][1][1][1] = 1 3881 a = memoryview(x) 3882 b = memoryview(y) 3883 self.assertEqual(a, x) 3884 self.assertEqual(b, y) 3885 self.assertNotEqual(a, b) 3886 self.assertNotEqual(a, y) 3887 self.assertNotEqual(b, x) 3888 3889 x = ndarray([(2**63, 2**31, 2**15)]*120, shape=[3,5,2,2,2], 3890 format=byteorder+'QLH') 3891 y = ndarray([(2**63, 2**31, 2**15)]*120, shape=[3,5,2,2,2], 3892 format=byteorder+'QLH', flags=ND_WRITABLE|ND_FORTRAN) 3893 y[2][3][1][1][1] = (1, 1, 1) 3894 a = memoryview(x) 3895 b = memoryview(y) 3896 self.assertEqual(a, x) 3897 self.assertEqual(b, y) 3898 self.assertNotEqual(a, b) 3899 self.assertNotEqual(a, y) 3900 self.assertNotEqual(b, x) 3901 3902 def test_memoryview_check_released(self): 3903 3904 a = array.array('d', [1.1, 2.2, 3.3]) 3905 3906 m = memoryview(a) 3907 m.release() 3908 3909 # PyMemoryView_FromObject() 3910 self.assertRaises(ValueError, memoryview, m) 3911 # memoryview.cast() 3912 self.assertRaises(ValueError, m.cast, 'c') 3913 # memoryview.__iter__() 3914 self.assertRaises(ValueError, m.__iter__) 3915 # getbuffer() 3916 self.assertRaises(ValueError, ndarray, m) 3917 # memoryview.tolist() 3918 self.assertRaises(ValueError, m.tolist) 3919 # memoryview.tobytes() 3920 self.assertRaises(ValueError, m.tobytes) 3921 # sequence 3922 self.assertRaises(ValueError, eval, "1.0 in m", locals()) 3923 # subscript 3924 self.assertRaises(ValueError, m.__getitem__, 0) 3925 # assignment 3926 self.assertRaises(ValueError, m.__setitem__, 0, 1) 3927 3928 for attr in ('obj', 'nbytes', 'readonly', 'itemsize', 'format', 'ndim', 3929 'shape', 'strides', 'suboffsets', 'c_contiguous', 3930 'f_contiguous', 'contiguous'): 3931 self.assertRaises(ValueError, m.__getattribute__, attr) 3932 3933 # richcompare 3934 b = array.array('d', [1.1, 2.2, 3.3]) 3935 m1 = memoryview(a) 3936 m2 = memoryview(b) 3937 3938 self.assertEqual(m1, m2) 3939 m1.release() 3940 self.assertNotEqual(m1, m2) 3941 self.assertNotEqual(m1, a) 3942 self.assertEqual(m1, m1) 3943 3944 def test_memoryview_tobytes(self): 3945 # Many implicit tests are already in self.verify(). 3946 3947 t = (-529, 576, -625, 676, -729) 3948 3949 nd = ndarray(t, shape=[5], format='@h') 3950 m = memoryview(nd) 3951 self.assertEqual(m, nd) 3952 self.assertEqual(m.tobytes(), nd.tobytes()) 3953 3954 nd = ndarray([t], shape=[1], format='>hQiLl') 3955 m = memoryview(nd) 3956 self.assertEqual(m, nd) 3957 self.assertEqual(m.tobytes(), nd.tobytes()) 3958 3959 nd = ndarray([t for _ in range(12)], shape=[2,2,3], format='=hQiLl') 3960 m = memoryview(nd) 3961 self.assertEqual(m, nd) 3962 self.assertEqual(m.tobytes(), nd.tobytes()) 3963 3964 nd = ndarray([t for _ in range(120)], shape=[5,2,2,3,2], 3965 format='<hQiLl') 3966 m = memoryview(nd) 3967 self.assertEqual(m, nd) 3968 self.assertEqual(m.tobytes(), nd.tobytes()) 3969 3970 # Unknown formats are handled: tobytes() purely depends on itemsize. 3971 if ctypes: 3972 # format: "T{>l:x:>l:y:}" 3973 class BEPoint(ctypes.BigEndianStructure): 3974 _fields_ = [("x", ctypes.c_long), ("y", ctypes.c_long)] 3975 point = BEPoint(100, 200) 3976 a = memoryview(point) 3977 self.assertEqual(a.tobytes(), bytes(point)) 3978 3979 def test_memoryview_get_contiguous(self): 3980 # Many implicit tests are already in self.verify(). 3981 3982 # no buffer interface 3983 self.assertRaises(TypeError, get_contiguous, {}, PyBUF_READ, 'F') 3984 3985 # writable request to read-only object 3986 self.assertRaises(BufferError, get_contiguous, b'x', PyBUF_WRITE, 'C') 3987 3988 # writable request to non-contiguous object 3989 nd = ndarray([1, 2, 3], shape=[2], strides=[2]) 3990 self.assertRaises(BufferError, get_contiguous, nd, PyBUF_WRITE, 'A') 3991 3992 # scalar, read-only request from read-only exporter 3993 nd = ndarray(9, shape=(), format="L") 3994 for order in ['C', 'F', 'A']: 3995 m = get_contiguous(nd, PyBUF_READ, order) 3996 self.assertEqual(m, nd) 3997 self.assertEqual(m[()], 9) 3998 3999 # scalar, read-only request from writable exporter 4000 nd = ndarray(9, shape=(), format="L", flags=ND_WRITABLE) 4001 for order in ['C', 'F', 'A']: 4002 m = get_contiguous(nd, PyBUF_READ, order) 4003 self.assertEqual(m, nd) 4004 self.assertEqual(m[()], 9) 4005 4006 # scalar, writable request 4007 for order in ['C', 'F', 'A']: 4008 nd[()] = 9 4009 m = get_contiguous(nd, PyBUF_WRITE, order) 4010 self.assertEqual(m, nd) 4011 self.assertEqual(m[()], 9) 4012 4013 m[()] = 10 4014 self.assertEqual(m[()], 10) 4015 self.assertEqual(nd[()], 10) 4016 4017 # zeros in shape 4018 nd = ndarray([1], shape=[0], format="L", flags=ND_WRITABLE) 4019 for order in ['C', 'F', 'A']: 4020 m = get_contiguous(nd, PyBUF_READ, order) 4021 self.assertRaises(IndexError, m.__getitem__, 0) 4022 self.assertEqual(m, nd) 4023 self.assertEqual(m.tolist(), []) 4024 4025 nd = ndarray(list(range(8)), shape=[2, 0, 7], format="L", 4026 flags=ND_WRITABLE) 4027 for order in ['C', 'F', 'A']: 4028 m = get_contiguous(nd, PyBUF_READ, order) 4029 self.assertEqual(ndarray(m).tolist(), [[], []]) 4030 4031 # one-dimensional 4032 nd = ndarray([1], shape=[1], format="h", flags=ND_WRITABLE) 4033 for order in ['C', 'F', 'A']: 4034 m = get_contiguous(nd, PyBUF_WRITE, order) 4035 self.assertEqual(m, nd) 4036 self.assertEqual(m.tolist(), nd.tolist()) 4037 4038 nd = ndarray([1, 2, 3], shape=[3], format="b", flags=ND_WRITABLE) 4039 for order in ['C', 'F', 'A']: 4040 m = get_contiguous(nd, PyBUF_WRITE, order) 4041 self.assertEqual(m, nd) 4042 self.assertEqual(m.tolist(), nd.tolist()) 4043 4044 # one-dimensional, non-contiguous 4045 nd = ndarray([1, 2, 3], shape=[2], strides=[2], flags=ND_WRITABLE) 4046 for order in ['C', 'F', 'A']: 4047 m = get_contiguous(nd, PyBUF_READ, order) 4048 self.assertEqual(m, nd) 4049 self.assertEqual(m.tolist(), nd.tolist()) 4050 self.assertRaises(TypeError, m.__setitem__, 1, 20) 4051 self.assertEqual(m[1], 3) 4052 self.assertEqual(nd[1], 3) 4053 4054 nd = nd[::-1] 4055 for order in ['C', 'F', 'A']: 4056 m = get_contiguous(nd, PyBUF_READ, order) 4057 self.assertEqual(m, nd) 4058 self.assertEqual(m.tolist(), nd.tolist()) 4059 self.assertRaises(TypeError, m.__setitem__, 1, 20) 4060 self.assertEqual(m[1], 1) 4061 self.assertEqual(nd[1], 1) 4062 4063 # multi-dimensional, contiguous input 4064 nd = ndarray(list(range(12)), shape=[3, 4], flags=ND_WRITABLE) 4065 for order in ['C', 'A']: 4066 m = get_contiguous(nd, PyBUF_WRITE, order) 4067 self.assertEqual(ndarray(m).tolist(), nd.tolist()) 4068 4069 self.assertRaises(BufferError, get_contiguous, nd, PyBUF_WRITE, 'F') 4070 m = get_contiguous(nd, PyBUF_READ, order) 4071 self.assertEqual(ndarray(m).tolist(), nd.tolist()) 4072 4073 nd = ndarray(list(range(12)), shape=[3, 4], 4074 flags=ND_WRITABLE|ND_FORTRAN) 4075 for order in ['F', 'A']: 4076 m = get_contiguous(nd, PyBUF_WRITE, order) 4077 self.assertEqual(ndarray(m).tolist(), nd.tolist()) 4078 4079 self.assertRaises(BufferError, get_contiguous, nd, PyBUF_WRITE, 'C') 4080 m = get_contiguous(nd, PyBUF_READ, order) 4081 self.assertEqual(ndarray(m).tolist(), nd.tolist()) 4082 4083 # multi-dimensional, non-contiguous input 4084 nd = ndarray(list(range(12)), shape=[3, 4], flags=ND_WRITABLE|ND_PIL) 4085 for order in ['C', 'F', 'A']: 4086 self.assertRaises(BufferError, get_contiguous, nd, PyBUF_WRITE, 4087 order) 4088 m = get_contiguous(nd, PyBUF_READ, order) 4089 self.assertEqual(ndarray(m).tolist(), nd.tolist()) 4090 4091 # flags 4092 nd = ndarray([1,2,3,4,5], shape=[3], strides=[2]) 4093 m = get_contiguous(nd, PyBUF_READ, 'C') 4094 self.assertTrue(m.c_contiguous) 4095 4096 def test_memoryview_serializing(self): 4097 4098 # C-contiguous 4099 size = struct.calcsize('i') 4100 a = array.array('i', [1,2,3,4,5]) 4101 m = memoryview(a) 4102 buf = io.BytesIO(m) 4103 b = bytearray(5*size) 4104 buf.readinto(b) 4105 self.assertEqual(m.tobytes(), b) 4106 4107 # C-contiguous, multi-dimensional 4108 size = struct.calcsize('L') 4109 nd = ndarray(list(range(12)), shape=[2,3,2], format="L") 4110 m = memoryview(nd) 4111 buf = io.BytesIO(m) 4112 b = bytearray(2*3*2*size) 4113 buf.readinto(b) 4114 self.assertEqual(m.tobytes(), b) 4115 4116 # Fortran contiguous, multi-dimensional 4117 #size = struct.calcsize('L') 4118 #nd = ndarray(list(range(12)), shape=[2,3,2], format="L", 4119 # flags=ND_FORTRAN) 4120 #m = memoryview(nd) 4121 #buf = io.BytesIO(m) 4122 #b = bytearray(2*3*2*size) 4123 #buf.readinto(b) 4124 #self.assertEqual(m.tobytes(), b) 4125 4126 def test_memoryview_hash(self): 4127 4128 # bytes exporter 4129 b = bytes(list(range(12))) 4130 m = memoryview(b) 4131 self.assertEqual(hash(b), hash(m)) 4132 4133 # C-contiguous 4134 mc = m.cast('c', shape=[3,4]) 4135 self.assertEqual(hash(mc), hash(b)) 4136 4137 # non-contiguous 4138 mx = m[::-2] 4139 b = bytes(list(range(12))[::-2]) 4140 self.assertEqual(hash(mx), hash(b)) 4141 4142 # Fortran contiguous 4143 nd = ndarray(list(range(30)), shape=[3,2,5], flags=ND_FORTRAN) 4144 m = memoryview(nd) 4145 self.assertEqual(hash(m), hash(nd)) 4146 4147 # multi-dimensional slice 4148 nd = ndarray(list(range(30)), shape=[3,2,5]) 4149 x = nd[::2, ::, ::-1] 4150 m = memoryview(x) 4151 self.assertEqual(hash(m), hash(x)) 4152 4153 # multi-dimensional slice with suboffsets 4154 nd = ndarray(list(range(30)), shape=[2,5,3], flags=ND_PIL) 4155 x = nd[::2, ::, ::-1] 4156 m = memoryview(x) 4157 self.assertEqual(hash(m), hash(x)) 4158 4159 # equality-hash invariant 4160 x = ndarray(list(range(12)), shape=[12], format='B') 4161 a = memoryview(x) 4162 4163 y = ndarray(list(range(12)), shape=[12], format='b') 4164 b = memoryview(y) 4165 4166 self.assertEqual(a, b) 4167 self.assertEqual(hash(a), hash(b)) 4168 4169 # non-byte formats 4170 nd = ndarray(list(range(12)), shape=[2,2,3], format='L') 4171 m = memoryview(nd) 4172 self.assertRaises(ValueError, m.__hash__) 4173 4174 nd = ndarray(list(range(-6, 6)), shape=[2,2,3], format='h') 4175 m = memoryview(nd) 4176 self.assertRaises(ValueError, m.__hash__) 4177 4178 nd = ndarray(list(range(12)), shape=[2,2,3], format='= L') 4179 m = memoryview(nd) 4180 self.assertRaises(ValueError, m.__hash__) 4181 4182 nd = ndarray(list(range(-6, 6)), shape=[2,2,3], format='< h') 4183 m = memoryview(nd) 4184 self.assertRaises(ValueError, m.__hash__) 4185 4186 def test_memoryview_release(self): 4187 4188 # Create re-exporter from getbuffer(memoryview), then release the view. 4189 a = bytearray([1,2,3]) 4190 m = memoryview(a) 4191 nd = ndarray(m) # re-exporter 4192 self.assertRaises(BufferError, m.release) 4193 del nd 4194 m.release() 4195 4196 a = bytearray([1,2,3]) 4197 m = memoryview(a) 4198 nd1 = ndarray(m, getbuf=PyBUF_FULL_RO, flags=ND_REDIRECT) 4199 nd2 = ndarray(nd1, getbuf=PyBUF_FULL_RO, flags=ND_REDIRECT) 4200 self.assertIs(nd2.obj, m) 4201 self.assertRaises(BufferError, m.release) 4202 del nd1, nd2 4203 m.release() 4204 4205 # chained views 4206 a = bytearray([1,2,3]) 4207 m1 = memoryview(a) 4208 m2 = memoryview(m1) 4209 nd = ndarray(m2) # re-exporter 4210 m1.release() 4211 self.assertRaises(BufferError, m2.release) 4212 del nd 4213 m2.release() 4214 4215 a = bytearray([1,2,3]) 4216 m1 = memoryview(a) 4217 m2 = memoryview(m1) 4218 nd1 = ndarray(m2, getbuf=PyBUF_FULL_RO, flags=ND_REDIRECT) 4219 nd2 = ndarray(nd1, getbuf=PyBUF_FULL_RO, flags=ND_REDIRECT) 4220 self.assertIs(nd2.obj, m2) 4221 m1.release() 4222 self.assertRaises(BufferError, m2.release) 4223 del nd1, nd2 4224 m2.release() 4225 4226 # Allow changing layout while buffers are exported. 4227 nd = ndarray([1,2,3], shape=[3], flags=ND_VAREXPORT) 4228 m1 = memoryview(nd) 4229 4230 nd.push([4,5,6,7,8], shape=[5]) # mutate nd 4231 m2 = memoryview(nd) 4232 4233 x = memoryview(m1) 4234 self.assertEqual(x.tolist(), m1.tolist()) 4235 4236 y = memoryview(m2) 4237 self.assertEqual(y.tolist(), m2.tolist()) 4238 self.assertEqual(y.tolist(), nd.tolist()) 4239 m2.release() 4240 y.release() 4241 4242 nd.pop() # pop the current view 4243 self.assertEqual(x.tolist(), nd.tolist()) 4244 4245 del nd 4246 m1.release() 4247 x.release() 4248 4249 # If multiple memoryviews share the same managed buffer, implicit 4250 # release() in the context manager's __exit__() method should still 4251 # work. 4252 def catch22(b): 4253 with memoryview(b) as m2: 4254 pass 4255 4256 x = bytearray(b'123') 4257 with memoryview(x) as m1: 4258 catch22(m1) 4259 self.assertEqual(m1[0], ord(b'1')) 4260 4261 x = ndarray(list(range(12)), shape=[2,2,3], format='l') 4262 y = ndarray(x, getbuf=PyBUF_FULL_RO, flags=ND_REDIRECT) 4263 z = ndarray(y, getbuf=PyBUF_FULL_RO, flags=ND_REDIRECT) 4264 self.assertIs(z.obj, x) 4265 with memoryview(z) as m: 4266 catch22(m) 4267 self.assertEqual(m[0:1].tolist(), [[[0, 1, 2], [3, 4, 5]]]) 4268 4269 # Test garbage collection. 4270 for flags in (0, ND_REDIRECT): 4271 x = bytearray(b'123') 4272 with memoryview(x) as m1: 4273 del x 4274 y = ndarray(m1, getbuf=PyBUF_FULL_RO, flags=flags) 4275 with memoryview(y) as m2: 4276 del y 4277 z = ndarray(m2, getbuf=PyBUF_FULL_RO, flags=flags) 4278 with memoryview(z) as m3: 4279 del z 4280 catch22(m3) 4281 catch22(m2) 4282 catch22(m1) 4283 self.assertEqual(m1[0], ord(b'1')) 4284 self.assertEqual(m2[1], ord(b'2')) 4285 self.assertEqual(m3[2], ord(b'3')) 4286 del m3 4287 del m2 4288 del m1 4289 4290 x = bytearray(b'123') 4291 with memoryview(x) as m1: 4292 del x 4293 y = ndarray(m1, getbuf=PyBUF_FULL_RO, flags=flags) 4294 with memoryview(y) as m2: 4295 del y 4296 z = ndarray(m2, getbuf=PyBUF_FULL_RO, flags=flags) 4297 with memoryview(z) as m3: 4298 del z 4299 catch22(m1) 4300 catch22(m2) 4301 catch22(m3) 4302 self.assertEqual(m1[0], ord(b'1')) 4303 self.assertEqual(m2[1], ord(b'2')) 4304 self.assertEqual(m3[2], ord(b'3')) 4305 del m1, m2, m3 4306 4307 # memoryview.release() fails if the view has exported buffers. 4308 x = bytearray(b'123') 4309 with self.assertRaises(BufferError): 4310 with memoryview(x) as m: 4311 ex = ndarray(m) 4312 m[0] == ord(b'1') 4313 4314 def test_memoryview_redirect(self): 4315 4316 nd = ndarray([1.0 * x for x in range(12)], shape=[12], format='d') 4317 a = array.array('d', [1.0 * x for x in range(12)]) 4318 4319 for x in (nd, a): 4320 y = ndarray(x, getbuf=PyBUF_FULL_RO, flags=ND_REDIRECT) 4321 z = ndarray(y, getbuf=PyBUF_FULL_RO, flags=ND_REDIRECT) 4322 m = memoryview(z) 4323 4324 self.assertIs(y.obj, x) 4325 self.assertIs(z.obj, x) 4326 self.assertIs(m.obj, x) 4327 4328 self.assertEqual(m, x) 4329 self.assertEqual(m, y) 4330 self.assertEqual(m, z) 4331 4332 self.assertEqual(m[1:3], x[1:3]) 4333 self.assertEqual(m[1:3], y[1:3]) 4334 self.assertEqual(m[1:3], z[1:3]) 4335 del y, z 4336 self.assertEqual(m[1:3], x[1:3]) 4337 4338 def test_memoryview_from_static_exporter(self): 4339 4340 fmt = 'B' 4341 lst = [0,1,2,3,4,5,6,7,8,9,10,11] 4342 4343 # exceptions 4344 self.assertRaises(TypeError, staticarray, 1, 2, 3) 4345 4346 # view.obj==x 4347 x = staticarray() 4348 y = memoryview(x) 4349 self.verify(y, obj=x, 4350 itemsize=1, fmt=fmt, readonly=True, 4351 ndim=1, shape=[12], strides=[1], 4352 lst=lst) 4353 for i in range(12): 4354 self.assertEqual(y[i], i) 4355 del x 4356 del y 4357 4358 x = staticarray() 4359 y = memoryview(x) 4360 del y 4361 del x 4362 4363 x = staticarray() 4364 y = ndarray(x, getbuf=PyBUF_FULL_RO) 4365 z = ndarray(y, getbuf=PyBUF_FULL_RO) 4366 m = memoryview(z) 4367 self.assertIs(y.obj, x) 4368 self.assertIs(m.obj, z) 4369 self.verify(m, obj=z, 4370 itemsize=1, fmt=fmt, readonly=True, 4371 ndim=1, shape=[12], strides=[1], 4372 lst=lst) 4373 del x, y, z, m 4374 4375 x = staticarray() 4376 y = ndarray(x, getbuf=PyBUF_FULL_RO, flags=ND_REDIRECT) 4377 z = ndarray(y, getbuf=PyBUF_FULL_RO, flags=ND_REDIRECT) 4378 m = memoryview(z) 4379 self.assertIs(y.obj, x) 4380 self.assertIs(z.obj, x) 4381 self.assertIs(m.obj, x) 4382 self.verify(m, obj=x, 4383 itemsize=1, fmt=fmt, readonly=True, 4384 ndim=1, shape=[12], strides=[1], 4385 lst=lst) 4386 del x, y, z, m 4387 4388 # view.obj==NULL 4389 x = staticarray(legacy_mode=True) 4390 y = memoryview(x) 4391 self.verify(y, obj=None, 4392 itemsize=1, fmt=fmt, readonly=True, 4393 ndim=1, shape=[12], strides=[1], 4394 lst=lst) 4395 for i in range(12): 4396 self.assertEqual(y[i], i) 4397 del x 4398 del y 4399 4400 x = staticarray(legacy_mode=True) 4401 y = memoryview(x) 4402 del y 4403 del x 4404 4405 x = staticarray(legacy_mode=True) 4406 y = ndarray(x, getbuf=PyBUF_FULL_RO) 4407 z = ndarray(y, getbuf=PyBUF_FULL_RO) 4408 m = memoryview(z) 4409 self.assertIs(y.obj, None) 4410 self.assertIs(m.obj, z) 4411 self.verify(m, obj=z, 4412 itemsize=1, fmt=fmt, readonly=True, 4413 ndim=1, shape=[12], strides=[1], 4414 lst=lst) 4415 del x, y, z, m 4416 4417 x = staticarray(legacy_mode=True) 4418 y = ndarray(x, getbuf=PyBUF_FULL_RO, flags=ND_REDIRECT) 4419 z = ndarray(y, getbuf=PyBUF_FULL_RO, flags=ND_REDIRECT) 4420 m = memoryview(z) 4421 # Clearly setting view.obj==NULL is inferior, since it 4422 # messes up the redirection chain: 4423 self.assertIs(y.obj, None) 4424 self.assertIs(z.obj, y) 4425 self.assertIs(m.obj, y) 4426 self.verify(m, obj=y, 4427 itemsize=1, fmt=fmt, readonly=True, 4428 ndim=1, shape=[12], strides=[1], 4429 lst=lst) 4430 del x, y, z, m 4431 4432 def test_memoryview_getbuffer_undefined(self): 4433 4434 # getbufferproc does not adhere to the new documentation 4435 nd = ndarray([1,2,3], [3], flags=ND_GETBUF_FAIL|ND_GETBUF_UNDEFINED) 4436 self.assertRaises(BufferError, memoryview, nd) 4437 4438 def test_issue_7385(self): 4439 x = ndarray([1,2,3], shape=[3], flags=ND_GETBUF_FAIL) 4440 self.assertRaises(BufferError, memoryview, x) 4441 4442 def test_bytearray_release_buffer_read_flag(self): 4443 # See https://github.com/python/cpython/issues/126980 4444 obj = bytearray(b'abc') 4445 with self.assertRaises(SystemError): 4446 obj.__buffer__(inspect.BufferFlags.READ) 4447 with self.assertRaises(SystemError): 4448 obj.__buffer__(inspect.BufferFlags.WRITE) 4449 4450 @support.cpython_only 4451 def test_pybuffer_size_from_format(self): 4452 # basic tests 4453 for format in ('', 'ii', '3s'): 4454 self.assertEqual(_testcapi.PyBuffer_SizeFromFormat(format), 4455 struct.calcsize(format)) 4456 4457 @support.cpython_only 4458 def test_flags_overflow(self): 4459 # gh-126594: Check for integer overlow on large flags 4460 try: 4461 from _testcapi import INT_MIN, INT_MAX 4462 except ImportError: 4463 INT_MIN = -(2 ** 31) 4464 INT_MAX = 2 ** 31 - 1 4465 4466 obj = b'abc' 4467 for flags in (INT_MIN - 1, INT_MAX + 1): 4468 with self.subTest(flags=flags): 4469 with self.assertRaises(OverflowError): 4470 obj.__buffer__(flags) 4471 4472 4473class TestPythonBufferProtocol(unittest.TestCase): 4474 def test_basic(self): 4475 class MyBuffer: 4476 def __buffer__(self, flags): 4477 return memoryview(b"hello") 4478 4479 mv = memoryview(MyBuffer()) 4480 self.assertEqual(mv.tobytes(), b"hello") 4481 self.assertEqual(bytes(MyBuffer()), b"hello") 4482 4483 def test_bad_buffer_method(self): 4484 class MustReturnMV: 4485 def __buffer__(self, flags): 4486 return 42 4487 4488 self.assertRaises(TypeError, memoryview, MustReturnMV()) 4489 4490 class NoBytesEither: 4491 def __buffer__(self, flags): 4492 return b"hello" 4493 4494 self.assertRaises(TypeError, memoryview, NoBytesEither()) 4495 4496 class WrongArity: 4497 def __buffer__(self): 4498 return memoryview(b"hello") 4499 4500 self.assertRaises(TypeError, memoryview, WrongArity()) 4501 4502 def test_release_buffer(self): 4503 class WhatToRelease: 4504 def __init__(self): 4505 self.held = False 4506 self.ba = bytearray(b"hello") 4507 4508 def __buffer__(self, flags): 4509 if self.held: 4510 raise TypeError("already held") 4511 self.held = True 4512 return memoryview(self.ba) 4513 4514 def __release_buffer__(self, buffer): 4515 self.held = False 4516 4517 wr = WhatToRelease() 4518 self.assertFalse(wr.held) 4519 with memoryview(wr) as mv: 4520 self.assertTrue(wr.held) 4521 self.assertEqual(mv.tobytes(), b"hello") 4522 self.assertFalse(wr.held) 4523 4524 def test_same_buffer_returned(self): 4525 class WhatToRelease: 4526 def __init__(self): 4527 self.held = False 4528 self.ba = bytearray(b"hello") 4529 self.created_mv = None 4530 4531 def __buffer__(self, flags): 4532 if self.held: 4533 raise TypeError("already held") 4534 self.held = True 4535 self.created_mv = memoryview(self.ba) 4536 return self.created_mv 4537 4538 def __release_buffer__(self, buffer): 4539 assert buffer is self.created_mv 4540 self.held = False 4541 4542 wr = WhatToRelease() 4543 self.assertFalse(wr.held) 4544 with memoryview(wr) as mv: 4545 self.assertTrue(wr.held) 4546 self.assertEqual(mv.tobytes(), b"hello") 4547 self.assertFalse(wr.held) 4548 4549 def test_buffer_flags(self): 4550 class PossiblyMutable: 4551 def __init__(self, data, mutable) -> None: 4552 self._data = bytearray(data) 4553 self._mutable = mutable 4554 4555 def __buffer__(self, flags): 4556 if flags & inspect.BufferFlags.WRITABLE: 4557 if not self._mutable: 4558 raise RuntimeError("not mutable") 4559 return memoryview(self._data) 4560 else: 4561 return memoryview(bytes(self._data)) 4562 4563 mutable = PossiblyMutable(b"hello", True) 4564 immutable = PossiblyMutable(b"hello", False) 4565 with memoryview._from_flags(mutable, inspect.BufferFlags.WRITABLE) as mv: 4566 self.assertEqual(mv.tobytes(), b"hello") 4567 mv[0] = ord(b'x') 4568 self.assertEqual(mv.tobytes(), b"xello") 4569 with memoryview._from_flags(mutable, inspect.BufferFlags.SIMPLE) as mv: 4570 self.assertEqual(mv.tobytes(), b"xello") 4571 with self.assertRaises(TypeError): 4572 mv[0] = ord(b'h') 4573 self.assertEqual(mv.tobytes(), b"xello") 4574 with memoryview._from_flags(immutable, inspect.BufferFlags.SIMPLE) as mv: 4575 self.assertEqual(mv.tobytes(), b"hello") 4576 with self.assertRaises(TypeError): 4577 mv[0] = ord(b'x') 4578 self.assertEqual(mv.tobytes(), b"hello") 4579 4580 with self.assertRaises(RuntimeError): 4581 memoryview._from_flags(immutable, inspect.BufferFlags.WRITABLE) 4582 with memoryview(immutable) as mv: 4583 self.assertEqual(mv.tobytes(), b"hello") 4584 with self.assertRaises(TypeError): 4585 mv[0] = ord(b'x') 4586 self.assertEqual(mv.tobytes(), b"hello") 4587 4588 def test_call_builtins(self): 4589 ba = bytearray(b"hello") 4590 mv = ba.__buffer__(0) 4591 self.assertEqual(mv.tobytes(), b"hello") 4592 ba.__release_buffer__(mv) 4593 with self.assertRaises(OverflowError): 4594 ba.__buffer__(sys.maxsize + 1) 4595 4596 @unittest.skipIf(_testcapi is None, "requires _testcapi") 4597 def test_c_buffer(self): 4598 buf = _testcapi.testBuf() 4599 self.assertEqual(buf.references, 0) 4600 mv = buf.__buffer__(0) 4601 self.assertIsInstance(mv, memoryview) 4602 self.assertEqual(mv.tobytes(), b"test") 4603 self.assertEqual(buf.references, 1) 4604 buf.__release_buffer__(mv) 4605 self.assertEqual(buf.references, 0) 4606 with self.assertRaises(ValueError): 4607 mv.tobytes() 4608 # Calling it again doesn't cause issues 4609 with self.assertRaises(ValueError): 4610 buf.__release_buffer__(mv) 4611 self.assertEqual(buf.references, 0) 4612 4613 @unittest.skipIf(_testcapi is None, "requires _testcapi") 4614 def test_c_buffer_invalid_flags(self): 4615 buf = _testcapi.testBuf() 4616 self.assertRaises(SystemError, buf.__buffer__, PyBUF_READ) 4617 self.assertRaises(SystemError, buf.__buffer__, PyBUF_WRITE) 4618 4619 @unittest.skipIf(_testcapi is None, "requires _testcapi") 4620 def test_c_fill_buffer_invalid_flags(self): 4621 # PyBuffer_FillInfo 4622 source = b"abc" 4623 self.assertRaises(SystemError, _testcapi.buffer_fill_info, 4624 source, 0, PyBUF_READ) 4625 self.assertRaises(SystemError, _testcapi.buffer_fill_info, 4626 source, 0, PyBUF_WRITE) 4627 4628 @unittest.skipIf(_testcapi is None, "requires _testcapi") 4629 def test_c_fill_buffer_readonly_and_writable(self): 4630 source = b"abc" 4631 with _testcapi.buffer_fill_info(source, 1, PyBUF_SIMPLE) as m: 4632 self.assertEqual(bytes(m), b"abc") 4633 self.assertTrue(m.readonly) 4634 with _testcapi.buffer_fill_info(source, 0, PyBUF_WRITABLE) as m: 4635 self.assertEqual(bytes(m), b"abc") 4636 self.assertFalse(m.readonly) 4637 self.assertRaises(BufferError, _testcapi.buffer_fill_info, 4638 source, 1, PyBUF_WRITABLE) 4639 4640 def test_inheritance(self): 4641 class A(bytearray): 4642 def __buffer__(self, flags): 4643 return super().__buffer__(flags) 4644 4645 a = A(b"hello") 4646 mv = memoryview(a) 4647 self.assertEqual(mv.tobytes(), b"hello") 4648 4649 def test_inheritance_releasebuffer(self): 4650 rb_call_count = 0 4651 class B(bytearray): 4652 def __buffer__(self, flags): 4653 return super().__buffer__(flags) 4654 def __release_buffer__(self, view): 4655 nonlocal rb_call_count 4656 rb_call_count += 1 4657 super().__release_buffer__(view) 4658 4659 b = B(b"hello") 4660 with memoryview(b) as mv: 4661 self.assertEqual(mv.tobytes(), b"hello") 4662 self.assertEqual(rb_call_count, 0) 4663 self.assertEqual(rb_call_count, 1) 4664 4665 def test_inherit_but_return_something_else(self): 4666 class A(bytearray): 4667 def __buffer__(self, flags): 4668 return memoryview(b"hello") 4669 4670 a = A(b"hello") 4671 with memoryview(a) as mv: 4672 self.assertEqual(mv.tobytes(), b"hello") 4673 4674 rb_call_count = 0 4675 rb_raised = False 4676 class B(bytearray): 4677 def __buffer__(self, flags): 4678 return memoryview(b"hello") 4679 def __release_buffer__(self, view): 4680 nonlocal rb_call_count 4681 rb_call_count += 1 4682 try: 4683 super().__release_buffer__(view) 4684 except ValueError: 4685 nonlocal rb_raised 4686 rb_raised = True 4687 4688 b = B(b"hello") 4689 with memoryview(b) as mv: 4690 self.assertEqual(mv.tobytes(), b"hello") 4691 self.assertEqual(rb_call_count, 0) 4692 self.assertEqual(rb_call_count, 1) 4693 self.assertIs(rb_raised, True) 4694 4695 def test_override_only_release(self): 4696 class C(bytearray): 4697 def __release_buffer__(self, buffer): 4698 super().__release_buffer__(buffer) 4699 4700 c = C(b"hello") 4701 with memoryview(c) as mv: 4702 self.assertEqual(mv.tobytes(), b"hello") 4703 4704 def test_release_saves_reference(self): 4705 smuggled_buffer = None 4706 4707 class C(bytearray): 4708 def __release_buffer__(s, buffer: memoryview): 4709 with self.assertRaises(ValueError): 4710 memoryview(buffer) 4711 with self.assertRaises(ValueError): 4712 buffer.cast("b") 4713 with self.assertRaises(ValueError): 4714 buffer.toreadonly() 4715 with self.assertRaises(ValueError): 4716 buffer[:1] 4717 with self.assertRaises(ValueError): 4718 buffer.__buffer__(0) 4719 nonlocal smuggled_buffer 4720 smuggled_buffer = buffer 4721 self.assertEqual(buffer.tobytes(), b"hello") 4722 super().__release_buffer__(buffer) 4723 4724 c = C(b"hello") 4725 with memoryview(c) as mv: 4726 self.assertEqual(mv.tobytes(), b"hello") 4727 c.clear() 4728 with self.assertRaises(ValueError): 4729 smuggled_buffer.tobytes() 4730 4731 def test_release_saves_reference_no_subclassing(self): 4732 ba = bytearray(b"hello") 4733 4734 class C: 4735 def __buffer__(self, flags): 4736 return memoryview(ba) 4737 4738 def __release_buffer__(self, buffer): 4739 self.buffer = buffer 4740 4741 c = C() 4742 with memoryview(c) as mv: 4743 self.assertEqual(mv.tobytes(), b"hello") 4744 self.assertEqual(c.buffer.tobytes(), b"hello") 4745 4746 with self.assertRaises(BufferError): 4747 ba.clear() 4748 c.buffer.release() 4749 ba.clear() 4750 4751 def test_multiple_inheritance_buffer_last(self): 4752 class A: 4753 def __buffer__(self, flags): 4754 return memoryview(b"hello A") 4755 4756 class B(A, bytearray): 4757 def __buffer__(self, flags): 4758 return super().__buffer__(flags) 4759 4760 b = B(b"hello") 4761 with memoryview(b) as mv: 4762 self.assertEqual(mv.tobytes(), b"hello A") 4763 4764 class Releaser: 4765 def __release_buffer__(self, buffer): 4766 self.buffer = buffer 4767 4768 class C(Releaser, bytearray): 4769 def __buffer__(self, flags): 4770 return super().__buffer__(flags) 4771 4772 c = C(b"hello C") 4773 with memoryview(c) as mv: 4774 self.assertEqual(mv.tobytes(), b"hello C") 4775 c.clear() 4776 with self.assertRaises(ValueError): 4777 c.buffer.tobytes() 4778 4779 def test_multiple_inheritance_buffer_last_raising(self): 4780 class A: 4781 def __buffer__(self, flags): 4782 raise RuntimeError("should not be called") 4783 4784 def __release_buffer__(self, buffer): 4785 raise RuntimeError("should not be called") 4786 4787 class B(bytearray, A): 4788 def __buffer__(self, flags): 4789 return super().__buffer__(flags) 4790 4791 b = B(b"hello") 4792 with memoryview(b) as mv: 4793 self.assertEqual(mv.tobytes(), b"hello") 4794 4795 class Releaser: 4796 buffer = None 4797 def __release_buffer__(self, buffer): 4798 self.buffer = buffer 4799 4800 class C(bytearray, Releaser): 4801 def __buffer__(self, flags): 4802 return super().__buffer__(flags) 4803 4804 c = C(b"hello") 4805 with memoryview(c) as mv: 4806 self.assertEqual(mv.tobytes(), b"hello") 4807 c.clear() 4808 self.assertIs(c.buffer, None) 4809 4810 def test_release_buffer_with_exception_set(self): 4811 class A: 4812 def __buffer__(self, flags): 4813 return memoryview(bytes(8)) 4814 def __release_buffer__(self, view): 4815 pass 4816 4817 b = bytearray(8) 4818 with memoryview(b): 4819 # now b.extend will raise an exception due to exports 4820 with self.assertRaises(BufferError): 4821 b.extend(A()) 4822 4823 4824if __name__ == "__main__": 4825 unittest.main() 4826