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