vtkPythonAlgorithm.cxx 8.83 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
/*=========================================================================

  Program:   Visualization Toolkit
  Module:    vtkPythonAlgorithm.h

  Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
  All rights reserved.
  See Copyright.txt or http://www.kitware.com/Copyright.htm for details.

     This software is distributed WITHOUT ANY WARRANTY; without even
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
     PURPOSE.  See the above copyright notice for more information.

=========================================================================*/
#include "vtkPythonAlgorithm.h"
#include "vtkObjectFactory.h"

#include "vtkInformation.h"
#include "vtkInformationVector.h"
#include "vtkPythonUtil.h"
21
#include "vtkSmartPyObject.h"
22 23 24 25 26 27 28

vtkStandardNewMacro(vtkPythonAlgorithm);

void vtkPythonAlgorithm::PrintSelf(ostream& os, vtkIndent indent)
{
  this->Superclass::PrintSelf(os,indent);

29
  vtkSmartPyObject str;
30
  if (this->Object)
31
  {
32
    str.TakeReference(PyObject_Str(this->Object));
33
  }
34 35 36

  os << indent << "Object: " << Object << std::endl;
  if (str)
37
  {
38 39 40 41 42 43
    os << indent << "Object (string): ";
#ifndef VTK_PY3K
    os << PyString_AsString(str);
#else
    PyObject *bytes = PyUnicode_EncodeLocale(str, VTK_PYUNICODE_ENC);
    if (bytes)
44
    {
45 46
      os << PyBytes_AsString(bytes);
      Py_DECREF(bytes);
47
    }
48 49
#endif
    os << std::endl;
50
  }
51 52 53 54
}

vtkPythonAlgorithm::vtkPythonAlgorithm()
{
55
  this->Object = nullptr;
56 57 58 59 60 61 62
}

vtkPythonAlgorithm::~vtkPythonAlgorithm()
{
  Py_XDECREF(this->Object);
}

63 64 65
// This macro gets the method passed in as the parameter method
// from the PyObject passed in as the parameter obj and creates a
// vtkSmartPyObject variable with the name passed in as the parameter
66
// var containing that method's PyObject.  If obj is nullptr, obj.method
67 68 69 70 71 72 73 74 75 76 77 78 79 80
// does not exist or obj.method is not a callable method, this macro
// causes the function using it to return with the return value
// passed in as the parameter failValue
//    var - the name of the resulting vtkSmartPyObject with the
//          method object in it.  Can be used in the code following
//          the macro's use as the variable name
//    obj - the PyObject to get the method from
//    method - the name of the method to look for.  Should be a
//          C string.
//    failValue - the value to return if the lookup fails and the
//          function using the macro should return.  Pass in a
//          block comment /**/ for void functions using this macro
#define VTK_GET_METHOD(var, obj, method, failValue)          \
  if (!obj)                                                  \
81
  {                                                        \
82
    return failValue;                                        \
83
  }                                                        \
84 85
  vtkSmartPyObject var(PyObject_GetAttrString(obj, method)); \
  if (!var)                                                  \
86
  {                                                        \
87
    return failValue;                                        \
88
  }                                                        \
89
  if (!PyCallable_Check(var))                                \
90
  {                                                        \
91
    return failValue;                                        \
92
  }
93 94 95 96 97 98 99 100 101 102 103 104 105 106

static PyObject* VTKToPython(vtkObjectBase* obj)
{
  return vtkPythonUtil::GetObjectFromPointer(obj);
}

static std::string GetPythonErrorString()
{
  PyObject* type;
  PyObject* value;
  PyObject* traceback;

  // Increments refcounts for returns.
  PyErr_Fetch(&type, &value, &traceback);
107 108 109 110 111
  // Put the returns in smartpointers that will
  // automatically decrement refcounts
  vtkSmartPyObject sType(type);
  vtkSmartPyObject sValue(value);
  vtkSmartPyObject sTraceback(traceback);
112

113
  if (!sType)
114
  {
115
    return "No error from Python?!";
116
  }
117 118

  std::string exc_string;
119 120 121

  vtkSmartPyObject tbModule(PyImport_ImportModule("traceback"));
  if (tbModule)
122
  {
123 124 125 126 127 128 129 130 131 132 133 134 135
    vtkSmartPyObject formatFunction(PyObject_GetAttrString(tbModule.GetPointer(), "format_exception"));

    vtkSmartPyObject args(PyTuple_New(3));

    Py_INCREF(sType.GetPointer()); // PyTuple steals a reference.
    PyTuple_SET_ITEM(args.GetPointer(), 0, sType.GetPointer());

    Py_INCREF(sValue.GetPointer()); // PyTuple steals a reference.
    PyTuple_SET_ITEM(args.GetPointer(), 1, sValue.GetPointer());

    Py_INCREF(sTraceback.GetPointer()); // PyTuple steals a reference.
    PyTuple_SET_ITEM(args.GetPointer(), 2, sTraceback.GetPointer());

136
    vtkSmartPyObject formatList(PyObject_Call(formatFunction.GetPointer(), args, nullptr));
137 138 139 140 141 142
    vtkSmartPyObject fastFormatList(PySequence_Fast(formatList.GetPointer(), "format_exception didn't return a list..."));

    Py_ssize_t sz = PySequence_Size(formatList.GetPointer());
    PyObject** lst = PySequence_Fast_ITEMS(fastFormatList.GetPointer());
    exc_string = "\n";
    for (Py_ssize_t i = 0; i < sz; ++i)
143
    {
144
      PyObject* str = lst[i];
145
#ifndef VTK_PY3K
146
      exc_string += PyString_AsString(str);
147 148 149
#else
      PyObject *bytes = PyUnicode_EncodeLocale(str, VTK_PYUNICODE_ENC);
      if (bytes)
150
      {
151 152
        exc_string += PyBytes_AsString(bytes);
        Py_DECREF(bytes);
153
      }
154
#endif
155
    }
156
  }
157
  else
158
  {
159 160
    vtkSmartPyObject pyexc_string(PyObject_Str(sValue));
    if (pyexc_string)
161
    {
162
#ifndef VTK_PY3K
163
      exc_string = PyString_AsString(pyexc_string);
164 165 166 167
#else
      PyObject *bytes = PyUnicode_EncodeLocale(
        pyexc_string, VTK_PYUNICODE_ENC);
      if (bytes)
168
      {
169 170
        exc_string = PyBytes_AsString(bytes);
        Py_DECREF(bytes);
171
      }
172 173
#endif
    }
174
    else
175
    {
176
      exc_string = "<Unable to convert Python error to string>";
177
    }
178
  }
179 180 181 182 183 184

  PyErr_Clear();

  return exc_string;
}

185
int vtkPythonAlgorithm::CheckResult(const char* method, const vtkSmartPyObject &res)
186 187
{
  if (!res)
188
  {
189 190 191 192
    std::string pymsg = GetPythonErrorString();
    vtkErrorMacro("Failure when calling method: \""
      << method << "\": " << pymsg << ".");
    return 0;
193
  }
194
  if (!PyInt_Check(res))
195
  {
196
    return 0;
197
  }
198 199 200 201 202 203 204 205 206

  int code = PyInt_AsLong(res);

  return code;
}

void vtkPythonAlgorithm::SetPythonObject(PyObject* obj)
{
  if (!obj)
207
  {
208
    return;
209
  }
210 211 212 213 214 215

  Py_XDECREF(this->Object);

  this->Object = obj;
  Py_INCREF(this->Object);

216
  char mname[] = "Initialize";
217 218
  VTK_GET_METHOD(method, this->Object, mname, /* no return */)

219
  vtkSmartPyObject args(PyTuple_New(1));
220 221

  PyObject* vtkself = VTKToPython(this);
222
  PyTuple_SET_ITEM(args.GetPointer(), 0, vtkself);
223

224
  vtkSmartPyObject result(PyObject_Call(method, args, nullptr));
225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242

  CheckResult(mname, result);
}

void vtkPythonAlgorithm::SetNumberOfInputPorts(int n)
{
  this->Superclass::SetNumberOfInputPorts(n);
}

void vtkPythonAlgorithm::SetNumberOfOutputPorts(int n)
{
  this->Superclass::SetNumberOfOutputPorts(n);
}

int vtkPythonAlgorithm::ProcessRequest(vtkInformation* request,
                                       vtkInformationVector** inInfo,
                                       vtkInformationVector* outInfo)
{
243
  char mname[] = "ProcessRequest";
244 245
  VTK_GET_METHOD(method, this->Object, mname, 0)

246
  vtkSmartPyObject args(PyTuple_New(4));
247 248

  PyObject* vtkself = VTKToPython(this);
249
  PyTuple_SET_ITEM(args.GetPointer(), 0, vtkself);
250 251

  PyObject* pyrequest = VTKToPython(request);
252
  PyTuple_SET_ITEM(args.GetPointer(), 1, pyrequest);
253 254 255 256

  int nports = this->GetNumberOfInputPorts();
  PyObject* pyininfos = PyTuple_New(nports);
  for (int i = 0; i < nports; ++i)
257
  {
258 259
    PyObject* pyininfo = VTKToPython(inInfo[i]);
    PyTuple_SET_ITEM(pyininfos, i, pyininfo);
260
  }
261
  PyTuple_SET_ITEM(args.GetPointer(), 2, pyininfos);
262 263

  PyObject* pyoutinfo = VTKToPython(outInfo);
264
  PyTuple_SET_ITEM(args.GetPointer(), 3, pyoutinfo);
265

266
  vtkSmartPyObject result(PyObject_Call(method, args, nullptr));
267 268 269 270 271 272

  return CheckResult(mname, result);
}

int vtkPythonAlgorithm::FillInputPortInformation(int port, vtkInformation* info)
{
273
  char mname[] = "FillInputPortInformation";
274 275
  VTK_GET_METHOD(method, this->Object, mname, 0)

276
  vtkSmartPyObject args(PyTuple_New(3));
277 278

  PyObject* vtkself = VTKToPython(this);
279
  PyTuple_SET_ITEM(args.GetPointer(), 0, vtkself);
280 281

  PyObject* pyport = PyInt_FromLong(port);
282
  PyTuple_SET_ITEM(args.GetPointer(), 1, pyport);
283 284

  PyObject* pyinfo = VTKToPython(info);
285
  PyTuple_SET_ITEM(args.GetPointer(), 2, pyinfo);
286

287
  vtkSmartPyObject result(PyObject_Call(method, args, nullptr));
288 289 290 291 292 293

  return CheckResult(mname, result);
}

int vtkPythonAlgorithm::FillOutputPortInformation(int port, vtkInformation* info)
{
294
  char mname[] = "FillOutputPortInformation";
295 296
  VTK_GET_METHOD(method, this->Object, mname, 0)

297
  vtkSmartPyObject args(PyTuple_New(3));
298 299

  PyObject* vtkself = VTKToPython(this);
300
  PyTuple_SET_ITEM(args.GetPointer(), 0, vtkself);
301 302

  PyObject* pyport = PyInt_FromLong(port);
303
  PyTuple_SET_ITEM(args.GetPointer(), 1, pyport);
304 305

  PyObject* pyinfo = VTKToPython(info);
306
  PyTuple_SET_ITEM(args.GetPointer(), 2, pyinfo);
307

308
  vtkSmartPyObject result(PyObject_Call(method, args, nullptr));
309 310 311

  return CheckResult(mname, result);
}