Skip to content

Commit

Permalink
Refs #4399. Overhaul Python->C++ property setters.
Browse files Browse the repository at this point in the history
This aligns each handler with the C type rather than the python
type which makes conversions into the C type easier.
  • Loading branch information
martyngigg committed Feb 16, 2012
1 parent 68b54e2 commit a9ebcae
Show file tree
Hide file tree
Showing 31 changed files with 1,094 additions and 512 deletions.
4 changes: 3 additions & 1 deletion Code/Mantid/Framework/PythonInterface/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,9 @@ add_subdirectory ( mantid )
# C++ unit tests
set ( TEST_FILES
test/cpp/PythonObjectInstantiatorTest.h
test/cpp/VectorDelegateTest.h # Windows doesn't like having two around
test/cpp/VectorDelegateTest.h
test/cpp/PySequenceToVectorConverterTest.h
test/cpp/NDArrayToVectorConverterTest.h
)

if ( CXXTEST_FOUND )
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
#ifndef MANTID_PYTHONINTERFACE_NDARRAYTOVECTORCONVERTER_H_
#define MANTID_PYTHONINTERFACE_NDARRAYTOVECTORCONVERTER_H_
/*
Copyright © 2011 ISIS Rutherford Appleton Laboratory & NScD Oak Ridge National Laboratory
This file is part of Mantid.
Mantid is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
Mantid is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
File change history is stored at: <https://svn.mantidproject.org/mantid/trunk/Code/Mantid>.
Code Documentation is available at: <http://doxygen.mantidproject.org>
*/
#include "MantidKernel/System.h"
#include <boost/python/object.hpp>
#include <vector>

namespace Mantid
{
namespace PythonInterface
{

/**
* Converts a Python sequence type to a C++ std::vector, where the vector element
* type is defined by the template type
*/
template <typename DestElementType>
struct NDArrayToVectorConverter
{
/// Constructor
NDArrayToVectorConverter(const boost::python::object & value);
/// Do the conversion
const std::vector<DestElementType> operator()();
private:
/// Check the array is of the correct type and coerce it if not
void typeCheck();
/// Pointer to ndarray object
boost::python::object m_arr;
};

}
}

#endif /* MANTID_PYTHONINTERFACE_NDARRAYTOVECTORCONVERTER_H_ */
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
#ifndef MANTID_PYTHONINTERFACE_NDARRAYTYPEINDEX_H_
#define MANTID_PYTHONINTERFACE_NDARRAYTYPEINDEX_H_
/**
Copyright &copy; 2011 ISIS Rutherford Appleton Laboratory & NScD Oak Ridge National Laboratory
This file is part of Mantid.
Mantid is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
Mantid is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
File change history is stored at: <https://svn.mantidproject.org/mantid/trunk/Code/Mantid>
Code Documentation is available at: <http://doxygen.mantidproject.org>
*/
#include "MantidKernel/System.h"
#include <boost/python/detail/prefix.hpp> // Safe include of Python.h

// See http://docs.scipy.org/doc/numpy/reference/c-api.array.html#PY_ARRAY_UNIQUE_SYMBOL
#define PY_ARRAY_UNIQUE_SYMBOL KERNEL_ARRAY_API
#define NO_IMPORT_ARRAY
#include <numpy/ndarrayobject.h>

namespace Mantid
{
namespace PythonInterface
{
namespace Numpy
{

/**
* Defines a mapping between C++ type given by
* the template parameter and numpy type enum
* NPY_TYPES.
*
* There is no general definition, only specialized
* versions are defined. Each specialization should
* contain a static const NPY_TYPES definition giving
* the result of the mapping
*/
template<typename T>
struct NDArrayTypeIndex
{};

/// Macro to define mappings between the CType and Numpy enum
#define DEFINE_TYPE_MAPPING(CType, NDTypeNum) \
template<>\
struct NDArrayTypeIndex<CType>\
{\
static int typenum() { return NDTypeNum; }\
};

DEFINE_TYPE_MAPPING(int16_t, NPY_INT16);
DEFINE_TYPE_MAPPING(uint16_t, NPY_UINT16);
DEFINE_TYPE_MAPPING(int32_t, NPY_INT32);
DEFINE_TYPE_MAPPING(uint32_t, NPY_UINT32);
DEFINE_TYPE_MAPPING(int64_t, NPY_INT64);
DEFINE_TYPE_MAPPING(uint64_t, NPY_UINT64);
DEFINE_TYPE_MAPPING(double, NPY_DOUBLE);
// Not needed outside here
#undef DEFINE_TYPE_MAPPING

}
}
}


#endif /* MANTID_PYTHONINTERFACE_NDARRAYTYPEINDEX_H_*/
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
#ifndef MANTID_PYTHONINTERFACE_PYSEQUENCETOVECTORCONVERTER_H_
#define MANTID_PYTHONINTERFACE_PYSEQUENCETOVECTORCONVERTER_H_
/*
Copyright &copy; 2011 ISIS Rutherford Appleton Laboratory & NScD Oak Ridge National Laboratory
This file is part of Mantid.
Mantid is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
Mantid is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
File change history is stored at: <https://svn.mantidproject.org/mantid/trunk/Code/Mantid>.
Code Documentation is available at: <http://doxygen.mantidproject.org>
*/
#include <boost/python/object.hpp>
#include <boost/python/extract.hpp>
#include <vector>

namespace Mantid
{
namespace PythonInterface
{
namespace // <anonymous>
{
/**
* Extract a C type from a Python object.
*/
template<typename CType>
struct ExtractCType
{
/**
* Calls extract on the Python object using the template type
* @param value A pointer to the Python object
* @return The value as a C type
*/
inline CType operator()(PyObject* value)
{
return boost::python::extract<CType>(value);
}
};

/**
* Template specialization to convert a Python object to a C++ std::string
*/
template<>
struct ExtractCType<std::string>
{
/**
* Uses boost lexical cast to convert the type to a string
* @param value A pointer to the Python object
* @return The value as a C type
*/
inline std::string operator()(PyObject *value)
{
return boost::python::extract<std::string>(PyObject_Str(value));
}
};

} //end <anonymous>

/**
* Converts a Python sequence type to a C++ std::vector, where the element
* type is defined by the template type
*/
template <typename DestElementType>
struct PySequenceToVectorConverter
{
PySequenceToVectorConverter(const boost::python::object & value)
: m_obj(value.ptr())
{
check(value);
}

/**
* Converts the Python object to a C++ vector
* @return A std::vector<ElementType> containing the values
* from the Python sequence
*/
inline const std::vector<DestElementType> operator()()
{
Py_ssize_t length = PySequence_Size(m_obj);
std::vector<DestElementType> cvector(length);
if(length == 0) return cvector;
ExtractCType<DestElementType> elementConverter;
for( Py_ssize_t i = 0; i < length; ++i )
{
PyObject *item = PySequence_Fast_GET_ITEM(m_obj, i);
DestElementType element = elementConverter(item);
cvector[i] = element;
}
return cvector;
}

private:
inline void check(const boost::python::object & obj)
{
if( !PySequence_Check(obj.ptr()) )
{
throw std::invalid_argument(std::string("PySequenceToVectorConverter expects Python sequence type, found ")
+ obj.ptr()->ob_type->tp_name);
}
}
/// Python object to convert
PyObject *m_obj;

};

}
}


#endif /* MANTID_PYTHONINTERFACE_PYSEQUENCETOVECTORCONVERTER_H_ */

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#ifndef MANTID_PYTHONINTERFACE_PYTHONTYPEHANDLER_H_
#define MANTID_PYTHONINTERFACE_PYTHONTYPEHANDLER_H_
#ifndef MANTID_PYTHONINTERFACE_PROPERTYVALUEHANDLER_H_
#define MANTID_PYTHONINTERFACE_PROPERTYVALUEHANDLER_H_
/**
Copyright &copy; 2011 ISIS Rutherford Appleton Laboratory & NScD Oak Ridge National Laboratory
Expand Down Expand Up @@ -34,24 +34,28 @@ namespace Mantid
}
namespace PythonInterface
{
namespace TypeRegistry
namespace Registry
{
/**
* A non-template base class that can be stored in a map so that
* its virtual functions are overridden in template derived classes
* that can extract the correct type from the Python object
* This class provides a base-class objects that are able to take
* a python object and set it on an algorithm property.
*
* The set function should call the setProperty method once it has the
* correct C++ type from the Python object
*/
struct DLLExport PythonTypeHandler
struct DLLExport PropertyValueHandler
{
/// Virtual Destructor
virtual ~PythonTypeHandler() {};
virtual ~PropertyValueHandler() {};
/// Set function to handle Python -> C++ calls
virtual void set(Kernel::IPropertyManager* alg, const std::string &name, boost::python::object value) = 0;
/// Is the given object an instance the handler's type
virtual bool isInstance(const boost::python::object&) const = 0;
/// Is the given object a derived type of this objects Type
virtual bool isDerivedType(const boost::python::object & value) const = 0;
/// Return the Python type corresponding to this object. May return NULL
virtual const PyTypeObject * pythonType() const = 0;
};
}
}
}

#endif /* MANTID_PYTHONINTERFACE_PYTHONTYPEHANDLER_H_ */
#endif /* MANTID_PYTHONINTERFACE_PROPERTYVALUEHANDLER_H_ */

0 comments on commit a9ebcae

Please sign in to comment.