Skip to content
Advertisement

Python boost to-Python converter for class already registered second conversion method ignored

I have next class (it was simplified):

class Value
{
    public:

    Value();
    ~Value();

    void setValue(int value);
    void setValue(double value);
}

I have python boost module:

#include <boost/python.hpp>
#include <boost/python/suite/indexing/vector_indexing_suite.hpp>
#include <boost/python/suite/indexing/map_indexing_suite.hpp>

BOOST_PYTHON_MODULE(py_classes) 
{
    typedef std::vector<Value> VectorClass;

    boost::python::type_info infoVectorValue = boost::python::type_id<VectorClass>();

    const boost::python::converter::registration* regVectorValue = boost::python::converter::registry::query(infoVectorValue);

    if (regVectorValue == NULL || (*regVectorValue).m_to_python == NULL) {
        class_<VectorClass>("std_vector_value")
            .def(vector_indexing_suite<VectorClass>());
    }
}

Python script is called from dll library and uses container from pyd py_classes. When dll-library is called first time std_vector_value type is used without any problems. When I reload dll-library inside executable I get next warning:

RuntimeWarning: to-Python converter for class
boost::python::detail::container_element<class std::vector<class Value,class std::allocator<class Value> >,
unsigned __int64,class boost::python::detail::final_vector_derived_policies
<class std::vector<class Value,
class std::allocator<class Value> >,0> > 
already registered; second conversion method ignored.
return f(*args, **kwds)

So, it means:

  • When dll-library is loaded first time, to-python converter is registered normally and python script can use std_vector_value type.
  • When dll-library is reloaded (FreeLibrary and LoadLibrary functions), to-python converter trying to register one more time and checking if it was registered says that it has been already registered, but I can’t use std_vector_value type from python.

And this situation appears only for container classes (if I use std::vector or std::map – generally if I use vector_indexing_suite or map_indexing_suite), for class Value this warning doesn’t appear.

What am I doing wrong?

Advertisement

Answer

Problem was next: boost python was loaded from one exe-process, but by different DLL-libraries. It means I had 3 DLL-libraries that executed python scripts. Python boost types worked without any problem until DLL-libraries were reloaded (calling FreeLibrary and LoadLibrary inside process without process relaunching). Python boost has static variable register (register is the name of this variable) stores references to python boost types. When executable is launched, references to types are added to the static variable register. So, this check works normally:

boost::python::type_info infoVectorValue = boost::python::type_id<VectorClass>();
const boost::python::converter::registration* regVectorValue = boost::python::converter::registry::query(infoVectorValue);
if (regVectorValue == NULL || (*regVectorValue).m_to_python == NULL) {

But when DLL-libraries are unloaded, references to these python boost types are left inside the static variable register and they lead to DLL-library addresses that were freed. It means when library is loaded again, types checking gets reference for needed type (VectorClass in my example) without problems, but this reference has already broken.

So, the solution for this problem is to link boost python library statically to each DLL-library – each DLL-library has it’s own static variable register and boost python types references are created for each DLL-library and when DLL-library is unloaded, register variable is destroyed for this DLL.

User contributions licensed under: CC BY-SA
6 People found this is helpful
Advertisement