aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFriedemann Kleint <Friedemann.Kleint@qt.io>2019-05-21 15:20:10 +0200
committerFriedemann Kleint <Friedemann.Kleint@qt.io>2019-05-21 15:20:10 +0200
commit11214e92a465d07e58116584849f168e1a6de884 (patch)
tree5f0e28ec5f930250d8d0d70ab48f8c9e75381d41
parent9ce268b576b00538aac3fa4b3a78a222f0f10380 (diff)
parentc134129bd55ebf91d3a74c720b8bd659f13bd93d (diff)
Merge remote-tracking branch 'origin/5.13' into dev
-rw-r--r--coin_build_instructions.py4
-rw-r--r--coin_test_instructions.py15
-rw-r--r--examples/sql/books/bookdelegate.py134
-rw-r--r--examples/sql/books/books.pyproject5
-rw-r--r--examples/sql/books/books.qrc5
-rw-r--r--examples/sql/books/bookwindow.py140
-rw-r--r--examples/sql/books/bookwindow.ui164
-rw-r--r--examples/sql/books/createdb.py117
-rw-r--r--examples/sql/books/images/star.pngbin0 -> 782 bytes
-rw-r--r--examples/sql/books/main.py53
-rw-r--r--examples/sql/books/rc_books.py88
-rw-r--r--examples/sql/books/ui_bookwindow.py129
-rw-r--r--sources/pyside2/cmake/Macros/PySideModules.cmake13
-rw-r--r--sources/pyside2/doc/deployment-fbs.rst20
-rw-r--r--sources/pyside2/doc/deployment-pyinstaller.rst49
-rw-r--r--sources/pyside2/doc/deployment.rst10
-rw-r--r--sources/shiboken2/libshiboken/basewrapper.cpp99
17 files changed, 1001 insertions, 44 deletions
diff --git a/coin_build_instructions.py b/coin_build_instructions.py
index d094d5b2a..9a7d6272c 100644
--- a/coin_build_instructions.py
+++ b/coin_build_instructions.py
@@ -101,7 +101,7 @@ def call_setup(python_ver):
rmtree(_env, True)
run_instruction(["virtualenv", "-p", _pExe, _env], "Failed to create virtualenv")
- install_pip_dependencies(env_pip, ["numpy", "setuptools", "sphinx", "six"])
+ install_pip_dependencies(env_pip, ["pip", "numpy", "setuptools", "sphinx", "six"])
install_pip_wheel_package(env_pip)
cmd = [env_python, "-u", "setup.py"]
@@ -116,8 +116,6 @@ def call_setup(python_ver):
"--verbose-build"]
if python_ver == "3":
cmd += ["--limited-api=yes"]
- else:
- cmd += ["--skip-docs"] # 1.4.2019: errors in sphinx_build on openSUSE 4.2
if is_snapshot_build():
cmd += ["--snapshot-build"]
diff --git a/coin_test_instructions.py b/coin_test_instructions.py
index 6c3e051bd..2a42ec677 100644
--- a/coin_test_instructions.py
+++ b/coin_test_instructions.py
@@ -38,7 +38,6 @@
#############################################################################
from build_scripts.options import has_option
from build_scripts.options import option_value
-from build_scripts.utils import get_python_dict
from build_scripts.utils import install_pip_dependencies
from build_scripts.utils import install_pip_wheel_package
from build_scripts.utils import get_qtci_virtualEnv
@@ -65,19 +64,11 @@ if _ci_features is not None:
CI_RELEASE_CONF = has_option("packaging")
-def get_package_version():
- """ Returns the version string for the PySide2 package. """
- pyside_version_py = os.path.join(os.path.dirname(__file__),
- "sources", "pyside2", "pyside_version.py")
- dict = get_python_dict(pyside_version_py)
- return (int(dict['major_version']), int(dict['minor_version']),
- int(dict['patch_version']))
-
def call_testrunner(python_ver, buildnro):
_pExe, _env, env_pip, env_python = get_qtci_virtualEnv(python_ver, CI_HOST_OS, CI_HOST_ARCH, CI_TARGET_ARCH)
rmtree(_env, True)
run_instruction(["virtualenv", "-p", _pExe, _env], "Failed to create virtualenv")
- install_pip_dependencies(env_pip, ["numpy", "PyOpenGL", "setuptools", "six", "pyinstaller"])
+ install_pip_dependencies(env_pip, ["pip", "numpy", "PyOpenGL", "setuptools", "six", "pyinstaller"])
install_pip_wheel_package(env_pip)
cmd = [env_python, "testrunner.py", "test",
"--blacklist", "build_history/blacklist.txt",
@@ -87,9 +78,7 @@ def call_testrunner(python_ver, buildnro):
qmake_path = get_ci_qmake_path(CI_ENV_INSTALL_DIR, CI_HOST_OS)
# Try to install built wheels, and build some buildable examples.
- # Fixme: Skip wheel testing for Qt >= 5.14 until
- # qt5/09f28e9e1d989a70c876138a4cf24e35c67e0fbb has landed in dev
- if CI_RELEASE_CONF and get_package_version()[1] < 14:
+ if CI_RELEASE_CONF:
wheel_tester_path = os.path.join("testing", "wheel_tester.py")
cmd = [env_python, wheel_tester_path, qmake_path]
run_instruction(cmd, "Error while running wheel_tester.py")
diff --git a/examples/sql/books/bookdelegate.py b/examples/sql/books/bookdelegate.py
new file mode 100644
index 000000000..a0bd92334
--- /dev/null
+++ b/examples/sql/books/bookdelegate.py
@@ -0,0 +1,134 @@
+#############################################################################
+##
+## Copyright (C) 2019 The Qt Company Ltd.
+## Contact: http://www.qt.io/licensing/
+##
+## This file is part of the Qt for Python examples of the Qt Toolkit.
+##
+## $QT_BEGIN_LICENSE:BSD$
+## You may use this file under the terms of the BSD license as follows:
+##
+## "Redistribution and use in source and binary forms, with or without
+## modification, are permitted provided that the following conditions are
+## met:
+## * Redistributions of source code must retain the above copyright
+## notice, this list of conditions and the following disclaimer.
+## * Redistributions in binary form must reproduce the above copyright
+## notice, this list of conditions and the following disclaimer in
+## the documentation and/or other materials provided with the
+## distribution.
+## * Neither the name of The Qt Company Ltd nor the names of its
+## contributors may be used to endorse or promote products derived
+## from this software without specific prior written permission.
+##
+##
+## THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+## "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+## LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+## A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+## OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+## SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+## LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+## DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+## THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+## (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+## OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+##
+## $QT_END_LICENSE$
+##
+#############################################################################
+
+import copy
+from PySide2.QtSql import QSqlRelationalDelegate
+from PySide2.QtWidgets import (QItemDelegate, QSpinBox, QStyledItemDelegate,
+ QStyle, QStyleOptionViewItem)
+from PySide2.QtGui import QMouseEvent, QPixmap, QPalette
+from PySide2.QtCore import QEvent, QSize, Qt
+
+
+class BookDelegate(QSqlRelationalDelegate):
+ """Books delegate to rate the books"""
+
+ def __init__(self, parent=None):
+ QSqlRelationalDelegate.__init__(self, parent)
+ self.star = QPixmap(":/images/star.png")
+
+ def paint(self, painter, option, index):
+ """ Paint the items in the table.
+
+ If the item referred to by <index> is a StarRating, we
+ handle the painting ourselves. For the other items, we
+ let the base class handle the painting as usual.
+
+ In a polished application, we'd use a better check than
+ the column number to find out if we needed to paint the
+ stars, but it works for the purposes of this example.
+ """
+ if index.column() != 5:
+ # Since we draw the grid ourselves:
+ opt = copy.copy(option)
+ opt.rect = option.rect.adjusted(0, 0, -1, -1)
+ QSqlRelationalDelegate.paint(self, painter, opt, index)
+ else:
+ model = index.model()
+ if option.state & QStyle.State_Enabled:
+ if option.state & QStyle.State_Active:
+ color_group = QPalette.Normal
+ else:
+ color_group = QPalette.Inactive
+ else:
+ color_group = QPalette.Disabled
+
+ if option.state & QStyle.State_Selected:
+ painter.fillRect(option.rect,
+ option.palette.color(color_group, QPalette.Highlight))
+ rating = model.data(index, Qt.DisplayRole)
+ width = self.star.width()
+ height = self.star.height()
+ x = option.rect.x()
+ y = option.rect.y() + (option.rect.height() / 2) - (height / 2)
+ for i in range(rating):
+ painter.drawPixmap(x, y, self.star)
+ x += width
+
+ # Since we draw the grid ourselves:
+ self.drawFocus(painter, option, option.rect.adjusted(0, 0, -1, -1))
+
+ pen = painter.pen()
+ painter.setPen(option.palette.color(QPalette.Mid))
+ painter.drawLine(option.rect.bottomLeft(), option.rect.bottomRight())
+ painter.drawLine(option.rect.topRight(), option.rect.bottomRight())
+ painter.setPen(pen)
+
+ def sizeHint(self, option, index):
+ """ Returns the size needed to display the item in a QSize object. """
+ if index.column() == 5:
+ size_hint = QSize(5 * self.star.width(), self.star.height()) + QSize(1, 1)
+ return size_hint
+ # Since we draw the grid ourselves:
+ return QSqlRelationalDelegate.sizeHint(self, option, index) + QSize(1, 1)
+
+ def editorEvent(self, event, model, option, index):
+ if index.column() != 5:
+ return False
+
+ if event.type() == QEvent.MouseButtonPress:
+ mouse_pos = event.pos()
+ new_stars = int(0.7 + (mouse_pos.x() - option.rect.x()) / self.star.width())
+ stars = max(0, min(new_stars, 5))
+ model.setData(index, stars)
+ # So that the selection can change
+ return False
+
+ return True
+
+ def createEditor(self, parent, option, index):
+ if index.column() != 4:
+ return QSqlRelationalDelegate.createEditor(self, parent, option, index)
+
+ # For editing the year, return a spinbox with a range from -1000 to 2100.
+ spinbox = QSpinBox(parent)
+ spinbox.setFrame(False)
+ spinbox.setMaximum(2100)
+ spinbox.setMinimum(-1000)
+ return spinbox
diff --git a/examples/sql/books/books.pyproject b/examples/sql/books/books.pyproject
new file mode 100644
index 000000000..44a1ef219
--- /dev/null
+++ b/examples/sql/books/books.pyproject
@@ -0,0 +1,5 @@
+{
+ "files": ["main.py", "bookdelegate.py", "bookwindow.py",
+ "createdb.py", "books.qrc", "bookwindow.ui",
+ "images/star.png"]
+}
diff --git a/examples/sql/books/books.qrc b/examples/sql/books/books.qrc
new file mode 100644
index 000000000..d6ad21337
--- /dev/null
+++ b/examples/sql/books/books.qrc
@@ -0,0 +1,5 @@
+<!DOCTYPE RCC><RCC version="1.0">
+<qresource>
+ <file>images/star.png</file>
+</qresource>
+</RCC>
diff --git a/examples/sql/books/bookwindow.py b/examples/sql/books/bookwindow.py
new file mode 100644
index 000000000..500acf2ef
--- /dev/null
+++ b/examples/sql/books/bookwindow.py
@@ -0,0 +1,140 @@
+#############################################################################
+##
+## Copyright (C) 2019 The Qt Company Ltd.
+## Contact: http://www.qt.io/licensing/
+##
+## This file is part of the Qt for Python examples of the Qt Toolkit.
+##
+## $QT_BEGIN_LICENSE:BSD$
+## You may use this file under the terms of the BSD license as follows:
+##
+## "Redistribution and use in source and binary forms, with or without
+## modification, are permitted provided that the following conditions are
+## met:
+## * Redistributions of source code must retain the above copyright
+## notice, this list of conditions and the following disclaimer.
+## * Redistributions in binary form must reproduce the above copyright
+## notice, this list of conditions and the following disclaimer in
+## the documentation and/or other materials provided with the
+## distribution.
+## * Neither the name of The Qt Company Ltd nor the names of its
+## contributors may be used to endorse or promote products derived
+## from this software without specific prior written permission.
+##
+##
+## THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+## "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+## LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+## A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+## OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+## SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+## LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+## DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+## THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+## (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+## OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+##
+## $QT_END_LICENSE$
+##
+#############################################################################
+
+from __future__ import print_function, absolute_import
+
+from PySide2.QtWidgets import (QAction, QAbstractItemView, qApp, QDataWidgetMapper,
+ QHeaderView, QMainWindow, QMessageBox)
+from PySide2.QtGui import QKeySequence
+from PySide2.QtSql import (QSqlRelation, QSqlRelationalTableModel, QSqlTableModel,
+ QSqlError)
+from PySide2.QtCore import QAbstractItemModel, QObject, QSize, Qt, Slot
+import createdb
+from ui_bookwindow import Ui_BookWindow
+from bookdelegate import BookDelegate
+
+
+class BookWindow(QMainWindow, Ui_BookWindow):
+ """A window to show the books available"""
+
+ def __init__(self):
+ QMainWindow.__init__(self)
+ self.setupUi(self)
+
+ #check for SQL errors
+ err = createdb.init_db()
+ if err.type() is not QSqlError.NoError:
+ showError(err)
+ return
+
+ model = QSqlRelationalTableModel(self.bookTable)
+ model.setEditStrategy(QSqlTableModel.OnManualSubmit)
+ model.setTable("books")
+
+ # Remember the indexes of the columns:
+ author_idx = model.fieldIndex("author")
+ genre_idx = model.fieldIndex("genre")
+
+ # Set the relations to the other database tables:
+ model.setRelation(author_idx, QSqlRelation("authors", "id", "name"))
+ model.setRelation(genre_idx, QSqlRelation("genres", "id", "name"))
+
+ # Set the localized header captions:
+ model.setHeaderData(author_idx, Qt.Horizontal, self.tr("Author Name"))
+ model.setHeaderData(genre_idx, Qt.Horizontal, self.tr("Genre"))
+ model.setHeaderData(model.fieldIndex("title"), Qt.Horizontal, self.tr("Title"))
+ model.setHeaderData(model.fieldIndex("year"), Qt.Horizontal, self.tr("Year"))
+ model.setHeaderData(model.fieldIndex("rating"), Qt.Horizontal, self.tr("Rating"))
+
+ if not model.select():
+ print(model.lastError())
+
+ # Set the model and hide the ID column:
+ self.bookTable.setModel(model)
+ self.bookTable.setItemDelegate(BookDelegate(self.bookTable))
+ self.bookTable.setColumnHidden(model.fieldIndex("id"), True)
+ self.bookTable.setSelectionMode(QAbstractItemView.SingleSelection)
+
+ # Initialize the Author combo box:
+ self.authorEdit.setModel(model.relationModel(author_idx))
+ self.authorEdit.setModelColumn(model.relationModel(author_idx).fieldIndex("name"))
+
+ self.genreEdit.setModel(model.relationModel(genre_idx))
+ self.genreEdit.setModelColumn(model.relationModel(genre_idx).fieldIndex("name"))
+
+ # Lock and prohibit resizing of the width of the rating column:
+ self.bookTable.horizontalHeader().setSectionResizeMode(model.fieldIndex("rating"),
+ QHeaderView.ResizeToContents)
+
+ mapper = QDataWidgetMapper(self)
+ mapper.setModel(model)
+ mapper.setItemDelegate(BookDelegate(self))
+ mapper.addMapping(self.titleEdit, model.fieldIndex("title"))
+ mapper.addMapping(self.yearEdit, model.fieldIndex("year"))
+ mapper.addMapping(self.authorEdit, author_idx)
+ mapper.addMapping(self.genreEdit, genre_idx)
+ mapper.addMapping(self.ratingEdit, model.fieldIndex("rating"))
+
+ selection_model = self.bookTable.selectionModel()
+ selection_model.currentRowChanged.connect(mapper.setCurrentModelIndex)
+
+ self.bookTable.setCurrentIndex(model.index(0, 0))
+ self.create_menubar()
+
+ def showError(err):
+ QMessageBox.critical(self, "Unable to initialize Database",
+ "Error initializing database: " + err.text())
+
+ def create_menubar(self):
+ file_menu = self.menuBar().addMenu(self.tr("&File"))
+ quit_action = file_menu.addAction(self.tr("&Quit"))
+ quit_action.triggered.connect(qApp.quit)
+
+ help_menu = self.menuBar().addMenu(self.tr("&Help"))
+ about_action = help_menu.addAction(self.tr("&About"))
+ about_action.setShortcut(QKeySequence.HelpContents)
+ about_action.triggered.connect(self.about)
+ aboutQt_action = help_menu.addAction("&About Qt")
+ aboutQt_action.triggered.connect(qApp.aboutQt)
+
+ def about(self):
+ QMessageBox.about(self, self.tr("About Books"),
+ self.tr("<p>The <b>Books</b> example shows how to use Qt SQL classes "
+ "with a model/view framework."))
diff --git a/examples/sql/books/bookwindow.ui b/examples/sql/books/bookwindow.ui
new file mode 100644
index 000000000..ce8f9f933
--- /dev/null
+++ b/examples/sql/books/bookwindow.ui
@@ -0,0 +1,164 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>BookWindow</class>
+ <widget class="QMainWindow" name="BookWindow">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>601</width>
+ <height>420</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Books</string>
+ </property>
+ <widget class="QWidget" name="centralWidget">
+ <layout class="QVBoxLayout">
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <property name="leftMargin">
+ <number>9</number>
+ </property>
+ <property name="topMargin">
+ <number>9</number>
+ </property>
+ <property name="rightMargin">
+ <number>9</number>
+ </property>
+ <property name="bottomMargin">
+ <number>9</number>
+ </property>
+ <item>
+ <widget class="QGroupBox" name="groupBox">
+ <property name="title">
+ <string/>
+ </property>
+ <layout class="QVBoxLayout">
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <property name="leftMargin">
+ <number>9</number>
+ </property>
+ <property name="topMargin">
+ <number>9</number>
+ </property>
+ <property name="rightMargin">
+ <number>9</number>
+ </property>
+ <property name="bottomMargin">
+ <number>9</number>
+ </property>
+ <item>
+ <widget class="QTableView" name="bookTable">
+ <property name="selectionBehavior">
+ <enum>QAbstractItemView::SelectRows</enum>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QGroupBox" name="groupBox_2">
+ <property name="title">
+ <string>Details</string>
+ </property>
+ <layout class="QFormLayout">
+ <item row="0" column="0">
+ <widget class="QLabel" name="label_5">
+ <property name="text">
+ <string>&lt;b&gt;Title:&lt;/b&gt;</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1">
+ <widget class="QLineEdit" name="titleEdit">
+ <property name="enabled">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="0">
+ <widget class="QLabel" name="label_2">
+ <property name="text">
+ <string>&lt;b&gt;Author: &lt;/b&gt;</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="1">
+ <widget class="QComboBox" name="authorEdit">
+ <property name="enabled">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="0">
+ <widget class="QLabel" name="label_3">
+ <property name="text">
+ <string>&lt;b&gt;Genre:&lt;/b&gt;</string>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="1">
+ <widget class="QComboBox" name="genreEdit">
+ <property name="enabled">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item row="3" column="0">
+ <widget class="QLabel" name="label_4">
+ <property name="text">
+ <string>&lt;b&gt;Year:&lt;/b&gt;</string>
+ </property>
+ </widget>
+ </item>
+ <item row="3" column="1">
+ <widget class="QSpinBox" name="yearEdit">
+ <property name="enabled">
+ <bool>true</bool>
+ </property>
+ <property name="prefix">
+ <string/>
+ </property>
+ <property name="minimum">
+ <number>-1000</number>
+ </property>
+ <property name="maximum">
+ <number>2100</number>
+ </property>
+ </widget>
+ </item>
+ <item row="4" column="0">
+ <widget class="QLabel" name="label">
+ <property name="text">
+ <string>&lt;b&gt;Rating:&lt;/b&gt;</string>
+ </property>
+ </widget>
+ </item>
+ <item row="4" column="1">
+ <widget class="QSpinBox" name="ratingEdit">
+ <property name="maximum">
+ <number>5</number>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </widget>
+ <tabstops>
+ <tabstop>bookTable</tabstop>
+ <tabstop>titleEdit</tabstop>
+ <tabstop>authorEdit</tabstop>
+ <tabstop>genreEdit</tabstop>
+ <tabstop>yearEdit</tabstop>
+ </tabstops>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/examples/sql/books/createdb.py b/examples/sql/books/createdb.py
new file mode 100644
index 000000000..d662cacd1
--- /dev/null
+++ b/examples/sql/books/createdb.py
@@ -0,0 +1,117 @@
+#############################################################################
+##
+## Copyright (C) 2019 The Qt Company Ltd.
+## Contact: http://www.qt.io/licensing/
+##
+## This file is part of the Qt for Python examples of the Qt Toolkit.
+##
+## $QT_BEGIN_LICENSE:BSD$
+## You may use this file under the terms of the BSD license as follows:
+##
+## "Redistribution and use in source and binary forms, with or without
+## modification, are permitted provided that the following conditions are
+## met:
+## * Redistributions of source code must retain the above copyright
+## notice, this list of conditions and the following disclaimer.
+## * Redistributions in binary form must reproduce the above copyright
+## notice, this list of conditions and the following disclaimer in
+## the documentation and/or other materials provided with the
+## distribution.
+## * Neither the name of The Qt Company Ltd nor the names of its
+## contributors may be used to endorse or promote products derived
+## from this software without specific prior written permission.
+##
+##
+## THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+## "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+## LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+## A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+## OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+## SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+## LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+## DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+## THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+## (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+## OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+##
+## $QT_END_LICENSE$
+##
+#############################################################################
+
+from PySide2.QtSql import QSqlDatabase, QSqlError, QSqlQuery
+from datetime import datetime
+
+
+def add_book(q, title, year, authorId, genreId, rating):
+ q.addBindValue(title)
+ q.addBindValue(year)
+ q.addBindValue(authorId)
+ q.addBindValue(genreId)
+ q.addBindValue(rating)
+ q.exec_()
+
+
+def add_genre(q, name):
+ q.addBindValue(name)
+ q.exec_()
+ return q.lastInsertId()
+
+
+def add_author(q, name, birthdate):
+ q.addBindValue(name)
+ q.addBindValue(birthdate)
+ q.exec_()
+ return q.lastInsertId()
+
+
+def init_db():
+ db = QSqlDatabase.addDatabase("QSQLITE")
+ db.setDatabaseName(":memory:")
+
+ if not db.open():
+ return db.lastError()
+
+ tables = db.tables()
+ for table in tables:
+ if table == "books" and table == "authors":
+ return QSqlError()
+
+ q = QSqlQuery()
+ if not q.exec_("create table books(id integer primary key, title varchar, author integer, "
+ "genre integer, year integer, rating integer)"):
+ return q.lastError()
+ if not q.exec_("create table authors(id integer primary key, name varchar, birthdate date)"):
+ return q.lastError()
+ if not q.exec_("create table genres(id integer primary key, name varchar)"):
+ return q.lastError()
+
+ if not q.prepare("insert into authors(name, birthdate) values(?, ?)"):
+ return q.lastError()
+ asimovId = add_author(q, "Isaac Asimov", datetime(1920, 2, 1))
+ greeneId = add_author(q, "Graham Greene", datetime(1904, 10, 2))
+ pratchettId = add_author(q, "Terry Pratchett", datetime(1948, 4, 28))
+
+ if not q.prepare("insert into genres(name) values(?)"):
+ return q.lastError()
+ sfiction = add_genre(q, "Science Fiction")
+ fiction = add_genre(q, "Fiction")
+ fantasy = add_genre(q, "Fantasy")
+
+ if not q.prepare("insert into books(title, year, author, genre, rating) "
+ "values(?, ?, ?, ?, ?)"):
+ return q.lastError()
+ add_book(q, "Foundation", 1951, asimovId, sfiction, 3)
+ add_book(q, "Foundation and Empire", 1952, asimovId, sfiction, 4)
+ add_book(q, "Second Foundation", 1953, asimovId, sfiction, 3)
+ add_book(q, "Foundation's Edge", 1982, asimovId, sfiction, 3)
+ add_book(q, "Foundation and Earth", 1986, asimovId, sfiction, 4)
+ add_book(q, "Prelude to Foundation", 1988, asimovId, sfiction, 3)
+ add_book(q, "Forward the Foundation", 1993, asimovId, sfiction, 3)
+ add_book(q, "The Power and the Glory", 1940, greeneId, fiction, 4)
+ add_book(q, "The Third Man", 1950, greeneId, fiction, 5)
+ add_book(q, "Our Man in Havana", 1958, greeneId, fiction, 4)
+ add_book(q, "Guards! Guards!", 1989, pratchettId, fantasy, 3)
+ add_book(q, "Night Watch", 2002, pratchettId, fantasy, 3)
+ add_book(q, "Going Postal", 2004, pratchettId, fantasy, 3)
+
+ return QSqlError()
diff --git a/examples/sql/books/images/star.png b/examples/sql/books/images/star.png
new file mode 100644
index 000000000..87f4464bd
--- /dev/null
+++ b/examples/sql/books/images/star.png
Binary files differ
diff --git a/examples/sql/books/main.py b/examples/sql/books/main.py
new file mode 100644
index 000000000..50d2c0d6b
--- /dev/null
+++ b/examples/sql/books/main.py
@@ -0,0 +1,53 @@
+#############################################################################
+##
+## Copyright (C) 2019 The Qt Company Ltd.
+## Contact: http://www.qt.io/licensing/
+##
+## This file is part of the Qt for Python examples of the Qt Toolkit.
+##
+## $QT_BEGIN_LICENSE:BSD$
+## You may use this file under the terms of the BSD license as follows:
+##
+## "Redistribution and use in source and binary forms, with or without
+## modification, are permitted provided that the following conditions are
+## met:
+## * Redistributions of source code must retain the above copyright
+## notice, this list of conditions and the following disclaimer.
+## * Redistributions in binary form must reproduce the above copyright
+## notice, this list of conditions and the following disclaimer in
+## the documentation and/or other materials provided with the
+## distribution.
+## * Neither the name of The Qt Company Ltd nor the names of its
+## contributors may be used to endorse or promote products derived
+## from this software without specific prior written permission.
+##
+##
+## THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+## "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+## LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+## A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+## OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+## SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+## LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+## DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+## THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+## (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+## OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+##
+## $QT_END_LICENSE$
+##
+#############################################################################
+
+import sys
+from PySide2.QtWidgets import QApplication
+from bookwindow import BookWindow
+import rc_books
+
+if __name__ == "__main__":
+ app = QApplication([])
+
+ window = BookWindow()
+ window.resize(800, 600)
+ window.show()
+
+ sys.exit(app.exec_())
diff --git a/examples/sql/books/rc_books.py b/examples/sql/books/rc_books.py
new file mode 100644
index 000000000..6f2cbbeb6
--- /dev/null
+++ b/examples/sql/books/rc_books.py
@@ -0,0 +1,88 @@
+# Resource object code (Python 3)
+# Created by: object code
+# Created by: The Resource Compiler for Qt version 5.14.0
+# WARNING! All changes made in this file will be lost!
+
+from PySide2 import QtCore
+
+qt_resource_data = b"\
+\x00\x00\x03\x0e\
+\x89\
+PNG\x0d\x0a\x1a\x0a\x00\x00\x00\x0dIHDR\x00\
+\x00\x00\x10\x00\x00\x00\x10\x08\x06\x00\x00\x00\x1f\xf3\xffa\
+\x00\x00\x00\x09pHYs\x00\x00\x0b\x11\x00\x00\x0b\x11\
+\x01\x7fd_\x91\x00\x00\x00\x07tIME\x07\xd4\x09\
+\x03\x12\x11\x08\x18~\xe5:\x00\x00\x00\x06bKGD\
+\x00\xff\x00\xff\x00\xff\xa0\xbd\xa7\x93\x00\x00\x02\x9bID\
+AT8\xcbc\x98:c\x1e#:\xe6\xe5d\xcf\x17\
+\x12\x12\x16\xc4&\x87\x8e\x19\xb0\x09v\xc6\x18\xb7x\xea\
+\x8b\xcd\x9c=o\x09i\x06,X4\x8f\xf1\xd2\xa5\x99\
+L\xb9\xa1\x16\xc5\xc7\xbb\xed\xff\x0a\xf2\xb2;M\x9f\xb5\
+\x908\x03\x16,\x9a\xcb\xf8\xe0\xde\x04\x96\xc7\x0f\xdby\
+\xe7MO\xc8\xfbv\xbf\xe5\xff\xb4\x0a\x9b\x9by\x851\
+\xdc\xd3g-\x82k\x983\x7f)\xe3l F1`\
+\xca\xf4y\x8c\xd7\xaeMg\x02i~\xf2\xa8Y\xe1\xd2\
+\xa5\xfa\xdc_\x9f7\xfd\xffx\xbf\xea\x7fE\x96m\x97\
+\x81\x81>'33\x8b\xa5\x9e8gi\xb8\x9e\xc0f\
+&&\xa6D\x14\x03&N\x9d\xc7x\xef\xdeD\x96'\
+\x0f[E\x9f>j\xd6\xbdu\xb3\x22\xef\xd7\xb7=\xff\
+\xbe\x7f\xe8\xfb\x7f~S\xcc\xef\x05\xc5\xea\x9fNOQ\
+\xfb\x7f\xbaM\xed\xbf\x87\x1a\xefn5-\x1dV\x14\x03\
+f\xcf[\xce\xa8\xa4\xa9![W\xed\x9b}\xefJ\xcb\
+\xcew\xaf&\x7f\xfa\xfee\xc9\xff\xef\x1f\xfa\xff\xbf\xbf\
+\x95\xf2\xff\xc9^\x83\xffW\x17\xaa\xfdot\x12{\xc4\
+\xc7\xc7/\x8e\x12\x06Y\xb9\x85\xcc\xb2\x82\x1c\xf3\xa7D\
+\xab\xfe\xfa\xbe%\xe2\xff\x8fgm\xff\x7f|\x9a\x08\xd6\
+\xfc\xf5Y\xcd\xff\xd7\xe7\xfc\xfe\xdf\xde\xa0\xf5\x7fE\x94\
+\xecO\x16\x16V\xebi3\xe7\xa3\x06\xe2\xe4is\x18\
+\xe7/Z\xc1\xc8\xce\xc1i\x10\xe5\xa8\xd2\xbe\xa6\xcd\xe7\
+\xf6\xc3m\x99\xff~^(\xf8\xff\xe1j\xe0\xff\x17G\
+L\xff\xdf\xdf\xae\xf6\xbf\xc2]\xf4\xba\x9a\x9a\x06\x1bF\
+,\x00\x01#2\xe6\xe6\xe6`Q\xd6\x941_\xde\xe4\
+q\xfb\xc3y\xd3\xff\x1b\x8aT\xff\xbf?`\xff\xff\xdc\
+l\xe5\xff\xea\xc2\x1c9\xd3g-\xc0i\x00\x13\x10\x8b\
+\x03\xb1?\x10\xe7\xf5\x16\xd8\xde\xf8p\xc6\xe4\xbf\x9d<\
+\xf7t\x7fC\xe9\x95\xb7\x96\xd9\xff\x9b\x9c,\xfdN@\
+@H\x14\x9b\x01LP,\x06\xc4\x19@|\x22;\xca\
+\xf0\xe7\xe9\xf9\x06\xff\x81\xec\x03@\xbc^\x82\x9f\xf3\xf6\
+\x9e\x1a\xf3_az\x823P\xd2\x01T#3\x10\x0b\
+\x00\xb1\x1e\x10\x17\x03\xf1\xd1\xa8@\xdd\x9f\xad\x09J \
+\x03\xfe\x00\xf17 >\x0f\xb4kf\xb9\xa7\xea\x0d}\
+i>#d\x03\xb4\x808\x08\x88k\x81x\x09\xd4\xc6\
+\x1b\x11a\x06\xdf\xec\x94\xb8\xdf\x03\xd9;\x81x\x1a\x10\
+\xf7\x82\xd4\xb0\xb2\xb1G\xf9\xda\x99:L\x9d9\x9f\x09\
+f\x80\x0e\x10;\x02\xb1\x13\x10[\x00\xb1\x01\x10\x07\x06\
+{h\x9c\x02\xd2k\xa0\x86\x8b\x001\x17\x10\xf3\x80\xb0\
+\x88\x88(\xcb,hFC\xf6\x02\x08\xb3\x001+\x10\
+K122\xe4\x01i7 \x96\x01b6\xa88\x0b\
+T=cW\xef$\xb0\x01\x00\xceo{\xf5UL\xf0\
+\xac\x00\x00\x00\x00IEND\xaeB`\x82\
+"
+
+qt_resource_name = b"\
+\x00\x06\
+\x07\x03}\xc3\
+\x00i\
+\x00m\x00a\x00g\x00e\x00s\
+\x00\x08\
+\x0a\x85X\x07\
+\x00s\
+\x00t\x00a\x00r\x00.\x00p\x00n\x00g\
+"
+
+qt_resource_struct = b"\
+\x00\x00\x00\x00\x00\x02\x00\x00\x00\x01\x00\x00\x00\x01\
+\x00\x00\x00\x00\x00\x00\x00\x00\
+\x00\x00\x00\x00\x00\x02\x00\x00\x00\x01\x00\x00\x00\x02\
+\x00\x00\x00\x00\x00\x00\x00\x00\
+\x00\x00\x00\x12\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\
+\x00\x00\x01j\x965\xd3\xea\
+"
+
+def qInitResources():
+ QtCore.qRegisterResourceData(0x03, qt_resource_struct, qt_resource_name, qt_resource_data)
+
+def qCleanupResources():
+ QtCore.qUnregisterResourceData(0x03, qt_resource_struct, qt_resource_name, qt_resource_data)
+
+qInitResources()
diff --git a/examples/sql/books/ui_bookwindow.py b/examples/sql/books/ui_bookwindow.py
new file mode 100644
index 000000000..5eb412d92
--- /dev/null
+++ b/examples/sql/books/ui_bookwindow.py
@@ -0,0 +1,129 @@
+# -*- coding: utf-8 -*-
+
+################################################################################
+## Form generated from reading UI file 'bookwindow.ui'
+##
+## Created by: Qt User Interface Compiler version 5.14.0
+##
+## WARNING! All changes made in this file will be lost when recompiling UI file!
+################################################################################
+
+from PySide2.QtCore import (QCoreApplication, QMetaObject, QObject, QPoint,
+ QRect, QSize, QUrl, Qt)
+from PySide2.QtGui import (QBrush, QColor, QConicalGradient, QFont,
+ QFontDatabase, QIcon, QLinearGradient, QPalette, QPainter, QPixmap,
+ QRadialGradient)
+from PySide2.QtWidgets import *
+
+class Ui_BookWindow(object):
+ def setupUi(self, BookWindow):
+ if BookWindow.objectName():
+ BookWindow.setObjectName(u"BookWindow")
+ BookWindow.resize(601, 420)
+ self.centralWidget = QWidget(BookWindow)
+ self.centralWidget.setObjectName(u"centralWidget")
+ self.vboxLayout = QVBoxLayout(self.centralWidget);
+ self.vboxLayout.setSpacing(6)
+ self.vboxLayout.setObjectName(u"vboxLayout")
+ self.vboxLayout.setContentsMargins(9, 9, 9, 9);
+ self.groupBox = QGroupBox(self.centralWidget)
+ self.groupBox.setObjectName(u"groupBox")
+ self.vboxLayout1 = QVBoxLayout(self.groupBox);
+ self.vboxLayout1.setSpacing(6)
+ self.vboxLayout1.setObjectName(u"vboxLayout1")
+ self.vboxLayout1.setContentsMargins(9, 9, 9, 9);
+ self.bookTable = QTableView(self.groupBox)
+ self.bookTable.setObjectName(u"bookTable")
+ self.bookTable.setSelectionBehavior(QAbstractItemView.SelectRows)
+
+ self.vboxLayout1.addWidget(self.bookTable);
+
+ self.groupBox_2 = QGroupBox(self.groupBox)
+ self.groupBox_2.setObjectName(u"groupBox_2")
+ self.formLayout = QFormLayout(self.groupBox_2);
+ self.formLayout.setObjectName(u"formLayout")
+ self.label_5 = QLabel(self.groupBox_2)
+ self.label_5.setObjectName(u"label_5")
+
+ self.formLayout.setWidget(0, QFormLayout.LabelRole, self.label_5);
+
+ self.titleEdit = QLineEdit(self.groupBox_2)
+ self.titleEdit.setObjectName(u"titleEdit")
+ self.titleEdit.setEnabled(True)
+
+ self.formLayout.setWidget(0, QFormLayout.FieldRole, self.titleEdit);
+
+ self.label_2 = QLabel(self.groupBox_2)
+ self.label_2.setObjectName(u"label_2")
+
+ self.formLayout.setWidget(1, QFormLayout.LabelRole, self.label_2);
+
+ self.authorEdit = QComboBox(self.groupBox_2)
+ self.authorEdit.setObjectName(u"authorEdit")
+ self.authorEdit.setEnabled(True)
+
+ self.formLayout.setWidget(1, QFormLayout.FieldRole, self.authorEdit);
+
+ self.label_3 = QLabel(self.groupBox_2)
+ self.label_3.setObjectName(u"label_3")
+
+ self.formLayout.setWidget(2, QFormLayout.LabelRole, self.label_3);
+
+ self.genreEdit = QComboBox(self.groupBox_2)
+ self.genreEdit.setObjectName(u"genreEdit")
+ self.genreEdit.setEnabled(True)
+
+ self.formLayout.setWidget(2, QFormLayout.FieldRole, self.genreEdit);
+
+ self.label_4 = QLabel(self.groupBox_2)
+ self.label_4.setObjectName(u"label_4")
+
+ self.formLayout.setWidget(3, QFormLayout.LabelRole, self.label_4);
+
+ self.yearEdit = QSpinBox(self.groupBox_2)
+ self.yearEdit.setObjectName(u"yearEdit")
+ self.yearEdit.setEnabled(True)
+ self.yearEdit.setMinimum(-1000)
+ self.yearEdit.setMaximum(2100)
+
+ self.formLayout.setWidget(3, QFormLayout.FieldRole, self.yearEdit);
+
+ self.label = QLabel(self.groupBox_2)
+ self.label.setObjectName(u"label")
+
+ self.formLayout.setWidget(4, QFormLayout.LabelRole, self.label);
+
+ self.ratingEdit = QSpinBox(self.groupBox_2)
+ self.ratingEdit.setObjectName(u"ratingEdit")
+ self.ratingEdit.setMaximum(5)
+
+ self.formLayout.setWidget(4, QFormLayout.FieldRole, self.ratingEdit);
+
+
+ self.vboxLayout1.addWidget(self.groupBox_2);
+
+
+ self.vboxLayout.addWidget(self.groupBox);
+
+ BookWindow.setCentralWidget(self.centralWidget)
+ QWidget.setTabOrder(self.bookTable, self.titleEdit)
+ QWidget.setTabOrder(self.titleEdit, self.authorEdit)
+ QWidget.setTabOrder(self.authorEdit, self.genreEdit)
+ QWidget.setTabOrder(self.genreEdit, self.yearEdit)
+
+ self.retranslateUi(BookWindow)
+
+ QMetaObject.connectSlotsByName(BookWindow)
+ # setupUi
+
+ def retranslateUi(self, BookWindow):
+ BookWindow.setWindowTitle(QCoreApplication.translate("BookWindow", u"Books", None))
+ self.groupBox.setTitle("")
+ self.groupBox_2.setTitle(QCoreApplication.translate("BookWindow", u"Details", None))
+ self.label_5.setText(QCoreApplication.translate("BookWindow", u"<b>Title:</b>", None))
+ self.label_2.setText(QCoreApplication.translate("BookWindow", u"<b>Author: </b>", None))
+ self.label_3.setText(QCoreApplication.translate("BookWindow", u"<b>Genre:</b>", None))
+ self.label_4.setText(QCoreApplication.translate("BookWindow", u"<b>Year:</b>", None))
+ self.yearEdit.setPrefix("")
+ self.label.setText(QCoreApplication.translate("BookWindow", u"<b>Rating:</b>", None))
+ # retranslateUi
diff --git a/sources/pyside2/cmake/Macros/PySideModules.cmake b/sources/pyside2/cmake/Macros/PySideModules.cmake
index cbf401102..77dc8c8ac 100644
--- a/sources/pyside2/cmake/Macros/PySideModules.cmake
+++ b/sources/pyside2/cmake/Macros/PySideModules.cmake
@@ -169,6 +169,19 @@ macro(create_pyside_module)
set(ld_prefix "LD_LIBRARY_PATH=")
endif()
set(ld_prefix "${ld_prefix}${pysidebindings_BINARY_DIR}/libpyside${PATH_SEP}${SHIBOKEN_SHARED_LIBRARY_DIR}")
+
+ # On Windows we also need to propagate the whole environment PATH value, because pyside modules
+ # import Qt, and the Qt modules are found from PATH.
+ if(WIN32)
+ # Get the value of PATH with CMake separators.
+ file(TO_CMAKE_PATH "$ENV{PATH}" path_value)
+
+ # Replace the CMake list separators with "\;"s, to avoid the PATH values being
+ # interpreted as CMake list elements, we actually want to pass the whole string separated
+ # by ";" to the command line.
+ make_path(path_value "${path_value}")
+ string(APPEND ld_prefix "${PATH_SEP}${path_value}")
+ endif()
set(generate_pyi_options run --skip --sys-path
"${pysidebindings_BINARY_DIR}"
"${SHIBOKEN_PYTHON_MODULE_DIR}")
diff --git a/sources/pyside2/doc/deployment-fbs.rst b/sources/pyside2/doc/deployment-fbs.rst
index 94c52a08b..ff489f745 100644
--- a/sources/pyside2/doc/deployment-fbs.rst
+++ b/sources/pyside2/doc/deployment-fbs.rst
@@ -14,9 +14,9 @@ options.
Preparation
===========
-Installing `fbs` can be done via **pip**::
+Installing `fbs` (>= 0.7.6) can be done via **pip**::
- pip install fbs pyinstaller==3.4
+ pip install fbs
If you are using a virtual environment, remember to activate it before
installing it.
@@ -62,18 +62,12 @@ The main file will be under the `python` directory, and its content by default i
import sys
- class AppContext(ApplicationContext): # 1. Subclass ApplicationContext
- def run(self): # 2. Implement run()
- window = QMainWindow()
- version = self.build_settings['version']
- window.setWindowTitle("MyApp v" + version)
- window.resize(250, 150)
- window.show()
- return self.app.exec_() # 3. End run() with this line
-
if __name__ == '__main__':
- appctxt = AppContext() # 4. Instantiate the subclass
- exit_code = appctxt.run() # 5. Invoke run()
+ appctxt = ApplicationContext() # 1. Instantiate ApplicationContext
+ window = QMainWindow()
+ window.resize(250, 150)
+ window.show()
+ exit_code = appctxt.app.exec_() # 2. Invoke appctxt.app.exec_()
sys.exit(exit_code)
The example will show an empty `QMainWindow`, and you can execute it by running::
diff --git a/sources/pyside2/doc/deployment-pyinstaller.rst b/sources/pyside2/doc/deployment-pyinstaller.rst
index 8e6a76052..f361daf4a 100644
--- a/sources/pyside2/doc/deployment-pyinstaller.rst
+++ b/sources/pyside2/doc/deployment-pyinstaller.rst
@@ -122,3 +122,52 @@ an executable inside the `dist/` directory that you can execute::
cd dist/
./MyApplication
+
+
+Current Caveats To Be Aware Of
+==============================
+
+
+PyInstaller Problem
+-------------------
+
+As already mentioned, `PyInstaller` will pick a system installation of PySide2 or
+Shiboken2 instead of your virtualenv version without notice, if it exists.
+This may be no problem if those PySide2 or shiboken2 versions are the same.
+
+If you are working with different versions, this can result in frustrating sessions,
+when you think you are testing a new version, but `PyInstaller`
+is silently working with a different, older version.
+
+
+Problem with numpy in Python 2.7.16
+-----------------------------------
+
+A recent problem of PyInstaller is the appearance of Python 2.7.16 .
+This Python version creates a problem that is known from Python 3 as a `Tcl/Tk` problem.
+This does rarely show up in Python 3 because `Tcl/Tk` is seldom used with `PyInstaller.
+
+On Python 2.7.16, this problem is very much visible, since many people are using numpy.
+For some reason, installing `numpy` creates a dependency of `Tcl/Tk`, which can
+be circumvented only by explicitly excluding `Tcl/Tk` related things by adding
+this line to the analysis section of the spec-file::
+
+ excludes=['FixTk', 'tcl', 'tk', '_tkinter', 'tkinter', 'Tkinter'],
+
+
+Safety Instructions
+-------------------
+
+o When using `PyInstaller` with `virtualenv`, make sure that there is no system
+ installation of PySide2 or shiboken2.
+
+o Before compiling, use `pip -uninstall pyside2 shiboken2 -y` multiple times, until
+ none of the programs is found anymore.
+
+o Pip is usually a good tool. But to be 100 % sure, you should directly remove
+ the PySide2 and shiboken2 folders from site-packages.
+
+o Be sure to use the right version of pip. The safest way to really run the right
+ pip, use the Python that you mean: Instead of the pip command, better use::
+
+ <path/to/your/>python -m pip
diff --git a/sources/pyside2/doc/deployment.rst b/sources/pyside2/doc/deployment.rst
index 582e38992..a125dc4d7 100644
--- a/sources/pyside2/doc/deployment.rst
+++ b/sources/pyside2/doc/deployment.rst
@@ -12,6 +12,7 @@ The options for a project are:
3. Freezing the application in a single binary file, or into a directory.
For the **third** option, there are many available tools:
+ * `fbs <https://build-system.fman.io/>`_,
* `PyInstaller <https://www.pyinstaller.org/>`_,
* `cx_Freeze <https://anthony-tuininga.github.io/cx_Freeze/>`_,
* `py2exe <http://www.py2exe.org/>`_,
@@ -26,13 +27,14 @@ The following table summarizes the above mentioned tools support:
=========== ======= ===== ===== =======
Name License Linux macOS Windows
=========== ======= ===== ===== =======
+fbs GPL yes yes yes
+PyInstaller GPL yes yes yes
+cx_Freeze MIT yes yes yes
py2exe MIT no no yes
py2app MIT no yes no
-cx_Freeze MIT yes yes yes
-PyInstaller GPL yes yes yes
=========== ======= ===== ===== =======
-From the table we can see that only *cx_Freeze* and *PyInstaller*
+From the table we can see that only *fbs*, *cx_Freeze* and *PyInstaller*
meet our requirements.
All tools are command-line based, and it could become
@@ -65,6 +67,6 @@ described tools.
:name: mastertoc
:maxdepth: 2
+ deployment-fbs.rst
deployment-pyinstaller.rst
deployment-cxfreeze.rst
- deployment-fbs.rst
diff --git a/sources/shiboken2/libshiboken/basewrapper.cpp b/sources/shiboken2/libshiboken/basewrapper.cpp
index 6ea793a79..faaca5e4b 100644
--- a/sources/shiboken2/libshiboken/basewrapper.cpp
+++ b/sources/shiboken2/libshiboken/basewrapper.cpp
@@ -94,6 +94,92 @@ static PyType_Spec SbkObjectType_Type_spec = {
};
+#if PY_VERSION_HEX < 0x03000000
+/*****************************************************************************
+ *
+ * PYSIDE-816: Workaround for Python 2.7
+ *
+ * This is an add-on for function typeobject.c:tp_new_wrapper from Python 2.7 .
+ * Problem:
+ * In Python 3.X, tp_new_wrapper uses this check:
+
+ while (staticbase && (staticbase->tp_new == slot_tp_new))
+
+ * In Python 2.7, it uses this, instead:
+
+ while (staticbase && (staticbase->tp_flags & Py_TPFLAGS_HEAPTYPE))
+
+ * The problem is that heap types have this unwanted dependency.
+ * But we cannot get at static slot_tp_new, and so we have to use
+ * the original function and patch Py_TPFLAGS_HEAPTYPE away during the call.
+ */
+
+static PyCFunction old_tp_new_wrapper = nullptr;
+
+static PyObject *
+tp_new_wrapper(PyObject *self, PyObject *args, PyObject *kwds)
+{
+ PyTypeObject *type = reinterpret_cast<PyTypeObject *>(self);
+ Py_ssize_t orig_flags = type->tp_flags;
+ type->tp_flags &= ~Py_TPFLAGS_HEAPTYPE;
+ PyObject *ret = reinterpret_cast<ternaryfunc>(old_tp_new_wrapper)(self, args, kwds);
+ type->tp_flags = orig_flags;
+ return ret;
+}
+
+// This is intentionally the new docstring of Python 3.7 .
+static struct PyMethodDef tp_new_methoddef[] = {
+ {"__new__", (PyCFunction)tp_new_wrapper, METH_VARARGS|METH_KEYWORDS,
+ PyDoc_STR("__new__($type, *args, **kwargs)\n--\n\n"
+ "Create and return a new object. "
+ "See help(type) for accurate signature.")},
+ {0}
+};
+
+static int
+get_old_tp_new_wrapper(void)
+{
+ // We get the old tp_new_wrapper from any initialized type.
+ PyTypeObject *type = &PyType_Type;
+ PyObject *dict = type->tp_dict;
+ PyObject *key, *func = nullptr;
+ Py_ssize_t pos = 0;
+ while (PyDict_Next(dict, &pos, &key, &func)) {
+ char *name = PyString_AsString(key);
+ if (strcmp(name, "__new__") == 0) {
+ break;
+ }
+ }
+ if (func == nullptr)
+ return -1;
+ PyCFunctionObject *pycf_ob = reinterpret_cast<PyCFunctionObject *>(func);
+ old_tp_new_wrapper = pycf_ob->m_ml->ml_meth;
+ return 0;
+}
+
+static int
+add_tp_new_wrapper(PyTypeObject *type)
+{
+ // get the original tp_new_wrapper
+ if (old_tp_new_wrapper == nullptr && get_old_tp_new_wrapper() < 0)
+ return -1;
+ // initialize tp_dict
+ if (type->tp_dict == nullptr)
+ type->tp_dict = PyDict_New();
+ if (type->tp_dict == nullptr)
+ return -1;
+ PyObject *ob_type = reinterpret_cast<PyObject *>(type);
+ Shiboken::AutoDecRef func(PyCFunction_New(tp_new_methoddef, ob_type));
+ if (func.isNull())
+ return -1;
+ if (PyDict_SetItemString(type->tp_dict, "__new__", func))
+ return -1;
+ return 0;
+}
+/*****************************************************************************/
+#endif // PY_VERSION_HEX < 0x03000000
+
+
PyTypeObject *SbkObjectType_TypeF(void)
{
static PyTypeObject *type = nullptr;
@@ -102,13 +188,8 @@ PyTypeObject *SbkObjectType_TypeF(void)
PepHeapType_SIZE + sizeof(SbkObjectTypePrivate);
type = reinterpret_cast<PyTypeObject *>(PyType_FromSpec(&SbkObjectType_Type_spec));
#if PY_VERSION_HEX < 0x03000000
- // PYSIDE-816: Python 2.7 has a bad check for Py_TPFLAGS_HEAPTYPE in
- // typeobject.c func tp_new_wrapper. In Python 3 it was updated after
- // the transition to the new type API, but not in 2.7 . Fortunately,
- // the types did not change much when transitioning to heaptypes. We
- // pretend that this type is a normal type in 2.7 and hope that this
- // has no bad effect.
- type->tp_flags &= ~Py_TPFLAGS_HEAPTYPE;
+ if (add_tp_new_wrapper(type) < 0)
+ return nullptr;
#endif
}
return type;
@@ -299,10 +380,6 @@ void SbkObjectTypeDealloc(PyObject* pyObj)
SbkObjectTypePrivate *sotp = PepType_SOTP(pyObj);
PyTypeObject *type = reinterpret_cast<PyTypeObject*>(pyObj);
-#if PY_VERSION_HEX < 0x03000000
- // PYSIDE-816: Restore the heap type flag. Better safe than sorry.
- type->tp_flags |= Py_TPFLAGS_HEAPTYPE;
-#endif
PyObject_GC_UnTrack(pyObj);
#ifndef Py_LIMITED_API
Py_TRASHCAN_SAFE_BEGIN(pyObj);