• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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