Team Ai
Datasetpublic

codekingpro/portable-devtools

sourceHugging Faceupdated 5mo agoView on Hugging Face
1likes14kdownloads
npy_3kcompat.h375 linesDownload Raw Back to numpy
1/*
2 * This is a convenience header file providing compatibility utilities
3 * for supporting different minor versions of Python 3.
4 * It was originally used to support the transition from Python 2,
5 * hence the "3k" naming.
6 *
7 * If you want to use this for your own projects, it's recommended to make a
8 * copy of it. We don't provide backwards compatibility guarantees.
9 */
10
11#ifndef NUMPY_CORE_INCLUDE_NUMPY_NPY_3KCOMPAT_H_
12#define NUMPY_CORE_INCLUDE_NUMPY_NPY_3KCOMPAT_H_
13
14#include <Python.h>
15#include <stdio.h>
16
17#include "npy_common.h"
18
19#ifdef __cplusplus
20extern "C" {
21#endif
22
23/* Python13 removes _PyLong_AsInt */
24static inline int
25Npy__PyLong_AsInt(PyObject *obj)
26{
27    int overflow;
28    long result = PyLong_AsLongAndOverflow(obj, &overflow);
29
30    /* INT_MAX and INT_MIN are defined in Python.h */
31    if (overflow || result > INT_MAX || result < INT_MIN) {
32        /* XXX: could be cute and give a different
33           message for overflow == -1 */
34        PyErr_SetString(PyExc_OverflowError,
35                        "Python int too large to convert to C int");
36        return -1;
37    }
38    return (int)result;
39}
40
41#if defined _MSC_VER && _MSC_VER >= 1900
42
43#include <stdlib.h>
44
45/*
46 * Macros to protect CRT calls against instant termination when passed an
47 * invalid parameter (https://bugs.python.org/issue23524).
48 */
49extern _invalid_parameter_handler _Py_silent_invalid_parameter_handler;
50#define NPY_BEGIN_SUPPRESS_IPH { _invalid_parameter_handler _Py_old_handler = \
51    _set_thread_local_invalid_parameter_handler(_Py_silent_invalid_parameter_handler);
52#define NPY_END_SUPPRESS_IPH _set_thread_local_invalid_parameter_handler(_Py_old_handler); }
53
54#else
55
56#define NPY_BEGIN_SUPPRESS_IPH
57#define NPY_END_SUPPRESS_IPH
58
59#endif /* _MSC_VER >= 1900 */
60
61/*
62 * PyFile_* compatibility
63 */
64
65/*
66 * Get a FILE* handle to the file represented by the Python object
67 */
68static inline FILE*
69npy_PyFile_Dup2(PyObject *file, char *mode, npy_off_t *orig_pos)
70{
71    int fd, fd2, unbuf;
72    Py_ssize_t fd2_tmp;
73    PyObject *ret, *os, *io, *io_raw;
74    npy_off_t pos;
75    FILE *handle;
76
77    /* Flush first to ensure things end up in the file in the correct order */
78    ret = PyObject_CallMethod(file, "flush", "");
79    if (ret == NULL) {
80        return NULL;
81    }
82    Py_DECREF(ret);
83    fd = PyObject_AsFileDescriptor(file);
84    if (fd == -1) {
85        return NULL;
86    }
87
88    /*
89     * The handle needs to be dup'd because we have to call fclose
90     * at the end
91     */
92    os = PyImport_ImportModule("os");
93    if (os == NULL) {
94        return NULL;
95    }
96    ret = PyObject_CallMethod(os, "dup", "i", fd);
97    Py_DECREF(os);
98    if (ret == NULL) {
99        return NULL;
100    }
101    fd2_tmp = PyNumber_AsSsize_t(ret, PyExc_IOError);
102    Py_DECREF(ret);
103    if (fd2_tmp == -1 && PyErr_Occurred()) {
104        return NULL;
105    }
106    if (fd2_tmp < INT_MIN || fd2_tmp > INT_MAX) {
107        PyErr_SetString(PyExc_IOError,
108                        "Getting an 'int' from os.dup() failed");
109        return NULL;
110    }
111    fd2 = (int)fd2_tmp;
112
113    /* Convert to FILE* handle */
114#ifdef _WIN32
115    NPY_BEGIN_SUPPRESS_IPH
116    handle = _fdopen(fd2, mode);
117    NPY_END_SUPPRESS_IPH
118#else
119    handle = fdopen(fd2, mode);
120#endif
121    if (handle == NULL) {
122        PyErr_SetString(PyExc_IOError,
123                        "Getting a FILE* from a Python file object via "
124                        "_fdopen failed. If you built NumPy, you probably "
125                        "linked with the wrong debug/release runtime");
126        return NULL;
127    }
128
129    /* Record the original raw file handle position */
130    *orig_pos = npy_ftell(handle);
131    if (*orig_pos == -1) {
132        /* The io module is needed to determine if buffering is used */
133        io = PyImport_ImportModule("io");
134        if (io == NULL) {
135            fclose(handle);
136            return NULL;
137        }
138        /* File object instances of RawIOBase are unbuffered */
139        io_raw = PyObject_GetAttrString(io, "RawIOBase");
140        Py_DECREF(io);
141        if (io_raw == NULL) {
142            fclose(handle);
143            return NULL;
144        }
145        unbuf = PyObject_IsInstance(file, io_raw);
146        Py_DECREF(io_raw);
147        if (unbuf == 1) {
148            /* Succeed if the IO is unbuffered */
149            return handle;
150        }
151        else {
152            PyErr_SetString(PyExc_IOError, "obtaining file position failed");
153            fclose(handle);
154            return NULL;
155        }
156    }
157
158    /* Seek raw handle to the Python-side position */
159    ret = PyObject_CallMethod(file, "tell", "");
160    if (ret == NULL) {
161        fclose(handle);
162        return NULL;
163    }
164    pos = PyLong_AsLongLong(ret);
165    Py_DECREF(ret);
166    if (PyErr_Occurred()) {
167        fclose(handle);
168        return NULL;
169    }
170    if (npy_fseek(handle, pos, SEEK_SET) == -1) {
171        PyErr_SetString(PyExc_IOError, "seeking file failed");
172        fclose(handle);
173        return NULL;
174    }
175    return handle;
176}
177
178/*
179 * Close the dup-ed file handle, and seek the Python one to the current position
180 */
181static inline int
182npy_PyFile_DupClose2(PyObject *file, FILE* handle, npy_off_t orig_pos)
183{
184    int fd, unbuf;
185    PyObject *ret, *io, *io_raw;
186    npy_off_t position;
187
188    position = npy_ftell(handle);
189
190    /* Close the FILE* handle */
191    fclose(handle);
192
193    /*
194     * Restore original file handle position, in order to not confuse
195     * Python-side data structures
196     */
197    fd = PyObject_AsFileDescriptor(file);
198    if (fd == -1) {
199        return -1;
200    }
201
202    if (npy_lseek(fd, orig_pos, SEEK_SET) == -1) {
203
204        /* The io module is needed to determine if buffering is used */
205        io = PyImport_ImportModule("io");
206        if (io == NULL) {
207            return -1;
208        }
209        /* File object instances of RawIOBase are unbuffered */
210        io_raw = PyObject_GetAttrString(io, "RawIOBase");
211        Py_DECREF(io);
212        if (io_raw == NULL) {
213            return -1;
214        }
215        unbuf = PyObject_IsInstance(file, io_raw);
216        Py_DECREF(io_raw);
217        if (unbuf == 1) {
218            /* Succeed if the IO is unbuffered */
219            return 0;
220        }
221        else {
222            PyErr_SetString(PyExc_IOError, "seeking file failed");
223            return -1;
224        }
225    }
226
227    if (position == -1) {
228        PyErr_SetString(PyExc_IOError, "obtaining file position failed");
229        return -1;
230    }
231
232    /* Seek Python-side handle to the FILE* handle position */
233    ret = PyObject_CallMethod(file, "seek", NPY_OFF_T_PYFMT "i", position, 0);
234    if (ret == NULL) {
235        return -1;
236    }
237    Py_DECREF(ret);
238    return 0;
239}
240
241static inline PyObject*
242npy_PyFile_OpenFile(PyObject *filename, const char *mode)
243{
244    PyObject *open;
245    open = PyDict_GetItemString(PyEval_GetBuiltins(), "open"); // noqa: borrowed-ref OK
246    if (open == NULL) {
247        return NULL;
248    }
249    return PyObject_CallFunction(open, "Os", filename, mode);
250}
251
252static inline int
253npy_PyFile_CloseFile(PyObject *file)
254{
255    PyObject *ret;
256
257    ret = PyObject_CallMethod(file, "close", NULL);
258    if (ret == NULL) {
259        return -1;
260    }
261    Py_DECREF(ret);
262    return 0;
263}
264
265/* This is a copy of _PyErr_ChainExceptions, which
266 *  is no longer exported from Python3.12
267 */
268static inline void
269npy_PyErr_ChainExceptions(PyObject *exc, PyObject *val, PyObject *tb)
270{
271    if (exc == NULL)
272        return;
273
274    if (PyErr_Occurred()) {
275        PyObject *exc2, *val2, *tb2;
276        PyErr_Fetch(&exc2, &val2, &tb2);
277        PyErr_NormalizeException(&exc, &val, &tb);
278        if (tb != NULL) {
279            PyException_SetTraceback(val, tb);
280            Py_DECREF(tb);
281        }
282        Py_DECREF(exc);
283        PyErr_NormalizeException(&exc2, &val2, &tb2);
284        PyException_SetContext(val2, val);
285        PyErr_Restore(exc2, val2, tb2);
286    }
287    else {
288        PyErr_Restore(exc, val, tb);
289    }
290}
291
292/* This is a copy of _PyErr_ChainExceptions, with:
293 *  __cause__ used instead of __context__
294 */
295static inline void
296npy_PyErr_ChainExceptionsCause(PyObject *exc, PyObject *val, PyObject *tb)
297{
298    if (exc == NULL)
299        return;
300
301    if (PyErr_Occurred()) {
302        PyObject *exc2, *val2, *tb2;
303        PyErr_Fetch(&exc2, &val2, &tb2);
304        PyErr_NormalizeException(&exc, &val, &tb);
305        if (tb != NULL) {
306            PyException_SetTraceback(val, tb);
307            Py_DECREF(tb);
308        }
309        Py_DECREF(exc);
310        PyErr_NormalizeException(&exc2, &val2, &tb2);
311        PyException_SetCause(val2, val);
312        PyErr_Restore(exc2, val2, tb2);
313    }
314    else {
315        PyErr_Restore(exc, val, tb);
316    }
317}
318
319/*
320 * PyCObject functions adapted to PyCapsules.
321 *
322 * The main job here is to get rid of the improved error handling
323 * of PyCapsules. It's a shame...
324 */
325static inline PyObject *
326NpyCapsule_FromVoidPtr(void *ptr, void (*dtor)(PyObject *))
327{
328    PyObject *ret = PyCapsule_New(ptr, NULL, dtor);
329    if (ret == NULL) {
330        PyErr_Clear();
331    }
332    return ret;
333}
334
335static inline PyObject *
336NpyCapsule_FromVoidPtrAndDesc(void *ptr, void* context, void (*dtor)(PyObject *))
337{
338    PyObject *ret = NpyCapsule_FromVoidPtr(ptr, dtor);
339    if (ret != NULL && PyCapsule_SetContext(ret, context) != 0) {
340        PyErr_Clear();
341        Py_DECREF(ret);
342        ret = NULL;
343    }
344    return ret;
345}
346
347static inline void *
348NpyCapsule_AsVoidPtr(PyObject *obj)
349{
350    void *ret = PyCapsule_GetPointer(obj, NULL);
351    if (ret == NULL) {
352        PyErr_Clear();
353    }
354    return ret;
355}
356
357static inline void *
358NpyCapsule_GetDesc(PyObject *obj)
359{
360    return PyCapsule_GetContext(obj);
361}
362
363static inline int
364NpyCapsule_Check(PyObject *ptr)
365{
366    return PyCapsule_CheckExact(ptr);
367}
368
369#ifdef __cplusplus
370}
371#endif
372
373
374#endif  /* NUMPY_CORE_INCLUDE_NUMPY_NPY_3KCOMPAT_H_ */
375 
codekingpro/portable-devtools · Team Ai