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