codekingpro/portable-devtools
114k
1#cython: language_level=3
2
3"""
4Functions in this module give python-space wrappers for cython functions
5exposed in numpy/__init__.pxd, so they can be tested in test_cython.py
6"""
7import numpy as np
8cimport numpy as cnp
9cnp.import_array()
10
11
12def is_td64(obj):
13 return cnp.is_timedelta64_object(obj)
14
15
16def is_dt64(obj):
17 return cnp.is_datetime64_object(obj)
18
19
20def get_dt64_value(obj):
21 return cnp.get_datetime64_value(obj)
22
23
24def get_td64_value(obj):
25 return cnp.get_timedelta64_value(obj)
26
27
28def get_dt64_unit(obj):
29 return cnp.get_datetime64_unit(obj)
30
31
32def is_integer(obj):
33 return isinstance(obj, (cnp.integer, int))
34
35
36def get_datetime_iso_8601_strlen():
37 return cnp.get_datetime_iso_8601_strlen(0, cnp.NPY_FR_ns)
38
39
40def convert_datetime64_to_datetimestruct():
41 cdef:
42 cnp.npy_datetimestruct dts
43 cnp.PyArray_DatetimeMetaData meta
44 cnp.int64_t value = 1647374515260292
45 # i.e. (time.time() * 10**6) at 2022-03-15 20:01:55.260292 UTC
46
47 meta.base = cnp.NPY_FR_us
48 meta.num = 1
49 cnp.convert_datetime64_to_datetimestruct(&meta, value, &dts)
50 return dts
51
52
53def make_iso_8601_datetime(dt: "datetime"):
54 cdef:
55 cnp.npy_datetimestruct dts
56 char result[36] # 36 corresponds to NPY_FR_s passed below
57 int local = 0
58 int utc = 0
59 int tzoffset = 0
60
61 dts.year = dt.year
62 dts.month = dt.month
63 dts.day = dt.day
64 dts.hour = dt.hour
65 dts.min = dt.minute
66 dts.sec = dt.second
67 dts.us = dt.microsecond
68 dts.ps = dts.as = 0
69
70 cnp.make_iso_8601_datetime(
71 &dts,
72 result,
73 sizeof(result),
74 local,
75 utc,
76 cnp.NPY_FR_s,
77 tzoffset,
78 cnp.NPY_NO_CASTING,
79 )
80 return result
81
82
83cdef cnp.broadcast multiiter_from_broadcast_obj(object bcast):
84 cdef dict iter_map = {
85 1: cnp.PyArray_MultiIterNew1,
86 2: cnp.PyArray_MultiIterNew2,
87 3: cnp.PyArray_MultiIterNew3,
88 4: cnp.PyArray_MultiIterNew4,
89 5: cnp.PyArray_MultiIterNew5,
90 }
91 arrays = [x.base for x in bcast.iters]
92 cdef cnp.broadcast result = iter_map[len(arrays)](*arrays)
93 return result
94
95
96def get_multiiter_size(bcast: "broadcast"):
97 cdef cnp.broadcast multi = multiiter_from_broadcast_obj(bcast)
98 return multi.size
99
100
101def get_multiiter_number_of_dims(bcast: "broadcast"):
102 cdef cnp.broadcast multi = multiiter_from_broadcast_obj(bcast)
103 return multi.nd
104
105
106def get_multiiter_current_index(bcast: "broadcast"):
107 cdef cnp.broadcast multi = multiiter_from_broadcast_obj(bcast)
108 return multi.index
109
110
111def get_multiiter_num_of_iterators(bcast: "broadcast"):
112 cdef cnp.broadcast multi = multiiter_from_broadcast_obj(bcast)
113 return multi.numiter
114
115
116def get_multiiter_shape(bcast: "broadcast"):
117 cdef cnp.broadcast multi = multiiter_from_broadcast_obj(bcast)
118 return tuple([multi.dimensions[i] for i in range(bcast.nd)])
119
120
121def get_multiiter_iters(bcast: "broadcast"):
122 cdef cnp.broadcast multi = multiiter_from_broadcast_obj(bcast)
123 return tuple([<cnp.flatiter>multi.iters[i] for i in range(bcast.numiter)])
124
125
126def get_default_integer():
127 if cnp.NPY_DEFAULT_INT == cnp.NPY_LONG:
128 return cnp.dtype("long")
129 if cnp.NPY_DEFAULT_INT == cnp.NPY_INTP:
130 return cnp.dtype("intp")
131 return None
132
133def get_ravel_axis():
134 return cnp.NPY_RAVEL_AXIS
135
136
137def conv_intp(cnp.intp_t val):
138 return val
139
140
141def get_dtype_flags(cnp.dtype dtype):
142 return dtype.flags
143
144
145cdef cnp.NpyIter* npyiter_from_nditer_obj(object it):
146 """A function to create a NpyIter struct from a nditer object.
147
148 This function is only meant for testing purposes and only extracts the
149 necessary info from nditer to test the functionality of NpyIter methods
150 """
151 cdef:
152 cnp.NpyIter* cit
153 cnp.PyArray_Descr* op_dtypes[3]
154 cnp.npy_uint32 op_flags[3]
155 cnp.PyArrayObject* ops[3]
156 cnp.npy_uint32 flags = 0
157
158 if it.has_index:
159 flags |= cnp.NPY_ITER_C_INDEX
160 if it.has_delayed_bufalloc:
161 flags |= cnp.NPY_ITER_BUFFERED | cnp.NPY_ITER_DELAY_BUFALLOC
162 if it.has_multi_index:
163 flags |= cnp.NPY_ITER_MULTI_INDEX
164
165 # one of READWRITE, READONLY and WRTIEONLY at the minimum must be specified for op_flags
166 for i in range(it.nop):
167 op_flags[i] = cnp.NPY_ITER_READONLY
168
169 for i in range(it.nop):
170 op_dtypes[i] = cnp.PyArray_DESCR(it.operands[i])
171 ops[i] = <cnp.PyArrayObject*>it.operands[i]
172
173 cit = cnp.NpyIter_MultiNew(it.nop, &ops[0], flags, cnp.NPY_KEEPORDER,
174 cnp.NPY_NO_CASTING, &op_flags[0],
175 <cnp.PyArray_Descr**>NULL)
176 return cit
177
178
179def get_npyiter_size(it: "nditer"):
180 cdef cnp.NpyIter* cit = npyiter_from_nditer_obj(it)
181 result = cnp.NpyIter_GetIterSize(cit)
182 cnp.NpyIter_Deallocate(cit)
183 return result
184
185
186def get_npyiter_ndim(it: "nditer"):
187 cdef cnp.NpyIter* cit = npyiter_from_nditer_obj(it)
188 result = cnp.NpyIter_GetNDim(cit)
189 cnp.NpyIter_Deallocate(cit)
190 return result
191
192
193def get_npyiter_nop(it: "nditer"):
194 cdef cnp.NpyIter* cit = npyiter_from_nditer_obj(it)
195 result = cnp.NpyIter_GetNOp(cit)
196 cnp.NpyIter_Deallocate(cit)
197 return result
198
199
200def get_npyiter_operands(it: "nditer"):
201 cdef cnp.NpyIter* cit = npyiter_from_nditer_obj(it)
202 try:
203 arr = cnp.NpyIter_GetOperandArray(cit)
204 return tuple([<cnp.ndarray>arr[i] for i in range(it.nop)])
205 finally:
206 cnp.NpyIter_Deallocate(cit)
207
208
209def get_npyiter_itviews(it: "nditer"):
210 cdef cnp.NpyIter* cit = npyiter_from_nditer_obj(it)
211 result = tuple([cnp.NpyIter_GetIterView(cit, i) for i in range(it.nop)])
212 cnp.NpyIter_Deallocate(cit)
213 return result
214
215
216def get_npyiter_dtypes(it: "nditer"):
217 cdef cnp.NpyIter* cit = npyiter_from_nditer_obj(it)
218 try:
219 arr = cnp.NpyIter_GetDescrArray(cit)
220 return tuple([<cnp.dtype>arr[i] for i in range(it.nop)])
221 finally:
222 cnp.NpyIter_Deallocate(cit)
223
224
225def npyiter_has_delayed_bufalloc(it: "nditer"):
226 cdef cnp.NpyIter* cit = npyiter_from_nditer_obj(it)
227 result = cnp.NpyIter_HasDelayedBufAlloc(cit)
228 cnp.NpyIter_Deallocate(cit)
229 return result
230
231
232def npyiter_has_index(it: "nditer"):
233 cdef cnp.NpyIter* cit = npyiter_from_nditer_obj(it)
234 result = cnp.NpyIter_HasIndex(cit)
235 cnp.NpyIter_Deallocate(cit)
236 return result
237
238
239def npyiter_has_multi_index(it: "nditer"):
240 cdef cnp.NpyIter* cit = npyiter_from_nditer_obj(it)
241 result = cnp.NpyIter_HasMultiIndex(cit)
242 cnp.NpyIter_Deallocate(cit)
243 return result
244
245
246def test_get_multi_index_iter_next(it: "nditer", cnp.ndarray[cnp.float64_t, ndim=2] arr):
247 cdef cnp.NpyIter* cit = npyiter_from_nditer_obj(it)
248 cdef cnp.NpyIter_GetMultiIndexFunc _get_multi_index = \
249 cnp.NpyIter_GetGetMultiIndex(cit, NULL)
250 cdef cnp.NpyIter_IterNextFunc _iternext = \
251 cnp.NpyIter_GetIterNext(cit, NULL)
252 cnp.NpyIter_Deallocate(cit)
253 return 1
254
255
256def npyiter_has_finished(it: "nditer"):
257 cdef cnp.NpyIter* cit
258 try:
259 cit = npyiter_from_nditer_obj(it)
260 cnp.NpyIter_GotoIterIndex(cit, it.index)
261 return not (cnp.NpyIter_GetIterIndex(cit) < cnp.NpyIter_GetIterSize(cit))
262 finally:
263 cnp.NpyIter_Deallocate(cit)
264
265def compile_fillwithbyte():
266 # Regression test for gh-25878, mostly checks it compiles.
267 cdef cnp.npy_intp dims[2]
268 dims = (1, 2)
269 pos = cnp.PyArray_ZEROS(2, dims, cnp.NPY_UINT8, 0)
270 cnp.PyArray_FILLWBYTE(pos, 1)
271 return pos
272
273def inc2_cfloat_struct(cnp.ndarray[cnp.cfloat_t] arr):
274 # This works since we compile in C mode, it will fail in cpp mode
275 arr[1].real += 1
276 arr[1].imag += 1
277 # This works in both modes
278 arr[1].real = arr[1].real + 1
279 arr[1].imag = arr[1].imag + 1
280
281
282def npystring_pack(arr):
283 cdef char *string = "Hello world"
284 cdef size_t size = 11
285
286 allocator = cnp.NpyString_acquire_allocator(
287 <cnp.PyArray_StringDTypeObject *>cnp.PyArray_DESCR(arr)
288 )
289
290 # copy string->packed_string, the pointer to the underlying array buffer
291 ret = cnp.NpyString_pack(
292 allocator, <cnp.npy_packed_static_string *>cnp.PyArray_DATA(arr), string, size,
293 )
294
295 cnp.NpyString_release_allocator(allocator)
296 return ret
297
298
299def npystring_load(arr):
300 allocator = cnp.NpyString_acquire_allocator(
301 <cnp.PyArray_StringDTypeObject *>cnp.PyArray_DESCR(arr)
302 )
303
304 cdef cnp.npy_static_string sdata
305 sdata.size = 0
306 sdata.buf = NULL
307
308 cdef cnp.npy_packed_static_string *packed_string = <cnp.npy_packed_static_string *>cnp.PyArray_DATA(arr)
309 cdef int is_null = cnp.NpyString_load(allocator, packed_string, &sdata)
310 cnp.NpyString_release_allocator(allocator)
311 if is_null == -1:
312 raise ValueError("String unpacking failed.")
313 elif is_null == 1:
314 # String in the array buffer is the null string
315 return ""
316 else:
317 # Cython syntax for copying a c string to python bytestring:
318 # slice the char * by the length of the string
319 return sdata.buf[:sdata.size].decode('utf-8')
320
321
322def npystring_pack_multiple(arr1, arr2):
323 cdef cnp.npy_string_allocator *allocators[2]
324 cdef cnp.PyArray_Descr *descrs[2]
325 descrs[0] = cnp.PyArray_DESCR(arr1)
326 descrs[1] = cnp.PyArray_DESCR(arr2)
327
328 cnp.NpyString_acquire_allocators(2, descrs, allocators)
329
330 # Write into the first element of each array
331 cdef int ret1 = cnp.NpyString_pack(
332 allocators[0], <cnp.npy_packed_static_string *>cnp.PyArray_DATA(arr1), "Hello world", 11,
333 )
334 cdef int ret2 = cnp.NpyString_pack(
335 allocators[1], <cnp.npy_packed_static_string *>cnp.PyArray_DATA(arr2), "test this", 9,
336 )
337
338 # Write a null string into the last element
339 cdef cnp.npy_intp elsize = cnp.PyArray_ITEMSIZE(arr1)
340 cdef int ret3 = cnp.NpyString_pack_null(
341 allocators[0],
342 <cnp.npy_packed_static_string *>(<char *>cnp.PyArray_DATA(arr1) + 2*elsize),
343 )
344
345 cnp.NpyString_release_allocators(2, allocators)
346 if ret1 == -1 or ret2 == -1 or ret3 == -1:
347 return -1
348
349 return 0
350
351
352def npystring_allocators_other_types(arr1, arr2):
353 cdef cnp.npy_string_allocator *allocators[2]
354 cdef cnp.PyArray_Descr *descrs[2]
355 descrs[0] = cnp.PyArray_DESCR(arr1)
356 descrs[1] = cnp.PyArray_DESCR(arr2)
357
358 cnp.NpyString_acquire_allocators(2, descrs, allocators)
359
360 # None of the dtypes here are StringDType, so every allocator
361 # should be NULL upon acquisition.
362 cdef int ret = 0
363 for allocator in allocators:
364 if allocator != NULL:
365 ret = -1
366 break
367
368 cnp.NpyString_release_allocators(2, allocators)
369 return ret
370
371
372def check_npy_uintp_type_enum():
373 # Regression test for gh-27890: cnp.NPY_UINTP was not defined.
374 # Cython would fail to compile this before gh-27890 was fixed.
375 return cnp.NPY_UINTP > 0
376
377
378def resize_refcheck_test():
379 # see gh-30991
380 a = np.array([[0, 1], [2, 3]], order='C')
381 a.resize((2, 1))
382 