Commit f9a208d6 authored by Shawn Waldon's avatar Shawn Waldon

Add a smartpointer for PyObjects

This refactors the SmartPyObject class from a local class in
vtkMatplotlibMathTextUtilities.cxx to be externally visible.  This class
is duplicated several places in Paraview and this refactor will allow
code to be shared between all places that need it.  It is added to the
vtkWrappingPythonCore module as the vtkSmartPyObject class.

This commit also refactors the vtkPythonAlgorithm to use the new smart
pointer.

This commit is part of a change to ParaView and thus the topic name
reflects that change and not the change to VTK.

Change-Id: If3f0387bb7bb24f823dbe690e64a0a8bb1e0df16
parent dace3979
......@@ -18,6 +18,7 @@
#include "vtkInformation.h"
#include "vtkInformationVector.h"
#include "vtkPythonUtil.h"
#include "vtkSmartPyObject.h"
vtkStandardNewMacro(vtkPythonAlgorithm);
......@@ -25,17 +26,16 @@ void vtkPythonAlgorithm::PrintSelf(ostream& os, vtkIndent indent)
{
this->Superclass::PrintSelf(os,indent);
PyObject* str = NULL;
vtkSmartPyObject str;
if (this->Object)
{
str = PyObject_Str(this->Object);
str.TakeReference(PyObject_Str(this->Object));
}
os << indent << "Object: " << Object << std::endl;
if (str)
{
os << indent << "Object (string): " << PyString_AsString(str) << std::endl;
Py_DECREF(str);
}
}
......@@ -49,20 +49,35 @@ vtkPythonAlgorithm::~vtkPythonAlgorithm()
Py_XDECREF(this->Object);
}
#define VTK_GET_METHOD(var, obj, method, failValue) \
if (!obj) \
{ \
return failValue; \
} \
PyObject* var = PyObject_GetAttrString(obj, method); \
if (!var) \
{ \
return failValue; \
} \
if (!PyCallable_Check(var)) \
{ \
Py_DECREF(var); \
return failValue; \
// 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
// var containing that method's PyObject. If obj is NULL, obj.method
// 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) \
{ \
return failValue; \
} \
vtkSmartPyObject var(PyObject_GetAttrString(obj, method)); \
if (!var) \
{ \
return failValue; \
} \
if (!PyCallable_Check(var)) \
{ \
return failValue; \
}
static PyObject* VTKToPython(vtkObjectBase* obj)
......@@ -78,34 +93,34 @@ static std::string GetPythonErrorString()
// Increments refcounts for returns.
PyErr_Fetch(&type, &value, &traceback);
// Put the returns in smartpointers that will
// automatically decrement refcounts
vtkSmartPyObject sType(type);
vtkSmartPyObject sValue(value);
vtkSmartPyObject sTraceback(traceback);
if (!type)
if (!sType)
{
return "No error from Python?!";
}
PyObject* pyexc_string = PyObject_Str(value);
vtkSmartPyObject pyexc_string(PyObject_Str(sValue));
std::string exc_string;
if (pyexc_string)
{
exc_string = PyString_AsString(pyexc_string);
Py_DECREF(pyexc_string);
}
else
{
exc_string = "<Unable to convert Python error to string>";
}
Py_XDECREF(type);
Py_XDECREF(value);
Py_XDECREF(traceback);
PyErr_Clear();
return exc_string;
}
int vtkPythonAlgorithm::CheckResult(const char* method, PyObject* res)
int vtkPythonAlgorithm::CheckResult(const char* method, const vtkSmartPyObject &res)
{
if (!res)
{
......@@ -116,12 +131,10 @@ int vtkPythonAlgorithm::CheckResult(const char* method, PyObject* res)
}
if (!PyInt_Check(res))
{
Py_DECREF(res);
return 0;
}
int code = PyInt_AsLong(res);
Py_DECREF(res);
return code;
}
......@@ -141,14 +154,12 @@ void vtkPythonAlgorithm::SetPythonObject(PyObject* obj)
char mname[] = "Initialize";
VTK_GET_METHOD(method, this->Object, mname, /* no return */)
PyObject* args = PyTuple_New(1);
vtkSmartPyObject args(PyTuple_New(1));
PyObject* vtkself = VTKToPython(this);
PyTuple_SET_ITEM(args, 0, vtkself);
PyTuple_SET_ITEM(args.GetPointer(), 0, vtkself);
PyObject* result = PyObject_Call(method, args, NULL);
Py_DECREF(args);
Py_DECREF(method);
vtkSmartPyObject result(PyObject_Call(method, args, NULL));
CheckResult(mname, result);
}
......@@ -170,13 +181,13 @@ int vtkPythonAlgorithm::ProcessRequest(vtkInformation* request,
char mname[] = "ProcessRequest";
VTK_GET_METHOD(method, this->Object, mname, 0)
PyObject* args = PyTuple_New(4);
vtkSmartPyObject args(PyTuple_New(4));
PyObject* vtkself = VTKToPython(this);
PyTuple_SET_ITEM(args, 0, vtkself);
PyTuple_SET_ITEM(args.GetPointer(), 0, vtkself);
PyObject* pyrequest = VTKToPython(request);
PyTuple_SET_ITEM(args, 1, pyrequest);
PyTuple_SET_ITEM(args.GetPointer(), 1, pyrequest);
int nports = this->GetNumberOfInputPorts();
PyObject* pyininfos = PyTuple_New(nports);
......@@ -185,14 +196,12 @@ int vtkPythonAlgorithm::ProcessRequest(vtkInformation* request,
PyObject* pyininfo = VTKToPython(inInfo[i]);
PyTuple_SET_ITEM(pyininfos, i, pyininfo);
}
PyTuple_SET_ITEM(args, 2, pyininfos);
PyTuple_SET_ITEM(args.GetPointer(), 2, pyininfos);
PyObject* pyoutinfo = VTKToPython(outInfo);
PyTuple_SET_ITEM(args, 3, pyoutinfo);
PyTuple_SET_ITEM(args.GetPointer(), 3, pyoutinfo);
PyObject* result = PyObject_Call(method, args, NULL);
Py_DECREF(method);
Py_DECREF(args);
vtkSmartPyObject result(PyObject_Call(method, args, NULL));
return CheckResult(mname, result);
}
......@@ -202,20 +211,18 @@ int vtkPythonAlgorithm::FillInputPortInformation(int port, vtkInformation* info)
char mname[] = "FillInputPortInformation";
VTK_GET_METHOD(method, this->Object, mname, 0)
PyObject* args = PyTuple_New(3);
vtkSmartPyObject args(PyTuple_New(3));
PyObject* vtkself = VTKToPython(this);
PyTuple_SET_ITEM(args, 0, vtkself);
PyTuple_SET_ITEM(args.GetPointer(), 0, vtkself);
PyObject* pyport = PyInt_FromLong(port);
PyTuple_SET_ITEM(args, 1, pyport);
PyTuple_SET_ITEM(args.GetPointer(), 1, pyport);
PyObject* pyinfo = VTKToPython(info);
PyTuple_SET_ITEM(args, 2, pyinfo);
PyTuple_SET_ITEM(args.GetPointer(), 2, pyinfo);
PyObject* result = PyObject_Call(method, args, NULL);
Py_DECREF(method);
Py_DECREF(args);
vtkSmartPyObject result(PyObject_Call(method, args, NULL));
return CheckResult(mname, result);
}
......@@ -225,20 +232,18 @@ int vtkPythonAlgorithm::FillOutputPortInformation(int port, vtkInformation* info
char mname[] = "FillOutputPortInformation";
VTK_GET_METHOD(method, this->Object, mname, 0)
PyObject* args = PyTuple_New(3);
vtkSmartPyObject args(PyTuple_New(3));
PyObject* vtkself = VTKToPython(this);
PyTuple_SET_ITEM(args, 0, vtkself);
PyTuple_SET_ITEM(args.GetPointer(), 0, vtkself);
PyObject* pyport = PyInt_FromLong(port);
PyTuple_SET_ITEM(args, 1, pyport);
PyTuple_SET_ITEM(args.GetPointer(), 1, pyport);
PyObject* pyinfo = VTKToPython(info);
PyTuple_SET_ITEM(args, 2, pyinfo);
PyTuple_SET_ITEM(args.GetPointer(), 2, pyinfo);
PyObject* result = PyObject_Call(method, args, NULL);
Py_DECREF(method);
Py_DECREF(args);
vtkSmartPyObject result(PyObject_Call(method, args, NULL));
return CheckResult(mname, result);
}
......@@ -42,6 +42,8 @@
#include "vtkFiltersPythonModule.h" // For export macro
#include "vtkAlgorithm.h"
class vtkSmartPyObject;
class VTKFILTERSPYTHON_EXPORT vtkPythonAlgorithm : public vtkAlgorithm
{
public:
......@@ -81,7 +83,7 @@ private:
vtkPythonAlgorithm(const vtkPythonAlgorithm&); // Not implemented.
void operator=(const vtkPythonAlgorithm&); // Not implemented.
int CheckResult(const char* method, PyObject* res);
int CheckResult(const char* method, const vtkSmartPyObject& res);
PyObject* Object;
};
......
......@@ -5,6 +5,8 @@ vtk_module(vtkRenderingMatplotlib
vtkImagingCore
vtkRenderingCore
vtkPythonInterpreter
PRIVATE_DEPENDS
vtkWrappingPythonCore
TEST_DEPENDS
vtkCommonColor
vtkInteractionImage
......
......@@ -25,6 +25,7 @@
#include "vtkPoints.h"
#include "vtkPythonInterpreter.h"
#include "vtkStdString.h"
#include "vtkSmartPyObject.h"
#include "vtkTextProperty.h"
#include "vtkTransform.h"
......@@ -44,33 +45,6 @@ typedef Py_intptr_t Py_ssize_t;
# endif
#endif
// Smart pointer for PyObjects. Calls Py_XDECREF when scope ends.
class SmartPyObject
{
PyObject *Object;
public:
SmartPyObject(PyObject *obj = NULL)
: Object(obj)
{
}
~SmartPyObject()
{
Py_XDECREF(this->Object);
}
PyObject *operator->() const
{
return this->Object;
}
PyObject *GetPointer() const
{
return this->Object;
}
};
//----------------------------------------------------------------------------
vtkMatplotlibMathTextUtilities::Availablity
vtkMatplotlibMathTextUtilities::MPLMathTextAvailable =
......@@ -109,9 +83,9 @@ void vtkMatplotlibMathTextUtilities::CheckMPLAvailability()
PyObject *value = NULL;
PyObject *traceback = NULL;
PyErr_Fetch(&type, &value, &traceback);
SmartPyObject typeStr(PyObject_Str(type));
SmartPyObject valueStr(PyObject_Str(value));
SmartPyObject tracebackStr(PyObject_Str(traceback));
vtkSmartPyObject typeStr(PyObject_Str(type));
vtkSmartPyObject valueStr(PyObject_Str(value));
vtkSmartPyObject tracebackStr(PyObject_Str(traceback));
vtkMplStartUpDebugMacro(
"Error during matplotlib import:\n"
<< "\nStack:\n"
......@@ -203,13 +177,13 @@ bool vtkMatplotlibMathTextUtilities::InitializeMaskParser()
// ensure that Python is initialized.
vtkPythonInterpreter::Initialize();
SmartPyObject mplMathTextLib(PyImport_ImportModule("matplotlib.mathtext"));
vtkSmartPyObject mplMathTextLib(PyImport_ImportModule("matplotlib.mathtext"));
if (this->CheckForError(mplMathTextLib.GetPointer()))
{
return false;
}
SmartPyObject mathTextParserClass(
vtkSmartPyObject mathTextParserClass(
PyObject_GetAttrString(mplMathTextLib.GetPointer(), "MathTextParser"));
if (this->CheckForError(mathTextParserClass.GetPointer()))
{
......@@ -234,13 +208,13 @@ bool vtkMatplotlibMathTextUtilities::InitializePathParser()
// ensure that Python is initialized.
vtkPythonInterpreter::Initialize();
SmartPyObject mplTextPathLib(PyImport_ImportModule("matplotlib.textpath"));
vtkSmartPyObject mplTextPathLib(PyImport_ImportModule("matplotlib.textpath"));
if (this->CheckForError(mplTextPathLib.GetPointer()))
{
return false;
}
SmartPyObject textToPathClass(
vtkSmartPyObject textToPathClass(
PyObject_GetAttrString(mplTextPathLib.GetPointer(), "TextToPath"));
if (this->CheckForError(textToPathClass.GetPointer()))
{
......@@ -263,7 +237,7 @@ bool vtkMatplotlibMathTextUtilities::InitializeFontPropertiesClass()
// ensure that Python is initialized.
vtkPythonInterpreter::Initialize();
SmartPyObject mplFontManagerLib(
vtkSmartPyObject mplFontManagerLib(
PyImport_ImportModule("matplotlib.font_manager"));
if (this->CheckForError(mplFontManagerLib.GetPointer()))
{
......@@ -295,9 +269,9 @@ bool vtkMatplotlibMathTextUtilities::CheckForError()
PyObject *value = NULL;
PyObject *traceback = NULL;
PyErr_Fetch(&type, &value, &traceback);
SmartPyObject typeStr(PyObject_Str(type));
SmartPyObject valueStr(PyObject_Str(value));
SmartPyObject tracebackStr(PyObject_Str(traceback));
vtkSmartPyObject typeStr(PyObject_Str(type));
vtkSmartPyObject valueStr(PyObject_Str(value));
vtkSmartPyObject tracebackStr(PyObject_Str(traceback));
vtkWarningMacro(<< "Python exception raised:\n"
<< "\nStack:\n"
<< (tracebackStr.GetPointer() == NULL
......@@ -517,7 +491,7 @@ bool vtkMatplotlibMathTextUtilities::GetBoundingBox(
// paths generated by StringToPath
long int fontSize = tprop->GetFontSize() * 72.0 / static_cast<float>(dpi);
SmartPyObject resultTuple(PyObject_CallMethod(this->MaskParser,
vtkSmartPyObject resultTuple(PyObject_CallMethod(this->MaskParser,
const_cast<char*>("to_mask"),
const_cast<char*>("sii"),
const_cast<char*>(str),
......@@ -534,7 +508,7 @@ bool vtkMatplotlibMathTextUtilities::GetBoundingBox(
return false;
}
SmartPyObject dimTuple(PyObject_GetAttrString(numpyArray,
vtkSmartPyObject dimTuple(PyObject_GetAttrString(numpyArray,
const_cast<char*>("shape")));
if (this->CheckForError(dimTuple.GetPointer()))
{
......@@ -598,7 +572,7 @@ bool vtkMatplotlibMathTextUtilities::RenderString(const char *str,
unsigned char b = static_cast<unsigned char>(dcolor[2] * 255);
double alpha = tprop->GetOpacity();
SmartPyObject resultTuple(PyObject_CallMethod(this->MaskParser,
vtkSmartPyObject resultTuple(PyObject_CallMethod(this->MaskParser,
const_cast<char*>("to_mask"),
const_cast<char*>("sii"),
const_cast<char*>(str),
......@@ -615,7 +589,7 @@ bool vtkMatplotlibMathTextUtilities::RenderString(const char *str,
return false;
}
SmartPyObject flatArray(PyObject_CallMethod(numpyArray,
vtkSmartPyObject flatArray(PyObject_CallMethod(numpyArray,
const_cast<char*>("flatten"),
const_cast<char*>("")));
if (this->CheckForError(flatArray.GetPointer()))
......@@ -623,7 +597,7 @@ bool vtkMatplotlibMathTextUtilities::RenderString(const char *str,
return false;
}
SmartPyObject list(PyObject_CallMethod(flatArray.GetPointer(),
vtkSmartPyObject list(PyObject_CallMethod(flatArray.GetPointer(),
const_cast<char*>("tolist"),
const_cast<char*>("")));
if (this->CheckForError(list.GetPointer()))
......@@ -631,7 +605,7 @@ bool vtkMatplotlibMathTextUtilities::RenderString(const char *str,
return false;
}
SmartPyObject dimTuple(PyObject_GetAttrString(numpyArray,
vtkSmartPyObject dimTuple(PyObject_GetAttrString(numpyArray,
const_cast<char*>("shape")));
if (this->CheckForError(dimTuple.GetPointer()))
{
......@@ -790,13 +764,13 @@ bool vtkMatplotlibMathTextUtilities::StringToPath(const char *str,
path->Reset();
// Create the font property
SmartPyObject pyFontProp(this->GetFontProperties(tprop));
vtkSmartPyObject pyFontProp(this->GetFontProperties(tprop));
if (this->CheckForError(pyFontProp.GetPointer()))
{
return false;
}
SmartPyObject pyResultTuple(
vtkSmartPyObject pyResultTuple(
PyObject_CallMethod(this->PathParser,
const_cast<char*>("get_text_path"),
const_cast<char*>("Osi"),
......@@ -835,8 +809,8 @@ bool vtkMatplotlibMathTextUtilities::StringToPath(const char *str,
for (Py_ssize_t i = 0; i < numVerts; ++i)
{
SmartPyObject pyVert(PySequence_GetItem(pyVerts, i));
SmartPyObject pyCode(PySequence_GetItem(pyCodes, i));
vtkSmartPyObject pyVert(PySequence_GetItem(pyVerts, i));
vtkSmartPyObject pyCode(PySequence_GetItem(pyCodes, i));
if (this->CheckForError(pyVert.GetPointer()) ||
this->CheckForError(pyCode.GetPointer()))
{
......@@ -865,7 +839,7 @@ bool vtkMatplotlibMathTextUtilities::StringToPath(const char *str,
}
else // Assume numpy array. Convert to list and extract elements.
{
SmartPyObject pyVertList(PyObject_CallMethod(pyVert.GetPointer(),
vtkSmartPyObject pyVertList(PyObject_CallMethod(pyVert.GetPointer(),
const_cast<char*>("tolist"),
NULL));
if (this->CheckForError(pyVertList.GetPointer()) ||
......@@ -878,8 +852,8 @@ bool vtkMatplotlibMathTextUtilities::StringToPath(const char *str,
pyVertYObj = PySequence_GetItem(pyVertList.GetPointer(), 1);
}
SmartPyObject pyVertX(pyVertXObj);
SmartPyObject pyVertY(pyVertYObj);
vtkSmartPyObject pyVertX(pyVertXObj);
vtkSmartPyObject pyVertY(pyVertYObj);
if (this->CheckForError(pyVertX.GetPointer()) ||
this->CheckForError(pyVertY.GetPointer()))
{
......
......@@ -6,6 +6,7 @@ set(Module_SRCS
vtkPythonCommand.cxx
vtkPythonOverload.cxx
vtkPythonUtil.cxx
vtkSmartPyObject.cxx
PyVTKClass.cxx
PyVTKMutableObject.cxx
PyVTKObject.cxx
......
/*=========================================================================
Program: Visualization Toolkit
Module: vtkSmartPyObject.cxx
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 "vtkSmartPyObject.h"
vtkSmartPyObject::vtkSmartPyObject(PyObject *obj) :
Object(obj)
{}
vtkSmartPyObject::vtkSmartPyObject(const vtkSmartPyObject &other) :
Object(other.Object)
{
Py_XINCREF(this->Object);
}
vtkSmartPyObject::~vtkSmartPyObject()
{
Py_XDECREF(this->Object);
}
vtkSmartPyObject &vtkSmartPyObject::operator=(const vtkSmartPyObject &other)
{
Py_XDECREF(this->Object);
this->Object = other.Object;
Py_XINCREF(this->Object);
return *this;
}
vtkSmartPyObject &vtkSmartPyObject::operator=(PyObject *obj)
{
Py_XDECREF(this->Object);
this->Object = obj;
Py_XINCREF(this->Object);
return *this;
}
void vtkSmartPyObject::TakeReference(PyObject *obj)
{
Py_XDECREF(this->Object);
this->Object = obj;
}
PyObject *vtkSmartPyObject::operator->() const
{
return this->Object;
}
vtkSmartPyObject::operator PyObject*() const
{
return this->Object;
}
vtkSmartPyObject::operator bool() const
{
return this->Object != NULL;
}
PyObject *vtkSmartPyObject::ReleaseReference()
{
PyObject *tmp = this->Object;
this->Object = NULL;
return tmp;
}
PyObject *vtkSmartPyObject::GetPointer() const
{
return this->Object;
}
PyObject *vtkSmartPyObject::GetAndIncreaseReferenceCount()
{
Py_XINCREF(this->Object);
return this->Object;
}
/*=========================================================================
Program: Visualization Toolkit
Module: vtkSmartPyObject.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.
=========================================================================*/
// .NAME vtkSmartPyObject
#ifndef _vtkSmartPyObject_h
#define _vtkSmartPyObject_h
// this must be included first
#include "vtkPython.h" // PyObject can't be forward declared
#include "vtkWrappingPythonCoreModule.h"
// This class serves as a smart pointer for PyObjects from the C++
// to Python bridge interface.
class VTKWRAPPINGPYTHONCORE_EXPORT vtkSmartPyObject {
public:
// Creates a new vtkSmartPyObject managing the existing reference
// to the object given
vtkSmartPyObject(PyObject *obj = NULL);
// Creates a new vtkSmartPyObject to the object in the other smart
// pointer and increments the reference count to the object
vtkSmartPyObject(const vtkSmartPyObject &other);
// Decrements the reference count to the object
~vtkSmartPyObject();
// The internal pointer is copied from the other vtkSmartPyObject.
// The reference count on the old object is decremented and the
// reference count on the new object is incremented
vtkSmartPyObject& operator=(const vtkSmartPyObject &other);
// Sets the internal pointer to the given PyObject. The reference
// count on the PyObject is incremented. To take a reference without
// incrementing the reference count use TakeReference.
vtkSmartPyObject& operator=(PyObject *obj);
// Sets the internal pointer to the given PyObject without incrementing
// the reference count
void TakeReference(PyObject* obj);
PyObject *operator->() const;
operator PyObject*() const;
// Returns true if the internal pointer is to a valid PyObject.
operator bool() const;
// Returns the pointer to a PyObject stored internally and clears the
// internally stored pointer. The caller is responsible for calling
// Py_DECREF on the returned object when finished with it as this
// does not change the reference count.
PyObject* ReleaseReference();
// Returns the internal pointer to a PyObject with no effect on its
// reference count
PyObject *GetPointer() const;
// Returns the internal pointer to a PyObject and incrments its reference
// count
PyObject* GetAndIncreaseReferenceCount();
private:
PyObject *Object;
};
#endif
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment