[PyQt] __setitem__ Problem

Phil Thompson phil at riverbankcomputing.com
Sat Apr 18 16:56:04 BST 2009


On Thu, 16 Apr 2009 12:26:17 -0600 (MDT), Neil Birkbeck
<birkbeck at cs.ualberta.ca> wrote:
> In older versions of sip (4.7.3), I have used __setitem__, __getitem__ to

> access/set elements from multidimensional quantities of a wrapped c++ 
> object that uses operator()(int,int).  For example, the following sip
code 
> used to work fine
> 
> class A {
>  int operator()(int x,int y) const;
> 
>  int __getitem__(int x,int y) const;
> %MethodCode
> ...
> %End
> 
>  void __setitem__(int x,int y, int val) const;
> %MethodCode
> ...
> %End
> };
> 
>>From the ChangeLog this feature seemed to have been removed (in a related

> mailing list post, it was reported that the above usage was a bug
>
http://article.gmane.org/gmane.comp.python.pyqt-pykde/12342/match=sip+__setitem__).
> 
> With the new checking (sip 4.7.9, possibly earlier), the above code will 
> now give an error (e.g., sip: A.sip:18: Incorrect number of arguments to 
> Python slot).  The previous mailing list post 
> (http://thread.gmane.org/gmane.comp.python.pyqt-pykde/12342) suggested to

> either not use __setitem__/__getitem__ for this purpose or to use a
tuple.
> 
> I updated my code and the tuples work fine for __getitem__, but I cannot 
> seem to get the tuple to work for __setitem__.
> 
> For example,
> 
> A.sip:
> 
> class A {
>  int __getitem(int x,int y);
> %MethodCode
>  //This is just a dummy, actually parse the tuple and extract indices...
> %End
> 
>  void __setitem__(SIP_PYOBJECT, SIP_PYOBJECT);
> %MethodCode
>   //Do something here....
> %End
> };
> 
> Python test:
> from A import A
> a = A(10,10)
> # Getting works fine, no error parsing arguments
> b = a[0,0]
> b = a[0]
> 
> # Setting works with anything but tuple
> a[0] = 1 # Works fine
> a[[1,2]] = 1 # Also works, but is not really a desired syntax
> a[0:5] = 1   # Works, would check for this when parsing args.
> a[(0,1)] = 1 # Error: "TypeError: too many arguments to A.__setitem__(),
2
> at most expected"
> a[0,1] = 1 #  Same error
> tup = (0,1)
> a[tup] = 1 # Same error
> 
> The tuple always gets unpacked into more than one argument for
__setitem__ 
> and causes the TypeError, which happens before any of the sip %MethodCode

> can be called.
> 
> Looking at the generated code for the __setitem__, the parsing of args 
> looks something like:
> sipParseArgs(&sipArgsParsed,sipArgs,"P0P0",&a0,&a1)
> 
> On the other hand, the parsing of args for __getitem__ seems to work due 
> to the single arg format of "1P0".  Manually editing the generated code
to 
> return the args packed into a single tuple (including the set value) like

> __getitem__ works but is not a satisfying solution.
> 
> Changing the function signature of __setitem__ to take a SIP_PYTUPLE as 
> the first argument also does not help, although it does change the 
> sipParseArgs format to "TP0" (e.g., 
> sipParseArgs(&sipArgsParsed,sipArgs,"TP0",&PyTuple_Type,&a0,&a1)).  I 
> suspect this call would succeed if there was a way to make sipParseArgs 
> put the first n-1 sipArgs into a0 and the last argument into a1.  
> 
> The parsing of arguments for other methods with similar signature, e.g., 
> "void afunc(SIP_PYOBJECT, SIP_PYOBJECT)", does indeed accept stuff like 
> afunc((1,2), 0), so the problem appears to be with __setitem__. 
> 
> I could be doing something wrong as no one else appears to be having this

> problem.  If not, is there a some other way to force the argument parsing

> to put the first args into a tuple?  Or is there a way to do it by hand 
> (like a NoArgParser for member functions)?    Currently, I modified the 
> sip source (in sipgen/parser.c:findFunction, line 7642, {"__setitem__", 
> "setitem_slot, TRUE, -1}) to not check the # of arguments to 
> __setitem__/__getitem__.   For the time being, this gives the behaviour
of 
> the older version, so that I can remain using my old sip files (like the 
> beginning of this post).

Try tonight's SIP snapshot.

Use __setitem__(SIP_PYTUPLE, SIP_PYOBJECT) and then unpack the tuple as you
are in your __getitem__.

Thanks,
Phil


More information about the PyQt mailing list