mirror of
https://github.com/boostorg/python.git
synced 2026-01-19 16:32:16 +00:00
moved from branch ralf_grosse_kunstleve to trunk
[SVN r9813]
This commit is contained in:
322
include/boost/python/cross_module.hpp
Normal file
322
include/boost/python/cross_module.hpp
Normal file
@@ -0,0 +1,322 @@
|
||||
/* (C) Copyright Ralf W. Grosse-Kunstleve 2001. Permission to copy, use,
|
||||
modify, sell and distribute this software is granted provided this
|
||||
copyright notice appears in all copies. This software is provided
|
||||
"as is" without express or implied warranty, and with no claim as to
|
||||
its suitability for any purpose.
|
||||
|
||||
Revision History:
|
||||
17 Apr 01 merged into boost CVS trunk (Ralf W. Grosse-Kunstleve)
|
||||
*/
|
||||
|
||||
/* Implementation of Boost.Python cross-module support.
|
||||
See root/libs/python/doc/cross_module.html for details.
|
||||
*/
|
||||
|
||||
#ifndef CROSS_MODULE_HPP
|
||||
# define CROSS_MODULE_HPP
|
||||
|
||||
# include <boost/python/class_builder.hpp>
|
||||
|
||||
namespace boost { namespace python {
|
||||
struct import_error : error_already_set {};
|
||||
struct export_error : error_already_set {};
|
||||
}}
|
||||
|
||||
namespace boost { namespace python { namespace detail {
|
||||
|
||||
// Concept: throw exception if api_major is changed
|
||||
// show warning on stderr if api_minor is changed
|
||||
const int export_converters_api_major = 4;
|
||||
const int export_converters_api_minor = 1;
|
||||
extern const char* converters_attribute_name;
|
||||
void* import_converter_object(const std::string& module_name,
|
||||
const std::string& py_class_name,
|
||||
const std::string& attribute_name);
|
||||
void check_export_converters_api(const int importing_major,
|
||||
const int importing_minor,
|
||||
const int imported_major,
|
||||
const int imported_minor);
|
||||
|
||||
}}}
|
||||
|
||||
// forward declaration
|
||||
namespace boost { namespace python { namespace detail {
|
||||
template <class T> class import_extension_class;
|
||||
}}}
|
||||
|
||||
BOOST_PYTHON_BEGIN_CONVERSION_NAMESPACE
|
||||
|
||||
/* This class template is instantiated by import_converters<T>.
|
||||
This class is a look-alike of class python_extension_class_converters.
|
||||
The converters in this class are wrappers that call converters
|
||||
imported from another module.
|
||||
To ensure that the dynamic loader resolves all symbols in the
|
||||
intended way, the signature of all friend functions is changed with
|
||||
respect to the original functions in class
|
||||
python_extension_class_converters by adding an arbitrary additional
|
||||
parameter with a default value, in this case "bool sig = false".
|
||||
See also: comments for class export_converter_object_base below.
|
||||
*/
|
||||
template <class T>
|
||||
class python_import_extension_class_converters
|
||||
{
|
||||
public:
|
||||
|
||||
friend python_import_extension_class_converters py_extension_class_converters(boost::python::type<T>, bool sig = false) {
|
||||
return python_import_extension_class_converters();
|
||||
}
|
||||
|
||||
PyObject* to_python(const T& x) const {
|
||||
return boost::python::detail::import_extension_class<T>::get_converters()->to_python(x);
|
||||
}
|
||||
|
||||
friend T* from_python(PyObject* p, boost::python::type<T*> t, bool sig = false) {
|
||||
return boost::python::detail::import_extension_class<T>::get_converters()->from_python_Ts(p, t);
|
||||
}
|
||||
friend const T* from_python(PyObject* p, boost::python::type<const T*> t, bool sig = false) {
|
||||
return boost::python::detail::import_extension_class<T>::get_converters()->from_python_cTs(p, t);
|
||||
}
|
||||
friend const T* from_python(PyObject* p, boost::python::type<const T*const&> t, bool sig = false) {
|
||||
return boost::python::detail::import_extension_class<T>::get_converters()->from_python_cTscr(p, t);
|
||||
}
|
||||
friend T* from_python(PyObject* p, boost::python::type<T* const&> t, bool sig = false) {
|
||||
return boost::python::detail::import_extension_class<T>::get_converters()->from_python_Tscr(p, t);
|
||||
}
|
||||
friend T& from_python(PyObject* p, boost::python::type<T&> t, bool sig = false) {
|
||||
return boost::python::detail::import_extension_class<T>::get_converters()->from_python_Tr(p, t);
|
||||
}
|
||||
friend const T& from_python(PyObject* p, boost::python::type<const T&> t, bool sig = false) {
|
||||
return boost::python::detail::import_extension_class<T>::get_converters()->from_python_cTr(p, t);
|
||||
}
|
||||
friend const T& from_python(PyObject* p, boost::python::type<T> t, bool sig = false) {
|
||||
return boost::python::detail::import_extension_class<T>::get_converters()->from_python_T(p, t);
|
||||
}
|
||||
|
||||
friend std::auto_ptr<T>& from_python(PyObject* p, boost::python::type<std::auto_ptr<T>&> t, bool sig = false) {
|
||||
return boost::python::detail::import_extension_class<T>::get_converters()->from_python_aTr(p, t);
|
||||
}
|
||||
friend std::auto_ptr<T> from_python(PyObject* p, boost::python::type<std::auto_ptr<T> > t, bool sig = false) {
|
||||
return boost::python::detail::import_extension_class<T>::get_converters()->from_python_aT(p, t);
|
||||
}
|
||||
friend const std::auto_ptr<T>& from_python(PyObject* p, boost::python::type<const std::auto_ptr<T>&> t, bool sig = false) {
|
||||
return boost::python::detail::import_extension_class<T>::get_converters()->from_python_caTr(p, t);
|
||||
}
|
||||
friend PyObject* to_python(std::auto_ptr<T> x, bool sig = false) {
|
||||
return boost::python::detail::import_extension_class<T>::get_converters()->to_python(x);
|
||||
}
|
||||
|
||||
friend boost::shared_ptr<T>& from_python(PyObject* p, boost::python::type<boost::shared_ptr<T>&> t, bool sig = false) {
|
||||
return boost::python::detail::import_extension_class<T>::get_converters()->from_python_sTr(p, t);
|
||||
}
|
||||
friend const boost::shared_ptr<T>& from_python(PyObject* p, boost::python::type<boost::shared_ptr<T> > t, bool sig = false) {
|
||||
return boost::python::detail::import_extension_class<T>::get_converters()->from_python_sT(p, t);
|
||||
}
|
||||
friend const boost::shared_ptr<T>& from_python(PyObject* p, boost::python::type<const boost::shared_ptr<T>&> t, bool sig = false) {
|
||||
return boost::python::detail::import_extension_class<T>::get_converters()->from_python_csTr(p, t);
|
||||
}
|
||||
friend PyObject* to_python(boost::shared_ptr<T> x, bool sig = false) {
|
||||
return boost::python::detail::import_extension_class<T>::get_converters()->to_python(x);
|
||||
}
|
||||
};
|
||||
|
||||
BOOST_PYTHON_END_CONVERSION_NAMESPACE
|
||||
|
||||
namespace boost { namespace python {
|
||||
|
||||
BOOST_PYTHON_IMPORT_CONVERSION(python_import_extension_class_converters);
|
||||
|
||||
/* This class template is instantiated by export_converters().
|
||||
A pointer to this class is exported/imported via the Python API.
|
||||
Using the Python API ensures maximum portability.
|
||||
All member functions are virtual. This is, what we export/import
|
||||
is essentially just a pointer to a vtbl.
|
||||
To work around a deficiency of Visual C++ 6.0, the name of each
|
||||
from_python() member functions is made unique by appending a few
|
||||
characters (derived in a ad-hoc manner from the corresponding type).
|
||||
*/
|
||||
template <class T>
|
||||
struct export_converter_object_base
|
||||
{
|
||||
virtual int get_api_major() const { return detail::export_converters_api_major; }
|
||||
virtual int get_api_minor() const { return detail::export_converters_api_minor; }
|
||||
|
||||
virtual PyObject* to_python(const T& x) = 0;
|
||||
|
||||
virtual T* from_python_Ts(PyObject* p, boost::python::type<T*> t) = 0;
|
||||
virtual const T* from_python_cTs(PyObject* p, boost::python::type<const T*> t) = 0;
|
||||
virtual const T* from_python_cTscr(PyObject* p, boost::python::type<const T*const&> t) = 0;
|
||||
virtual T* from_python_Tscr(PyObject* p, boost::python::type<T* const&> t) = 0;
|
||||
virtual T& from_python_Tr(PyObject* p, boost::python::type<T&> t) = 0;
|
||||
virtual const T& from_python_cTr(PyObject* p, boost::python::type<const T&> t) = 0;
|
||||
virtual const T& from_python_T(PyObject* p, boost::python::type<T> t) = 0;
|
||||
|
||||
virtual std::auto_ptr<T>& from_python_aTr(PyObject* p, boost::python::type<std::auto_ptr<T>&> t) = 0;
|
||||
virtual std::auto_ptr<T> from_python_aT(PyObject* p, boost::python::type<std::auto_ptr<T> > t) = 0;
|
||||
virtual const std::auto_ptr<T>& from_python_caTr(PyObject* p, boost::python::type<const std::auto_ptr<T>&> t) = 0;
|
||||
virtual PyObject* to_python(std::auto_ptr<T> x) = 0;
|
||||
|
||||
virtual boost::shared_ptr<T>& from_python_sTr(PyObject* p, boost::python::type<boost::shared_ptr<T>&> t) = 0;
|
||||
virtual const boost::shared_ptr<T>& from_python_sT(PyObject* p, boost::python::type<boost::shared_ptr<T> > t) = 0;
|
||||
virtual const boost::shared_ptr<T>& from_python_csTr(PyObject* p, boost::python::type<const boost::shared_ptr<T>&> t) = 0;
|
||||
virtual PyObject* to_python(boost::shared_ptr<T> x) = 0;
|
||||
};
|
||||
|
||||
// Converters to be used if T is not copyable.
|
||||
template <class T>
|
||||
struct export_converter_object_noncopyable : export_converter_object_base<T>
|
||||
{
|
||||
virtual PyObject* to_python(const T& x) {
|
||||
PyErr_SetString(PyExc_RuntimeError,
|
||||
"to_python(const T&) converter not exported");
|
||||
throw import_error();
|
||||
}
|
||||
|
||||
virtual T* from_python_Ts(PyObject* p, boost::python::type<T*> t) {
|
||||
return BOOST_PYTHON_CONVERSION::from_python(p, t);
|
||||
}
|
||||
virtual const T* from_python_cTs(PyObject* p, boost::python::type<const T*> t) {
|
||||
return BOOST_PYTHON_CONVERSION::from_python(p, t);
|
||||
}
|
||||
virtual const T* from_python_cTscr(PyObject* p, boost::python::type<const T*const&> t) {
|
||||
return BOOST_PYTHON_CONVERSION::from_python(p, t);
|
||||
}
|
||||
virtual T* from_python_Tscr(PyObject* p, boost::python::type<T* const&> t) {
|
||||
return BOOST_PYTHON_CONVERSION::from_python(p, t);
|
||||
}
|
||||
virtual T& from_python_Tr(PyObject* p, boost::python::type<T&> t) {
|
||||
return BOOST_PYTHON_CONVERSION::from_python(p, t);
|
||||
}
|
||||
virtual const T& from_python_cTr(PyObject* p, boost::python::type<const T&> t) {
|
||||
return BOOST_PYTHON_CONVERSION::from_python(p, t);
|
||||
}
|
||||
virtual const T& from_python_T(PyObject* p, boost::python::type<T> t) {
|
||||
return BOOST_PYTHON_CONVERSION::from_python(p, t);
|
||||
}
|
||||
|
||||
virtual std::auto_ptr<T>& from_python_aTr(PyObject* p, boost::python::type<std::auto_ptr<T>&> t) {
|
||||
return BOOST_PYTHON_CONVERSION::from_python(p, t);
|
||||
}
|
||||
virtual std::auto_ptr<T> from_python_aT(PyObject* p, boost::python::type<std::auto_ptr<T> > t) {
|
||||
return BOOST_PYTHON_CONVERSION::from_python(p, t);
|
||||
}
|
||||
virtual const std::auto_ptr<T>& from_python_caTr(PyObject* p, boost::python::type<const std::auto_ptr<T>&> t) {
|
||||
return BOOST_PYTHON_CONVERSION::from_python(p, t);
|
||||
}
|
||||
virtual PyObject* to_python(std::auto_ptr<T> x) {
|
||||
return BOOST_PYTHON_CONVERSION::to_python(x);
|
||||
}
|
||||
|
||||
virtual boost::shared_ptr<T>& from_python_sTr(PyObject* p, boost::python::type<boost::shared_ptr<T>&> t) {
|
||||
return BOOST_PYTHON_CONVERSION::from_python(p, t);
|
||||
}
|
||||
virtual const boost::shared_ptr<T>& from_python_sT(PyObject* p, boost::python::type<boost::shared_ptr<T> > t) {
|
||||
return BOOST_PYTHON_CONVERSION::from_python(p, t);
|
||||
}
|
||||
virtual const boost::shared_ptr<T>& from_python_csTr(PyObject* p, boost::python::type<const boost::shared_ptr<T>&> t) {
|
||||
return BOOST_PYTHON_CONVERSION::from_python(p, t);
|
||||
}
|
||||
virtual PyObject* to_python(boost::shared_ptr<T> x) {
|
||||
return BOOST_PYTHON_CONVERSION::to_python(x);
|
||||
}
|
||||
};
|
||||
|
||||
// The addditional to_python() converter that can be used if T is copyable.
|
||||
template <class T>
|
||||
struct export_converter_object : export_converter_object_noncopyable<T>
|
||||
{
|
||||
virtual PyObject* to_python(const T& x) {
|
||||
return BOOST_PYTHON_CONVERSION::py_extension_class_converters(boost::python::type<T>()).to_python(x);
|
||||
}
|
||||
};
|
||||
|
||||
namespace detail {
|
||||
|
||||
/* This class template is instantiated by import_converters<T>.
|
||||
Its purpose is to import the converter_object via the Python API.
|
||||
The actual import is only done once. The pointer to the
|
||||
imported converter object is kept in the static data member
|
||||
imported_converters.
|
||||
*/
|
||||
template <class T>
|
||||
class import_extension_class
|
||||
: public python_import_extension_class_converters<T>
|
||||
{
|
||||
public:
|
||||
inline import_extension_class(const char* module, const char* py_class) {
|
||||
m_module = module;
|
||||
m_py_class = py_class;
|
||||
}
|
||||
|
||||
static boost::python::export_converter_object_base<T>* get_converters();
|
||||
|
||||
private:
|
||||
static std::string m_module;
|
||||
static std::string m_py_class;
|
||||
static boost::python::export_converter_object_base<T>* imported_converters;
|
||||
};
|
||||
|
||||
template <class T> std::string import_extension_class<T>::m_module;
|
||||
template <class T> std::string import_extension_class<T>::m_py_class;
|
||||
template <class T>
|
||||
boost::python::export_converter_object_base<T>*
|
||||
import_extension_class<T>::imported_converters = 0;
|
||||
|
||||
template <class T>
|
||||
boost::python::export_converter_object_base<T>*
|
||||
import_extension_class<T>::get_converters() {
|
||||
if (imported_converters == 0) {
|
||||
void* cobject
|
||||
= import_converter_object(m_module, m_py_class,
|
||||
converters_attribute_name);
|
||||
imported_converters
|
||||
= static_cast<boost::python::export_converter_object_base<T>*>(cobject);
|
||||
check_export_converters_api(
|
||||
export_converters_api_major,
|
||||
export_converters_api_minor,
|
||||
imported_converters->get_api_major(),
|
||||
imported_converters->get_api_minor());
|
||||
}
|
||||
return imported_converters;
|
||||
}
|
||||
|
||||
}}} // namespace boost::python::detail
|
||||
|
||||
namespace boost { namespace python {
|
||||
|
||||
// Implementation of export_converters().
|
||||
template <class T, class U>
|
||||
void export_converters(class_builder<T, U>& cb)
|
||||
{
|
||||
static export_converter_object<T> export_cvts;
|
||||
cb.add(
|
||||
ref(PyCObject_FromVoidPtr(reinterpret_cast<void*>(&export_cvts), NULL)),
|
||||
detail::converters_attribute_name);
|
||||
}
|
||||
|
||||
// Implementation of export_converters_noncopyable().
|
||||
template <class T, class U>
|
||||
void export_converters_noncopyable(class_builder<T, U>& cb)
|
||||
{
|
||||
static export_converter_object_noncopyable<T> export_cvts;
|
||||
cb.add(
|
||||
ref(PyCObject_FromVoidPtr(reinterpret_cast<void*>(&export_cvts), NULL)),
|
||||
detail::converters_attribute_name);
|
||||
}
|
||||
|
||||
// Implementation of import_converters<T>.
|
||||
template <class T>
|
||||
class import_converters
|
||||
: python_import_extension_class_converters<T> // Works around MSVC6.x/GCC2.95.2 bug described
|
||||
// at the bottom of class_builder.hpp.
|
||||
{
|
||||
public:
|
||||
import_converters(const char* module, const char* py_class)
|
||||
: m_class(new detail::import_extension_class<T>(module, py_class))
|
||||
{ }
|
||||
private:
|
||||
boost::shared_ptr<detail::import_extension_class<T> > m_class;
|
||||
};
|
||||
|
||||
}} // namespace boost::python
|
||||
|
||||
#endif // CROSS_MODULE_HPP
|
||||
87
src/cross_module.cpp
Normal file
87
src/cross_module.cpp
Normal file
@@ -0,0 +1,87 @@
|
||||
/* (C) Copyright Ralf W. Grosse-Kunstleve 2001. Permission to copy, use,
|
||||
modify, sell and distribute this software is granted provided this
|
||||
copyright notice appears in all copies. This software is provided
|
||||
"as is" without express or implied warranty, and with no claim as to
|
||||
its suitability for any purpose.
|
||||
|
||||
Revision History:
|
||||
17 Apr 01 merged into boost CVS trunk (Ralf W. Grosse-Kunstleve)
|
||||
*/
|
||||
|
||||
# include <boost/python/cross_module.hpp>
|
||||
namespace python = boost::python;
|
||||
# include <stdio.h> // MSVC6.0SP4 does not know std::fprintf
|
||||
# include <string.h> // MSVC6.0SP4 does not know std::strcmp
|
||||
|
||||
namespace {
|
||||
|
||||
PyObject* get_module_dict(const char* module_name)
|
||||
{
|
||||
python::ref module_obj(PyImport_ImportModule((char*) module_name));
|
||||
PyObject* module_dict = PyModule_GetDict(module_obj.get());
|
||||
if (module_dict == 0) throw python::import_error();
|
||||
return module_dict;
|
||||
}
|
||||
}
|
||||
|
||||
namespace boost { namespace python { namespace detail {
|
||||
|
||||
const char* converters_attribute_name = "__converters__";
|
||||
|
||||
void* import_converter_object(const std::string& module_name,
|
||||
const std::string& py_class_name,
|
||||
const std::string& attribute_name)
|
||||
{
|
||||
static std::string err;
|
||||
PyObject* module_dict = get_module_dict(const_cast<char*>(module_name.c_str()));
|
||||
PyObject* py_class = PyDict_GetItemString(module_dict, const_cast<char*>(py_class_name.c_str()));
|
||||
if (py_class == 0) {
|
||||
err = std::string("module ") + module_name + " has no attribute " + py_class_name;
|
||||
PyErr_SetString(PyExc_RuntimeError, const_cast<char*>(err.c_str()));
|
||||
throw python::import_error();
|
||||
}
|
||||
python::ref c_obj(PyObject_GetAttrString(py_class, const_cast<char*>(attribute_name.c_str())), ref::null_ok);
|
||||
if (c_obj.get() == 0) {
|
||||
err = std::string("object ") + module_name + "." + py_class_name
|
||||
+ " has no attribute " + attribute_name;
|
||||
PyErr_SetString(PyExc_RuntimeError, const_cast<char*>(err.c_str()));
|
||||
throw python::import_error();
|
||||
}
|
||||
if (! PyCObject_Check(c_obj.get())) {
|
||||
err = std::string("object ") + module_name + "." + py_class_name + "."
|
||||
+ attribute_name + " is not a PyCObject";
|
||||
PyErr_SetString(PyExc_RuntimeError, const_cast<char*>(err.c_str()));
|
||||
throw python::import_error();
|
||||
}
|
||||
return PyCObject_AsVoidPtr(c_obj.get());
|
||||
}
|
||||
|
||||
void check_export_converters_api(const int importing_major,
|
||||
const int importing_minor,
|
||||
const int imported_major,
|
||||
const int imported_minor)
|
||||
{
|
||||
if (importing_major != imported_major) {
|
||||
// Python uses fprintf(stderr, ...) for API warnings.
|
||||
fprintf(stderr,
|
||||
"Fatal: export_converters_api mismatch:"
|
||||
" Importing module = %d.%d"
|
||||
" Imported module = %d.%d\n",
|
||||
importing_major, importing_minor,
|
||||
imported_major, imported_minor);
|
||||
PyErr_SetString(PyExc_RuntimeError,
|
||||
"Fatal: export_converters_api mismatch");
|
||||
throw import_error();
|
||||
}
|
||||
if (importing_minor != imported_minor) {
|
||||
// Python uses fprintf(stderr, ...) for API warnings.
|
||||
fprintf(stderr,
|
||||
"Warning: export_converters_api mismatch:"
|
||||
" Importing module = %d.%d"
|
||||
" Imported module = %d.%d\n",
|
||||
importing_major, importing_minor,
|
||||
imported_major, imported_minor);
|
||||
}
|
||||
}
|
||||
|
||||
}}} // namespace boost::python::detail
|
||||
Reference in New Issue
Block a user