aboutsummaryrefslogtreecommitdiffstats
path: root/sources/shiboken6/doc/considerations.rst
blob: 3488c340771ff17e5ec61c65e1e779e7fd6b35b6 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
.. _words-of-advice:

***************
Words of Advice
***************

When writing or using Python bindings there is some things you must keep in mind.


.. _duck-punching-and-virtual-methods:

Duck punching and virtual methods
=================================

The combination of duck punching, the practice of altering class characteristics
of already instantiated objects, and virtual methods of wrapped C++ classes, can
be tricky. That was an optimistic statement.

Let's see duck punching in action for educational purposes.

    .. code-block:: python

       import types
       import Binding

       obj = Binding.CppClass()

       # CppClass has a virtual method called 'virtualMethod',
       # but we don't like it anymore.
       def myVirtualMethod(self_obj, arg):
           pass

       obj.virtualMethod = types.MethodType(myVirtualMethod, obj, Binding.CppClass)


If some C++ code happens to call `CppClass::virtualMethod(...)` on the C++ object
held by "obj" Python object, the new duck punched "virtualMethod" method will be
properly called. That happens because the underlying C++ object is in fact an instance
of a generated C++ class that inherits from `CppClass`, let's call it `CppClassWrapper`,
responsible for receiving the C++ virtual method calls and finding out the proper Python
override to which handle such a call.

Now that you know this, consider the case when C++ has a factory method that gives you
new C++ objects originated somewhere in C++-land, in opposition to the ones generated in
Python-land by the usage of class constructors, like in the example above.

Brief interruption to show what I was saying:

    .. code-block:: python

       import types
       import Binding

       obj = Binding.createCppClass()
       def myVirtualMethod(self_obj, arg):
           pass

       # Punching a dead duck...
       obj.virtualMethod = types.MethodType(myVirtualMethod, obj, Binding.CppClass)


The `Binding.createCppClass()` factory method is just an example, C++ created objects
can pop out for a number of other reasons. Objects created this way have a Python wrapper
holding them as usual, but the object held is not a `CppClassWrapper`, but a regular
`CppClass`. All virtual method calls originated in C++ will stay in C++ and never reach
a Python virtual method overridden via duck punching.

Although duck punching is an interesting Python feature, it don't mix well with wrapped
C++ virtual methods, specially when you can't tell the origin of every single wrapped
C++ object. In summary: don't do it!


.. _pyside-old-style-class:

Python old style classes and PySide
===================================

Because of some architectural decisions and deprecated Python types.
Since PySide 1.1 old style classes are not supported with multiple inheritance.

Below you can check the examples:

Example with old style class:

    .. code-block:: python

        from PySide2 import QtCore

        class MyOldStyleObject:
            pass

        class MyObject(QtCore, MyOldStyleObject):
            pass


this example will raise a 'TypeError' due to the limitation on PySide, to fix
this you will need use the new style class:


    .. code-block:: python

        from PySide2 import QtCore

        class MyOldStyleObject(object):
            pass

        class MyObject(QtCore, MyOldStyleObject):
            pass


All classes used for multiple inheritance with other PySide types need to have
'object' as base class.
**************************
Frequently Asked Questions
**************************

This is a list of Frequently Asked Questions about |project|.
Feel free to suggest new entries using our `Mailing list`_ or our IRC channel!

General
=======

What is Shiboken?
-----------------

Shiboken is a Generator Runner plugin that outputs C++ code for CPython
extensions.
The first version of PySide had source code based on Boost templates.
It was easier to produce code but a paradigm change was needed, as the next
question explains.


Why did you switch from Boost.Python to Shiboken?
-------------------------------------------------

The main reason was the size reduction. Boost.Python makes excessive use of
templates resulting in a significant increase of the binaries size.
On the other hand, as Shiboken generates CPython code, the resulting binaries
are smaller.

Creating bindings
=================

Can I wrap non-Qt libraries?
----------------------------

Yes. Check Shiboken source code for an example (libsample).


Is there any runtime dependency on the generated binding?
---------------------------------------------------------

Yes. Only libshiboken, and the obvious Python interpreter
and the C++ library that is being wrapped.

What do I have to do to create my bindings?
-------------------------------------------

Most of the work is already done by the API Extractor.
The developer creates a :std:doc:`typesystem <typesystem>`
file with any customization wanted in
the generated code, like removing classes or changing method signatures.
The generator will output the *.h* and *.cpp* files with the CPython code that
will wrap the target library for python.


Is there any recommended build system?
--------------------------------------

Both API Extractor and generator uses and recommends the CMake build system.

Can I write closed-source bindings with the generator?
------------------------------------------------------

Yes, as long as you use a LGPL version of Qt, due to runtime requirements.

What is 'inject code'?
----------------------

That's how we call customized code that will be *injected* into the
generated at specific locations. They are specified inside the typesystem.

.. _`Mailing list`:  http://lists.qt-project.org/mailman/listinfo/pyside