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 :directive:`%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 :ref:`ref-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. .. parsed-literal:: *specification* ::= {*module-statement*} *module-statement* ::= [*module-directive* | *statement*] *module-directive* ::= [ :directive:`%API` | :directive:`%CModule` | :directive:`%CompositeModule` | :directive:`%ConsolidatedModule` | :directive:`%Copying` | :directive:`%DefaultEncoding` | :directive:`%DefaultMetatype` | :directive:`%DefaultSupertype` | :directive:`%Doc` | :directive:`%ExportedDoc` | :directive:`%ExportedHeaderCode` | :directive:`%Feature` | :directive:`%Import` | :directive:`%Include` | :directive:`%InitialisationCode` | :directive:`%License` | :directive:`%MappedType` | :directive:`%Module` | :directive:`%ModuleCode` | :directive:`%ModuleHeaderCode` | :directive:`%OptionalInclude` | :directive:`%Platforms` | :directive:`%PreInitialisationCode` | :directive:`%PostInitialisationCode` | :directive:`%Timeline` | :directive:`%UnitCode` | *mapped-type-template*] *statement* :: [*class-statement* | *function* | *variable*] *class-statement* :: [ :directive:`%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* | :directive:`%BIGetBufferCode` | :directive:`%BIGetReadBufferCode` | :directive:`%BIGetWriteBufferCode` | :directive:`%BIGetSegCountCode` | :directive:`%BIGetCharBufferCode` | :directive:`%BIReleaseBufferCode` | :directive:`%ConvertToSubClassCode` | :directive:`%ConvertToTypeCode` | :directive:`%Docstring` | :directive:`%GCClearCode` | :directive:`%GCTraverseCode` | :directive:`%PickleCode` | :directive:`%TypeCode` | :directive:`%TypeHeaderCode` | *constructor* | *destructor* | *method* | *static-method* | *virtual-method* | *special-method* | *operator* | *virtual-operator* | *class-variable* | **public:** | **public Q_SLOTS:** | **public Q_SLOTS:** | **protected:** | **protected Q_SLOTS:** | **protected Q_SLOTS:** | **private:** | **private Q_SLOTS:** | **private Q_SLOTS:** | **Q_SIGNALS:** | **Q_SIGNALS:**] *constructor* ::= [**explicit**] *name* **(** [*argument-list*] **)** [*exceptions*] [*function-annotations*] [*c++-constructor-signature*] **;** [:directive:`%Docstring`] [:directive:`%MethodCode`] *c++-constructor-signature* ::= **[(** [*argument-list*] **)]** *destructor* ::= [**virtual**] **~** *name* **()** [*exceptions*] [**= 0**] [*function-annotations*] **;** [:directive:`%MethodCode`] [:directive:`%VirtualCatcherCode`] *method* ::= [**Q_SIGNAL**] [**Q_SLOT**] *type* *name* **(** [*argument-list*] **)** [**const**] [*exceptions*] [**= 0**] [*function-annotations*] [*c++-signature*] **;** [:directive:`%Docstring`] [:directive:`%MethodCode`] *c++-signature* ::= **[** *type* **(** [*argument-list*] **)]** *static-method* ::= **static** *function* *virtual-method* ::= [**Q_SIGNAL**] [**Q_SLOT**] **virtual** *type* *name* **(** [*argument-list*] **)** [**const**] [*exceptions*] [**= 0**] [*function-annotations*] [*c++-signature*] **;** [:directive:`%MethodCode`] [:directive:`%VirtualCatcherCode`] *special-method* ::= *type* *special-method-name* **(** [*argument-list*] **)** [*function-annotations*] **;** [:directive:`%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*] **;** [:directive:`%MethodCode`] *virtual-operator* ::= **virtual** *operator-type* **(** [*argument-list*] **)** [**const**] [*exceptions*] [**= 0**] [*function-annotations*] **;** [:directive:`%MethodCode`] [:directive:`%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* **>** :directive:`%MappedType` *enum* ::= **enum** [*name*] [*enum-annotations*] **{** {*enum-line*} **};** *enum-line* ::= [:directive:`%If` | *name* [*enum-annotations*] **,** *function* ::= *type* *name* **(** [*argument-list*] **)** [*exceptions*] [*function-annotations*] **;** [:directive:`%Docstring`] [:directive:`%MethodCode`] *namespace* ::= **namespace** *name* **{** {*namespace-line*} **};** *namespace-line* ::= [:directive:`%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*] **;** [:directive:`%AccessCode`] [:directive:`%GetCode`] [:directive:`%SetCode`] *exception* ::= :directive:`%Exception` *exception-name* [*exception-base*] **{** [:directive:`%TypeHeaderCode`] :directive:`%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*] | :stype:`SIP_ANYSLOT` [*default-value*] | :stype:`SIP_QOBJECT` | :stype:`SIP_RXOBJ_CON` | :stype:`SIP_RXOBJ_DIS` | :stype:`SIP_SIGNAL` [*default-value*] | :stype:`SIP_SLOT` [*default-value*] | :stype:`SIP_SLOT_CON` | :stype:`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 :ref:`ref-arg-annos` *class-annotations* ::= see :ref:`ref-class-annos` *enum-annotations* ::= see :ref:`ref-enum-annos` *function-annotations* ::= see :ref:`ref-function-annos` *typedef-annotations* ::= see :ref:`ref-typedef-annos` *variable-annotations* ::= see :ref:`ref-variable-annos` *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** | :stype:`SIP_PYCALLABLE` | :stype:`SIP_PYDICT` | :stype:`SIP_PYLIST` | :stype:`SIP_PYOBJECT` | :stype:`SIP_PYSLICE` | :stype:`SIP_PYTUPLE` | :stype:`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-type:: 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-type:: SIP_PYCALLABLE This is a ``PyObject *`` that is a Python callable object. .. sip-type:: SIP_PYDICT This is a ``PyObject *`` that is a Python dictionary object. .. sip-type:: SIP_PYLIST This is a ``PyObject *`` that is a Python list object. .. sip-type:: SIP_PYOBJECT This is a ``PyObject *`` of any Python type. .. sip-type:: SIP_PYSLICE This is a ``PyObject *`` that is a Python slice object. .. sip-type:: SIP_PYTUPLE This is a ``PyObject *`` that is a Python tuple object. .. sip-type:: SIP_PYTYPE This is a ``PyObject *`` that is a Python type object. .. sip-type:: SIP_QOBJECT This is a ``QObject *`` that is a C++ instance of a class derived from Qt's ``QObject`` class. .. sip-type:: SIP_RXOBJ_CON This is a ``QObject *`` that is a C++ instance of a class derived from Qt's ``QObject`` class. It is used as the type of the receiver instead of ``const QObject *`` in functions that implement a connection to a slot. .. sip-type:: SIP_RXOBJ_DIS This is a ``QObject *`` that is a C++ instance of a class derived from Qt's ``QObject`` class. It is used as the type of the receiver instead of ``const QObject *`` in functions that implement a disconnection from a slot. .. sip-type:: 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-type:: 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-type:: 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, ``QAccel::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 QObject *receiver, const char *member); The corresponding SIP specification is:: bool connectItem(int, SIP_RXOBJ_CON, SIP_SLOT_CON(int)); .. sip-type:: 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.