Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

wxWidgets inheritance export? #1905

Closed
Suryavarman opened this issue Sep 2, 2019 · 2 comments
Closed

wxWidgets inheritance export? #1905

Suryavarman opened this issue Sep 2, 2019 · 2 comments

Comments

@Suryavarman
Copy link

Suryavarman commented Sep 2, 2019

MyWxClass to python

I use wxWidgets, wxPython and pybind11.

My project code is here: https://framagit.org/Suryavarman/ma/

and here a video

I have create a class from wxControl.

class M_DLL_EXPORT OgreView : public wxControl
{
    public:
            OgreView(wxWindow* parent, wxWindowID id = wxID_ANY, const wxPoint &pos=wxDefaultPosition, const wxSize &size=wxDefaultSize, long style=0,
                     const wxValidator& validator = wxDefaultValidator, const wxString &name=wxPanelNameStr);
[…]
}

Here a part of code to export the OgreView to python.

    py::class_<API::wx::OgreView>(subModule, "wxOgreView")
        .def(py::init<>())
        .def(py::init<>
        (
             [] (py::object inWindow)
             {

                 wxWindow *window = API_Py::wxLoad<wxWindow>(inWindow.release(), "wxWindow");
                 wxASSERT(window);

                 return new API::wx::OgreView(window);
             }
        ), py::arg("inWindow")
        )
        .def("getParentClass", [](const API::wx::OgreView& self){return static_cast<wxControl*>(const_cast<API::wx::OgreView*>(&self));}, py::call_guard<py::gil_scoped_release>(), py::return_value_policy::reference, "Retourne la classe parente de wxOgreView.")
        ;

Here the casters:
wxPy.h
wxPy.tpp
wxPy.cpp

Note: the typed casters are define at the end of wxPy.h file.

M_WX_PY_CASTER(wxWindow, "wx.Window")
M_WX_PY_CASTER_NO_CLASSINFO(wxSize, "wx.Size")
M_WX_PY_CASTER_NO_CLASSINFO(wxPoint, "wx.Point")
M_WX_PY_CASTER(wxValidator, "wx.Validator")
M_WX_PY_CASTER(wxControl, "wx.Control")
M_WX_PY_CASTER(wxAuiNotebook, "wx._aui.AuiNotebook")
M_WX_PY_CASTER(wxFrame, "wx.Frame")

I want to remove the getParentClass to use directly OgreView parent class.
To do that there are two options (see pybind11 documentation)

  1. Load and add the PyObject parent
    py::object py_wx_module = py::module::import("wx");
    py::object py_type_wxControl = static_cast<py::object>(py_wx_module.attr("Control"));
    py::class_<API::wx::OgreView>(subModule, "wxOgreView", py_type_wxControl)
        .def(py::init<>
        (
  1. Load the wxPython module and let the casters working.
py::object py_wx_module = py::module::import("wx");

py::class_<API::wx::OgreView, wxControl>(subModule, "wxOgreView")
 .def(py::init<>
 (

The both doesn't work.

First option:

  1. During the loading module, it's crash here (segmentation fault):

pybind11.h > generic_type::initialize(const type_record &rec)
line: 933

        else if (rec.bases.size() == 1) {
            auto parent_tinfo = get_type_info((PyTypeObject *) rec.bases[0].ptr());
            tinfo->simple_ancestors = parent_tinfo->simple_ancestors;  // <--- crash here line 933
        }

parent_tinfo is null because, get_type_info return a nullptr if the types are not pybind11-registered.
Remark: It will be good to test the parent_tinfo value.

pybnd11/cast.h line 155-167 get_type_info function

// Gets a single pybind11 type info for a python type.  Returns nullptr if neither the type nor any
// ancestors are pybind11-registered.  Throws an exception if there are multiple bases--use
// `all_type_info` instead if you want to support multiple bases.

Second option:

  1. During the loading module, pybind11 send this error:

    ImportError: generic_type: type "wxOgreView" referenced unknown base type "wxControl"

Questions:

What does it mean exactly «pybind11-registered»? Define the caster is not enough?

@Suryavarman
Copy link
Author

Suryavarman commented Sep 3, 2019

If I execute in a python console (in my case inside Pycharm and my Application's console) :

globals()
import wx
globals()

Here a screenshot

At the first globals() call there no 'wx' reference and at the second there a the reference:

'wx': <module 'wx' from

Now if write the same code with pybind11:

auto py_wx_module = py::module::import("wx");
py::print(py::globals());

There no wxWidgets reference.
Therefore I think that's the reason why I can't define the wxWidgets inheritance.

Even though py::module::import("wx") seem work.

auto py_wx_module = py::module::import("wx");

py::object py_type_wxControl = static_cast<py::object>(py_wx_module.attr("Control"));
py::print(py_type_wxControl);

result:

<class 'wx._core.Control'>

@YannickJadoul
Copy link
Collaborator

As far as I know, inheriting C++ from Python classes is not supported. It would be cool if possible, but there's no way we can do that.

Both your original two options fail because of that, I believe.

See #1193 for a further explanation of why this is and what you could do.

Now if write the same code with pybind11:

auto py_wx_module = py::module::import("wx");
py::print(py::globals());

There no wxWidgets reference.
Therefore I think that's the reason why I can't define the wxWidgets inheritance.

No, this is unrelated. This is because the import is not evaluated in the context of globals. This is not an issue.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants