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