Inheritance in SWIG Directors - c++

When I create a SWIG Director for a class A inheriting from class B it fails when the C++ library tries to call methods of class B.
libc++abi.dylib: terminating with uncaught exception of type Swig::DirectorMethodException: SWIG director method error. Error detected when calling 'B.MethodB'
Is there any limitation on SWIG Directors support for classes with multiple levels of inheritance?
UPDATE: The actual code below
class RefCountInterface {
public:
virtual int AddRef() = 0;
virtual int Release() = 0;
protected:
virtual ~RefCountInterface() {}
};
class SessionObserver : public RefCountInterface {
public:
virtual void OnSuccess() = 0;
virtual void OnFailure() = 0;
protected:
~SessionObserver() {}
};
void CreateOffer(SessionObserver* observer); // This ends up calling observer->Release and that raises the exception
%module(directors="1") module
%feature("director") SessionObserver;
Python code:
class MySessionObserver(module.SessionObserver):
def __init__(self, *args, **kwargs):
module.SessionObserver.__init__(self, *args, **kwargs)
self.count = 1
def AddRef(self):
self.count += 1
return self.count
def Release(self):
self.count -= 1
return self.count
def OnSuccess(self, desc):
print "OnSuccess"
def OnFailure(self, err):
print "OnFailure"

Related

Generic dispatcher for multiple classes

I am trying to achieve the same effect in C++. In Python it is so simple to just pass a class method pointer to a dispatcher and to execute the function callback when the specific event occurs. The effect I am looking for is a true generic dispatch class method. Also, the classes should not be related in any way (like in the example below).
class Dispatcher:
def __init__(self):
self.map = {}
def register(self, func, event):
try:
self.map[event].append(func)
except KeyError:
self.map[event] = [func]
def dispatch(self, event):
for func in self.map[event]:
func(event)
class A:
def __init__(self):
pass
def foo(self, event):
print("A", event)
class B:
def __init__(self):
pass
def bar(self, event):
print("B", event)
if __name__ == '__main__':
d = Dispatcher()
a = A()
b = B()
d.register(a.foo, 6)
d.register(b.bar, 6)
d.register(a.foo, 7)
d.dispatch(6)
Expected output:
A 6
B 6
#include <map>
#include <vector>
#include <functional>
using namespace std;
class dispatcher
{
public:
using event_t = int;
using callback_t = function<void(event_t)>;
void register(callback_t c, event_t e)
{
m[e].emplace_back(move(c));
}
void dispatch(event_t e)
{
for(auto&&c: m[e])
c(e);
}
private:
map<event_t, vector<callback_t>> m;
};
You can do something like this. I wrote this in one go on mobile so I have no idea if it works.
That said, this won’t really work exactly the same way as you cannot pass functions that automatically capture the thisptr of an object. You’ll use it as follows, with a functor:
A a;
d.register([&](int i){a.foo(i);}, 6);

boost-python pure virtual detecting missing implementation

I have a C++ class with a pure virtual method exposed to python using boost-python. I am calling the virtual function from C++ and assuming the virtual function is implemented in python. It all works if the function is implemented but if it's not I get a nasty exception.
I am trying to find a way to detect if the method is in fact implemented without calling when I load the class
Roughly the code looks like this
#include <boost/python.hpp>
using namespace boost::python;
public Foo {
public:
void func() = 0;
}
class PyFoo : public Foo, public boost::python::wrapper<Foo> {
public:
void func() override {
get_override("func")();
}
};
BOOST_PYTHON_MODULE(example)
{
using namespace boost::python;
class_<PyFoo>, boost::noncopyable>("Foo")
.def("func", pure_virtual(&PyFoo::func))
;
}
void create {
object main_module = import("__main__");
object main_namespace = main_module.attr("__dict__");
std::string overrideCommand(
R"(
import example
class MyFoo(example.Foo):
def __init__(self):
example.Foo.__init__(self)
# virtual function in C++. (Should be defined)
# def func(self):
# print('func called')
)");
boost::python::exec(overrideCommand.c_str(), main_namespace);
result = eval("MyFoo()", main_namespace);
// Can I detect if 'result' has func implemented? If I call it and it
// is not defined death results. I have tried:
object attr = result.attr("func");
// but attr always seems to be set even if there is no function,
// I think from the base class Foo.
// This is the call:
Foo& t = extract<Foo&>(result);
t.func();
}
You can use PyCallable_Check.
if (!PyCallable_Check(result.func()))
{
PyErr_SetString(PyExc_TypeError, error_msg.str().c_str());
python::throw_error_already_set();
}
I found a solution. Workable not elegant. I added the method:
bool isThere() {
auto obj = get_override("func");
return PyCallable_Check(obj.ptr());
}
to FooPy. Then:
FooPy& t = extract<FooPy&>(result);
t.isThere();

boost.Python How to expose typedef of boost::shared_ptr?

I have a C++ class defined as:
class MyFuture {
public:
virtual bool isDone() = 0;
virtual const std::string& get() = 0;
virtual void onDone(MyCallBack& callBack) = 0;
virtual ~MyFuture() { /* empty */ }
};
typedef boost::shared_ptr<MyFuture> MyFuturePtr;
I expose the class to Python using boost.python as (this class is never created in Python but returned from an API call and thus the noncopyable):
BOOST_PYTHON_MODULE(MySDK)
{
class_<MyFuture, noncopyable>("MyFuture", no_init)
.def("isDone", &MyFuture::isDone)
.def("get", &MyFuture::get, return_value_policy<copy_const_reference>())
.def("onDone", &MyFuture::onDone)
;
}
From python I use it like:
import MySDK
def main():
# more code here ...
future = session.submit()
response = future.get
print response
if __name__ == "__main__":
main()
but this leads to the Python error:
File "main.py", line 14, in main
future = session.submit()
TypeError: No to_python (by-value) converter found for C++ type: class boost::shared_ptr<class MySDK::MyFuture>
How can I expose the typedef typedef boost::shared_ptr<MyFuture> MyFuturePtr;?
UPDATE
Changing the class expose using boost.Python to:
class_<MyFuture, boost::shared_ptr<MyFuture> >("MyFuture", no_init)
leads to the compiler error:
boost\python\converter\as_to_python_function.hpp(21):
error C2259: 'MySDK::MyFuture' : cannot instantiate abstract class
class_<MyFuture, boost::shared_ptr<MyFuture>, boost::noncopyable>("MyFuture")
as per the docs
http://www.boost.org/doc/libs/1_62_0/libs/python/doc/html/reference/high_level_components.html#high_level_components.boost_python_class_hpp.class_template_class_t_bases_hel

How to mock a method call which is being called using setattr during class instantiation?

I have the following class:
class ClassA(Object):
VERSIONS = {
'1': {
'x': a.b.x.X # where x is the module and X is the class
}
}
ATTRS = ['y', 'z']
def __init__(self, **kwargs):
...
do_something...
...
for attr in ATTRS:
setattr(self, attr, VERSIONS[ver][attr]())
I am using the above code as follows:
class_a = ClassA()
class_a.x.y
where x is a module and y is the method in that module
I need to mock this call now. How do I mock it, since the method y is not part of ClassA?
This can be done as follows:
mock_class_a.return_value.x.y = value_to_return

C++-style private access in Scala?

In C++, one can have (please forgive errors as I haven't done C++ in a while and corrections are appreciated):
class Super {
private: virtual void g() = 0;
public: void f() {
g();
}
};
class Sub: public Super {
private: virtual void g() {
}
};
such that Sub defines g but cannot call it directly.
Can the same thing be done in Scala?
If you try it like this
abstract class Super {
private def g()
def f() {
g()
}
}
the compiler will give you this error messge:
scala: abstract member may not have private modifier
private def g()
You have to declare g() at least protected.
I think the closest thing is
abstract class Super {
protected[this] def g: Int
def f { println(g) }
}
class Sub extends Super {
protected[this] def g = 5
}
but this does not give Super any more access rights than Sub; it just prevents Sub from calling that method on other instances.
The exact same pattern is not possible in Scala. (It would have to be a compiler fiction, as the JVM doesn't support it, but many of the access patterns are already compiler fictions.)