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