2013-08-30 63 views
1

我想使用PySide定义基本Qt类和python C之间的映射++和,但使用boost :: python的两个独立的Python代码和嵌入式Python这样做。从pyside导入类在boost python模块中的类?

首先,模块定义和类返回QPointF:

QPointF X::getY() { 
    return QPointF(); 
}  

BOOST_PYTHON_MODULE(myBoostPythonModule) 
{ 
// is there some magic init/register commands to put here? 
boost::python::api::object module  = import("__main__"); 
boost::python::api::object name_space = module.attr("__dict__"); 
boost::python::exec("from PySide.QtCore import *",name_space,name_space); 
boost::python::exec("import sys,os\nprint(sys.modules)",name_space,name_space); 

class_<X, boost::noncopyable>(
      "X", init<const char*>()) 
     .def("getY",&X::getY) 
     ; 
} 

现在,应用程序的嵌入Python代码,最后一行就是失败,我不知道怎么去解决:

execute("import myBoostPythonModule");  // OK 
execute("x=myBoostPythonModule.X('foo')"); // OK 

execute("w=QPointF()\nprint(w)");   // OK 
// PySide.QtCore.QPointF(0.000000, 0.000000) 

execute("y=x.getY()");      // FAIL: 
// TypeError: No to_python (by-value) converter found for C++ type: QPointF 

这里发生了什么事情,我可以创建一个QPointF,但是名字在python和C++之间没有绑定?我是否在模块中缺少一些导入来告诉它从PySide导入?

回答

2

PySide提供了Qt的绑定与Shiboken。 Shiboken生成支持其自己的类型转换系统的Python C API绑定。这些转换的知识存在于Shiboken生成的绑定中,而不是Python类型的系统。因此,PySide知道如何将一个QPointF对象转换为C++/Python; Python的类型系统没有。

当通过与Boost.Python的暴露的功能的对象转变,然后Boost.Python的将检查其注册表中的适当的类型转换器。这些转换器为Boost.Python提供了关于如何将通过Boost.Python公开的类型转换为C++/Python的知识。因此,当Boost.Python的尝试将QPointF C++型返回到Python,它抛出作为转换尚未注册与Boost.Python的异常。

下面是注释的代码:

import myBoostPythonModule 
from PySide.QtCore import * 
... 
x=myBoostPythonModule.X('foo') # Boost.Python knows how to convert C++ X 
           # to Python X. Python's type system does not. 

w=QPointF()     # Shiboken knows how to convert C++ QPointF to 
           # Python QPointF. Python's type system does not. 
print(w)      # Shiboken knows how to represent C++ QPointF as 
           # a string. 

y=x.getY()      # Boost.Python knows how to invoke X::getY(), 
           # but only Shiboken knows how to convert C++ 
           # QPointF to Python QPointF. Thus, the TypeError 
           # exception is raised. 

这是可以实现的Boost.Python的converters在另一个实施方面。扩大后的Shiboken type converter example,下面是Shiboken的旧型转换器来实现的Boost.Python的转换器的一个完整的例子。我会使用新的Shiboken类型转换器API,但我不清楚它是基于文档的。

#include <iostream> 

#include <boost/python.hpp> 

/// @brief Mockup Complex class from Shiboken documentation. 
class Complex 
{ 
public: 
    Complex(double real, double imaginary) 
    : real_(real), 
     imaginary_(imaginary) 
    {} 

    double real() const  { return real_;  } 
    double imaginary() const { return imaginary_; } 

private: 
    double real_; 
    double imaginary_; 
}; 

/// @brief Mocked up Shiboken converter. 
namespace Shiboken { 

template <typename> struct Converter; 

template <> struct Converter<Complex> 
{ 
public: 
    // ... 

    static inline bool isConvertible(PyObject* pyObj) 
    { 
    std::cout << "Shiboken::Converter<Complex>::isConvertible()" << std::endl; 
    return PyComplex_Check(pyObj); 
    } 

    // ... 

    static inline PyObject* toPython(const Complex& cpx) 
    { 
    std::cout << "Shiboken::Converter<Complex>::toPython()" << std::endl; 
    return PyComplex_FromDoubles(cpx.real(), cpx.imaginary()); 
    } 

    static inline Complex toCpp(PyObject* pyobj) 
    { 
    std::cout << "Shiboken::Converter<Complex>::toCpp()" << std::endl; 
    double real  = PyComplex_RealAsDouble(pyobj); 
    double imaginary = PyComplex_ImagAsDouble(pyobj); 
    return Complex(real, imaginary); 
    } 
}; 
} // namespace Shiboken 

/// @brief Type used to convert a complex to Python. 
struct complex_converter_to_python 
{ 
    static PyObject* convert(const Complex& c) 
    { 
    // Delegate to Shiboken. 
    std::cout << "complex_converter_to_python::convert()" << std::endl; 
    return Shiboken::Converter<Complex>::toPython(c); 
    } 
}; 

/// @brief Type that registers a Python Complex type to C++ 
///  Complex when passing through Boost.Python. 
struct complex_converter_from_python 
{ 
    /// @note Registers converter from a python complex to C++ complex. 
    complex_converter_from_python() 
    { 
    boost::python::converter::registry::push_back(
     &complex_converter_from_python::convertible, 
     &complex_converter_from_python::construct, 
     boost::python::type_id<Complex>()); 
    } 

    /// @brief Check if PyObject is a Complex. 
    static void* convertible(PyObject* object) 
    { 
    // Delegate to Shiboken. Based on the documentation, the 
    // isConvertible function is gone, so explicit checking may 
    // be required based on the version of Shiboken. 
    std::cout << "complex_converter_from_python::convertible()" << std::endl; 
    return Shiboken::Converter<Complex>::isConvertible(object) 
     ? object 
     : NULL; 
    } 

    /// @brief Convert Python Complex to C++ Complex. 
    static void construct(
    PyObject* object, 
    boost::python::converter::rvalue_from_python_stage1_data* data) 
    { 
    // Obtain a handle to the memory block that the Boost.Python 
    // converter has allocated for the C++ type. 
    namespace python = boost::python; 
    typedef python::converter::rvalue_from_python_storage<Complex> 
                   storage_type; 
    void* storage = reinterpret_cast<storage_type*>(data)->storage.bytes; 

    // In-place construct a Complex type via copy-constructor, passing 
    // in a Complex created from Shiboken. 
    std::cout << "complex_converter_from_python::construct()" << std::endl; 
    data->convertible = new (storage) Complex(
     Shiboken::Converter<Complex>::toCpp(object)); 
    } 
}; 

/// @brief Factory function used to exercise to-python conversion. 
Complex make_complex(double real, double imaginary) 
{ 
    return Complex(real, imaginary); 
} 

/// @brief Printing function used to exercise from-python converison. 
void print_complex(const Complex& c) 
{ 
    std::cout << "In print_complex: " 
      << c.real() << ", " 
      << c.imaginary() << std::endl; 
} 

BOOST_PYTHON_MODULE(example) 
{ 
    namespace python = boost::python; 

    // Register Complex from python converter. 
    complex_converter_from_python(); 

    // Register Complex to python converter. 
    python::to_python_converter< 
    Complex, 
    complex_converter_to_python>(); 

    python::def("make_complex", &make_complex); 
    python::def("print_complex", &print_complex); 
} 

及其用法:

>>> import example 
>>> x = example.make_complex(4, 2) 
complex_converter_to_python::convert() 
Shiboken::Converter<Complex>::toPython() 
>>> example.print_complex(x) 
complex_converter_from_python::convertible() 
Shiboken::Converter<Complex>::isConvertible() 
complex_converter_from_python::construct() 
Shiboken::Converter<Complex>::toCpp() 
In print_complex: 4, 2 

的替代,而不是最优雅的方式,一个人可能从Boost.Python的暴露的功能使用boost::python::object类型,并通过Python语句对象接口。类似的东西到:

boost::python::object X::getY() 
{ 
    return boost::python::exec("QPointF()", ...); 
} 

上面的代码将具有的Python实例化一个QPointF Python对象,这将委托给Shiboken的类型系统。作为X::getY()返回一个通用对象,Boost.Python的将不尝试执行类型转换当对象处理来自C++转变到Python。

+0

但是,是不是有一个全球性的蟒蛇转换器列表?例如,如果您尝试为QString注册两个转换器,则会出现运行时错误。我认为这有一个更优雅的解决方案,它只是从shiboken调用适当的注册函数,例如正如这个人试图在这里做的:http://www.mail-archive.com/[email protected]/msg00952.html –

+1

@peterkarasev:Boost.Python类型转换器的底层注册表是一个单例。我扩展了Boost.Python中转换器的显示答案,以及如何使用另一个API实现它们。在这种情况下,我使用了您提供的链接中提到的API。 –

+0

是的,这是正确的想法,虽然该链接中的API似乎不正确。 “根据对Shiboken :: Conversions和Shiboken :: Module的调用注册boost :: python转换器”是我正常工作的。 –

0

基于早期的答复和其他信息我发现,这里的有些一般常规,让事情像PySide.QtGui.QColor参数得到传递到了需要一个QColor&输入参数一个boost::python包装的C++方法:

template<class QtGuiClass,int SBK_BOGAN_IDX> 
struct QtGui_from_python { 
QtGui_from_python() { 
    qDebug()<<" registering type: " << typeid(this).name() << " in " << __FUNCTION__; 
    boost::python::converter::registry::push_back(
    &convertible, 
    &construct, 
    boost::python::type_id<QtGuiClass>()); 
} 
static void* convertible(PyObject* obj_ptr) { 
    if(!PyObject_TypeCheck(obj_ptr, 
      (PyTypeObject*)XSbkPySide_QtGuiTypes[SBK_BOGAN_IDX])) 
    { qDebug()<<"Failed type check!?"; } 
    return obj_ptr; 
} 
static void construct(PyObject* obj_ptr, 
    bp::converter::rvalue_from_python_stage1_data* data) 
{ 
    void* storage = (
    (boost::python::converter::rvalue_from_python_storage<QtGuiClass>*) 
    data)->storage.bytes; 

    SbkObject* result = reinterpret_cast<SbkObject*>(obj_ptr); 
    auto _ptr = (QtGuiClass*) (Shiboken::Object::cppPointer(
             result,Py_TYPE(result))); 
    new (storage) QtGuiClass(*_ptr); 
    qDebug() << "__alloc'd " << typeid(*_ptr).name() <<" at "<<_ptr; 
    data->convertible = storage; 
} 
}; 

,并在调用上述从启动功能:

QtGui_from_python<QColor,SBK_QCOLOR_IDX>();