[PyQt] sip: add new annotation for specifying ownership of results of virtual methods
Mathias.Born at gmx.de
Mathias.Born at gmx.de
Fri Sep 21 20:17:31 BST 2012
On 21.09.2012, 16:28:20 Phil Thompson wrote:
> On Mon, 3 Sep 2012 22:27:41 +0200, Mathias.Born at gmx.de wrote:
>> Hi Phil,
>>
>> I've come across a case which I think deserves its own function
> annotation.
>> This is the proplem:
>>
>> I'm embedding Python code into a C++ app. There are two wrapped classes:
>>
>> class Netlister
>> {
>> virtual ~Netlister();
>> ...
>> };
>>
>> and
>>
>> class Project
>> {
>> virtual ~Project();
>> ...
>> virtual NetLister* netLister(const std::string& netListText)
> const;
>> };
>>
>> In Python, I have ("ltse_app" is the C++ app exposed as module)
>>
>>
>> class LTspiceNetLister(ltse_app.NetLister):
>> ...
>>
>> and
>>
>> class Project(ltse_app.Project):
>> ...
>> def netLister(self, netListText):
>> return LTspiceNetLister()
>>
>>
>> First, I call a Python function which gives me an instance of the Python
>> class "Project". Then (in C++, using its wrapper), I call its method
>> "netLister",
>> which returns an instance of "LTspiceNetLister". The goal is to use
>> this instance on the C++ side via its wrapper. Thus, ownership should be
>> with C++.
>>
>> But there is no corresponding annotation for the sip file. I have to
>> provide
>> a "%VirtualCatcherCode":
>>
>> virtual NetLister* netLister(const std::string& netListText /NoCopy/)
>> const;
>> %VirtualCatcherCode
>> PyObject *resObj = sipCallMethod(0, sipMethod, "D",
>> const_cast<std::string*>(&a0), sipType_std_string, NULL);
>> sipIsErr = !resObj || sipParseResult(0, sipMethod, resObj, "H0",
>> sipType_NetLister, &sipRes) < 0;
>> if (!sipIsErr) sipTransferTo(resObj, Py_None);
>> Py_XDECREF(resObj);
>> %End
>>
>> Note how I use "sipTransferTo(resObj, Py_None);" to bind the Python
> object
>> to the C++ instance.
>> I'm basically asking for something like the "Factory" annotation which
>> does just that.
>>
>> "Factory" tells sip that a wrapped C++ function creates a new object
> that
>> will be owned by the
>> Python side. I'd like to have another annotation which tells sip that
> the
>> Python implementation
>> of a class method creates a new object that will be owned by the C++
> side.
> The documentation for /Factory/ is wrong (now fixed in hg). It effectively
> does...
> sipTransferTo(resObj, selfObj);
> ...in the virtual catcher (where selfObj) is the class's self object (the
> Project instance in this case). You are using Py_None but I don't think it
> would make a difference.
> Would this remove your use case for sipTransfer(obj, Py_None)?
> Phil
No it wouldn't. My embedding currently works like this: I have a .py file
which is imported as module at program start. This module defines a
factory function, which is called from C++ and returns an instance of
a Python class derived from a sip-wrapped C++ class ("Project"). The
PyObject* obtained this way is then fed into sip's "api_convert_to_type"
to get hold of the wrapper instance. This instance is then used in the
C++ code. It transparently forwards method calls to the Python part.
(That's why it was so important to have the wrapper "re-throw" Python
exceptions as C++ exceptions.)
Thanks to "sipTransfer(obj, Py_None)" I don't have to manually manage the
PyObject representing the Python part. It just gets automatically deleted
by the C++ wrapper.
Further, your "sipTransferTo(resObj, selfObj);" above would bind the returned
"NetLister" to the "Project" instance. But they are not related in terms
of life time. I only want the reference count of the Python part to be decreased
by one when the C++ wrapper is destroyed. Provided there are no further
references on the Python side, this automatically destroys the Python part, too.
No parent-child relationships here like in Qt. Just Python objects that can be
used in C++ as if they were C++ only.
Best Regards,
Mathias Born
More information about the PyQt
mailing list