1 /*=========================================================================
2 
3   Program:   Visualization Toolkit
4   Module:    vtkPythonAlgorithm.h
5 
6   Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
7   All rights reserved.
8   See Copyright.txt or http://www.kitware.com/Copyright.htm for details.
9 
10      This software is distributed WITHOUT ANY WARRANTY; without even
11      the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
12      PURPOSE.  See the above copyright notice for more information.
13 
14 =========================================================================*/
15 #include "vtkPythonAlgorithm.h"
16 #include "vtkObjectFactory.h"
17 
18 #include "vtkInformation.h"
19 #include "vtkInformationVector.h"
20 #include "vtkPythonUtil.h"
21 #include "vtkSmartPyObject.h"
22 
23 vtkStandardNewMacro(vtkPythonAlgorithm);
24 
PrintSelf(ostream & os,vtkIndent indent)25 void vtkPythonAlgorithm::PrintSelf(ostream& os, vtkIndent indent)
26 {
27   this->Superclass::PrintSelf(os,indent);
28 
29   vtkSmartPyObject str;
30   if (this->Object)
31     {
32     str.TakeReference(PyObject_Str(this->Object));
33     }
34 
35   os << indent << "Object: " << Object << std::endl;
36   if (str)
37     {
38     os << indent << "Object (string): " << PyString_AsString(str) << std::endl;
39     }
40 }
41 
vtkPythonAlgorithm()42 vtkPythonAlgorithm::vtkPythonAlgorithm()
43 {
44   this->Object = NULL;
45 }
46 
~vtkPythonAlgorithm()47 vtkPythonAlgorithm::~vtkPythonAlgorithm()
48 {
49   Py_XDECREF(this->Object);
50 }
51 
52 // This macro gets the method passed in as the parameter method
53 // from the PyObject passed in as the parameter obj and creates a
54 // vtkSmartPyObject variable with the name passed in as the parameter
55 // var containing that method's PyObject.  If obj is NULL, obj.method
56 // does not exist or obj.method is not a callable method, this macro
57 // causes the function using it to return with the return value
58 // passed in as the parameter failValue
59 //    var - the name of the resulting vtkSmartPyObject with the
60 //          method object in it.  Can be used in the code following
61 //          the macro's use as the variable name
62 //    obj - the PyObject to get the method from
63 //    method - the name of the method to look for.  Should be a
64 //          C string.
65 //    failValue - the value to return if the lookup fails and the
66 //          function using the macro should return.  Pass in a
67 //          block comment /**/ for void functions using this macro
68 #define VTK_GET_METHOD(var, obj, method, failValue)          \
69   if (!obj)                                                  \
70     {                                                        \
71     return failValue;                                        \
72     }                                                        \
73   vtkSmartPyObject var(PyObject_GetAttrString(obj, method)); \
74   if (!var)                                                  \
75     {                                                        \
76     return failValue;                                        \
77     }                                                        \
78   if (!PyCallable_Check(var))                                \
79     {                                                        \
80     return failValue;                                        \
81     }
82 
VTKToPython(vtkObjectBase * obj)83 static PyObject* VTKToPython(vtkObjectBase* obj)
84 {
85   return vtkPythonUtil::GetObjectFromPointer(obj);
86 }
87 
GetPythonErrorString()88 static std::string GetPythonErrorString()
89 {
90   PyObject* type;
91   PyObject* value;
92   PyObject* traceback;
93 
94   // Increments refcounts for returns.
95   PyErr_Fetch(&type, &value, &traceback);
96   // Put the returns in smartpointers that will
97   // automatically decrement refcounts
98   vtkSmartPyObject sType(type);
99   vtkSmartPyObject sValue(value);
100   vtkSmartPyObject sTraceback(traceback);
101 
102   if (!sType)
103     {
104     return "No error from Python?!";
105     }
106 
107   std::string exc_string;
108 
109   vtkSmartPyObject tbModule(PyImport_ImportModule("traceback"));
110   if (tbModule)
111     {
112     vtkSmartPyObject formatFunction(PyObject_GetAttrString(tbModule.GetPointer(), "format_exception"));
113 
114     vtkSmartPyObject args(PyTuple_New(3));
115 
116     Py_INCREF(sType.GetPointer()); // PyTuple steals a reference.
117     PyTuple_SET_ITEM(args.GetPointer(), 0, sType.GetPointer());
118 
119     Py_INCREF(sValue.GetPointer()); // PyTuple steals a reference.
120     PyTuple_SET_ITEM(args.GetPointer(), 1, sValue.GetPointer());
121 
122     Py_INCREF(sTraceback.GetPointer()); // PyTuple steals a reference.
123     PyTuple_SET_ITEM(args.GetPointer(), 2, sTraceback.GetPointer());
124 
125     vtkSmartPyObject formatList(PyObject_Call(formatFunction.GetPointer(), args, NULL));
126     vtkSmartPyObject fastFormatList(PySequence_Fast(formatList.GetPointer(), "format_exception didn't return a list..."));
127 
128     Py_ssize_t sz = PySequence_Size(formatList.GetPointer());
129     PyObject** lst = PySequence_Fast_ITEMS(fastFormatList.GetPointer());
130     exc_string = "\n";
131     for (Py_ssize_t i = 0; i < sz; ++i)
132       {
133       PyObject* str = lst[i];
134       exc_string += PyString_AsString(str);
135       }
136     }
137   else
138     {
139     vtkSmartPyObject pyexc_string(PyObject_Str(sValue));
140     if (pyexc_string)
141       {
142       exc_string = PyString_AsString(pyexc_string);
143       }
144     else
145       {
146       exc_string = "<Unable to convert Python error to string>";
147       }
148     }
149 
150   PyErr_Clear();
151 
152   return exc_string;
153 }
154 
CheckResult(const char * method,const vtkSmartPyObject & res)155 int vtkPythonAlgorithm::CheckResult(const char* method, const vtkSmartPyObject &res)
156 {
157   if (!res)
158     {
159     std::string pymsg = GetPythonErrorString();
160     vtkErrorMacro("Failure when calling method: \""
161       << method << "\": " << pymsg << ".");
162     return 0;
163     }
164   if (!PyInt_Check(res))
165     {
166     return 0;
167     }
168 
169   int code = PyInt_AsLong(res);
170 
171   return code;
172 }
173 
SetPythonObject(PyObject * obj)174 void vtkPythonAlgorithm::SetPythonObject(PyObject* obj)
175 {
176   if (!obj)
177     {
178     return;
179     }
180 
181   Py_XDECREF(this->Object);
182 
183   this->Object = obj;
184   Py_INCREF(this->Object);
185 
186   char mname[] = "Initialize";
187   VTK_GET_METHOD(method, this->Object, mname, /* no return */)
188 
189   vtkSmartPyObject args(PyTuple_New(1));
190 
191   PyObject* vtkself = VTKToPython(this);
192   PyTuple_SET_ITEM(args.GetPointer(), 0, vtkself);
193 
194   vtkSmartPyObject result(PyObject_Call(method, args, NULL));
195 
196   CheckResult(mname, result);
197 }
198 
SetNumberOfInputPorts(int n)199 void vtkPythonAlgorithm::SetNumberOfInputPorts(int n)
200 {
201   this->Superclass::SetNumberOfInputPorts(n);
202 }
203 
SetNumberOfOutputPorts(int n)204 void vtkPythonAlgorithm::SetNumberOfOutputPorts(int n)
205 {
206   this->Superclass::SetNumberOfOutputPorts(n);
207 }
208 
ProcessRequest(vtkInformation * request,vtkInformationVector ** inInfo,vtkInformationVector * outInfo)209 int vtkPythonAlgorithm::ProcessRequest(vtkInformation* request,
210                                        vtkInformationVector** inInfo,
211                                        vtkInformationVector* outInfo)
212 {
213   char mname[] = "ProcessRequest";
214   VTK_GET_METHOD(method, this->Object, mname, 0)
215 
216   vtkSmartPyObject args(PyTuple_New(4));
217 
218   PyObject* vtkself = VTKToPython(this);
219   PyTuple_SET_ITEM(args.GetPointer(), 0, vtkself);
220 
221   PyObject* pyrequest = VTKToPython(request);
222   PyTuple_SET_ITEM(args.GetPointer(), 1, pyrequest);
223 
224   int nports = this->GetNumberOfInputPorts();
225   PyObject* pyininfos = PyTuple_New(nports);
226   for (int i = 0; i < nports; ++i)
227     {
228     PyObject* pyininfo = VTKToPython(inInfo[i]);
229     PyTuple_SET_ITEM(pyininfos, i, pyininfo);
230     }
231   PyTuple_SET_ITEM(args.GetPointer(), 2, pyininfos);
232 
233   PyObject* pyoutinfo = VTKToPython(outInfo);
234   PyTuple_SET_ITEM(args.GetPointer(), 3, pyoutinfo);
235 
236   vtkSmartPyObject result(PyObject_Call(method, args, NULL));
237 
238   return CheckResult(mname, result);
239 }
240 
FillInputPortInformation(int port,vtkInformation * info)241 int vtkPythonAlgorithm::FillInputPortInformation(int port, vtkInformation* info)
242 {
243   char mname[] = "FillInputPortInformation";
244   VTK_GET_METHOD(method, this->Object, mname, 0)
245 
246   vtkSmartPyObject args(PyTuple_New(3));
247 
248   PyObject* vtkself = VTKToPython(this);
249   PyTuple_SET_ITEM(args.GetPointer(), 0, vtkself);
250 
251   PyObject* pyport = PyInt_FromLong(port);
252   PyTuple_SET_ITEM(args.GetPointer(), 1, pyport);
253 
254   PyObject* pyinfo = VTKToPython(info);
255   PyTuple_SET_ITEM(args.GetPointer(), 2, pyinfo);
256 
257   vtkSmartPyObject result(PyObject_Call(method, args, NULL));
258 
259   return CheckResult(mname, result);
260 }
261 
FillOutputPortInformation(int port,vtkInformation * info)262 int vtkPythonAlgorithm::FillOutputPortInformation(int port, vtkInformation* info)
263 {
264   char mname[] = "FillOutputPortInformation";
265   VTK_GET_METHOD(method, this->Object, mname, 0)
266 
267   vtkSmartPyObject args(PyTuple_New(3));
268 
269   PyObject* vtkself = VTKToPython(this);
270   PyTuple_SET_ITEM(args.GetPointer(), 0, vtkself);
271 
272   PyObject* pyport = PyInt_FromLong(port);
273   PyTuple_SET_ITEM(args.GetPointer(), 1, pyport);
274 
275   PyObject* pyinfo = VTKToPython(info);
276   PyTuple_SET_ITEM(args.GetPointer(), 2, pyinfo);
277 
278   vtkSmartPyObject result(PyObject_Call(method, args, NULL));
279 
280   return CheckResult(mname, result);
281 }
282