numpy  2.0.0
include/numpy/npy_3kcompat.h
Go to the documentation of this file.
00001 /*
00002  * This is a convenience header file providing compatibility utilities
00003  * for supporting Python 2 and Python 3 in the same code base.
00004  *
00005  * If you want to use this for your own projects, it's recommended to make a
00006  * copy of it. Although the stuff below is unlikely to change, we don't provide
00007  * strong backwards compatibility guarantees at the moment.
00008  */
00009 
00010 #ifndef _NPY_3KCOMPAT_H_
00011 #define _NPY_3KCOMPAT_H_
00012 
00013 #include <Python.h>
00014 #include <stdio.h>
00015 
00016 #if PY_VERSION_HEX >= 0x03000000
00017 #ifndef NPY_PY3K
00018 #define NPY_PY3K 1
00019 #endif
00020 #endif
00021 
00022 #include "numpy/npy_common.h"
00023 #include "numpy/ndarrayobject.h"
00024 
00025 #ifdef __cplusplus
00026 extern "C" {
00027 #endif
00028 
00029 /*
00030  * PyInt -> PyLong
00031  */
00032 
00033 #if defined(NPY_PY3K)
00034 /* Return True only if the long fits in a C long */
00035 static NPY_INLINE int PyInt_Check(PyObject *op) {
00036     int overflow = 0;
00037     if (!PyLong_Check(op)) {
00038         return 0;
00039     }
00040     PyLong_AsLongAndOverflow(op, &overflow);
00041     return (overflow == 0);
00042 }
00043 
00044 #define PyInt_FromLong PyLong_FromLong
00045 #define PyInt_AsLong PyLong_AsLong
00046 #define PyInt_AS_LONG PyLong_AsLong
00047 #define PyInt_AsSsize_t PyLong_AsSsize_t
00048 
00049 /* NOTE:
00050  *
00051  * Since the PyLong type is very different from the fixed-range PyInt,
00052  * we don't define PyInt_Type -> PyLong_Type.
00053  */
00054 #endif /* NPY_PY3K */
00055 
00056 /* Py3 changes PySlice_GetIndicesEx' first argument's type to PyObject* */
00057 #ifdef NPY_PY3K
00058 #  define NpySlice_GetIndicesEx PySlice_GetIndicesEx
00059 #else
00060 #  define NpySlice_GetIndicesEx(op, nop, start, end, step, slicelength) \
00061     PySlice_GetIndicesEx((PySliceObject *)op, nop, start, end, step, slicelength)
00062 #endif
00063 
00064 /*
00065  * PyString -> PyBytes
00066  */
00067 
00068 #if defined(NPY_PY3K)
00069 
00070 #define PyString_Type PyBytes_Type
00071 #define PyString_Check PyBytes_Check
00072 #define PyStringObject PyBytesObject
00073 #define PyString_FromString PyBytes_FromString
00074 #define PyString_FromStringAndSize PyBytes_FromStringAndSize
00075 #define PyString_AS_STRING PyBytes_AS_STRING
00076 #define PyString_AsStringAndSize PyBytes_AsStringAndSize
00077 #define PyString_FromFormat PyBytes_FromFormat
00078 #define PyString_Concat PyBytes_Concat
00079 #define PyString_ConcatAndDel PyBytes_ConcatAndDel
00080 #define PyString_AsString PyBytes_AsString
00081 #define PyString_GET_SIZE PyBytes_GET_SIZE
00082 #define PyString_Size PyBytes_Size
00083 
00084 #define PyUString_Type PyUnicode_Type
00085 #define PyUString_Check PyUnicode_Check
00086 #define PyUStringObject PyUnicodeObject
00087 #define PyUString_FromString PyUnicode_FromString
00088 #define PyUString_FromStringAndSize PyUnicode_FromStringAndSize
00089 #define PyUString_FromFormat PyUnicode_FromFormat
00090 #define PyUString_Concat PyUnicode_Concat2
00091 #define PyUString_ConcatAndDel PyUnicode_ConcatAndDel
00092 #define PyUString_GET_SIZE PyUnicode_GET_SIZE
00093 #define PyUString_Size PyUnicode_Size
00094 #define PyUString_InternFromString PyUnicode_InternFromString
00095 #define PyUString_Format PyUnicode_Format
00096 
00097 #else
00098 
00099 #define PyBytes_Type PyString_Type
00100 #define PyBytes_Check PyString_Check
00101 #define PyBytesObject PyStringObject
00102 #define PyBytes_FromString PyString_FromString
00103 #define PyBytes_FromStringAndSize PyString_FromStringAndSize
00104 #define PyBytes_AS_STRING PyString_AS_STRING
00105 #define PyBytes_AsStringAndSize PyString_AsStringAndSize
00106 #define PyBytes_FromFormat PyString_FromFormat
00107 #define PyBytes_Concat PyString_Concat
00108 #define PyBytes_ConcatAndDel PyString_ConcatAndDel
00109 #define PyBytes_AsString PyString_AsString
00110 #define PyBytes_GET_SIZE PyString_GET_SIZE
00111 #define PyBytes_Size PyString_Size
00112 
00113 #define PyUString_Type PyString_Type
00114 #define PyUString_Check PyString_Check
00115 #define PyUStringObject PyStringObject
00116 #define PyUString_FromString PyString_FromString
00117 #define PyUString_FromStringAndSize PyString_FromStringAndSize
00118 #define PyUString_FromFormat PyString_FromFormat
00119 #define PyUString_Concat PyString_Concat
00120 #define PyUString_ConcatAndDel PyString_ConcatAndDel
00121 #define PyUString_GET_SIZE PyString_GET_SIZE
00122 #define PyUString_Size PyString_Size
00123 #define PyUString_InternFromString PyString_InternFromString
00124 #define PyUString_Format PyString_Format
00125 
00126 #endif /* NPY_PY3K */
00127 
00128 
00129 static NPY_INLINE void
00130 PyUnicode_ConcatAndDel(PyObject **left, PyObject *right)
00131 {
00132     PyObject *newobj;
00133     newobj = PyUnicode_Concat(*left, right);
00134     Py_DECREF(*left);
00135     Py_DECREF(right);
00136     *left = newobj;
00137 }
00138 
00139 static NPY_INLINE void
00140 PyUnicode_Concat2(PyObject **left, PyObject *right)
00141 {
00142     PyObject *newobj;
00143     newobj = PyUnicode_Concat(*left, right);
00144     Py_DECREF(*left);
00145     *left = newobj;
00146 }
00147 
00148 /*
00149  * PyFile_* compatibility
00150  */
00151 #if defined(NPY_PY3K)
00152 /*
00153  * Get a FILE* handle to the file represented by the Python object
00154  */
00155 static NPY_INLINE FILE*
00156 npy_PyFile_Dup2(PyObject *file, char *mode, npy_off_t *orig_pos)
00157 {
00158     int fd, fd2, unbuf;
00159     PyObject *ret, *os, *io, *io_raw;
00160     npy_off_t pos;
00161     FILE *handle;
00162 
00163     /* Flush first to ensure things end up in the file in the correct order */
00164     ret = PyObject_CallMethod(file, "flush", "");
00165     if (ret == NULL) {
00166         return NULL;
00167     }
00168     Py_DECREF(ret);
00169     fd = PyObject_AsFileDescriptor(file);
00170     if (fd == -1) {
00171         return NULL;
00172     }
00173 
00174     /*
00175      * The handle needs to be dup'd because we have to call fclose
00176      * at the end
00177      */
00178     os = PyImport_ImportModule("os");
00179     if (os == NULL) {
00180         return NULL;
00181     }
00182     ret = PyObject_CallMethod(os, "dup", "i", fd);
00183     Py_DECREF(os);
00184     if (ret == NULL) {
00185         return NULL;
00186     }
00187     fd2 = PyNumber_AsSsize_t(ret, NULL);
00188     Py_DECREF(ret);
00189 
00190     /* Convert to FILE* handle */
00191 #ifdef _WIN32
00192     handle = _fdopen(fd2, mode);
00193 #else
00194     handle = fdopen(fd2, mode);
00195 #endif
00196     if (handle == NULL) {
00197         PyErr_SetString(PyExc_IOError,
00198                         "Getting a FILE* from a Python file object failed");
00199     }
00200 
00201     /* Record the original raw file handle position */
00202     *orig_pos = npy_ftell(handle);
00203     if (*orig_pos == -1) {
00204         /* The io module is needed to determine if buffering is used */
00205         io = PyImport_ImportModule("io");
00206         if (io == NULL) {
00207             fclose(handle);
00208             return NULL;
00209         }
00210         /* File object instances of RawIOBase are unbuffered */
00211         io_raw = PyObject_GetAttrString(io, "RawIOBase");
00212         Py_DECREF(io);
00213         if (io_raw == NULL) {
00214             fclose(handle);
00215             return NULL;
00216         }
00217         unbuf = PyObject_IsInstance(file, io_raw);
00218         Py_DECREF(io_raw);
00219         if (unbuf == 1) {
00220             /* Succeed if the IO is unbuffered */
00221             return handle;
00222         }
00223         else {
00224             PyErr_SetString(PyExc_IOError, "obtaining file position failed");
00225             fclose(handle);
00226             return NULL;
00227         }
00228     }
00229 
00230     /* Seek raw handle to the Python-side position */
00231     ret = PyObject_CallMethod(file, "tell", "");
00232     if (ret == NULL) {
00233         fclose(handle);
00234         return NULL;
00235     }
00236     pos = PyLong_AsLongLong(ret);
00237     Py_DECREF(ret);
00238     if (PyErr_Occurred()) {
00239         fclose(handle);
00240         return NULL;
00241     }
00242     if (npy_fseek(handle, pos, SEEK_SET) == -1) {
00243         PyErr_SetString(PyExc_IOError, "seeking file failed");
00244         fclose(handle);
00245         return NULL;
00246     }
00247     return handle;
00248 }
00249 
00250 /*
00251  * Close the dup-ed file handle, and seek the Python one to the current position
00252  */
00253 static NPY_INLINE int
00254 npy_PyFile_DupClose2(PyObject *file, FILE* handle, npy_off_t orig_pos)
00255 {
00256     int fd, unbuf;
00257     PyObject *ret, *io, *io_raw;
00258     npy_off_t position;
00259 
00260     position = npy_ftell(handle);
00261 
00262     /* Close the FILE* handle */
00263     fclose(handle);
00264 
00265     /*
00266      * Restore original file handle position, in order to not confuse
00267      * Python-side data structures
00268      */
00269     fd = PyObject_AsFileDescriptor(file);
00270     if (fd == -1) {
00271         return -1;
00272     }
00273 
00274     if (npy_lseek(fd, orig_pos, SEEK_SET) == -1) {
00275 
00276         /* The io module is needed to determine if buffering is used */
00277         io = PyImport_ImportModule("io");
00278         if (io == NULL) {
00279             return -1;
00280         }
00281         /* File object instances of RawIOBase are unbuffered */
00282         io_raw = PyObject_GetAttrString(io, "RawIOBase");
00283         Py_DECREF(io);
00284         if (io_raw == NULL) {
00285             return -1;
00286         }
00287         unbuf = PyObject_IsInstance(file, io_raw);
00288         Py_DECREF(io_raw);
00289         if (unbuf == 1) {
00290             /* Succeed if the IO is unbuffered */
00291             return 0;
00292         }
00293         else {
00294             PyErr_SetString(PyExc_IOError, "seeking file failed");
00295             return -1;
00296         }
00297     }
00298 
00299     if (position == -1) {
00300         PyErr_SetString(PyExc_IOError, "obtaining file position failed");
00301         return -1;
00302     }
00303 
00304     /* Seek Python-side handle to the FILE* handle position */
00305     ret = PyObject_CallMethod(file, "seek", NPY_OFF_T_PYFMT "i", position, 0);
00306     if (ret == NULL) {
00307         return -1;
00308     }
00309     Py_DECREF(ret);
00310     return 0;
00311 }
00312 
00313 static NPY_INLINE int
00314 npy_PyFile_Check(PyObject *file)
00315 {
00316     int fd;
00317     fd = PyObject_AsFileDescriptor(file);
00318     if (fd == -1) {
00319         PyErr_Clear();
00320         return 0;
00321     }
00322     return 1;
00323 }
00324 
00325 #else
00326 
00327 static NPY_INLINE FILE *
00328 npy_PyFile_Dup2(PyObject *file,
00329                 const char *NPY_UNUSED(mode), npy_off_t *NPY_UNUSED(orig_pos))
00330 {
00331     FILE * fp = PyFile_AsFile(file);
00332     if (fp == NULL) {
00333         PyErr_SetString(PyExc_IOError,
00334                         "first argument must be an open file");
00335         return NULL;
00336     }
00337     return fp;
00338 }
00339 
00340 static NPY_INLINE int
00341 npy_PyFile_DupClose2(PyObject *NPY_UNUSED(file), FILE* NPY_UNUSED(handle),
00342                      npy_off_t NPY_UNUSED(orig_pos))
00343 {
00344     return 0;
00345 }
00346 
00347 #define npy_PyFile_Check PyFile_Check
00348 
00349 #endif
00350 
00351 static NPY_INLINE PyObject*
00352 npy_PyFile_OpenFile(PyObject *filename, const char *mode)
00353 {
00354     PyObject *open;
00355     open = PyDict_GetItemString(PyEval_GetBuiltins(), "open");
00356     if (open == NULL) {
00357         return NULL;
00358     }
00359     return PyObject_CallFunction(open, "Os", filename, mode);
00360 }
00361 
00362 static NPY_INLINE int
00363 npy_PyFile_CloseFile(PyObject *file)
00364 {
00365     PyObject *ret;
00366 
00367     ret = PyObject_CallMethod(file, "close", NULL);
00368     if (ret == NULL) {
00369         return -1;
00370     }
00371     Py_DECREF(ret);
00372     return 0;
00373 }
00374 
00375 /*
00376  * PyObject_Cmp
00377  */
00378 #if defined(NPY_PY3K)
00379 static NPY_INLINE int
00380 PyObject_Cmp(PyObject *i1, PyObject *i2, int *cmp)
00381 {
00382     int v;
00383     v = PyObject_RichCompareBool(i1, i2, Py_LT);
00384     if (v == 1) {
00385         *cmp = -1;
00386         return 1;
00387     }
00388     else if (v == -1) {
00389         return -1;
00390     }
00391 
00392     v = PyObject_RichCompareBool(i1, i2, Py_GT);
00393     if (v == 1) {
00394         *cmp = 1;
00395         return 1;
00396     }
00397     else if (v == -1) {
00398         return -1;
00399     }
00400 
00401     v = PyObject_RichCompareBool(i1, i2, Py_EQ);
00402     if (v == 1) {
00403         *cmp = 0;
00404         return 1;
00405     }
00406     else {
00407         *cmp = 0;
00408         return -1;
00409     }
00410 }
00411 #endif
00412 
00413 /*
00414  * PyCObject functions adapted to PyCapsules.
00415  *
00416  * The main job here is to get rid of the improved error handling
00417  * of PyCapsules. It's a shame...
00418  */
00419 #if PY_VERSION_HEX >= 0x03000000
00420 
00421 static NPY_INLINE PyObject *
00422 NpyCapsule_FromVoidPtr(void *ptr, void (*dtor)(PyObject *))
00423 {
00424     PyObject *ret = PyCapsule_New(ptr, NULL, dtor);
00425     if (ret == NULL) {
00426         PyErr_Clear();
00427     }
00428     return ret;
00429 }
00430 
00431 static NPY_INLINE PyObject *
00432 NpyCapsule_FromVoidPtrAndDesc(void *ptr, void* context, void (*dtor)(PyObject *))
00433 {
00434     PyObject *ret = NpyCapsule_FromVoidPtr(ptr, dtor);
00435     if (ret != NULL && PyCapsule_SetContext(ret, context) != 0) {
00436         PyErr_Clear();
00437         Py_DECREF(ret);
00438         ret = NULL;
00439     }
00440     return ret;
00441 }
00442 
00443 static NPY_INLINE void *
00444 NpyCapsule_AsVoidPtr(PyObject *obj)
00445 {
00446     void *ret = PyCapsule_GetPointer(obj, NULL);
00447     if (ret == NULL) {
00448         PyErr_Clear();
00449     }
00450     return ret;
00451 }
00452 
00453 static NPY_INLINE void *
00454 NpyCapsule_GetDesc(PyObject *obj)
00455 {
00456     return PyCapsule_GetContext(obj);
00457 }
00458 
00459 static NPY_INLINE int
00460 NpyCapsule_Check(PyObject *ptr)
00461 {
00462     return PyCapsule_CheckExact(ptr);
00463 }
00464 
00465 #else
00466 
00467 static NPY_INLINE PyObject *
00468 NpyCapsule_FromVoidPtr(void *ptr, void (*dtor)(void *))
00469 {
00470     return PyCObject_FromVoidPtr(ptr, dtor);
00471 }
00472 
00473 static NPY_INLINE PyObject *
00474 NpyCapsule_FromVoidPtrAndDesc(void *ptr, void* context,
00475         void (*dtor)(void *, void *))
00476 {
00477     return PyCObject_FromVoidPtrAndDesc(ptr, context, dtor);
00478 }
00479 
00480 static NPY_INLINE void *
00481 NpyCapsule_AsVoidPtr(PyObject *ptr)
00482 {
00483     return PyCObject_AsVoidPtr(ptr);
00484 }
00485 
00486 static NPY_INLINE void *
00487 NpyCapsule_GetDesc(PyObject *obj)
00488 {
00489     return PyCObject_GetDesc(obj);
00490 }
00491 
00492 static NPY_INLINE int
00493 NpyCapsule_Check(PyObject *ptr)
00494 {
00495     return PyCObject_Check(ptr);
00496 }
00497 
00498 #endif
00499 
00500 #ifdef __cplusplus
00501 }
00502 #endif
00503 
00504 #endif /* _NPY_3KCOMPAT_H_ */