SIP Specification Files

A SIP specification consists of some C/C++ type and function declarations and some directives. The declarations may contain annotations which provide SIP with additional information that cannot be expressed in C/C++. SIP does not include a full C/C++ parser.

It is important to understand that a SIP specification describes the Python API, i.e. the API available to the Python programmer when they import the generated module. It does not have to accurately represent the underlying C/C++ library. There is nothing wrong with omitting functions that make little sense in a Python context, or adding functions implemented with handwritten code that have no C/C++ equivalent. It is even possible (and sometimes necessary) to specify a different super-class hierarchy for a C++ class. All that matters is that the generated code compiles properly.

In most cases the Python API matches the C/C++ API. In some cases handwritten code (see %MethodCode) is used to map from one to the other without SIP having to know the details itself. However, there are a few cases where SIP generates a thin wrapper around a C++ method or constructor (see Generated Derived Classes) and needs to know the exact C++ signature. To deal with these cases SIP allows two signatures to be specified. For example:

class Klass
{
public:
    // The Python signature is a tuple, but the underlying C++ signature
    // is a 2 element array.
    Klass(SIP_PYTUPLE) [(int *)];
%MethodCode
        int iarr[2];

        if (PyArg_ParseTuple(a0, "ii", &iarr[0], &iarr[1]))
        {
            // Note that we use the SIP generated derived class
            // constructor.
            Py_BEGIN_ALLOW_THREADS
            sipCpp = new sipKlass(iarr);
            Py_END_ALLOW_THREADS
        }
%End
};

Syntax Definition

The following is a semi-formal description of the syntax of a specification file.

specification ::= {module-statement}

module-statement ::= [module-directive | statement]

module-directive ::= [
        %API |
        %CModule |
        %CompositeModule |
        %ConsolidatedModule |
        %Copying |
        %DefaultEncoding |
        %DefaultMetatype |
        %DefaultSupertype |
        %Doc |
        %ExportedDoc |
        %ExportedHeaderCode |
        %Feature |
        %Import |
        %Include |
        %InitialisationCode |
        %License |
        %MappedType |
        %Module |
        %ModuleCode |
        %ModuleHeaderCode |
        %OptionalInclude |
        %Platforms |
        %PreInitialisationCode |
        %PostInitialisationCode |
        %Timeline |
        %UnitCode |
        mapped-type-template]

statement :: [class-statement | function | variable]

class-statement :: [
        %If |
        class |
        class-template |
        enum |
        namespace |
        opaque-class |
        operator |
        struct |
        typedef |
        exception]

class ::= class name [: super-classes] [class-annotations]
        { {class-line} };

super-classes ::= name [, super-classes]

class-line ::= [
        class-statement |
        %BIGetBufferCode |
        %BIGetReadBufferCode |
        %BIGetWriteBufferCode |
        %BIGetSegCountCode |
        %BIGetCharBufferCode |
        %BIReleaseBufferCode |
        %ConvertToSubClassCode |
        %ConvertToTypeCode |
        %Docstring |
        %GCClearCode |
        %GCTraverseCode |
        %PickleCode |
        %TypeCode |
        %TypeHeaderCode |
        constructor |
        destructor |
        method |
        static-method |
        virtual-method |
        special-method |
        operator |
        virtual-operator |
        class-variable |
        public: |
        public slots: |
        public slots: |
        protected: |
        protected slots: |
        protected slots: |
        private: |
        private slots: |
        private slots: |
        signals: |
        signals:]

constructor ::= [explicit] name ( [argument-list] )
        [exceptions] [function-annotations]
        [c++-constructor-signature] ; [%Docstring]
        [%MethodCode]

c++-constructor-signature ::= [( [argument-list] )]

destructor ::= [virtual] ~ name () [exceptions] [= 0]
        [function-annotations] ; [%MethodCode]
        [%VirtualCatcherCode]

method ::= [TQ_SIGNAL] [TQ_SLOT] type name (
        [argument-list] ) [const] [exceptions] [= 0]
        [function-annotations] [c++-signature] ;
        [%Docstring] [%MethodCode]

c++-signature ::= [ type ( [argument-list] )]

static-method ::= static function

virtual-method ::= [TQ_SIGNAL] [TQ_SLOT] virtual type name
        ( [argument-list] ) [const] [exceptions] [= 0]
        [function-annotations] [c++-signature] ;
        [%MethodCode] [%VirtualCatcherCode]

special-method ::= type special-method-name
        ( [argument-list] ) [function-annotations] ;
        [%MethodCode]

special-method-name ::= [__abs__ | __add__ | __and__ |
        __bool__ | __call__ | __cmp__ | __contains__ |
        __delitem__ | __div__ | __eq__ | __float__ |
        __floordiv__ | __ge__ | __getitem__ | __gt__ |
        __hash__ | __iadd__ | __iand__ | __idiv__ |
        __ifloordiv__ | __ilshift__ | __imod__ | __imul__ |
        __index__ | __int__ | __invert__ | __ior__ |
        __irshift__ | __isub__ | __iter__ | __itruediv__ |
        __ixor__ | __le__ | __len__ | __long__ |
        __lshift__ | __lt__ | __mod__ | __mul__ |
        __ne__ | __neg__ | __next__ | __nonzero__ |
        __or__ | __pos__ | __repr__ | __rshift__ |
        __setitem__ | __str__ | __sub__ | __truediv__ |
        __xor__]

operator ::= operator-type
        ( [argument-list] ) [const] [exceptions]
        [function-annotations] ; [%MethodCode]

virtual-operator ::= virtual operator-type
        ( [argument-list] ) [const] [exceptions] [= 0]
        [function-annotations] ; [%MethodCode]
        [%VirtualCatcherCode]

operatator-type ::= [ operator-function | operator-cast ]

operator-function ::= type operator operator-name

operator-cast ::= operator type

operator-name ::= [+ | - | * | / | % | & |
        | | ^ | << | >> | += | -= | *= |
        /= | %= | &= | |= | ^= | <<= | >>= |
        ~ | () | [] | < | <= | == | != |
        > | >>= | =]

class-variable ::= [static] variable

class-template :: = template < type-list > class

mapped-type-template :: = template < type-list >
        %MappedType

enum ::= enum [name] [enum-annotations] { {enum-line} };

enum-line ::= [%If | name [enum-annotations] ,

function ::= type name ( [argument-list] ) [exceptions]
        [function-annotations] ; [%Docstring]
        [%MethodCode]

namespace ::= namespace name { {namespace-line} };

namespace-line ::= [%TypeHeaderCode | statement]

opaque-class ::= class scoped-name ;

struct ::= struct name { {class-line} };

typedef ::= typedef [typed-name | function-pointer]
        typedef-annotations ;

variable::= typed-name [variable-annotations] ;
        [%AccessCode] [%GetCode]
        [%SetCode]

exception ::= %Exception exception-name [exception-base]
        { [%TypeHeaderCode] %RaiseCode };

exception-name ::= scoped-name

exception-base ::= ( [exception-name | python-exception] )

python-exception ::= [SIP_Exception | SIP_StopIteration |
        SIP_StandardError | SIP_ArithmeticError |
        SIP_LookupError | SIP_AssertionError |
        SIP_AttributeError | SIP_EOFError |
        SIP_FloatingPointError | SIP_EnvironmentError |
        SIP_IOError | SIP_OSError | SIP_ImportError |
        SIP_IndexError | SIP_KeyError | SIP_KeyboardInterrupt |
        SIP_MemoryError | SIP_NameError | SIP_OverflowError |
        SIP_RuntimeError | SIP_NotImplementedError |
        SIP_SyntaxError | SIP_IndentationError | SIP_TabError |
        SIP_ReferenceError | SIP_SystemError | SIP_SystemExit |
        SIP_TypeError | SIP_UnboundLocalError |
        SIP_UnicodeError | SIP_UnicodeEncodeError |
        SIP_UnicodeDecodeError | SIP_UnicodeTranslateError |
        SIP_ValueError | SIP_ZeroDivisionError |
        SIP_WindowsError | SIP_VMSError]

exceptions ::= throw ( [exception-list] )

exception-list ::= scoped-name [, exception-list]

argument-list ::= argument [, argument-list] [, ...]

argument ::= [
        type [name] [argument-annotations] [default-value] |
        SIP_ANYSLOT [default-value] |
        SIP_TQOBJECT |
        SIP_RXOBJ_CON |
        SIP_RXOBJ_DIS |
        SIP_SIGNAL [default-value] |
        SIP_SLOT [default-value] |
        SIP_SLOT_CON |
        SIP_SLOT_DIS]

default-value ::= = expression

expression ::= [value | value binary-operator expression]

value ::= [unary-operator] simple-value

simple-value ::= [scoped-name | function-call | real-value |
        integer-value | boolean-value | string-value |
        character-value]

typed-name::= type name

function-pointer::= type (* name )( [type-list] )

type-list ::= type [, type-list]

function-call ::= scoped-name ( [value-list] )

value-list ::= value [, value-list]

real-value ::= a floating point number

integer-value ::= a number

boolean-value ::= [true | false]

string-value ::=  {character} 

character-value ::=  character 

unary-operator ::= [! | ~ | - | +]

binary-operator ::= [- | + | * | / | & | |]

argument-annotations ::= see Argument Annotations

class-annotations ::= see Class Annotations

enum-annotations ::= see Enum Annotations

function-annotations ::= see Function Annotations

typedef-annotations ::= see Typedef Annotations

variable-annotations ::= see Variable Annotations

type ::= [const] base-type {*} [&]

type-list ::= type [, type-list]

base-type ::= [scoped-name | template | struct scoped-name |
        char | signed char | unsigned char | wchar_t |
        int | unsigned | unsigned int |
        short | unsigned short |
        long | unsigned long |
        long long | unsigned long long |
        float | double |
        bool |
        void |
        SIP_PYCALLABLE |
        SIP_PYDICT |
        SIP_PYLIST |
        SIP_PYOBJECT |
        SIP_PYSLICE |
        SIP_PYTUPLE |
        SIP_PYTYPE]

scoped-name ::= name [:: scoped-name]

template ::= scoped-name < type-list >

dotted-name ::= name [. dotted-name]

name ::= _A-Za-z {_A-Za-z0-9}

Here is a short list of differences between C++ and the subset supported by SIP that might trip you up.

  • SIP does not support the use of [] in types. Use pointers instead.
  • A global operator can only be defined if its first argument is a class or a named enum that has been wrapped in the same module.
  • Variables declared outside of a class are effectively read-only.
  • A class’s list of super-classes doesn’t not include any access specifier (e.g. public).

Variable Numbers of Arguments

SIP supports the use of ... as the last part of a function signature. Any remaining arguments are collected as a Python tuple.

Additional SIP Types

SIP supports a number of additional data types that can be used in Python signatures.

SIP_ANYSLOT

This is both a const char * and a PyObject * that is used as the type of the member instead of const char * in functions that implement the connection or disconnection of an explicitly generated signal to a slot. Handwritten code must be provided to interpret the conversion correctly.

SIP_PYCALLABLE

This is a PyObject * that is a Python callable object.

SIP_PYDICT

This is a PyObject * that is a Python dictionary object.

SIP_PYLIST

This is a PyObject * that is a Python list object.

SIP_PYOBJECT

This is a PyObject * of any Python type.

SIP_PYSLICE

This is a PyObject * that is a Python slice object.

SIP_PYTUPLE

This is a PyObject * that is a Python tuple object.

SIP_PYTYPE

This is a PyObject * that is a Python type object.

SIP_TQOBJECT

This is a TQObject * that is a C++ instance of a class derived from TQt’s TQObject class.

SIP_RXOBJ_CON

This is a TQObject * that is a C++ instance of a class derived from TQt’s TQObject class. It is used as the type of the receiver instead of const TQObject * in functions that implement a connection to a slot.

SIP_RXOBJ_DIS

This is a TQObject * that is a C++ instance of a class derived from TQt’s TQObject class. It is used as the type of the receiver instead of const TQObject * in functions that implement a disconnection from a slot.

SIP_SIGNAL

This is a const char * that is used as the type of the signal instead of const char * in functions that implement the connection or disconnection of an explicitly generated signal to a slot.

SIP_SLOT

This is a const char * that is used as the type of the member instead of const char * in functions that implement the connection or disconnection of an explicitly generated signal to a slot.

SIP_SLOT_CON

This is a const char * that is used as the type of the member instead of const char * in functions that implement the connection of an internally generated signal to a slot. The type includes a comma separated list of types that is the C++ signature of of the signal.

To take an example, TQAccel::connectItem() connects an internally generated signal to a slot. The signal is emitted when the keyboard accelerator is activated and it has a single integer argument that is the ID of the accelerator. The C++ signature is:

bool connectItem(int id, const TQObject *receiver, const char *member);

The corresponding SIP specification is:

bool connectItem(int, SIP_RXOBJ_CON, SIP_SLOT_CON(int));
SIP_SLOT_DIS

This is a const char * that is used as the type of the member instead of const char * in functions that implement the disconnection of an internally generated signal to a slot. The type includes a comma separated list of types that is the C++ signature of of the signal.

Classic Division and True Division

SIP supports the __div__ and __truediv__ special methods (and the corresponding inplace versions) for both Python v2 and v3.

For Python v2 the __div__ method will be used for both classic and true division if a __truediv__ method is not defined.

For Python v3 the __div__ method will be used for true division if a __truediv__ method is not defined.

For all versions of Python, if both methods are defined then __div__ should be defined first.

Table Of Contents

Previous topic

The SIP Command Line

Next topic

Directives