1
/*
2
 * This is a convenience header file providing compatibility utilities
3
 * for supporting Python 2 and Python 3 in the same code base.
4
 *
5
 * If you want to use this for your own projects, it's recommended to make a
6
 * copy of it. Although the stuff below is unlikely to change, we don't provide
7
 * strong backwards compatibility guarantees at the moment.
8
 */
9

10
#ifndef _NPY_3KCOMPAT_H_
11
#define _NPY_3KCOMPAT_H_
12

13
#include <Python.h>
14
#include <stdio.h>
15

16
#ifndef NPY_PY3K
17
#define NPY_PY3K 1
18
#endif
19

20
#include "numpy/npy_common.h"
21
#include "numpy/ndarrayobject.h"
22

23
#ifdef __cplusplus
24
extern "C" {
25
#endif
26

27
/*
28
 * PyInt -> PyLong
29
 */
30

31
#if defined(NPY_PY3K)
32
/* Return True only if the long fits in a C long */
33 1
static NPY_INLINE int PyInt_Check(PyObject *op) {
34 1
    int overflow = 0;
35 1
    if (!PyLong_Check(op)) {
36
        return 0;
37
    }
38 1
    PyLong_AsLongAndOverflow(op, &overflow);
39 1
    return (overflow == 0);
40
}
41

42
#define PyInt_FromLong PyLong_FromLong
43
#define PyInt_AsLong PyLong_AsLong
44
#define PyInt_AS_LONG PyLong_AsLong
45
#define PyInt_AsSsize_t PyLong_AsSsize_t
46
#define PyNumber_Int PyNumber_Long
47

48
/* NOTE:
49
 *
50
 * Since the PyLong type is very different from the fixed-range PyInt,
51
 * we don't define PyInt_Type -> PyLong_Type.
52
 */
53
#endif /* NPY_PY3K */
54

55
/* Py3 changes PySlice_GetIndicesEx' first argument's type to PyObject* */
56
#ifdef NPY_PY3K
57
#  define NpySlice_GetIndicesEx PySlice_GetIndicesEx
58
#else
59
#  define NpySlice_GetIndicesEx(op, nop, start, end, step, slicelength) \
60
    PySlice_GetIndicesEx((PySliceObject *)op, nop, start, end, step, slicelength)
61
#endif
62

63
#if PY_VERSION_HEX < 0x030900a4
64
    /* Introduced in https://github.com/python/cpython/commit/d2ec81a8c99796b51fb8c49b77a7fe369863226f */
65
    #define Py_SET_TYPE(obj, type) ((Py_TYPE(obj) = (type)), (void)0)
66
    /* Introduced in https://github.com/python/cpython/commit/b10dc3e7a11fcdb97e285882eba6da92594f90f9 */
67
    #define Py_SET_SIZE(obj, size) ((Py_SIZE(obj) = (size)), (void)0)
68
    /* Introduced in https://github.com/python/cpython/commit/c86a11221df7e37da389f9c6ce6e47ea22dc44ff */
69
    #define Py_SET_REFCNT(obj, refcnt) ((Py_REFCNT(obj) = (refcnt)), (void)0)
70
#endif
71

72

73
#define Npy_EnterRecursiveCall(x) Py_EnterRecursiveCall(x)
74

75
/* Py_SETREF was added in 3.5.2, and only if Py_LIMITED_API is absent */
76
#if PY_VERSION_HEX < 0x03050200
77
    #define Py_SETREF(op, op2)                      \
78
        do {                                        \
79
            PyObject *_py_tmp = (PyObject *)(op);   \
80
            (op) = (op2);                           \
81
            Py_DECREF(_py_tmp);                     \
82
        } while (0)
83
#endif
84

85
/* introduced in https://github.com/python/cpython/commit/a24107b04c1277e3c1105f98aff5bfa3a98b33a0 */
86
#if PY_VERSION_HEX < 0x030800A3
87
    static NPY_INLINE PyObject *
88 1
    _PyDict_GetItemStringWithError(PyObject *v, const char *key)
89
    {
90
        PyObject *kv, *rv;
91 1
        kv = PyUnicode_FromString(key);
92 1
        if (kv == NULL) {
93
            return NULL;
94
        }
95 1
        rv = PyDict_GetItemWithError(v, kv);
96 1
        Py_DECREF(kv);
97
        return rv;
98
    }
99
#endif
100

101
/*
102
 * PyString -> PyBytes
103
 */
104

105
#if defined(NPY_PY3K)
106

107
#define PyString_Type PyBytes_Type
108
#define PyString_Check PyBytes_Check
109
#define PyStringObject PyBytesObject
110
#define PyString_FromString PyBytes_FromString
111
#define PyString_FromStringAndSize PyBytes_FromStringAndSize
112
#define PyString_AS_STRING PyBytes_AS_STRING
113
#define PyString_AsStringAndSize PyBytes_AsStringAndSize
114
#define PyString_FromFormat PyBytes_FromFormat
115
#define PyString_Concat PyBytes_Concat
116
#define PyString_ConcatAndDel PyBytes_ConcatAndDel
117
#define PyString_AsString PyBytes_AsString
118
#define PyString_GET_SIZE PyBytes_GET_SIZE
119
#define PyString_Size PyBytes_Size
120

121
#define PyUString_Type PyUnicode_Type
122
#define PyUString_Check PyUnicode_Check
123
#define PyUStringObject PyUnicodeObject
124
#define PyUString_FromString PyUnicode_FromString
125
#define PyUString_FromStringAndSize PyUnicode_FromStringAndSize
126
#define PyUString_FromFormat PyUnicode_FromFormat
127
#define PyUString_Concat PyUnicode_Concat2
128
#define PyUString_ConcatAndDel PyUnicode_ConcatAndDel
129
#define PyUString_GET_SIZE PyUnicode_GET_SIZE
130
#define PyUString_Size PyUnicode_Size
131
#define PyUString_InternFromString PyUnicode_InternFromString
132
#define PyUString_Format PyUnicode_Format
133

134
#define PyBaseString_Check(obj) (PyUnicode_Check(obj))
135

136
#else
137

138
#define PyBytes_Type PyString_Type
139
#define PyBytes_Check PyString_Check
140
#define PyBytesObject PyStringObject
141
#define PyBytes_FromString PyString_FromString
142
#define PyBytes_FromStringAndSize PyString_FromStringAndSize
143
#define PyBytes_AS_STRING PyString_AS_STRING
144
#define PyBytes_AsStringAndSize PyString_AsStringAndSize
145
#define PyBytes_FromFormat PyString_FromFormat
146
#define PyBytes_Concat PyString_Concat
147
#define PyBytes_ConcatAndDel PyString_ConcatAndDel
148
#define PyBytes_AsString PyString_AsString
149
#define PyBytes_GET_SIZE PyString_GET_SIZE
150
#define PyBytes_Size PyString_Size
151

152
#define PyUString_Type PyString_Type
153
#define PyUString_Check PyString_Check
154
#define PyUStringObject PyStringObject
155
#define PyUString_FromString PyString_FromString
156
#define PyUString_FromStringAndSize PyString_FromStringAndSize
157
#define PyUString_FromFormat PyString_FromFormat
158
#define PyUString_Concat PyString_Concat
159
#define PyUString_ConcatAndDel PyString_ConcatAndDel
160
#define PyUString_GET_SIZE PyString_GET_SIZE
161
#define PyUString_Size PyString_Size
162
#define PyUString_InternFromString PyString_InternFromString
163
#define PyUString_Format PyString_Format
164

165
#define PyBaseString_Check(obj) (PyBytes_Check(obj) || PyUnicode_Check(obj))
166

167
#endif /* NPY_PY3K */
168

169

170
static NPY_INLINE void
171 1
PyUnicode_ConcatAndDel(PyObject **left, PyObject *right)
172
{
173 1
    Py_SETREF(*left, PyUnicode_Concat(*left, right));
174 1
    Py_DECREF(right);
175
}
176

177
static NPY_INLINE void
178 1
PyUnicode_Concat2(PyObject **left, PyObject *right)
179
{
180 1
    Py_SETREF(*left, PyUnicode_Concat(*left, right));
181
}
182

183
/*
184
 * PyFile_* compatibility
185
 */
186

187
/*
188
 * Get a FILE* handle to the file represented by the Python object
189
 */
190
static NPY_INLINE FILE*
191 1
npy_PyFile_Dup2(PyObject *file, char *mode, npy_off_t *orig_pos)
192
{
193
    int fd, fd2, unbuf;
194
    PyObject *ret, *os, *io, *io_raw;
195
    npy_off_t pos;
196
    FILE *handle;
197

198
    /* For Python 2 PyFileObject, use PyFile_AsFile */
199
#if !defined(NPY_PY3K)
200
    if (PyFile_Check(file)) {
201
        return PyFile_AsFile(file);
202
    }
203
#endif
204

205
    /* Flush first to ensure things end up in the file in the correct order */
206 1
    ret = PyObject_CallMethod(file, "flush", "");
207 1
    if (ret == NULL) {
208
        return NULL;
209
    }
210 1
    Py_DECREF(ret);
211 1
    fd = PyObject_AsFileDescriptor(file);
212 1
    if (fd == -1) {
213
        return NULL;
214
    }
215

216
    /*
217
     * The handle needs to be dup'd because we have to call fclose
218
     * at the end
219
     */
220 1
    os = PyImport_ImportModule("os");
221 1
    if (os == NULL) {
222
        return NULL;
223
    }
224 1
    ret = PyObject_CallMethod(os, "dup", "i", fd);
225 1
    Py_DECREF(os);
226 1
    if (ret == NULL) {
227
        return NULL;
228
    }
229 1
    fd2 = PyNumber_AsSsize_t(ret, NULL);
230 1
    Py_DECREF(ret);
231

232
    /* Convert to FILE* handle */
233
#ifdef _WIN32
234
    handle = _fdopen(fd2, mode);
235
#else
236 1
    handle = fdopen(fd2, mode);
237
#endif
238 1
    if (handle == NULL) {
239 0
        PyErr_SetString(PyExc_IOError,
240
                        "Getting a FILE* from a Python file object failed");
241 0
        return NULL;
242
    }
243

244
    /* Record the original raw file handle position */
245 1
    *orig_pos = npy_ftell(handle);
246 1
    if (*orig_pos == -1) {
247
        /* The io module is needed to determine if buffering is used */
248 0
        io = PyImport_ImportModule("io");
249 0
        if (io == NULL) {
250 0
            fclose(handle);
251 0
            return NULL;
252
        }
253
        /* File object instances of RawIOBase are unbuffered */
254 0
        io_raw = PyObject_GetAttrString(io, "RawIOBase");
255 0
        Py_DECREF(io);
256 0
        if (io_raw == NULL) {
257 0
            fclose(handle);
258 0
            return NULL;
259
        }
260 0
        unbuf = PyObject_IsInstance(file, io_raw);
261 0
        Py_DECREF(io_raw);
262 0
        if (unbuf == 1) {
263
            /* Succeed if the IO is unbuffered */
264
            return handle;
265
        }
266
        else {
267 0
            PyErr_SetString(PyExc_IOError, "obtaining file position failed");
268 0
            fclose(handle);
269 0
            return NULL;
270
        }
271
    }
272

273
    /* Seek raw handle to the Python-side position */
274 1
    ret = PyObject_CallMethod(file, "tell", "");
275 1
    if (ret == NULL) {
276 1
        fclose(handle);
277 1
        return NULL;
278
    }
279 1
    pos = PyLong_AsLongLong(ret);
280 1
    Py_DECREF(ret);
281 1
    if (PyErr_Occurred()) {
282 0
        fclose(handle);
283 0
        return NULL;
284
    }
285 1
    if (npy_fseek(handle, pos, SEEK_SET) == -1) {
286 0
        PyErr_SetString(PyExc_IOError, "seeking file failed");
287 0
        fclose(handle);
288 0
        return NULL;
289
    }
290
    return handle;
291
}
292

293
/*
294
 * Close the dup-ed file handle, and seek the Python one to the current position
295
 */
296
static NPY_INLINE int
297 1
npy_PyFile_DupClose2(PyObject *file, FILE* handle, npy_off_t orig_pos)
298
{
299
    int fd, unbuf;
300
    PyObject *ret, *io, *io_raw;
301
    npy_off_t position;
302

303
    /* For Python 2 PyFileObject, do nothing */
304
#if !defined(NPY_PY3K)
305
    if (PyFile_Check(file)) {
306
        return 0;
307
    }
308
#endif
309

310 1
    position = npy_ftell(handle);
311

312
    /* Close the FILE* handle */
313 1
    fclose(handle);
314

315
    /*
316
     * Restore original file handle position, in order to not confuse
317
     * Python-side data structures
318
     */
319 1
    fd = PyObject_AsFileDescriptor(file);
320 1
    if (fd == -1) {
321
        return -1;
322
    }
323

324 1
    if (npy_lseek(fd, orig_pos, SEEK_SET) == -1) {
325

326
        /* The io module is needed to determine if buffering is used */
327 0
        io = PyImport_ImportModule("io");
328 0
        if (io == NULL) {
329
            return -1;
330
        }
331
        /* File object instances of RawIOBase are unbuffered */
332 0
        io_raw = PyObject_GetAttrString(io, "RawIOBase");
333 0
        Py_DECREF(io);
334 0
        if (io_raw == NULL) {
335
            return -1;
336
        }
337 0
        unbuf = PyObject_IsInstance(file, io_raw);
338 0
        Py_DECREF(io_raw);
339 0
        if (unbuf == 1) {
340
            /* Succeed if the IO is unbuffered */
341
            return 0;
342
        }
343
        else {
344 0
            PyErr_SetString(PyExc_IOError, "seeking file failed");
345 0
            return -1;
346
        }
347
    }
348

349 1
    if (position == -1) {
350 0
        PyErr_SetString(PyExc_IOError, "obtaining file position failed");
351 0
        return -1;
352
    }
353

354
    /* Seek Python-side handle to the FILE* handle position */
355 1
    ret = PyObject_CallMethod(file, "seek", NPY_OFF_T_PYFMT "i", position, 0);
356 1
    if (ret == NULL) {
357
        return -1;
358
    }
359 1
    Py_DECREF(ret);
360
    return 0;
361
}
362

363
static NPY_INLINE int
364
npy_PyFile_Check(PyObject *file)
365
{
366
    int fd;
367
    /* For Python 2, check if it is a PyFileObject */
368
#if !defined(NPY_PY3K)
369
    if (PyFile_Check(file)) {
370
        return 1;
371
    }
372
#endif
373
    fd = PyObject_AsFileDescriptor(file);
374
    if (fd == -1) {
375
        PyErr_Clear();
376
        return 0;
377
    }
378
    return 1;
379
}
380

381
static NPY_INLINE PyObject*
382 1
npy_PyFile_OpenFile(PyObject *filename, const char *mode)
383
{
384
    PyObject *open;
385 1
    open = PyDict_GetItemString(PyEval_GetBuiltins(), "open");
386 1
    if (open == NULL) {
387
        return NULL;
388
    }
389 1
    return PyObject_CallFunction(open, "Os", filename, mode);
390
}
391

392
static NPY_INLINE int
393 1
npy_PyFile_CloseFile(PyObject *file)
394
{
395
    PyObject *ret;
396

397 1
    ret = PyObject_CallMethod(file, "close", NULL);
398 1
    if (ret == NULL) {
399
        return -1;
400
    }
401 1
    Py_DECREF(ret);
402
    return 0;
403
}
404

405

406
/* This is a copy of _PyErr_ChainExceptions
407
 */
408
static NPY_INLINE void
409 1
npy_PyErr_ChainExceptions(PyObject *exc, PyObject *val, PyObject *tb)
410
{
411 1
    if (exc == NULL)
412
        return;
413

414 1
    if (PyErr_Occurred()) {
415
        /* only py3 supports this anyway */
416
        #ifdef NPY_PY3K
417
            PyObject *exc2, *val2, *tb2;
418 1
            PyErr_Fetch(&exc2, &val2, &tb2);
419 1
            PyErr_NormalizeException(&exc, &val, &tb);
420 1
            if (tb != NULL) {
421 0
                PyException_SetTraceback(val, tb);
422 0
                Py_DECREF(tb);
423
            }
424 1
            Py_DECREF(exc);
425 1
            PyErr_NormalizeException(&exc2, &val2, &tb2);
426 1
            PyException_SetContext(val2, val);
427 1
            PyErr_Restore(exc2, val2, tb2);
428
        #endif
429
    }
430
    else {
431 0
        PyErr_Restore(exc, val, tb);
432
    }
433
}
434

435

436
/* This is a copy of _PyErr_ChainExceptions, with:
437
 *  - a minimal implementation for python 2
438
 *  - __cause__ used instead of __context__
439
 */
440
static NPY_INLINE void
441 1
npy_PyErr_ChainExceptionsCause(PyObject *exc, PyObject *val, PyObject *tb)
442
{
443 1
    if (exc == NULL)
444
        return;
445

446 1
    if (PyErr_Occurred()) {
447
        /* only py3 supports this anyway */
448
        #ifdef NPY_PY3K
449
            PyObject *exc2, *val2, *tb2;
450 1
            PyErr_Fetch(&exc2, &val2, &tb2);
451 1
            PyErr_NormalizeException(&exc, &val, &tb);
452 1
            if (tb != NULL) {
453 1
                PyException_SetTraceback(val, tb);
454 1
                Py_DECREF(tb);
455
            }
456 1
            Py_DECREF(exc);
457 1
            PyErr_NormalizeException(&exc2, &val2, &tb2);
458 1
            PyException_SetCause(val2, val);
459 1
            PyErr_Restore(exc2, val2, tb2);
460
        #endif
461
    }
462
    else {
463 0
        PyErr_Restore(exc, val, tb);
464
    }
465
}
466

467
/*
468
 * PyObject_Cmp
469
 */
470
#if defined(NPY_PY3K)
471
static NPY_INLINE int
472
PyObject_Cmp(PyObject *i1, PyObject *i2, int *cmp)
473
{
474
    int v;
475
    v = PyObject_RichCompareBool(i1, i2, Py_LT);
476
    if (v == 1) {
477
        *cmp = -1;
478
        return 1;
479
    }
480
    else if (v == -1) {
481
        return -1;
482
    }
483

484
    v = PyObject_RichCompareBool(i1, i2, Py_GT);
485
    if (v == 1) {
486
        *cmp = 1;
487
        return 1;
488
    }
489
    else if (v == -1) {
490
        return -1;
491
    }
492

493
    v = PyObject_RichCompareBool(i1, i2, Py_EQ);
494
    if (v == 1) {
495
        *cmp = 0;
496
        return 1;
497
    }
498
    else {
499
        *cmp = 0;
500
        return -1;
501
    }
502
}
503
#endif
504

505
/*
506
 * PyCObject functions adapted to PyCapsules.
507
 *
508
 * The main job here is to get rid of the improved error handling
509
 * of PyCapsules. It's a shame...
510
 */
511
static NPY_INLINE PyObject *
512
NpyCapsule_FromVoidPtr(void *ptr, void (*dtor)(PyObject *))
513
{
514 1
    PyObject *ret = PyCapsule_New(ptr, NULL, dtor);
515 1
    if (ret == NULL) {
516 0
        PyErr_Clear();
517
    }
518
    return ret;
519
}
520

521
static NPY_INLINE PyObject *
522 0
NpyCapsule_FromVoidPtrAndDesc(void *ptr, void* context, void (*dtor)(PyObject *))
523
{
524 0
    PyObject *ret = NpyCapsule_FromVoidPtr(ptr, dtor);
525 0
    if (ret != NULL && PyCapsule_SetContext(ret, context) != 0) {
526 0
        PyErr_Clear();
527 0
        Py_DECREF(ret);
528
        ret = NULL;
529
    }
530 0
    return ret;
531
}
532

533
static NPY_INLINE void *
534
NpyCapsule_AsVoidPtr(PyObject *obj)
535
{
536
    void *ret = PyCapsule_GetPointer(obj, NULL);
537
    if (ret == NULL) {
538
        PyErr_Clear();
539
    }
540
    return ret;
541
}
542

543
static NPY_INLINE void *
544
NpyCapsule_GetDesc(PyObject *obj)
545
{
546
    return PyCapsule_GetContext(obj);
547
}
548

549
static NPY_INLINE int
550
NpyCapsule_Check(PyObject *ptr)
551
{
552
    return PyCapsule_CheckExact(ptr);
553
}
554

555
#ifdef __cplusplus
556
}
557
#endif
558

559

560
#endif /* _NPY_3KCOMPAT_H_ */

Read our documentation on viewing source code .

Loading