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