From 3d50d4828447e886042cc4988bb190f9fd5ce544 Mon Sep 17 00:00:00 2001 From: Julien Malik <julien.malik@c-s.fr> Date: Mon, 10 Oct 2011 05:51:23 +0200 Subject: [PATCH] ENH: add PyCommand to receive ITK event in Python callable --- Code/Wrappers/SWIG/CMakeLists.txt | 3 +- Code/Wrappers/SWIG/PyCommand.i | 43 +++++++++++ Code/Wrappers/SWIG/itkPyCommand.cxx | 112 ++++++++++++++++++++++++++++ Code/Wrappers/SWIG/itkPyCommand.h | 81 ++++++++++++++++++++ Code/Wrappers/SWIG/otbApplication.i | 3 + 5 files changed, 241 insertions(+), 1 deletion(-) create mode 100644 Code/Wrappers/SWIG/PyCommand.i create mode 100644 Code/Wrappers/SWIG/itkPyCommand.cxx create mode 100644 Code/Wrappers/SWIG/itkPyCommand.h diff --git a/Code/Wrappers/SWIG/CMakeLists.txt b/Code/Wrappers/SWIG/CMakeLists.txt index ed3a08ee34..3cf717b707 100644 --- a/Code/Wrappers/SWIG/CMakeLists.txt +++ b/Code/Wrappers/SWIG/CMakeLists.txt @@ -34,6 +34,7 @@ if ( WRAP_LUA OR WRAP_PYTHON OR WRAP_JAVA OR WRAP_CSHARP OR WRAP_TCL OR WRAP_R O set ( SWIG_HEADERS ${SWIG_HEADERS} ${CMAKE_CURRENT_SOURCE_DIR}/itkBase.i ${CMAKE_CURRENT_SOURCE_DIR}/itkMacro.i + ${CMAKE_CURRENT_SOURCE_DIR}/PyCommand.i ${CMAKE_CURRENT_SOURCE_DIR}/Python.i ${CMAKE_CURRENT_SOURCE_DIR}/Java.i @@ -63,7 +64,7 @@ if ( WRAP_PYTHON ) set(CMAKE_SWIG_FLAGS ${CMAKE_SWIG_GLOBAL_FLAGS}) set(CMAKE_SWIG_OUTDIR ${CMAKE_CURRENT_BINARY_DIR}) set(SWIG_MODULE_otbApplication_EXTRA_DEPS OTBApplicationEngine ${SWIG_HEADERS}) - SWIG_add_module ( otbApplication python otbApplication.i otbApplicationPYTHON_wrap.cxx ) + SWIG_add_module ( otbApplication python otbApplication.i otbApplicationPYTHON_wrap.cxx itkPyCommand.cxx ) SWIG_link_libraries ( otbApplication ${PYTHON_LIBRARIES} OTBApplicationEngine) set_source_files_properties(${CMAKE_CURRENT_BINARY_DIR}/otbApplicationPYTHON_wrap.cxx COMPILE_FLAGS "-w") diff --git a/Code/Wrappers/SWIG/PyCommand.i b/Code/Wrappers/SWIG/PyCommand.i new file mode 100644 index 0000000000..1cc2abfa82 --- /dev/null +++ b/Code/Wrappers/SWIG/PyCommand.i @@ -0,0 +1,43 @@ +/*========================================================================= + + Program: ORFEO Toolbox + Language: C++ + Date: $Date$ + Version: $Revision$ + + + Copyright (c) Centre National d'Etudes Spatiales. All rights reserved. + See OTBCopyright.txt 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 notices for more information. + +=========================================================================*/ +#if SWIGPYTHON + + %{ +#include "itkPyCommand.h" +typedef itk::PyCommand itkPyCommand; +typedef itk::PyCommand::Pointer itkPyCommand_Pointer; + %} + + +class itkPyCommand : public itkCommand +{ +public: + static itkPyCommand_Pointer New(); + virtual char const * GetNameOfClass() const; + + void SetCommandCallable(PyObject *obj); + PyObject * GetCommandCallable(); + void Execute(itkObject *, const itkEventObject&); + //void Execute(const itkObject *, const EventObject&); +protected: + itkPyCommand(); + ~itkPyCommand(); +}; +DECLARE_REF_COUNT_CLASS( itkPyCommand ) + +#endif diff --git a/Code/Wrappers/SWIG/itkPyCommand.cxx b/Code/Wrappers/SWIG/itkPyCommand.cxx new file mode 100644 index 0000000000..da0f40a6f5 --- /dev/null +++ b/Code/Wrappers/SWIG/itkPyCommand.cxx @@ -0,0 +1,112 @@ +/*========================================================================= + + Program: Insight Segmentation & Registration Toolkit + Module: $RCSfile: itkPyCommand.cxx,v $ + Language: C++ + Date: $Date: 2006/09/06 20:58:42 $ + Version: $Revision: 1.1 $ + + Copyright (c) Insight Software Consortium. All rights reserved. + See ITKCopyright.txt or http://www.itk.org/HTML/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 notices for more information. + +=========================================================================*/ +#include "itkPyCommand.h" + +namespace itk +{ + +PyCommand::PyCommand() +{ + this->obj = NULL; +} + +PyCommand::~PyCommand() +{ + if (this->obj) + { + Py_DECREF(this->obj); + } + this->obj = NULL; +} + +void PyCommand::SetCommandCallable(PyObject *obj) +{ + if (obj != this->obj) + { + if (this->obj) + { + // get rid of our reference + Py_DECREF(this->obj); + } + + // store the new object + this->obj = obj; + + if (this->obj) + { + // take out reference (so that the calling code doesn't + // have to keep a binding to the callable around) + Py_INCREF(this->obj); + } + } +} + +PyObject * PyCommand::GetCommandCallable() +{ + return this->obj; +} + +void PyCommand::Execute(Object *, const EventObject&) +{ + this->PyExecute(); +} + + +void PyCommand::Execute(const Object*, const EventObject&) +{ + this->PyExecute(); + +} + +void PyCommand::PyExecute() +{ + // make sure that the CommandCallable is in fact callable + if (!PyCallable_Check(this->obj)) + { + // we throw a standard ITK exception: this makes it possible for + // our standard CableSwig exception handling logic to take this + // through to the invoking Python process + itkExceptionMacro(<<"CommandCallable is not a callable Python object, " + <<"or it has not been set."); + } + else + { + PyObject *result; + + result = PyEval_CallObject(this->obj, (PyObject *)NULL); + + if (result) + { + Py_DECREF(result); + } + else + { + // there was a Python error. Clear the error by printing to stdout + PyErr_Print(); + // make sure the invoking Python code knows there was a problem + // by raising an exception + itkExceptionMacro(<<"There was an error executing the " + <<"CommandCallable."); + } + } +} + + + +} // namespace itk + + diff --git a/Code/Wrappers/SWIG/itkPyCommand.h b/Code/Wrappers/SWIG/itkPyCommand.h new file mode 100644 index 0000000000..71611b4d03 --- /dev/null +++ b/Code/Wrappers/SWIG/itkPyCommand.h @@ -0,0 +1,81 @@ +/*========================================================================= + + Program: Insight Segmentation & Registration Toolkit + Module: $RCSfile: itkPyCommand.h,v $ + Language: C++ + Date: $Date: 2006/09/06 20:58:42 $ + Version: $Revision: 1.1 $ + + Copyright (c) Insight Software Consortium. All rights reserved. + See ITKCopyright.txt or http://www.itk.org/HTML/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 notices for more information. + +=========================================================================*/ +#ifndef _itkPyCommand_h +#define _itkPyCommand_h + +#include "itkCommand.h" + +// The python header defines _POSIX_C_SOURCE without a preceding #undef +#undef _POSIX_C_SOURCE +#include <Python.h> + +namespace itk +{ + +/** \class PyCommand + * \brief Command subclass that calls a Python callable object, e.g. + * a Python function. + * + * With this class, arbitrary Python callable objects (e.g. functions) + * can be associated with an instance to be used in AddObserver calls. + * This is analogous to itk::TclCommand, but then a tad more flexible. ;) + * + * This class was contributed by Charl P. Botha <cpbotha |AT| ieee.org> + */ +class PyCommand : public Command +{ +public: + ///! Standard "Self" typedef. + typedef PyCommand Self; + + ///! Smart pointer typedef support. + typedef SmartPointer<Self> Pointer; + + ///! Run-time type information (and related methods). + itkTypeMacro(PyCommand,Command); + + ///! Method for creation through the object factory. + itkNewMacro(Self); + + /** + * Assign a Python callable object to be used. You don't have to keep + * a binding to the callable, PyCommand will also take out a reference + * to make sure the Callable sticks around. + */ + void SetCommandCallable(PyObject *obj); + + PyObject * GetCommandCallable(); + + void Execute(Object *, const EventObject&); + void Execute(const Object *, const EventObject&); + +protected: + PyCommand(); + ~PyCommand(); + void PyExecute(); + PyCommand(const Self&); // Not implemented. + void operator=(const Self&); // Not implemented. + +private: + PyObject *obj; +}; + + +} // namespace itk + +#endif // _itkPyCommand_h + diff --git a/Code/Wrappers/SWIG/otbApplication.i b/Code/Wrappers/SWIG/otbApplication.i index 8d033c5414..b1aa4175c9 100644 --- a/Code/Wrappers/SWIG/otbApplication.i +++ b/Code/Wrappers/SWIG/otbApplication.i @@ -161,3 +161,6 @@ private: void operator=(const Self&); }; +%include "PyCommand.i" + + -- GitLab