7

Suppose I have two boost python modules that are defined as follows. Module A:

class SomeClass {
public:
    SomeClass() {}
    ~SomeClass() {}
};
BOOST_PYTHON_MODULE(A)
{   
    class_<SomeClass>("SomeClass");
}

And module B:

class AnotherClass {
public:
    AnotherClass() {}
    ~AnotherClass() {}
    void func(SomeClass& sp) {}
};
BOOST_PYTHON_MODULE(B)
{   class_<AnotherClass>("AnotherClass")
        .def("func", &AnotherClass::func)
    ;
}

Module B has a dependency on module A (i.e. it uses SomeClass from module A). Now, I execute the following python script:

import A
import B
obj1 = A.SomeClass()
obj2 = B.AnotherClass()
obj2.func(obj1)

I get the following error:

Traceback (most recent call last):
  File "C:\bladiebla\script.py", line 8, in <module>
    obj2.func(obj1)
ArgumentError: Python argument types in
AnotherClass.func(AnotherClass, SomeClass)
did not match C++ signature:
func(class AnotherClass {lvalue}, class SomeClass)

It seems that Python does not automatically translate classes between modules. Does anyone have an idea how to solve this?

Arjan
  • 71
  • 1
  • 3

3 Answers3

7

I just recently started fiddling with Boost.Python and had the same problem.

Check out section 6 of the following doc:

http://www.boost.org/doc/libs/1_47_0/libs/python/doc/building.html

6.1 - The Dynamic Binary

The library contains a type conversion registry. Because one registry is shared among all extension modules, instances of a class exposed to Python in one dynamically-loaded extension module can be passed to functions exposed in another such module.

I was using the static binary and got the same type of error you were getting. Once I changed to the dynamic binary, it compiled and ran fine.

Fat Elvis
  • 441
  • 3
  • 2
0

Based on your latest response and updated error message in your question, I think the problem might be because your BOOST_PYTHON_MODULE usage might be incorrect (based on what I've seen in other examples of using it). Try something like this and see if it helps:

Module A:

class SomeClass {
public:
    SomeClass() {}
    ~SomeClass() {}
};
BOOST_PYTHON_MODULE(A)
{   
    boost::python::class_<SomeClass>("SomeClass");
}

And module B:

class AnotherClass {
public:
    AnotherClass() {}
    ~AnotherClass() {}
    void func(SomeClass& sp) {}
};
BOOST_PYTHON_MODULE(B)
{   boost::python::class_<AnotherClass>("AnotherClass")
        .def("func", &AnotherClass::func)
    ;
}

Note the insertion of a "boost::python::" prefix onto the class_<...> statement in each of the two BOOST_PYTHON_MODULE declarations.

martineau
  • 119,623
  • 25
  • 170
  • 301
  • Hi, thank you very much for your feedback. However, I would like to solve this problem for two classes that do not have an inheritance relationship. For example, you could imagine that 'SomeClass' is in fact a class 'Triangle' and that 'AnotherClass' is the class 'Polygon'. I definitely do not want Polygon to inherit from Triangle, because it doesn't make sense from an OO point of view. So how can I have two classes in different modules that do not inherit from each other, but that use each other through Python, as in my original example? – Arjan Dec 15 '10 at 11:46
  • `func()` wants a `SomeClass` argument. If you want to pass it something different, like `AnotherClass`, you can do so **without** making `AnotherClass` inherit from `SomeClass` by adding a constructor to `SomeClass` that takes an `AnotherClass` as an argument. Alternatively you could just write something that accepted an `AnotherClass` argument and returned a `SomeClass` instance, but would have to call it explicitly. If you can't do something like that then I think you're stuck -- what's `func()` supposed to do anyway, if passed some arbitrary class it knows nothing about? – martineau Dec 15 '10 at 13:02
  • Yes, I understand that, but I do not want to pass anything different to this function, only an argument of type SomeClass. In the python script example, my obj1 is of type A.SomeClass. It is unrelated to B.AnotherClass. 'func' in B.AnotherClass should accept parameters of type A.SomeClass, such as obj1. – Arjan Dec 15 '10 at 13:51
  • If `func()` accepts `AnotherClass` arguments, change its declaration inside `class AnotherClass` in Module B to `void func(AnotherClass& sp)` -- that is its "C++ signature". Afterwards the `obj2.func(obj1)` call should be OK. – martineau Dec 15 '10 at 15:31
  • P.S, The only reason you can get away with changing `func()`'s signature like I suggested is because it doesn't do anything with it's argument since its *defined* (inline) to be an empty function, `{}`, in your sample code. If it accessed its argument and tried to do something with it, the change would likely would not work unless the code can really handle an object of type `AnotherCLass`. – martineau Dec 15 '10 at 15:44
  • I think you misunderstand what I am trying to do. I do not want to pass anything other than an argument of type SomeClass to func(). In the Python script, obj1 is of type SomeClass. I should be able to pass it to func() as a parameter, as I do in the last line of the script. The core of this problem is that module B is not aware of the symbols exported to Python by module A. I'm looking for a way to tell module B that the class SomeClass was exposed to Python by module A. – Arjan Dec 16 '10 at 13:29
  • OK, but I don't think the problem is needing to "tell module B that the class SomeClass was exposed to Python by module A". If you look very closely at the error messages it says that `func()`'s C++ signature requires a `class SomeClass *` second argument which is a *pointer* to a `Someclass` instance -- but looks like it thinks you're trying to pass it an instance *by value* via the `obj2.func(obj1)` statement. – martineau Dec 16 '10 at 19:23
  • You are right. I pasted the wrong error message in the question when I was testing whether perhaps it worked with pointers instead. I put the right error message in the example. This is the error I get when executing the script. – Arjan Dec 20 '10 at 12:36
-1

I had similar issue and solved it by importing module A from module B using boost::python::import() function.

Sachith Muhandiram
  • 2,819
  • 10
  • 45
  • 94
Dmitry
  • 1