Commit d3eb4043 authored by David Gobbi's avatar David Gobbi

Python API compatibility for py3k.

This is a large change that adds conditional compilation to support
both python 2 and python 3.  The header vtkPythonCompatibility.h
does a lot of the necessary work:
1) PyInt is redefined to PyLong for py3k
2) PyString is redefied to PyUnicode for py3k
3) PyBytes is redefined to PyString for python 2
parent c96458b9
......@@ -35,7 +35,18 @@ void vtkPythonAlgorithm::PrintSelf(ostream& os, vtkIndent indent)
os << indent << "Object: " << Object << std::endl;
if (str)
{
os << indent << "Object (string): " << PyString_AsString(str) << std::endl;
os << indent << "Object (string): ";
#ifndef VTK_PY3K
os << PyString_AsString(str);
#else
PyObject *bytes = PyUnicode_EncodeLocale(str, VTK_PYUNICODE_ENC);
if (bytes)
{
os << PyBytes_AsString(bytes);
Py_DECREF(bytes);
}
#endif
os << std::endl;
}
}
......@@ -131,7 +142,16 @@ static std::string GetPythonErrorString()
for (Py_ssize_t i = 0; i < sz; ++i)
{
PyObject* str = lst[i];
#ifndef VTK_PY3K
exc_string += PyString_AsString(str);
#else
PyObject *bytes = PyUnicode_EncodeLocale(str, VTK_PYUNICODE_ENC);
if (bytes)
{
exc_string += PyBytes_AsString(bytes);
Py_DECREF(bytes);
}
#endif
}
}
else
......@@ -139,7 +159,17 @@ static std::string GetPythonErrorString()
vtkSmartPyObject pyexc_string(PyObject_Str(sValue));
if (pyexc_string)
{
#ifndef VTK_PY3K
exc_string = PyString_AsString(pyexc_string);
#else
PyObject *bytes = PyUnicode_EncodeLocale(
pyexc_string, VTK_PYUNICODE_ENC);
if (bytes)
{
exc_string = PyBytes_AsString(bytes);
Py_DECREF(bytes);
}
#endif
}
else
{
......
......@@ -73,14 +73,18 @@ they are system headers. Do NOT add any #undef lines here. */
#endif
#if defined(_MSC_VER) && _MSC_VER >= 1800
#if VTK_PYTHON_VERSION_HEX < 0x03040000
#define HAVE_ROUND
#endif
#endif
#include <Python.h>
#if defined(_MSC_VER) && _MSC_VER >= 1800
#if VTK_PYTHON_VERSION_HEX < 0x03040000
#undef HAVE_ROUND
#endif
#endif
#if defined(_MSC_VER)
# pragma warning (pop)
......
......@@ -16,6 +16,7 @@
/* Minimal main program -- everything is loaded from the library */
#include "vtkPython.h"
#include "vtkPythonCompatibility.h"
#ifdef VTK_COMPILED_USING_MPI
# include <mpi.h>
......@@ -81,9 +82,20 @@ static void AtExitCallback()
#endif // VTK_COMPILED_USING_MPI
extern "C" {
extern DL_IMPORT(int) Py_Main(int, char **);
#ifdef VTK_PY3K
PyAPI_FUNC(int) Py_Main(int, wchar_t **);
#else
PyAPI_FUNC(int) Py_Main(int, char **);
#endif
}
#if defined(VTK_PY3K) && defined(__APPLE__)
extern "C" {
extern wchar_t*
_Py_DecodeUTF8_surrogateescape(const char *s, Py_ssize_t size);
}
#endif
static void vtkPythonAppInitEnableMSVCDebugHook();
static void vtkPythonAppInitPrependPath(const char* self_dir);
static void RemoveArgumentFromArgv(int &argc, char **&argv, int at);
......@@ -103,7 +115,6 @@ static void RemoveArgumentFromArgv(int &argc, char **&argv, int at);
#define VTK_PYTHON_TO_STRING1(x) #x
#define VTK_PYTHON_VERSION VTK_PYTHON_TO_STRING(PY_MAJOR_VERSION.PY_MINOR_VERSION)
int main(int argc, char **argv)
{
vtkPythonAppInitEnableMSVCDebugHook();
......@@ -147,9 +158,24 @@ int main(int argc, char **argv)
// Set the program name, so that we can ask python to provide us
// full path. We need to collapse the path name to aid relative
// path computation for the VTK python module installation.
static char argv0[VTK_PYTHON_MAXPATH];
std::string av0 = vtksys::SystemTools::CollapseFullPath(argv[0]);
#ifdef VTK_PY3K
wchar_t *argv0;
#ifdef __APPLE__
argv0 = _Py_DecodeUTF8_surrogateescape(av0.data(), av0.length());
#else
argv0 = _Py_char2wchar(av0.c_str(), NULL);
#endif
if (argv0 == 0)
{
fprintf(stderr, "Fatal vtkpython error: "
"unable to decode the program name\n");
return 1;
}
#else /* VTK < PY3K */
static char argv0[VTK_PYTHON_MAXPATH];
strcpy(argv0, av0.c_str());
#endif
Py_SetProgramName(argv0);
// This function is generated, and will register any static Python modules for VTK
......@@ -169,17 +195,62 @@ int main(int argc, char **argv)
// sys.executable variable contains the full path to the interpreter
// executable.
char tmpExe[] = "executable";
PyObject* executable = PySys_GetObject(tmpExe);
if(const char* exe_str = PyString_AsString(executable))
PyObject *executable = PySys_GetObject(tmpExe);
#ifdef VTK_PY3K
executable = PyUnicode_EncodeFSDefault(executable);
#endif
const char *exe_str = PyBytes_AsString(executable);
if (exe_str)
{
// Use the executable location to try to set sys.path to include
// the VTK python modules.
std::string self_dir = vtksys::SystemTools::GetFilenamePath(exe_str);
vtkPythonAppInitPrependPath(self_dir.c_str());
}
#ifdef VTK_PY3K
Py_DECREF(executable);
#endif
// Ok, all done, now enter python main.
#ifdef VTK_PY3K
// Need two copies of args, because programs might modify the first
wchar_t **argvWide = new wchar_t *[argc];
wchar_t **argvWide2 = new wchar_t *[argc];
for (int i = 0; i < argc; i++)
{
#ifdef __APPLE__
argvWide[i] = _Py_DecodeUTF8_surrogateescape(argv[i], strlen(argv[i]));
#else
argvWide[i] = _Py_char2wchar(argv[i], NULL);
#endif
argvWide2[i] = argvWide[i];
if (argvWide[i] == 0)
{
fprintf(stderr, "Fatal vtkpython error: "
"unable to decode the command line argument #%i\n",
i + 1);
for (int k = 0; k < i; k++)
{
PyMem_Free(argvWide2[i]);
}
PyMem_Free(argv0);
delete [] argvWide;
delete [] argvWide2;
return 1;
}
}
int res = Py_Main(argc, argvWide);
PyMem_Free(argv0);
for (int i = 0; i < argc; i++)
{
PyMem_Free(argvWide2[i]);
}
delete [] argvWide;
delete [] argvWide2;
return res;
#else
return Py_Main(argc, argv);
#endif
}
// For a DEBUG build on MSVC, add a hook to prevent error dialogs when
......
......@@ -26,6 +26,12 @@
#pragma GCC diagnostic ignored "-Wstrict-aliasing"
#endif
// Required for Python 2.5 through Python 2.7
#ifndef PyDescr_TYPE
#define PyDescr_TYPE(x) (((PyDescrObject *)(x))->d_type)
#define PyDescr_NAME(x) (((PyDescrObject *)(x))->d_name)
#endif
//--------------------------------------------------------------------
// C API
......@@ -37,11 +43,11 @@ PyObject *PyVTKMethodDescriptor_New(PyTypeObject *pytype, PyMethodDef *meth)
if (descr)
{
Py_XINCREF(pytype);
descr->d_type = pytype;
descr->d_name = PyString_InternFromString(meth->ml_name);
PyDescr_TYPE(descr) = pytype;
PyDescr_NAME(descr) = PyString_InternFromString(meth->ml_name);
descr->d_method = meth;
if (!descr->d_name)
if (!PyDescr_NAME(descr))
{
Py_DECREF(descr);
descr = 0;
......@@ -58,23 +64,28 @@ static void PyVTKMethodDescriptor_Delete(PyObject *ob)
{
PyMethodDescrObject *descr = (PyMethodDescrObject *)ob;
PyObject_GC_UnTrack(descr);
Py_XDECREF(descr->d_type);
Py_XDECREF(descr->d_name);
Py_XDECREF(PyDescr_TYPE(descr));
Py_XDECREF(PyDescr_NAME(descr));
PyObject_GC_Del(descr);
}
static PyObject *PyVTKMethodDescriptor_Repr(PyObject *ob)
{
PyMethodDescrObject *descr = (PyMethodDescrObject *)ob;
#ifdef VTK_PY3K
return PyUnicode_FromFormat("<method \'%U\' of \'%s\' objects>",
PyDescr_NAME(descr), PyDescr_TYPE(descr)->tp_name);
#else
return PyString_FromFormat("<method \'%s\' of \'%s\' objects>",
PyString_AS_STRING(descr->d_name), descr->d_type->tp_name);
#endif
}
static int PyVTKMethodDescriptor_Traverse(
PyObject *ob, visitproc visit, void *arg)
{
PyMethodDescrObject *descr = (PyMethodDescrObject *)ob;
Py_VISIT(descr->d_type);
Py_VISIT(PyDescr_TYPE(descr));
return 0;
}
......@@ -84,7 +95,7 @@ static PyObject *PyVTKMethodDescriptor_Call(
PyMethodDescrObject *descr = (PyMethodDescrObject *)ob;
PyObject *result = 0;
PyObject *func = PyCFunction_New(
descr->d_method, (PyObject *)descr->d_type);
descr->d_method, (PyObject *)PyDescr_TYPE(descr));
if (func)
{
......@@ -107,17 +118,25 @@ static PyObject *PyVTKMethodDescriptor_Get(
return self;
}
if (PyObject_TypeCheck(obj, descr->d_type))
if (PyObject_TypeCheck(obj, PyDescr_TYPE(descr)))
{
// Bind the method to the object
return PyCFunction_New(descr->d_method, obj);
}
#ifdef VTK_PY3K
PyErr_Format(
PyExc_TypeError,
"descriptor '%U' for '%s' objects doesn't apply to '%s' object",
PyDescr_NAME(descr), PyDescr_TYPE(descr)->tp_name,
Py_TYPE(obj)->tp_name);
#else
PyErr_Format(
PyExc_TypeError,
"descriptor '%s' for '%s' objects doesn't apply to '%s' object",
PyString_AS_STRING(descr->d_name), descr->d_type->tp_name,
PyString_AS_STRING(PyDescr_NAME(descr)), PyDescr_TYPE(descr)->tp_name,
Py_TYPE(obj)->tp_name);
#endif
return NULL;
}
......
......@@ -52,11 +52,13 @@ static PyObject *PyVTKMutableObject_CompatibleObject(PyObject *opn)
if (PyFloat_Check(opn) ||
PyLong_Check(opn) ||
#ifndef VTK_PY3K
PyInt_Check(opn) ||
#endif
#ifdef Py_USING_UNICODE
PyUnicode_Check(opn) ||
#endif
PyString_Check(opn))
PyBytes_Check(opn))
{
Py_INCREF(opn);
}
......@@ -68,7 +70,11 @@ static PyObject *PyVTKMutableObject_CompatibleObject(PyObject *opn)
else if (nb && nb->nb_index)
{
opn = nb->nb_index(opn);
if (opn == 0 || (!PyLong_Check(opn) && !PyInt_Check(opn)))
if (opn == 0 || (!PyLong_Check(opn)
#ifndef VTK_PY3K
&& !PyInt_Check(opn)
#endif
))
{
PyErr_SetString(PyExc_TypeError,
"nb_index should return integer object");
......@@ -119,12 +125,16 @@ int PyVTKMutableObject_SetValue(PyObject *self, PyObject *val)
PyObject **op = &((PyVTKMutableObject *)self)->value;
if (PyFloat_Check(val) ||
PyLong_Check(val) ||
PyInt_Check(val))
#ifndef VTK_PY3K
PyInt_Check(val) ||
#endif
PyLong_Check(val))
{
if (PyFloat_Check(*op) ||
PyLong_Check(*op) ||
PyInt_Check(*op))
#ifndef VTK_PY3K
PyInt_Check(*op) ||
#endif
PyLong_Check(*op))
{
Py_DECREF(*op);
*op = val;
......@@ -137,13 +147,13 @@ int PyVTKMutableObject_SetValue(PyObject *self, PyObject *val)
#ifdef Py_USING_UNICODE
PyUnicode_Check(val) ||
#endif
PyString_Check(val))
PyBytes_Check(val))
{
if (
#ifdef Py_USING_UNICODE
PyUnicode_Check(*op) ||
#endif
PyString_Check(*op))
PyBytes_Check(*op))
{
Py_DECREF(*op);
*op = val;
......@@ -202,9 +212,65 @@ static PyObject *PyVTKMutableObject_Set(PyObject *self, PyObject *args)
return NULL;
}
#ifdef VTK_PY3K
static PyObject *PyVTKMutableObject_Trunc(PyObject *self, PyObject *args)
{
PyObject *opn;
if (PyArg_ParseTuple(args, ":__trunc__", &opn))
{
PyObject *attr = PyUnicode_InternFromString("__trunc__");
PyObject *ob = PyVTKMutableObject_GetValue(self);
PyObject *meth = _PyType_Lookup(Py_TYPE(ob), attr);
if (meth == NULL)
{
PyErr_Format(PyExc_TypeError,
"type %.100s doesn't define __trunc__ method",
Py_TYPE(ob)->tp_name);
return NULL;
}
return PyObject_CallFunction(meth, (char *)"O", ob);
}
return NULL;
}
static PyObject *PyVTKMutableObject_Round(PyObject *self, PyObject *args)
{
PyObject *opn;
if (PyArg_ParseTuple(args, "|O:__round__", &opn))
{
PyObject *attr = PyUnicode_InternFromString("__round__");
PyObject *ob = PyVTKMutableObject_GetValue(self);
PyObject *meth = _PyType_Lookup(Py_TYPE(ob), attr);
if (meth == NULL)
{
PyErr_Format(PyExc_TypeError,
"type %.100s doesn't define __round__ method",
Py_TYPE(ob)->tp_name);
return NULL;
}
if (opn)
{
return PyObject_CallFunction(meth, (char *)"OO", ob, opn);
}
return PyObject_CallFunction(meth, (char *)"O", ob);
}
return NULL;
}
#endif
static PyMethodDef PyVTKMutableObject_Methods[] = {
{"get", PyVTKMutableObject_Get, 1, "Get the stored value."},
{"set", PyVTKMutableObject_Set, 1, "Set the stored value."},
{"get", PyVTKMutableObject_Get, METH_VARARGS, "Get the stored value."},
{"set", PyVTKMutableObject_Set, METH_VARARGS, "Set the stored value."},
#ifdef VTK_PY3K
{"__trunc__", PyVTKMutableObject_Trunc, METH_VARARGS,
"Returns the Integral closest to x between 0 and x."},
{"__round__", PyVTKMutableObject_Round, METH_VARARGS,
"Returns the Integral closest to x, rounding half toward even.\n"},
#endif
{ NULL, NULL, 0, NULL }
};
......@@ -366,6 +432,7 @@ static int PyVTKMutableObject_NonZero(PyObject *ob)
return PyObject_IsTrue(ob);
}
#ifndef VTK_PY3K
static int PyVTKMutableObject_Coerce(PyObject **ob1, PyObject **ob2)
{
*ob1 = ((PyVTKMutableObject *)*ob1)->value;
......@@ -411,12 +478,15 @@ static PyObject *PyVTKMutableObject_Oct(PyObject *ob)
return NULL;
#endif
}
#endif
REFOBJECT_BINARYFUNC(Number,Add)
REFOBJECT_BINARYFUNC(Number,Subtract)
REFOBJECT_BINARYFUNC(Number,Multiply)
#ifndef VTK_PY3K
REFOBJECT_BINARYFUNC(Number,Divide)
#endif
REFOBJECT_BINARYFUNC(Number,Remainder)
REFOBJECT_BINARYFUNC(Number,Divmod)
REFOBJECT_TERNARYFUNC(Number,Power)
......@@ -431,16 +501,18 @@ REFOBJECT_BINARYFUNC(Number,And)
REFOBJECT_BINARYFUNC(Number,Or)
REFOBJECT_BINARYFUNC(Number,Xor)
// Coerce
#ifndef VTK_PY3K
REFOBJECT_UNARYFUNC(Number,Int)
#endif
REFOBJECT_UNARYFUNC(Number,Long)
REFOBJECT_UNARYFUNC(Number,Float)
// Hex
// Oct
REFOBJECT_INPLACEFUNC(Number,Add)
REFOBJECT_INPLACEFUNC(Number,Subtract)
REFOBJECT_INPLACEFUNC(Number,Multiply)
#ifndef VTK_PY3K
REFOBJECT_INPLACEFUNC(Number,Divide)
#endif
REFOBJECT_INPLACEFUNC(Number,Remainder)
REFOBJECT_INPLACETFUNC(Number,Power)
REFOBJECT_INPLACEFUNC(Number,Lshift)
......@@ -461,7 +533,9 @@ static PyNumberMethods PyVTKMutableObject_AsNumber = {
PyVTKMutableObject_Add, // nb_add
PyVTKMutableObject_Subtract, // nb_subtract
PyVTKMutableObject_Multiply, // nb_multiply
#ifndef VTK_PY3K
PyVTKMutableObject_Divide, // nb_divide
#endif
PyVTKMutableObject_Remainder, // nb_remainder
PyVTKMutableObject_Divmod, // nb_divmod
PyVTKMutableObject_Power, // nb_power
......@@ -475,16 +549,25 @@ static PyNumberMethods PyVTKMutableObject_AsNumber = {
PyVTKMutableObject_And, // nb_and
PyVTKMutableObject_Xor, // nb_xor
PyVTKMutableObject_Or, // nb_or
#ifndef VTK_PY3K
PyVTKMutableObject_Coerce, // nb_coerce
PyVTKMutableObject_Int, // nb_int
PyVTKMutableObject_Long, // nb_long
#else
PyVTKMutableObject_Long, // nb_int
NULL, // nb_reserved
#endif
PyVTKMutableObject_Float, // nb_float
#ifndef VTK_PY3K
PyVTKMutableObject_Oct, // nb_oct
PyVTKMutableObject_Hex, // nb_hex
#endif
PyVTKMutableObject_InPlaceAdd, // nb_inplace_add
PyVTKMutableObject_InPlaceSubtract, // nb_inplace_subtract
PyVTKMutableObject_InPlaceMultiply, // nb_inplace_multiply
#ifndef VTK_PY3K
PyVTKMutableObject_InPlaceDivide, // nb_inplace_divide
#endif
PyVTKMutableObject_InPlaceRemainder, // nb_inplace_remainder
PyVTKMutableObject_InPlacePower, // nb_inplace_power
PyVTKMutableObject_InPlaceLshift, // nb_inplace_lshift
......@@ -558,6 +641,8 @@ static PyMappingMethods PyVTKMutableObject_AsMapping = {
//--------------------------------------------------------------------
// Buffer protocol
#ifndef VTK_PY3K
// old buffer protocol
static Py_ssize_t PyVTKMutableObject_GetReadBuf(
PyObject *op, Py_ssize_t segment, void **ptrptr)
{
......@@ -640,8 +725,10 @@ static Py_ssize_t PyVTKMutableObject_GetCharBuf(
return -1;
}
#endif
#if PY_VERSION_HEX >= 0x02060000
// new buffer protocol
static int PyVTKMutableObject_GetBuffer(
PyObject *self, Py_buffer *view, int flags)
{
......@@ -657,10 +744,12 @@ static void PyVTKMutableObject_ReleaseBuffer(
#endif
static PyBufferProcs PyVTKMutableObject_AsBuffer = {
#ifndef VTK_PY3K
PyVTKMutableObject_GetReadBuf, // bf_getreadbuffer
PyVTKMutableObject_GetWriteBuf, // bf_getwritebuffer
PyVTKMutableObject_GetSegCount, // bf_getsegcount
PyVTKMutableObject_GetCharBuf, // bf_getcharbuffer
#endif
#if PY_VERSION_HEX >= 0x02060000
PyVTKMutableObject_GetBuffer, // bf_getbuffer
PyVTKMutableObject_ReleaseBuffer // bf_releasebuffer
......@@ -678,12 +767,15 @@ static void PyVTKMutableObject_Delete(PyObject *ob)
static PyObject *PyVTKMutableObject_Repr(PyObject *ob)
{
char textspace[128];
PyObject *r = 0;
const char *name = Py_TYPE(ob)->tp_name;
PyObject *s = PyObject_Repr(((PyVTKMutableObject *)ob)->value);
if (s)
{
#ifdef VTK_PY3K
r = PyUnicode_FromFormat("%s(%U)", name, s);
#else
char textspace[128];
const char *text = PyString_AsString(s);
size_t n = strlen(name) + strlen(text) + 3;
char *cp = textspace;
......@@ -691,6 +783,7 @@ static PyObject *PyVTKMutableObject_Repr(PyObject *ob)
sprintf(cp, "%s(%s)", name, text);
r = PyString_FromString(cp);
if (n > 128) { free(cp); }
#endif
Py_DECREF(s);
}
return r;
......@@ -717,17 +810,30 @@ static PyObject *PyVTKMutableObject_RichCompare(
static PyObject *PyVTKMutableObject_GetAttr(PyObject *self, PyObject *attr)
{
char text[128];
char *name = PyString_AsString(attr);
PyObject *a;
a = PyObject_GenericGetAttr(self, attr);
PyObject *a = PyObject_GenericGetAttr(self, attr);
if (a || !PyErr_ExceptionMatches(PyExc_AttributeError))
{
return a;
}
PyErr_Clear();
if (name[0] != '_')
#ifndef VTK_PY3K
char *name = PyString_AsString(attr);
int firstchar = name[0];
#elif PY_VERSION_HEX >= 0x03030000
int firstchar = '\0';
if (PyUnicode_GetLength(attr) > 0)
{
firstchar = PyUnicode_ReadChar(attr, 0);
}
#else
int firstchar = '\0';
if (PyUnicode_Check(attr) && PyUnicode_GetSize(attr) > 0)
{
firstchar = PyUnicode_AS_UNICODE(attr)[0];
}
#endif
if (firstchar != '_')
{
a = PyObject_GetAttr(((PyVTKMutableObject *)self)->value, attr);
......@@ -738,9 +844,15 @@ static PyObject *PyVTKMutableObject_GetAttr(PyObject *self, PyObject *attr)
PyErr_Clear();
}
sprintf(text, "'%.20s' object has no attribute '%.80s'",
Py_TYPE(self)->tp_name, name);
PyErr_SetString(PyExc_AttributeError, text);
#ifdef VTK_PY3K
PyErr_Format(PyExc_AttributeError,
"'%.50s' object has no attribute '%U'",
Py_TYPE(self)->tp_name, attr);
#else
PyErr_Format(PyExc_AttributeError,
"'%.50s' object has no attribute '%.80s'",
Py_TYPE(self)->tp_name, name);
#endif
return NULL;