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