I replaced my template copy with 
object bc_copy(object copyable, dict memo){     object copyMod = 
import("copy");        object deepcopy = copyMod.attr("deepcopy");
        BaseClassWrap *newCopyable(new BaseClassWrap(extract<const 
BaseClassWrap                &>(copyable)));
        BaseClass tmp = boost::python::extract<BaseClass const &>(copyable);    
object result(tmp);
        int copyableId = (int)(copyable.ptr()); memo[copyableId] = result;
        extract<dict>(result.attr("__dict__"))().update(                
deepcopy(extract<dict>(copyable.attr("__dict__"))(),            memo));
        return result;}
and wrapped
class_<BaseClass, boost::shared_ptr<BaseClassWrap> >("BaseClass", init<>())     
        .def(init<const BaseClass&>())          .def(init<const 
BaseClassWrap&>())              .def("GetID", &BaseClassWrap::GetIDDefault)     
        .def("Clone", &BaseClassWrap::CloneDefault)             .def("Test", 
&BaseClassWrap::TestDefault)               .def("__copy__", &generic__copy__< 
BaseClass >)         .def("__deepcopy__", &bc_copy)          ;
But I'm still getting the non overriden behaviour. Calling Test on the clone 
prints out the C++ side code, while the non clone prints out the python side 
code.




> Date: Thu, 7 Jun 2012 17:13:55 -0400
> From: jbo...@astro.princeton.edu
> To: super24bitso...@hotmail.com
> Subject: Re: [C++-sig] Properly copying wrapped classes
> 
> On 06/05/2012 12:41 AM, Jay Riley wrote:
> > That got rid of the compile time errors. However, On the python side I
> > get the following error when I try to clone:
> >
> >
> > File ... line 9 in Clone
> > return copy.deepcopy(self)
> > File C:\Python27\Lib\copy.py" line 174 in deepcopy
> > y = copier(memo)
> > TypeError: No to_python (by-value) converter for C++ type: class
> > BaseClassWrap
> >
> 
> Hmm.  I would have expected that to work.  As long as BaseClass can be 
> instantiated itself (i.e. it isn't pure abstract), you could try this in 
> the copy/deepcopy implementation:
> 
> BaseClass tmp = boost::python::extract<BaseClass const &>(copyable);
> object result(tmp);
> 
> (I don't remember which of these types your Copyable template parameter 
> was, but I'd recommend just trying to write this in a non-template 
> function until you get it working).
> 
> That will involve one extra copy, but it should invoke the BaseClass 
> by-value converter instead of the BaseClassWrap by-value converter, and 
> I *think* that should do the right thing.
> 
> 
> Jim
> 
> 
> 
> 
> > In the interest of trying it out, I added the BaseClassWrap to the
> > python module
> >
> > class_<BaseClassWrap, bases<BaseClass> >("BaseClassWrap", init<PyObject*>())
> > .def(init<PyObject*, const BaseClass&>())
> > .def(init<PyObject*, const BaseClassWrap&>())
> > .def("__copy__", &generic__copy__< BaseClassWrap >)
> > .def("__deepcopy__", &generic__deepcopy__< BaseClassWrap >)
> > ;
> >
> > But this put me back at square one, where self isn't indicative of the
> > cloned instance.
> >
> > Just in the interest of seeing the effect, I changed my python exposing to:
> >
> > class_<BaseClass, boost::shared_ptr<BaseClassWrap> >("BaseClass", init<>())
> > .def(init<const BaseClass&>())
> > .def(init<const BaseClassWrap&>())
> > .def("GetID", &BaseClassWrap::GetIDDefault)
> > .def("Clone", &BaseClassWrap::CloneDefault)
> > .def("Test", &BaseClassWrap::TestDefault)
> > .def("__copy__", &generic__copy__< BaseClass >)
> > .def("__deepcopy__", &generic__deepcopy__< BaseClass >)
> > ;
> >
> > But as expected, the overloading doesn't work on clones made with this
> > exposing. Anything else I should try?
> >
> > Again, thanks for the help so far, appreciate it.
> >
> >
> >
> >
> >  > Date: Mon, 4 Jun 2012 11:52:42 -0400
> >  > From: jbo...@astro.princeton.edu
> >  > To: super24bitso...@hotmail.com
> >  > Subject: Re: [C++-sig] Properly copying wrapped classes
> >  >
> >  > On 06/04/2012 12:58 AM, Jay Riley wrote:
> >  > >
> >  > > Hi Jim,
> >  > > Thanks for the help so far. From what you said, I should be able to
> > change my deepcopy to this correct?
> >  > >
> >  > > template<class Copyable> object generic__deepcopy__(object
> > copyable, dict memo) { object copyMod = import("copy"); object deepcopy
> > = copyMod.attr("deepcopy");
> >  > > Copyable *newCopyable(new Copyable(extract<const Copyable
> > &>(copyable))); //object
> > result(boost::python::detail::new_reference(managingPyObject(newCopyable)));
> >  > > object result(extract<const Copyable&>(copyable)());
> >  > > // HACK: copyableId shall be the same as the result of id(copyable)
> > //in Python - // please tell me that there is a better way! (and which
> > ;-p) int copyableId = (int)(copyable.ptr()); memo[copyableId] = result;
> >  > > extract<dict>(result.attr("__dict__"))().update(
> > deepcopy(extract<dict>(copyable.attr("__dict__"))(), memo));
> >  > > return result; }
> >  > > When I attempt to compile it gives me the following error:
> >  > > Error 48 error C2664: 'boost::python::api::object::object(const
> > boost::python::api::object&)' : cannot convert parameter 1 from
> > 'boost::python::api::object (__cdecl *)(boost::python::extract<T>
> > (__cdecl *)(void))' to 'const boost::python::api::object&'
> > c:\khmp\src\engine\scripting\python\scripthelpers.h 67
> >  > > Did you mean something else? This level of boost python is above my
> > head, so I'm a bit lost
> >  > >
> >  >
> >  > It looks like the version I gave you is a bad corner case where the
> >  > compiler is incapable of parsing a constructor properly when templates
> >  > and overloaded function-call operators are involved; I always forget
> >  > exactly when that comes into play (not a compiler bug, just a weird part
> >  > of the standard, I think). In any case, I think separating it into two
> >  > lines should fix the problem:
> >  >
> >  > const Copyable & tmp = extract<const Copyable &>(copyable);
> >  > object result(tmp);
> >  >
> >  > Let me know if that doesn't work either; at that point I should try to
> >  > compile it myself and see what's going on.
> >  >
> >  > Jim
> >  >
> >  >
> >  >
> >  >
> >  >
> >  > >> Date: Sun, 3 Jun 2012 11:25:38 -0400
> >  > >> From: jbo...@astro.princeton.edu
> >  > >> To: cplusplus-sig@python.org
> >  > >> CC: super24bitso...@hotmail.com
> >  > >> Subject: Re: [C++-sig] Properly copying wrapped classes
> >  > >>
> >  > >> On 05/31/2012 08:49 PM, Jay Riley wrote:
> >  > >>> I'm having a problem with some python objects derived in python.
> > I have
> >  > >>> a Clone method that's supposed to make a full copy of these python
> >  > >>> inherited objects, but it isn't working. The problem is my wrapper
> >  > >>> class' PyObject* self isn't getting copied, so when I use
> >  > >>> call_method<>(self, "method name"), self will never point to the
> > copied
> >  > >>> instance. Here's a brief example showing the issue
> >  > >>>
> >  > >>
> >  > >> <snip>
> >  > >>
> >  > >>>
> >  > >>> Sorry about the length, just want to make sure I got everything
> > relevant
> >  > >>> in. When I run this code, it prints:
> >  > >>>
> >  > >>> Python Clone
> >  > >>> Python Side Test. ID: 1
> >  > >>> Python Side Test. ID: 1
> >  > >>> Original ID 1
> >  > >>> Clone ID 1
> >  > >>>
> >  > >>> this is wrong because Clone ID should be 2 (inspecting the object
> >  > >>> confirms it is 2). Like I said I'm pretty sure the problem is
> > that the
> >  > >>> wrapper class' copy constructor only makes a copy of the
> > PyObject* self,
> >  > >>> not a full copy. This is how every reference doc I saw was doing
> > class
> >  > >>> wrapping, but isn't this wrong? Should we be making a full copy
> > of the
> >  > >>> PyObject*? How would I go about doing that, or otherwise modifying my
> >  > >>> classes to get the behaviour I expect.
> >  > >>>
> >  > >>
> >  > >> There are a couple of things here that probably need to be addressed:
> >  > >>
> >  > >> - Be wary of relying on copy-constructor side effects to demonstrate
> >  > >> whether something is working; the compiler is allowed to elide copy
> >  > >> constructors under many conditions, which might result in misleading
> >  > >> results. That said, I don't think that's what's causing your problem
> >  > >> here (or at least not all of it).
> >  > >>
> >  > >> - Your implementations of __copy__ and __deepcopy__ won't work with
> >  > >> polymorphic wrapper classes, because they construct a BaseClass
> > instance
> >  > >> and tell Boost.Python to wrap it by managing the new reference. That
> >  > >> necessarily makes a Python object that holds a BaseClass object,
> > not one
> >  > >> that holds a BaseClassWrap object. If you want to get a BaseClassWrap
> >  > >> Python object, you want to pass it by value to Boost.Python; that
> > should
> >  > >> invoke the BaseClassWrap copy constructor and pass it a new
> > PyObject* to
> >  > >> manage (so it doesn't have to copy the PyObject* itself).
> >  > >>
> >  > >> I think that just means you can remove the "managingPyObject"
> > function,
> >  > >> and instead use:
> >  > >>
> >  > >> object result(extract<const Copyable&>(copyable)());
> >  > >>
> >  > >>
> >  > >> HTH
> >  > >>
> >  > >> Jim
> >  > >
> >  >
> 
                                          
_______________________________________________
Cplusplus-sig mailing list
Cplusplus-sig@python.org
http://mail.python.org/mailman/listinfo/cplusplus-sig

Reply via email to