Hello everybody, I am using Boost.python to interface a C++ set of classes. In one of my C+++ class, I am calling a method implemented in Python with the boost "call_method" call. This method has one parameter of our own data type and return a pointer to this type. I have installed converters for this type as it is adviced in the FAQ "How can I automatically convert my custom string type..." If I call my method like this MyType *ret = call_method<MyType *>(my_py_obj,"My_method", my_ptr) With my_ptr being a MyType *, it works. But if I call it like this MyType *ret = call_method<MyType *>(my_py_obj,"My_method", ptr(my_ptr)) to avoid a copy, I received a run time error complaining that "No Python class registered for C++..." Could someone explain me why it works in the first case and not in the second one. Many thanks in advance Emmanuel Taurel (etaurel@cells.es)
Emmanuel Taurel wrote:
Hello everybody,
I am using Boost.python to interface a C++ set of classes. In one of my C+++ class, I am calling a method implemented in Python with the boost “call_method” call. This method has one parameter of our own data type and return a pointer to this type. I have installed converters for this type as it is adviced in the FAQ “How can I automatically convert my custom string type…..” If I call my method like this
MyType *ret = call_method<MyType *>(my_py_obj,”My_method”, my_ptr)
With my_ptr being a MyType *, it works. But if I call it like this
MyType *ret = call_method<MyType *>(my_py_obj,”My_method”, ptr(my_ptr)) to avoid a copy, I received a run time error complaining that
“No Python class registered for C++…..”
I believe the reason is that strings in python are non-mutable, meaning that you can't modify them in-place. Instead, string variables are rebound to a new value when you modify them. That is incompatible with the way you want your string type to be handled. Regards, Stefan
Hello Stefan, Thank's for your answer, but I don't use string at all. The data type I am using is our own data type. The problem I have is with the usage of My_ptr or ptr(My_ptr) in the last parameter of the boost call_method. Regards, Emmanuel Taurel (etaurel@cells.es) -----Original Message----- From: c++-sig-bounces@python.org [mailto:c++-sig-bounces@python.org] On Behalf Of Stefan Seefeld Sent: Wednesday, October 26, 2005 3:45 PM To: Development of Python/C++ integration Subject: Re: [C++-sig] Problem using the ptr() function Emmanuel Taurel wrote:
Hello everybody,
I am using Boost.python to interface a C++ set of classes. In one of my C+++ class, I am calling a method implemented in Python with the boost "call_method" call. This method has one parameter of our own data type and return a pointer to this type. I have installed converters for this type as it is adviced in the FAQ "How can I automatically convert my custom string type..." If I call my method like this
MyType *ret = call_method<MyType *>(my_py_obj,"My_method", my_ptr)
With my_ptr being a MyType *, it works. But if I call it like this
MyType *ret = call_method<MyType *>(my_py_obj,"My_method", ptr(my_ptr)) to avoid a copy, I received a run time error complaining that
"No Python class registered for C++..."
I believe the reason is that strings in python are non-mutable, meaning that you can't modify them in-place. Instead, string variables are rebound to a new value when you modify them. That is incompatible with the way you want your string type to be handled. Regards, Stefan _______________________________________________ C++-sig mailing list C++-sig@python.org http://mail.python.org/mailman/listinfo/c++-sig
Emmanuel Taurel <etaurel@cells.es> writes:
Hello everybody,
I am using Boost.python to interface a C++ set of classes. In one of my C+++ class, I am calling a method implemented in Python with the boost "call_method" call. This method has one parameter of our own data type and return a pointer to this type. I have installed converters for this type as it is adviced in the FAQ "How can I automatically convert my custom string type..." If I call my method like this
MyType *ret = call_method<MyType *>(my_py_obj,"My_method", my_ptr)
With my_ptr being a MyType *, it works. But if I call it like this
MyType *ret = call_method<MyType *>(my_py_obj,"My_method", ptr(my_ptr)) to avoid a copy, I received a run time error complaining that
"No Python class registered for C++..."
Could someone explain me why it works in the first case and not in the second one.
Please post a minimal, complete, reproducible testcase: one C++ file, one Python file, the result you expect and the result you got. Thanks, -- Dave Abrahams Boost Consulting www.boost-consulting.com
Hi Dave, I have attached to this e-mail five files which demonstrates my problem. These files are : 1 - ds.h : The C++ include file 2 - ds.cpp : The C++ implementation 3 - py_ds.cpp : The boost interface stuff 4 - py_ds.h : The boost interface include file 5 - main.py : The python code I am a beginner in both Python and boost. Therefore, they are certainly some piece of code in these files that you will find strange... I have isolated the problem as far as I am able to. If in file de.cpp, I use line 16, the python code outputs are ------------------------------------------------------------ In init_module function Conversion from MyStrArray to python installed in Boost In Device constructor with string a/b/c in the MyStrArray convert function to_python Input args = The first string Input args = The second string ------------------------------------------------------------ And it is correct. If I use line 15 (using the ptr() function), the python code outputs are ----------------------------------------------------------- In init_module function Conversion from MyStrArray to python installed in Boost In Device constructor with string a/b/c Traceback (most recent call last): File "main.py", line 23, in ? c.execute_device_method() TypeError: No Python class registered for C++ class std::vector<std::string, std::allocator<std::string> > ------------------------------------------------------------ The principle of this software is : I create one python instance of the "MyContainer" class. Then I create one instance of the "MyDevice" class which is stored in a data member of the C++ class from which MyContainer inherits from. This is done by calling the create_device() method of the MyContainer object in the python code. Then, I call the execute_device_method() of the MyContainer class which is coded in C++ and which callback one of the MyDevice method defined in Python. This is this callback (C++ calls a Python method) which fails if I use the ptr() function. You will also certainly notice that I have installed my own converters
From my type which in this small example is a vector<string>. In the real application, it is not a vector<string> but something more complicated.
Thank's for your help Emmanuel Taurel (etaurel@cells.es) -----Original Message----- From: c++-sig-bounces@python.org [mailto:c++-sig-bounces@python.org] On Behalf Of David Abrahams Sent: Thursday, October 27, 2005 1:40 PM To: c++-sig@python.org Subject: Re: [C++-sig] Problem using the ptr() function Emmanuel Taurel <etaurel@cells.es> writes:
Hello everybody,
I am using Boost.python to interface a C++ set of classes. In one of my C+++ class, I am calling a method implemented in Python with the boost "call_method" call. This method has one parameter of our own data type and return a pointer to this type. I have installed converters for this type as it is adviced in the FAQ "How can I automatically convert my custom string type..." If I call my method like this
MyType *ret = call_method<MyType *>(my_py_obj,"My_method", my_ptr)
With my_ptr being a MyType *, it works. But if I call it like this
MyType *ret = call_method<MyType *>(my_py_obj,"My_method", ptr(my_ptr)) to avoid a copy, I received a run time error complaining that
"No Python class registered for C++..."
Could someone explain me why it works in the first case and not in the second one.
Please post a minimal, complete, reproducible testcase: one C++ file, one Python file, the result you expect and the result you got. Thanks, -- Dave Abrahams Boost Consulting www.boost-consulting.com _______________________________________________ C++-sig mailing list C++-sig@python.org http://mail.python.org/mailman/listinfo/c++-sig
Emmanuel Taurel <etaurel@cells.es> writes:
Hi Dave,
I have attached to this e-mail five files which demonstrates my problem. These files are : 1 - ds.h : The C++ include file 2 - ds.cpp : The C++ implementation 3 - py_ds.cpp : The boost interface stuff 4 - py_ds.h : The boost interface include file 5 - main.py : The python code
Emmanuel, I asked for two files. Could you please save me the effort of consolidating these? Could you please also make an effort to reduce the code even further? Just the minimum amount to show the part that doesn't work, please. I don't need to see code that does work. Please also, as I asked, post the result you expect and the result you actually got. Thanks. -- Dave Abrahams Boost Consulting www.boost-consulting.com
Hello everybody, As requested by Dave, I have reduced my example as far as I can. Sorry for the very, very long response time.... I recall my problem: I have a C++ class called Device. In the Python world, I create a class inheriting from this C++ class (called MyDevice) and I create one python method in this new class which is called "a_new_method". This python method receives one parameter of a type for which I have installed Boost converter. The type is called "MyStrArray" The Python code creates one instance of the MyDevice class and call its C++ method called "execute_device_method". This C++ method callback the new "a_new_method" python code with the help of the Boost call_method() function. If, when calling back the new Python method, I am using the Boost ptr() Function, I have a run-time error: Traceback (most recent call last): File "main.py", line 13, in ? d.execute_device_method() TypeError: No Python class registered for C++ class std::vector<std::string, std::allocator<std::string> > If I don't use the Boost ptr() function, everything works fine and the "a_new_method" Python method is executed correctly. I have added to this file two files which are the Python and the C++ code. Thank's for your help Sincerely Emmanuel Taurel (etaurel@cells.es)
Emmanuel Taurel <etaurel@cells.es> writes:
As requested by Dave, I have reduced my example as far as I can.
Your example can still be reduced a *lot* further. You could start by taking out all the use of std::cout. I doubt you need a loop in a_new_method. Next time, please remove *all* unnecessary code and get it down to the bare minimum required to exhibit the behavior you don't expect. Anyway, this time the problem is pretty straightforward. Basically, ptr(p) will only work when the type of *p has been exported with class_. In that case, Python ends up with an object of some Python type corresponding to the C++ type of *p, containing a copy of p. You are converting MyStrArray to and from a Python list instead of wrapping it as a class. There's no way that modifications to a regular python list will be able to automatically affect *p. In the past it has been requested that we support "write-back" converters that let you convert, e.g., a MyStrArray to a Python list, and then, when the call completes, convert the list back to a MyStrArray. We don't support that yet, but since you're actually doing the call from Python to C++, it's easy for you to fake it: python::list send_msa_(send_msa); // convert to a Python list call_method<void>(dev_ptr->m_self.get(),"a_new_method", send_msa_); send_msa = extract<MyStrArray>(send_msa_); BTW, something about class DeviceWrap : public Device, public wrapper<Device> { public: DeviceWrap(PyObject *self):Device(),m_self(borrowed(self)) {}; DeviceWrap(PyObject *self, const string &na):Device(na),m_self(borrowed(self)) {}; handle<> m_self; }; looks very wrong. If you're using wrapper<...> there's almost never cause for an initial self argument, and storing it in a handle<> is almost guaranteed to result in a leak or a reference counting error. I would unconditionally drop handle<>, and either try to make wrapper<Device> work by itself, using get_override to get ahold of a_new_method, or drop wrapper<Device> store a raw PyObject* in lieu of handle<>, specializing has_back_reference for Device. In this case the latter approach might be better, by allowing you to get rid of the artificial derived class and the dangerous downcast. Good luck, Dave -- Dave Abrahams Boost Consulting www.boost-consulting.com
participants (3)
-
David Abrahams -
Emmanuel Taurel -
Stefan Seefeld