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