Qt for Python/Considerations: Difference between revisions
No edit summary |
(Added solution for a known issue regarding ImportError:undefined symbol: _ZTI18QOpenGLTimeMonitor) |
||
(18 intermediate revisions by 6 users not shown) | |||
Line 1: | Line 1: | ||
== General considerations == | ==General considerations== | ||
===== QString, QVariant and other types ===== | =====QString, QVariant and other types===== | ||
Qt for Python does not provide access to ''QString'' and ''QVariant'', meaning that we decided to use Python's native types for them. | Qt for Python does not provide access to ''QString'' and ''QVariant'', meaning that we decided to use Python's native types for them. | ||
Line 11: | Line 11: | ||
''QTextStream's'' ''bin()'', ''hex()'', and ''oct()'' functions have been renamed ''bin_()'', ''hex_()'', and ''oct_()'', to avoid conflicting with Python's built-ins of the same names. | ''QTextStream's'' ''bin()'', ''hex()'', and ''oct()'' functions have been renamed ''bin_()'', ''hex_()'', and ''oct_()'', to avoid conflicting with Python's built-ins of the same names. | ||
== | =====QByteArrays, QStrings and Python strings===== | ||
===== Problems with Python 3. | Previous versions of PySide included a wrong implementation regarding the behavior of QByteArrays, representing them as Python strings. | ||
Currently, QByteArray is treated as a list of bytes without an encoding. | |||
Please be aware that the equivalent type in Python will depend on its version, Python 2 uses "str" as type, and Python 3 uses "bytes". | |||
To avoid confusion, a QString on the other hand, is represented as a human readable string with an encoding, which is represented in Python 2 as an "unicode" object, | |||
and in Python 3 as a "str". | |||
The following cases represent the conversion between these types: | |||
Conversion between string and byte types should not be allowed implicitly. | |||
So with a Qt API like: | |||
<syntaxhighlight lang="cpp"> | |||
void A::foo(QString a) | |||
</syntaxhighlight> | |||
The following should happen in Python 3 | |||
<syntaxhighlight lang="python"> | |||
b = bytes("hi", "utf-8") | |||
c = b"hi" | |||
d = "hi" | |||
e = str("hi") | |||
A.foo(b) # doesn't work | |||
A.foo(c) # doesn't work | |||
A.foo(d) # works | |||
A.foo(e) # works | |||
</syntaxhighlight> | |||
And vice versa when expecting a QString, and passing a QByteArray or bytes, the following should happen in Python 3 | |||
<syntaxhighlight lang="cpp"> | |||
void A::bar(QByteArray) // or void A::bar(const char *) | |||
</syntaxhighlight> | |||
<syntaxhighlight lang="python"> | |||
b = "hi" | |||
c = str("hi") | |||
d = "hi".encode() | |||
e = QByteArray("hi") | |||
f = b"hi" | |||
A.bar(b) # doesn't work | |||
A.bar(c) # doesn't work | |||
A.bar(d) # works | |||
A.bar(e) # works | |||
A.bar(f) # works | |||
</syntaxhighlight> | |||
An explicit cast should be used when the user knows what kind of data they have, and what encoding they have / expect, in order to move from QString (Python 3 str, Python 2 unicode) to QByteArray ( Python 3 bytes, Python 2 str) and vice versa. | |||
So if you have a QByteArray, and you know it contains unicode data, and you need to pass it to a function taking a QString, something like this should work in Python 3: | |||
<syntaxhighlight lang="python"> | |||
a = QByteArray("hi".encode()) | |||
b = bytes(a.data(), "utf-8") | |||
A.foo(b.decode()) | |||
</syntaxhighlight> | |||
And for a function that takes a QByteArray, but you have a Python 2 unicode or Python 3 str, something like this should work: | |||
<syntaxhighlight lang="python"> | |||
# On python 3 | |||
a = "hi" | |||
# On python 2 | |||
a = unicode("hi") | |||
A.bar(a.encode()) | |||
</syntaxhighlight> | |||
==Known issues 5.12== | |||
===Qt Binary installer Windows=== | |||
When using MSCV2015 on the online installer you will not get QtWebEngine libraries, for that you would need MSVC2017. | |||
===Problems with Python 3.8.0=== | |||
Python 3.8.0 for Windows is missing a symbol causing DLL load errors when using Qt for Python. Python 3.8.1 is the minimum supported version of the Python 3.8 series. | |||
===Problems with Python 3.6.0=== | |||
There seems to be a binary compatibility between 3.6.0 and 3.6.1: | There seems to be a binary compatibility between 3.6.0 and 3.6.1: | ||
<syntaxhighlight lang="sh" line= | <syntaxhighlight lang="sh" line="line"> | ||
import 'PySide2' # <_frozen_importlib_external.SourceFileLoader object at 0x000001AB2E658F60> | import 'PySide2' # <_frozen_importlib_external.SourceFileLoader object at 0x000001AB2E658F60> | ||
Traceback (most recent call last): | Traceback (most recent call last): | ||
Line 30: | Line 99: | ||
ImportError: DLL load failed: The specified procedure could not be found. | ImportError: DLL load failed: The specified procedure could not be found. | ||
</syntaxhighlight> | </syntaxhighlight> | ||
<syntaxhighlight lang="sh" line= | <syntaxhighlight lang="sh" line="line"> | ||
4628:4698 @ 1025492328 - LdrpReportError - ERROR: Locating export "PyUnicode_AsWideCharString" for DLL "C:\Dev\super_pyside_clang\py360_ap\lib\site-packages\PySide2\QtCore.pyd" failed with status: 0xc0000139 | 4628:4698 @ 1025492328 - LdrpReportError - ERROR: Locating export "PyUnicode_AsWideCharString" for DLL "C:\Dev\super_pyside_clang\py360_ap\lib\site-packages\PySide2\QtCore.pyd" failed with status: 0xc0000139 | ||
</syntaxhighlight> | </syntaxhighlight> | ||
(Related: https://stackoverflow.com/questions/43264773/pil-dll-load-failed-specified-procedure-could-not-be-found/43504007#43504007 ) | (Related: https://stackoverflow.com/questions/43264773/pil-dll-load-failed-specified-procedure-could-not-be-found/43504007#43504007 ) | ||
==== | ===Missing QtScript=== | ||
At the moment we do not provide a QtScript interface since most of the functionality behind it is covered by native Python, but we plan to include it in the future. | |||
===Issues using shiboken2=== | |||
We noticed that on some linux machines, the built-in shiboken2 depends on Clang headers that are not found, depending on the Linux distribution. | |||
We recommend to have a local PySide2 build when trying to generate bindings for any other C++ project. | |||
===Missing Windows / Python 2.7 release=== | |||
The official Python 2.7 binary package which can be downloaded at https://www.python.org/downloads/ is built using MSVC 2008. The Qt libraries are built using MSVC 2015/2017. | |||
Both of these will load different MSVC runtime libraries, which is unsafe. | |||
The usual recommendation is that all built software should use the same MSVC runtime libraries, otherwise this could lead to memory corruption, crashes or undefined behavior. | |||
Therefore we do no ship a Python 2.7 Windows package. | |||
Here are some resources about this: | |||
https://blogs.msdn.microsoft.com/oldnewthing/20150911-00/?p=91611 | |||
http://siomsystems.com/mixing-visual-studio-versions/ | |||
Note that if you build your own custom Python2.7 interpreter with an MSVC version equivalent to the one that Qt was built with, you can safely build and use Qt For Python against that Python interpreter. | |||
===Missing DLLs on Windows=== | |||
Some users have been reporting missing DLLs on the Windows wheels (the wheels for Windows are built using MSVC 2015) a workaround for this issue is to install the | |||
[https://www.microsoft.com/en-us/download/details.aspx?id=48145 Visual C++ Redistributable for Visual Studio 2015]. | |||
===ImportError: DLL load failed: The specified module could not be found=== | |||
If you try to use the PySide2 package on Windows within a virtual environment and you see an error similar to the one below, make sure to update your virtualenv package to the latest version ('''16.1.0'''+) and then recreate the virtual environment. | |||
<syntaxhighlight lang="sh" line="line"> | |||
>>> import PySide2 | |||
Traceback (most recent call last): | |||
File "<stdin>", line 1, in <module> | |||
File "C:\Dev\env\lib\site-packages\PySide2\__init__.py", line 49, in <module> | |||
_setupQtDirectories() | |||
File "C:\Dev\env\lib\site-packages\PySide2\__init__.py", line 21, in _setupQtDirectories | |||
import shiboken2 | |||
File "C:\Dev\env\lib\site-packages\shiboken2\__init__.py", line 4, in <module> | |||
from .shiboken2 import * | |||
ImportError: DLL load failed: The specified module could not be found. | |||
</syntaxhighlight> | |||
===ImportError: undefined symbol: _ZTI18QOpenGLTimeMonitor=== | |||
If you try to use PySide2 package from '''pip''' on '''Plasma Mobile''', you might get an error similar to this :<syntaxhighlight lang="python3" line="1"> | |||
>>> import PySide2.QtGui | |||
Traceback (most recent call last): | |||
File "<stdin>", line 1, in <module> | |||
File "/usr/lib/python3.9/site-packages/shiboken2/files.dir/shibokensupport/__feature__.py", line 142, in _import | |||
return original_import(name, *args, **kwargs) | |||
ImportError: /usr/lib/python3.9/site-packages/PySide2/QtGui.cpython-39-aarch64-linux-gnu.so: undefined symbol: _ZTI18QOpenGLTimeMonitor, version Qt_5 | |||
</syntaxhighlight>This error usually occurs because Plasma Mobile uses '''qt5-es2-*''' packages and PySide2 from '''pip''' was compiled with non es2 Qt libraries. | |||
To resolve this error, you need to use PySide2 compiled with '''qt5-es2-*''' packages. Prebuilt packages of PySide2 with '''qt5-es2-*''' are provided my Manjaro ARM team. | |||
===='''Solution :'''==== | |||
*Either use the prebuilt '''pyside2-es2''' package provided by Manjaro ARM team on Manjaro Images | |||
*Or you need to custom compile PySide2 with '''qt5-es2-*''' packages | |||
===Documentation=== | |||
Most of the code snippets on the documentation are based on Qt/C++. | |||
It is probable that some pieces are still using C++, so the examples are invalid for Python. | |||
We are working to adapt them all, but if you need to understand a certain method or class, you can use our IRC channel to discuss your issue. |
Latest revision as of 19:33, 6 February 2021
General considerations
QString, QVariant and other types
Qt for Python does not provide access to QString and QVariant, meaning that we decided to use Python's native types for them. Internally we convert Python strings to QStrings and other types that could be accepted as QVariant, like dictionaries, lists and tuples.
Furthermore, the same idea is applied to QChar and QStringRef which are represented as Python strings and QStringList is converted to a Python lists of strings.
QDate, QDateTime, QTime, and QUrl's __hash__() methods return a string representation so that identical dates (and identical date/times or times or URLs) will have identical hash values. QTextStream's bin(), hex(), and oct() functions have been renamed bin_(), hex_(), and oct_(), to avoid conflicting with Python's built-ins of the same names.
QByteArrays, QStrings and Python strings
Previous versions of PySide included a wrong implementation regarding the behavior of QByteArrays, representing them as Python strings. Currently, QByteArray is treated as a list of bytes without an encoding. Please be aware that the equivalent type in Python will depend on its version, Python 2 uses "str" as type, and Python 3 uses "bytes". To avoid confusion, a QString on the other hand, is represented as a human readable string with an encoding, which is represented in Python 2 as an "unicode" object, and in Python 3 as a "str".
The following cases represent the conversion between these types:
Conversion between string and byte types should not be allowed implicitly. So with a Qt API like:
void A::foo(QString a)
The following should happen in Python 3
b = bytes("hi", "utf-8")
c = b"hi"
d = "hi"
e = str("hi")
A.foo(b) # doesn't work
A.foo(c) # doesn't work
A.foo(d) # works
A.foo(e) # works
And vice versa when expecting a QString, and passing a QByteArray or bytes, the following should happen in Python 3
void A::bar(QByteArray) // or void A::bar(const char *)
b = "hi"
c = str("hi")
d = "hi".encode()
e = QByteArray("hi")
f = b"hi"
A.bar(b) # doesn't work
A.bar(c) # doesn't work
A.bar(d) # works
A.bar(e) # works
A.bar(f) # works
An explicit cast should be used when the user knows what kind of data they have, and what encoding they have / expect, in order to move from QString (Python 3 str, Python 2 unicode) to QByteArray ( Python 3 bytes, Python 2 str) and vice versa.
So if you have a QByteArray, and you know it contains unicode data, and you need to pass it to a function taking a QString, something like this should work in Python 3:
a = QByteArray("hi".encode())
b = bytes(a.data(), "utf-8")
A.foo(b.decode())
And for a function that takes a QByteArray, but you have a Python 2 unicode or Python 3 str, something like this should work:
# On python 3
a = "hi"
# On python 2
a = unicode("hi")
A.bar(a.encode())
Known issues 5.12
Qt Binary installer Windows
When using MSCV2015 on the online installer you will not get QtWebEngine libraries, for that you would need MSVC2017.
Problems with Python 3.8.0
Python 3.8.0 for Windows is missing a symbol causing DLL load errors when using Qt for Python. Python 3.8.1 is the minimum supported version of the Python 3.8 series.
Problems with Python 3.6.0
There seems to be a binary compatibility between 3.6.0 and 3.6.1:
import 'PySide2' # <_frozen_importlib_external.SourceFileLoader object at 0x000001AB2E658F60>
Traceback (most recent call last):
File "C:\Qt5\pyside-setup\examples\tutorial\t1.py", line 47, in <module>
from PySide2 import QtWidgets
File "<frozen importlib._bootstrap>", line 1009, in _handle_fromlist
File "<frozen importlib._bootstrap>", line 205, in _call_with_frames_removed
File "<frozen importlib._bootstrap>", line 961, in _find_and_load
File "<frozen importlib._bootstrap>", line 950, in _find_and_load_unlocked
File "<frozen importlib._bootstrap>", line 648, in _load_unlocked
File "<frozen importlib._bootstrap>", line 560, in module_from_spec
File "<frozen importlib._bootstrap_external>", line 922, in create_module
File "<frozen importlib._bootstrap>", line 205, in _call_with_frames_removed
ImportError: DLL load failed: The specified procedure could not be found.
4628:4698 @ 1025492328 - LdrpReportError - ERROR: Locating export "PyUnicode_AsWideCharString" for DLL "C:\Dev\super_pyside_clang\py360_ap\lib\site-packages\PySide2\QtCore.pyd" failed with status: 0xc0000139
Missing QtScript
At the moment we do not provide a QtScript interface since most of the functionality behind it is covered by native Python, but we plan to include it in the future.
Issues using shiboken2
We noticed that on some linux machines, the built-in shiboken2 depends on Clang headers that are not found, depending on the Linux distribution. We recommend to have a local PySide2 build when trying to generate bindings for any other C++ project.
Missing Windows / Python 2.7 release
The official Python 2.7 binary package which can be downloaded at https://www.python.org/downloads/ is built using MSVC 2008. The Qt libraries are built using MSVC 2015/2017.
Both of these will load different MSVC runtime libraries, which is unsafe.
The usual recommendation is that all built software should use the same MSVC runtime libraries, otherwise this could lead to memory corruption, crashes or undefined behavior.
Therefore we do no ship a Python 2.7 Windows package.
Here are some resources about this:
https://blogs.msdn.microsoft.com/oldnewthing/20150911-00/?p=91611
http://siomsystems.com/mixing-visual-studio-versions/
Note that if you build your own custom Python2.7 interpreter with an MSVC version equivalent to the one that Qt was built with, you can safely build and use Qt For Python against that Python interpreter.
Missing DLLs on Windows
Some users have been reporting missing DLLs on the Windows wheels (the wheels for Windows are built using MSVC 2015) a workaround for this issue is to install the Visual C++ Redistributable for Visual Studio 2015.
ImportError: DLL load failed: The specified module could not be found
If you try to use the PySide2 package on Windows within a virtual environment and you see an error similar to the one below, make sure to update your virtualenv package to the latest version (16.1.0+) and then recreate the virtual environment.
>>> import PySide2
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "C:\Dev\env\lib\site-packages\PySide2\__init__.py", line 49, in <module>
_setupQtDirectories()
File "C:\Dev\env\lib\site-packages\PySide2\__init__.py", line 21, in _setupQtDirectories
import shiboken2
File "C:\Dev\env\lib\site-packages\shiboken2\__init__.py", line 4, in <module>
from .shiboken2 import *
ImportError: DLL load failed: The specified module could not be found.
ImportError: undefined symbol: _ZTI18QOpenGLTimeMonitor
If you try to use PySide2 package from pip on Plasma Mobile, you might get an error similar to this :
>>> import PySide2.QtGui
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/usr/lib/python3.9/site-packages/shiboken2/files.dir/shibokensupport/__feature__.py", line 142, in _import
return original_import(name, *args, **kwargs)
ImportError: /usr/lib/python3.9/site-packages/PySide2/QtGui.cpython-39-aarch64-linux-gnu.so: undefined symbol: _ZTI18QOpenGLTimeMonitor, version Qt_5
This error usually occurs because Plasma Mobile uses qt5-es2-* packages and PySide2 from pip was compiled with non es2 Qt libraries.
To resolve this error, you need to use PySide2 compiled with qt5-es2-* packages. Prebuilt packages of PySide2 with qt5-es2-* are provided my Manjaro ARM team.
Solution :
- Either use the prebuilt pyside2-es2 package provided by Manjaro ARM team on Manjaro Images
- Or you need to custom compile PySide2 with qt5-es2-* packages
Documentation
Most of the code snippets on the documentation are based on Qt/C++. It is probable that some pieces are still using C++, so the examples are invalid for Python. We are working to adapt them all, but if you need to understand a certain method or class, you can use our IRC channel to discuss your issue.