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