Re: [C++-sig] Conversion of python files to C++ ostreams
On Thu, Apr 1, 2010 at 7:11 PM, Ralf W. Grosse-Kunstleve wrote: >> Is it necessary to explicitly invoke the streambuf object from python? > > Yes. I could be different and in fact was different in the initial > implementation (if you look back in the svn history). But there were > a few subtle problems (buffer size, exception handling) and in the end > I decided the most obvious and robust approach is to require > streambuf(sys.stdout) or ostream(sys.stdout). I finally got streambuf to work with my wrapped classes. This feels much better than the approach I was using before. I added "[with_custodian_and_ward< 1, 2 >()]" to the streambuf wrapper init declaration, because I imagined it might be possible for the python file to be destroyed before the streambuf otherwise. Now I am faced with wrapping a constructor that takes a "std::ostream&" as an argument. I don't know how to write a wrapper for a constructor in boost.python. I'm open to suggestions on this. For example: // C++ API struct Foo { Foo(ostream& os); }; # desired python usage foo = Foo(streambuf(sys.stdout)) How would I wrap this Foo example? ___ Cplusplus-sig mailing list Cplusplus-sig@python.org http://mail.python.org/mailman/listinfo/cplusplus-sig
Re: [C++-sig] Conversion of python files to C++ ostreams
On Thu, Apr 1, 2010 at 1:32 PM, Michele De Stefano wrote: > So, as shown into the doxygen example, you have to program a wrapper > like this one: > > foo_wrap(boost::python::object pyfile) { > > mds_utils::python::oFileObj fobj(py_file); > > foo(fobj); > } That's clever. I wonder how boost.python would deal with overloaded methods that use this technique. void foo_wrap1(boost::python::object pyfile) {} void foo_wrap2(bar_t bar) {} def("foo", &foo_wrap1); def("foo", &foo_wrap2); Would boost.python know to send "bar" objects to foo_wrap2? ___ Cplusplus-sig mailing list Cplusplus-sig@python.org http://mail.python.org/mailman/listinfo/cplusplus-sig
[C++-sig] Boost.Python to_python_indirect and intrusive_ptr.
Hi everyone. I'm trying to use Boost.Python to expose some of my C++ classes and I encountered an odd behaviour of the to_python_indirect result converter for intrusive_ptr with specific classes. Here is the deal: I'm using a component-based design for my classes, meaning an aggregation of objects with different features. These objects are ref-counted, and if they are in the same aggregation, they share the same lifetime. That is to say, as long as one of the components in the "ring" has a strictly positive reference counter, every component in the ring survive even if their ref-count drops to zero. I use boost::intrusive_ptr to manipulate them easily. There is the basic interface: class Component { void AddRef(); void Release(); unsigned int GetRefCount(); bool AddComponent(Component*); bool RemoveComponent(Component*); Component* ComponentIterator(Component*);//-->Used to parse the ring. virtual some_virtual_fn(); }; To avoid lifetime problems when manipulating an object both from C++ and python side, i want python to manipulate components only through boost::intrusive_ptr. There is the exposition code: //-->Object wrapper struct Component_wrapper : SandBoxProj::Component, bp::wrapper< SandBoxProj::Component > { Component_wrapper( ) :Component( ), bp::wrapper< SandBoxProj::Component >(){} virtual some_virtual_fn() { //overriding code... } default_some_virtual_fn() { Component::some_virtual_fn(); } }; //-->Some declarations that boost.python needs to manipulate boost::intrusive_ptr namespace boost { namespace python { template struct pointee< intrusive_ptr > //-->pointee struct for intrusive_ptr holder { typedef T type; }; struct make_owning_intrusive_ptr_holder//-->ResultConverter to make an intrusive_ptr from a raw one, inspired from to_python_indirect.hpp:79 { template static PyObject* execute(T* p) { typedef objects::pointer_holder, T> holder_t; boost::intrusive_ptr ptr(p); return boost::python::objects::make_ptr_instance::execute(ptr); } }; struct return_by_intrusive_ptr//-->corresponding ResultConverterGenerator { template struct apply { typedef to_python_indirect type; //--> here is the usage of to_python_indirect }; }; }} bp::class_< Component_wrapper,boost::intrusive_ptr,boost::noncopyable >( "Component", bp::init< >() ) .def( "AddComponent", &Component::AddComponent, ( bp::arg("arg0") ) ) .def( "ComponentIterator",&Component::ComponentIterator, ( bp::arg("arg0") ), bp::return_value_policy< bp::return_by_intrusive_ptr >() )//-->this class uses the converter. .def( "some_virtual_fn",&Component::some_virtual_fn,&Component_wrapper::default_some_virtual_fn) .def( "GetRefCount",&Component::GetRefCount) .def( "RemoveComponent",&Component::RemoveComponent, ( bp::arg("arg0") ) ) ; And finally there is a scripts that uses this class and its output: >>>from pythonbinder import * >>>import gc >>>Comp1=Component() >>>Comp2=Component() >>>print Comp2.GetRefCount() 1 //-->Ok, I manipulate an intrusive_ptr >>>Comp2.AddComponent(Comp1) >>>iter=None >>>iter=Comp1.ComponentIterator(iter) >>>print iter //-->Ok, There is my C++ object >>>iter=Comp1.ComponentIterator(iter) >>>print iter >>>print iter.GetRefCount() 1 //-->What the ? iter is supposed to be an intrusive ptr. After a look at to_python_indirect, it seems that iter==Comp2, the python object wrapping the intrusive_ptr was just addref'ed. Ok, fair enough. >>>iter=Comp1.ComponentIterator(iter) >>>print iter None //-->Now the troubles begin. >>>del Comp2 >>>gc.collect()//-->ensure deletion, Comp2 is still alive from the C++ side, because Comp1 is alive. >>>iter=Comp1.ComponentIterator(iter) //May crash >>>print iter //-->if we made it through, a weak_ptr to some random structure. After that, i figured out that i never went through the ResultConverters i declared. Let's look at the execute function from to_python_indirect, template inline PyObject* execute(U const& x, mpl::false_) const { U* const p = &const_cast(x); if (is_polymorphic::value) //-->My type is polymorphic { if (PyObject* o = detail::wrapper_base_::owner(p)) //-->Ok, that's why I have a refcount of 1, no matter how many python intrusive_ptr wrappers I seem to have return incref(o); } return MakeHolder::execute(p); //-->There is the call to my result converter. } What happen is that after deletion of the last python wrapping of the intrusive_ptr, which is o in the code above, the Component_wrapper, which is partly a python object, is not deleted (the component ring still holds it), but it still reference its last owner which is the last instance_holder that just got deleted, so the object returned is a random memory garbage. Changing th
Re: [C++-sig] Conversion of python files to C++ ostreams
Michele De Stefano wrote: there is a much easier way to treat a FILE* as a C++ stream. The easy way is to use my open source library (mds-utils, http://code.google.com/p/mds-utils/). Elegant use of boost::iostreams if I may say so. I've been looking for some usecases for some boost.python modifications I've been playing with so I tried incorporating your FileObj. Seems to work well. One can wrap a function that takes a std::ostream& like this: using mds_utils::python::FileObj; // c++ function we're wrapping void sayhello(std::ostream& os) { os << "*** hello ***\n"; } // // function object that converts object& and implements // result_of protocol // struct conv { typedef FileObj result_type; result_type operator()(object& obj) { return FileObj(obj); } }; BOOST_PYTHON_MODULE(mod) { def("sayhello", as( &sayhello )); // arg converter ^ }; In this case python sees "sayhello" as taking a bp::object. The as<> might need some clarification It takes a function type argument. Above, the argument is the type of a function that returns void, which takes one argument, which is a function that returns conv and takes one argument of type object&. In general, for a unary function 'fn' returning type R it is: as(&fn) where T(U) means "convert the python object to C++ type U, then create a temporary object T and use it to create result_of::type, then convert that type to R and return to python". This is a little boost::proto-ish. Maybe also a little like a C++1x concept map. You could also provide a generic 'conv' struct, I skipped this so as not to confuse things. -t ___ Cplusplus-sig mailing list Cplusplus-sig@python.org http://mail.python.org/mailman/listinfo/cplusplus-sig
Re: [C++-sig] Conversion of python files to C++ ostreams
Christopher Bruns wrote: On Thu, Apr 1, 2010 at 1:32 PM, Michele De Stefano wrote: So, as shown into the doxygen example, you have to program a wrapper like this one: foo_wrap(boost::python::object pyfile) { mds_utils::python::oFileObj fobj(py_file); foo(fobj); } That's clever. I wonder how boost.python would deal with overloaded methods that use this technique. void foo_wrap1(boost::python::object pyfile) {} void foo_wrap2(bar_t bar) {} def("foo", &foo_wrap1); def("foo", &foo_wrap2); Would boost.python know to send "bar" objects to foo_wrap2? Boost python's "first match" overloading would kick in here... there was a long discussion about this on the list, check the archives. Short story: order of registration matters. I have a possible alternate implementation that went dormant and hasn't been thoroughly vetted, but I'm coming back around to it now. -t ___ Cplusplus-sig mailing list Cplusplus-sig@python.org http://mail.python.org/mailman/listinfo/cplusplus-sig
Re: [C++-sig] Conversion of python files to C++ ostreams
troy d. straszheim wrote: as(&fn) where T(U) means "convert the python object to C++ type U, then create a temporary object T and use it to create result_of::type, correction, add here "then pass that thing to fn" > then convert that type to R and return to python". -t ___ Cplusplus-sig mailing list Cplusplus-sig@python.org http://mail.python.org/mailman/listinfo/cplusplus-sig
Re: [C++-sig] Conversion of python files to C++ ostreams
> Now I am faced with wrapping a constructor that takes a > "std::ostream&" as an argument. I don't know how to write a wrapper > for a constructor in boost.python. I'm open to suggestions on this. > For example: > > // C++ API > struct Foo { > Foo(ostream& os); > }; > > # desired python usage > foo = Foo(streambuf(sys.stdout)) Did you already try the usual def(init((arg("os" ? I think it should just work (but I haven't actually tried it). Ralf ___ Cplusplus-sig mailing list Cplusplus-sig@python.org http://mail.python.org/mailman/listinfo/cplusplus-sig