Skip to content

Commit

Permalink
Refactor CallMethod with macros to avoid duplication.Refs #970
Browse files Browse the repository at this point in the history
  • Loading branch information
martyngigg committed Apr 15, 2013
1 parent 47915c8 commit c20e9c6
Showing 1 changed file with 82 additions and 159 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -33,10 +33,60 @@ namespace Mantid { namespace PythonInterface {
/// Handle a Python error state
DLLExport void translateErrorToException(const bool withTrace = true);

///
/// A wrapper around the boost::call_method to ensure that
/// the GIL is locked while the call is happening
///
/// Defines start of CallMethod function
/// @param obj A Python object to perform the call
/// @param name A string containing the method name
#define PRE_CALL(obj,name)\
GlobalInterpreterLock gil;\
if(Environment::typeHasAttribute(self, funcName))\
{\
try\
{\

/// Defines the end of CallMethod that returns a default value
#define POST_CALL_DEFAULT() \
}\
catch(boost::python::error_already_set&)\
{\
translateErrorToException();\
}\
}\
return defaultValue;

/// Defines the end of CallMethod that throws an exception if the method doesn't exist
#define POST_CALL_EXCEPT() \
}\
catch(boost::python::error_already_set&)\
{\
translateErrorToException();\
}\
}\
else\
{\
std::ostringstream os;\
os << self->ob_type->tp_name << " has no function named '" << funcName << "'\n"\
<< "Check the function exists and that its first argument is self.";\
throw std::runtime_error(os.str());\
}\
return ResultType(); // required to avoid compiler warning

/// Defines the end of CallMethod that throws an exception but doesn't return anything
/// to be used for void return types
#define POST_CALL_EXCEPT_VOID() \
}\
catch(boost::python::error_already_set&)\
{\
translateErrorToException();\
}\
}\
else\
{\
std::ostringstream os;\
os << self->ob_type->tp_name << " has no function named '" << funcName << "'\n"\
<< "Check the function exists and that its first argument is self.";\
throw std::runtime_error(os.str());\
}\


/** @name No argument Python calls */
//@{
Expand All @@ -56,19 +106,9 @@ namespace Mantid { namespace PythonInterface {
*/
static ResultType dispatchWithDefaultReturn(PyObject *self, const char * funcName, const ResultType & defaultValue)
{
GlobalInterpreterLock gil;
if(Environment::typeHasAttribute(self, funcName))
{
try
{
return boost::python::call_method<ResultType>(self, funcName);
}
catch(boost::python::error_already_set&)
{
translateErrorToException();
}
}
return defaultValue;
PRE_CALL(self, funcName);
return boost::python::call_method<ResultType>(self,funcName);
POST_CALL_DEFAULT();
}

/**
Expand All @@ -81,55 +121,16 @@ namespace Mantid { namespace PythonInterface {
*/
static ResultType dispatchWithException(PyObject *self, const char * funcName)
{
GlobalInterpreterLock gil;
if(Environment::typeHasAttribute(self, funcName))
{
try
{
return boost::python::call_method<ResultType>(self, funcName);
}
catch(boost::python::error_already_set&)
{
translateErrorToException();
}
}
else
{
std::ostringstream os;
os << self->ob_type->tp_name << " has no function named '" << funcName << "'\n"
<< "Check the function exists and that its first argument is self.";
throw std::runtime_error(os.str());
}
return ResultType();
PRE_CALL(self,funcName);
return boost::python::call_method<ResultType>(self, funcName);
POST_CALL_EXCEPT();
}
};

///Specialization for void return type
template<>
struct DLLExport CallMethod0<void>
{
/**
* Dispatch a call to the method on the given object. If the method does not exist
* then do nothing
* @param self :: The object containing the method definition
* @param funcName :: The method name
* @return The value of the function or the default value if it does not exist
*/
static void dispatchWithDefaultReturn(PyObject *self, const char * funcName)
{
GlobalInterpreterLock gil;
if(Environment::typeHasAttribute(self, funcName))
{
try
{
boost::python::call_method<void>(self, funcName);
}
catch(boost::python::error_already_set&)
{
translateErrorToException();
}
}
}
/**
* Dispatch a call to the method on the given object. If the method does not exist
* then raise a runtime_error
Expand All @@ -140,34 +141,15 @@ namespace Mantid { namespace PythonInterface {
*/
static void dispatchWithException(PyObject *self, const char * funcName)
{
GlobalInterpreterLock gil;
if(Environment::typeHasAttribute(self, funcName))
{
try
{
boost::python::call_method<void>(self, funcName);
}
catch(boost::python::error_already_set&)
{
translateErrorToException();
}
}
else
{
std::ostringstream os;
os << self->ob_type->tp_name << " has no function named '" << funcName << "'\n"
<< "Check the function exists and that its first argument is self.";
throw std::runtime_error(os.str());
}
PRE_CALL(self, funcName);
boost::python::call_method<void>(self,funcName);
POST_CALL_EXCEPT_VOID();
}
};
//@}

/** @name Two argument Python calls */
//@{
/**
* Perform a call to a python function that takes no arguments and returns a value
*/
template<typename ResultType,typename Arg1,typename Arg2>
struct DLLExport CallMethod2
{
Expand All @@ -177,86 +159,40 @@ namespace Mantid { namespace PythonInterface {
* @param self :: The object containing the method definition
* @param funcName :: The method name
* @param defaultValue :: A default value if the method does not exist
* @param arg1 :: The value of the first argument
* @param arg2 :: The value of the second argument
* @return The value of the function or the default value if it does not exist
*/
static ResultType dispatchWithDefaultReturn(PyObject *self, const char * funcName, const ResultType & defaultValue,
const Arg1 & arg1, const Arg2 & arg2)
{
GlobalInterpreterLock gil;
if(Environment::typeHasAttribute(self, funcName))
{
try
{
return boost::python::call_method<ResultType,Arg1,Arg2>(self, funcName,arg1,arg2);
}
catch(boost::python::error_already_set&)
{
translateErrorToException();
}
}
return defaultValue;
PRE_CALL(self, funcName);
return boost::python::call_method<ResultType,Arg1,Arg2>(self,funcName,arg1,arg2);
POST_CALL_DEFAULT();
}

/**
* Dispatch a call to the method on the given object. If the method does not exist
* then raise a std::runtime_error exception
* @param self :: The object containing the method definition
* @param funcName :: The method name
* @param errorMsg :: An error message to pass to the generated exception
* @param arg1 :: The value of the first argument
* @param arg2 :: The value of the second argument
* @return The value of the function or the default value if it does not exist
*/
static ResultType dispatchWithException(PyObject *self, const char * funcName)
static ResultType dispatchWithException(PyObject *self, const char * funcName,
const Arg1 & arg1, const Arg2 & arg2)
{
GlobalInterpreterLock gil;
if(Environment::typeHasAttribute(self, funcName))
{
try
{
return boost::python::call_method<ResultType>(self, funcName);
}
catch(boost::python::error_already_set&)
{
translateErrorToException();
}
}
else
{
std::ostringstream os;
os << self->ob_type->tp_name << " has no function named '" << funcName << "'\n"
<< "Check the function exists and that its first argument is self.";
throw std::runtime_error(os.str());
}
return ResultType();
PRE_CALL(self, funcName);
return boost::python::call_method<ResultType,Arg1,Arg2>(self, funcName,arg1,arg2);
POST_CALL_EXCEPT();
}
};

///Specialization for void return type
template<typename Arg1,typename Arg2>
struct DLLExport CallMethod2<void,Arg1,Arg2>
{
/**
* Dispatch a call to the method on the given object. If the method does not exist
* then do nothing
* @param self :: The object containing the method definition
* @param funcName :: The method name
* @return The value of the function or the default value if it does not exist
*/
static void dispatchWithDefaultReturn(PyObject *self, const char * funcName,
const Arg1 & arg1, const Arg2 & arg2)
{
GlobalInterpreterLock gil;
if(Environment::typeHasAttribute(self, funcName))
{
try
{
boost::python::call_method<void,Arg1,Arg2>(self, funcName,arg1,arg2);
}
catch(boost::python::error_already_set&)
{
translateErrorToException();
}
}
}
/**
* Dispatch a call to the method on the given object. If the method does not exist
* then raise a runtime_error
Expand All @@ -268,29 +204,16 @@ namespace Mantid { namespace PythonInterface {
static void dispatchWithException(PyObject *self, const char * funcName,
const Arg1 & arg1, const Arg2 & arg2)
{
GlobalInterpreterLock gil;
if(Environment::typeHasAttribute(self, funcName))
{
try
{
boost::python::call_method<void,Arg1,Arg2>(self, funcName,arg1,arg2);
}
catch(boost::python::error_already_set&)
{
translateErrorToException();
}
}
else
{
std::ostringstream os;
os << self->ob_type->tp_name << " has no function named '" << funcName << "'\n"
<< "Check the function exists and that its first argument is self.";
throw std::runtime_error(os.str());
}
PRE_CALL(self, funcName);
boost::python::call_method<void,Arg1,Arg2>(self,funcName,arg1,arg2);
POST_CALL_EXCEPT_VOID();
}
};
//@}


// Tidy up
#undef PRE_CALL
#undef POST_CALL_DEFAULT
}
}}

Expand Down

0 comments on commit c20e9c6

Please sign in to comment.