импортировать классы из pyside внутри модуля python boost?

Я хотел бы использовать PySide для определения основных классов QT и отображения между C ++ и python, но сделать это как в автономном коде Python, так и из встроенного Python с использованием 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?

1

Решение

PySide предоставляет свои привязки Qt Shiboken. Shiboken генерирует привязки Python C API, поддерживающие его собственную систему преобразования типов. Знание этих преобразований находится в сгенерированных привязках Shiboken, а не в системе типов Python. Таким образом, PySide знает, как конвертировать QPointF объект в / из C ++ / Python; Система типов Python этого не делает.

Когда объект переходит через функцию, предоставляемую Boost.Python, Boost.Python проверит свой реестр на наличие соответствующего конвертера типов. Эти конвертеры предоставляют Boost.Python знания о том, как конвертировать в / из C ++ / Python для типов, предоставляемых через Boost.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’s преобразователи с точки зрения другой реализации. Расширение на Пример преобразователя типа Шибокен, ниже приведен полный пример преобразователей Boost.Python, реализованных с помощью старого преобразователя типов Shiboken. Я бы использовал новый API конвертера типов Shiboken, но мне было неясно, на чем он основан на документации.

#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.

2

Другие решения

Основываясь на предыдущих ответах и ​​другой информации, которую я нашел, вот несколько общих правил, позволяющих такие вещи, как PySide.QtGui.QColor аргумент, чтобы передать в boost::python обернутый метод C ++, который ожидает QColor& входной аргумент:

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>();
0

По вопросам рекламы [email protected]