From 886ac8eeb34c319481c1695aa69707ab6f6ee7e8 Mon Sep 17 00:00:00 2001 From: Andre Anjos <andre.dos.anjos@gmail.com> Date: Wed, 29 Jan 2014 14:28:27 +0100 Subject: [PATCH] Python3 C-API support --- doc/c_cpp_api.rst | 19 ++++++ setup.py | 1 + xbob/io/file.cpp | 54 +++++++++++++--- xbob/io/hdf5.cpp | 97 ++++++++++++++++++++++------- xbob/io/include/xbob.io/api.h | 113 +++++++++++++++++++--------------- xbob/io/main.cpp | 111 ++++++++++++++------------------- xbob/io/videoreader.cpp | 20 ++++-- xbob/io/videowriter.cpp | 21 +++++-- 8 files changed, 283 insertions(+), 153 deletions(-) diff --git a/doc/c_cpp_api.rst b/doc/c_cpp_api.rst index cf90f56..2333977 100644 --- a/doc/c_cpp_api.rst +++ b/doc/c_cpp_api.rst @@ -69,6 +69,25 @@ Generic Functions described above in case of success. +.. cpp:function:: int PyBobIo_FilenameConverter (PyObject* o, PyObject** b) + + This function is meant to be used with :c:func:`PyArg_ParseTupleAndKeywords` + family of functions in the Python C-API. It converts an arbitrary input + object into a ``PyStringObject`` (in Python2.x) and into a ``PyBytesObject`` + (in Python3.x). If the input object is of type ``PyUnicodeObject``, which is + the default in Python3.x, the unicode code is properly decoded using + :c:func:`PyUnicode_AsEncodedString` with ``encoding`` set to + ``Py_FileSystemDefaultEncoding`` and ``errors`` set to ``"strict"``. On + versions of Python >= 3.2, this is just an alias for + :c:func:`PyUnicode_FSConverter`, which does a similar job. + + Objects which are not ``PyUnicodeObject`` are coerced into a bytes/string + object using :c:func:`PyObject_Bytes` (on Python3.x) and + :c:func:`PyObject_Str` (on Python 2.x). + + Returns 0 if an error is detected, 1 on success. + + Bob File Support ---------------- diff --git a/setup.py b/setup.py index e20f5b3..0e4947d 100644 --- a/setup.py +++ b/setup.py @@ -33,6 +33,7 @@ setup( install_requires=[ 'setuptools', 'xbob.blitz', + 'pillow', ], namespace_packages=[ diff --git a/xbob/io/file.cpp b/xbob/io/file.cpp index d7c4fe4..e4b3cc6 100644 --- a/xbob/io/file.cpp +++ b/xbob/io/file.cpp @@ -12,6 +12,7 @@ #include <bob/io/utils.h> #include <numpy/arrayobject.h> #include <xbob.blitz/capi.h> +#include <xbob.blitz/cleanup.h> #include <stdexcept> #define FILETYPE_NAME "File" @@ -62,6 +63,25 @@ static void PyBobIoFile_Delete (PyBobIoFileObject* o) { } +int PyBobIo_FilenameConverter (PyObject* o, PyObject** b) { +#if PY_VERSION_HEX >= 0x03020000 + if (!PyUnicode_FSConverter(o, b)) return 0; +#else + if (PyUnicode_Check(o)) { + *b = PyUnicode_AsEncodedString(o, Py_FileSystemDefaultEncoding, "strict"); + } + else { +#if PY_VERSION_HEX >= 0x03000000 + *b = PyObject_Bytes(o); +#else + *b = PyObject_Str(o); +#endif + } + if (!b) return 0; +#endif + return 1; +} + /* The __init__(self) method */ static int PyBobIoFile_Init(PyBobIoFileObject* self, PyObject *args, PyObject* kwds) { @@ -69,23 +89,41 @@ static int PyBobIoFile_Init(PyBobIoFileObject* self, PyObject *args, PyObject* k static const char* const_kwlist[] = {"filename", "mode", "pretend_extension", 0}; static char** kwlist = const_cast<char**>(const_kwlist); - char* filename = 0; - char mode = 'r'; + PyObject* filename = 0; char* pretend_extension = 0; - if (!PyArg_ParseTupleAndKeywords(args, kwds, "s|cs", kwlist, &filename, - &mode, &pretend_extension)) return -1; + +#if PY_VERSION_HEX >= 0x03000000 +# define MODE_CHAR "C" + int mode = 'r'; +#else +# define MODE_CHAR "c" + char mode = 'r'; +#endif + + if (!PyArg_ParseTupleAndKeywords(args, kwds, "O&|" MODE_CHAR "s", kwlist, + &PyBobIo_FilenameConverter, &filename, &mode, &pretend_extension)) return -1; + +#undef MODE_CHAR + + auto filename_ = make_safe(filename); if (mode != 'r' && mode != 'w' && mode != 'a') { PyErr_Format(PyExc_ValueError, "file open mode string should have 1 element and be either 'r' (read), 'w' (write) or 'a' (append)"); return -1; } +#if PY_VERSION_HEX >= 0x03000000 + const char* c_filename = PyBytes_AS_STRING(filename); +#else + const char* c_filename = PyString_AS_STRING(filename); +#endif + try { if (pretend_extension) { - self->f = bob::io::open(filename, mode, pretend_extension); + self->f = bob::io::open(c_filename, mode, pretend_extension); } else { - self->f = bob::io::open(filename, mode); + self->f = bob::io::open(c_filename, mode); } } catch (std::exception& e) { @@ -93,7 +131,7 @@ static int PyBobIoFile_Init(PyBobIoFileObject* self, PyObject *args, PyObject* k return -1; } catch (...) { - PyErr_Format(PyExc_RuntimeError, "cannot open file `%s' with mode `%c': unknown exception caught", filename, mode); + PyErr_Format(PyExc_RuntimeError, "cannot open file `%s' with mode `%c': unknown exception caught", c_filename, mode); return -1; } @@ -107,7 +145,7 @@ static PyObject* PyBobIoFile_Repr(PyBobIoFileObject* self) { # else PyString_FromFormat # endif - ("%s(filename='%s', codec='%s')", Py_TYPE(self)->tp_name, + ("%s(filename='%s', codec='%s')", Py_TYPE(self)->tp_name, self->f->filename().c_str(), self->f->name().c_str()); } diff --git a/xbob/io/hdf5.cpp b/xbob/io/hdf5.cpp index 17cf508..68ff783 100644 --- a/xbob/io/hdf5.cpp +++ b/xbob/io/hdf5.cpp @@ -11,7 +11,9 @@ #include <boost/make_shared.hpp> #include <numpy/arrayobject.h> #include <xbob.blitz/cppapi.h> +#include <xbob.blitz/cleanup.h> #include <stdexcept> +#include <cstring> #include "bobskin.h" #define HDF5FILE_NAME "HDF5File" @@ -82,25 +84,44 @@ static int PyBobIoHDF5File_Init(PyBobIoHDF5FileObject* self, static const char* const_kwlist[] = {"filename", "mode", 0}; static char** kwlist = const_cast<char**>(const_kwlist); - const char* filename = 0; + PyObject* filename = 0; + +#if PY_VERSION_HEX >= 0x03000000 +# define MODE_CHAR "C" + int mode = 'r'; +#else +# define MODE_CHAR "c" char mode = 'r'; - if (!PyArg_ParseTupleAndKeywords(args, kwds, "s|c", kwlist, &filename, &mode)) +#endif + + if (!PyArg_ParseTupleAndKeywords(args, kwds, "O&|" MODE_CHAR, kwlist, + &PyBobIo_FilenameConverter, &filename, &mode)) return -1; +#undef MODE_CHAR + + auto filename_ = make_safe(filename); + if (mode != 'r' && mode != 'w' && mode != 'a' && mode != 'x') { PyErr_Format(PyExc_ValueError, "file open mode string should have 1 element and be either 'r' (read), 'w' (write), 'a' (append), 'x' (exclusive)"); return -1; } +#if PY_VERSION_HEX >= 0x03000000 + const char* c_filename = PyBytes_AS_STRING(filename); +#else + const char* c_filename = PyString_AS_STRING(filename); +#endif + try { - self->f.reset(new bob::io::HDF5File(filename, mode)); + self->f.reset(new bob::io::HDF5File(c_filename, mode)); } catch (std::exception& e) { PyErr_SetString(PyExc_RuntimeError, e.what()); return -1; } catch (...) { - PyErr_Format(PyExc_RuntimeError, "cannot open file `%s' with mode `%c': unknown exception caught", filename, mode); + PyErr_Format(PyExc_RuntimeError, "cannot open file `%s' with mode `%c': unknown exception caught", c_filename, mode); return -1; } @@ -846,18 +867,48 @@ value >= 0, or a list of arrays otherwise.\n\ * simple scalar. */ -static char* PyBobIo_GetString(PyObject* o) { +static void null_char_array_deleter(char*) {} +static void char_array_deleter(char* o) { delete[] o; } + +static std::shared_ptr<char> PyBobIo_GetString(PyObject* o) { + #if PY_VERSION_HEX < 0x03000000 - return PyString_AsString(o); + + return std::shared_ptr<char>(PyString_AsString(o), null_char_array_deleter); + #else - return PyBytes_AsString(o); + + if (PyBytes_Check(o)) { + //fast way out + return std::shared_ptr<char>(PyBytes_AsString(o), null_char_array_deleter); + } + + PyObject* bytes = 0; + + if (PyUnicode_Check(o)) { + //re-encode using utf-8 + bytes = PyUnicode_AsEncodedString(o, "utf-8", "strict"); + } + else { + //tries coercion + bytes = PyObject_Bytes(o); + } + auto bytes_ = make_safe(bytes); ///< protects acquired resource + + Py_ssize_t length = PyBytes_GET_SIZE(bytes)+1; + char* copy = new char[length]; + std::strncpy(copy, PyBytes_AsString(bytes), length); + + return std::shared_ptr<char>(copy, char_array_deleter); + #endif + } static int PyBobIoHDF5File_SetStringType(bob::io::HDF5Type& t, PyObject* o) { - const char* value = PyBobIo_GetString(o); + auto value = PyBobIo_GetString(o); if (!value) return -1; - t = bob::io::HDF5Type(value); + t = bob::io::HDF5Type(value.get()); return 0; } @@ -1074,9 +1125,9 @@ static PyObject* PyBobIoHDF5File_Replace(PyBobIoHDF5FileObject* self, PyObject* switch(type.type()) { case bob::io::s: { - const char* value = PyBobIo_GetString(data); + auto value = PyBobIo_GetString(data); if (!value) return 0; - self->f->replace<std::string>(path, pos, value); + self->f->replace<std::string>(path, pos, value.get()); Py_RETURN_NONE; } case bob::io::b: @@ -1208,9 +1259,9 @@ static int PyBobIoHDF5File_InnerAppend(PyBobIoHDF5FileObject* self, const char* switch(type.type()) { case bob::io::s: { - const char* value = PyBobIo_GetString(data); + auto value = PyBobIo_GetString(data); if (!value) return 0; - self->f->append<std::string>(path, value); + self->f->append<std::string>(path, value.get()); return 1; } case bob::io::b: @@ -1400,9 +1451,9 @@ static PyObject* PyBobIoHDF5File_Set(PyBobIoHDF5FileObject* self, PyObject* args switch(type.type()) { case bob::io::s: { - const char* value = PyBobIo_GetString(data); + auto value = PyBobIo_GetString(data); if (!value) return 0; - self->f->set<std::string>(path, value); + self->f->set<std::string>(path, value.get()); Py_RETURN_NONE; } break; @@ -1804,11 +1855,11 @@ template <> PyObject* PyBobIoHDF5File_WriteScalarAttribute<const char*> (PyBobIoHDF5FileObject* self, const char* path, const char* name, const bob::io::HDF5Type& type, PyObject* o) { - const char* value = PyBobIo_GetString(o); + auto value = PyBobIo_GetString(o); if (!value) return 0; try { - self->f->write_attribute(path, name, type, static_cast<const void*>(value)); + self->f->write_attribute(path, name, type, static_cast<const void*>(value.get())); } catch (std::exception& e) { PyErr_SetString(PyExc_RuntimeError, e.what()); @@ -1988,16 +2039,16 @@ static PyObject* PyBobIoHDF5File_SetAttributes(PyBobIoHDF5FileObject* self, PyOb bob::io::HDF5Type type; PyObject* converted = 0; - const char* name = PyBobIo_GetString(key); + auto name = PyBobIo_GetString(key); if (!name) return 0; int is_array = PyBobIoHDF5File_GetObjectType(value, type, &converted); if (is_array < 0) { ///< error condition, signal - PyErr_Format(PyExc_TypeError, "error setting attribute `%s' of resource `%s' at HDF5 file `%s': no support for storing objects of type `%s' on HDF5 files", name, path, self->f->filename().c_str(), Py_TYPE(value)->tp_name); + PyErr_Format(PyExc_TypeError, "error setting attribute `%s' of resource `%s' at HDF5 file `%s': no support for storing objects of type `%s' on HDF5 files", name.get(), path, self->f->filename().c_str(), Py_TYPE(value)->tp_name); return 0; } - PyObject* retval = PyBobIoHDF5File_WriteAttribute(self, path, name, type, value, is_array, converted); + PyObject* retval = PyBobIoHDF5File_WriteAttribute(self, path, name.get(), type, value, is_array, converted); if (!retval) return 0; Py_DECREF(retval); @@ -2106,14 +2157,14 @@ static PyObject* PyBobIoHDF5File_DelAttributes(PyBobIoHDF5FileObject* self, PyOb PyObject* iter = PyObject_GetIter(attrs); if (!iter) return 0; while (PyObject* item = PyIter_Next(iter)) { - const char* name = PyBobIo_GetString(item); + auto name = PyBobIo_GetString(item); Py_DECREF(item); if (!name) { Py_DECREF(iter); return 0; } try { - self->f->deleteAttribute(path, name); + self->f->deleteAttribute(path, name.get()); } catch (std::exception& e) { PyErr_SetString(PyExc_RuntimeError, e.what()); @@ -2121,7 +2172,7 @@ static PyObject* PyBobIoHDF5File_DelAttributes(PyBobIoHDF5FileObject* self, PyOb return 0; } catch (...) { - PyErr_Format(PyExc_RuntimeError, "cannot delete attribute `%s' at resource `%s' of HDF5 file `%s': unknown exception caught", name, path, self->f->filename().c_str()); + PyErr_Format(PyExc_RuntimeError, "cannot delete attribute `%s' at resource `%s' of HDF5 file `%s': unknown exception caught", name.get(), path, self->f->filename().c_str()); Py_DECREF(iter); return 0; } diff --git a/xbob/io/include/xbob.io/api.h b/xbob/io/include/xbob.io/api.h index a53cc22..b605378 100644 --- a/xbob/io/include/xbob.io/api.h +++ b/xbob/io/include/xbob.io/api.h @@ -78,6 +78,33 @@ typedef struct { #define PyBobIo_TypeInfoAsTuple_RET PyObject* #define PyBobIo_TypeInfoAsTuple_PROTO (const bob::core::array::typeinfo& ti) +#define PyBobIo_FilenameConverter_NUM 5 +#define PyBobIo_FilenameConverter_RET int +#define PyBobIo_FilenameConverter_PROTO (PyObject* o, PyObject** b) + +/***************** + * HDF5 bindings * + *****************/ + +typedef struct { + PyObject_HEAD + + /* Type-specific fields go here. */ + boost::shared_ptr<bob::io::HDF5File> f; + +} PyBobIoHDF5FileObject; + +#define PyBobIoHDF5File_Type_NUM 6 +#define PyBobIoHDF5File_Type_TYPE PyTypeObject + +#define PyBobIoHDF5File_Check_NUM 7 +#define PyBobIoHDF5File_Check_RET int +#define PyBobIoHDF5File_Check_PROTO (PyObject* o) + +#define PyBobIoHDF5File_Converter_NUM 8 +#define PyBobIoHDF5File_Converter_RET int +#define PyBobIoHDF5File_Converter_PROTO (PyObject* o, PyBobIoHDF5FileObject** a) + #if WITH_FFMPEG /****************** @@ -92,7 +119,7 @@ typedef struct { } PyBobIoVideoReaderObject; -#define PyBobIoVideoReader_Type_NUM 5 +#define PyBobIoVideoReader_Type_NUM 9 #define PyBobIoVideoReader_Type_TYPE PyTypeObject typedef struct { @@ -104,7 +131,7 @@ typedef struct { } PyBobIoVideoReaderIteratorObject; -#define PyBobIoVideoReaderIterator_Type_NUM 5 +#define PyBobIoVideoReaderIterator_Type_NUM 10 #define PyBobIoVideoReaderIterator_Type_TYPE PyTypeObject typedef struct { @@ -115,39 +142,16 @@ typedef struct { } PyBobIoVideoWriterObject; -#define PyBobIoVideoWriter_Type_NUM 6 +#define PyBobIoVideoWriter_Type_NUM 11 #define PyBobIoVideoWriter_Type_TYPE PyTypeObject #endif /* WITH_FFMPEG */ -/***************** - * HDF5 bindings * - *****************/ - -typedef struct { - PyObject_HEAD - - /* Type-specific fields go here. */ - boost::shared_ptr<bob::io::HDF5File> f; - -} PyBobIoHDF5FileObject; - -#define PyBobIoHDF5File_Type_NUM 7 -#define PyBobIoHDF5File_Type_TYPE PyTypeObject - -#define PyBobIoHDF5File_Check_NUM 8 -#define PyBobIoHDF5File_Check_RET int -#define PyBobIoHDF5File_Check_PROTO (PyObject* o) - -#define PyBobIoHDF5File_Converter_NUM 9 -#define PyBobIoHDF5File_Converter_RET int -#define PyBobIoHDF5File_Converter_PROTO (PyObject* o, PyBobIoHDF5FileObject** a) - /* Total number of C API pointers */ #if WITH_FFMPEG -# define PyXbobIo_API_pointers 10 +# define PyXbobIo_API_pointers 12 #else -# define PyXbobIo_API_pointers 11 +# define PyXbobIo_API_pointers 9 #endif /* WITH_FFMPEG */ #ifdef XBOB_IO_MODULE @@ -175,6 +179,18 @@ typedef struct { PyBobIo_TypeInfoAsTuple_RET PyBobIo_TypeInfoAsTuple PyBobIo_TypeInfoAsTuple_PROTO; + PyBobIo_FilenameConverter_RET PyBobIo_FilenameConverter PyBobIo_FilenameConverter_PROTO; + +/***************** + * HDF5 bindings * + *****************/ + + extern PyBobIoHDF5File_Type_TYPE PyBobIoHDF5File_Type; + + PyBobIoHDF5File_Check_RET PyBobIoHDF5File_Check PyBobIoHDF5File_Check_PROTO; + + PyBobIoHDF5File_Converter_RET PyBobIoHDF5File_Converter PyBobIoHDF5File_Converter_PROTO; + #if WITH_FFMPEG /****************** * Video bindings * @@ -187,16 +203,6 @@ typedef struct { extern PyBobIoVideoWriter_Type_TYPE PyBobIoVideoWriter_Type; #endif /* WITH_FFMPEG */ -/***************** - * HDF5 bindings * - *****************/ - - extern PyBobIoHDF5File_Type_TYPE PyBobIoHDF5File_Type; - - PyBobIoHDF5File_Check_RET PyBobIoHDF5File_Check PyBobIoHDF5File_Check_PROTO; - - PyBobIoHDF5File_Converter_RET PyBobIoHDF5File_Converter PyBobIoHDF5File_Converter_PROTO; - #else /* This section is used in modules that use `xbob.io's' C-API */ @@ -244,6 +250,18 @@ typedef struct { # define PyBobIo_TypeInfoAsTuple (*(PyBobIo_TypeInfoAsTuple_RET (*)PyBobIo_TypeInfoAsTuple_PROTO) PyXbobIo_API[PyBobIo_TypeInfoAsTuple_NUM]) +# define PyBobIo_FilenameConverter (*(PyBobIo_FilenameConverter_RET (*)PyBobIo_FilenameConverter_PROTO) PyXbobIo_API[PyBobIo_FilenameConverter_NUM]) + + /***************** + * HDF5 bindings * + *****************/ + +# define PyBobIoHDF5File_Type (*(PyBobIoHDF5File_Type_TYPE *)PyXbobIo_API[PyBobIoHDF5File_Type_NUM]) + +# define PyBobIoHDF5File_Check (*(PyBobIoHDF5File_Check_RET (*)PyBobIoHDF5File_Check_PROTO) PyXbobIo_API[PyBobIoHDF5File_Check_NUM]) + +# define PyBobIoHDF5File_Converter (*(PyBobIoHDF5File_Converter_RET (*)PyBobIoHDF5File_Converter_PROTO) PyXbobIo_API[PyBobIoHDF5File_Converter_NUM]) + #if WITH_FFMPEG /****************** * Video bindings * @@ -256,18 +274,10 @@ typedef struct { # define PyBobIoVideoWriterIterator_Type (*(PyBobIoVideoWriterIterator_Type_TYPE *)PyXbobIo_API[PyBobIoVideoWriterIterator_Type_NUM]) #endif /* WITH_FFMPEG */ - /***************** - * HDF5 bindings * - *****************/ - -# define PyBobIoHDF5File_Type (*(PyBobIoHDF5File_Type_TYPE *)PyXbobIo_API[PyBobIoHDF5File_Type_NUM]) - -# define PyBobIoHDF5File_Check (*(PyBobIoHDF5File_Check_RET (*)PyBobIoHDF5File_Check_PROTO) PyXbobIo_API[PyBobIoHDF5File_Check_NUM]) - -# define PyBobIoHDF5File_Converter (*(PyBobIoHDF5File_Converter_RET (*)PyBobIoHDF5File_Converter_PROTO) PyXbobIo_API[PyBobIoHDF5File_Converter_NUM]) - # if !defined(NO_IMPORT_ARRAY) +#include <xbob.blitz/capi.h> + /** * Returns -1 on error, 0 on success. */ @@ -320,6 +330,13 @@ typedef struct { return -1; } + /* Imports the xbob.blitz C-API */ + if (import_xbob_blitz() < 0) { + PyErr_Print(); + PyErr_SetString(PyExc_ImportError, "xbob.blitz failed to import"); + return -1; + } + /* If you get to this point, all is good */ return 0; diff --git a/xbob/io/main.cpp b/xbob/io/main.cpp index c30def1..36a54b1 100644 --- a/xbob/io/main.cpp +++ b/xbob/io/main.cpp @@ -12,6 +12,7 @@ #undef NO_IMPORT_ARRAY #endif #include <xbob.blitz/capi.h> +#include <xbob.blitz/cleanup.h> static PyMethodDef module_methods[] = { {0} /* Sentinel */ @@ -32,86 +33,61 @@ static PyModuleDef module_definition = { }; #endif -PyMODINIT_FUNC XBOB_EXT_ENTRY_NAME (void) { +static PyObject* create_module (void) { PyBobIoFile_Type.tp_new = PyType_GenericNew; - if (PyType_Ready(&PyBobIoFile_Type) < 0) return -# if PY_VERSION_HEX >= 0x03000000 - 0 -# endif - ; + if (PyType_Ready(&PyBobIoFile_Type) < 0) return 0; PyBobIoFileIterator_Type.tp_new = PyType_GenericNew; - if (PyType_Ready(&PyBobIoFileIterator_Type) < 0) return -# if PY_VERSION_HEX >= 0x03000000 - 0 -# endif - ; + if (PyType_Ready(&PyBobIoFileIterator_Type) < 0) return 0; + + PyBobIoHDF5File_Type.tp_new = PyType_GenericNew; + if (PyType_Ready(&PyBobIoHDF5File_Type) < 0) return 0; #if WITH_FFMPEG PyBobIoVideoReader_Type.tp_new = PyType_GenericNew; - if (PyType_Ready(&PyBobIoVideoReader_Type) < 0) return -# if PY_VERSION_HEX >= 0x03000000 - 0 -# endif - ; + if (PyType_Ready(&PyBobIoVideoReader_Type) < 0) return 0; PyBobIoVideoReaderIterator_Type.tp_new = PyType_GenericNew; - if (PyType_Ready(&PyBobIoVideoReaderIterator_Type) < 0) return -# if PY_VERSION_HEX >= 0x03000000 - 0 -# endif - ; + if (PyType_Ready(&PyBobIoVideoReaderIterator_Type) < 0) return 0; PyBobIoVideoWriter_Type.tp_new = PyType_GenericNew; - if (PyType_Ready(&PyBobIoVideoWriter_Type) < 0) return -# if PY_VERSION_HEX >= 0x03000000 - 0 -# endif - ; + if (PyType_Ready(&PyBobIoVideoWriter_Type) < 0) return 0; #endif /* WITH_FFMPEG */ - PyBobIoHDF5File_Type.tp_new = PyType_GenericNew; - if (PyType_Ready(&PyBobIoHDF5File_Type) < 0) return -# if PY_VERSION_HEX >= 0x03000000 - 0 -# endif - ; - # if PY_VERSION_HEX >= 0x03000000 PyObject* m = PyModule_Create(&module_definition); - if (!m) return 0; # else - PyObject* m = Py_InitModule3(XBOB_EXT_MODULE_NAME, - module_methods, module_docstr); - if (!m) return; + PyObject* m = Py_InitModule3(XBOB_EXT_MODULE_NAME, module_methods, module_docstr); # endif + if (!m) return 0; + auto m_ = make_safe(m); /* register some constants */ - PyModule_AddIntConstant(m, "__api_version__", XBOB_IO_API_VERSION); - PyModule_AddStringConstant(m, "__version__", XBOB_EXT_MODULE_VERSION); + if (PyModule_AddIntConstant(m, "__api_version__", XBOB_IO_API_VERSION) < 0) return 0; + if (PyModule_AddStringConstant(m, "__version__", XBOB_EXT_MODULE_VERSION) < 0) return 0; /* register the types to python */ Py_INCREF(&PyBobIoFile_Type); - PyModule_AddObject(m, "File", (PyObject *)&PyBobIoFile_Type); + if (PyModule_AddObject(m, "File", (PyObject *)&PyBobIoFile_Type) < 0) return 0; Py_INCREF(&PyBobIoFileIterator_Type); - PyModule_AddObject(m, "File.iter", (PyObject *)&PyBobIoFileIterator_Type); + if (PyModule_AddObject(m, "File.iter", (PyObject *)&PyBobIoFileIterator_Type) < 0) return 0; + + Py_INCREF(&PyBobIoHDF5File_Type); + if (PyModule_AddObject(m, "HDF5File", (PyObject *)&PyBobIoHDF5File_Type) < 0) return 0; #if WITH_FFMPEG Py_INCREF(&PyBobIoVideoReader_Type); - PyModule_AddObject(m, "VideoReader", (PyObject *)&PyBobIoVideoReader_Type); + if (PyModule_AddObject(m, "VideoReader", (PyObject *)&PyBobIoVideoReader_Type) < 0) return 0; Py_INCREF(&PyBobIoVideoReaderIterator_Type); - PyModule_AddObject(m, "VideoReader.iter", (PyObject *)&PyBobIoVideoReaderIterator_Type); + if (PyModule_AddObject(m, "VideoReader.iter", (PyObject *)&PyBobIoVideoReaderIterator_Type) < 0) return 0; Py_INCREF(&PyBobIoVideoWriter_Type); - PyModule_AddObject(m, "VideoWriter", (PyObject *)&PyBobIoVideoWriter_Type); + if (PyModule_AddObject(m, "VideoWriter", (PyObject *)&PyBobIoVideoWriter_Type) < 0) return 0; #endif /* WITH_FFMPEG */ - Py_INCREF(&PyBobIoHDF5File_Type); - PyModule_AddObject(m, "HDF5File", (PyObject *)&PyBobIoHDF5File_Type); - static void* PyXbobIo_API[PyXbobIo_API_pointers]; /* exhaustive list of C APIs */ @@ -138,6 +114,18 @@ PyMODINIT_FUNC XBOB_EXT_ENTRY_NAME (void) { PyXbobIo_API[PyBobIo_TypeInfoAsTuple_NUM] = (void *)PyBobIo_TypeInfoAsTuple; + PyXbobIo_API[PyBobIo_FilenameConverter_NUM] = (void *)PyBobIo_FilenameConverter; + + /***************** + * HDF5 bindings * + *****************/ + + PyXbobIo_API[PyBobIoHDF5File_Type_NUM] = (void *)&PyBobIoHDF5File_Type; + + PyXbobIo_API[PyBobIoHDF5File_Check_NUM] = (void *)&PyBobIoHDF5File_Check; + + PyXbobIo_API[PyBobIoHDF5File_Converter_NUM] = (void *)&PyBobIoHDF5File_Converter; + #if WITH_FFMPEG /****************** * Video bindings * @@ -150,16 +138,6 @@ PyMODINIT_FUNC XBOB_EXT_ENTRY_NAME (void) { PyXbobIo_API[PyBobIoVideoWriter_Type_NUM] = (void *)&PyBobIoVideoWriter_Type; #endif /* WITH_FFMPEG */ - /***************** - * HDF5 bindings * - *****************/ - - PyXbobIo_API[PyBobIoHDF5File_Type_NUM] = (void *)&PyBobIoHDF5File_Type; - - PyXbobIo_API[PyBobIoHDF5File_Check_NUM] = (void *)&PyBobIoHDF5File_Check; - - PyXbobIo_API[PyBobIoHDF5File_Converter_NUM] = (void *)&PyBobIoHDF5File_Converter; - #if PY_VERSION_HEX >= 0x02070000 /* defines the PyCapsule */ @@ -173,16 +151,21 @@ PyMODINIT_FUNC XBOB_EXT_ENTRY_NAME (void) { #endif - if (c_api_object) PyModule_AddObject(m, "_C_API", c_api_object); + if (!c_api_object) return 0; - /* imports the NumPy C-API */ - import_array(); + if (PyModule_AddObject(m, "_C_API", c_api_object) < 0) return 0; - /* imports xbob.blitz C-API */ - import_xbob_blitz(); + /* imports xbob.blitz C-API + dependencies */ + if (import_xbob_blitz() < 0) return 0; -# if PY_VERSION_HEX >= 0x03000000 + Py_INCREF(m); return m; -# endif } + +PyMODINIT_FUNC XBOB_EXT_ENTRY_NAME (void) { +# if PY_VERSION_HEX >= 0x03000000 + return +# endif + create_module(); +} diff --git a/xbob/io/videoreader.cpp b/xbob/io/videoreader.cpp index 439bd79..f5f499c 100644 --- a/xbob/io/videoreader.cpp +++ b/xbob/io/videoreader.cpp @@ -13,6 +13,7 @@ #include <boost/make_shared.hpp> #include <numpy/arrayobject.h> #include <xbob.blitz/capi.h> +#include <xbob.blitz/cleanup.h> #include <stdexcept> #define VIDEOREADER_NAME "VideoReader" @@ -78,23 +79,32 @@ static int PyBobIoVideoReader_Init(PyBobIoVideoReaderObject* self, static const char* const_kwlist[] = {"filename", "check", 0}; static char** kwlist = const_cast<char**>(const_kwlist); - char* filename = 0; + PyObject* filename = 0; + PyObject* pycheck = 0; - if (!PyArg_ParseTupleAndKeywords(args, kwds, "s|O", kwlist, - &filename, &pycheck)) return -1; + if (!PyArg_ParseTupleAndKeywords(args, kwds, "O&|O", kwlist, + &PyBobIo_FilenameConverter, &filename, &pycheck)) return -1; + + auto filename_ = make_safe(filename); bool check = false; if (pycheck && PyObject_IsTrue(pycheck)) check = true; +#if PY_VERSION_HEX >= 0x03000000 + const char* c_filename = PyBytes_AS_STRING(filename); +#else + const char* c_filename = PyString_AS_STRING(filename); +#endif + try { - self->v = boost::make_shared<bob::io::VideoReader>(filename, check); + self->v = boost::make_shared<bob::io::VideoReader>(c_filename, check); } catch (std::exception& e) { PyErr_SetString(PyExc_RuntimeError, e.what()); return -1; } catch (...) { - PyErr_Format(PyExc_RuntimeError, "cannot open video file `%s' for reading: unknown exception caught", filename); + PyErr_Format(PyExc_RuntimeError, "cannot open video file `%s' for reading: unknown exception caught", c_filename); return -1; } diff --git a/xbob/io/videowriter.cpp b/xbob/io/videowriter.cpp index 5d5c5f3..c8ebce2 100644 --- a/xbob/io/videowriter.cpp +++ b/xbob/io/videowriter.cpp @@ -13,6 +13,7 @@ #include <boost/make_shared.hpp> #include <numpy/arrayobject.h> #include <xbob.blitz/cppapi.h> +#include <xbob.blitz/cleanup.h> #include <stdexcept> #define VIDEOWRITER_NAME "VideoWriter" @@ -100,7 +101,8 @@ static int PyBobIoVideoWriter_Init(PyBobIoVideoWriterObject* self, 0}; static char** kwlist = const_cast<char**>(const_kwlist); - char* filename = 0; + PyObject* filename = 0; + Py_ssize_t height = 0; Py_ssize_t width = 0; @@ -111,10 +113,13 @@ static int PyBobIoVideoWriter_Init(PyBobIoVideoWriterObject* self, char* format = 0; PyObject* pycheck = 0; - if (!PyArg_ParseTupleAndKeywords(args, kwds, "snn|ddnssO", kwlist, - &filename, &height, &width, &framerate, &bitrate, &gop, &codec, + if (!PyArg_ParseTupleAndKeywords(args, kwds, "O&nn|ddnssO", kwlist, + &PyBobIo_FilenameConverter, &filename, + &height, &width, &framerate, &bitrate, &gop, &codec, &format, &pycheck)) return -1; + auto filename_ = make_safe(filename); + if (pycheck && PyObject_IsTrue(pycheck)) { PyErr_SetString(PyExc_TypeError, "argument to `check' must be a boolean"); return -1; @@ -123,8 +128,14 @@ static int PyBobIoVideoWriter_Init(PyBobIoVideoWriterObject* self, bool check = false; if (pycheck && (pycheck == Py_True)) check = true; +#if PY_VERSION_HEX >= 0x03000000 + const char* c_filename = PyBytes_AS_STRING(filename); +#else + const char* c_filename = PyString_AS_STRING(filename); +#endif + try { - self->v = boost::make_shared<bob::io::VideoWriter>(filename, height, width, + self->v = boost::make_shared<bob::io::VideoWriter>(c_filename, height, width, framerate, bitrate, gop, codec, format, check); } catch (std::exception& e) { @@ -132,7 +143,7 @@ static int PyBobIoVideoWriter_Init(PyBobIoVideoWriterObject* self, return -1; } catch (...) { - PyErr_Format(PyExc_RuntimeError, "cannot open video file `%s' for writing: unknown exception caught", filename); + PyErr_Format(PyExc_RuntimeError, "cannot open video file `%s' for writing: unknown exception caught", c_filename); return -1; } -- GitLab