python::boost modules over aliases : RecursionError

31 Views Asked by At

So I am working with python boost. The goal for me is to be able to overload c++ functions from python modules. I have managed that, but I have observed a weird behavior when using aliases.

I have recreated a basic examples to reproduce the error :

#include <boost/python.hpp>
#include <iostream>
#include <string>

// CppBase class
class CppBase {
 public:
  CppBase(){};  // Default constructor

  virtual std::string myOverridableCallback() {
    return "Callback triggered from CppBase";  // Default implementation
  }

  virtual void display() {
    std::cout << "CppBase class display function" << std::endl;
    std::cout << this->myOverridableCallback() << std::endl;
  }
};

// CppBase class WRAPPER
struct CppBaseWrap : public CppBase, boost::python::wrapper<CppBase> {
 public:
  virtual std::string myOverridableCallback() override {
    // Check if override is provided in Python
    if (boost::python::override f =
            this->get_override("myOverridableCallback")) {
      return f();  // Call the Python version
    }
    return CppBase::myOverridableCallback();  // Call the Default implementation
  }
};

// CppDerived class
class CppDerived : public CppBase {
 public:
  CppDerived() {}  // Default constructor

  void show() {
    std::cout << "CppDerived class show function" << std::endl;
    std::cout << this->myOverridableCallback() << std::endl;
  }
};

using CppDerivedCopy = CppDerived;

// CppDerived class WRAPPER
struct CppDerivedWrap : public CppDerived, boost::python::wrapper<CppDerived> {
  virtual std::string myOverridableCallback() override {
    // Check if override is provided in Python
    if (boost::python::override f =
            this->get_override("myOverridableCallback")) {
      return f();  // Call the Python version
    }
    return CppBase::myOverridableCallback();  // Call the Default implementation
  }
};

BOOST_PYTHON_MODULE(InheritedFunctionTest) {
  // Expose the CppBase class
  boost::python::class_<CppBaseWrap, boost::noncopyable>("CppBase", boost::python::init<>())
      .def("myOverridableCallback", &CppBaseWrap::myOverridableCallback)
      .def("display", &CppBase::display);

  // Expose the CppDerived class
  boost::python::class_<CppDerivedWrap, boost::python::bases<CppBase>, boost::noncopyable>("CppDerived", boost::python::init<>())
      .def("myOverridableCallback", &CppDerived::myOverridableCallback)
      .def("show", &CppDerived::show);

  // Expose the CppDerivedCopy class
  boost::python::class_<CppDerivedWrap, boost::python::bases<CppBase>, boost::noncopyable>("CppDerivedCopy", boost::python::init<>())
      .def("myOverridableCallback", &CppDerivedCopy::myOverridableCallback)
      .def("show", &CppDerivedCopy::show);
}

So as you can see, I have using CppDerivedCopy = CppDerived;. The idea for me is to be able in python to from InheritedFunctionTest import CppDerivedCopy and have the exact same behavior as if it were CppDerived.

My code compiles, and this is my python basic example:

import sys
sys.path.append('./build')
import InheritedFunctionTest


derived_obj = InheritedFunctionTest.CppDerived()
derived_obj.show()  # Calls show from Derived and myCallback from CppBase

derived_obj2 = InheritedFunctionTest.CppDerivedCopy()
derived_obj2.show()  # Calls show from Derived and myCallback from CppBase

this will trigger following error :

Traceback (most recent call last):
  File "test_script.py", line 13, in <module>
    derived_obj.show()  # Calls show from Derived and myCallback from CppBase
RecursionError: maximum recursion depth exceeded while calling a Python object

So here the InheritedFunctionTest.CppDerived() triggers this error. And here comes the weird behavior, if in my cpp code I had exposed CppDerivedCopy before CppDerived (so simply reversing the last 2 blocs of code in the c++ file), I'd have the same error but on the InheritedFunctionTest.CppDerivedCopy() object, and the InheritedFunctionTest.CppDerived() object did not cause any issue.

So the last of the 2 declarations will have no issues, and the first will have this RecursionError.

I have tried a lot of different things but I don't get the root of the issue, chatGPT doesn't either, and google did not give me much documentation. Any help would be greatly appreciated !! Thanks

1

There are 1 best solutions below

2
Mezaber Yanis On

Please test the modified Boost.Python code provided below to see if it resolves the recursion error. Make sure to replace your existing code with the following changes:

  1. Use call instead of get_override in the myOverridableCallback function.
virtual std::string myOverridableCallback() override {
  namespace bp = boost::python;
  bp::object pyOverride = this->get_override("myOverridableCallback");
  if (pyOverride) {
    return bp::extract<std::string>(pyOverride());
  }
  return CppBase::myOverridableCallback();
}
// Expose the CppBase class
boost::python::class_<CppBaseWrap, boost::noncopyable>("CppBase", boost::python::init<>())
    .def("display", &CppBase::display);

// Expose the CppDerived class
boost::python::class_<CppDerivedWrap, boost::python::bases<CppBase>, boost::noncopyable>("CppDerived", boost::python::init<>())
    .def("myOverridableCallback", &CppDerived::myOverridableCallback)
    .def("show", &CppDerived::show);
// Expose the CppBase class
boost::python::class_<CppBaseWrap, boost::noncopyable>("CppBase", boost::python::init<>())
    .def("display", &CppBase::display)
    .def("myOverridableCallback", &CppBase::myOverridableCallback);

// Expose the CppDerived class
boost::python::class_<CppDerivedWrap, boost::python::bases<CppBase>, boost::noncopyable>("CppDerived", boost::python::init<>())
    .def("show", &CppDerived::show);