[C++-sig] Re: Converting CString to/from std::string

Martin Blais blais at iro.umontreal.ca
Wed Sep 24 21:09:50 CEST 2003


Me again.

I wrapped up the ugly bits of the automated conversion to do some of
the cooking automatically.  I use it like this, for an hypothetical
MyPath class for which I want to declare automatic conversion to/from
a string (without exposing MyPath)::

   template <>
   python::object AutoConverter<MyPath>::toObject( MyPath const& s )
   {
      return python::str( s.cstr() );
   }

   template <>
   void* AutoConverter<MyPath>::convertible( PyObject* obj_ptr )
   {
      if ( !PyString_Check(obj_ptr) ) return 0;
      return obj_ptr;
   }

   template <>
   void AutoConverter<MyPath>::fromPython(
      PyObject* obj_ptr,
      void*     memblock
   )
   {
      const char* value = PyString_AsString( obj_ptr );
      if (value == 0) {
         python::throw_error_already_set();
      }
      new ( memblock ) MyPath( value );
   }

Then in my initmodule definition I add::

   ...
   AutoConverter<MyPath>();
   ...


I tested this with MSVC7.1 (2003/.NET) on Windows XP.  Works for me, 
does the gig for now.

But somehow, I feel like I'm not doing something right, there must be
a better way to do this.  I'm sure Dave thought about some way for
automatic conversions to occur but I am not finding it.

The template file that wraps this up is attached.

(Dave: feel free to massage and include the file in attachment to 
Boost.Python, if you think it's worth anything.)

comments appreciated.
cheers,






Martin Blais wrote:
> Hi guys
> 
> I just found the mail below, answers one of my questions, and
> AFAIK the answer for my query is not clearly there in the
> Boost.Python docos.  In fact, porting code from v1 to v2, I
> think that this should be in the FAQ for the following
> question:
> 
>   "How do I register automatic conversions to/from a specific
>    C++ class without exposing the C++ class itself to the
>    Python interface?"
> 
> in v1, I used to do with by declaring to_python and from_python
> converter methods in the appropriate namespace.  The C++ class
> that was converted was not known to the Python interface at
> all.  I think the example below seems to address my query, I
> tried it and it works.
> 
> It would be nice to add this capability to the FAQ or docs.
> 
> also, maybe I'm going about this wrong, but it seems to perform
> this task in v1 was cleaner... is there a better way?  I'm sure
> there must be but I just didn't find it.
> 
> If there is no better way, some C++ code magic to wrap this up
> and make it look nicer would be a desired feature IMHO.
> 
> Note that I wouldn't mind wrapping up and exposing the class
> instead, if the implicit converters would always be triggered
> such that my users never have to be aware of the existence of
> the corresponding C++ class; I tried changing my C++ class to
> add implicit conversions but it doesn't get triggered somehow,
> here is an example, with a MyPath class that I would like to
> be automatically convertible from/to a Python string::
> 
>   class MyPath {
> 
>   public:
> 
>      /*----- member functions -----*/
> 
>      MyPath();
>      MyPath( const char* );
>      operator const char* ();
> 
>    ...
> 
> In initmodule:
> 
>    class_<MyPath> clsMyPath( "MyPath", init<const char*>() );
>    implicitly_convertible<const char*, MyPath>();
> 
> 
> Then from Python calling::
> 
>   objin('/some/path')
> 
> 
> Which is supposed to be able to call a function wrapped in C++::
> 
>   void objin( MyPath a ) const
> 
> 
> I get::
> 
>   Traceback (most recent call last):
>     File "c:/tmp/aaa", line 16, in ?
>       a.objin('/some/path')
>   Boost.Python.ArgumentError: Python argument types in
>       ClassA.objin(ClassA, str)
>   did not match C++ signature:
>       objin(class Dl::PyextModuleA::ClassA {lvalue}, class 
> Dl::PyextModuleA::MyPath)
> 
> 
> Also, if my function takes a ``const MyPath&``, it behaves the
> same (but I did not expect this one to work though).
> 
> 
> any info greatly appreciated.
> 
> cheers,
> 
> 
> 
> 
> 
> 
> 
> 
> Ralf W. Grosse-Kunstleve wrote:
> 
>> --- Kirsebom Nikolai <nikolai.kirsebom at siemens.no> wrote:
>>
>>> Some time ago I made a 'socket based' system (using BISON/FLEX for 
>>> parsing)
>>> where I expose C++ objects to python.  In this system CStrings are 
>>> regular
>>> Python strings.
>>
>>
>>
>> Attached is a small, self-contained demo extension module that shows 
>> how to do
>> what you want. Here is the corresponding trivial regression test:
>>
>> from sandbx_boost import custom_string
>> assert custom_string.hello() == "Hello world."
>> assert custom_string.size("california") == 10
>>
>> If you look at the code you will find:
>>
>> 1. A custom to_python converter (easy): custom_string_to_python_str
>>
>> 2. A custom lvalue converter (needs more code): 
>> custom_string_from_python_str
>>
>> The custom converters are registered in the global Boost.Python 
>> registry near
>> the top of the module initialization function. Once flow control has 
>> passed
>> through the registration code the automatic conversions from and to 
>> Python
>> strings will work in any module imported in the same process.
>>
>> HTH,
>>         Ralf
>>
>> #include <boost/python/module.hpp>
>> #include <boost/python/def.hpp>
>> #include <boost/python/to_python_converter.hpp>
>>
>> namespace sandbx { namespace {
>>
>>   class custom_string
>>   {
>>     public:
>>       custom_string() {}
>>       custom_string(std::string const& value) : value_(value) {}
>>       std::string const& value() const { return value_; }
>>     private:
>>       std::string value_;
>>   };
>>
>>   struct custom_string_to_python_str
>>   {
>>     static PyObject* convert(custom_string const& s)
>>     {
>>       return 
>> boost::python::incref(boost::python::object(s.value()).ptr());
>>     }
>>   };
>>
>>   struct custom_string_from_python_str
>>   {
>>     custom_string_from_python_str()
>>     {
>>       boost::python::converter::registry::push_back(
>>         &convertible,
>>         &construct,
>>         boost::python::type_id<custom_string>());
>>     }
>>
>>     static void* convertible(PyObject* obj_ptr)
>>     {
>>       if (!PyString_Check(obj_ptr)) return 0;
>>       return obj_ptr;
>>     }
>>
>>     static void construct(
>>       PyObject* obj_ptr,
>>       boost::python::converter::rvalue_from_python_stage1_data* data)
>>     {
>>       const char* value = PyString_AsString(obj_ptr);
>>       if (value == 0) boost::python::throw_error_already_set();
>>       void* storage = (
>>         
>> (boost::python::converter::rvalue_from_python_storage<custom_string>*)
>>           data)->storage.bytes;
>>       new (storage) custom_string(value);
>>       data->convertible = storage;
>>     }
>>   };
>>
>>   custom_string hello() { return custom_string("Hello world."); }
>>
>>   std::size_t size(custom_string const& s) { return s.value().size(); }
>>
>>   void init_module()
>>   {
>>     using namespace boost::python;
>>
>>     boost::python::to_python_converter<
>>       custom_string,
>>       custom_string_to_python_str>();
>>
>>     custom_string_from_python_str();
>>
>>     def("hello", hello);
>>     def("size", size);
>>   }
>>
>> }} // namespace sandbx::<anonymous>
>>
>> BOOST_PYTHON_MODULE(custom_string)
>> {
>>   sandbx::init_module();
>> }
>>
>>
>> __________________________________
>> Do you Yahoo!?
>> The New Yahoo! Search - Faster. Easier. Bingo.
>> http://search.yahoo.com

-------------- next part --------------
An embedded and charset-unspecified text was scrubbed...
Name: caba.cpp
URL: <http://mail.python.org/pipermail/cplusplus-sig/attachments/20030924/b4aeac6c/attachment.txt>


More information about the Cplusplus-sig mailing list