|
53 | 53 | 'f':0, 'd':0, 'P':0 |
54 | 54 | } |
55 | 55 |
|
| 56 | +# NumPy does not have 'n' or 'N': |
| 57 | +if numpy_array: |
| 58 | + del NATIVE['n'] |
| 59 | + del NATIVE['N'] |
| 60 | + |
56 | 61 | if struct: |
57 | 62 | try: |
58 | 63 | # Add "qQ" if present in native mode. |
@@ -855,11 +860,49 @@ def verify(self, result, obj=-1, |
855 | 860 | is_contiguous(result, 'F') and order == 'C': |
856 | 861 | # The flattened list is already in C-order. |
857 | 862 | expected = ndarray(flattened, shape=shape, format=ff) |
858 | | - contig = get_contiguous(result, PyBUF_READ, order) |
| 863 | + |
859 | 864 | contig = get_contiguous(result, PyBUF_READ, order) |
860 | 865 | self.assertEqual(contig.tobytes(), b) |
861 | 866 | self.assertTrue(cmp_contig(contig, expected)) |
862 | 867 |
|
| 868 | + 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 | + |
863 | 906 | if is_memoryview_format(fmt): |
864 | 907 | try: |
865 | 908 | m = memoryview(result) |
@@ -1805,6 +1848,9 @@ def test_ndarray_random(self): |
1805 | 1848 | self.assertEqual(mvlist, ylist) |
1806 | 1849 |
|
1807 | 1850 | if numpy_array: |
| 1851 | + # XXX NumPy (as far as it compiles with 3.3) currently |
| 1852 | + # segfaults here. Wait for a stable 3.3 compatible version. |
| 1853 | + continue |
1808 | 1854 | shape = t[3] |
1809 | 1855 | if 0 in shape: |
1810 | 1856 | continue # http://projects.scipy.org/numpy/ticket/1910 |
@@ -1884,6 +1930,9 @@ def test_ndarray_random_slice_assign(self): |
1884 | 1930 | self.assertEqual(mr.tolist(), yrlist) |
1885 | 1931 |
|
1886 | 1932 | if numpy_array: |
| 1933 | + # XXX NumPy (as far as it compiles with 3.3) currently |
| 1934 | + # segfaults here. Wait for a stable 3.3 compatible version. |
| 1935 | + continue |
1887 | 1936 | if 0 in lshape or 0 in rshape: |
1888 | 1937 | continue # http://projects.scipy.org/numpy/ticket/1910 |
1889 | 1938 |
|
@@ -2020,6 +2069,246 @@ def test_ndarray_hash(self): |
2020 | 2069 | nd = ndarray(list(range(12)), shape=[2,2,3], format='L') |
2021 | 2070 | self.assertEqual(hash(nd), hash(nd.tobytes())) |
2022 | 2071 |
|
| 2072 | + 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 | + |
2023 | 2312 | def test_memoryview_construction(self): |
2024 | 2313 |
|
2025 | 2314 | items_shape = [(9, []), ([1,2,3], [3]), (list(range(2*3*5)), [2,3,5])] |
|
0 commit comments