Things sip can't do automatically

In a lot of cases, sip needs nothing but a stripped header file to do its work on—but sometimes more is needed.

Handwritten code

Look at the cursorPosition method. It does something Python can't do: it returns values via pointer arguments (the two int * parameters) passed to the method, instead of returning a tuple of values.

Call by reference and call by value: C and C++ (and Visual Basic and a host of other programming languages) have two ways of passing arguments to functions: by reference, or by value. If a function is called with arguments by reference, changing the value of the arguments will change their value outside the function. Python only has call by (object) reference. If an object is mutable, then changing it inside a function, will also change the object outside a function:

>>> def f(a):
...     a.append("bla")
... 
>>> a=["bla"]
>>> f(a)
>>> a
['bla', 'bla']
        

When you can a Python function with an immutable object like a string or an integer, the value of the reference outside the function won't change:

>>> 
>>> def f(a):
...     a="b"
... 
>>> a="a"
>>> f(a)
>>> a
'a'
>>> 
        

That's because the name of the argument and the name of the variable are not aliases, they are two seperate names, that might point to different objects, or to the same. As soon as you assign a new string to the argument, the references no longer point to the same name.

%MemberCode
  // The Python interface returns a tuple.

  QMultiLineEdit *ptr;

  if (sipParseArgs(&sipArgsParsed,sipArgs,
                   "m",
                   sipThisObj,
                   sipClass_QMultiLineEdit,
                   &ptr))
  {
    int line, col;

    ptr -> QMultiLineEdit::cursorPosition(&line,&col);

    return Py_BuildValue("(ii)",line,col);
  }
%End
      

However, sip can't determine whether these pointers contain data being sent to the cursorPosition function, or data being returned by cursorPosition to the calling code. Since Python has nothing comparable to a C/C++ pointer, there is no automatic way to generate the wrapper for this method. Inside knowledge of what the code actually does is required to generate wrappers, and the developer has to provide sip with this knowledge.

Immediately following the cursorPosition method declaration is a %MemberCode declaration. This allows the developer to tell sip how to wrap this function by providing most of the necessary C++ code. The contents of the %Membercode block is, in fact, C++ code.

Looking at the %Membercode block, sip is instructed to first parse the arguments which Python will pass to the wrapper code. The sipParseArgs function is the most important, and complex, function in the sip library. The third parameter is a string that encodes the number and types of the Python parameters that are expected, with more information given in later parameters. In this case the sipParseArgs is being told to expect exactly one Python parameter which is a Python instance of the QMultiLineEdit class which corresponds to the value of self.

Next, some variables are defined (line, col) to hold the data cursorPosition will return. The member next calls the Qt/C++ version of QMultiLineEdit::cursorPosition, which will fill in the values pointed to by &line and &col.

Last, the code uses the Py_BuildValue to return the line and col values obtained to the Python caller. In this case, since two values are returned, the code places the two values in a tuple which is returned to the Python program that called the method. Even though a Python method can return 2 or more distinct values, C++ can't, and the member code is in the C++ domain.

If you look at some of the code sip generates, you'll find it looks very much like the member code generated manually for the cursorPosition method. There will be a number of references to functions or methods which begin with ‘sip' or ‘Py'. The ‘Py'-prefixed calls are to code built into Python itself. Python contains a library of functions used to write wrappers/interfaces for C and C++ code. The ‘sip'-prefixed functions are calls to the sip library, and occur in all sip-generated code (including all of PyQt). This is why you need to have the sip library installed before you can use PyQt, even though you don't need to run the sip program itself.

Other limitations

Presently, sip can't automatically generate code for methods which have parameters or return values with types like int&, int* or bool*.

In addition, sip can't directly handle types based on C++ templates. In these cases you have to used the %MappedType directive to supply your own C++ code to explicitly handle how such types are converted to and from Python objects. You still use the C++ template type in parameters and return values of functions and methods, sip will automatically carry out the necessary conversions based on the C++ code you provided.