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);
Related
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();
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
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"
given a domain constellation like this:
abstract class A {
def myService
def beforeInsert() {
myService.doIt()
}
}
class B extends A {
def beforeInsert() {
super.beforeInsert()
}
}
Is it possible to mock the following methods:
- beforeInsert() in B?
- beforeInsert() in A?
For making service method calls optional for unit testing the easiest thing to do is to use null safe method calls:
abstract class A {
def myService
static transients = ['myService']
def beforeInsert() {
myService?.doIt()
}
}
class B extends A {
def beforeInsert() {
super.beforeInsert()
}
}
Save B objects without flushing in unit tests or
override beforeInsert by metaClass:
B.metaClass.beforeInsert = {-> }
this is my first post :). I could convert a python extended object into a C++ pointer, but I have a problem. First I will show you my code and then I will explain the problem.
This is my class:
#include <boost/python.hpp>
using namespace boost::python;
class Base
{
public:
virtual const char* HelloWorld() = 0;
};
class BaseWrapper : public Base, public wrapper<BaseWrapper>
{
public:
virtual const char* HelloWorld()
{
if (override f = this->get_override("HelloWorld"))
return call<const char*>(f.ptr());
return "FAILED TO CALL";
}
};
Boost wrapping:
BOOST_PYTHON_MODULE(hello_ext)
{
class_<Base, boost::noncopyable>("Base", no_init);
class_<BaseWrapper, bases<Base> >("BaseWrapper")
.def("HelloWorld", &BaseWrapper::HelloWorld);
}
The Python code (hello.py):
def NewDerived():
import hello_ext
class Derived(hello_ext.BaseWrapper):
def __init__(self):
super(Derived, self).__init__()
def HelloWorld(self):
return "This is a Hello World!!!"
return Derived()
and the main file:
int main()
{
// Start the interpreter.
Py_Initialize();
// Import the module that we need (hello.py)
object module = import("hello");
// Get a C++ pointer of the derived python class.
Base* base = extract< Base* >( module.attr("NewDerived")() );
// Call the HelloWorld function
std::cout << base->HelloWorld() << std::endl;
}
When I run my application I can see at the screen "This is a Hello World!!!" as I expected.
So, what is the problem??? Suppose I change the python code to:
def NewDerived():
import hello_ext
class Derived(hello_ext.BaseWrapper):
def __init__(self):
super(Derived, self).__init__()
def HelloWorld(self):
return "This is a Hello" # I CHANGED THIS LINE!!!!
return Derived()
Then, when I run my application again, it crashes, because I got an error in the line:
std::cout << base->HelloWorld() << std::endl;
because base is NULL.
More precisely, the error is "Access violation reading location 0xblablabla".
When I debug, the debugguer stops at the function (Boost or Python code, I think)
inline api::object_base::~object_base()
{
Py_DECREF(m_ptr);
}
What do you think???
Finally, another programmer explained me the solution.
I don't know why it worked originally, but the problem is that the object is getting destroyed before I try calling the member function. I need to break the extract call into two parts like so:
object derived = module.attr("NewDerived")();
Base* base = extract< Base* >( derived );
This will keep the object around long enough for me to actually call functions on it.