blob: c91f3c40a5b246d50c80332ac0983b49ad3cf764 [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:
Stefan Krah7d12d9d2012-07-28 12:25:55 +02001851 # XXX NumPy (as far as it compiles with 3.3) currently
1852 # segfaults here. Wait for a stable 3.3 compatible version.
1853 continue
Stefan Krah9a2d99e2012-02-25 12:24:21 +01001854 shape = t[3]
1855 if 0 in shape:
1856 continue # http://projects.scipy.org/numpy/ticket/1910
1857 z = numpy_array_from_structure(items, fmt, t)
1858 self.verify(x, obj=None,
1859 itemsize=z.itemsize, fmt=fmt, readonly=0,
1860 ndim=z.ndim, shape=z.shape, strides=z.strides,
1861 lst=z.tolist())
1862
1863 def test_ndarray_random_invalid(self):
1864 # exceptions during construction of invalid arrays
1865 for _ in range(ITERATIONS):
1866 for fmt in fmtdict['@']:
1867 itemsize = struct.calcsize(fmt)
1868
1869 t = rand_structure(itemsize, False, maxdim=MAXDIM,
1870 maxshape=MAXSHAPE)
1871 self.assertFalse(verify_structure(*t))
1872 items = randitems_from_structure(fmt, t)
1873
1874 nderr = False
1875 try:
1876 x = ndarray_from_structure(items, fmt, t)
1877 except Exception as e:
1878 nderr = e.__class__
1879 self.assertTrue(nderr)
1880
1881 if numpy_array:
1882 numpy_err = False
1883 try:
1884 y = numpy_array_from_structure(items, fmt, t)
1885 except Exception as e:
1886 numpy_err = e.__class__
1887
1888 if 0: # http://projects.scipy.org/numpy/ticket/1910
1889 self.assertTrue(numpy_err)
1890
1891 def test_ndarray_random_slice_assign(self):
1892 # valid slice assignments
1893 for _ in range(ITERATIONS):
1894 for fmt in fmtdict['@']:
1895 itemsize = struct.calcsize(fmt)
1896
1897 lshape, rshape, lslices, rslices = \
1898 rand_aligned_slices(maxdim=MAXDIM, maxshape=MAXSHAPE)
1899 tl = rand_structure(itemsize, True, shape=lshape)
1900 tr = rand_structure(itemsize, True, shape=rshape)
1901 self.assertTrue(verify_structure(*tl))
1902 self.assertTrue(verify_structure(*tr))
1903 litems = randitems_from_structure(fmt, tl)
1904 ritems = randitems_from_structure(fmt, tr)
1905
1906 xl = ndarray_from_structure(litems, fmt, tl)
1907 xr = ndarray_from_structure(ritems, fmt, tr)
1908 xl[lslices] = xr[rslices]
1909 xllist = xl.tolist()
1910 xrlist = xr.tolist()
1911
1912 ml = memoryview(xl)
1913 mr = memoryview(xr)
1914 self.assertEqual(ml.tolist(), xllist)
1915 self.assertEqual(mr.tolist(), xrlist)
1916
1917 if tl[2] > 0 and tr[2] > 0:
1918 # ndim > 0: test against suboffsets representation.
1919 yl = ndarray_from_structure(litems, fmt, tl, flags=ND_PIL)
1920 yr = ndarray_from_structure(ritems, fmt, tr, flags=ND_PIL)
1921 yl[lslices] = yr[rslices]
1922 yllist = yl.tolist()
1923 yrlist = yr.tolist()
1924 self.assertEqual(xllist, yllist)
1925 self.assertEqual(xrlist, yrlist)
1926
1927 ml = memoryview(yl)
1928 mr = memoryview(yr)
1929 self.assertEqual(ml.tolist(), yllist)
1930 self.assertEqual(mr.tolist(), yrlist)
1931
1932 if numpy_array:
Stefan Krah7d12d9d2012-07-28 12:25:55 +02001933 # XXX NumPy (as far as it compiles with 3.3) currently
1934 # segfaults here. Wait for a stable 3.3 compatible version.
1935 continue
Stefan Krah9a2d99e2012-02-25 12:24:21 +01001936 if 0 in lshape or 0 in rshape:
1937 continue # http://projects.scipy.org/numpy/ticket/1910
1938
1939 zl = numpy_array_from_structure(litems, fmt, tl)
1940 zr = numpy_array_from_structure(ritems, fmt, tr)
1941 zl[lslices] = zr[rslices]
1942
1943 if not is_overlapping(tl) and not is_overlapping(tr):
1944 # Slice assignment of overlapping structures
1945 # is undefined in NumPy.
1946 self.verify(xl, obj=None,
1947 itemsize=zl.itemsize, fmt=fmt, readonly=0,
1948 ndim=zl.ndim, shape=zl.shape,
1949 strides=zl.strides, lst=zl.tolist())
1950
1951 self.verify(xr, obj=None,
1952 itemsize=zr.itemsize, fmt=fmt, readonly=0,
1953 ndim=zr.ndim, shape=zr.shape,
1954 strides=zr.strides, lst=zr.tolist())
1955
1956 def test_ndarray_re_export(self):
1957 items = [1,2,3,4,5,6,7,8,9,10,11,12]
1958
1959 nd = ndarray(items, shape=[3,4], flags=ND_PIL)
1960 ex = ndarray(nd)
1961
1962 self.assertTrue(ex.flags & ND_PIL)
1963 self.assertIs(ex.obj, nd)
1964 self.assertEqual(ex.suboffsets, (0, -1))
1965 self.assertFalse(ex.c_contiguous)
1966 self.assertFalse(ex.f_contiguous)
1967 self.assertFalse(ex.contiguous)
1968
1969 def test_ndarray_zero_shape(self):
1970 # zeros in shape
1971 for flags in (0, ND_PIL):
1972 nd = ndarray([1,2,3], shape=[0], flags=flags)
1973 mv = memoryview(nd)
1974 self.assertEqual(mv, nd)
1975 self.assertEqual(nd.tolist(), [])
1976 self.assertEqual(mv.tolist(), [])
1977
1978 nd = ndarray([1,2,3], shape=[0,3,3], flags=flags)
1979 self.assertEqual(nd.tolist(), [])
1980
1981 nd = ndarray([1,2,3], shape=[3,0,3], flags=flags)
1982 self.assertEqual(nd.tolist(), [[], [], []])
1983
1984 nd = ndarray([1,2,3], shape=[3,3,0], flags=flags)
1985 self.assertEqual(nd.tolist(),
1986 [[[], [], []], [[], [], []], [[], [], []]])
1987
1988 def test_ndarray_zero_strides(self):
1989 # zero strides
1990 for flags in (0, ND_PIL):
1991 nd = ndarray([1], shape=[5], strides=[0], flags=flags)
1992 mv = memoryview(nd)
1993 self.assertEqual(mv, nd)
1994 self.assertEqual(nd.tolist(), [1, 1, 1, 1, 1])
1995 self.assertEqual(mv.tolist(), [1, 1, 1, 1, 1])
1996
1997 def test_ndarray_offset(self):
1998 nd = ndarray(list(range(20)), shape=[3], offset=7)
1999 self.assertEqual(nd.offset, 7)
2000 self.assertEqual(nd.tolist(), [7,8,9])
2001
2002 def test_ndarray_memoryview_from_buffer(self):
2003 for flags in (0, ND_PIL):
2004 nd = ndarray(list(range(3)), shape=[3], flags=flags)
2005 m = nd.memoryview_from_buffer()
2006 self.assertEqual(m, nd)
2007
2008 def test_ndarray_get_pointer(self):
2009 for flags in (0, ND_PIL):
2010 nd = ndarray(list(range(3)), shape=[3], flags=flags)
2011 for i in range(3):
2012 self.assertEqual(nd[i], get_pointer(nd, [i]))
2013
2014 def test_ndarray_tolist_null_strides(self):
2015 ex = ndarray(list(range(20)), shape=[2,2,5])
2016
2017 nd = ndarray(ex, getbuf=PyBUF_ND|PyBUF_FORMAT)
2018 self.assertEqual(nd.tolist(), ex.tolist())
2019
2020 m = memoryview(ex)
2021 self.assertEqual(m.tolist(), ex.tolist())
2022
2023 def test_ndarray_cmp_contig(self):
2024
2025 self.assertFalse(cmp_contig(b"123", b"456"))
2026
2027 x = ndarray(list(range(12)), shape=[3,4])
2028 y = ndarray(list(range(12)), shape=[4,3])
2029 self.assertFalse(cmp_contig(x, y))
2030
2031 x = ndarray([1], shape=[1], format="B")
2032 self.assertTrue(cmp_contig(x, b'\x01'))
2033 self.assertTrue(cmp_contig(b'\x01', x))
2034
2035 def test_ndarray_hash(self):
2036
2037 a = array.array('L', [1,2,3])
2038 nd = ndarray(a)
2039 self.assertRaises(ValueError, hash, nd)
2040
2041 # one-dimensional
2042 b = bytes(list(range(12)))
2043
2044 nd = ndarray(list(range(12)), shape=[12])
2045 self.assertEqual(hash(nd), hash(b))
2046
2047 # C-contiguous
2048 nd = ndarray(list(range(12)), shape=[3,4])
2049 self.assertEqual(hash(nd), hash(b))
2050
2051 nd = ndarray(list(range(12)), shape=[3,2,2])
2052 self.assertEqual(hash(nd), hash(b))
2053
2054 # Fortran contiguous
2055 b = bytes(transpose(list(range(12)), shape=[4,3]))
2056 nd = ndarray(list(range(12)), shape=[3,4], flags=ND_FORTRAN)
2057 self.assertEqual(hash(nd), hash(b))
2058
2059 b = bytes(transpose(list(range(12)), shape=[2,3,2]))
2060 nd = ndarray(list(range(12)), shape=[2,3,2], flags=ND_FORTRAN)
2061 self.assertEqual(hash(nd), hash(b))
2062
2063 # suboffsets
2064 b = bytes(list(range(12)))
2065 nd = ndarray(list(range(12)), shape=[2,2,3], flags=ND_PIL)
2066 self.assertEqual(hash(nd), hash(b))
2067
2068 # non-byte formats
2069 nd = ndarray(list(range(12)), shape=[2,2,3], format='L')
2070 self.assertEqual(hash(nd), hash(nd.tobytes()))
2071
Stefan Krah7d12d9d2012-07-28 12:25:55 +02002072 def test_py_buffer_to_contiguous(self):
2073
2074 # The requests are used in _testbuffer.c:py_buffer_to_contiguous
2075 # to generate buffers without full information for testing.
2076 requests = (
2077 # distinct flags
2078 PyBUF_INDIRECT, PyBUF_STRIDES, PyBUF_ND, PyBUF_SIMPLE,
2079 # compound requests
2080 PyBUF_FULL, PyBUF_FULL_RO,
2081 PyBUF_RECORDS, PyBUF_RECORDS_RO,
2082 PyBUF_STRIDED, PyBUF_STRIDED_RO,
2083 PyBUF_CONTIG, PyBUF_CONTIG_RO,
2084 )
2085
2086 # no buffer interface
2087 self.assertRaises(TypeError, py_buffer_to_contiguous, {}, 'F',
2088 PyBUF_FULL_RO)
2089
2090 # scalar, read-only request
2091 nd = ndarray(9, shape=(), format="L", flags=ND_WRITABLE)
2092 for order in ['C', 'F', 'A']:
2093 for request in requests:
2094 b = py_buffer_to_contiguous(nd, order, request)
2095 self.assertEqual(b, nd.tobytes())
2096
2097 # zeros in shape
2098 nd = ndarray([1], shape=[0], format="L", flags=ND_WRITABLE)
2099 for order in ['C', 'F', 'A']:
2100 for request in requests:
2101 b = py_buffer_to_contiguous(nd, order, request)
2102 self.assertEqual(b, b'')
2103
2104 nd = ndarray(list(range(8)), shape=[2, 0, 7], format="L",
2105 flags=ND_WRITABLE)
2106 for order in ['C', 'F', 'A']:
2107 for request in requests:
2108 b = py_buffer_to_contiguous(nd, order, request)
2109 self.assertEqual(b, b'')
2110
2111 ### One-dimensional arrays are trivial, since Fortran and C order
2112 ### are the same.
2113
2114 # one-dimensional
2115 for f in [0, ND_FORTRAN]:
2116 nd = ndarray([1], shape=[1], format="h", flags=f|ND_WRITABLE)
2117 ndbytes = nd.tobytes()
2118 for order in ['C', 'F', 'A']:
2119 for request in requests:
2120 b = py_buffer_to_contiguous(nd, order, request)
2121 self.assertEqual(b, ndbytes)
2122
2123 nd = ndarray([1, 2, 3], shape=[3], format="b", flags=f|ND_WRITABLE)
2124 ndbytes = nd.tobytes()
2125 for order in ['C', 'F', 'A']:
2126 for request in requests:
2127 b = py_buffer_to_contiguous(nd, order, request)
2128 self.assertEqual(b, ndbytes)
2129
2130 # one-dimensional, non-contiguous input
2131 nd = ndarray([1, 2, 3], shape=[2], strides=[2], flags=ND_WRITABLE)
2132 ndbytes = nd.tobytes()
2133 for order in ['C', 'F', 'A']:
2134 for request in [PyBUF_STRIDES, PyBUF_FULL]:
2135 b = py_buffer_to_contiguous(nd, order, request)
2136 self.assertEqual(b, ndbytes)
2137
2138 nd = nd[::-1]
2139 ndbytes = nd.tobytes()
2140 for order in ['C', 'F', 'A']:
2141 for request in requests:
2142 try:
2143 b = py_buffer_to_contiguous(nd, order, request)
2144 except BufferError:
2145 continue
2146 self.assertEqual(b, ndbytes)
2147
2148 ###
2149 ### Multi-dimensional arrays:
2150 ###
2151 ### The goal here is to preserve the logical representation of the
2152 ### input array but change the physical representation if necessary.
2153 ###
2154 ### _testbuffer example:
2155 ### ====================
2156 ###
2157 ### C input array:
2158 ### --------------
2159 ### >>> nd = ndarray(list(range(12)), shape=[3, 4])
2160 ### >>> nd.tolist()
2161 ### [[0, 1, 2, 3],
2162 ### [4, 5, 6, 7],
2163 ### [8, 9, 10, 11]]
2164 ###
2165 ### Fortran output:
2166 ### ---------------
2167 ### >>> py_buffer_to_contiguous(nd, 'F', PyBUF_FULL_RO)
2168 ### >>> b'\x00\x04\x08\x01\x05\t\x02\x06\n\x03\x07\x0b'
2169 ###
2170 ### The return value corresponds to this input list for
2171 ### _testbuffer's ndarray:
2172 ### >>> nd = ndarray([0,4,8,1,5,9,2,6,10,3,7,11], shape=[3,4],
2173 ### flags=ND_FORTRAN)
2174 ### >>> nd.tolist()
2175 ### [[0, 1, 2, 3],
2176 ### [4, 5, 6, 7],
2177 ### [8, 9, 10, 11]]
2178 ###
2179 ### The logical array is the same, but the values in memory are now
2180 ### in Fortran order.
2181 ###
2182 ### NumPy example:
2183 ### ==============
2184 ### _testbuffer's ndarray takes lists to initialize the memory.
2185 ### Here's the same sequence in NumPy:
2186 ###
2187 ### C input:
2188 ### --------
2189 ### >>> nd = ndarray(buffer=bytearray(list(range(12))),
2190 ### shape=[3, 4], dtype='B')
2191 ### >>> nd
2192 ### array([[ 0, 1, 2, 3],
2193 ### [ 4, 5, 6, 7],
2194 ### [ 8, 9, 10, 11]], dtype=uint8)
2195 ###
2196 ### Fortran output:
2197 ### ---------------
2198 ### >>> fortran_buf = nd.tostring(order='F')
2199 ### >>> fortran_buf
2200 ### b'\x00\x04\x08\x01\x05\t\x02\x06\n\x03\x07\x0b'
2201 ###
2202 ### >>> nd = ndarray(buffer=fortran_buf, shape=[3, 4],
2203 ### dtype='B', order='F')
2204 ###
2205 ### >>> nd
2206 ### array([[ 0, 1, 2, 3],
2207 ### [ 4, 5, 6, 7],
2208 ### [ 8, 9, 10, 11]], dtype=uint8)
2209 ###
2210
2211 # multi-dimensional, contiguous input
2212 lst = list(range(12))
2213 for f in [0, ND_FORTRAN]:
2214 nd = ndarray(lst, shape=[3, 4], flags=f|ND_WRITABLE)
2215 if numpy_array:
2216 na = numpy_array(buffer=bytearray(lst),
2217 shape=[3, 4], dtype='B',
2218 order='C' if f == 0 else 'F')
2219
2220 # 'C' request
2221 if f == ND_FORTRAN: # 'F' to 'C'
2222 x = ndarray(transpose(lst, [4, 3]), shape=[3, 4],
2223 flags=ND_WRITABLE)
2224 expected = x.tobytes()
2225 else:
2226 expected = nd.tobytes()
2227 for request in requests:
2228 try:
2229 b = py_buffer_to_contiguous(nd, 'C', request)
2230 except BufferError:
2231 continue
2232
2233 self.assertEqual(b, expected)
2234
2235 # Check that output can be used as the basis for constructing
2236 # a C array that is logically identical to the input array.
2237 y = ndarray([v for v in b], shape=[3, 4], flags=ND_WRITABLE)
2238 self.assertEqual(memoryview(y), memoryview(nd))
2239
2240 if numpy_array:
2241 self.assertEqual(b, na.tostring(order='C'))
2242
2243 # 'F' request
2244 if f == 0: # 'C' to 'F'
2245 x = ndarray(transpose(lst, [3, 4]), shape=[4, 3],
2246 flags=ND_WRITABLE)
2247 else:
2248 x = ndarray(lst, shape=[3, 4], flags=ND_WRITABLE)
2249 expected = x.tobytes()
2250 for request in [PyBUF_FULL, PyBUF_FULL_RO, PyBUF_INDIRECT,
2251 PyBUF_STRIDES, PyBUF_ND]:
2252 try:
2253 b = py_buffer_to_contiguous(nd, 'F', request)
2254 except BufferError:
2255 continue
2256 self.assertEqual(b, expected)
2257
2258 # Check that output can be used as the basis for constructing
2259 # a Fortran array that is logically identical to the input array.
2260 y = ndarray([v for v in b], shape=[3, 4], flags=ND_FORTRAN|ND_WRITABLE)
2261 self.assertEqual(memoryview(y), memoryview(nd))
2262
2263 if numpy_array:
2264 self.assertEqual(b, na.tostring(order='F'))
2265
2266 # 'A' request
2267 if f == ND_FORTRAN:
2268 x = ndarray(lst, shape=[3, 4], flags=ND_WRITABLE)
2269 expected = x.tobytes()
2270 else:
2271 expected = nd.tobytes()
2272 for request in [PyBUF_FULL, PyBUF_FULL_RO, PyBUF_INDIRECT,
2273 PyBUF_STRIDES, PyBUF_ND]:
2274 try:
2275 b = py_buffer_to_contiguous(nd, 'A', request)
2276 except BufferError:
2277 continue
2278
2279 self.assertEqual(b, expected)
2280
2281 # Check that output can be used as the basis for constructing
2282 # an array with order=f that is logically identical to the input
2283 # array.
2284 y = ndarray([v for v in b], shape=[3, 4], flags=f|ND_WRITABLE)
2285 self.assertEqual(memoryview(y), memoryview(nd))
2286
2287 if numpy_array:
2288 self.assertEqual(b, na.tostring(order='A'))
2289
2290 # multi-dimensional, non-contiguous input
2291 nd = ndarray(list(range(12)), shape=[3, 4], flags=ND_WRITABLE|ND_PIL)
2292
2293 # 'C'
2294 b = py_buffer_to_contiguous(nd, 'C', PyBUF_FULL_RO)
2295 self.assertEqual(b, nd.tobytes())
2296 y = ndarray([v for v in b], shape=[3, 4], flags=ND_WRITABLE)
2297 self.assertEqual(memoryview(y), memoryview(nd))
2298
2299 # 'F'
2300 b = py_buffer_to_contiguous(nd, 'F', PyBUF_FULL_RO)
2301 x = ndarray(transpose(lst, [3, 4]), shape=[4, 3], flags=ND_WRITABLE)
2302 self.assertEqual(b, x.tobytes())
2303 y = ndarray([v for v in b], shape=[3, 4], flags=ND_FORTRAN|ND_WRITABLE)
2304 self.assertEqual(memoryview(y), memoryview(nd))
2305
2306 # 'A'
2307 b = py_buffer_to_contiguous(nd, 'A', PyBUF_FULL_RO)
2308 self.assertEqual(b, nd.tobytes())
2309 y = ndarray([v for v in b], shape=[3, 4], flags=ND_WRITABLE)
2310 self.assertEqual(memoryview(y), memoryview(nd))
2311
Stefan Krah9a2d99e2012-02-25 12:24:21 +01002312 def test_memoryview_construction(self):
2313
2314 items_shape = [(9, []), ([1,2,3], [3]), (list(range(2*3*5)), [2,3,5])]
2315
2316 # NumPy style, C-contiguous:
2317 for items, shape in items_shape:
2318
2319 # From PEP-3118 compliant exporter:
2320 ex = ndarray(items, shape=shape)
2321 m = memoryview(ex)
2322 self.assertTrue(m.c_contiguous)
2323 self.assertTrue(m.contiguous)
2324
2325 ndim = len(shape)
2326 strides = strides_from_shape(ndim, shape, 1, 'C')
2327 lst = carray(items, shape)
2328
2329 self.verify(m, obj=ex,
2330 itemsize=1, fmt='B', readonly=1,
2331 ndim=ndim, shape=shape, strides=strides,
2332 lst=lst)
2333
2334 # From memoryview:
2335 m2 = memoryview(m)
2336 self.verify(m2, obj=ex,
2337 itemsize=1, fmt='B', readonly=1,
2338 ndim=ndim, shape=shape, strides=strides,
2339 lst=lst)
2340
2341 # PyMemoryView_FromBuffer(): no strides
2342 nd = ndarray(ex, getbuf=PyBUF_CONTIG_RO|PyBUF_FORMAT)
2343 self.assertEqual(nd.strides, ())
2344 m = nd.memoryview_from_buffer()
2345 self.verify(m, obj=None,
2346 itemsize=1, fmt='B', readonly=1,
2347 ndim=ndim, shape=shape, strides=strides,
2348 lst=lst)
2349
2350 # PyMemoryView_FromBuffer(): no format, shape, strides
2351 nd = ndarray(ex, getbuf=PyBUF_SIMPLE)
2352 self.assertEqual(nd.format, '')
2353 self.assertEqual(nd.shape, ())
2354 self.assertEqual(nd.strides, ())
2355 m = nd.memoryview_from_buffer()
2356
2357 lst = [items] if ndim == 0 else items
2358 self.verify(m, obj=None,
2359 itemsize=1, fmt='B', readonly=1,
2360 ndim=1, shape=[ex.nbytes], strides=(1,),
2361 lst=lst)
2362
2363 # NumPy style, Fortran contiguous:
2364 for items, shape in items_shape:
2365
2366 # From PEP-3118 compliant exporter:
2367 ex = ndarray(items, shape=shape, flags=ND_FORTRAN)
2368 m = memoryview(ex)
2369 self.assertTrue(m.f_contiguous)
2370 self.assertTrue(m.contiguous)
2371
2372 ndim = len(shape)
2373 strides = strides_from_shape(ndim, shape, 1, 'F')
2374 lst = farray(items, shape)
2375
2376 self.verify(m, obj=ex,
2377 itemsize=1, fmt='B', readonly=1,
2378 ndim=ndim, shape=shape, strides=strides,
2379 lst=lst)
2380
2381 # From memoryview:
2382 m2 = memoryview(m)
2383 self.verify(m2, obj=ex,
2384 itemsize=1, fmt='B', readonly=1,
2385 ndim=ndim, shape=shape, strides=strides,
2386 lst=lst)
2387
2388 # PIL style:
2389 for items, shape in items_shape[1:]:
2390
2391 # From PEP-3118 compliant exporter:
2392 ex = ndarray(items, shape=shape, flags=ND_PIL)
2393 m = memoryview(ex)
2394
2395 ndim = len(shape)
2396 lst = carray(items, shape)
2397
2398 self.verify(m, obj=ex,
2399 itemsize=1, fmt='B', readonly=1,
2400 ndim=ndim, shape=shape, strides=ex.strides,
2401 lst=lst)
2402
2403 # From memoryview:
2404 m2 = memoryview(m)
2405 self.verify(m2, obj=ex,
2406 itemsize=1, fmt='B', readonly=1,
2407 ndim=ndim, shape=shape, strides=ex.strides,
2408 lst=lst)
2409
2410 # Invalid number of arguments:
2411 self.assertRaises(TypeError, memoryview, b'9', 'x')
2412 # Not a buffer provider:
2413 self.assertRaises(TypeError, memoryview, {})
2414 # Non-compliant buffer provider:
2415 ex = ndarray([1,2,3], shape=[3])
2416 nd = ndarray(ex, getbuf=PyBUF_SIMPLE)
2417 self.assertRaises(BufferError, memoryview, nd)
2418 nd = ndarray(ex, getbuf=PyBUF_CONTIG_RO|PyBUF_FORMAT)
2419 self.assertRaises(BufferError, memoryview, nd)
2420
2421 # ndim > 64
2422 nd = ndarray([1]*128, shape=[1]*128, format='L')
2423 self.assertRaises(ValueError, memoryview, nd)
2424 self.assertRaises(ValueError, nd.memoryview_from_buffer)
2425 self.assertRaises(ValueError, get_contiguous, nd, PyBUF_READ, 'C')
2426 self.assertRaises(ValueError, get_contiguous, nd, PyBUF_READ, 'F')
2427 self.assertRaises(ValueError, get_contiguous, nd[::-1], PyBUF_READ, 'C')
2428
2429 def test_memoryview_cast_zero_shape(self):
2430 # Casts are undefined if shape contains zeros. These arrays are
2431 # regarded as C-contiguous by Numpy and PyBuffer_GetContiguous(),
2432 # so they are not caught by the test for C-contiguity in memory_cast().
2433 items = [1,2,3]
2434 for shape in ([0,3,3], [3,0,3], [0,3,3]):
2435 ex = ndarray(items, shape=shape)
2436 self.assertTrue(ex.c_contiguous)
2437 msrc = memoryview(ex)
2438 self.assertRaises(TypeError, msrc.cast, 'c')
2439
2440 def test_memoryview_struct_module(self):
2441
2442 class INT(object):
2443 def __init__(self, val):
2444 self.val = val
2445 def __int__(self):
2446 return self.val
2447
2448 class IDX(object):
2449 def __init__(self, val):
2450 self.val = val
2451 def __index__(self):
2452 return self.val
2453
2454 def f(): return 7
2455
2456 values = [INT(9), IDX(9),
2457 2.2+3j, Decimal("-21.1"), 12.2, Fraction(5, 2),
2458 [1,2,3], {4,5,6}, {7:8}, (), (9,),
2459 True, False, None, NotImplemented,
2460 b'a', b'abc', bytearray(b'a'), bytearray(b'abc'),
2461 'a', 'abc', r'a', r'abc',
2462 f, lambda x: x]
2463
2464 for fmt, items, item in iter_format(10, 'memoryview'):
2465 ex = ndarray(items, shape=[10], format=fmt, flags=ND_WRITABLE)
2466 nd = ndarray(items, shape=[10], format=fmt, flags=ND_WRITABLE)
2467 m = memoryview(ex)
2468
2469 struct.pack_into(fmt, nd, 0, item)
2470 m[0] = item
2471 self.assertEqual(m[0], nd[0])
2472
2473 itemsize = struct.calcsize(fmt)
2474 if 'P' in fmt:
2475 continue
2476
2477 for v in values:
2478 struct_err = None
2479 try:
2480 struct.pack_into(fmt, nd, itemsize, v)
2481 except struct.error:
2482 struct_err = struct.error
2483
2484 mv_err = None
2485 try:
2486 m[1] = v
2487 except (TypeError, ValueError) as e:
2488 mv_err = e.__class__
2489
2490 if struct_err or mv_err:
2491 self.assertIsNot(struct_err, None)
2492 self.assertIsNot(mv_err, None)
2493 else:
2494 self.assertEqual(m[1], nd[1])
2495
2496 def test_memoryview_cast_zero_strides(self):
2497 # Casts are undefined if strides contains zeros. These arrays are
2498 # (sometimes!) regarded as C-contiguous by Numpy, but not by
2499 # PyBuffer_GetContiguous().
2500 ex = ndarray([1,2,3], shape=[3], strides=[0])
2501 self.assertFalse(ex.c_contiguous)
2502 msrc = memoryview(ex)
2503 self.assertRaises(TypeError, msrc.cast, 'c')
2504
2505 def test_memoryview_cast_invalid(self):
2506 # invalid format
2507 for sfmt in NON_BYTE_FORMAT:
2508 sformat = '@' + sfmt if randrange(2) else sfmt
2509 ssize = struct.calcsize(sformat)
2510 for dfmt in NON_BYTE_FORMAT:
2511 dformat = '@' + dfmt if randrange(2) else dfmt
2512 dsize = struct.calcsize(dformat)
2513 ex = ndarray(list(range(32)), shape=[32//ssize], format=sformat)
2514 msrc = memoryview(ex)
2515 self.assertRaises(TypeError, msrc.cast, dfmt, [32//dsize])
2516
2517 for sfmt, sitems, _ in iter_format(1):
2518 ex = ndarray(sitems, shape=[1], format=sfmt)
2519 msrc = memoryview(ex)
2520 for dfmt, _, _ in iter_format(1):
2521 if (not is_memoryview_format(sfmt) or
2522 not is_memoryview_format(dfmt)):
2523 self.assertRaises(ValueError, msrc.cast, dfmt,
2524 [32//dsize])
2525 else:
2526 if not is_byte_format(sfmt) and not is_byte_format(dfmt):
2527 self.assertRaises(TypeError, msrc.cast, dfmt,
2528 [32//dsize])
2529
2530 # invalid shape
2531 size_h = struct.calcsize('h')
2532 size_d = struct.calcsize('d')
2533 ex = ndarray(list(range(2*2*size_d)), shape=[2,2,size_d], format='h')
2534 msrc = memoryview(ex)
2535 self.assertRaises(TypeError, msrc.cast, shape=[2,2,size_h], format='d')
2536
2537 ex = ndarray(list(range(120)), shape=[1,2,3,4,5])
2538 m = memoryview(ex)
2539
2540 # incorrect number of args
2541 self.assertRaises(TypeError, m.cast)
2542 self.assertRaises(TypeError, m.cast, 1, 2, 3)
2543
2544 # incorrect dest format type
2545 self.assertRaises(TypeError, m.cast, {})
2546
2547 # incorrect dest format
2548 self.assertRaises(ValueError, m.cast, "X")
2549 self.assertRaises(ValueError, m.cast, "@X")
2550 self.assertRaises(ValueError, m.cast, "@XY")
2551
2552 # dest format not implemented
2553 self.assertRaises(ValueError, m.cast, "=B")
2554 self.assertRaises(ValueError, m.cast, "!L")
2555 self.assertRaises(ValueError, m.cast, "<P")
2556 self.assertRaises(ValueError, m.cast, ">l")
2557 self.assertRaises(ValueError, m.cast, "BI")
2558 self.assertRaises(ValueError, m.cast, "xBI")
2559
2560 # src format not implemented
2561 ex = ndarray([(1,2), (3,4)], shape=[2], format="II")
2562 m = memoryview(ex)
2563 self.assertRaises(NotImplementedError, m.__getitem__, 0)
2564 self.assertRaises(NotImplementedError, m.__setitem__, 0, 8)
2565 self.assertRaises(NotImplementedError, m.tolist)
2566
2567 # incorrect shape type
2568 ex = ndarray(list(range(120)), shape=[1,2,3,4,5])
2569 m = memoryview(ex)
2570 self.assertRaises(TypeError, m.cast, "B", shape={})
2571
2572 # incorrect shape elements
2573 ex = ndarray(list(range(120)), shape=[2*3*4*5])
2574 m = memoryview(ex)
2575 self.assertRaises(OverflowError, m.cast, "B", shape=[2**64])
2576 self.assertRaises(ValueError, m.cast, "B", shape=[-1])
2577 self.assertRaises(ValueError, m.cast, "B", shape=[2,3,4,5,6,7,-1])
2578 self.assertRaises(ValueError, m.cast, "B", shape=[2,3,4,5,6,7,0])
2579 self.assertRaises(TypeError, m.cast, "B", shape=[2,3,4,5,6,7,'x'])
2580
2581 # N-D -> N-D cast
2582 ex = ndarray(list([9 for _ in range(3*5*7*11)]), shape=[3,5,7,11])
2583 m = memoryview(ex)
2584 self.assertRaises(TypeError, m.cast, "I", shape=[2,3,4,5])
2585
2586 # cast with ndim > 64
2587 nd = ndarray(list(range(128)), shape=[128], format='I')
2588 m = memoryview(nd)
2589 self.assertRaises(ValueError, m.cast, 'I', [1]*128)
2590
2591 # view->len not a multiple of itemsize
2592 ex = ndarray(list([9 for _ in range(3*5*7*11)]), shape=[3*5*7*11])
2593 m = memoryview(ex)
2594 self.assertRaises(TypeError, m.cast, "I", shape=[2,3,4,5])
2595
2596 # product(shape) * itemsize != buffer size
2597 ex = ndarray(list([9 for _ in range(3*5*7*11)]), shape=[3*5*7*11])
2598 m = memoryview(ex)
2599 self.assertRaises(TypeError, m.cast, "B", shape=[2,3,4,5])
2600
2601 # product(shape) * itemsize overflow
2602 nd = ndarray(list(range(128)), shape=[128], format='I')
2603 m1 = memoryview(nd)
2604 nd = ndarray(list(range(128)), shape=[128], format='B')
2605 m2 = memoryview(nd)
2606 if sys.maxsize == 2**63-1:
2607 self.assertRaises(TypeError, m1.cast, 'B',
2608 [7, 7, 73, 127, 337, 92737, 649657])
2609 self.assertRaises(ValueError, m1.cast, 'B',
2610 [2**20, 2**20, 2**10, 2**10, 2**3])
2611 self.assertRaises(ValueError, m2.cast, 'I',
2612 [2**20, 2**20, 2**10, 2**10, 2**1])
2613 else:
2614 self.assertRaises(TypeError, m1.cast, 'B',
2615 [1, 2147483647])
2616 self.assertRaises(ValueError, m1.cast, 'B',
2617 [2**10, 2**10, 2**5, 2**5, 2**1])
2618 self.assertRaises(ValueError, m2.cast, 'I',
2619 [2**10, 2**10, 2**5, 2**3, 2**1])
2620
2621 def test_memoryview_cast(self):
2622 bytespec = (
2623 ('B', lambda ex: list(ex.tobytes())),
2624 ('b', lambda ex: [x-256 if x > 127 else x for x in list(ex.tobytes())]),
2625 ('c', lambda ex: [bytes(chr(x), 'latin-1') for x in list(ex.tobytes())]),
2626 )
2627
2628 def iter_roundtrip(ex, m, items, fmt):
2629 srcsize = struct.calcsize(fmt)
2630 for bytefmt, to_bytelist in bytespec:
2631
2632 m2 = m.cast(bytefmt)
2633 lst = to_bytelist(ex)
2634 self.verify(m2, obj=ex,
2635 itemsize=1, fmt=bytefmt, readonly=0,
2636 ndim=1, shape=[31*srcsize], strides=(1,),
2637 lst=lst, cast=True)
2638
2639 m3 = m2.cast(fmt)
2640 self.assertEqual(m3, ex)
2641 lst = ex.tolist()
2642 self.verify(m3, obj=ex,
2643 itemsize=srcsize, fmt=fmt, readonly=0,
2644 ndim=1, shape=[31], strides=(srcsize,),
2645 lst=lst, cast=True)
2646
2647 # cast from ndim = 0 to ndim = 1
2648 srcsize = struct.calcsize('I')
2649 ex = ndarray(9, shape=[], format='I')
2650 destitems, destshape = cast_items(ex, 'B', 1)
2651 m = memoryview(ex)
2652 m2 = m.cast('B')
2653 self.verify(m2, obj=ex,
2654 itemsize=1, fmt='B', readonly=1,
2655 ndim=1, shape=destshape, strides=(1,),
2656 lst=destitems, cast=True)
2657
2658 # cast from ndim = 1 to ndim = 0
2659 destsize = struct.calcsize('I')
2660 ex = ndarray([9]*destsize, shape=[destsize], format='B')
2661 destitems, destshape = cast_items(ex, 'I', destsize, shape=[])
2662 m = memoryview(ex)
2663 m2 = m.cast('I', shape=[])
2664 self.verify(m2, obj=ex,
2665 itemsize=destsize, fmt='I', readonly=1,
2666 ndim=0, shape=(), strides=(),
2667 lst=destitems, cast=True)
2668
2669 # array.array: roundtrip to/from bytes
2670 for fmt, items, _ in iter_format(31, 'array'):
2671 ex = array.array(fmt, items)
2672 m = memoryview(ex)
2673 iter_roundtrip(ex, m, items, fmt)
2674
2675 # ndarray: roundtrip to/from bytes
2676 for fmt, items, _ in iter_format(31, 'memoryview'):
2677 ex = ndarray(items, shape=[31], format=fmt, flags=ND_WRITABLE)
2678 m = memoryview(ex)
2679 iter_roundtrip(ex, m, items, fmt)
2680
2681 def test_memoryview_cast_1D_ND(self):
2682 # Cast between C-contiguous buffers. At least one buffer must
2683 # be 1D, at least one format must be 'c', 'b' or 'B'.
2684 for _tshape in gencastshapes():
2685 for char in fmtdict['@']:
2686 tfmt = ('', '@')[randrange(2)] + char
2687 tsize = struct.calcsize(tfmt)
2688 n = prod(_tshape) * tsize
2689 obj = 'memoryview' if is_byte_format(tfmt) else 'bytefmt'
2690 for fmt, items, _ in iter_format(n, obj):
2691 size = struct.calcsize(fmt)
2692 shape = [n] if n > 0 else []
2693 tshape = _tshape + [size]
2694
2695 ex = ndarray(items, shape=shape, format=fmt)
2696 m = memoryview(ex)
2697
2698 titems, tshape = cast_items(ex, tfmt, tsize, shape=tshape)
2699
2700 if titems is None:
2701 self.assertRaises(TypeError, m.cast, tfmt, tshape)
2702 continue
2703 if titems == 'nan':
2704 continue # NaNs in lists are a recipe for trouble.
2705
2706 # 1D -> ND
2707 nd = ndarray(titems, shape=tshape, format=tfmt)
2708
2709 m2 = m.cast(tfmt, shape=tshape)
2710 ndim = len(tshape)
2711 strides = nd.strides
2712 lst = nd.tolist()
2713 self.verify(m2, obj=ex,
2714 itemsize=tsize, fmt=tfmt, readonly=1,
2715 ndim=ndim, shape=tshape, strides=strides,
2716 lst=lst, cast=True)
2717
2718 # ND -> 1D
2719 m3 = m2.cast(fmt)
2720 m4 = m2.cast(fmt, shape=shape)
2721 ndim = len(shape)
2722 strides = ex.strides
2723 lst = ex.tolist()
2724
2725 self.verify(m3, obj=ex,
2726 itemsize=size, fmt=fmt, readonly=1,
2727 ndim=ndim, shape=shape, strides=strides,
2728 lst=lst, cast=True)
2729
2730 self.verify(m4, obj=ex,
2731 itemsize=size, fmt=fmt, readonly=1,
2732 ndim=ndim, shape=shape, strides=strides,
2733 lst=lst, cast=True)
2734
2735 def test_memoryview_tolist(self):
2736
2737 # Most tolist() tests are in self.verify() etc.
2738
2739 a = array.array('h', list(range(-6, 6)))
2740 m = memoryview(a)
2741 self.assertEqual(m, a)
2742 self.assertEqual(m.tolist(), a.tolist())
2743
2744 a = a[2::3]
2745 m = m[2::3]
2746 self.assertEqual(m, a)
2747 self.assertEqual(m.tolist(), a.tolist())
2748
2749 ex = ndarray(list(range(2*3*5*7*11)), shape=[11,2,7,3,5], format='L')
2750 m = memoryview(ex)
2751 self.assertEqual(m.tolist(), ex.tolist())
2752
2753 ex = ndarray([(2, 5), (7, 11)], shape=[2], format='lh')
2754 m = memoryview(ex)
2755 self.assertRaises(NotImplementedError, m.tolist)
2756
2757 ex = ndarray([b'12345'], shape=[1], format="s")
2758 m = memoryview(ex)
2759 self.assertRaises(NotImplementedError, m.tolist)
2760
2761 ex = ndarray([b"a",b"b",b"c",b"d",b"e",b"f"], shape=[2,3], format='s')
2762 m = memoryview(ex)
2763 self.assertRaises(NotImplementedError, m.tolist)
2764
2765 def test_memoryview_repr(self):
2766 m = memoryview(bytearray(9))
2767 r = m.__repr__()
2768 self.assertTrue(r.startswith("<memory"))
2769
2770 m.release()
2771 r = m.__repr__()
2772 self.assertTrue(r.startswith("<released"))
2773
2774 def test_memoryview_sequence(self):
2775
2776 for fmt in ('d', 'f'):
2777 inf = float(3e400)
2778 ex = array.array(fmt, [1.0, inf, 3.0])
2779 m = memoryview(ex)
2780 self.assertIn(1.0, m)
2781 self.assertIn(5e700, m)
2782 self.assertIn(3.0, m)
2783
2784 ex = ndarray(9.0, [], format='f')
2785 m = memoryview(ex)
2786 self.assertRaises(TypeError, eval, "9.0 in m", locals())
2787
2788 def test_memoryview_index(self):
2789
2790 # ndim = 0
2791 ex = ndarray(12.5, shape=[], format='d')
2792 m = memoryview(ex)
2793 self.assertEqual(m[()], 12.5)
2794 self.assertEqual(m[...], m)
2795 self.assertEqual(m[...], ex)
2796 self.assertRaises(TypeError, m.__getitem__, 0)
2797
2798 ex = ndarray((1,2,3), shape=[], format='iii')
2799 m = memoryview(ex)
2800 self.assertRaises(NotImplementedError, m.__getitem__, ())
2801
2802 # range
2803 ex = ndarray(list(range(7)), shape=[7], flags=ND_WRITABLE)
2804 m = memoryview(ex)
2805
2806 self.assertRaises(IndexError, m.__getitem__, 2**64)
2807 self.assertRaises(TypeError, m.__getitem__, 2.0)
2808 self.assertRaises(TypeError, m.__getitem__, 0.0)
2809
2810 # out of bounds
2811 self.assertRaises(IndexError, m.__getitem__, -8)
2812 self.assertRaises(IndexError, m.__getitem__, 8)
2813
2814 # Not implemented: multidimensional sub-views
2815 ex = ndarray(list(range(12)), shape=[3,4], flags=ND_WRITABLE)
2816 m = memoryview(ex)
2817
2818 self.assertRaises(NotImplementedError, m.__getitem__, 0)
2819 self.assertRaises(NotImplementedError, m.__setitem__, 0, 9)
2820 self.assertRaises(NotImplementedError, m.__getitem__, 0)
2821
2822 def test_memoryview_assign(self):
2823
2824 # ndim = 0
2825 ex = ndarray(12.5, shape=[], format='f', flags=ND_WRITABLE)
2826 m = memoryview(ex)
2827 m[()] = 22.5
2828 self.assertEqual(m[()], 22.5)
2829 m[...] = 23.5
2830 self.assertEqual(m[()], 23.5)
2831 self.assertRaises(TypeError, m.__setitem__, 0, 24.7)
2832
2833 # read-only
2834 ex = ndarray(list(range(7)), shape=[7])
2835 m = memoryview(ex)
2836 self.assertRaises(TypeError, m.__setitem__, 2, 10)
2837
2838 # range
2839 ex = ndarray(list(range(7)), shape=[7], flags=ND_WRITABLE)
2840 m = memoryview(ex)
2841
2842 self.assertRaises(IndexError, m.__setitem__, 2**64, 9)
2843 self.assertRaises(TypeError, m.__setitem__, 2.0, 10)
2844 self.assertRaises(TypeError, m.__setitem__, 0.0, 11)
2845
2846 # out of bounds
2847 self.assertRaises(IndexError, m.__setitem__, -8, 20)
2848 self.assertRaises(IndexError, m.__setitem__, 8, 25)
2849
2850 # pack_single() success:
2851 for fmt in fmtdict['@']:
2852 if fmt == 'c' or fmt == '?':
2853 continue
2854 ex = ndarray([1,2,3], shape=[3], format=fmt, flags=ND_WRITABLE)
2855 m = memoryview(ex)
2856 i = randrange(-3, 3)
2857 m[i] = 8
2858 self.assertEqual(m[i], 8)
2859 self.assertEqual(m[i], ex[i])
2860
2861 ex = ndarray([b'1', b'2', b'3'], shape=[3], format='c',
2862 flags=ND_WRITABLE)
2863 m = memoryview(ex)
2864 m[2] = b'9'
2865 self.assertEqual(m[2], b'9')
2866
2867 ex = ndarray([True, False, True], shape=[3], format='?',
2868 flags=ND_WRITABLE)
2869 m = memoryview(ex)
2870 m[1] = True
2871 self.assertEqual(m[1], True)
2872
2873 # pack_single() exceptions:
2874 nd = ndarray([b'x'], shape=[1], format='c', flags=ND_WRITABLE)
2875 m = memoryview(nd)
2876 self.assertRaises(TypeError, m.__setitem__, 0, 100)
2877
2878 ex = ndarray(list(range(120)), shape=[1,2,3,4,5], flags=ND_WRITABLE)
2879 m1 = memoryview(ex)
2880
2881 for fmt, _range in fmtdict['@'].items():
2882 if (fmt == '?'): # PyObject_IsTrue() accepts anything
2883 continue
2884 if fmt == 'c': # special case tested above
2885 continue
2886 m2 = m1.cast(fmt)
2887 lo, hi = _range
2888 if fmt == 'd' or fmt == 'f':
2889 lo, hi = -2**1024, 2**1024
2890 if fmt != 'P': # PyLong_AsVoidPtr() accepts negative numbers
2891 self.assertRaises(ValueError, m2.__setitem__, 0, lo-1)
2892 self.assertRaises(TypeError, m2.__setitem__, 0, "xyz")
2893 self.assertRaises(ValueError, m2.__setitem__, 0, hi)
2894
2895 # invalid item
2896 m2 = m1.cast('c')
2897 self.assertRaises(ValueError, m2.__setitem__, 0, b'\xff\xff')
2898
2899 # format not implemented
2900 ex = ndarray(list(range(1)), shape=[1], format="xL", flags=ND_WRITABLE)
2901 m = memoryview(ex)
2902 self.assertRaises(NotImplementedError, m.__setitem__, 0, 1)
2903
2904 ex = ndarray([b'12345'], shape=[1], format="s", flags=ND_WRITABLE)
2905 m = memoryview(ex)
2906 self.assertRaises(NotImplementedError, m.__setitem__, 0, 1)
2907
2908 # Not implemented: multidimensional sub-views
2909 ex = ndarray(list(range(12)), shape=[3,4], flags=ND_WRITABLE)
2910 m = memoryview(ex)
2911
2912 self.assertRaises(NotImplementedError, m.__setitem__, 0, [2, 3])
2913
2914 def test_memoryview_slice(self):
2915
2916 ex = ndarray(list(range(12)), shape=[12], flags=ND_WRITABLE)
2917 m = memoryview(ex)
2918
2919 # zero step
2920 self.assertRaises(ValueError, m.__getitem__, slice(0,2,0))
2921 self.assertRaises(ValueError, m.__setitem__, slice(0,2,0),
2922 bytearray([1,2]))
2923
2924 # invalid slice key
2925 self.assertRaises(TypeError, m.__getitem__, ())
2926
2927 # multidimensional slices
2928 ex = ndarray(list(range(12)), shape=[12], flags=ND_WRITABLE)
2929 m = memoryview(ex)
2930
2931 self.assertRaises(NotImplementedError, m.__getitem__,
2932 (slice(0,2,1), slice(0,2,1)))
2933 self.assertRaises(NotImplementedError, m.__setitem__,
2934 (slice(0,2,1), slice(0,2,1)), bytearray([1,2]))
2935
2936 # invalid slice tuple
2937 self.assertRaises(TypeError, m.__getitem__, (slice(0,2,1), {}))
2938 self.assertRaises(TypeError, m.__setitem__, (slice(0,2,1), {}),
2939 bytearray([1,2]))
2940
2941 # rvalue is not an exporter
2942 self.assertRaises(TypeError, m.__setitem__, slice(0,1,1), [1])
2943
2944 # non-contiguous slice assignment
2945 for flags in (0, ND_PIL):
2946 ex1 = ndarray(list(range(12)), shape=[12], strides=[-1], offset=11,
2947 flags=ND_WRITABLE|flags)
2948 ex2 = ndarray(list(range(24)), shape=[12], strides=[2], flags=flags)
2949 m1 = memoryview(ex1)
2950 m2 = memoryview(ex2)
2951
2952 ex1[2:5] = ex1[2:5]
2953 m1[2:5] = m2[2:5]
2954
2955 self.assertEqual(m1, ex1)
2956 self.assertEqual(m2, ex2)
2957
2958 ex1[1:3][::-1] = ex2[0:2][::1]
2959 m1[1:3][::-1] = m2[0:2][::1]
2960
2961 self.assertEqual(m1, ex1)
2962 self.assertEqual(m2, ex2)
2963
2964 ex1[4:1:-2][::-1] = ex1[1:4:2][::1]
2965 m1[4:1:-2][::-1] = m1[1:4:2][::1]
2966
2967 self.assertEqual(m1, ex1)
2968 self.assertEqual(m2, ex2)
2969
2970 def test_memoryview_array(self):
2971
2972 def cmptest(testcase, a, b, m, singleitem):
2973 for i, _ in enumerate(a):
2974 ai = a[i]
2975 mi = m[i]
2976 testcase.assertEqual(ai, mi)
2977 a[i] = singleitem
2978 if singleitem != ai:
2979 testcase.assertNotEqual(a, m)
2980 testcase.assertNotEqual(a, b)
2981 else:
2982 testcase.assertEqual(a, m)
2983 testcase.assertEqual(a, b)
2984 m[i] = singleitem
2985 testcase.assertEqual(a, m)
2986 testcase.assertEqual(b, m)
2987 a[i] = ai
2988 m[i] = mi
2989
2990 for n in range(1, 5):
2991 for fmt, items, singleitem in iter_format(n, 'array'):
2992 for lslice in genslices(n):
2993 for rslice in genslices(n):
2994
2995 a = array.array(fmt, items)
2996 b = array.array(fmt, items)
2997 m = memoryview(b)
2998
2999 self.assertEqual(m, a)
3000 self.assertEqual(m.tolist(), a.tolist())
3001 self.assertEqual(m.tobytes(), a.tobytes())
3002 self.assertEqual(len(m), len(a))
3003
3004 cmptest(self, a, b, m, singleitem)
3005
3006 array_err = None
3007 have_resize = None
3008 try:
3009 al = a[lslice]
3010 ar = a[rslice]
3011 a[lslice] = a[rslice]
3012 have_resize = len(al) != len(ar)
3013 except Exception as e:
3014 array_err = e.__class__
3015
3016 m_err = None
3017 try:
3018 m[lslice] = m[rslice]
3019 except Exception as e:
3020 m_err = e.__class__
3021
3022 if have_resize: # memoryview cannot change shape
3023 self.assertIs(m_err, ValueError)
3024 elif m_err or array_err:
3025 self.assertIs(m_err, array_err)
3026 else:
3027 self.assertEqual(m, a)
3028 self.assertEqual(m.tolist(), a.tolist())
3029 self.assertEqual(m.tobytes(), a.tobytes())
3030 cmptest(self, a, b, m, singleitem)
3031
3032 def test_memoryview_compare(self):
3033
3034 a = array.array('L', [1, 2, 3])
3035 b = array.array('L', [1, 2, 7])
3036
3037 # Ordering comparisons raise:
3038 v = memoryview(a)
3039 w = memoryview(b)
3040 for attr in ('__lt__', '__le__', '__gt__', '__ge__'):
3041 self.assertIs(getattr(v, attr)(w), NotImplemented)
3042 self.assertIs(getattr(a, attr)(v), NotImplemented)
3043
3044 # Released views compare equal to themselves:
3045 v = memoryview(a)
3046 v.release()
3047 self.assertEqual(v, v)
3048 self.assertNotEqual(v, a)
3049 self.assertNotEqual(a, v)
3050
3051 v = memoryview(a)
3052 w = memoryview(a)
3053 w.release()
3054 self.assertNotEqual(v, w)
3055 self.assertNotEqual(w, v)
3056
3057 # Operand does not implement the buffer protocol:
3058 v = memoryview(a)
3059 self.assertNotEqual(v, [1, 2, 3])
3060
3061 # Different formats:
3062 c = array.array('l', [1, 2, 3])
3063 v = memoryview(a)
3064 self.assertNotEqual(v, c)
3065 self.assertNotEqual(c, v)
3066
3067 # Not implemented formats. Ugly, but inevitable. This is the same as
3068 # issue #2531: equality is also used for membership testing and must
3069 # return a result.
3070 a = ndarray([(1, 1.5), (2, 2.7)], shape=[2], format='ld')
3071 v = memoryview(a)
3072 self.assertNotEqual(v, a)
3073 self.assertNotEqual(a, v)
3074
3075 a = ndarray([b'12345'], shape=[1], format="s")
3076 v = memoryview(a)
3077 self.assertNotEqual(v, a)
3078 self.assertNotEqual(a, v)
3079
3080 nd = ndarray([(1,1,1), (2,2,2), (3,3,3)], shape=[3], format='iii')
3081 v = memoryview(nd)
3082 self.assertNotEqual(v, nd)
3083 self.assertNotEqual(nd, v)
3084
3085 # '@' prefix can be dropped:
3086 nd1 = ndarray([1,2,3], shape=[3], format='@i')
3087 nd2 = ndarray([1,2,3], shape=[3], format='i')
3088 v = memoryview(nd1)
3089 w = memoryview(nd2)
3090 self.assertEqual(v, w)
3091 self.assertEqual(w, v)
3092 self.assertEqual(v, nd2)
3093 self.assertEqual(nd2, v)
3094 self.assertEqual(w, nd1)
3095 self.assertEqual(nd1, w)
3096
3097 # ndim = 0
3098 nd1 = ndarray(1729, shape=[], format='@L')
3099 nd2 = ndarray(1729, shape=[], format='L', flags=ND_WRITABLE)
3100 v = memoryview(nd1)
3101 w = memoryview(nd2)
3102 self.assertEqual(v, w)
3103 self.assertEqual(w, v)
3104 self.assertEqual(v, nd2)
3105 self.assertEqual(nd2, v)
3106 self.assertEqual(w, nd1)
3107 self.assertEqual(nd1, w)
3108
3109 self.assertFalse(v.__ne__(w))
3110 self.assertFalse(w.__ne__(v))
3111
3112 w[()] = 1728
3113 self.assertNotEqual(v, w)
3114 self.assertNotEqual(w, v)
3115 self.assertNotEqual(v, nd2)
3116 self.assertNotEqual(nd2, v)
3117 self.assertNotEqual(w, nd1)
3118 self.assertNotEqual(nd1, w)
3119
3120 self.assertFalse(v.__eq__(w))
3121 self.assertFalse(w.__eq__(v))
3122
3123 nd = ndarray(list(range(12)), shape=[12], flags=ND_WRITABLE|ND_PIL)
3124 ex = ndarray(list(range(12)), shape=[12], flags=ND_WRITABLE|ND_PIL)
3125 m = memoryview(ex)
3126
3127 self.assertEqual(m, nd)
3128 m[9] = 100
3129 self.assertNotEqual(m, nd)
3130
3131 # ndim = 1: contiguous
3132 nd1 = ndarray([-529, 576, -625, 676, -729], shape=[5], format='@h')
3133 nd2 = ndarray([-529, 576, -625, 676, 729], shape=[5], format='@h')
3134 v = memoryview(nd1)
3135 w = memoryview(nd2)
3136
3137 self.assertEqual(v, nd1)
3138 self.assertEqual(w, nd2)
3139 self.assertNotEqual(v, nd2)
3140 self.assertNotEqual(w, nd1)
3141 self.assertNotEqual(v, w)
3142
3143 # ndim = 1: non-contiguous
3144 nd1 = ndarray([-529, -625, -729], shape=[3], format='@h')
3145 nd2 = ndarray([-529, 576, -625, 676, -729], shape=[5], format='@h')
3146 v = memoryview(nd1)
3147 w = memoryview(nd2)
3148
3149 self.assertEqual(v, nd2[::2])
3150 self.assertEqual(w[::2], nd1)
3151 self.assertEqual(v, w[::2])
3152 self.assertEqual(v[::-1], w[::-2])
3153
3154 # ndim = 1: non-contiguous, suboffsets
3155 nd1 = ndarray([-529, -625, -729], shape=[3], format='@h')
3156 nd2 = ndarray([-529, 576, -625, 676, -729], shape=[5], format='@h',
3157 flags=ND_PIL)
3158 v = memoryview(nd1)
3159 w = memoryview(nd2)
3160
3161 self.assertEqual(v, nd2[::2])
3162 self.assertEqual(w[::2], nd1)
3163 self.assertEqual(v, w[::2])
3164 self.assertEqual(v[::-1], w[::-2])
3165
3166 # ndim = 1: zeros in shape
3167 nd1 = ndarray([900, 961], shape=[0], format='@h')
3168 nd2 = ndarray([-900, -961], shape=[0], format='@h')
3169 v = memoryview(nd1)
3170 w = memoryview(nd2)
3171
3172 self.assertEqual(v, nd1)
3173 self.assertEqual(w, nd2)
3174 self.assertEqual(v, nd2)
3175 self.assertEqual(w, nd1)
3176 self.assertEqual(v, w)
3177
3178 # ndim = 1: zero strides
3179 nd1 = ndarray([900, 900, 900, 900], shape=[4], format='@L')
3180 nd2 = ndarray([900], shape=[4], strides=[0], format='L')
3181 v = memoryview(nd1)
3182 w = memoryview(nd2)
3183
3184 self.assertEqual(v, nd1)
3185 self.assertEqual(w, nd2)
3186 self.assertEqual(v, nd2)
3187 self.assertEqual(w, nd1)
3188 self.assertEqual(v, w)
3189
3190 n = 10
3191 for char in fmtdict['@m']:
3192 fmt, items, singleitem = randitems(n, 'memoryview', '@', char)
3193 for flags in (0, ND_PIL):
3194 nd = ndarray(items, shape=[n], format=fmt, flags=flags)
3195 m = memoryview(nd)
3196 self.assertEqual(m, nd)
3197
3198 nd = nd[::-3]
3199 m = memoryview(nd)
3200 self.assertEqual(m, nd)
3201
3202 ##### ndim > 1: C-contiguous
3203 # different values
3204 nd1 = ndarray(list(range(-15, 15)), shape=[3, 2, 5], format='@h')
3205 nd2 = ndarray(list(range(0, 30)), shape=[3, 2, 5], format='@h')
3206 v = memoryview(nd1)
3207 w = memoryview(nd2)
3208
3209 self.assertEqual(v, nd1)
3210 self.assertEqual(w, nd2)
3211 self.assertNotEqual(v, nd2)
3212 self.assertNotEqual(w, nd1)
3213 self.assertNotEqual(v, w)
3214
3215 # different shape
3216 nd1 = ndarray(list(range(30)), shape=[2, 3, 5], format='L')
3217 nd2 = ndarray(list(range(30)), shape=[3, 2, 5], format='L')
3218 v = memoryview(nd1)
3219 w = memoryview(nd2)
3220
3221 self.assertEqual(v, nd1)
3222 self.assertEqual(w, nd2)
3223 self.assertNotEqual(v, nd2)
3224 self.assertNotEqual(w, nd1)
3225 self.assertNotEqual(v, w)
3226
3227 # different format
3228 nd1 = ndarray(list(range(30)), shape=[2, 3, 5], format='L')
3229 nd2 = ndarray(list(range(30)), shape=[2, 3, 5], format='l')
3230 v = memoryview(nd1)
3231 w = memoryview(nd2)
3232
3233 self.assertEqual(v, nd1)
3234 self.assertEqual(w, nd2)
3235 self.assertNotEqual(v, nd2)
3236 self.assertNotEqual(w, nd1)
3237 self.assertNotEqual(v, w)
3238
3239 ##### ndim > 1: Fortran contiguous
3240 # different values
3241 nd1 = ndarray(list(range(-15, 15)), shape=[5, 2, 3], format='@h',
3242 flags=ND_FORTRAN)
3243 nd2 = ndarray(list(range(0, 30)), shape=[5, 2, 3], format='@h',
3244 flags=ND_FORTRAN)
3245 v = memoryview(nd1)
3246 w = memoryview(nd2)
3247
3248 self.assertEqual(v, nd1)
3249 self.assertEqual(w, nd2)
3250 self.assertNotEqual(v, nd2)
3251 self.assertNotEqual(w, nd1)
3252 self.assertNotEqual(v, w)
3253
3254 # different shape
3255 nd1 = ndarray(list(range(-15, 15)), shape=[2, 3, 5], format='l',
3256 flags=ND_FORTRAN)
3257 nd2 = ndarray(list(range(-15, 15)), shape=[3, 2, 5], format='l',
3258 flags=ND_FORTRAN)
3259 v = memoryview(nd1)
3260 w = memoryview(nd2)
3261
3262 self.assertEqual(v, nd1)
3263 self.assertEqual(w, nd2)
3264 self.assertNotEqual(v, nd2)
3265 self.assertNotEqual(w, nd1)
3266 self.assertNotEqual(v, w)
3267
3268 # different format
3269 nd1 = ndarray(list(range(30)), shape=[5, 2, 3], format='@h',
3270 flags=ND_FORTRAN)
3271 nd2 = ndarray(list(range(30)), shape=[5, 2, 3], format='@b',
3272 flags=ND_FORTRAN)
3273 v = memoryview(nd1)
3274 w = memoryview(nd2)
3275
3276 self.assertEqual(v, nd1)
3277 self.assertEqual(w, nd2)
3278 self.assertNotEqual(v, nd2)
3279 self.assertNotEqual(w, nd1)
3280 self.assertNotEqual(v, w)
3281
3282 ##### ndim > 1: mixed C/Fortran contiguous
3283 lst1 = list(range(-15, 15))
3284 lst2 = transpose(lst1, [3, 2, 5])
3285 nd1 = ndarray(lst1, shape=[3, 2, 5], format='@l')
3286 nd2 = ndarray(lst2, shape=[3, 2, 5], format='l', flags=ND_FORTRAN)
3287 v = memoryview(nd1)
3288 w = memoryview(nd2)
3289
3290 self.assertEqual(v, nd1)
3291 self.assertEqual(w, nd2)
3292 self.assertEqual(v, w)
3293
3294 ##### ndim > 1: non-contiguous
3295 # different values
3296 ex1 = ndarray(list(range(40)), shape=[5, 8], format='@I')
3297 nd1 = ex1[3:1:-1, ::-2]
3298 ex2 = ndarray(list(range(40)), shape=[5, 8], format='I')
3299 nd2 = ex2[1:3:1, ::-2]
3300 v = memoryview(nd1)
3301 w = memoryview(nd2)
3302
3303 self.assertEqual(v, nd1)
3304 self.assertEqual(w, nd2)
3305 self.assertNotEqual(v, nd2)
3306 self.assertNotEqual(w, nd1)
3307 self.assertNotEqual(v, w)
3308
3309 # different shape
3310 ex1 = ndarray(list(range(30)), shape=[2, 3, 5], format='b')
3311 nd1 = ex1[1:3:, ::-2]
3312 nd2 = ndarray(list(range(30)), shape=[3, 2, 5], format='b')
3313 nd2 = ex2[1:3:, ::-2]
3314 v = memoryview(nd1)
3315 w = memoryview(nd2)
3316
3317 self.assertEqual(v, nd1)
3318 self.assertEqual(w, nd2)
3319 self.assertNotEqual(v, nd2)
3320 self.assertNotEqual(w, nd1)
3321 self.assertNotEqual(v, w)
3322
3323 # different format
3324 ex1 = ndarray(list(range(30)), shape=[5, 3, 2], format='i')
3325 nd1 = ex1[1:3:, ::-2]
3326 nd2 = ndarray(list(range(30)), shape=[5, 3, 2], format='@I')
3327 nd2 = ex2[1:3:, ::-2]
3328 v = memoryview(nd1)
3329 w = memoryview(nd2)
3330
3331 self.assertEqual(v, nd1)
3332 self.assertEqual(w, nd2)
3333 self.assertNotEqual(v, nd2)
3334 self.assertNotEqual(w, nd1)
3335 self.assertNotEqual(v, w)
3336
3337 ##### ndim > 1: zeros in shape
3338 nd1 = ndarray(list(range(30)), shape=[0, 3, 2], format='i')
3339 nd2 = ndarray(list(range(30)), shape=[5, 0, 2], format='@i')
3340 v = memoryview(nd1)
3341 w = memoryview(nd2)
3342
3343 self.assertEqual(v, nd1)
3344 self.assertEqual(w, nd2)
3345 self.assertNotEqual(v, nd2)
3346 self.assertNotEqual(w, nd1)
3347 self.assertNotEqual(v, w)
3348
3349 # ndim > 1: zero strides
3350 nd1 = ndarray([900]*80, shape=[4, 5, 4], format='@L')
3351 nd2 = ndarray([900], shape=[4, 5, 4], strides=[0, 0, 0], format='L')
3352 v = memoryview(nd1)
3353 w = memoryview(nd2)
3354
3355 self.assertEqual(v, nd1)
3356 self.assertEqual(w, nd2)
3357 self.assertEqual(v, nd2)
3358 self.assertEqual(w, nd1)
3359 self.assertEqual(v, w)
3360 self.assertEqual(v.tolist(), w.tolist())
3361
3362 ##### ndim > 1: suboffsets
3363 ex1 = ndarray(list(range(40)), shape=[5, 8], format='@I')
3364 nd1 = ex1[3:1:-1, ::-2]
3365 ex2 = ndarray(list(range(40)), shape=[5, 8], format='I', flags=ND_PIL)
3366 nd2 = ex2[1:3:1, ::-2]
3367 v = memoryview(nd1)
3368 w = memoryview(nd2)
3369
3370 self.assertEqual(v, nd1)
3371 self.assertEqual(w, nd2)
3372 self.assertNotEqual(v, nd2)
3373 self.assertNotEqual(w, nd1)
3374 self.assertNotEqual(v, w)
3375
3376 # different shape
3377 ex1 = ndarray(list(range(30)), shape=[2, 3, 5], format='b', flags=ND_PIL)
3378 nd1 = ex1[1:3:, ::-2]
3379 nd2 = ndarray(list(range(30)), shape=[3, 2, 5], format='b')
3380 nd2 = ex2[1:3:, ::-2]
3381 v = memoryview(nd1)
3382 w = memoryview(nd2)
3383
3384 self.assertEqual(v, nd1)
3385 self.assertEqual(w, nd2)
3386 self.assertNotEqual(v, nd2)
3387 self.assertNotEqual(w, nd1)
3388 self.assertNotEqual(v, w)
3389
3390 # different format
3391 ex1 = ndarray(list(range(30)), shape=[5, 3, 2], format='i', flags=ND_PIL)
3392 nd1 = ex1[1:3:, ::-2]
3393 nd2 = ndarray(list(range(30)), shape=[5, 3, 2], format='@I', flags=ND_PIL)
3394 nd2 = ex2[1:3:, ::-2]
3395 v = memoryview(nd1)
3396 w = memoryview(nd2)
3397
3398 self.assertEqual(v, nd1)
3399 self.assertEqual(w, nd2)
3400 self.assertNotEqual(v, nd2)
3401 self.assertNotEqual(w, nd1)
3402 self.assertNotEqual(v, w)
3403
3404 # initialize mixed C/Fortran + suboffsets
3405 lst1 = list(range(-15, 15))
3406 lst2 = transpose(lst1, [3, 2, 5])
3407 nd1 = ndarray(lst1, shape=[3, 2, 5], format='@l', flags=ND_PIL)
3408 nd2 = ndarray(lst2, shape=[3, 2, 5], format='l', flags=ND_FORTRAN|ND_PIL)
3409 v = memoryview(nd1)
3410 w = memoryview(nd2)
3411
3412 self.assertEqual(v, nd1)
3413 self.assertEqual(w, nd2)
3414 self.assertEqual(v, w)
3415
3416 def test_memoryview_check_released(self):
3417
3418 a = array.array('d', [1.1, 2.2, 3.3])
3419
3420 m = memoryview(a)
3421 m.release()
3422
3423 # PyMemoryView_FromObject()
3424 self.assertRaises(ValueError, memoryview, m)
3425 # memoryview.cast()
3426 self.assertRaises(ValueError, m.cast, 'c')
3427 # getbuffer()
3428 self.assertRaises(ValueError, ndarray, m)
3429 # memoryview.tolist()
3430 self.assertRaises(ValueError, m.tolist)
3431 # memoryview.tobytes()
3432 self.assertRaises(ValueError, m.tobytes)
3433 # sequence
3434 self.assertRaises(ValueError, eval, "1.0 in m", locals())
3435 # subscript
3436 self.assertRaises(ValueError, m.__getitem__, 0)
3437 # assignment
3438 self.assertRaises(ValueError, m.__setitem__, 0, 1)
3439
3440 for attr in ('obj', 'nbytes', 'readonly', 'itemsize', 'format', 'ndim',
3441 'shape', 'strides', 'suboffsets', 'c_contiguous',
3442 'f_contiguous', 'contiguous'):
3443 self.assertRaises(ValueError, m.__getattribute__, attr)
3444
3445 # richcompare
3446 b = array.array('d', [1.1, 2.2, 3.3])
3447 m1 = memoryview(a)
3448 m2 = memoryview(b)
3449
3450 self.assertEqual(m1, m2)
3451 m1.release()
3452 self.assertNotEqual(m1, m2)
3453 self.assertNotEqual(m1, a)
3454 self.assertEqual(m1, m1)
3455
3456 def test_memoryview_tobytes(self):
3457 # Many implicit tests are already in self.verify().
3458
3459 nd = ndarray([-529, 576, -625, 676, -729], shape=[5], format='@h')
3460
3461 m = memoryview(nd)
3462 self.assertEqual(m.tobytes(), nd.tobytes())
3463
3464 def test_memoryview_get_contiguous(self):
3465 # Many implicit tests are already in self.verify().
3466
3467 # no buffer interface
3468 self.assertRaises(TypeError, get_contiguous, {}, PyBUF_READ, 'F')
3469
3470 # writable request to read-only object
3471 self.assertRaises(BufferError, get_contiguous, b'x', PyBUF_WRITE, 'C')
3472
3473 # writable request to non-contiguous object
3474 nd = ndarray([1, 2, 3], shape=[2], strides=[2])
3475 self.assertRaises(BufferError, get_contiguous, nd, PyBUF_WRITE, 'A')
3476
3477 # scalar, read-only request from read-only exporter
3478 nd = ndarray(9, shape=(), format="L")
3479 for order in ['C', 'F', 'A']:
3480 m = get_contiguous(nd, PyBUF_READ, order)
3481 self.assertEqual(m, nd)
3482 self.assertEqual(m[()], 9)
3483
3484 # scalar, read-only request from writable exporter
3485 nd = ndarray(9, shape=(), format="L", flags=ND_WRITABLE)
3486 for order in ['C', 'F', 'A']:
3487 m = get_contiguous(nd, PyBUF_READ, order)
3488 self.assertEqual(m, nd)
3489 self.assertEqual(m[()], 9)
3490
3491 # scalar, writable request
3492 for order in ['C', 'F', 'A']:
3493 nd[()] = 9
3494 m = get_contiguous(nd, PyBUF_WRITE, order)
3495 self.assertEqual(m, nd)
3496 self.assertEqual(m[()], 9)
3497
3498 m[()] = 10
3499 self.assertEqual(m[()], 10)
3500 self.assertEqual(nd[()], 10)
3501
3502 # zeros in shape
3503 nd = ndarray([1], shape=[0], format="L", flags=ND_WRITABLE)
3504 for order in ['C', 'F', 'A']:
3505 m = get_contiguous(nd, PyBUF_READ, order)
3506 self.assertRaises(IndexError, m.__getitem__, 0)
3507 self.assertEqual(m, nd)
3508 self.assertEqual(m.tolist(), [])
3509
3510 nd = ndarray(list(range(8)), shape=[2, 0, 7], format="L",
3511 flags=ND_WRITABLE)
3512 for order in ['C', 'F', 'A']:
3513 m = get_contiguous(nd, PyBUF_READ, order)
3514 self.assertEqual(ndarray(m).tolist(), [[], []])
3515
3516 # one-dimensional
3517 nd = ndarray([1], shape=[1], format="h", 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 nd = ndarray([1, 2, 3], shape=[3], format="b", flags=ND_WRITABLE)
3524 for order in ['C', 'F', 'A']:
3525 m = get_contiguous(nd, PyBUF_WRITE, order)
3526 self.assertEqual(m, nd)
3527 self.assertEqual(m.tolist(), nd.tolist())
3528
3529 # one-dimensional, non-contiguous
3530 nd = ndarray([1, 2, 3], shape=[2], strides=[2], flags=ND_WRITABLE)
3531 for order in ['C', 'F', 'A']:
3532 m = get_contiguous(nd, PyBUF_READ, order)
3533 self.assertEqual(m, nd)
3534 self.assertEqual(m.tolist(), nd.tolist())
3535 self.assertRaises(TypeError, m.__setitem__, 1, 20)
3536 self.assertEqual(m[1], 3)
3537 self.assertEqual(nd[1], 3)
3538
3539 nd = nd[::-1]
3540 for order in ['C', 'F', 'A']:
3541 m = get_contiguous(nd, PyBUF_READ, order)
3542 self.assertEqual(m, nd)
3543 self.assertEqual(m.tolist(), nd.tolist())
3544 self.assertRaises(TypeError, m.__setitem__, 1, 20)
3545 self.assertEqual(m[1], 1)
3546 self.assertEqual(nd[1], 1)
3547
3548 # multi-dimensional, contiguous input
3549 nd = ndarray(list(range(12)), shape=[3, 4], flags=ND_WRITABLE)
3550 for order in ['C', 'A']:
3551 m = get_contiguous(nd, PyBUF_WRITE, order)
3552 self.assertEqual(ndarray(m).tolist(), nd.tolist())
3553
3554 self.assertRaises(BufferError, get_contiguous, nd, PyBUF_WRITE, 'F')
3555 m = get_contiguous(nd, PyBUF_READ, order)
3556 self.assertEqual(ndarray(m).tolist(), nd.tolist())
3557
3558 nd = ndarray(list(range(12)), shape=[3, 4],
3559 flags=ND_WRITABLE|ND_FORTRAN)
3560 for order in ['F', 'A']:
3561 m = get_contiguous(nd, PyBUF_WRITE, order)
3562 self.assertEqual(ndarray(m).tolist(), nd.tolist())
3563
3564 self.assertRaises(BufferError, get_contiguous, nd, PyBUF_WRITE, 'C')
3565 m = get_contiguous(nd, PyBUF_READ, order)
3566 self.assertEqual(ndarray(m).tolist(), nd.tolist())
3567
3568 # multi-dimensional, non-contiguous input
3569 nd = ndarray(list(range(12)), shape=[3, 4], flags=ND_WRITABLE|ND_PIL)
3570 for order in ['C', 'F', 'A']:
3571 self.assertRaises(BufferError, get_contiguous, nd, PyBUF_WRITE,
3572 order)
3573 m = get_contiguous(nd, PyBUF_READ, order)
3574 self.assertEqual(ndarray(m).tolist(), nd.tolist())
3575
3576 # flags
3577 nd = ndarray([1,2,3,4,5], shape=[3], strides=[2])
3578 m = get_contiguous(nd, PyBUF_READ, 'C')
3579 self.assertTrue(m.c_contiguous)
3580
3581 def test_memoryview_serializing(self):
3582
3583 # C-contiguous
3584 size = struct.calcsize('i')
3585 a = array.array('i', [1,2,3,4,5])
3586 m = memoryview(a)
3587 buf = io.BytesIO(m)
3588 b = bytearray(5*size)
3589 buf.readinto(b)
3590 self.assertEqual(m.tobytes(), b)
3591
3592 # C-contiguous, multi-dimensional
3593 size = struct.calcsize('L')
3594 nd = ndarray(list(range(12)), shape=[2,3,2], format="L")
3595 m = memoryview(nd)
3596 buf = io.BytesIO(m)
3597 b = bytearray(2*3*2*size)
3598 buf.readinto(b)
3599 self.assertEqual(m.tobytes(), b)
3600
3601 # Fortran contiguous, multi-dimensional
3602 #size = struct.calcsize('L')
3603 #nd = ndarray(list(range(12)), shape=[2,3,2], format="L",
3604 # flags=ND_FORTRAN)
3605 #m = memoryview(nd)
3606 #buf = io.BytesIO(m)
3607 #b = bytearray(2*3*2*size)
3608 #buf.readinto(b)
3609 #self.assertEqual(m.tobytes(), b)
3610
3611 def test_memoryview_hash(self):
3612
3613 # bytes exporter
3614 b = bytes(list(range(12)))
3615 m = memoryview(b)
3616 self.assertEqual(hash(b), hash(m))
3617
3618 # C-contiguous
3619 mc = m.cast('c', shape=[3,4])
3620 self.assertEqual(hash(mc), hash(b))
3621
3622 # non-contiguous
3623 mx = m[::-2]
3624 b = bytes(list(range(12))[::-2])
3625 self.assertEqual(hash(mx), hash(b))
3626
3627 # Fortran contiguous
3628 nd = ndarray(list(range(30)), shape=[3,2,5], flags=ND_FORTRAN)
3629 m = memoryview(nd)
3630 self.assertEqual(hash(m), hash(nd))
3631
3632 # multi-dimensional slice
3633 nd = ndarray(list(range(30)), shape=[3,2,5])
3634 x = nd[::2, ::, ::-1]
3635 m = memoryview(x)
3636 self.assertEqual(hash(m), hash(x))
3637
3638 # multi-dimensional slice with suboffsets
3639 nd = ndarray(list(range(30)), shape=[2,5,3], flags=ND_PIL)
3640 x = nd[::2, ::, ::-1]
3641 m = memoryview(x)
3642 self.assertEqual(hash(m), hash(x))
3643
3644 # non-byte formats
3645 nd = ndarray(list(range(12)), shape=[2,2,3], format='L')
3646 m = memoryview(nd)
3647 self.assertEqual(hash(m), hash(nd.tobytes()))
3648
3649 nd = ndarray(list(range(-6, 6)), shape=[2,2,3], format='h')
3650 m = memoryview(nd)
3651 self.assertEqual(hash(m), hash(nd.tobytes()))
3652
3653 def test_memoryview_release(self):
3654
3655 # Create re-exporter from getbuffer(memoryview), then release the view.
3656 a = bytearray([1,2,3])
3657 m = memoryview(a)
3658 nd = ndarray(m) # re-exporter
3659 self.assertRaises(BufferError, m.release)
3660 del nd
3661 m.release()
3662
Stefan Krah4e99a312012-03-05 09:30:47 +01003663 a = bytearray([1,2,3])
3664 m = memoryview(a)
3665 nd1 = ndarray(m, getbuf=PyBUF_FULL_RO, flags=ND_REDIRECT)
3666 nd2 = ndarray(nd1, getbuf=PyBUF_FULL_RO, flags=ND_REDIRECT)
3667 self.assertIs(nd2.obj, m)
3668 self.assertRaises(BufferError, m.release)
3669 del nd1, nd2
3670 m.release()
3671
Stefan Krah9a2d99e2012-02-25 12:24:21 +01003672 # chained views
3673 a = bytearray([1,2,3])
3674 m1 = memoryview(a)
3675 m2 = memoryview(m1)
3676 nd = ndarray(m2) # re-exporter
3677 m1.release()
3678 self.assertRaises(BufferError, m2.release)
3679 del nd
3680 m2.release()
3681
Stefan Krah4e99a312012-03-05 09:30:47 +01003682 a = bytearray([1,2,3])
3683 m1 = memoryview(a)
3684 m2 = memoryview(m1)
3685 nd1 = ndarray(m2, getbuf=PyBUF_FULL_RO, flags=ND_REDIRECT)
3686 nd2 = ndarray(nd1, getbuf=PyBUF_FULL_RO, flags=ND_REDIRECT)
3687 self.assertIs(nd2.obj, m2)
3688 m1.release()
3689 self.assertRaises(BufferError, m2.release)
3690 del nd1, nd2
3691 m2.release()
3692
Stefan Krah9a2d99e2012-02-25 12:24:21 +01003693 # Allow changing layout while buffers are exported.
3694 nd = ndarray([1,2,3], shape=[3], flags=ND_VAREXPORT)
3695 m1 = memoryview(nd)
3696
3697 nd.push([4,5,6,7,8], shape=[5]) # mutate nd
3698 m2 = memoryview(nd)
3699
3700 x = memoryview(m1)
3701 self.assertEqual(x.tolist(), m1.tolist())
3702
3703 y = memoryview(m2)
3704 self.assertEqual(y.tolist(), m2.tolist())
3705 self.assertEqual(y.tolist(), nd.tolist())
3706 m2.release()
3707 y.release()
3708
3709 nd.pop() # pop the current view
3710 self.assertEqual(x.tolist(), nd.tolist())
3711
3712 del nd
3713 m1.release()
3714 x.release()
3715
3716 # If multiple memoryviews share the same managed buffer, implicit
3717 # release() in the context manager's __exit__() method should still
3718 # work.
3719 def catch22(b):
3720 with memoryview(b) as m2:
3721 pass
3722
3723 x = bytearray(b'123')
3724 with memoryview(x) as m1:
3725 catch22(m1)
3726 self.assertEqual(m1[0], ord(b'1'))
3727
Stefan Krah4e99a312012-03-05 09:30:47 +01003728 x = ndarray(list(range(12)), shape=[2,2,3], format='l')
3729 y = ndarray(x, getbuf=PyBUF_FULL_RO, flags=ND_REDIRECT)
3730 z = ndarray(y, getbuf=PyBUF_FULL_RO, flags=ND_REDIRECT)
3731 self.assertIs(z.obj, x)
3732 with memoryview(z) as m:
3733 catch22(m)
3734 self.assertEqual(m[0:1].tolist(), [[[0, 1, 2], [3, 4, 5]]])
3735
3736 # Test garbage collection.
3737 for flags in (0, ND_REDIRECT):
3738 x = bytearray(b'123')
3739 with memoryview(x) as m1:
3740 del x
3741 y = ndarray(m1, getbuf=PyBUF_FULL_RO, flags=flags)
3742 with memoryview(y) as m2:
3743 del y
3744 z = ndarray(m2, getbuf=PyBUF_FULL_RO, flags=flags)
3745 with memoryview(z) as m3:
3746 del z
3747 catch22(m3)
3748 catch22(m2)
3749 catch22(m1)
3750 self.assertEqual(m1[0], ord(b'1'))
3751 self.assertEqual(m2[1], ord(b'2'))
3752 self.assertEqual(m3[2], ord(b'3'))
3753 del m3
3754 del m2
3755 del m1
3756
3757 x = bytearray(b'123')
3758 with memoryview(x) as m1:
3759 del x
3760 y = ndarray(m1, getbuf=PyBUF_FULL_RO, flags=flags)
3761 with memoryview(y) as m2:
3762 del y
3763 z = ndarray(m2, getbuf=PyBUF_FULL_RO, flags=flags)
3764 with memoryview(z) as m3:
3765 del z
3766 catch22(m1)
3767 catch22(m2)
3768 catch22(m3)
3769 self.assertEqual(m1[0], ord(b'1'))
3770 self.assertEqual(m2[1], ord(b'2'))
3771 self.assertEqual(m3[2], ord(b'3'))
3772 del m1, m2, m3
3773
Stefan Krahfcbb4162012-03-05 10:45:31 +01003774 # memoryview.release() fails if the view has exported buffers.
3775 x = bytearray(b'123')
3776 with self.assertRaises(BufferError):
3777 with memoryview(x) as m:
3778 ex = ndarray(m)
3779 m[0] == ord(b'1')
Stefan Krah9a2d99e2012-02-25 12:24:21 +01003780
Stefan Krah4e99a312012-03-05 09:30:47 +01003781 def test_memoryview_redirect(self):
3782
3783 nd = ndarray([1.0 * x for x in range(12)], shape=[12], format='d')
3784 a = array.array('d', [1.0 * x for x in range(12)])
3785
3786 for x in (nd, a):
3787 y = ndarray(x, getbuf=PyBUF_FULL_RO, flags=ND_REDIRECT)
3788 z = ndarray(y, getbuf=PyBUF_FULL_RO, flags=ND_REDIRECT)
3789 m = memoryview(z)
3790
3791 self.assertIs(y.obj, x)
3792 self.assertIs(z.obj, x)
3793 self.assertIs(m.obj, x)
3794
3795 self.assertEqual(m, x)
3796 self.assertEqual(m, y)
3797 self.assertEqual(m, z)
3798
3799 self.assertEqual(m[1:3], x[1:3])
3800 self.assertEqual(m[1:3], y[1:3])
3801 self.assertEqual(m[1:3], z[1:3])
3802 del y, z
3803 self.assertEqual(m[1:3], x[1:3])
3804
Stefan Krahbf6c7ec2012-03-05 14:37:34 +01003805 def test_memoryview_from_static_exporter(self):
3806
3807 fmt = 'B'
3808 lst = [0,1,2,3,4,5,6,7,8,9,10,11]
3809
3810 # exceptions
3811 self.assertRaises(TypeError, staticarray, 1, 2, 3)
3812
3813 # view.obj==x
3814 x = staticarray()
3815 y = memoryview(x)
3816 self.verify(y, obj=x,
3817 itemsize=1, fmt=fmt, readonly=1,
3818 ndim=1, shape=[12], strides=[1],
3819 lst=lst)
3820 for i in range(12):
3821 self.assertEqual(y[i], i)
3822 del x
3823 del y
3824
3825 x = staticarray()
3826 y = memoryview(x)
3827 del y
3828 del x
3829
3830 x = staticarray()
3831 y = ndarray(x, getbuf=PyBUF_FULL_RO)
3832 z = ndarray(y, getbuf=PyBUF_FULL_RO)
3833 m = memoryview(z)
3834 self.assertIs(y.obj, x)
3835 self.assertIs(m.obj, z)
3836 self.verify(m, obj=z,
3837 itemsize=1, fmt=fmt, readonly=1,
3838 ndim=1, shape=[12], strides=[1],
3839 lst=lst)
3840 del x, y, z, m
3841
3842 x = staticarray()
3843 y = ndarray(x, getbuf=PyBUF_FULL_RO, flags=ND_REDIRECT)
3844 z = ndarray(y, getbuf=PyBUF_FULL_RO, flags=ND_REDIRECT)
3845 m = memoryview(z)
3846 self.assertIs(y.obj, x)
3847 self.assertIs(z.obj, x)
3848 self.assertIs(m.obj, x)
3849 self.verify(m, obj=x,
3850 itemsize=1, fmt=fmt, readonly=1,
3851 ndim=1, shape=[12], strides=[1],
3852 lst=lst)
3853 del x, y, z, m
3854
3855 # view.obj==NULL
3856 x = staticarray(legacy_mode=True)
3857 y = memoryview(x)
3858 self.verify(y, obj=None,
3859 itemsize=1, fmt=fmt, readonly=1,
3860 ndim=1, shape=[12], strides=[1],
3861 lst=lst)
3862 for i in range(12):
3863 self.assertEqual(y[i], i)
3864 del x
3865 del y
3866
3867 x = staticarray(legacy_mode=True)
3868 y = memoryview(x)
3869 del y
3870 del x
3871
3872 x = staticarray(legacy_mode=True)
3873 y = ndarray(x, getbuf=PyBUF_FULL_RO)
3874 z = ndarray(y, getbuf=PyBUF_FULL_RO)
3875 m = memoryview(z)
3876 self.assertIs(y.obj, None)
3877 self.assertIs(m.obj, z)
3878 self.verify(m, obj=z,
3879 itemsize=1, fmt=fmt, readonly=1,
3880 ndim=1, shape=[12], strides=[1],
3881 lst=lst)
3882 del x, y, z, m
3883
3884 x = staticarray(legacy_mode=True)
3885 y = ndarray(x, getbuf=PyBUF_FULL_RO, flags=ND_REDIRECT)
3886 z = ndarray(y, getbuf=PyBUF_FULL_RO, flags=ND_REDIRECT)
3887 m = memoryview(z)
3888 # Clearly setting view.obj==NULL is inferior, since it
3889 # messes up the redirection chain:
3890 self.assertIs(y.obj, None)
3891 self.assertIs(z.obj, y)
3892 self.assertIs(m.obj, y)
3893 self.verify(m, obj=y,
3894 itemsize=1, fmt=fmt, readonly=1,
3895 ndim=1, shape=[12], strides=[1],
3896 lst=lst)
3897 del x, y, z, m
3898
Stefan Krah1649c1b2012-03-05 17:45:17 +01003899 def test_memoryview_getbuffer_undefined(self):
3900
3901 # getbufferproc does not adhere to the new documentation
3902 nd = ndarray([1,2,3], [3], flags=ND_GETBUF_FAIL|ND_GETBUF_UNDEFINED)
3903 self.assertRaises(BufferError, memoryview, nd)
3904
Stefan Krah9a2d99e2012-02-25 12:24:21 +01003905 def test_issue_7385(self):
3906 x = ndarray([1,2,3], shape=[3], flags=ND_GETBUF_FAIL)
3907 self.assertRaises(BufferError, memoryview, x)
3908
3909
3910def test_main():
3911 support.run_unittest(TestBufferProtocol)
3912
3913
3914if __name__ == "__main__":
3915 test_main()