aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSimo Fält <simo.falt@qt.io>2023-05-25 11:12:40 +0300
committerSimo Fält <simo.falt@qt.io>2023-05-25 11:12:40 +0300
commitca0519cb3f6b62e3b61ba74f0c60eac891dd3a15 (patch)
tree46e94d1b9a77648ca080a36b7d266f2322031d67
parent72d32f66685fbb7fefc41eee629e63f4824cb10b (diff)
parent7c386888b453b7f2ac78ef1da59d077b25e372b3 (diff)
Merge tag 'v5.15.4-lts' into tqtc/lts-5.15-opensourcev5.15.4-lts-lgpl
Qt For Python Release 5.15.4 Change-Id: I8457501ba90fc481fb9de686eb8a2f880ecc06cd
-rw-r--r--build_scripts/main.py29
-rw-r--r--coin/dependencies.yaml46
-rw-r--r--dist/changes-5.15.438
-rw-r--r--examples/widgets/richtext/textobject/textobject.py23
-rw-r--r--product_dependencies.yaml3
-rw-r--r--sources/pyside2/CMakeLists.txt2
-rw-r--r--sources/pyside2/PySide2/QtDataVisualization/typesystem_datavisualization.xml131
-rw-r--r--sources/pyside2/PySide2/QtGui/typesystem_gui_common.xml16
-rw-r--r--sources/pyside2/PySide2/QtOpenGLFunctions/CMakeLists.txt6
-rw-r--r--sources/pyside2/PySide2/QtOpenGLFunctions/QtOpenGLFunctions_global.post.h.in2
-rw-r--r--sources/pyside2/PySide2/QtOpenGLFunctions/typesystem_openglfunctions.xml9
-rw-r--r--sources/pyside2/PySide2/glue/qtdatavisualization.cpp37
-rw-r--r--sources/pyside2/PySide2/glue/qtgui.cpp25
-rw-r--r--sources/pyside2/PySide2/glue/qtopenglfunctions.cpp76
-rw-r--r--sources/pyside2/PySide2/qopenglversionfunctionsfactory.h45
-rw-r--r--sources/pyside2/PySide2/templates/gui_common.xml4
-rw-r--r--sources/pyside2/doc/extras/QtCore.Property.rst73
-rw-r--r--sources/pyside2/doc/quickstart.rst6
-rw-r--r--sources/pyside2/pyside_version.py2
-rw-r--r--sources/pyside2/tests/QtCore/bug_686.py2
-rw-r--r--sources/pyside2/tests/QtCore/qsettings_test.py10
-rw-r--r--sources/pyside2/tests/QtDataVisualization/datavisualization_test.py13
-rw-r--r--sources/pyside2/tests/QtGui/qdatastream_gui_operators_test.py8
-rw-r--r--sources/shiboken2/ApiExtractor/abstractmetabuilder.cpp7
-rw-r--r--sources/shiboken2/ApiExtractor/abstractmetalang.cpp12
-rw-r--r--sources/shiboken2/ApiExtractor/abstractmetalang.h8
-rw-r--r--sources/shiboken2/ApiExtractor/qtdocparser.cpp36
-rw-r--r--sources/shiboken2/ApiExtractor/tests/testmodifydocumentation.cpp7
-rw-r--r--sources/shiboken2/CMakeLists.txt29
-rw-r--r--sources/shiboken2/doc/typesystem_codeinjection.rst20
-rw-r--r--sources/shiboken2/doc/typesystem_conversionrule.rst4
-rw-r--r--sources/shiboken2/doc/typesystem_variables.rst12
-rw-r--r--sources/shiboken2/generator/qtdoc/qtdocgenerator.cpp33
-rw-r--r--sources/shiboken2/generator/shiboken2/cppgenerator.cpp59
-rw-r--r--sources/shiboken2/generator/shiboken2/cppgenerator.h3
-rw-r--r--sources/shiboken2/libshiboken/CMakeLists.txt24
-rw-r--r--sources/shiboken2/libshiboken/embed/embedding_generator.py22
-rw-r--r--sources/shiboken2/libshiboken/sbkarrayconverter.cpp1
-rw-r--r--sources/shiboken2/libshiboken/shibokenbuffer.cpp23
-rw-r--r--sources/shiboken2/libshiboken/shibokenbuffer.h8
-rw-r--r--sources/shiboken2/libshiboken/signature/signature.cpp2
-rw-r--r--sources/shiboken2/shiboken_version.py2
-rw-r--r--sources/shiboken2/shibokenmodule/CMakeLists.txt37
-rw-r--r--sources/shiboken2/shibokenmodule/files.dir/shibokensupport/feature.py (renamed from sources/shiboken2/shibokenmodule/files.dir/shibokensupport/__feature__.py)0
-rw-r--r--sources/shiboken2/shibokenmodule/files.dir/shibokensupport/signature/lib/enum_sig.py2
-rw-r--r--sources/shiboken2/shibokenmodule/files.dir/shibokensupport/signature/loader.py27
-rw-r--r--sources/shiboken2/shibokenmodule/files.dir/shibokensupport/signature/mapping.py4
-rw-r--r--sources/shiboken2/shibokenmodule/files.dir/shibokensupport/signature/parser.py16
-rw-r--r--tools/license_changer.py85
-rw-r--r--tools/license_check.py70
-rw-r--r--tools/uic_test.py123
51 files changed, 1053 insertions, 229 deletions
diff --git a/build_scripts/main.py b/build_scripts/main.py
index 796ea2040..461e5a712 100644
--- a/build_scripts/main.py
+++ b/build_scripts/main.py
@@ -805,6 +805,8 @@ class PysideBuild(_build, DistUtilsCommandMixin):
# Add source location for generating documentation
cmake_src_dir = OPTION["QT_SRC"] if OPTION["QT_SRC"] else qt_src_dir
cmake_cmd.append("-DQT_SRC_DIR={}".format(cmake_src_dir))
+ if OPTION['SKIP_DOCS']:
+ cmake_cmd.append("-DSKIP_DOCS=yes")
log.info("Qt Source dir: {}".format(cmake_src_dir))
if self.build_type.lower() == 'debug':
@@ -905,15 +907,18 @@ class PysideBuild(_build, DistUtilsCommandMixin):
cmake_cmd.append("-DCMAKE_C_COMPILER=cl.exe")
cmake_cmd.append("-DCMAKE_CXX_COMPILER=cl.exe")
- if OPTION["DOC_BUILD_ONLINE"]:
- log.info("Output format will be HTML")
- cmake_cmd.append("-DDOC_OUTPUT_FORMAT=html")
- else:
- log.info("Output format will be qthelp")
- cmake_cmd.append("-DDOC_OUTPUT_FORMAT=qthelp")
+ if not OPTION["SKIP_DOCS"]:
+ # Build the whole documentation (rst + API) by default
+ cmake_cmd.append("-DFULLDOCSBUILD=1")
- # Build the whole documentation (rst + API) by default
- cmake_cmd.append("-DFULLDOCSBUILD=1")
+ if OPTION["DOC_BUILD_ONLINE"]:
+ log.info("Output format will be HTML")
+ cmake_cmd.append("-DDOC_OUTPUT_FORMAT=html")
+ else:
+ log.info("Output format will be qthelp")
+ cmake_cmd.append("-DDOC_OUTPUT_FORMAT=qthelp")
+ else:
+ cmake_cmd.append("-DSKIP_DOCS=1")
if not OPTION["SKIP_CMAKE"]:
log.info("Configuring module {} ({})...".format(extension, module_src_dir))
@@ -930,6 +935,13 @@ class PysideBuild(_build, DistUtilsCommandMixin):
if run_process(cmd_make) != 0:
raise DistutilsSetupError("Error compiling {}".format(extension))
+ if sys.version_info == (3, 6) and sys.platform == "darwin":
+ # Python 3.6 has a Sphinx problem because of docutils 0.17 .
+ # Instead of pinning v0.16, setting the default encoding fixes that.
+ # Since other platforms are not affected, we restrict this to macOS.
+ if "UTF-8" not in os.environ.get("LC_ALL", ""):
+ os.environ["LC_ALL"] = "en_US.UTF-8"
+
if not OPTION["SKIP_DOCS"]:
if extension.lower() == "shiboken2":
try:
@@ -944,6 +956,7 @@ class PysideBuild(_build, DistUtilsCommandMixin):
log.info("Sphinx not found, skipping documentation build")
else:
log.info("Skipped documentation generation")
+ cmake_cmd.append("-DSKIP_DOCS=1")
if not OPTION["SKIP_MAKE_INSTALL"]:
log.info("Installing module {}...".format(extension))
diff --git a/coin/dependencies.yaml b/coin/dependencies.yaml
new file mode 100644
index 000000000..c2717bc08
--- /dev/null
+++ b/coin/dependencies.yaml
@@ -0,0 +1,46 @@
+product_dependency:
+ ../../qt/tqtc-qt5.git:
+ ref: "ce5066de40100b04dee7087c7b860693b379c990"
+dependency_source: supermodule
+dependencies: [
+ "../../qt/qt3d",
+ "../../qt/qtactiveqt",
+ "../../qt/qtandroidextras",
+ "../../qt/qtbase",
+ "../../qt/qtcharts",
+ "../../qt/qtconnectivity",
+ "../../qt/qtdatavis3d",
+ "../../qt/qtdeclarative",
+ "../../qt/qtdoc",
+ "../../qt/qtgamepad",
+ "../../qt/qtgraphicaleffects",
+ "../../qt/qtimageformats",
+ "../../qt/qtlocation",
+ "../../qt/qtlottie",
+ "../../qt/qtmacextras",
+ "../../qt/qtmultimedia",
+ "../../qt/qtnetworkauth",
+ "../../qt/qtpurchasing",
+ "../../qt/qtqa",
+ "../../qt/qtquick3d",
+ "../../qt/qtquickcontrols2",
+ "../../qt/qtquicktimeline",
+ "../../qt/qtremoteobjects",
+ "../../qt/qtscxml",
+ "../../qt/qtsensors",
+ "../../qt/qtserialbus",
+ "../../qt/qtserialport",
+ "../../qt/qtspeech",
+ "../../qt/qtsvg",
+ "../../qt/qttools",
+ "../../qt/qttranslations",
+ "../../qt/qtvirtualkeyboard",
+ "../../qt/qtwayland",
+ "../../qt/qtwebchannel",
+ "../../qt/qtwebengine",
+ "../../qt/qtwebglplugin",
+ "../../qt/qtwebsockets",
+ "../../qt/qtwebview",
+ "../../qt/qtwinextras",
+ "../../qt/qtx11extras"
+ ]
diff --git a/dist/changes-5.15.4 b/dist/changes-5.15.4
new file mode 100644
index 000000000..a97be5dc6
--- /dev/null
+++ b/dist/changes-5.15.4
@@ -0,0 +1,38 @@
+Qt for Python 5.15.4 is a bug-fix release.
+
+For more details, refer to the online documentation included in this
+distribution. The documentation is also available online:
+
+https://doc.qt.io/qtforpython/
+
+Some of the changes listed in this file include issue tracking numbers
+corresponding to tasks in the Qt Bug Tracker:
+
+https://bugreports.qt.io/
+
+Each of these identifiers can be entered in the bug tracker to obtain more
+information about a particular change.
+
+****************************************************************************
+* PySide2 *
+****************************************************************************
+
+ - [PYSIDE-955] QOpenGLContext.versionFunctions() have been implemented.
+ Class QOpenGLVersionFunctionsFactory (from Qt 6) has also
+ been added.
+ - [PYSIDE-1409] signature: The decision heuristics of result tuples have
+ been refined.
+ - [PYSIDE-1438] Crashes in Qt Datavisualization's QBar/SurfaceDataProxy
+ add/set/insertRow() members have been fixed.
+ - [PYSIDE-1502] Import errors will now be properly reported.
+ - [PYSIDE-1513] Documentation on properties has been added.
+ - [PYSIDE-1538] signature: Unrecognized items will no longer raise
+ exceptions.
+ - [PYSIDE-1540] The performance of QPainter::drawPoints(QPolygon) has been
+ improved.
+
+****************************************************************************
+* Shiboken2 *
+****************************************************************************
+
+ - [PYSIDE-1529] Crashes when registering static fields have been fixed.
diff --git a/examples/widgets/richtext/textobject/textobject.py b/examples/widgets/richtext/textobject/textobject.py
index b828ea3d0..e82ea95dc 100644
--- a/examples/widgets/richtext/textobject/textobject.py
+++ b/examples/widgets/richtext/textobject/textobject.py
@@ -42,13 +42,17 @@
"""PySide2 port of the widgets/richtext/textobject example from Qt v5.x"""
+import os
+
from PySide2 import QtCore, QtGui, QtWidgets, QtSvg
-class SvgTextObject(QtCore.QObject, QtGui.QTextObjectInterface):
+class SvgTextObject(QtGui.QPyTextObject):
+ def __init__(self, parent=None):
+ super(SvgTextObject, self).__init__(parent)
def intrinsicSize(self, doc, posInDocument, format):
- renderer = QtSvg.QSvgRenderer(format.property(Window.SvgData).toByteArray())
+ renderer = QtSvg.QSvgRenderer(format.property(Window.SvgData))
size = renderer.defaultSize()
if size.height() > 25:
@@ -57,7 +61,7 @@ class SvgTextObject(QtCore.QObject, QtGui.QTextObjectInterface):
return QtCore.QSizeF(size)
def drawObject(self, painter, rect, doc, posInDocument, format):
- renderer = QtSvg.QSvgRenderer(format.property(Window.SvgData).toByteArray())
+ renderer = QtSvg.QSvgRenderer(format.property(Window.SvgData))
renderer.render(painter, rect)
@@ -80,8 +84,10 @@ class Window(QtWidgets.QWidget):
file = QtCore.QFile(fileName)
if not file.open(QtCore.QIODevice.ReadOnly):
- QtWidgets.QMessageBox.warning(self, self.tr("Error Opening File"),
- self.tr("Could not open '%1'").arg(fileName))
+ reason = file.errorString()
+ message = "Could not open '{}': {}".format(fileName, reason)
+ QtWidgets.QMessageBox.warning(self, "Error Opening File",
+ message.arg(fileName))
svgData = file.readAll()
@@ -90,7 +96,7 @@ class Window(QtWidgets.QWidget):
svgCharFormat.setProperty(Window.SvgData, svgData)
cursor = self.textEdit.textCursor()
- cursor.insertText(u"\uFFFD", svgCharFormat)
+ cursor.insertText(chr(0xfffc), svgCharFormat)
self.textEdit.setTextCursor(cursor)
def setupTextObject(self):
@@ -102,8 +108,9 @@ class Window(QtWidgets.QWidget):
self.fileNameLineEdit = QtWidgets.QLineEdit()
insertTextObjectButton = QtWidgets.QPushButton(self.tr("Insert Image"))
- self.fileNameLineEdit.setText('./files/heart.svg')
- QtCore.QObject.connect(insertTextObjectButton, QtCore.SIGNAL('clicked()'), self.insertTextObject)
+ file = os.path.join(os.path.dirname(__file__), 'files', 'heart.svg')
+ self.fileNameLineEdit.setText(file)
+ insertTextObjectButton.clicked.connect(self.insertTextObject)
bottomLayout = QtWidgets.QHBoxLayout()
bottomLayout.addWidget(fileNameLabel)
diff --git a/product_dependencies.yaml b/product_dependencies.yaml
deleted file mode 100644
index ab9fb943e..000000000
--- a/product_dependencies.yaml
+++ /dev/null
@@ -1,3 +0,0 @@
-dependencies:
- ../../qt/tqtc-qt5.git:
- ref: "06ddf5f2dd73cf63ec554a104b7e5e2a56920239"
diff --git a/sources/pyside2/CMakeLists.txt b/sources/pyside2/CMakeLists.txt
index dc2beded0..4336d6cc4 100644
--- a/sources/pyside2/CMakeLists.txt
+++ b/sources/pyside2/CMakeLists.txt
@@ -268,7 +268,7 @@ endif ()
find_program(SPHINX_BUILD sphinx-build)
find_program(DOT_EXEC dot)
-if (QT_SRC_DIR AND SPHINX_BUILD AND DOT_EXEC)
+if (QT_SRC_DIR AND SPHINX_BUILD AND DOT_EXEC AND NOT SKIP_DOCS)
add_subdirectory(doc)
else ()
set(DOCS_TARGET_DISABLED_MESSAGE "apidoc generation targets disabled.")
diff --git a/sources/pyside2/PySide2/QtDataVisualization/typesystem_datavisualization.xml b/sources/pyside2/PySide2/QtDataVisualization/typesystem_datavisualization.xml
index f10aeea3e..5dc87a013 100644
--- a/sources/pyside2/PySide2/QtDataVisualization/typesystem_datavisualization.xml
+++ b/sources/pyside2/PySide2/QtDataVisualization/typesystem_datavisualization.xml
@@ -119,56 +119,43 @@
<parent index="this" action="add"/>
</modify-argument>
</modify-function>
- <modify-function signature="addRow(QVector&lt;QtDataVisualization::QBarDataItem&gt;*)">
- <modify-argument index="1">
- <parent index="this" action="add"/>
- </modify-argument>
- </modify-function>
- <modify-function signature="addRow(QVector&lt;QtDataVisualization::QBarDataItem&gt;*, const QString&amp;)">
- <modify-argument index="1">
- <parent index="this" action="add"/>
- </modify-argument>
- </modify-function>
- <modify-function signature="addRows(const QtDataVisualization::QBarDataArray&amp;)">
- <modify-argument index="1">
- <parent index="this" action="add"/>
- </modify-argument>
- </modify-function>
- <modify-function signature="addRows(const QtDataVisualization::QBarDataArray&amp;, const QStringList&amp;)">
- <modify-argument index="1">
- <parent index="this" action="add"/>
- </modify-argument>
- </modify-function>
- <modify-function signature="insertRow(int, QVector&lt;QtDataVisualization::QBarDataItem&gt;*)">
- <modify-argument index="2">
- <parent index="this" action="add"/>
- </modify-argument>
- </modify-function>
- <modify-function signature="insertRow(int, QVector&lt;QtDataVisualization::QBarDataItem&gt;*, const QString&amp;)">
- <modify-argument index="2">
- <parent index="this" action="add"/>
- </modify-argument>
- </modify-function>
- <modify-function signature="insertRows(int, const QtDataVisualization::QBarDataArray&amp;)">
- <modify-argument index="2">
- <parent index="this" action="add"/>
- </modify-argument>
- </modify-function>
- <modify-function signature="insertRows(int, const QtDataVisualization::QBarDataArray&amp;, const QStringList&amp;)">
- <modify-argument index="2">
- <parent index="this" action="add"/>
- </modify-argument>
- </modify-function>
- <modify-function signature="setRow(int, QVector&lt;QtDataVisualization::QBarDataItem&gt;*)">
- <modify-argument index="2">
- <parent index="this" action="add"/>
- </modify-argument>
- </modify-function>
- <modify-function signature="setRow(int, QVector&lt;QtDataVisualization::QBarDataItem&gt;*, const QString&amp;)">
- <modify-argument index="2">
- <parent index="this" action="add"/>
- </modify-argument>
- </modify-function>
+
+ <!-- PYSIDE-1438: Replace all add/set/insertRow() taking a 'QVector*' by overloads
+ taking 'const QVector &' since an allocated list needs to be passed. -->
+ <modify-function signature="addRow(QVector&lt;QtDataVisualization::QBarDataItem&gt;*)" remove="all"/>
+ <add-function signature="addRow(const QVector&lt;QtDataVisualization::QBarDataItem&gt;&amp;)" return-type="int">
+ <inject-code class="target" position="beginning" file="../glue/qtdatavisualization.cpp"
+ snippet="dataproxy-addrow"/>
+ </add-function>
+ <modify-function signature="addRow(QVector&lt;QtDataVisualization::QBarDataItem&gt;*,const QString&amp;)" remove="all"/>
+ <add-function signature="addRow(const QVector&lt;QtDataVisualization::QBarDataItem&gt;&amp;,const QString&amp;)"
+ return-type="int">
+ <inject-code class="target" position="beginning" file="../glue/qtdatavisualization.cpp"
+ snippet="dataproxy-addrow-string"/>
+ </add-function>
+
+ <modify-function signature="insertRow(int,QVector&lt;QtDataVisualization::QBarDataItem&gt;*)" remove="all"/>
+ <add-function signature="insertRow(int,const QVector&lt;QtDataVisualization::QBarDataItem&gt;&amp;)">
+ <inject-code class="target" position="beginning" file="../glue/qtdatavisualization.cpp"
+ snippet="dataproxy-insertrow"/>
+ </add-function>
+ <modify-function signature="insertRow(int,QVector&lt;QtDataVisualization::QBarDataItem&gt;*,const QString&amp;)" remove="all"/>
+ <add-function signature="insertRow(int,const QVector&lt;QtDataVisualization::QBarDataItem&gt;&amp;, const QString&amp;)">
+ <inject-code class="target" position="beginning" file="../glue/qtdatavisualization.cpp"
+ snippet="dataproxy-insertrow-string"/>
+ </add-function>
+
+ <modify-function signature="setRow(int,QVector&lt;QtDataVisualization::QBarDataItem&gt;*)" remove="all"/>
+ <add-function signature="setRow(int,const QVector&lt;QtDataVisualization::QBarDataItem&gt;&amp;)">
+ <inject-code class="target" position="beginning" file="../glue/qtdatavisualization.cpp"
+ snippet="dataproxy-setrow"/>
+ </add-function>
+ <modify-function signature="setRow(int,QVector&lt;QtDataVisualization::QBarDataItem&gt;*,const QString&amp;)" remove="all"/>
+ <add-function signature="setRow(int,const QVector&lt;QtDataVisualization::QBarDataItem&gt;&amp;,const QString&amp;)">
+ <inject-code class="target" position="beginning" file="../glue/qtdatavisualization.cpp"
+ snippet="dataproxy-setrow-string"/>
+ </add-function>
+
<modify-function signature="setRows(int, const QtDataVisualization::QBarDataArray&amp;)">
<modify-argument index="2">
<parent index="this" action="add"/>
@@ -182,7 +169,13 @@
</object-type>
<object-type name="QCustom3DItem"/>
<object-type name="QCustom3DLabel"/>
- <object-type name="QCustom3DVolume"/>
+ <object-type name="QCustom3DVolume">
+ <modify-function signature="setTextureData(QVector&lt;uchar&gt;*)" remove="all"/>
+ <add-function signature="setTextureData(const QVector&lt;uchar&gt;&amp;)">
+ <inject-code class="target" position="beginning" file="../glue/qtdatavisualization.cpp"
+ snippet="qcustom3dvolume-settexturedata"/>
+ </add-function>
+ </object-type>
<object-type name="QHeightMapSurfaceDataProxy"/>
<object-type name="QItemModelBarDataProxy">
<enum-type name="MultiMatchBehavior"/>
@@ -251,21 +244,27 @@
</object-type>
<value-type name="QSurfaceDataItem"/>
<object-type name="QSurfaceDataProxy">
- <modify-function signature="addRow(QVector&lt;QtDataVisualization::QSurfaceDataItem&gt;*)">
- <modify-argument index="1">
- <parent index="this" action="add"/>
- </modify-argument>
- </modify-function>
- <modify-function signature="insertRow(int, QVector&lt;QtDataVisualization::QSurfaceDataItem&gt;*)">
- <modify-argument index="2">
- <parent index="this" action="add"/>
- </modify-argument>
- </modify-function>
- <modify-function signature="setRow(int, QVector&lt;QtDataVisualization::QSurfaceDataItem&gt;*)">
- <modify-argument index="2">
- <parent index="this" action="add"/>
- </modify-argument>
- </modify-function>
+
+ <!-- PYSIDE-1438: Replace all add/set/insertRow() taking a 'QVector*' by overloads
+ taking 'const QVector &' since an allocated list needs to be passed. -->
+ <modify-function signature="addRow(QVector&lt;QtDataVisualization::QSurfaceDataItem&gt;*)" remove="all"/>
+ <add-function signature="addRow(const QVector&lt;QtDataVisualization::QSurfaceDataItem&gt;&amp;)" return-type="int">
+ <inject-code class="target" position="beginning" file="../glue/qtdatavisualization.cpp"
+ snippet="dataproxy-addrow"/>
+ </add-function>
+
+ <modify-function signature="insertRow(int,QVector&lt;QtDataVisualization::QSurfaceDataItem&gt;*)" remove="all"/>
+ <add-function signature="insertRow(int,const QVector&lt;QtDataVisualization::QSurfaceDataItem&gt;&amp;)">
+ <inject-code class="target" position="beginning" file="../glue/qtdatavisualization.cpp"
+ snippet="dataproxy-insertrow"/>
+ </add-function>
+
+ <modify-function signature="setRow(int,QVector&lt;QtDataVisualization::QSurfaceDataItem&gt;*)" remove="all"/>
+ <add-function signature="setRow(int,const QVector&lt;QtDataVisualization::QSurfaceDataItem&gt;&amp;)">
+ <inject-code class="target" position="beginning" file="../glue/qtdatavisualization.cpp"
+ snippet="dataproxy-setrow"/>
+ </add-function>
+
<modify-function signature="resetArray(QtDataVisualization::QSurfaceDataArray*)">
<modify-argument index="1">
<parent index="this" action="add"/>
diff --git a/sources/pyside2/PySide2/QtGui/typesystem_gui_common.xml b/sources/pyside2/PySide2/QtGui/typesystem_gui_common.xml
index aa8391f8f..b0c61fe64 100644
--- a/sources/pyside2/PySide2/QtGui/typesystem_gui_common.xml
+++ b/sources/pyside2/PySide2/QtGui/typesystem_gui_common.xml
@@ -1871,18 +1871,23 @@
<modify-function signature="drawRects(const QRect*,int)" remove="all"/>
<modify-function signature="drawRects(const QRectF*,int)" remove="all"/>
<!-- ### -->
+ <!-- PYSIDE-1540: Preferably use the QPolygon overloads first to avoid
+ a costly sequence type check on QPolygon. -->
<modify-function signature="drawPoints(const QPoint*,int)" remove="all"/>
- <add-function signature="drawPoints(QVector&lt;QPoint>)">
+ <add-function signature="drawPoints(QVector&lt;QPoint>)" overload-number="2">
<inject-code>
<insert-template name="qpainter_drawlist"/>
</inject-code>
</add-function>
<modify-function signature="drawPoints(const QPointF*,int)" remove="all"/>
- <add-function signature="drawPoints(QVector&lt;QPointF>)">
+ <add-function signature="drawPoints(QVector&lt;QPointF>)" overload-number="3">
<inject-code>
<insert-template name="qpainter_drawlist"/>
</inject-code>
</add-function>
+ <modify-function signature="drawPoints(const QPolygon&amp;)" overload-number="0"/>
+ <modify-function signature="drawPoints(const QPolygonF&amp;)" overload-number="1"/>
+
<modify-function signature="drawPolygon(const QPoint*,int,Qt::FillRule)" remove="all"/>
<add-function signature="drawPolygon(QVector&lt;QPoint>,Qt::FillRule)">
<inject-code file="../glue/qtgui.cpp" snippet="qpainter-drawpolygon"/>
@@ -2601,6 +2606,10 @@
</object-type>
<object-type name="QOpenGLContext">
<enum-type name="OpenGLModuleType"/>
+ <modify-function signature="versionFunctions(const QOpenGLVersionProfile&amp;) const">
+ <inject-code class="target" position="beginning" file="../glue/qtgui.cpp"
+ snippet="qopenglcontext-versionfunctions"/>
+ </modify-function>
</object-type>
<object-type name="QOpenGLContextGroup" since="5.0"/>
<object-type name="QOpenGLDebugLogger" since="5.1">
@@ -2835,7 +2844,8 @@
<modify-argument index="return">
<replace-type modified-type="QString"/>
</modify-argument>
- <inject-code class="target" position="beginning" file="../glue/qtcore.cpp" snippet="qstring-return"/>
+ <inject-code class="target" position="end" file="../glue/qtgui.cpp"
+ snippet="glgetstring-return"/>
</modify-function>
</object-type>
<object-type name="QOpenGLFunctions" since="5.0">
diff --git a/sources/pyside2/PySide2/QtOpenGLFunctions/CMakeLists.txt b/sources/pyside2/PySide2/QtOpenGLFunctions/CMakeLists.txt
index 383afb68f..62ed669cc 100644
--- a/sources/pyside2/PySide2/QtOpenGLFunctions/CMakeLists.txt
+++ b/sources/pyside2/PySide2/QtOpenGLFunctions/CMakeLists.txt
@@ -42,7 +42,8 @@ else()
${QtOpenGLFunctions_GEN_DIR}/qopenglfunctions_4_4_compatibility_wrapper.cpp
${QtOpenGLFunctions_GEN_DIR}/qopenglfunctions_4_4_core_wrapper.cpp
${QtOpenGLFunctions_GEN_DIR}/qopenglfunctions_4_5_compatibility_wrapper.cpp
- ${QtOpenGLFunctions_GEN_DIR}/qopenglfunctions_4_5_core_wrapper.cpp)
+ ${QtOpenGLFunctions_GEN_DIR}/qopenglfunctions_4_5_core_wrapper.cpp
+ ${QtOpenGLFunctions_GEN_DIR}/qopenglversionfunctionsfactory_wrapper.cpp)
message(STATUS "Qt${QT_MAJOR_VERSION}OpenGLFunctions: Adding Desktop OpenGL classes")
endif()
@@ -71,3 +72,6 @@ create_pyside_module(NAME QtOpenGLFunctions
SOURCES QtOpenGLFunctions_SRC
TYPESYSTEM_NAME ${QtOpenGLFunctions_BINARY_DIR}/typesystem_openglfunctions.xml
DROPPED_ENTRIES QtOpenGLFunctions_DROPPED_ENTRIES)
+
+install(FILES ${pyside2_SOURCE_DIR}/qopenglversionfunctionsfactory.h
+ DESTINATION include/PySide2/QtOpenGLFunctions)
diff --git a/sources/pyside2/PySide2/QtOpenGLFunctions/QtOpenGLFunctions_global.post.h.in b/sources/pyside2/PySide2/QtOpenGLFunctions/QtOpenGLFunctions_global.post.h.in
index 6c8c77087..e43bc2b81 100644
--- a/sources/pyside2/PySide2/QtOpenGLFunctions/QtOpenGLFunctions_global.post.h.in
+++ b/sources/pyside2/PySide2/QtOpenGLFunctions/QtOpenGLFunctions_global.post.h.in
@@ -59,3 +59,5 @@
#if QT_CONFIG(opengles2)
# include <QtGui/qopenglfunctions_es2.h>
#endif
+
+#include "qopenglversionfunctionsfactory.h" // PySide class
diff --git a/sources/pyside2/PySide2/QtOpenGLFunctions/typesystem_openglfunctions.xml b/sources/pyside2/PySide2/QtOpenGLFunctions/typesystem_openglfunctions.xml
index 1d5b08edb..edb271362 100644
--- a/sources/pyside2/PySide2/QtOpenGLFunctions/typesystem_openglfunctions.xml
+++ b/sources/pyside2/PySide2/QtOpenGLFunctions/typesystem_openglfunctions.xml
@@ -404,6 +404,15 @@
&openglfunctions_modifications1_0;
&openglfunctions_modifications1_1;
</object-type>
+
+ <object-type name="QOpenGLVersionFunctionsFactory">
+ <modify-function signature="get(const QOpenGLVersionProfile&amp;,QOpenGLContext*)"
+ return-type="QAbstractOpenGLFunctions*">
+ <inject-code class="target" position="beginning" file="../glue/qtopenglfunctions.cpp"
+ snippet="qopenglversionfunctionsfactory-get"/>
+ </modify-function>
+ </object-type>
+
<suppress-warning text="^There's no user provided way.*QOpenGLFunctions_\d_\d.*::glIndex.*$"/>
</typesystem>
diff --git a/sources/pyside2/PySide2/glue/qtdatavisualization.cpp b/sources/pyside2/PySide2/glue/qtdatavisualization.cpp
index 119d79a40..ce5aa6932 100644
--- a/sources/pyside2/PySide2/glue/qtdatavisualization.cpp
+++ b/sources/pyside2/PySide2/glue/qtdatavisualization.cpp
@@ -40,3 +40,40 @@
// @snippet releaseownership
Shiboken::Object::releaseOwnership(%PYARG_1);
// @snippet releaseownership
+
+// @snippet qcustom3dvolume-settexturedata
+using VectorType = decltype(%1);
+%CPPSELF.setTextureData(new VectorType(%1));
+// @snippet qcustom3dvolume-settexturedata
+
+// @snippet dataproxy-addrow
+using VectorType = decltype(%1);
+%RETURN_TYPE %0 = %CPPSELF.addRow(new VectorType(%1));
+%PYARG_0 = %CONVERTTOPYTHON[%RETURN_TYPE](%0);
+// @snippet dataproxy-addrow
+
+// @snippet dataproxy-addrow-string
+using VectorType = decltype(%1);
+%RETURN_TYPE %0 = %CPPSELF.addRow(new VectorType(%1), %2);
+%PYARG_0 = %CONVERTTOPYTHON[%RETURN_TYPE](%0);
+// @snippet dataproxy-addrow-string
+
+// @snippet dataproxy-insertrow
+using VectorType = decltype(%2);
+%CPPSELF.insertRow(%1, new VectorType(%2));
+// @snippet dataproxy-insertrow
+
+// @snippet dataproxy-insertrow-string
+using VectorType = decltype(%2);
+%CPPSELF.insertRow(%1, new VectorType(%2), %3);
+// @snippet dataproxy-insertrow-string
+
+// @snippet dataproxy-setrow
+using VectorType = decltype(%2);
+%CPPSELF.setRow(%1, new VectorType(%2));
+// @snippet dataproxy-setrow
+
+// @snippet dataproxy-setrow-string
+using VectorType = decltype(%2);
+%CPPSELF.setRow(%1, new VectorType(%2), %3);
+// @snippet dataproxy-setrow-string
diff --git a/sources/pyside2/PySide2/glue/qtgui.cpp b/sources/pyside2/PySide2/glue/qtgui.cpp
index e802a9f59..1c74c73d2 100644
--- a/sources/pyside2/PySide2/glue/qtgui.cpp
+++ b/sources/pyside2/PySide2/glue/qtgui.cpp
@@ -41,6 +41,27 @@
* INJECT CODE
********************************************************************/
+// @snippet qopenglcontext-versionfunctions
+
+// %CPPSELF.%FUNCTION_NAME(%1, %2); Pretend to shiboken we call the function
+
+// Import QtOpenGLFunctions and call the factory function
+// QOpenGLVersionFunctionsFactory.get()
+PyObject *module = PyImport_ImportModule("PySide2.QtOpenGLFunctions");
+if (module == nullptr)
+ return nullptr;
+PyObject *loc = PyModule_GetDict(module);
+static PyObject *const factoryName =
+ Shiboken::String::createStaticString("QOpenGLVersionFunctionsFactory");
+auto factory = PyDict_GetItem(loc, factoryName);
+if (factory == nullptr)
+ return nullptr;
+
+static PyObject *const getMethod = Shiboken::String::createStaticString("get");
+%PYARG_0 = PyObject_CallMethodObjArgs(factory, getMethod, pyArgs[0], %PYSELF,
+ nullptr);
+// @snippet qopenglcontext-versionfunctions
+
// @snippet glgetshadersource
GLsizei bufSize = 4096;
GLsizei length = bufSize - 1;
@@ -63,6 +84,10 @@ const char *sources[] = {buffer.constData()};
%CPPSELF->%FUNCTION_NAME(%1, 1, sources, nullptr);
// @snippet glshadersource
+// @snippet glgetstring-return
+%PYARG_0 = %CONVERTTOPYTHON[const char *](%0);
+// @snippet glgetstring-return
+
// @snippet qtransform-quadtoquad
QTransform _result;
if (QTransform::quadToQuad(%1, %2, _result)) {
diff --git a/sources/pyside2/PySide2/glue/qtopenglfunctions.cpp b/sources/pyside2/PySide2/glue/qtopenglfunctions.cpp
new file mode 100644
index 000000000..c839ae44b
--- /dev/null
+++ b/sources/pyside2/PySide2/glue/qtopenglfunctions.cpp
@@ -0,0 +1,76 @@
+/****************************************************************************
+**
+** Copyright (C) 2021 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt for Python.
+**
+** $QT_BEGIN_LICENSE:COMM$
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+// @snippet qopenglversionfunctionsfactory-get
+QAbstractOpenGLFunctions *af = %CPPSELF.%FUNCTION_NAME(%1, %2);
+if (auto *f = dynamic_cast<QOpenGLFunctions_4_5_Core *>(af)) {
+ %PYARG_0 = %CONVERTTOPYTHON[QOpenGLFunctions_4_5_Core *](f);
+} else if (auto *f = dynamic_cast<QOpenGLFunctions_4_5_Compatibility *>(af)) {
+ %PYARG_0 = %CONVERTTOPYTHON[QOpenGLFunctions_4_5_Compatibility *](f);
+} else if (auto *f = dynamic_cast<QOpenGLFunctions_4_4_Core *>(af)) {
+ %PYARG_0 = %CONVERTTOPYTHON[QOpenGLFunctions_4_4_Core *](f);
+} else if (auto *f = dynamic_cast<QOpenGLFunctions_4_4_Compatibility *>(af)) {
+ %PYARG_0 = %CONVERTTOPYTHON[QOpenGLFunctions_4_4_Compatibility *](f);
+} else if (auto *f = dynamic_cast<QOpenGLFunctions_4_3_Core *>(af)) {
+ %PYARG_0 = %CONVERTTOPYTHON[QOpenGLFunctions_4_3_Core *](f);
+} else if (auto *f = dynamic_cast<QOpenGLFunctions_4_2_Core *>(af)) {
+ %PYARG_0 = %CONVERTTOPYTHON[QOpenGLFunctions_4_2_Core *](f);
+} else if (auto *f = dynamic_cast<QOpenGLFunctions_4_1_Core *>(af)) {
+ %PYARG_0 = %CONVERTTOPYTHON[QOpenGLFunctions_4_1_Core *](f);
+} else if (auto *f = dynamic_cast<QOpenGLFunctions_4_0_Core *>(af)) {
+ %PYARG_0 = %CONVERTTOPYTHON[QOpenGLFunctions_4_0_Core *](f);
+} else if (auto *f = dynamic_cast<QOpenGLFunctions_4_0_Compatibility *>(af)) {
+ %PYARG_0 = %CONVERTTOPYTHON[QOpenGLFunctions_4_0_Compatibility *](f);
+} else if (auto *f = dynamic_cast<QOpenGLFunctions_3_3_Core *>(af)) {
+ %PYARG_0 = %CONVERTTOPYTHON[QOpenGLFunctions_3_3_Core *](f);
+} else if (auto *f = dynamic_cast<QOpenGLFunctions_3_3_Compatibility *>(af)) {
+ %PYARG_0 = %CONVERTTOPYTHON[QOpenGLFunctions_3_3_Compatibility *](f);
+} else if (auto *f = dynamic_cast<QOpenGLFunctions_3_2_Core *>(af)) {
+ %PYARG_0 = %CONVERTTOPYTHON[QOpenGLFunctions_3_2_Core *](f);
+} else if (auto *f = dynamic_cast<QOpenGLFunctions_3_2_Compatibility *>(af)) {
+ %PYARG_0 = %CONVERTTOPYTHON[QOpenGLFunctions_3_2_Compatibility *](f);
+} else if (auto *f = dynamic_cast<QOpenGLFunctions_3_1 *>(af)) {
+ %PYARG_0 = %CONVERTTOPYTHON[QOpenGLFunctions_3_1 *](f);
+} else if (auto *f = dynamic_cast<QOpenGLFunctions_3_0 *>(af)) {
+ %PYARG_0 = %CONVERTTOPYTHON[QOpenGLFunctions_3_0 *](f);
+} else if (auto *f = dynamic_cast<QOpenGLFunctions_2_1 *>(af)) {
+ %PYARG_0 = %CONVERTTOPYTHON[QOpenGLFunctions_2_1 *](f);
+} else if (auto *f = dynamic_cast<QOpenGLFunctions_2_0 *>(af)) {
+ %PYARG_0 = %CONVERTTOPYTHON[QOpenGLFunctions_2_0 *](f);
+} else if (auto *f = dynamic_cast<QOpenGLFunctions_1_5 *>(af)) {
+ %PYARG_0 = %CONVERTTOPYTHON[QOpenGLFunctions_1_5 *](f);
+} else if (auto *f = dynamic_cast<QOpenGLFunctions_1_4 *>(af)) {
+ %PYARG_0 = %CONVERTTOPYTHON[QOpenGLFunctions_1_4 *](f);
+} else if (auto *f = dynamic_cast<QOpenGLFunctions_1_3 *>(af)) {
+ %PYARG_0 = %CONVERTTOPYTHON[QOpenGLFunctions_1_3 *](f);
+} else if (auto *f = dynamic_cast<QOpenGLFunctions_1_2 *>(af)) {
+ %PYARG_0 = %CONVERTTOPYTHON[QOpenGLFunctions_1_2 *](f);
+} else if (auto *f = dynamic_cast<QOpenGLFunctions_1_1 *>(af)) {
+ %PYARG_0 = %CONVERTTOPYTHON[QOpenGLFunctions_1_1 *](f);
+} else if (auto *f = dynamic_cast<QOpenGLFunctions_1_0 *>(af)) {
+ %PYARG_0 = %CONVERTTOPYTHON[QOpenGLFunctions_1_0 *](f);
+} else {
+ QString message;
+ QDebug(&message) << "No OpenGL functions could be obtained for" << %1;
+ PyErr_SetString(PyExc_RuntimeError, message.toUtf8().constData());
+ %PYARG_0 = Py_None;
+}
+// @snippet qopenglversionfunctionsfactory-get
diff --git a/sources/pyside2/PySide2/qopenglversionfunctionsfactory.h b/sources/pyside2/PySide2/qopenglversionfunctionsfactory.h
new file mode 100644
index 000000000..27b8373fa
--- /dev/null
+++ b/sources/pyside2/PySide2/qopenglversionfunctionsfactory.h
@@ -0,0 +1,45 @@
+/****************************************************************************
+**
+** Copyright (C) 2021 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt for Python.
+**
+** $QT_BEGIN_LICENSE:COMM$
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QOPENGLVERSIONFUNCTIONSFACTORY_H
+#define QOPENGLVERSIONFUNCTIONSFACTORY_H
+
+#include <QtGui/QOpenGLContext>
+
+QT_BEGIN_NAMESPACE
+
+class QOpenGLVersionProfile;
+
+class QOpenGLVersionFunctionsFactory
+{
+public:
+ static QAbstractOpenGLFunctions *get(const QOpenGLVersionProfile &versionProfile,
+ QOpenGLContext *context)
+ {
+ return context
+ ? context->versionFunctions(versionProfile)
+ : nullptr;
+ }
+};
+
+QT_END_NAMESPACE
+
+#endif // QOPENGLVERSIONFUNCTIONSFACTORY_H
diff --git a/sources/pyside2/PySide2/templates/gui_common.xml b/sources/pyside2/PySide2/templates/gui_common.xml
index a139a5fe9..16116877f 100644
--- a/sources/pyside2/PySide2/templates/gui_common.xml
+++ b/sources/pyside2/PySide2/templates/gui_common.xml
@@ -80,8 +80,8 @@
</template>
<template name="qimage_buffer_constructor">
- auto ptr = reinterpret_cast&lt;uchar*&gt;(Shiboken::Buffer::getPointer(%PYARG_1));
- %0 = new %TYPE(ptr, %ARGS);
+ auto *ptr = reinterpret_cast&lt;uchar *&gt;(Shiboken::Buffer::copyData(%PYARG_1));
+ %0 = new %TYPE(ptr, %ARGS, std::free);
</template>
<template name="qcolor_repr">
diff --git a/sources/pyside2/doc/extras/QtCore.Property.rst b/sources/pyside2/doc/extras/QtCore.Property.rst
index 8aa629f6b..6bcfc2655 100644
--- a/sources/pyside2/doc/extras/QtCore.Property.rst
+++ b/sources/pyside2/doc/extras/QtCore.Property.rst
@@ -9,7 +9,9 @@ Detailed Description
The Property function lets you declare properties that
behave both as Qt and Python properties, and have their
-setters and getters defined as Python functions.
+getters and setters defined as Python functions.
+
+They are equivalent to the ``Q_PROPERTY`` macro in the `Qt Docs`_.
Here is an example that illustrates how to use this
function:
@@ -20,14 +22,14 @@ function:
from PySide2.QtCore import QObject, Property
class MyObject(QObject):
- def __init__(self,startval=42):
+ def __init__(self, startval=42):
QObject.__init__(self)
self.ppval = startval
def readPP(self):
return self.ppval
- def setPP(self,val):
+ def setPP(self, val):
self.ppval = val
pp = Property(int, readPP, setPP)
@@ -36,6 +38,68 @@ function:
obj.pp = 47
print(obj.pp)
+The full options for ``QtCore.Property`` can be found with ``QtCore.Property.__doc__``:
+
+.. code-block::
+
+ Property(self, type: type,
+ fget: Optional[Callable] = None,
+ fset: Optional[Callable] = None,
+ freset: Optional[Callable] = None,
+ fdel: Optional[Callable] = None,
+ doc: str = '', notify: Optional[Callable] = None,
+ designable: bool = True, scriptable: bool = True,
+ stored: bool = True, user: bool = False,
+ constant: bool = False, final: bool = False) -> PySide2.QtCore.Property
+
+Normally, only ``type``, ``fget``and ``fset`` are used.
+
+
+Properties compared with Python properties
+------------------------------------------
+
+``Python`` has property objects very similar to ``QtCore.Property``.
+Despite the fact that the latter has an extra ``freset`` function, the usage
+of properties is almost the same. The main difference is that ``QtCore.Property``
+requires a ``type`` parameter.
+
+In the above example, the following lines would be equivalent properties:
+
+.. code-block::
+
+ pp = QtCore.Property(int, readPP, setPP) # PySide version
+ pp = property(readPP, setPP) # Python version
+
+As you know from the `Python Docs`_, ``Python`` allows to break the property
+creation into multiple steps, using the decorator syntax. We can do this in
+``PySide`` as well:
+
+.. code-block::
+ :linenos:
+
+ from PySide2.QtCore import QObject, Property
+
+ class MyObject(QObject):
+ def __init__(self, startval=42):
+ QObject.__init__(self)
+ self.ppval = startval
+
+ @Property(int)
+ def pp(self):
+ return self.ppval
+
+ @pp.setter
+ def pp(self, val):
+ self.ppval = val
+
+ obj = MyObject()
+ obj.pp = 47
+ print(obj.pp)
+
+Please be careful here: The two ``Python`` functions have the same name, intentionally.
+This is needed to let ``Python`` know that these functions belong to the same property.
+
+
Properties in QML expressions
-----------------------------
@@ -61,3 +125,6 @@ example illustrating how to do this:
pass
name = Property(str, _name, notify=name_changed)
+
+.. _`Python Docs`: https://docs.python.org/3/library/functions.html?highlight=property#property
+.. _`Qt Docs`: https://doc.qt.io/qt-5/properties.html
diff --git a/sources/pyside2/doc/quickstart.rst b/sources/pyside2/doc/quickstart.rst
index 87471a8a8..db2e93280 100644
--- a/sources/pyside2/doc/quickstart.rst
+++ b/sources/pyside2/doc/quickstart.rst
@@ -52,12 +52,6 @@ constructs to print version information::
# Prints the Qt version used to compile PySide2
print(PySide2.QtCore.__version__)
-.. note::
-
- As it happened in 5.14.2, PySide had a couple of new releases to fix
- issues in 5.14.2, adding yet another version level. In that case, you
- will have different versions being shown for Qt and PySide.
-
Create a Simple Application
---------------------------
diff --git a/sources/pyside2/pyside_version.py b/sources/pyside2/pyside_version.py
index 0985e2559..ecc975ddf 100644
--- a/sources/pyside2/pyside_version.py
+++ b/sources/pyside2/pyside_version.py
@@ -39,7 +39,7 @@
major_version = "5"
minor_version = "15"
-patch_version = "3"
+patch_version = "4"
# For example: "a", "b", "rc"
# (which means "alpha", "beta", "release candidate").
diff --git a/sources/pyside2/tests/QtCore/bug_686.py b/sources/pyside2/tests/QtCore/bug_686.py
index 6e4f8994a..d944cafe8 100644
--- a/sources/pyside2/tests/QtCore/bug_686.py
+++ b/sources/pyside2/tests/QtCore/bug_686.py
@@ -49,6 +49,7 @@ class MyWriteThread(QThread):
self.started = True
while not self.lock.tryLockForWrite():
pass
+ self.lock.unlock()
self.canQuit = True
class MyReadThread(QThread):
@@ -62,6 +63,7 @@ class MyReadThread(QThread):
self.started = True
while not self.lock.tryLockForRead():
pass
+ self.lock.unlock()
self.canQuit = True
class MyMutexedThread(QThread):
diff --git a/sources/pyside2/tests/QtCore/qsettings_test.py b/sources/pyside2/tests/QtCore/qsettings_test.py
index 639f6d276..a9f42a5d5 100644
--- a/sources/pyside2/tests/QtCore/qsettings_test.py
+++ b/sources/pyside2/tests/QtCore/qsettings_test.py
@@ -38,7 +38,7 @@ init_test_paths(False)
from helper.helper import adjust_filename
import py3kcompat as py3k
-from PySide2.QtCore import QSettings
+from PySide2.QtCore import QDir, QSettings, QTemporaryDir
class TestQSettings(unittest.TestCase):
def testConversions(self):
@@ -59,7 +59,11 @@ class TestQSettings(unittest.TestCase):
def testDefaultValueConversion(self):
- settings = QSettings('foo.ini', QSettings.IniFormat)
+ temp_dir = QDir.tempPath()
+ dir = QTemporaryDir('{}/qsettings_XXXXXX'.format(temp_dir))
+ self.assertTrue(dir.isValid())
+ file_name = dir.filePath('foo.ini')
+ settings = QSettings(file_name, QSettings.IniFormat)
settings.setValue('zero_value', 0)
settings.setValue('empty_list', [])
settings.setValue('bool1', False)
@@ -67,7 +71,7 @@ class TestQSettings(unittest.TestCase):
del settings
# Loading values already set
- settings = QSettings('foo.ini', QSettings.IniFormat)
+ settings = QSettings(file_name, QSettings.IniFormat)
# Getting value that doesn't exist
r = settings.value("variable")
diff --git a/sources/pyside2/tests/QtDataVisualization/datavisualization_test.py b/sources/pyside2/tests/QtDataVisualization/datavisualization_test.py
index af6e5f5d5..32fd432e8 100644
--- a/sources/pyside2/tests/QtDataVisualization/datavisualization_test.py
+++ b/sources/pyside2/tests/QtDataVisualization/datavisualization_test.py
@@ -88,5 +88,18 @@ class QtDataVisualizationTestCase(UsesQGuiApplication):
QTimer.singleShot(500, self.app.quit)
self.app.exec_()
+ def testBarDataProxy(self):
+ '''PSYSIDE-1438, crashes in QBarDataProxy.addRow()'''
+ items = [QtDataVisualization.QBarDataItem(v) for v in [1.0, 2.0]]
+ data_proxy = QtDataVisualization.QBarDataProxy()
+ data_proxy.addRow(items)
+ data_proxy.addRow(items, 'bla')
+ data_proxy.insertRow(0, items)
+ data_proxy.insertRow(0, items, 'bla')
+ data_proxy.setRow(0, items)
+ data_proxy.setRow(0, items, 'bla')
+ self.assertTrue(data_proxy.rowCount(), 4)
+
+
if __name__ == '__main__':
unittest.main()
diff --git a/sources/pyside2/tests/QtGui/qdatastream_gui_operators_test.py b/sources/pyside2/tests/QtGui/qdatastream_gui_operators_test.py
index c9b5c16a5..4db0a0a6e 100644
--- a/sources/pyside2/tests/QtGui/qdatastream_gui_operators_test.py
+++ b/sources/pyside2/tests/QtGui/qdatastream_gui_operators_test.py
@@ -47,7 +47,9 @@ class QPixmapQDatastream(UsesQApplication):
def setUp(self):
super(QPixmapQDatastream, self).setUp()
self.source_pixmap = QPixmap(100, 100)
- self.source_pixmap.fill(Qt.red)
+ # PYSIDE-1533: Use Qt.transparent to force Format_ARGB32_Premultiplied
+ # when converting to QImage in any case.
+ self.source_pixmap.fill(Qt.transparent)
self.output_pixmap = QPixmap()
self.buffer = QByteArray()
self.read_stream = QDataStream(self.buffer, QIODevice.ReadOnly)
@@ -60,8 +62,8 @@ class QPixmapQDatastream(UsesQApplication):
image = self.output_pixmap.toImage()
pixel = image.pixel(10,10)
- self.assertEqual(pixel, QColor(Qt.red).rgba())
- self.assertEqual(self.source_pixmap.toImage(), self.output_pixmap.toImage())
+ self.assertEqual(pixel, QColor(Qt.transparent).rgba())
+ self.assertEqual(self.source_pixmap.toImage(), image)
if __name__ == '__main__':
diff --git a/sources/shiboken2/ApiExtractor/abstractmetabuilder.cpp b/sources/shiboken2/ApiExtractor/abstractmetabuilder.cpp
index 05f9cf203..d7ae45ae3 100644
--- a/sources/shiboken2/ApiExtractor/abstractmetabuilder.cpp
+++ b/sources/shiboken2/ApiExtractor/abstractmetabuilder.cpp
@@ -3088,8 +3088,11 @@ AbstractMetaClassList AbstractMetaBuilderPrivate::classesTopologicalSorted(const
// Member fields need to be initialized
const AbstractMetaFieldList &fields = clazz->fields();
for (AbstractMetaField *field : fields) {
- addClassDependency(field->type()->typeEntry(), clazz, classIndex,
- map, &graph);
+ auto typeEntry = field->type()->typeEntry();
+ if (typeEntry->isEnum()) // Enum defined in class?
+ typeEntry = typeEntry->parent();
+ if (typeEntry != nullptr)
+ addClassDependency(typeEntry, clazz, classIndex, map, &graph);
}
}
diff --git a/sources/shiboken2/ApiExtractor/abstractmetalang.cpp b/sources/shiboken2/ApiExtractor/abstractmetalang.cpp
index f1f01e02c..723a13164 100644
--- a/sources/shiboken2/ApiExtractor/abstractmetalang.cpp
+++ b/sources/shiboken2/ApiExtractor/abstractmetalang.cpp
@@ -2123,6 +2123,12 @@ AbstractMetaField *AbstractMetaClass::findField(const QString &name) const
return AbstractMetaField::find(m_fields, name);
}
+bool AbstractMetaClass::hasStaticFields() const
+{
+ return std::any_of(m_fields.cbegin(), m_fields.cend(),
+ [](const AbstractMetaField *f) { return f->isStatic(); });
+}
+
AbstractMetaEnum *AbstractMetaClass::findEnum(const QString &enumName)
{
if (AbstractMetaEnum *e = findByName(m_enums, enumName))
@@ -2171,6 +2177,11 @@ void AbstractMetaClass::getFunctionsFromInvisibleNamespacesToBeGenerated(Abstrac
}
}
+QString AbstractMetaClass::fullName() const
+{
+ return package() + QLatin1Char('.') + m_typeEntry->targetLangName();
+}
+
static void addExtraIncludeForType(AbstractMetaClass *metaClass, const AbstractMetaType *type)
{
if (!type)
@@ -2742,4 +2753,3 @@ QString AbstractMetaEnum::package() const
{
return m_typeEntry->targetLangPackage();
}
-
diff --git a/sources/shiboken2/ApiExtractor/abstractmetalang.h b/sources/shiboken2/ApiExtractor/abstractmetalang.h
index c100c63a1..8a0363f4c 100644
--- a/sources/shiboken2/ApiExtractor/abstractmetalang.h
+++ b/sources/shiboken2/ApiExtractor/abstractmetalang.h
@@ -84,6 +84,7 @@ public:
Format fmt = Documentation::Native);
bool isEmpty() const;
+ bool hasBrief() const { return m_data.contains(Brief); }
QString value(Type t = Documentation::Detailed) const;
void setValue(const QString& value, Type t = Documentation::Detailed,
@@ -1424,6 +1425,8 @@ public:
AbstractMetaField *findField(const QString &name) const;
+ bool hasStaticFields() const;
+
const AbstractMetaEnumList &enums() const { return m_enums; }
void setEnums(const AbstractMetaEnumList &enums)
{
@@ -1442,10 +1445,7 @@ public:
void getFunctionsFromInvisibleNamespacesToBeGenerated(AbstractMetaFunctionList *funcList) const;
- QString fullName() const
- {
- return package() + QLatin1Char('.') + name();
- }
+ QString fullName() const;
/**
* Retrieves the class name without any namespace/scope information.
diff --git a/sources/shiboken2/ApiExtractor/qtdocparser.cpp b/sources/shiboken2/ApiExtractor/qtdocparser.cpp
index d439b3fd5..1aeab85ed 100644
--- a/sources/shiboken2/ApiExtractor/qtdocparser.cpp
+++ b/sources/shiboken2/ApiExtractor/qtdocparser.cpp
@@ -41,6 +41,9 @@
#include <QtCore/QXmlStreamReader>
#include <QUrl>
+static inline QString briefStartElement() { return QStringLiteral("<brief>"); }
+static inline QString briefEndElement() { return QStringLiteral("</brief>"); }
+
Documentation QtDocParser::retrieveModuleDocumentation()
{
return retrieveModuleDocumentation(packageName());
@@ -206,6 +209,25 @@ QString QtDocParser::queryFunctionDocumentation(const QString &sourceFileName,
return result;
}
+// Extract the <brief> section from a WebXML (class) documentation and remove it
+// from the source.
+static QString extractBrief(QString *value)
+{
+ const auto briefStart = value->indexOf(briefStartElement());
+ if (briefStart < 0)
+ return {};
+ const auto briefEnd = value->indexOf(briefEndElement(),
+ briefStart + briefStartElement().size());
+ if (briefEnd < briefStart)
+ return {};
+ const auto briefLength = briefEnd + briefEndElement().size() - briefStart;
+ QString briefValue = value->mid(briefStart, briefLength);
+ briefValue.insert(briefValue.size() - briefEndElement().size(),
+ QLatin1String("<rst> More_...</rst>"));
+ value->remove(briefStart, briefLength);
+ return briefValue;
+}
+
void QtDocParser::fillDocumentation(AbstractMetaClass* metaClass)
{
if (!metaClass)
@@ -257,9 +279,17 @@ void QtDocParser::fillDocumentation(AbstractMetaClass* metaClass)
signedModifs.append(docModif);
}
- Documentation doc(getDocumentation(xquery, query, classModifs));
- if (doc.isEmpty())
- qCWarning(lcShibokenDoc, "%s", qPrintable(msgCannotFindDocumentation(sourceFileName, "class", className, query)));
+ QString docString = getDocumentation(xquery, query, classModifs);
+ if (docString.isEmpty()) {
+ qCWarning(lcShibokenDoc, "%s",
+ qPrintable(msgCannotFindDocumentation(sourceFileName, "class", className, query)));
+ }
+ const QString brief = extractBrief(&docString);
+
+ Documentation doc;
+ if (!brief.isEmpty())
+ doc.setValue(brief, Documentation::Brief);
+ doc.setValue(docString);
metaClass->setDocumentation(doc);
//Functions Documentation
diff --git a/sources/shiboken2/ApiExtractor/tests/testmodifydocumentation.cpp b/sources/shiboken2/ApiExtractor/tests/testmodifydocumentation.cpp
index 6acac41d5..cf3982a18 100644
--- a/sources/shiboken2/ApiExtractor/tests/testmodifydocumentation.cpp
+++ b/sources/shiboken2/ApiExtractor/tests/testmodifydocumentation.cpp
@@ -72,13 +72,14 @@ R"(<typesystem package="Foo">
docParser.setDocumentationDataDirectory(tempDir.path());
docParser.fillDocumentation(classA);
- const QString actualDocSimplified = classA->documentation().value().simplified();
+ const Documentation &doc = classA->documentation();
+ const QString actualDocSimplified = doc.value(Documentation::Detailed).simplified();
+ const QString actualBriefSimplified = doc.value(Documentation::Brief).simplified();
QVERIFY(!actualDocSimplified.isEmpty());
const char expectedDoc[] =
R"(<?xml version="1.0"?>
<description>oi
-<brief>Modified Brief</brief>
<para>Paragraph number 1</para>
<para>Paragraph number 2</para>
<para>Some changed contents here</para>
@@ -86,7 +87,7 @@ R"(<?xml version="1.0"?>
)";
const QString expectedDocSimplified = QString::fromLatin1(expectedDoc).simplified();
// Check whether the first modification worked.
- QVERIFY(actualDocSimplified.contains(QLatin1String("Modified Brief")));
+ QVERIFY(actualBriefSimplified.contains(QLatin1String("Modified Brief")));
#ifndef HAVE_LIBXSLT
// QtXmlPatterns is unable to handle para[3] in style sheets,
diff --git a/sources/shiboken2/CMakeLists.txt b/sources/shiboken2/CMakeLists.txt
index 3de5d3223..8b626af09 100644
--- a/sources/shiboken2/CMakeLists.txt
+++ b/sources/shiboken2/CMakeLists.txt
@@ -197,6 +197,35 @@ if(CMAKE_BUILD_TYPE STREQUAL "Debug")
endif()
######################################################################
+## Define the Python files involved in the build process.
+##
+## They are installed into the file system (see shibokenmodule)
+## and embedded into the libshiboken binary through a .zip file.
+######################################################################
+
+set(shiboken_python_files
+ "signature/lib/__init__.py"
+ "signature/lib/enum_sig.py"
+ "signature/lib/tool.py"
+ "signature/__init__.py"
+ "signature/errorhandler.py"
+ "signature/importhandler.py"
+ "signature/layout.py"
+ "signature/loader.py"
+ "signature/mapping.py"
+ "signature/parser.py"
+ "__init__.py"
+ "feature.py"
+ )
+
+if (PYTHON_VERSION_MAJOR LESS 3)
+ list(APPEND shiboken_python_files
+ "backport_inspect.py"
+ "typing27.py"
+ )
+endif()
+
+######################################################################
# Adding sub directories to build
######################################################################
add_subdirectory(ApiExtractor)
diff --git a/sources/shiboken2/doc/typesystem_codeinjection.rst b/sources/shiboken2/doc/typesystem_codeinjection.rst
index b0d5f3851..836609508 100644
--- a/sources/shiboken2/doc/typesystem_codeinjection.rst
+++ b/sources/shiboken2/doc/typesystem_codeinjection.rst
@@ -112,7 +112,8 @@ Below is the example C++ class for whom wrapper code will be generated.
.. code-block:: c++
- class InjectCode {
+ class InjectCode
+ {
public:
InjectCode();
double overloadedMethod(int arg);
@@ -124,6 +125,10 @@ From the C++ class, |project| will generate a ``injectcode_wrapper.cpp`` file
with the binding code. The next section will use a simplified version of the
generated wrapper code with the injection spots marked with comments.
+There are a number of placeholders indicated by a percent sign ``%``, which
+will be expanded when inserting the code. For a list, see
+:ref:`typesystemvariables`.
+
Noteworthy Cases
----------------
@@ -196,7 +201,7 @@ class is polymorphic.
int InjectCodeWrapper::virtualMethod(int arg)
{
- PyObject* method = BindingManager::instance().getOverride(this, "virtualMethod");
+ PyObject *method = BindingManager::instance().getOverride(this, "virtualMethod");
if (!py_override)
return this->InjectCode::virtualMethod(arg);
@@ -228,10 +233,9 @@ own ``beginning`` and ``end`` code injections.
.. code-block:: c++
- static PyObject*
- PyInjectCode_overloadedMethod(PyObject* self, PyObject* arg)
+ static PyObject *PyInjectCode_overloadedMethod(PyObject *self, PyObject *arg)
{
- PyObject* py_result = 0;
+ PyObject* py_result{};
if (PyFloat_Check(arg)) {
double cpp_arg0 = Shiboken::Converter<double >::toCpp(arg);
@@ -250,13 +254,13 @@ own ``beginning`` and ``end`` code injections.
} else goto PyInjectCode_overloadedMethod_TypeError;
if (PyErr_Occurred() || !py_result)
- return 0;
+ return {};
return py_result;
PyInjectCode_overloadedMethod_TypeError:
PyErr_SetString(PyExc_TypeError, "'overloadedMethod()' called with wrong parameters.");
- return 0;
+ return {};
}
@@ -371,7 +375,7 @@ to prevent bad custom code to pass unnoticed.
// INJECT-CODE: <typesystem><inject-code class="target" position="beginning">
// Uses: do something before the module is created.
- PyObject* module = Py_InitModule("MODULENAME", MODULENAME_methods);
+ PyObject *module = Py_InitModule("MODULENAME", MODULENAME_methods);
(... initialization of wrapped classes, namespaces, functions and enums ...)
diff --git a/sources/shiboken2/doc/typesystem_conversionrule.rst b/sources/shiboken2/doc/typesystem_conversionrule.rst
index 27e7a72de..fc87a85c9 100644
--- a/sources/shiboken2/doc/typesystem_conversionrule.rst
+++ b/sources/shiboken2/doc/typesystem_conversionrule.rst
@@ -32,6 +32,10 @@ conversion-rule
</conversion-rule>
</value-type>
+ The code can be inserted directly, via ``add-conversion`` (providing snippet
+ functionality) or via ``insert-template`` (XML template,
+ see :ref:`using-code-templates`).
+
The example above show the structure of a complete conversion rule. Each of the
child tags comprising the conversion rule are described in their own sections
below.
diff --git a/sources/shiboken2/doc/typesystem_variables.rst b/sources/shiboken2/doc/typesystem_variables.rst
index 73d4dd12c..3d4638253 100644
--- a/sources/shiboken2/doc/typesystem_variables.rst
+++ b/sources/shiboken2/doc/typesystem_variables.rst
@@ -1,3 +1,5 @@
+.. _typesystemvariables:
+
*********************
Type System Variables
*********************
@@ -24,9 +26,9 @@ Variables
.. _arg_number:
-**%#**
+**%<number>**
- Replaced by the name of a C++ argument in the position indicated by ``#``.
+ Replaced by the name of a C++ argument in the position indicated by ``<number>``.
The argument counting starts with ``%1``, since ``%0`` represents the return
variable name. If the number indicates a variable that was removed in the
type system description, but there is a default value for it, this value will
@@ -214,13 +216,13 @@ Variables
.. _pyarg:
-**%PYARG_#**
+**%PYARG_<number>**
- Similar to ``%#``, but is replaced by the Python arguments (PyObjects)
+ Similar to ``%<number>``, but is replaced by the Python arguments (PyObjects)
received by the Python wrapper method.
If used in the context of a native code injection, i.e. in a virtual method
- override, ``%PYARG_#`` will be translated to one item of the Python tuple
+ override, ``%PYARG_<number>`` will be translated to one item of the Python tuple
holding the arguments that should be passed to the Python override for this
virtual method.
diff --git a/sources/shiboken2/generator/qtdoc/qtdocgenerator.cpp b/sources/shiboken2/generator/qtdoc/qtdocgenerator.cpp
index 5e75cbf87..d330d8c18 100644
--- a/sources/shiboken2/generator/qtdoc/qtdocgenerator.cpp
+++ b/sources/shiboken2/generator/qtdoc/qtdocgenerator.cpp
@@ -1588,30 +1588,6 @@ static void writeInheritedByList(QTextStream& s, const AbstractMetaClass* metaCl
s << classes.join(QLatin1String(", ")) << Qt::endl << Qt::endl;
}
-// Extract the <brief> section from a WebXML (class) documentation and remove it
-// from the source.
-static bool extractBrief(Documentation *sourceDoc, Documentation *brief)
-{
- if (sourceDoc->format() != Documentation::Native)
- return false;
- QString value = sourceDoc->value();
- const int briefStart = value.indexOf(briefStartElement());
- if (briefStart < 0)
- return false;
- const int briefEnd = value.indexOf(briefEndElement(), briefStart + briefStartElement().size());
- if (briefEnd < briefStart)
- return false;
- const int briefLength = briefEnd + briefEndElement().size() - briefStart;
- brief->setFormat(Documentation::Native);
- QString briefValue = value.mid(briefStart, briefLength);
- briefValue.insert(briefValue.size() - briefEndElement().size(),
- QLatin1String("<rst> More_...</rst>"));
- brief->setValue(briefValue);
- value.remove(briefStart, briefLength);
- sourceDoc->setValue(value);
- return true;
-}
-
void QtDocGenerator::generateClass(QTextStream &s, const GeneratorContext &classContext)
{
const AbstractMetaClass *metaClass = classContext.metaClass();
@@ -1630,9 +1606,8 @@ void QtDocGenerator::generateClass(QTextStream &s, const GeneratorContext &class
s << Pad('*', className.count()) << Qt::endl << Qt::endl;
auto documentation = metaClass->documentation();
- Documentation brief;
- if (extractBrief(&documentation, &brief))
- writeFormattedText(s, brief.value(), metaClass);
+ if (documentation.hasBrief())
+ writeFormattedText(s, documentation.value(Documentation::Brief), metaClass);
s << ".. inheritance-diagram:: " << metaClass->fullName() << Qt::endl
<< " :parts: 2" << Qt::endl << Qt::endl;
@@ -1659,7 +1634,7 @@ void QtDocGenerator::generateClass(QTextStream &s, const GeneratorContext &class
writeInjectDocumentation(s, TypeSystem::DocModificationPrepend, metaClass, nullptr);
if (!writeInjectDocumentation(s, TypeSystem::DocModificationReplace, metaClass, nullptr))
- writeFormattedText(s, documentation.value(), metaClass);
+ writeFormattedText(s, documentation.value(Documentation::Detailed), metaClass);
if (!metaClass->isNamespace())
writeConstructors(s, metaClass);
@@ -1972,7 +1947,7 @@ bool QtDocGenerator::writeInjectDocumentation(QTextStream& s,
continue;
doc.setValue(mod.code(), Documentation::Detailed, fmt);
- writeFormattedText(s, doc.value(), cppClass);
+ writeFormattedText(s, doc, cppClass);
didSomething = true;
}
}
diff --git a/sources/shiboken2/generator/shiboken2/cppgenerator.cpp b/sources/shiboken2/generator/shiboken2/cppgenerator.cpp
index c84557180..9739dfef6 100644
--- a/sources/shiboken2/generator/shiboken2/cppgenerator.cpp
+++ b/sources/shiboken2/generator/shiboken2/cppgenerator.cpp
@@ -762,6 +762,9 @@ void CppGenerator::generateClass(QTextStream &s, const GeneratorContext &classCo
writeConverterFunctions(s, metaClass, classContext);
writeClassRegister(s, metaClass, classContext, signatureStream);
+ if (metaClass->hasStaticFields())
+ writeStaticFieldInitialization(s, metaClass);
+
// class inject-code native/end
if (!metaClass->typeEntry()->codeSnips().isEmpty()) {
writeClassCodeSnips(s, metaClass->typeEntry()->codeSnips(),
@@ -5281,6 +5284,12 @@ QString CppGenerator::getSimpleClassInitFunctionName(const AbstractMetaClass *me
return initFunctionName;
}
+QString CppGenerator::getSimpleClassStaticFieldsInitFunctionName(const AbstractMetaClass *metaClass) const
+{
+ return QLatin1String("init_") + getSimpleClassInitFunctionName(metaClass)
+ + QLatin1String("StaticFields");
+}
+
QString CppGenerator::getInitFunctionName(const GeneratorContext &context) const
{
return !context.forSmartPointer()
@@ -5483,18 +5492,6 @@ void CppGenerator::writeClassRegister(QTextStream &s,
if (metaClass->hasSignals())
writeSignalInitialization(s, metaClass);
- // Write static fields
- const AbstractMetaFieldList &fields = metaClass->fields();
- for (const AbstractMetaField *field : fields) {
- if (!field->isStatic())
- continue;
- s << INDENT << QLatin1String("PyDict_SetItemString(reinterpret_cast<PyTypeObject *>(") + cpythonTypeName(metaClass) + QLatin1String(")->tp_dict, \"");
- s << field->name() << "\", ";
- writeToPythonConversion(s, field->type(), metaClass, metaClass->qualifiedCppName() + QLatin1String("::") + field->name());
- s << ");\n";
- }
- s << Qt::endl;
-
// class inject-code target/end
if (!classTypeEntry->codeSnips().isEmpty()) {
s << Qt::endl;
@@ -5524,6 +5521,29 @@ void CppGenerator::writeClassRegister(QTextStream &s,
s << "}\n";
}
+void CppGenerator::writeStaticFieldInitialization(QTextStream &s,
+ const AbstractMetaClass *metaClass)
+{
+ s << "\nvoid " << getSimpleClassStaticFieldsInitFunctionName(metaClass)
+ << "()\n{\n" << INDENT << "auto dict = reinterpret_cast<PyTypeObject *>("
+ << cpythonTypeName(metaClass) << ")->tp_dict;\n";
+ const auto &fields = metaClass->fields();
+ for (const AbstractMetaField *field : fields) {
+ if (field->isStatic()) {
+ QString cppName = field->originalName();
+ if (cppName.isEmpty())
+ cppName = field->name();
+ const QString name = field->enclosingClass()->qualifiedCppName()
+ + QLatin1String("::") + cppName;
+ s << INDENT << "PyDict_SetItemString(dict, \"" << field->name()
+ << "\",\n" << INDENT << " ";
+ writeToPythonConversion(s, field->type(), metaClass, name);
+ s << ");\n";
+ }
+ }
+ s << "\n}\n";
+}
+
void CppGenerator::writeInitQtMetaTypeFunctionBody(QTextStream &s, const GeneratorContext &context) const
{
const AbstractMetaClass *metaClass = context.metaClass();
@@ -5934,11 +5954,18 @@ bool CppGenerator::finishGeneration()
}
const AbstractMetaClassList lst = classesTopologicalSorted(additionalDependencies);
+ QVector<const AbstractMetaClass *> classesWithStaticFields;
+
for (const AbstractMetaClass *cls : lst){
if (shouldGenerate(cls)) {
writeInitFunc(s_classInitDecl, s_classPythonDefines, INDENT,
getSimpleClassInitFunctionName(cls),
cls->typeEntry()->targetLangEnclosingEntry());
+ if (cls->hasStaticFields()) {
+ s_classInitDecl << "void "
+ << getSimpleClassStaticFieldsInitFunctionName(cls) << "();\n";
+ classesWithStaticFields.append(cls);
+ }
}
}
@@ -6240,6 +6267,14 @@ bool CppGenerator::finishGeneration()
s << INDENT << "Shiboken::Module::registerTypes(module, " << cppApiVariableName() << ");\n";
s << INDENT << "Shiboken::Module::registerTypeConverters(module, " << convertersVariableName() << ");\n";
+ // Static fields are registered last since they may use converter functions
+ // of the previously registered types (PYSIDE-1529).
+ if (!classesWithStaticFields.isEmpty()) {
+ s << "\n// Static field initialization\n";
+ for (auto cls : qAsConst(classesWithStaticFields))
+ s << getSimpleClassStaticFieldsInitFunctionName(cls) << "();\n";
+ }
+
s << '\n' << INDENT << "if (PyErr_Occurred()) {\n" << indent(INDENT)
<< INDENT << "PyErr_Print();\n"
<< INDENT << "Py_FatalError(\"can't initialize module " << moduleName() << "\");\n"
diff --git a/sources/shiboken2/generator/shiboken2/cppgenerator.h b/sources/shiboken2/generator/shiboken2/cppgenerator.h
index 25bb51ef5..64396d61f 100644
--- a/sources/shiboken2/generator/shiboken2/cppgenerator.h
+++ b/sources/shiboken2/generator/shiboken2/cppgenerator.h
@@ -257,6 +257,7 @@ private:
QString getInitFunctionName(const GeneratorContext &context) const;
QString getSimpleClassInitFunctionName(const AbstractMetaClass *metaClass) const;
+ QString getSimpleClassStaticFieldsInitFunctionName(const AbstractMetaClass *metaClass) const;
void writeSignatureStrings(QTextStream &s, QTextStream &signatureStream,
const QString &arrayName,
@@ -265,6 +266,8 @@ private:
const AbstractMetaClass *metaClass,
const GeneratorContext &classContext,
QTextStream &signatureStream);
+ void writeStaticFieldInitialization(QTextStream &s,
+ const AbstractMetaClass *metaClass);
void writeClassDefinition(QTextStream &s,
const AbstractMetaClass *metaClass,
const GeneratorContext &classContext);
diff --git a/sources/shiboken2/libshiboken/CMakeLists.txt b/sources/shiboken2/libshiboken/CMakeLists.txt
index 45b41fd13..96effd280 100644
--- a/sources/shiboken2/libshiboken/CMakeLists.txt
+++ b/sources/shiboken2/libshiboken/CMakeLists.txt
@@ -29,13 +29,35 @@ configure_file("${CMAKE_CURRENT_SOURCE_DIR}/sbkversion.h.in"
configure_file("${CMAKE_CURRENT_SOURCE_DIR}/embed/signature_bootstrap.py"
"${CMAKE_CURRENT_BINARY_DIR}/embed/signature_bootstrap.py" @ONLY)
+# Variable from enclosing scope.
+# list(TRANSFORM shiboken_python_files
+# PREPEND "${CMAKE_CURRENT_SOURCE_DIR}/../shibokenmodule/files.dir/shibokensupport/"
+# OUTPUT_VARIABLE embedded_shiboken_files)
+# Replacement for CMake version < 3.12:
+set(embedded_shiboken_files "")
+foreach(item IN LISTS shiboken_python_files)
+ list(APPEND embedded_shiboken_files
+ "${CMAKE_CURRENT_SOURCE_DIR}/../shibokenmodule/files.dir/shibokensupport/${item}")
+endforeach()
+
+if (QUIET_BUILD)
+ set(embedding_option "--quiet")
+else()
+ set(embedding_option "")
+endif()
+
add_custom_command(
OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/embed/signature_bootstrap_inc.h"
OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/embed/signature_inc.h"
COMMAND ${PYTHON_EXECUTABLE} -E
"${CMAKE_CURRENT_SOURCE_DIR}/embed/embedding_generator.py"
--cmake-dir "${CMAKE_CURRENT_BINARY_DIR}/embed"
- --limited-api ${PYTHON_LIMITED_API})
+ --limited-api ${PYTHON_LIMITED_API}
+ ${embedding_option}
+ DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/embed/embedding_generator.py"
+ "${CMAKE_CURRENT_SOURCE_DIR}/embed/signature_bootstrap.py"
+ ${embedded_shiboken_files}
+ )
set(libshiboken_MAJOR_VERSION ${shiboken_MAJOR_VERSION})
set(libshiboken_MINOR_VERSION ${shiboken_MINOR_VERSION})
diff --git a/sources/shiboken2/libshiboken/embed/embedding_generator.py b/sources/shiboken2/libshiboken/embed/embedding_generator.py
index 15f63649b..a9a58ee07 100644
--- a/sources/shiboken2/libshiboken/embed/embedding_generator.py
+++ b/sources/shiboken2/libshiboken/embed/embedding_generator.py
@@ -82,7 +82,7 @@ def runpy(cmd, **kw):
subprocess.call([sys.executable, '-E'] + cmd.split(), **kw)
-def create_zipfile(limited_api):
+def create_zipfile(limited_api, quiet):
"""
Collect all Python files, compile them, create a zip file
and make a chunked base64 encoded file from it.
@@ -129,11 +129,28 @@ def create_zipfile(limited_api):
with open(inc_name, "w") as inc:
_embed_file(tmp, inc)
tmp.close()
+
# also generate a simple embeddable .pyc file for signature_bootstrap.pyc
boot_name = "signature_bootstrap.py" if limited_api else "signature_bootstrap.pyc"
with open(boot_name, "rb") as ldr, open("signature_bootstrap_inc.h", "w") as inc:
_embed_bytefile(ldr, inc, limited_api)
os.chdir(cur_dir)
+ if quiet:
+ return
+
+ # have a look at our populated folder unless quiet option
+ def list_files(startpath):
+ for root, dirs, files in os.walk(startpath):
+ level = root.replace(startpath, '').count(os.sep)
+ indent = ' ' * 4 * (level)
+ print('+ {}{}/'.format(indent, os.path.basename(root)))
+ subindent = ' ' * 4 * (level + 1)
+ for f in files:
+ print('+ {}{}'.format(subindent, f))
+
+ print("++++ Current contents of")
+ list_files(work_dir)
+ print("++++")
def _embed_file(fin, fout):
@@ -236,7 +253,8 @@ if __name__ == "__main__":
parser = argparse.ArgumentParser()
parser.add_argument('--cmake-dir', nargs="?")
parser.add_argument('--limited-api', type=str2bool)
+ parser.add_argument('--quiet', action='store_true')
args = parser.parse_args()
if args.cmake_dir:
work_dir = os.path.abspath(args.cmake_dir)
- create_zipfile(args.limited_api)
+ create_zipfile(args.limited_api, args.quiet)
diff --git a/sources/shiboken2/libshiboken/sbkarrayconverter.cpp b/sources/shiboken2/libshiboken/sbkarrayconverter.cpp
index fd09efdae..b828aa8e0 100644
--- a/sources/shiboken2/libshiboken/sbkarrayconverter.cpp
+++ b/sources/shiboken2/libshiboken/sbkarrayconverter.cpp
@@ -90,7 +90,6 @@ SbkArrayConverter *createArrayConverter(IsArrayConvertibleToCppFunc toCppCheckFu
static PythonToCppFunc unimplementedArrayCheck(PyObject *, int, int)
{
- warning(PyExc_RuntimeWarning, 0, "SbkConverter: Unimplemented C++ array type.");
return nullptr;
}
diff --git a/sources/shiboken2/libshiboken/shibokenbuffer.cpp b/sources/shiboken2/libshiboken/shibokenbuffer.cpp
index dd6e46320..8d44878ac 100644
--- a/sources/shiboken2/libshiboken/shibokenbuffer.cpp
+++ b/sources/shiboken2/libshiboken/shibokenbuffer.cpp
@@ -74,6 +74,29 @@ void *Shiboken::Buffer::getPointer(PyObject *pyObj, Py_ssize_t *size)
return const_cast<void *>(buffer);
}
+void *Shiboken::Buffer::copyData(PyObject *pyObj, Py_ssize_t *sizeIn)
+{
+ void *result = nullptr;
+ Py_ssize_t size = 0;
+
+ Py_buffer view;
+ if (PyObject_GetBuffer(pyObj, &view, PyBUF_ND) == 0) {
+ size = view.len;
+ if (size) {
+ result = std::malloc(size);
+ if (result != nullptr)
+ std::memcpy(result, view.buf, size);
+ else
+ size = 0;
+ }
+ PyBuffer_Release(&view);
+ }
+
+ if (sizeIn != nullptr)
+ *sizeIn = size;
+ return result;
+}
+
PyObject *Shiboken::Buffer::newObject(void *memory, Py_ssize_t size, Type type)
{
if (size == 0)
diff --git a/sources/shiboken2/libshiboken/shibokenbuffer.h b/sources/shiboken2/libshiboken/shibokenbuffer.h
index dc9f8d89f..512d9db4d 100644
--- a/sources/shiboken2/libshiboken/shibokenbuffer.h
+++ b/sources/shiboken2/libshiboken/shibokenbuffer.h
@@ -79,6 +79,14 @@ namespace Buffer
*/
LIBSHIBOKEN_API void *getPointer(PyObject *pyObj, Py_ssize_t *size = nullptr);
+ /**
+ * Returns a copy of the buffer data which should be free'd.
+ *
+ * If the \p pyObj is a non-contiguous buffer a Python error is set.
+ * nullptr is returned for empty buffers.
+ */
+ LIBSHIBOKEN_API void *copyData(PyObject *pyObj, Py_ssize_t *size = nullptr);
+
} // namespace Buffer
} // namespace Shiboken
diff --git a/sources/shiboken2/libshiboken/signature/signature.cpp b/sources/shiboken2/libshiboken/signature/signature.cpp
index 4c251af5b..601df4730 100644
--- a/sources/shiboken2/libshiboken/signature/signature.cpp
+++ b/sources/shiboken2/libshiboken/signature/signature.cpp
@@ -499,7 +499,7 @@ static PyObject *adjustFuncName(const char *func_name)
}
// Finally, generate the correct path expression.
- char _buf[200 + 1] = {};
+ char _buf[250 + 1] = {};
if (is_prop) {
auto _prop_name = String::toCString(prop_name);
if (is_class_prop)
diff --git a/sources/shiboken2/shiboken_version.py b/sources/shiboken2/shiboken_version.py
index 0985e2559..ecc975ddf 100644
--- a/sources/shiboken2/shiboken_version.py
+++ b/sources/shiboken2/shiboken_version.py
@@ -39,7 +39,7 @@
major_version = "5"
minor_version = "15"
-patch_version = "3"
+patch_version = "4"
# For example: "a", "b", "rc"
# (which means "alpha", "beta", "release candidate").
diff --git a/sources/shiboken2/shibokenmodule/CMakeLists.txt b/sources/shiboken2/shibokenmodule/CMakeLists.txt
index b14de5c9e..9b2b58528 100644
--- a/sources/shiboken2/shibokenmodule/CMakeLists.txt
+++ b/sources/shiboken2/shibokenmodule/CMakeLists.txt
@@ -42,37 +42,12 @@ install(FILES "${CMAKE_CURRENT_BINARY_DIR}/_config.py"
configure_file("${CMAKE_CURRENT_SOURCE_DIR}/__init__.py.in"
"${CMAKE_CURRENT_BINARY_DIR}/__init__.py" @ONLY)
-configure_file("${CMAKE_CURRENT_SOURCE_DIR}/files.dir/shibokensupport/__feature__.py"
- "${CMAKE_CURRENT_BINARY_DIR}/files.dir/shibokensupport/__feature__.py" COPYONLY)
-configure_file("${CMAKE_CURRENT_SOURCE_DIR}/files.dir/shibokensupport/__init__.py"
- "${CMAKE_CURRENT_BINARY_DIR}/files.dir/shibokensupport/__init__.py" COPYONLY)
-configure_file("${CMAKE_CURRENT_SOURCE_DIR}/files.dir/shibokensupport/signature/__init__.py"
- "${CMAKE_CURRENT_BINARY_DIR}/files.dir/shibokensupport/signature/__init__.py" COPYONLY)
-configure_file("${CMAKE_CURRENT_SOURCE_DIR}/files.dir/shibokensupport/signature/errorhandler.py"
- "${CMAKE_CURRENT_BINARY_DIR}/files.dir/shibokensupport/signature/errorhandler.py" COPYONLY)
-configure_file("${CMAKE_CURRENT_SOURCE_DIR}/files.dir/shibokensupport/signature/layout.py"
- "${CMAKE_CURRENT_BINARY_DIR}/files.dir/shibokensupport/signature/layout.py" COPYONLY)
-configure_file("${CMAKE_CURRENT_SOURCE_DIR}/files.dir/shibokensupport/signature/loader.py"
- "${CMAKE_CURRENT_BINARY_DIR}/files.dir/shibokensupport/signature/loader.py" COPYONLY)
-configure_file("${CMAKE_CURRENT_SOURCE_DIR}/files.dir/shibokensupport/signature/importhandler.py"
- "${CMAKE_CURRENT_BINARY_DIR}/files.dir/shibokensupport/signature/importhandler.py" COPYONLY)
-configure_file("${CMAKE_CURRENT_SOURCE_DIR}/files.dir/shibokensupport/signature/mapping.py"
- "${CMAKE_CURRENT_BINARY_DIR}/files.dir/shibokensupport/signature/mapping.py" COPYONLY)
-configure_file("${CMAKE_CURRENT_SOURCE_DIR}/files.dir/shibokensupport/signature/parser.py"
- "${CMAKE_CURRENT_BINARY_DIR}/files.dir/shibokensupport/signature/parser.py" COPYONLY)
-configure_file("${CMAKE_CURRENT_SOURCE_DIR}/files.dir/shibokensupport/signature/lib/__init__.py"
- "${CMAKE_CURRENT_BINARY_DIR}/files.dir/shibokensupport/signature/lib/__init__.py" COPYONLY)
-configure_file("${CMAKE_CURRENT_SOURCE_DIR}/files.dir/shibokensupport/signature/lib/enum_sig.py"
- "${CMAKE_CURRENT_BINARY_DIR}/files.dir/shibokensupport/signature/lib/enum_sig.py" COPYONLY)
-configure_file("${CMAKE_CURRENT_SOURCE_DIR}/files.dir/shibokensupport/signature/lib/tool.py"
- "${CMAKE_CURRENT_BINARY_DIR}/files.dir/shibokensupport/signature/lib/tool.py" COPYONLY)
-if (PYTHON_VERSION_MAJOR EQUAL 3)
-else()
- configure_file("${CMAKE_CURRENT_SOURCE_DIR}/files.dir/shibokensupport/backport_inspect.py"
- "${CMAKE_CURRENT_BINARY_DIR}/files.dir/shibokensupport/backport_inspect.py" COPYONLY)
- configure_file("${CMAKE_CURRENT_SOURCE_DIR}/files.dir/shibokensupport/typing27.py"
- "${CMAKE_CURRENT_BINARY_DIR}/files.dir/shibokensupport/typing27.py" COPYONLY)
-endif()
+# Variable from enclosing scope.
+foreach(item IN LISTS shiboken_python_files)
+ configure_file("${CMAKE_CURRENT_SOURCE_DIR}/files.dir/shibokensupport/${item}"
+ "${CMAKE_CURRENT_BINARY_DIR}/files.dir/shibokensupport/${item}" COPYONLY)
+endforeach()
+
install(DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/files.dir"
DESTINATION "${PYTHON_SITE_PACKAGES}/shiboken2")
diff --git a/sources/shiboken2/shibokenmodule/files.dir/shibokensupport/__feature__.py b/sources/shiboken2/shibokenmodule/files.dir/shibokensupport/feature.py
index ece3d2edb..ece3d2edb 100644
--- a/sources/shiboken2/shibokenmodule/files.dir/shibokensupport/__feature__.py
+++ b/sources/shiboken2/shibokenmodule/files.dir/shibokensupport/feature.py
diff --git a/sources/shiboken2/shibokenmodule/files.dir/shibokensupport/signature/lib/enum_sig.py b/sources/shiboken2/shibokenmodule/files.dir/shibokensupport/signature/lib/enum_sig.py
index 21c284f88..088a93aa4 100644
--- a/sources/shiboken2/shibokenmodule/files.dir/shibokensupport/signature/lib/enum_sig.py
+++ b/sources/shiboken2/shibokenmodule/files.dir/shibokensupport/signature/lib/enum_sig.py
@@ -103,8 +103,6 @@ class ExactEnumerator(object):
self.fmt.class_name = None
for class_name, klass in members:
ret.update(self.klass(class_name, klass))
- if isinstance(klass, EnumMeta):
- raise SystemError("implement enum instances at module level")
for func_name, func in functions:
ret.update(self.function(func_name, func))
return ret
diff --git a/sources/shiboken2/shibokenmodule/files.dir/shibokensupport/signature/loader.py b/sources/shiboken2/shibokenmodule/files.dir/shibokensupport/signature/loader.py
index a6c3e420d..a509ecf07 100644
--- a/sources/shiboken2/shibokenmodule/files.dir/shibokensupport/signature/loader.py
+++ b/sources/shiboken2/shibokenmodule/files.dir/shibokensupport/signature/loader.py
@@ -114,7 +114,7 @@ def finish_import(module):
import signature_bootstrap
-from shibokensupport import signature, __feature__
+from shibokensupport import signature, feature as __feature__
signature.get_signature = signature_bootstrap.get_signature
# PYSIDE-1019: Publish the __feature__ dictionary.
__feature__.pyside_feature_dict = signature_bootstrap.pyside_feature_dict
@@ -195,8 +195,9 @@ def move_into_pyside_package():
try:
import PySide2.support
except ModuleNotFoundError:
- PySide2.support = types.ModuleType("PySide2.support")
- put_into_package(PySide2.support, __feature__)
+ # This can happen in the embedding case.
+ put_into_package(PySide2, shibokensupport, "support")
+ put_into_package(PySide2.support, __feature__, "__feature__")
put_into_package(PySide2.support, signature)
put_into_package(PySide2.support.signature, mapping)
put_into_package(PySide2.support.signature, errorhandler)
@@ -220,16 +221,18 @@ from shibokensupport.signature.lib import enum_sig
if "PySide2" in sys.modules:
# We publish everything under "PySide2.support.signature", again.
move_into_pyside_package()
+ # PYSIDE-1502: Make sure that support can be imported.
+ try:
+ import PySide2.support
+ except ModuleNotFoundError as e:
+ print("PySide2.support could not be imported. "
+ "This is a serious configuration error.", file=sys.stderr)
+ raise
# PYSIDE-1019: Modify `__import__` to be `__feature__` aware.
# __feature__ is already in sys.modules, so this is actually no import
- try:
- import PySide2.support.__feature__
- sys.modules["__feature__"] = PySide2.support.__feature__
- PySide2.support.__feature__.original_import = __builtins__["__import__"]
- __builtins__["__import__"] = PySide2.support.__feature__._import
- # Maybe we should optimize that and change `__import__` from C, instead?
- except ModuleNotFoundError:
- print("__feature__ could not be imported. "
- "This is an unsolved PyInstaller problem.", file=sys.stderr)
+ import PySide2.support.__feature__
+ sys.modules["__feature__"] = PySide2.support.__feature__
+ PySide2.support.__feature__.original_import = __builtins__["__import__"]
+ __builtins__["__import__"] = PySide2.support.__feature__._import
# end of file
diff --git a/sources/shiboken2/shibokenmodule/files.dir/shibokensupport/signature/mapping.py b/sources/shiboken2/shibokenmodule/files.dir/shibokensupport/signature/mapping.py
index 4c9f02dc2..92511df32 100644
--- a/sources/shiboken2/shibokenmodule/files.dir/shibokensupport/signature/mapping.py
+++ b/sources/shiboken2/shibokenmodule/files.dir/shibokensupport/signature/mapping.py
@@ -351,6 +351,10 @@ type_map.update({
"self" : "self",
})
+# PYSIDE-1538: We need to treat "std::optional" accordingly.
+type_map.update({
+ "std.optional": typing.Optional,
+ })
# The Shiboken Part
def init_Shiboken():
diff --git a/sources/shiboken2/shibokenmodule/files.dir/shibokensupport/signature/parser.py b/sources/shiboken2/shibokenmodule/files.dir/shibokensupport/signature/parser.py
index 20c791cc1..a1cb58074 100644
--- a/sources/shiboken2/shibokenmodule/files.dir/shibokensupport/signature/parser.py
+++ b/sources/shiboken2/shibokenmodule/files.dir/shibokensupport/signature/parser.py
@@ -196,7 +196,7 @@ def _resolve_value(thing, valtype, line):
if res is not None:
type_map[thing] = res
return res
- warnings.warn("""pyside_type_init:
+ warnings.warn("""pyside_type_init:_resolve_value
UNRECOGNIZED: {!r}
OFFENDING LINE: {!r}
@@ -277,7 +277,15 @@ def _resolve_type(thing, line, level, var_handler):
pieces.append(to_string(part))
thing = ", ".join(pieces)
result = "{contr}[{thing}]".format(**locals())
- return eval(result, namespace)
+ # PYSIDE-1538: Make sure that the eval does not crash.
+ try:
+ return eval(result, namespace)
+ except Exception as e:
+ warnings.warn("""pyside_type_init:_resolve_type
+
+ UNRECOGNIZED: {!r}
+ OFFENDING LINE: {!r}
+ """.format(result, line), RuntimeWarning)
return _resolve_value(thing, None, line)
@@ -380,7 +388,9 @@ def fix_variables(props, line):
if not isinstance(ann, ResultVariable):
continue
# We move the variable to the end and remove it.
- retvars.append(ann.type)
+ # PYSIDE-1409: If the variable was the first arg, we move it to the front.
+ # XXX This algorithm should probably be replaced by more introspection.
+ retvars.insert(0 if idx == 0 else len(retvars), ann.type)
deletions.append(idx)
del annos[name]
for idx in reversed(deletions):
diff --git a/tools/license_changer.py b/tools/license_changer.py
new file mode 100644
index 000000000..0c3443b83
--- /dev/null
+++ b/tools/license_changer.py
@@ -0,0 +1,85 @@
+#############################################################################
+##
+## Copyright (C) 2021 The Qt Company Ltd.
+## Contact: https://www.qt.io/licensing/
+##
+## This file is part of the Qt for Python project.
+##
+## $QT_BEGIN_LICENSE:COMM$
+##
+## Commercial License Usage
+## Licensees holding valid commercial Qt licenses may use this file in
+## accordance with the commercial license agreement provided with the
+## Software or, alternatively, in accordance with the terms contained in
+## a written agreement between you and The Qt Company. For licensing terms
+## and conditions see https://www.qt.io/terms-conditions. For further
+## information use the contact form at https://www.qt.io/contact-us.
+##
+## $QT_END_LICENSE$
+##
+#############################################################################
+
+from argparse import ArgumentParser, RawTextHelpFormatter
+import os
+from pathlib import Path
+import subprocess
+import sys
+
+
+DESC = """
+Tool to adapt licenses to a commercial LTS branch
+Requires the qtsdk/tqtc-qtsdk and qtqa repos to be checked out as siblings.
+"""
+
+
+REPO_DIR = Path(__file__).resolve().parents[1]
+
+
+EXCLUSIONS = ['/build_scripts/', '/coin/', '/doc/', '/examples/',
+ '/testing/', '/tests/',
+ '/coin_build_instructions.py', '/coin_test_instructions.py',
+ '/ez_setup.py', '/setup.py', '/testrunner.py']
+
+
+if __name__ == '__main__':
+ argument_parser = ArgumentParser(description=DESC,
+ formatter_class=RawTextHelpFormatter)
+ argument_parser.add_argument('--dry-run', '-d', action='store_true',
+ help='Dry run, print commands')
+ options = argument_parser.parse_args()
+ dry_run = options.dry_run
+
+ license_changer = (REPO_DIR.parent / 'tqtc-qtsdk' / 'packaging-tools'
+ / 'release_tools' / 'license_changer.pl')
+ print('Checking ', license_changer)
+ if not license_changer.is_file:
+ print('Not found, please clone the qtsdk/tqtc-qtsdk repo')
+ sys.exit(1)
+ template = (REPO_DIR.parent / 'qtqa' / 'tests' / 'prebuild'
+ / 'license' / 'templates' / 'header.COMM')
+ print('Checking ', template)
+ if not template.is_file():
+ print('Not found, please clone the qtqa repo')
+ sys.exit(1)
+
+ os.chdir(REPO_DIR)
+ fixed_cmd = [str(license_changer), '--path', str(REPO_DIR),
+ '--headerfile', str(template)]
+ for e in EXCLUSIONS:
+ fixed_cmd.append('--exclude')
+ fixed_cmd.append(e)
+
+ for license in ['GPL-EXCEPT', 'GPL', 'LGPL']:
+ log = f'license_{license.lower()}_log.txt'
+ cmd = fixed_cmd
+ cmd.extend(['--replacehdr', license, '--errorlog', log])
+ cmds = ' '.join(cmd)
+ print('Running: ', cmds)
+ if not dry_run:
+ ex = subprocess.call(cmd)
+ if ex != 0:
+ print('FAIL! ', cmds)
+ sys.exit(1)
+
+ if not dry_run:
+ subprocess.call(['git', 'diff'])
diff --git a/tools/license_check.py b/tools/license_check.py
new file mode 100644
index 000000000..052c41ca5
--- /dev/null
+++ b/tools/license_check.py
@@ -0,0 +1,70 @@
+#############################################################################
+##
+## Copyright (C) 2021 The Qt Company Ltd.
+## Contact: https://www.qt.io/licensing/
+##
+## This file is part of the Qt for Python project.
+##
+## $QT_BEGIN_LICENSE:LGPL$
+## Commercial License Usage
+## Licensees holding valid commercial Qt licenses may use this file in
+## accordance with the commercial license agreement provided with the
+## Software or, alternatively, in accordance with the terms contained in
+## a written agreement between you and The Qt Company. For licensing terms
+## and conditions see https://www.qt.io/terms-conditions. For further
+## information use the contact form at https://www.qt.io/contact-us.
+##
+## GNU Lesser General Public License Usage
+## Alternatively, this file may be used under the terms of the GNU Lesser
+## General Public License version 3 as published by the Free Software
+## Foundation and appearing in the file LICENSE.LGPL3 included in the
+## packaging of this file. Please review the following information to
+## ensure the GNU Lesser General Public License version 3 requirements
+## will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+##
+## GNU General Public License Usage
+## Alternatively, this file may be used under the terms of the GNU
+## General Public License version 2.0 or (at your option) the GNU General
+## Public license version 3 or any later version approved by the KDE Free
+## Qt Foundation. The licenses are as published by the Free Software
+## Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+## included in the packaging of this file. Please review the following
+## information to ensure the GNU General Public License requirements will
+## be met: https://www.gnu.org/licenses/gpl-2.0.html and
+## https://www.gnu.org/licenses/gpl-3.0.html.
+##
+## $QT_END_LICENSE$
+##
+#############################################################################
+
+import os
+from pathlib import Path
+import subprocess
+import sys
+
+
+"""Tool to run a license check
+
+Requires the qtqa repo to be checked out as sibling.
+"""
+
+
+REPO_DIR = Path(__file__).resolve().parents[1]
+
+
+if __name__ == '__main__':
+ license_check = (REPO_DIR.parent / 'qtqa' / 'tests' / 'prebuild'
+ / 'license' / 'tst_licenses.pl')
+ print('Checking ', license_check)
+ if not license_check.is_file():
+ print('Not found, please clone the qtqa repo')
+ sys.exit(1)
+
+ os.environ['QT_MODULE_TO_TEST'] = str(REPO_DIR)
+ cmd = [str(license_check), '-m', 'pyside-setup']
+ cmds = ' '.join(cmd)
+ print('Running: ', cmds)
+ ex = subprocess.call(cmd)
+ if ex != 0:
+ print('FAIL! ', cmds)
+ sys.exit(1)
diff --git a/tools/uic_test.py b/tools/uic_test.py
new file mode 100644
index 000000000..6c1f2b888
--- /dev/null
+++ b/tools/uic_test.py
@@ -0,0 +1,123 @@
+#############################################################################
+##
+## Copyright (C) 2021 The Qt Company Ltd.
+## Contact: https://www.qt.io/licensing/
+##
+## This file is part of the Qt for Python project.
+##
+## $QT_BEGIN_LICENSE:LGPL$
+## Commercial License Usage
+## Licensees holding valid commercial Qt licenses may use this file in
+## accordance with the commercial license agreement provided with the
+## Software or, alternatively, in accordance with the terms contained in
+## a written agreement between you and The Qt Company. For licensing terms
+## and conditions see https://www.qt.io/terms-conditions. For further
+## information use the contact form at https://www.qt.io/contact-us.
+##
+## GNU Lesser General Public License Usage
+## Alternatively, this file may be used under the terms of the GNU Lesser
+## General Public License version 3 as published by the Free Software
+## Foundation and appearing in the file LICENSE.LGPL3 included in the
+## packaging of this file. Please review the following information to
+## ensure the GNU Lesser General Public License version 3 requirements
+## will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+##
+## GNU General Public License Usage
+## Alternatively, this file may be used under the terms of the GNU
+## General Public License version 2.0 or (at your option) the GNU General
+## Public license version 3 or any later version approved by the KDE Free
+## Qt Foundation. The licenses are as published by the Free Software
+## Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+## included in the packaging of this file. Please review the following
+## information to ensure the GNU General Public License requirements will
+## be met: https://www.gnu.org/licenses/gpl-2.0.html and
+## https://www.gnu.org/licenses/gpl-3.0.html.
+##
+## $QT_END_LICENSE$
+##
+#############################################################################
+
+import os
+import re
+import subprocess
+import sys
+import tempfile
+from argparse import ArgumentParser, RawTextHelpFormatter
+from pathlib import Path
+from textwrap import dedent
+from typing import Optional, Tuple
+
+
+VERSION = 2
+
+
+DESC = """Runs uic on a set of UI files and displays the resulting widgets."""
+
+
+TEMP_DIR = Path(tempfile.gettempdir())
+
+
+def get_class_name(file: Path) -> Tuple[Optional[str], Optional[str]]:
+ """Return class name and widget name of UI file."""
+ pattern = re.compile('^\s*<widget class="(\w+)" name="(\w+)"\s*>.*$')
+ for l in Path(file).read_text().splitlines():
+ match = pattern.match(l)
+ if match:
+ return (match.group(1), match.group(2))
+ return (None, None)
+
+
+def test_file(file: str, uic: bool=False) -> bool:
+ """Run uic on a UI file and show the resulting UI."""
+ path = Path(file)
+ (klass, name) = get_class_name(path)
+ if not klass:
+ print(f'{file} does not appear to be a UI file', file=sys.stderr)
+ return False
+ py_klass = f'Ui_{name}'
+ py_file_basename = py_klass.lower()
+ py_file = TEMP_DIR / (py_file_basename + '.py')
+ py_main = TEMP_DIR / 'main.py'
+ cmd = ['uic', '-g', 'python'] if uic else [f'pyside{VERSION}-uic']
+ cmd.extend(['-o', os.fspath(py_file), file])
+ try:
+ subprocess.call(cmd)
+ except FileNotFoundError as e:
+ print(str(e) + " (try -u for uic)", file=sys.stderr)
+ return False
+ main_source = dedent(f'''\
+ import sys
+ from PySide{VERSION}.QtWidgets import QApplication, {klass}
+ from {py_file_basename} import {py_klass}
+
+ if __name__ == "__main__":
+ app = QApplication(sys.argv)
+ ui = {py_klass}()
+ widget = {klass}()
+ ui.setupUi(widget)
+ widget.show()
+ sys.exit(app.exec_())''')
+ py_main.write_text(main_source)
+ exit_code = subprocess.call([sys.executable, os.fspath(py_main)])
+ py_main.unlink()
+ py_file.unlink()
+ return exit_code == 0
+
+
+if __name__ == '__main__':
+ argument_parser = ArgumentParser(description=DESC,
+ formatter_class=RawTextHelpFormatter)
+ argument_parser.add_argument('--uic', '-u', action='store_true',
+ help='Use uic instead of pyside-uic')
+ argument_parser.add_argument("files", help="UI Files",
+ nargs='+', type=str)
+ options = argument_parser.parse_args()
+ failed = 0
+ count = len(options.files)
+ for i, file in enumerate(options.files):
+ print(f'{i+1}/{count} {file}')
+ if not test_file(file, options.uic):
+ failed += 1
+ if failed != 0:
+ print(f'{failed}/{count} failed.')
+ sys.exit(failed)