diff options
52 files changed, 1757 insertions, 1477 deletions
diff --git a/dist/changes-5.12.2 b/dist/changes-5.12.2 index 39e845fb7..b45d38ca2 100644 --- a/dist/changes-5.12.2 +++ b/dist/changes-5.12.2 @@ -20,7 +20,7 @@ information about a particular change. - [PYSIDE-934] Added a method to VoidPtr called toBytes() to get the bytes representation. - [PYSIDE-95] Added ownership transfer for QGraphicsItemGroup.addToGroup - [PYSIDE-928][PYSIDE-937][PYSIDE-943] Fixing a refcounting bug shown by __doc__ handling - - [PYSIIDE-931] Added the attribute 'allow-thread' to the type system and class entries. + - [PYSIDE-931] Added the attribute 'allow-thread' to the type system and class entries. - [PYSIDE-947] Fixed conversions of list of smart pointers to python - [PYSIDE-953] Preventing Python 3.5 from crashing the build - [PYSIDE-940] Added setPageSize new signature to QPageSize @@ -46,3 +46,4 @@ information about a particular change. - Extended the exception handling test in shiboken - [PYSIDE-929] Added dependency version for shiboken2 - [PYSIDE-914] Including MSVC dlls in the shiboken module package + - [PYSIDE-932] Implement Embedding To Make Signatures Always Available diff --git a/examples/widgets/dialogs/standarddialogs.py b/examples/widgets/dialogs/standarddialogs.py index 872e08ed4..f61157e75 100644 --- a/examples/widgets/dialogs/standarddialogs.py +++ b/examples/widgets/dialogs/standarddialogs.py @@ -216,7 +216,7 @@ class Dialog(QtWidgets.QDialog): self.colorLabel.setAutoFillBackground(True) def setFont(self): - font, ok = QtWidgets.QFontDialog.getFont(QtGui.QFont(self.fontLabel.text()), self) + ok, font = QtWidgets.QFontDialog.getFont(QtGui.QFont(self.fontLabel.text()), self) if ok: self.fontLabel.setText(font.key()) self.fontLabel.setFont(font) diff --git a/sources/pyside2/PySide2/CMakeLists.txt b/sources/pyside2/PySide2/CMakeLists.txt index ea1a7de16..5a371b8a9 100644 --- a/sources/pyside2/PySide2/CMakeLists.txt +++ b/sources/pyside2/PySide2/CMakeLists.txt @@ -6,22 +6,6 @@ configure_file("${CMAKE_CURRENT_SOURCE_DIR}/global.h.in" configure_file("${CMAKE_CURRENT_SOURCE_DIR}/__init__.py.in" "${CMAKE_CURRENT_BINARY_DIR}/__init__.py" @ONLY) -configure_file("${CMAKE_CURRENT_SOURCE_DIR}/support/__init__.py" - "${CMAKE_CURRENT_BINARY_DIR}/support/__init__.py" COPYONLY) -configure_file("${CMAKE_CURRENT_SOURCE_DIR}/support/generate_pyi.py" - "${CMAKE_CURRENT_BINARY_DIR}/support/generate_pyi.py" COPYONLY) -configure_file("${CMAKE_CURRENT_SOURCE_DIR}/support/signature/__init__.py" - "${CMAKE_CURRENT_BINARY_DIR}/support/signature/__init__.py" COPYONLY) -configure_file("${CMAKE_CURRENT_SOURCE_DIR}/support/signature/layout.py" - "${CMAKE_CURRENT_BINARY_DIR}/support/signature/layout.py" COPYONLY) -configure_file("${CMAKE_CURRENT_SOURCE_DIR}/support/signature/mapping.py" - "${CMAKE_CURRENT_BINARY_DIR}/support/signature/mapping.py" COPYONLY) -configure_file("${CMAKE_CURRENT_SOURCE_DIR}/support/signature/typing.py" - "${CMAKE_CURRENT_BINARY_DIR}/support/signature/typing.py" COPYONLY) -configure_file("${CMAKE_CURRENT_SOURCE_DIR}/support/signature/lib/__init__.py" - "${CMAKE_CURRENT_BINARY_DIR}/support/signature/lib/__init__.py" COPYONLY) -configure_file("${CMAKE_CURRENT_SOURCE_DIR}/support/signature/lib/enum_sig.py" - "${CMAKE_CURRENT_BINARY_DIR}/support/signature/lib/enum_sig.py" COPYONLY) configure_file("${CMAKE_CURRENT_SOURCE_DIR}/_config.py.in" "${CMAKE_CURRENT_BINARY_DIR}/_config.py" @ONLY) diff --git a/sources/pyside2/PySide2/__init__.py.in b/sources/pyside2/PySide2/__init__.py.in index ac75f52b6..d896ab603 100644 --- a/sources/pyside2/PySide2/__init__.py.in +++ b/sources/pyside2/PySide2/__init__.py.in @@ -19,6 +19,8 @@ def _setupQtDirectories(): # loads the libraries into the process memory beforehand, and # thus takes care of it for us. import shiboken2 + # Trigger signature initialization. + type.__signature__ pyside_package_dir = os.path.abspath(os.path.dirname(__file__)) diff --git a/sources/pyside2/PySide2/support/generate_pyi.py b/sources/pyside2/PySide2/support/generate_pyi.py index a92ee76f0..3b4b3409a 100644 --- a/sources/pyside2/PySide2/support/generate_pyi.py +++ b/sources/pyside2/PySide2/support/generate_pyi.py @@ -55,6 +55,7 @@ import argparse import glob from contextlib import contextmanager from textwrap import dedent +import traceback import logging @@ -105,7 +106,7 @@ class Formatter(Writer): def module(self, mod_name): self.mod_name = mod_name self.print("# Module", mod_name) - self.print("import shiboken2 as Shiboken") + self.print("import PySide2") from PySide2.support.signature import typing self.print("from PySide2.support.signature import typing") self.print("from PySide2.support.signature.mapping import (") @@ -113,6 +114,7 @@ class Formatter(Writer): self.print() self.print("class Object(object): pass") self.print() + self.print("import shiboken2 as Shiboken") self.print("Shiboken.Object = Object") self.print() # This line will be replaced by the missing imports. @@ -254,7 +256,11 @@ def generate_pyi(import_name, outpath, options): logger.info("Generated: {outfilepath}".format(**locals())) if is_py3: # Python 3: We can check the file directly if the syntax is ok. - subprocess.check_output([sys.executable, outfilepath]) + try: + subprocess.check_output([sys.executable, outfilepath]) + except Exception as e: + print("+++ Problem executing test, although it works") + traceback.print_exc(file=sys.stdout) return 1 diff --git a/sources/pyside2/PySide2/support/signature/layout.py b/sources/pyside2/PySide2/support/signature/layout.py deleted file mode 100644 index c8a4062cb..000000000 --- a/sources/pyside2/PySide2/support/signature/layout.py +++ /dev/null @@ -1,42 +0,0 @@ -############################################################################# -## -## Copyright (C) 2018 The Qt Company Ltd. -## Contact: https://www.qt.io/licensing/ -## -## This file is part of Qt for Python. -## -## $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$ -## -############################################################################# - -from __future__ import print_function, absolute_import - -from signature_loader.layout import * diff --git a/sources/pyside2/PySide2/support/signature/lib/enum_sig.py b/sources/pyside2/PySide2/support/signature/lib/enum_sig.py deleted file mode 100644 index 1d19ad5e4..000000000 --- a/sources/pyside2/PySide2/support/signature/lib/enum_sig.py +++ /dev/null @@ -1,42 +0,0 @@ -############################################################################# -## -## Copyright (C) 2018 The Qt Company Ltd. -## Contact: https://www.qt.io/licensing/ -## -## This file is part of Qt for Python. -## -## $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$ -## -############################################################################# - -from __future__ import print_function, absolute_import - -from signature_loader.enum_sig import * diff --git a/sources/pyside2/doc/tutorials/index.rst b/sources/pyside2/doc/tutorials/index.rst index 8979f1a18..e394c4d24 100644 --- a/sources/pyside2/doc/tutorials/index.rst +++ b/sources/pyside2/doc/tutorials/index.rst @@ -29,3 +29,4 @@ Tutorials qmltutorial/index.rst qmladvancedtutorial/index.rst datavisualize/index.rst + qmlapp/qmlapplication.rst diff --git a/sources/pyside2/doc/tutorials/qmlapp/logo.png b/sources/pyside2/doc/tutorials/qmlapp/logo.png Binary files differnew file mode 100644 index 000000000..30c621c9c --- /dev/null +++ b/sources/pyside2/doc/tutorials/qmlapp/logo.png diff --git a/sources/pyside2/doc/tutorials/qmlapp/main.py b/sources/pyside2/doc/tutorials/qmlapp/main.py new file mode 100644 index 000000000..54edf0e37 --- /dev/null +++ b/sources/pyside2/doc/tutorials/qmlapp/main.py @@ -0,0 +1,82 @@ +############################################################################# +## +## 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$ +## +############################################################################# + +#!/usr/bin/env python +# -*- conding: utf-8 -*- + +import os, sys, urllib.request, json +import PySide2.QtQml +from PySide2.QtQuick import QQuickView +from PySide2.QtCore import QStringListModel, Qt, QUrl +from PySide2.QtGui import QGuiApplication + +if __name__ == '__main__': + + #get our data + url = "http://country.io/names.json" + response = urllib.request.urlopen(url) + data = json.loads(response.read().decode('utf-8')) + + #Format and sort the data + data_list = list(data.values()) + data_list.sort() + + #Set up the application window + app = QGuiApplication(sys.argv) + view = QQuickView() + view.setResizeMode(QQuickView.SizeRootObjectToView) + + #Expose the list to the Qml code + my_model = QStringListModel() + my_model.setStringList(data_list) + view.rootContext().setContextProperty("myModel",my_model) + + #Load the QML file + qml_file = os.path.join(os.path.dirname(__file__),"view.qml") + view.setSource(QUrl.fromLocalFile(os.path.abspath(qml_file))) + + #Show the window + if view.status() == QQuickView.Error: + sys.exit(-1) + view.show() + + #execute and cleanup + app.exec_() + del view diff --git a/sources/pyside2/doc/tutorials/qmlapp/newpyproject.png b/sources/pyside2/doc/tutorials/qmlapp/newpyproject.png Binary files differnew file mode 100644 index 000000000..93968a52d --- /dev/null +++ b/sources/pyside2/doc/tutorials/qmlapp/newpyproject.png diff --git a/sources/pyside2/doc/tutorials/qmlapp/projectsmode.png b/sources/pyside2/doc/tutorials/qmlapp/projectsmode.png Binary files differnew file mode 100644 index 000000000..c66d88723 --- /dev/null +++ b/sources/pyside2/doc/tutorials/qmlapp/projectsmode.png diff --git a/sources/pyside2/doc/tutorials/qmlapp/pyprojname.png b/sources/pyside2/doc/tutorials/qmlapp/pyprojname.png Binary files differnew file mode 100644 index 000000000..98328074d --- /dev/null +++ b/sources/pyside2/doc/tutorials/qmlapp/pyprojname.png diff --git a/sources/pyside2/doc/tutorials/qmlapp/pyprojxplor.png b/sources/pyside2/doc/tutorials/qmlapp/pyprojxplor.png Binary files differnew file mode 100644 index 000000000..e01e2ebeb --- /dev/null +++ b/sources/pyside2/doc/tutorials/qmlapp/pyprojxplor.png diff --git a/sources/pyside2/doc/tutorials/qmlapp/qmlapplication.png b/sources/pyside2/doc/tutorials/qmlapp/qmlapplication.png Binary files differnew file mode 100644 index 000000000..ec0ad3dea --- /dev/null +++ b/sources/pyside2/doc/tutorials/qmlapp/qmlapplication.png diff --git a/sources/pyside2/doc/tutorials/qmlapp/qmlapplication.rst b/sources/pyside2/doc/tutorials/qmlapp/qmlapplication.rst new file mode 100644 index 000000000..78bae94a8 --- /dev/null +++ b/sources/pyside2/doc/tutorials/qmlapp/qmlapplication.rst @@ -0,0 +1,133 @@ +######################### +QML Application Tutorial +######################### + +This tutorial provides a quick walk-through of a python application +that loads a QML file. QML is a declarative language that lets you +design UIs faster than a traditional language, such as C++. The +QtQml and QtQuick modules provides the necessary infrastructure for +QML-based UIs. + +In this tutorial, you'll also learn how to provide data from Python +as a QML context property, which is then consumed by the ListView +defined in the QML file. + +Before you begin, install the following prerequisites: + +* The `PySide2 <https://pypi.org/project/PySide2/>`_ Python packages. +* Qt Creator v4.9 beta1 or later from + `http://download.qt.io + <http://download.qt.io/snapshots/qtcreator/4.9/4.9.0-beta1/>`_. + + +The following step-by-step instructions guide you through application +development process using Qt Creator: + +#. Open Qt Creator and select **File > New File or Project..** menu item + to open following dialog: + + .. image:: newpyproject.png + +#. Select **Qt for Python - Empty** from the list of application templates + and select **Choose**. + + .. image:: pyprojname.png + +#. Give a **Name** to your project, choose its location in the + filesystem, and select **Finish** to create an empty ``main.py`` + and ``main.pyproject``. + + .. image:: pyprojxplor.png + + This should create a ``main.py`` and ```main.pyproject`` files + for the project. + +#. Download :download:`view.qml<view.qml>` and :download:`logo.png <logo.png>` + and move them to your project folder. + +#. Double-click on ``main.pyproject`` to open it in edit mode, and append + ``view.qml`` and ``logo.png`` to the **files** list. This is how your + project file should look after this change: + + .. code:: + + { + "files": ["main.py", "view.qml", "logo.png"] + } + +#. Now that you have the necessary bits for the application, import the + Python modules in your ``main.py``, and download country data and + format it: + + .. literalinclude:: main.py + :linenos: + :lines: 40-60 + :emphasize-lines: 12-20 + +#. Now, set up the application window using + :ref:`PySide2.QtGui.QGuiApplication<qguiapplication>`, which manages the application-wide + settings. + + .. literalinclude:: main.py + :linenos: + :lines: 40-65 + :emphasize-lines: 23-25 + + .. note:: Setting the resize policy is important if you want the + root item to resize itself to fit the window or vice-a-versa. + Otherwise, the root item will retain its original size on + resizing the window. + +#. You can now expose the ``data_list`` variable as a QML context + property, which will be consumed by the QML ListView item in ``view.qml``. + + .. literalinclude:: main.py + :linenos: + :lines: 40-70 + :emphasize-lines: 27-30 + +#. Load the ``view.qml`` to the ``QQuickView`` and call ``show()`` to + display the application window. + + .. literalinclude:: main.py + :linenos: + :lines: 40-79 + :emphasize-lines: 33-39 + +#. Finally, execute the application to start the event loop and clean up. + + .. literalinclude:: main.py + :linenos: + :lines: 40- + :emphasize-lines: 41-43 + +#. Your application is ready to be run now. Select **Projects** mode to + choose the Python version to run it. + + .. image:: projectsmode.png + +Run the application by using the ``CTRL+R`` keyboard shortcut to see if it +looks like this: + +.. image:: qmlapplication.png + +You could also watch the following video tutorial for guidance to develop +this application: + +.. raw:: html + + <div style="position: relative; padding-bottom: 56.25%; height: 0; + overflow: hidden; max-width: 100%; height: auto;"> + <iframe src="https://www.youtube.com/embed/JxfiUx60Mbg" frameborder="0" + allowfullscreen style="position: absolute; top: 0; left: 0; + width: 100%; height: 100%;"> + </iframe> + </div> + +******************** +Related information +******************** + +* `QML Reference <https://doc.qt.io/qt-5/qmlreference.html>`_ +* :doc:`../qmltutorial/index` +* :doc:`../qmladvancedtutorial/index` diff --git a/sources/pyside2/doc/tutorials/qmlapp/view.qml b/sources/pyside2/doc/tutorials/qmlapp/view.qml new file mode 100644 index 000000000..c75052b29 --- /dev/null +++ b/sources/pyside2/doc/tutorials/qmlapp/view.qml @@ -0,0 +1,102 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the examples of Qt for Python. +** +** $QT_BEGIN_LICENSE:BSD$ +** 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. +** +** BSD License Usage +** Alternatively, 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 QtQuick 2.12 +import QtQuick.Controls 2.12 + +Page { + width: 640 + height: 480 + + header: Label { + color: "#15af15" + text: qsTr("Where do people use Qt?") + font.pointSize: 17 + font.bold: true + font.family: "Arial" + renderType: Text.NativeRendering + horizontalAlignment: Text.AlignHCenter + padding: 10 + } + Rectangle { + id: root + width: parent.width + height: parent.height + + Image { + id: image + fillMode: Image.PreserveAspectFit + anchors.centerIn: root + source: "./logo.png" + opacity: 0.5 + + } + + ListView { + id: view + anchors.fill: root + anchors.margins: 25 + model: myModel + delegate: Text { + anchors.leftMargin: 50 + font.pointSize: 15 + horizontalAlignment: Text.AlignHCenter + text: display + } + } + } + NumberAnimation { + id: anim + running: true + target: view + property: "contentY" + duration: 500 + } +} diff --git a/sources/pyside2/tests/QtWidgets/signature_test.py b/sources/pyside2/tests/QtWidgets/signature_test.py index 15a9333b4..3a0114b07 100644 --- a/sources/pyside2/tests/QtWidgets/signature_test.py +++ b/sources/pyside2/tests/QtWidgets/signature_test.py @@ -42,7 +42,7 @@ from __future__ import print_function, absolute_import import unittest import PySide2.QtCore import PySide2.QtWidgets -from PySide2.support.signature import inspect +from shibokensupport.signature import inspect class PySideSignatureTest(unittest.TestCase): diff --git a/sources/pyside2/tests/pysidetest/CMakeLists.txt b/sources/pyside2/tests/pysidetest/CMakeLists.txt index 1b1baf39a..cb8ba04cf 100644 --- a/sources/pyside2/tests/pysidetest/CMakeLists.txt +++ b/sources/pyside2/tests/pysidetest/CMakeLists.txt @@ -140,3 +140,4 @@ PYSIDE_TEST(mixin_signal_slots_test.py) PYSIDE_TEST(signal_slot_warning.py) PYSIDE_TEST(all_modules_load_test.py) PYSIDE_TEST(qapp_like_a_macro_test.py) +PYSIDE_TEST(embedding_test.py) diff --git a/sources/pyside2/PySide2/support/signature/__init__.py b/sources/pyside2/tests/pysidetest/embedding_test.py index 5a87a814a..aa71360ca 100644 --- a/sources/pyside2/PySide2/support/signature/__init__.py +++ b/sources/pyside2/tests/pysidetest/embedding_test.py @@ -1,9 +1,9 @@ ############################################################################# ## -## Copyright (C) 2018 The Qt Company Ltd. +## Copyright (C) 2019 The Qt Company Ltd. ## Contact: https://www.qt.io/licensing/ ## -## This file is part of Qt for Python. +## This file is part of PySide2. ## ## $QT_BEGIN_LICENSE:LGPL$ ## Commercial License Usage @@ -37,10 +37,38 @@ ## ############################################################################# -from __future__ import print_function, absolute_import +import unittest -# Trigger initialization phase 2. -_ = type.__signature__ -from signature_loader import get_signature, inspect, typing +# This test tests the embedding feature of PySide. +# Normally, embedding is only used when necessary. +# By setting the variable "pyside_uses_embedding", +# we enforce usage of embedding. -__all__ = "get_signature inspect typing layout mapping lib".split() + +class EmbeddingTest(unittest.TestCase): + + # def test_pyside_normal(self): + # import sys + # self.assertFalse(hasattr(sys, "pyside_uses_embedding")) + # import PySide2 + # # everything has to be imported + # self.assertTrue("PySide2.support.signature" in sys.modules) + # # there should be a variale in sys, now (no idea if set) + # self.assertTrue(hasattr(sys, "pyside_uses_embedding")) + + # Unfortunately, I see no way how to shut things enough down + # to trigger a second initiatization. Therefore, only one test :-/ + def test_pyside_embedding(self): + import sys, os + self.assertFalse(hasattr(sys, "pyside_uses_embedding")) + sys.pyside_uses_embedding = "anything true" + import PySide2 + # everything has to be imported + self.assertTrue("PySide2.support.signature" in sys.modules) + self.assertEqual(sys.pyside_uses_embedding, True) + dn = os.path.dirname + name = os.path.basename(dn(dn(dn(PySide2.support.signature.__file__)))) + self.assertTrue(name.startswith("embedded.") and name.endswith(".zip")) + +if __name__ == '__main__': + unittest.main() diff --git a/sources/pyside2/tests/registry/existence_test.py b/sources/pyside2/tests/registry/existence_test.py index 83f9d79f9..62795f232 100644 --- a/sources/pyside2/tests/registry/existence_test.py +++ b/sources/pyside2/tests/registry/existence_test.py @@ -116,7 +116,9 @@ class TestSignaturesExists(unittest.TestCase): continue if key not in found_sigs: warn("missing key: '{}'".format(key)) - elif isinstance(value, list) and len(value) != len(found_sigs[key]): + elif isinstance(value, list) and len(value) > len(found_sigs[key]): + # We check that nothing got lost. But it is ok when an older + # registry file does not have all variants, yet! warn(msgMultiSignatureCount(key, found_sigs[key], value)) if is_ci and check_warnings(): raise RuntimeError("There are errors, see above.") @@ -132,7 +134,9 @@ class TestSignaturesExists(unittest.TestCase): continue if key not in found_sigs: warn("missing key: '{}'".format(key)) - elif isinstance(value, list) and len(value) != len(found_sigs[key]): + elif isinstance(value, list) and len(value) > len(found_sigs[key]): + # We check that nothing got lost. But it is ok when an older + # registry file does not have all variants, yet! warn(msgMultiSignatureCount(key, found_sigs[key], value)) self.assertTrue(check_warnings()) diff --git a/sources/pyside2/tests/registry/init_platform.py b/sources/pyside2/tests/registry/init_platform.py index a324c36a2..31e212287 100644 --- a/sources/pyside2/tests/registry/init_platform.py +++ b/sources/pyside2/tests/registry/init_platform.py @@ -139,7 +139,7 @@ for modname in "minimal sample other smart".split(): all_modules.append(modname) from PySide2.QtCore import __version__ -from PySide2.support.signature.lib.enum_sig import SimplifyingEnumerator +from shibokensupport.signature.lib.enum_sig import SimplifyingEnumerator is_py3 = sys.version_info[0] == 3 is_ci = os.environ.get("QTEST_ENVIRONMENT", "") == "ci" diff --git a/sources/shiboken2/generator/shiboken2/cppgenerator.cpp b/sources/shiboken2/generator/shiboken2/cppgenerator.cpp index 86a632e78..be9d426b5 100644 --- a/sources/shiboken2/generator/shiboken2/cppgenerator.cpp +++ b/sources/shiboken2/generator/shiboken2/cppgenerator.cpp @@ -68,12 +68,14 @@ static const char *typeNameOf(const T &t) size = lastStar - typeName + 1; } #else // g++, Clang: "QPaintDevice *" -> "P12QPaintDevice" - if (size > 2 && typeName[0] == 'P' && std::isdigit(typeName[1])) + if (size > 2 && typeName[0] == 'P' && std::isdigit(typeName[1])) { ++typeName; + --size; + } #endif char *result = new char[size + 1]; result[size] = '\0'; - strncpy(result, typeName, size); + memcpy(result, typeName, size); return result; } )CPP"; diff --git a/sources/shiboken2/generator/shiboken2/shibokengenerator.cpp b/sources/shiboken2/generator/shiboken2/shibokengenerator.cpp index ec0d466f7..c572a98d9 100644 --- a/sources/shiboken2/generator/shiboken2/shibokengenerator.cpp +++ b/sources/shiboken2/generator/shiboken2/shibokengenerator.cpp @@ -1491,6 +1491,9 @@ QString ShibokenGenerator::functionSignature(const AbstractMetaFunction *func, if (func->isConstant() && !(options & Generator::ExcludeMethodConst)) s << " const"; + if (func->exceptionSpecification() == ExceptionSpecification::NoExcept) + s << " noexcept"; + return result; } diff --git a/sources/shiboken2/libshiboken/CMakeLists.txt b/sources/shiboken2/libshiboken/CMakeLists.txt index 79f83ec73..7cbb22978 100644 --- a/sources/shiboken2/libshiboken/CMakeLists.txt +++ b/sources/shiboken2/libshiboken/CMakeLists.txt @@ -26,6 +26,16 @@ endif() configure_file("${CMAKE_CURRENT_SOURCE_DIR}/sbkversion.h.in" "${CMAKE_CURRENT_BINARY_DIR}/sbkversion.h" @ONLY) +configure_file("${CMAKE_CURRENT_SOURCE_DIR}/embed/signature_bootstrap.py" + "${CMAKE_CURRENT_BINARY_DIR}/embed/signature_bootstrap.py" @ONLY) + +add_custom_command( + OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/embed/signature_bootstrap.inc" + OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/embed/signature.inc" + COMMAND ${PYTHON_EXECUTABLE} -E + "${CMAKE_CURRENT_SOURCE_DIR}/embed/embedding_generator.py" + --cmake-dir "${CMAKE_CURRENT_BINARY_DIR}/embed" + --limited-api ${PYTHON_LIMITED_API}) set(libshiboken_MAJOR_VERSION ${shiboken_MAJOR_VERSION}) set(libshiboken_MINOR_VERSION ${shiboken_MINOR_VERSION}) @@ -52,6 +62,8 @@ pep384impl.cpp voidptr.cpp typespec.cpp bufferprocs_py37.cpp +embed/signature_bootstrap.inc +embed/signature.inc ) get_numpy_location() diff --git a/sources/shiboken2/libshiboken/embed/embedding_generator.py b/sources/shiboken2/libshiboken/embed/embedding_generator.py new file mode 100644 index 000000000..3ee96a1a5 --- /dev/null +++ b/sources/shiboken2/libshiboken/embed/embedding_generator.py @@ -0,0 +1,241 @@ +############################################################################# +## +## Copyright (C) 2019 The Qt Company Ltd. +## Contact: https://www.qt.io/licensing/ +## +## This file is part of PySide2. +## +## $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$ +## +############################################################################# + +""" +embedding_generator.py + +This file takes the content of the two supported directories and inserts +it into a zip file. The zip file is then converted into a C++ source +file that can easily be unpacked again with Python (see signature.cpp, +constant 'PySide_PythonCode'). + +Note that this _is_ a zipfile, but since it is embedded into the shiboken +binary, we cannot use the zipimport module from Python. +But a similar solution is possible that allows for normal imports. + +See signature_bootstrap.py for details. +""" + +from __future__ import print_function, absolute_import + +import sys +import os +import subprocess +import textwrap +import tempfile +import argparse +import marshal +import traceback + +# work_dir is set to the source for testing, onl. +# It can be overridden in the command line. +work_dir = os.path.abspath(os.path.dirname(__file__)) +embed_dir = work_dir +cur_dir = os.getcwd() +source_dir = os.path.normpath(os.path.join(work_dir, "..", "..", "..")) +assert os.path.basename(source_dir) == "sources" +build_script_dir = os.path.normpath(os.path.join(work_dir, "..", "..", "..", "..")) +assert os.path.exists(os.path.join(build_script_dir, "build_scripts")) + +sys.path.insert(0, build_script_dir) + +from build_scripts import utils + + +def runpy(cmd, **kw): + subprocess.call([sys.executable, '-E'] + cmd.split(), **kw) + + +def create_zipfile(limited_api): + """ + Collect all Python files, compile them, create a zip file + and make a chunked base64 encoded file from it. + """ + zip_name = "signature.zip" + inc_name = "signature.inc" + flag = '-b' if sys.version_info >= (3,) else '' + os.chdir(work_dir) + + # Limited API: Remove all left-over py[co] files first, in case we use '--reuse-build'. + # Note that we could improve that with the PyZipfile function to use .pyc files + # in different folders, but that makes only sense when COIN allows us to have + # multiple Python versions in parallel. + from os.path import join, getsize + for root, dirs, files in os.walk(work_dir): + for name in files: + fpath = os.path.join(root, name) + if name.endswith(".pyc") or name.endswith(".pyo"): + os.remove(fpath) + + # We copy every Python file into this dir, but only for the right version. + # For testing in the source dir, we need to filter. + if sys.version_info[0] == 3: + ignore = "backport_inspect.py typing27.py".split() + else: + ignore = "".split() + utils.copydir(os.path.join(source_dir, "shiboken2", "shibokenmodule", "files.dir", "shibokensupport"), + os.path.join(work_dir, "shibokensupport"), + ignore=ignore, file_filter_function=lambda name, n2: name.endswith(".py")) + if embed_dir != work_dir: + utils.copyfile(os.path.join(embed_dir, "signature_bootstrap.py"), work_dir) + + if limited_api: + pass # We cannot compile, unless we have folders per Python version + else: + files = ' '.join(fn for fn in os.listdir('.')) + runpy('-m compileall -q {flag} {files}'.format(**locals())) + files = ' '.join(fn for fn in os.listdir('.') if not fn == zip_name) + runpy('-m zipfile -c {zip_name} {files}'.format(**locals())) + tmp = tempfile.TemporaryFile(mode="w+") + runpy('-m base64 {zip_name}'.format(**locals()), stdout=tmp) + # now generate the include file + tmp.seek(0) + with open(inc_name, "w") as inc: + _embed_file(tmp, inc) + # 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", "w") as inc: + _embed_bytefile(ldr, inc, limited_api) + os.chdir(cur_dir) + + +def _embed_file(fin, fout): + """ + Format a text file for embedding in a C++ source file. + """ + # MSVC has a 64k string limitation. In C, it would be easy to create an + # array of 64 byte strings and use them as one big array. In C++ this does + # not work, since C++ insists in having the terminating nullbyte. + # Therefore, we split the string after an arbitrary number of lines + # (chunked file). + limit = 50 + text = fin.readlines() + print(textwrap.dedent(""" + /* + * This is a ZIP archive of all Python files in the directory + * "shiboken2/shibokenmodule/files.dir/shibokensupport/signature" + * There is also a toplevel file "signature_bootstrap.py[c]" that will be + * directly executed from C++ as a bootstrap loader. + */ + """).strip(), file=fout) + block, blocks = 0, len(text) // limit + 1 + for idx, line in enumerate(text): + if idx % limit == 0: + comma = "," if block else "" + block += 1 + print(file=fout) + print('/* Block {block} of {blocks} */{comma}'.format(**locals()), file=fout) + print('\"{}\"'.format(line.strip()), file=fout) + print('/* Sentinel */, \"\"', file=fout) + + +def _embed_bytefile(fin, fout, is_text): + """ + Format a binary file for embedding in a C++ source file. + This version works directly with a single .pyc file. + """ + fname = fin.name + remark = ("No .pyc file because '--LIMITED-API=yes'" if is_text else + "The .pyc header is stripped away") + print(textwrap.dedent(""" + /* + * This is the file "{fname}" as a simple byte array. + * It can be directly embedded without any further processing. + * {remark}. + */ + """).format(**locals()).strip(), file=fout) + headsize = ( 0 if is_text else + 16 if sys.version_info >= (3, 7) else 12 if sys.version_info >= (3, 3) else 8) + binstr = fin.read()[headsize:] + if is_text: + try: + compile(binstr, fin.name, "exec") + except SyntaxError as e: + print(e) + traceback.print_exc(file=sys.stdout) + print(textwrap.dedent(""" + ************************************************************************* + *** + *** Could not compile the boot loader '{fname}'! + *** + ************************************************************************* + """).format(version=sys.version_info[:3], **locals())) + raise SystemError + else: + try: + marshal.loads(binstr) + except ValueError as e: + print(e) + traceback.print_exc(file=sys.stdout) + print(textwrap.dedent(""" + ************************************************************************* + *** + *** This Python version {version} seems to have a new .pyc header size. + *** Please correct the 'headsize' constant ({headsize}). + *** + ************************************************************************* + """).format(version=sys.version_info[:3], **locals())) + raise SystemError + + print(file=fout) + use_ord = sys.version_info[0] == 2 + for i in range(0, len(binstr), 16): + for c in bytes(binstr[i : i + 16]): + print("{:#4},".format(ord(c) if use_ord else c), file=fout, end="") + print(file=fout) + print("/* End Of File */", file=fout) + + +def str2bool(v): + if v.lower() in ('yes', 'true', 't', 'y', '1'): + return True + elif v.lower() in ('no', 'false', 'f', 'n', '0'): + return False + else: + raise argparse.ArgumentTypeError('Boolean value expected.') + + +if __name__ == "__main__": + parser = argparse.ArgumentParser() + parser.add_argument('--cmake-dir', nargs="?") + parser.add_argument('--limited-api', type=str2bool) + args = parser.parse_args() + if args.cmake_dir: + work_dir = os.path.abspath(args.cmake_dir) + create_zipfile(args.limited_api) diff --git a/sources/shiboken2/libshiboken/embed/module_collector.py b/sources/shiboken2/libshiboken/embed/module_collector.py new file mode 100644 index 000000000..3eaa0be5d --- /dev/null +++ b/sources/shiboken2/libshiboken/embed/module_collector.py @@ -0,0 +1,105 @@ +# This Python file uses the following encoding: utf-8 +# It has been edited by fix-complaints.py . + +############################################################################# +## +## Copyright (C) 2019 The Qt Company Ltd. +## Contact: https://www.qt.io/licensing/ +## +## This file is part of Qt for Python. +## +## $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$ +## +############################################################################# + +""" +module_collector.py + +Collect a number of modules listed on the command line. + +The purpose of this script is to generate the scripts needed for +a complete isolation of the signature extension. + +Usage: + +Run this script in one of the used python versions. +It will create an executable archive of the files on the command line. +""" + +import sys +import os +import argparse +import pickle +from textwrap import dedent + +def source_archive(module, modname): + fname = os.path.splitext(module.__file__)[0] + ".py" + with open(fname) as source: + text = source.read() + encoded = text.replace("'''", "(triple_single)") + # modname = module.__name__ + # Do not use: Some modules rename themselves! + version = ".".join(map(str, sys.version_info[:3])) + shortname = os.path.basename(fname) + preamble = dedent(r""" + # BEGIN SOURCE ARCHIVE Python {version} module {modname} + + sources = {{}} if "sources" not in globals() else sources + sources["{modname}"] = '''\ + {encoded}'''.replace("(triple_single)", "'''") + + # END SOURCE ARCHIVE Python {version} module {modname} + """).format(**locals()) + return preamble + +def read_all(modules): + collected = "" + for modname in modules: + mod = __import__(modname) + collected += source_archive(mod, modname) + return collected + +def license_header(): + license = os.path.join(os.path.dirname(__file__), "qt_python_license.txt") + with open(license) as f: + return f.read() + +if __name__ == "__main__": + parser = argparse.ArgumentParser() + parser.add_argument('modules', nargs="+") + args = parser.parse_args() + print("modules:", args.modules) + ret = license_header() + read_all(args.modules) + ma_mi = "_".join(map(str, sys.version_info[:2])) + outpath = os.path.join(os.path.dirname(__file__), "..", "..", "shibokenmodule", + "files.dir", "shibokensupport", "python_minilib_{ma_mi}.py".format(**locals())) + with open(outpath, "w") as f: + f.write(ret) diff --git a/sources/shiboken2/libshiboken/embed/qt_python_license.txt b/sources/shiboken2/libshiboken/embed/qt_python_license.txt new file mode 100644 index 000000000..b5f8c581a --- /dev/null +++ b/sources/shiboken2/libshiboken/embed/qt_python_license.txt @@ -0,0 +1,87 @@ +# This Python file uses the following encoding: utf-8 +# It has been edited by fix-complaints.py . + +############################################################################# +## +## Copyright (C) 2019 The Qt Company Ltd. +## Contact: https://www.qt.io/licensing/ +## +## This file is part of Qt for Python. +## +## $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$ +## +############################################################################# + +## +## PSF LICENSE AGREEMENT FOR PYTHON 3.7.0 +## +## 1. This LICENSE AGREEMENT is between the Python Software Foundation ("PSF"), and +## the Individual or Organization ("Licensee") accessing and otherwise using Python +## 3.7.0 software in source or binary form and its associated documentation. +## +## 2. Subject to the terms and conditions of this License Agreement, PSF hereby +## grants Licensee a nonexclusive, royalty-free, world-wide license to reproduce, +## analyze, test, perform and/or display publicly, prepare derivative works, +## distribute, and otherwise use Python 3.7.0 alone or in any derivative +## version, provided, however, that PSF's License Agreement and PSF's notice of +## copyright, i.e., "Copyright © 2001-2018 Python Software Foundation; All Rights +## Reserved" are retained in Python 3.7.0 alone or in any derivative version +## prepared by Licensee. +## +## 3. In the event Licensee prepares a derivative work that is based on or +## incorporates Python 3.7.0 or any part thereof, and wants to make the +## derivative work available to others as provided herein, then Licensee hereby +## agrees to include in any such work a brief summary of the changes made to Python +## 3.7.0. +## +## 4. PSF is making Python 3.7.0 available to Licensee on an "AS IS" basis. +## PSF MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED. BY WAY OF +## EXAMPLE, BUT NOT LIMITATION, PSF MAKES NO AND DISCLAIMS ANY REPRESENTATION OR +## WARRANTY OF MERCHANTABILITY OR FITNESS FOR ANY PARTICULAR PURPOSE OR THAT THE +## USE OF PYTHON 3.7.0 WILL NOT INFRINGE ANY THIRD PARTY RIGHTS. +## +## 5. PSF SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF PYTHON 3.7.0 +## FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS AS A RESULT OF +## MODIFYING, DISTRIBUTING, OR OTHERWISE USING PYTHON 3.7.0, OR ANY DERIVATIVE +## THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF. +## +## 6. This License Agreement will automatically terminate upon a material breach of +## its terms and conditions. +## +## 7. Nothing in this License Agreement shall be deemed to create any relationship +## of agency, partnership, or joint venture between PSF and Licensee. This License +## Agreement does not grant permission to use PSF trademarks or trade name in a +## trademark sense to endorse or promote products or services of Licensee, or any +## third party. +## +## 8. By copying, installing or otherwise using Python 3.7.0, Licensee agrees +## to be bound by the terms and conditions of this License Agreement. +## diff --git a/sources/shiboken2/libshiboken/embed/signature_bootstrap.py b/sources/shiboken2/libshiboken/embed/signature_bootstrap.py new file mode 100644 index 000000000..eb182d8c4 --- /dev/null +++ b/sources/shiboken2/libshiboken/embed/signature_bootstrap.py @@ -0,0 +1,180 @@ +############################################################################# +## +## Copyright (C) 2019 The Qt Company Ltd. +## Contact: https://www.qt.io/licensing/ +## +## This file is part of PySide2. +## +## $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$ +## +############################################################################# + +""" +signature_bootstrap.py +---------------------- + +This file was originally directly embedded into the C source. +After it grew more and more, I now prefer to have it as Python file. + +Meanwhile, there is also no more a stub loader necessary: +Because we meanwhile have embedding support, we could also load this file +directly from a .pyc file. + +This file replaces the hard to read Python stub in 'signature.cpp', and we +could distinguish better between bootstrap related functions and loader +functions. +It is embedded into 'signature.cpp' as "embed/signature_bootstrap.inc". +""" + +from __future__ import print_function, absolute_import + +recursion_trap = 0 + +# We avoid real imports in phase 1 that could fail (simply removed all). +# Python 2 is not able to import when the extension import is still active. +# Phase 1 simply defines the functions, which will be used in Phase 2. + +def bootstrap(): + import sys + import os + import tempfile + import traceback + from contextlib import contextmanager + + global recursion_trap + if recursion_trap: + # we are probably called from outside, already + print("Recursion occurred in Bootstrap. Did you start by hand? Then it's ok.") + print("But you should trigger start by 'type.__signature__', only!") + recursion_trap += 1 + + @contextmanager + def ensure_shibokensupport(support_path): + # Make sure that we always have the shibokensupport containing package first. + # Also remove any prior loaded module of this name, just in case. + sys.path.insert(0, support_path) + + sbks = "shibokensupport" + if sbks in sys.modules: + del sys.modules[sbks] + prefix = sbks + "." + for key in list(key for key in sys.modules if key.startswith(prefix)): + del sys.modules[key] + try: + import shibokensupport + yield + except Exception as e: + print("Problem importing shibokensupport:") + print(e) + traceback.print_exc() + print("sys.path:") + for p in sys.path: + print(" " + p) + sys.stdout.flush() + sys.exit(-1) + sys.path.remove(support_path) + + try: + import shiboken2 as root + except ImportError: + # uninstalled case without ctest, try only this one which has __init__: + import shibokenmodule as root + rp = os.path.realpath(os.path.dirname(root.__file__)) + # This can be the shiboken2 directory or the binary module, so search. + look_for = os.path.join("files.dir", "shibokensupport", "signature", "loader.py") + while len(rp) > 3 and not os.path.exists(os.path.join(rp, look_for)): + rp = os.path.abspath(os.path.join(rp, "..")) + + # Here we decide if we work embedded or not. + embedding_var = "pyside_uses_embedding" + use_embedding = bool(getattr(sys, embedding_var, False)) + # We keep the zip file for inspection if the sys variable has been set. + keep_zipfile = hasattr(sys, embedding_var) + loader_path = os.path.join(rp, look_for) + files_dir = os.path.abspath(os.path.join(loader_path, "..", "..", "..")) + assert files_dir.endswith("files.dir") + + # We report in sys what we used. We could put more here as well. + if not os.path.exists(loader_path): + use_embedding = True + support_path = prepare_zipfile() if use_embedding else files_dir + setattr(sys, embedding_var, use_embedding) + + try: + with ensure_shibokensupport(support_path): + from shibokensupport.signature import loader + + except Exception as e: + print('Exception:', e) + traceback.print_exc(file=sys.stdout) + + finally: + if use_embedding and not keep_zipfile: + # clear the temp zipfile + try: + os.remove(support_path) + except OSError as e: + print(e) + print("Error deleting {support_path}, ignored".format(**locals())) + return loader + +# New functionality: Loading from a zip archive. +# There exists the zip importer, but as it is written, only real zip files are +# supported. Before I will start an own implementation, it is easiest to use +# a temporary zip file. + +def prepare_zipfile(): + """ + Write the zip file to a real file and return its name. + It will be implicitly opened as such when we add the name to sys.path . + """ + import base64 + import tempfile + import os + import zipfile + + # 'zipstring_sequence' comes from signature.cpp + zipbytes = base64.b64decode(''.join(zipstring_sequence)) + fd, fname = tempfile.mkstemp(prefix='embedded.', suffix='.zip') + os.write(fd, zipbytes) + os.close(fd) + # Let us test the zipfile if it really is one. + # Otherwise, zipimporter would simply ignore it without notice. + try: + z = zipfile.ZipFile(fname) + z.close() + except zipfile.BadZipFile as e: + print('Broken Zip File:', e) + traceback.print_exc(file=sys.stdout) + finally: + return fname + +# eof diff --git a/sources/shiboken2/libshiboken/signature.cpp b/sources/shiboken2/libshiboken/signature.cpp index cd00a1482..dea4c9b09 100644 --- a/sources/shiboken2/libshiboken/signature.cpp +++ b/sources/shiboken2/libshiboken/signature.cpp @@ -92,11 +92,6 @@ static PyObject *PySide_BuildSignatureProps(PyObject *class_mod); static void init_module_1(void); static void init_module_2(void); -const char helper_module_name[] = "signature_loader"; -const char bootstrap_name[] = "bootstrap"; -const char arg_name[] = "pyside_arg_dict"; -const char func_name[] = "pyside_type_init"; - static PyObject * CreateSignature(PyObject *props, PyObject *key) { @@ -423,74 +418,101 @@ GetSignature_Cached(PyObject *props, const char *sig_kind, const char *modifier) return Py_INCREF(value), value; } -static const char PySide_PythonCode[] = - "from __future__ import print_function, absolute_import\n" R"~(if True: - - # This is becoming the 'signature_loader' module. - - import sys, os, traceback - # We avoid imports in phase 1 that could fail. "import shiboken" of the - # binary would even crash in FinishSignatureInitialization. - - def bootstrap(): - global __file__ - try: - import shiboken2 as root - except ImportError: - # uninstalled case without ctest, try only this one which has __init__: - from shibokenmodule import shiboken2 as root - rp = os.path.realpath(os.path.dirname(root.__file__)) - # This can be the shiboken2 directory or the binary module, so search. - while len(rp) > 3 and not os.path.exists(os.path.join(rp, 'support')): - rp = os.path.abspath(os.path.join(rp, '..')) - __file__ = os.path.join(rp, 'support', 'signature', 'loader.py') - try: - with open(__file__) as _f: - exec(compile(_f.read(), __file__, 'exec')) - except Exception as e: - try: - from shiboken2.support.signature import loader - except: - print('Exception:', e) - traceback.print_exc(file=sys.stdout) - globals().update(locals()) - - )~"; +static const char *PySide_CompressedSignaturePackage[] = { +#include "embed/signature.inc" + }; + +static const unsigned char PySide_SignatureLoader[] = { +#include "embed/signature_bootstrap.inc" + }; static safe_globals_struc * init_phase_1(void) { - PyObject *d, *v; - safe_globals_struc *p = (safe_globals_struc *) - malloc(sizeof(safe_globals_struc)); - if (p == NULL) - goto error; - p->helper_module = PyImport_AddModule((char *) helper_module_name); - if (p->helper_module == NULL) - goto error; - - // Initialize the module - d = PyModule_GetDict(p->helper_module); - if (PyDict_SetItemString(d, "__builtins__", PyEval_GetBuiltins()) < 0) - goto error; - v = PyRun_String(PySide_PythonCode, Py_file_input, d, d); - if (v == NULL) - goto error; - Py_DECREF(v); - - // build a dict for diverse mappings - p->map_dict = PyDict_New(); - if (p->map_dict == NULL) - goto error; - - // build a dict for the prepared arguments - p->arg_dict = PyDict_New(); - if (p->arg_dict == NULL - || PyObject_SetAttrString(p->helper_module, arg_name, p->arg_dict) < 0) - goto error; - return p; + { + safe_globals_struc *p = (safe_globals_struc *) + malloc(sizeof(safe_globals_struc)); + if (p == NULL) + goto error; + /* + * Initializing module signature_bootstrap. + * Since we now have an embedding script, we can do this without any + * Python strings in the C code. + */ +#ifdef Py_LIMITED_API + // We must work for multiple versions, so use source code. +#else + Shiboken::AutoDecRef marshal_str(Py_BuildValue("s", "marshal")); + if (marshal_str.isNull()) + goto error; + Shiboken::AutoDecRef marshal_module(PyImport_Import(marshal_str)); + if (marshal_module.isNull()) + goto error; + Shiboken::AutoDecRef loads(PyObject_GetAttrString(marshal_module, "loads")); + if (loads.isNull()) + goto error; +#endif + char *bytes_cast = reinterpret_cast<char *>( + const_cast<unsigned char *>(PySide_SignatureLoader)); + Shiboken::AutoDecRef bytes(PyBytes_FromStringAndSize(bytes_cast, + sizeof(PySide_SignatureLoader))); + if (bytes.isNull()) + goto error; +#ifdef Py_LIMITED_API + PyObject *builtins = PyEval_GetBuiltins(); + PyObject *compile = PyDict_GetItemString(builtins, "compile"); + if (compile == nullptr) + goto error; + Shiboken::AutoDecRef code_obj(PyObject_CallFunction(compile, "Oss", + bytes.object(), "(builtin)", "exec")); +#else + Shiboken::AutoDecRef code_obj(PyObject_CallFunctionObjArgs( + loads, bytes.object(), nullptr)); +#endif + if (code_obj.isNull()) + goto error; + p->helper_module = PyImport_ExecCodeModule(const_cast<char *> + ("signature_bootstrap"), code_obj); + if (p->helper_module == nullptr) + goto error; + // Initialize the module + PyObject *mdict = PyModule_GetDict(p->helper_module); + if (PyDict_SetItemString(mdict, "__builtins__", PyEval_GetBuiltins()) < 0) + goto error; + + /* + * Unpack an embedded ZIP file with more signature modules. + * They will be loaded later with the zipimporter. + * Due to MSVC's limitation to 64k strings, we need to assemble pieces. + */ + const char **block_ptr = (const char **)PySide_CompressedSignaturePackage; + int npieces = 0; + PyObject *piece, *zipped_string_sequence = PyList_New(0); + for (; **block_ptr != 0; ++block_ptr) { + npieces++; + // we avoid the string/unicode dilemma by not using PyString_XXX: + piece = Py_BuildValue("s", *block_ptr); + if (piece == NULL || PyList_Append(zipped_string_sequence, piece) < 0) + goto error; + } + if (PyDict_SetItemString(mdict, "zipstring_sequence", zipped_string_sequence) < 0) + goto error; + Py_DECREF(zipped_string_sequence); + + // build a dict for diverse mappings + p->map_dict = PyDict_New(); + if (p->map_dict == NULL) + goto error; + // build a dict for the prepared arguments + p->arg_dict = PyDict_New(); + if (p->arg_dict == NULL + || PyObject_SetAttrString(p->helper_module, "pyside_arg_dict", p->arg_dict) < 0) + goto error; + return p; + } error: + PyErr_Print(); PyErr_SetString(PyExc_SystemError, "could not initialize part 1"); return NULL; } @@ -498,38 +520,40 @@ error: static int init_phase_2(safe_globals_struc *p, PyMethodDef *methods) { - PyObject *bootstrap_func, *v = nullptr; - PyMethodDef *ml; - - // The single function to be called, but maybe more to come. - for (ml = methods; ml->ml_name != NULL; ml++) { - v = PyCFunction_NewEx(ml, nullptr, nullptr); - if (v == nullptr - || PyObject_SetAttrString(p->helper_module, ml->ml_name, v) != 0) + { + PyMethodDef *ml; + + // The single function to be called, but maybe more to come. + for (ml = methods; ml->ml_name != NULL; ml++) { + PyObject *v = PyCFunction_NewEx(ml, nullptr, nullptr); + if (v == nullptr + || PyObject_SetAttrString(p->helper_module, ml->ml_name, v) != 0) + goto error; + Py_DECREF(v); + } + PyObject *bootstrap_func = PyObject_GetAttrString(p->helper_module, "bootstrap"); + if (bootstrap_func == NULL) goto error; - Py_DECREF(v); + // The return value of the bootstrap function is the loader module. + PyObject *loader = PyObject_CallFunction(bootstrap_func, (char *)"()"); + if (loader == nullptr) + goto error; + // now the loader should be initialized + p->sigparse_func = PyObject_GetAttrString(loader, "pyside_type_init"); + if (p->sigparse_func == NULL) + goto error; + p->createsig_func = PyObject_GetAttrString(loader, "create_signature"); + if (p->createsig_func == NULL) + goto error; + p->seterror_argument_func = PyObject_GetAttrString(loader, "seterror_argument"); + if (p->seterror_argument_func == NULL) + goto error; + p->make_helptext_func = PyObject_GetAttrString(loader, "make_helptext"); + if (p->make_helptext_func == NULL) + goto error; + return 0; } - bootstrap_func = PyObject_GetAttrString(p->helper_module, bootstrap_name); - if (bootstrap_func == NULL - || PyObject_CallFunction(bootstrap_func, (char *)"()") == NULL) - goto error; - // now the loader should be initialized - p->sigparse_func = PyObject_GetAttrString(p->helper_module, func_name); - if (p->sigparse_func == NULL) - goto error; - p->createsig_func = PyObject_GetAttrString(p->helper_module, "create_signature"); - if (p->createsig_func == NULL) - goto error; - p->seterror_argument_func = PyObject_GetAttrString(p->helper_module, "seterror_argument"); - if (p->seterror_argument_func == NULL) - goto error; - p->make_helptext_func = PyObject_GetAttrString(p->helper_module, "make_helptext"); - if (p->make_helptext_func == NULL) - goto error; - return 0; - error: - Py_XDECREF(v); PyErr_Print(); PyErr_SetString(PyExc_SystemError, "could not initialize part 2"); return -1; diff --git a/sources/shiboken2/libshiboken/signature_doc.rst b/sources/shiboken2/libshiboken/signature_doc.rst index f51649b5b..9c42c5976 100644 --- a/sources/shiboken2/libshiboken/signature_doc.rst +++ b/sources/shiboken2/libshiboken/signature_doc.rst @@ -50,7 +50,7 @@ result of the ``__signature__`` attribute of the real ``PyCFunction`` object. There is one thing that really changes Python a bit: -* I added the ``__signature__`` attribute to every function. +* We added the ``__signature__`` attribute to every function. That is a little change to Python that does not harm, but it saves us tons of code, that was needed in the early versions of the module. @@ -59,9 +59,9 @@ The internal work is done in two steps: * All functions of a class get the *signature text* when the module is imported. This is only a very small overhead added to the startup time. It is a single - string for the whole class. + string for each whole class. * The actual signature object is created later, when the attribute is really - accessed. Signatures are cached and only created on first access. + requested. Signatures are cached and only created on first access. Example: @@ -76,10 +76,12 @@ Why this Code is Fast It costs a little time (maybe 4 seconds) to run througs every single signature object, since these are more than 15000 Python objects. But all the signature objects will be rarely accessed but in special applications. -The normal case are only a few accesses, and these work pretty fast. +The normal case are only a few accesses, and these are working pretty fast. The key to make this signature module fast is to avoid computation as much as -possible. When no signature objects are used, then no time is lost in initialization. +possible. When no signature objects are used, then almost no time is lost in +initialization. Only the above mentioned strings and some support modules are +additionally loaded on ``import PySide2``. When it comes to signature usage, then late initialization is used and cached. This technique is also known as *full laziness* in haskell. @@ -107,15 +109,27 @@ The C++ code involved with the signature module is completely in the file shiboken2/libshiboken/signature.cpp . All other functionality is implemented in the ``signature`` Python package. It has the following structure:: - pyside2/PySide2/support/signature/__init__.py - loader.py - parser.py - mapping.py - typing27.py - backport_inspect.py + shiboken2/files.dir/shibokensupport/ + backport_inspect.py + python_minilib_2_7.py + python_minilib_3_5.py + python_minilib_3_6.py + python_minilib_3_7.py -Really important are the **parser**, **mapping** and **loader** modules. The rest is -needed to create Python 2 compatibility. + signature/ + loader.py + parser.py + mapping.py + errorhandler.py + layout.py + + lib/ + enum_sig.py + + +Really important are the **parser**, **mapping**, **errorhandler**, **enum_sig**, +**layout** and **loader** modules. The rest is needed to create Python 2 compatibility +or be compatible with embedding and installers. loader.py @@ -143,6 +157,34 @@ needs. A lot of mappings are resolved by rather complex expressions in ``parser. but a few hundred cases are better to spell explicitly, here. +errorhandler.py +~~~~~~~~~~~~~~~ + +Since ``Qt For Python 5.12``, we no longer use the builtin type error messages from C++. +Instead, we get much better results with the signature module. At the same time, +this enforced supporting shiboken as well, and the signature module was no longer +optional. + + +enum_sig.py +~~~~~~~~~~~ + +The diverse applications of the signature module all needed to iterate over modules, +classes and functions. In order to centralize this enumeration, the process has +been factored out as a context manager. The user has only to supply functions +that do the actual formatting. + +See for example the .pyi generator ``pyside2/PySide2/support/generate_pyi.py``. + + +layout.py +~~~~~~~~~ + +As more applications used the signature module, different formatting of signatures +was needed. To support that, we created the function ``create_signature``, which +has a parameter to choose from some prefefined layouts. + + *typing27.py* ~~~~~~~~~~~~~ @@ -276,19 +318,21 @@ This serves as an extra challenge that has a very positive effect on the completeness and correctness of signatures. -Future Extension ----------------- +Current Extensions +------------------ Before the signature module was written, there already existed the concept of -signatures, but in a more C++ - centric way. From that time, there still exist +signatures, but in a more C++ - centric way. From that time, there existed the error messages, which are created when a function gets wrong argument types. -These error messages should be replaced by text generated on demand by +These error messages were replaced by text generated on demand by the signature module, in order to be more consistent and correct. +This was implemented in ``Qt For Python 5.12.0``. -Additionally, the ``__doc__`` attribute of PySide methods is not set, yet. -It would be easy to get a nice ``help()`` feature by creating signatures +Additionally, the ``__doc__`` attribute of PySide methods was not set. +It was easy to get a nice ``help()`` feature by creating signatures as default content for docstrings. +This was implemented in ``Qt For Python 5.12.1``. Literature diff --git a/sources/shiboken2/shibokenmodule/CMakeLists.txt b/sources/shiboken2/shibokenmodule/CMakeLists.txt index b37d0c941..61c38c5d7 100644 --- a/sources/shiboken2/shibokenmodule/CMakeLists.txt +++ b/sources/shiboken2/shibokenmodule/CMakeLists.txt @@ -51,32 +51,32 @@ 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}/support/__init__.py" - "${CMAKE_CURRENT_BINARY_DIR}/support/__init__.py" COPYONLY) -configure_file("${CMAKE_CURRENT_SOURCE_DIR}/support/signature/__init__.py" - "${CMAKE_CURRENT_BINARY_DIR}/support/signature/__init__.py" COPYONLY) -configure_file("${CMAKE_CURRENT_SOURCE_DIR}/support/signature/errorhandler.py" - "${CMAKE_CURRENT_BINARY_DIR}/support/signature/errorhandler.py" COPYONLY) -configure_file("${CMAKE_CURRENT_SOURCE_DIR}/support/signature/layout.py" - "${CMAKE_CURRENT_BINARY_DIR}/support/signature/layout.py" COPYONLY) -configure_file("${CMAKE_CURRENT_SOURCE_DIR}/support/signature/loader.py" - "${CMAKE_CURRENT_BINARY_DIR}/support/signature/loader.py" COPYONLY) -configure_file("${CMAKE_CURRENT_SOURCE_DIR}/support/signature/mapping.py" - "${CMAKE_CURRENT_BINARY_DIR}/support/signature/mapping.py" COPYONLY) -configure_file("${CMAKE_CURRENT_SOURCE_DIR}/support/signature/parser.py" - "${CMAKE_CURRENT_BINARY_DIR}/support/signature/parser.py" COPYONLY) -configure_file("${CMAKE_CURRENT_SOURCE_DIR}/support/signature/lib/__init__.py" - "${CMAKE_CURRENT_BINARY_DIR}/support/signature/lib/__init__.py" COPYONLY) -configure_file("${CMAKE_CURRENT_SOURCE_DIR}/support/signature/lib/enum_sig.py" - "${CMAKE_CURRENT_BINARY_DIR}/support/signature/lib/enum_sig.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/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) if (PYTHON_VERSION_MAJOR EQUAL 3) else() - configure_file("${CMAKE_CURRENT_SOURCE_DIR}/support/signature/backport_inspect.py" - "${CMAKE_CURRENT_BINARY_DIR}/support/signature/backport_inspect.py" COPYONLY) - configure_file("${CMAKE_CURRENT_SOURCE_DIR}/support/signature/typing27.py" - "${CMAKE_CURRENT_BINARY_DIR}/support/signature/typing27.py" COPYONLY) + 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() -install(DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/support" +install(DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/files.dir" DESTINATION "${PYTHON_SITE_PACKAGES}/shiboken2") install(FILES "${CMAKE_CURRENT_BINARY_DIR}/__init__.py" diff --git a/sources/shiboken2/shibokenmodule/__init__.py.in b/sources/shiboken2/shibokenmodule/__init__.py.in index 81ab0063a..066fd3584 100644 --- a/sources/shiboken2/shibokenmodule/__init__.py.in +++ b/sources/shiboken2/shibokenmodule/__init__.py.in @@ -1,4 +1,11 @@ __version__ = "@FINAL_PACKAGE_VERSION@" __version_info__ = (@shiboken_MAJOR_VERSION@, @shiboken_MINOR_VERSION@, @shiboken_MICRO_VERSION@, "@shiboken_PRE_RELEASE_VERSION_TYPE@", "@shiboken_PRE_RELEASE_VERSION@") +# PYSIDE-932: Python 2 cannot import 'zipfile' for embedding while being imported, itself. +# We simply pre-load all imports for the signature extension. +import sys, zipfile, base64, marshal, io, contextlib + from .shiboken2 import * + +# Trigger signature initialization. +type.__signature__ diff --git a/sources/pyside2/PySide2/support/signature/lib/__init__.py b/sources/shiboken2/shibokenmodule/files.dir/shibokensupport/__init__.py index 2d640cb89..2d640cb89 100644 --- a/sources/pyside2/PySide2/support/signature/lib/__init__.py +++ b/sources/shiboken2/shibokenmodule/files.dir/shibokensupport/__init__.py diff --git a/sources/shiboken2/shibokenmodule/support/signature/backport_inspect.py b/sources/shiboken2/shibokenmodule/files.dir/shibokensupport/backport_inspect.py index e890dcdcf..c690493b6 100644 --- a/sources/shiboken2/shibokenmodule/support/signature/backport_inspect.py +++ b/sources/shiboken2/shibokenmodule/files.dir/shibokensupport/backport_inspect.py @@ -3,7 +3,7 @@ ############################################################################# ## -## Copyright (C) 2018 The Qt Company Ltd. +## Copyright (C) 2019 The Qt Company Ltd. ## Contact: https://www.qt.io/licensing/ ## ## This file is part of Qt for Python. @@ -111,10 +111,9 @@ CO_NOFREE = 0x0040 # This function was changed: 'builtins' and 'qualname' don't exist. # We use '__builtin__' and '__name__' instead. -# It is further changed because we use a local copy of typing def formatannotation(annotation, base_module=None): - if getattr(annotation, '__module__', None) == 'support.signature.typing27': - return repr(annotation).replace('support.signature.typing27', 'typing') + if getattr(annotation, '__module__', None) == 'typing': + return repr(annotation).replace('typing.', '') if isinstance(annotation, type): if annotation.__module__ in ('__builtin__', base_module): return annotation.__name__ @@ -378,7 +377,7 @@ class Parameter(object): # Add annotation and default value if self._annotation is not _empty: - formatted = '{}:{}'.format(formatted, + formatted = '{}: {}'.format(formatted, formatannotation(self._annotation)) if self._default is not _empty: @@ -892,65 +891,3 @@ class Signature(object): def signature(obj, follow_wrapped=True): """Get a signature object for the passed callable.""" return Signature.from_callable(obj, follow_wrapped=follow_wrapped) - - -def _main(): - """ Logic for inspecting an object given at command line """ - import argparse - import importlib - - parser = argparse.ArgumentParser() - parser.add_argument( - 'object', - help="The object to be analysed. " - "It supports the 'module:qualname' syntax") - parser.add_argument( - '-d', '--details', action='store_true', - help='Display info about the module rather than its source code') - - args = parser.parse_args() - - target = args.object - mod_name, has_attrs, attrs = target.partition(":") - try: - obj = module = importlib.import_module(mod_name) - except Exception as exc: - msg = "Failed to import {} ({}: {})".format(mod_name, - type(exc).__name__, - exc) - print(msg, file=sys.stderr) - exit(2) - - if has_attrs: - parts = attrs.split(".") - obj = module - for part in parts: - obj = getattr(obj, part) - - if module.__name__ in sys.builtin_module_names: - print("Can't get info for builtin modules.", file=sys.stderr) - exit(1) - - if args.details: - print('Target: {}'.format(target)) - print('Origin: {}'.format(getsourcefile(module))) - print('Cached: {}'.format(module.__cached__)) - if obj is module: - print('Loader: {}'.format(repr(module.__loader__))) - if hasattr(module, '__path__'): - print('Submodule search path: {}'.format(module.__path__)) - else: - try: - __, lineno = findsource(obj) - except Exception: - pass - else: - print('Line: {}'.format(lineno)) - - print('\n') - else: - print(getsource(obj)) - - -if __name__ == "__main__": - _main() diff --git a/sources/shiboken2/shibokenmodule/support/signature/fix-complaints.py b/sources/shiboken2/shibokenmodule/files.dir/shibokensupport/fix-complaints.py index cdd84f9be..3818ad602 100644 --- a/sources/shiboken2/shibokenmodule/support/signature/fix-complaints.py +++ b/sources/shiboken2/shibokenmodule/files.dir/shibokensupport/fix-complaints.py @@ -1,3 +1,6 @@ +# This Python file uses the following encoding: utf-8 +# It has been edited by fix-complaints.py . + ############################################################################# ## ## Copyright (C) 2019 The Qt Company Ltd. @@ -42,14 +45,15 @@ from __future__ import print_function, absolute_import """ fix-complaints.py -This module fixes the buildbot messages of external python modules. +This module fixes the buildbot messages of external python files. Run it once after copying a new version. It is idem-potent, unless you are changing messages (what I did, of course :-) . """ import os +import glob -patched_modules = "backport_inspect typing27" +patched_file_patterns = "backport_inspect.py typing27.py python_minilib_*.py" offending_words = { "behavio""ur": "behavior", @@ -79,9 +83,12 @@ def patch_file(fname): f.write("".join(lines)) def doit(): - dir = os.path.dirname(__file__) - for name in patched_modules.split(): - fname = os.path.join(dir, name + ".py") + dirname = os.path.dirname(__file__) + patched_files = [] + for name in patched_file_patterns.split(): + pattern = os.path.join(dirname, name) + patched_files += glob.glob(pattern) + for fname in patched_files: print("Working on", fname) patch_file(fname) diff --git a/sources/shiboken2/shibokenmodule/support/signature/PSF-3.7.0.txt b/sources/shiboken2/shibokenmodule/files.dir/shibokensupport/signature/PSF-3.7.0.txt index be42010dd..be42010dd 100644 --- a/sources/shiboken2/shibokenmodule/support/signature/PSF-3.7.0.txt +++ b/sources/shiboken2/shibokenmodule/files.dir/shibokensupport/signature/PSF-3.7.0.txt diff --git a/sources/pyside2/PySide2/support/signature/typing.py b/sources/shiboken2/shibokenmodule/files.dir/shibokensupport/signature/__init__.py index dd52a2c45..ee541d0ea 100644 --- a/sources/pyside2/PySide2/support/signature/typing.py +++ b/sources/shiboken2/shibokenmodule/files.dir/shibokensupport/signature/__init__.py @@ -1,6 +1,6 @@ ############################################################################# ## -## Copyright (C) 2018 The Qt Company Ltd. +## Copyright (C) 2019 The Qt Company Ltd. ## Contact: https://www.qt.io/licensing/ ## ## This file is part of Qt for Python. @@ -39,4 +39,4 @@ from __future__ import print_function, absolute_import -from signature_loader.typing import * +__all__ = "get_signature layout mapping lib".split() diff --git a/sources/shiboken2/shibokenmodule/support/signature/errorhandler.py b/sources/shiboken2/shibokenmodule/files.dir/shibokensupport/signature/errorhandler.py index df24234e3..cb148830f 100644 --- a/sources/shiboken2/shibokenmodule/support/signature/errorhandler.py +++ b/sources/shiboken2/shibokenmodule/files.dir/shibokensupport/signature/errorhandler.py @@ -56,8 +56,9 @@ enough to produce a useful ValueError. This matter will be improved in a later version. """ -from signature_loader import get_signature, inspect -from signature_loader.mapping import update_mapping, namespace +from shibokensupport.signature import inspect +from shibokensupport.signature import get_signature +from shibokensupport.signature.mapping import update_mapping, namespace from textwrap import dedent diff --git a/sources/shiboken2/shibokenmodule/support/signature/layout.py b/sources/shiboken2/shibokenmodule/files.dir/shibokensupport/signature/layout.py index cd3a5dc8f..c43d6d076 100644 --- a/sources/shiboken2/shibokenmodule/support/signature/layout.py +++ b/sources/shiboken2/shibokenmodule/files.dir/shibokensupport/signature/layout.py @@ -1,6 +1,6 @@ ############################################################################# ## -## Copyright (C) 2018 The Qt Company Ltd. +## Copyright (C) 2019 The Qt Company Ltd. ## Contact: https://www.qt.io/licensing/ ## ## This file is part of Qt for Python. @@ -56,8 +56,8 @@ used literally as strings like "signature", "existence", etc. """ from textwrap import dedent -from signature_loader import inspect -from signature_loader.mapping import ellipsis +from shibokensupport.signature import inspect +from shibokensupport.signature.mapping import ellipsis class SimpleNamespace(object): diff --git a/sources/shiboken2/shibokenmodule/support/signature/lib/__init__.py b/sources/shiboken2/shibokenmodule/files.dir/shibokensupport/signature/lib/__init__.py index 2d640cb89..2d640cb89 100644 --- a/sources/shiboken2/shibokenmodule/support/signature/lib/__init__.py +++ b/sources/shiboken2/shibokenmodule/files.dir/shibokensupport/signature/lib/__init__.py diff --git a/sources/shiboken2/shibokenmodule/support/signature/lib/enum_sig.py b/sources/shiboken2/shibokenmodule/files.dir/shibokensupport/signature/lib/enum_sig.py index 013ec36cc..e6f6dc379 100644 --- a/sources/shiboken2/shibokenmodule/support/signature/lib/enum_sig.py +++ b/sources/shiboken2/shibokenmodule/files.dir/shibokensupport/signature/lib/enum_sig.py @@ -50,7 +50,8 @@ by producing a lot of clarity. """ import sys -from signature_loader import get_signature, inspect +from shibokensupport.signature import inspect +from shibokensupport.signature import get_signature class ExactEnumerator(object): diff --git a/sources/shiboken2/shibokenmodule/files.dir/shibokensupport/signature/loader.py b/sources/shiboken2/shibokenmodule/files.dir/shibokensupport/signature/loader.py new file mode 100644 index 000000000..a564aedb9 --- /dev/null +++ b/sources/shiboken2/shibokenmodule/files.dir/shibokensupport/signature/loader.py @@ -0,0 +1,215 @@ +# This Python file uses the following encoding: utf-8 +# It has been edited by fix-complaints.py . + +############################################################################# +## +## Copyright (C) 2019 The Qt Company Ltd. +## Contact: https://www.qt.io/licensing/ +## +## This file is part of Qt for Python. +## +## $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$ +## +############################################################################# + +from __future__ import print_function, absolute_import + +""" +loader.py + +The loader has to load the signature module completely at startup, +to make sure that the functions are available when needed. +This is meanwhile necessary to make the '__doc__' attribute work correctly. + +It does not mean that everything is initialized in advance. Only the modules +are loaded completely after 'import PySide2'. + +This version uses both a normal directory, but has also an embedded ZIP file +as a fallback solution. The ZIP file is generated by 'embedding_generator.py' +and embedded into 'signature.cpp' as "embed/signature.inc". + +Meanwhile, the ZIP file grew so much, that MSVC had problems +with it's 64k string limit, so we had to break the string up. +See 'zipped_string_sequence' in signature.cpp. +""" + +import sys +import os +import traceback +import types + +# On Python 2, we only have ImportError, which is way too coarse. +# When problems occour, please use Python 3, because it has the finer +# ModuleNotFoundError. + +try: + ModuleNotFoundError +except NameError: + ModuleNotFoundError = ImportError + +# patching inspect's formatting to keep the word "typing": +def formatannotation(annotation, base_module=None): + # if getattr(annotation, '__module__', None) == 'typing': + # return repr(annotation).replace('typing.', '') + if isinstance(annotation, type): + if annotation.__module__ in ('builtins', base_module): + return annotation.__qualname__ + return annotation.__module__ + '.' + annotation.__qualname__ + return repr(annotation) + +# patching __repr__ to disable the __repr__ of typing.TypeVar: +""" + def __repr__(self): + if self.__covariant__: + prefix = '+' + elif self.__contravariant__: + prefix = '-' + else: + prefix = '~' + return prefix + self.__name__ +""" +def _typevar__repr__(self): + return "typing." + self.__name__ + +# Note also that during the tests we have a different encoding that would +# break the Python license decorated files without an encoding line. + +# name used in signature.cpp +def create_signature(props, key): + return layout.create_signature(props, key) + +# name used in signature.cpp +def seterror_argument(args, func_name): + return errorhandler.seterror_argument(args, func_name) + +# name used in signature.cpp +def make_helptext(func): + return errorhandler.make_helptext(func) + +import signature_bootstrap +from shibokensupport import signature +signature.get_signature = signature_bootstrap.get_signature +del signature_bootstrap + + +def _get_modname(mod): + return mod.__spec__.name if getattr(mod, "__spec__", None) else mod.__name__ + +def _set_modname(mod, name): + if getattr(mod, "__spec__", None): + mod.__spec__.name = name + else: + mod.__name__ = name + + +def put_into_package(package, module, override=None): + # take the last component of the module name + name = (override if override else _get_modname(module)).rsplit(".", 1)[-1] + # allow access as {package}.typing + if package: + setattr(package, name, module) + # put into sys.modules as a package to allow all import options + fullname = "{}.{}".format(_get_modname(package), name) if package else name + _set_modname(module, fullname) + # publish new dotted name in sys.modules + sys.modules[fullname] = module + + +# Debug: used to inspect what each step loads +def list_modules(message): + ext_modules = {key:value for (key, value) in sys.modules.items() + if hasattr(value, "__file__")} + print("SYS.MODULES", message, len(sys.modules), len(ext_modules)) + for (name, module) in sorted(ext_modules.items()): + print(" {:23}".format(name), repr(module)[:70]) + + +if sys.version_info >= (3,): + import typing + import inspect + inspect.formatannotation = formatannotation +else: + from shibokensupport import typing27 as typing + import inspect + namespace = inspect.__dict__ + from shibokensupport import backport_inspect as inspect + _doc = inspect.__doc__ + inspect.__dict__.update(namespace) + inspect.__doc__ += _doc + # force inspect to find all attributes. See "heuristic" in pydoc.py! + inspect.__all__ = list(x for x in dir(inspect) if not x.startswith("_")) +typing.TypeVar.__repr__ = _typevar__repr__ + +# Fix the module names in typing if possible. This is important since +# the typing names should be I/O compatible, so that typing.Dict +# shows itself as "typing.Dict". +for name, obj in typing.__dict__.items(): + if hasattr(obj, "__module__"): + try: + obj.__module__ = "typing" + except (TypeError, AttributeError): + pass + +import shibokensupport +put_into_package(shibokensupport.signature, typing, "typing") +put_into_package(shibokensupport.signature, inspect, "inspect") + + +def move_into_pyside_package(): + import PySide2 + try: + import PySide2.support + except ModuleNotFoundError: + PySide2.support = types.ModuleType("PySide2.support") + put_into_package(PySide2.support, signature) + put_into_package(PySide2.support.signature, mapping) + put_into_package(PySide2.support.signature, errorhandler) + put_into_package(PySide2.support.signature, layout) + put_into_package(PySide2.support.signature, lib) + put_into_package(PySide2.support.signature, parser) + put_into_package(PySide2.support.signature.lib, enum_sig) + + put_into_package(PySide2.support.signature, typing) + put_into_package(PySide2.support.signature, inspect) + +from shibokensupport.signature import mapping +from shibokensupport.signature import errorhandler +from shibokensupport.signature import layout +from shibokensupport.signature import lib +from shibokensupport.signature import parser +from shibokensupport.signature.lib import enum_sig +from shibokensupport.signature.parser import pyside_type_init + +if "PySide2" in sys.modules: + # We publish everything under "PySide2.support.signature", again. + move_into_pyside_package() + +# end of file diff --git a/sources/pyside2/PySide2/support/signature/mapping.py b/sources/shiboken2/shibokenmodule/files.dir/shibokensupport/signature/mapping.py index 2b234ecd4..9a8ee4c4e 100644 --- a/sources/pyside2/PySide2/support/signature/mapping.py +++ b/sources/shiboken2/shibokenmodule/files.dir/shibokensupport/signature/mapping.py @@ -1,6 +1,6 @@ ############################################################################# ## -## Copyright (C) 2018 The Qt Company Ltd. +## Copyright (C) 2019 The Qt Company Ltd. ## Contact: https://www.qt.io/licensing/ ## ## This file is part of Qt for Python. @@ -49,24 +49,305 @@ The PySide modules are not loaded in advance, but only after they appear in sys.modules. This minimizes the loading overhead. """ -import PySide2 +import sys +import struct +import os -from signature_loader.sbk_mapping import * -from signature_loader.sbk_mapping import _NotCalled +from shibokensupport.signature import typing +from shibokensupport.signature.typing import TypeVar, Generic -Sbk_Reloader = Reloader +class ellipsis(object): + def __repr__(self): + return "..." -class Reloader(Sbk_Reloader): - _uninitialized = Sbk_Reloader._uninitialized + PySide2.__all__ + ["testbinding"] - _prefixes = Sbk_Reloader._prefixes + ["PySide2."] +ellipsis = ellipsis() +StringList = typing.List[str] +IntList = typing.List[int] +Point = typing.Tuple[float, float] +PointList = typing.List[Point] +IntMatrix = typing.List[IntList] +Variant = typing.Any +ModelIndexList = typing.List[int] +QImageCleanupFunction = typing.Callable + +# First time installing our own Pair type into typing. +T = TypeVar('T') +S = TypeVar('S') + +class Pair(Generic[T, S]): + __module__ = "typing" + +typing.Pair = Pair + + +# Building our own Char type, which is much nicer than +# Char = typing.Union[str, int] # how do I model the limitation to 1 char? + +# Copied from the six module: +def with_metaclass(meta, *bases): + """Create a base class with a metaclass.""" + # This requires a bit of explanation: the basic idea is to make a dummy + # metaclass for one level of class instantiation that replaces itself with + # the actual metaclass. + class metaclass(type): + + def __new__(cls, name, this_bases, d): + return meta(name, bases, d) + + @classmethod + def __prepare__(cls, name, this_bases): + return meta.__prepare__(name, bases) + return type.__new__(metaclass, 'temporary_class', (), {}) + +class _CharMeta(type): + def __repr__(self): + return '%s.%s' % (self.__module__, self.__name__) + + +class Char(with_metaclass(_CharMeta)): + """ + From http://doc.qt.io/qt-5/qchar.html : + + In Qt, Unicode characters are 16-bit entities without any markup or + structure. This class represents such an entity. It is lightweight, + so it can be used everywhere. Most compilers treat it like an + unsigned short. + + Here, we provide a simple implementation just to avoid long aliases. + """ + __module__ = "typing" + + def __init__(self, code): + if isinstance(code, int): + self.code = code & 0xffff + else: + self.code = ord(code) + + def __add__(self, other): + return chr(self.code) + other + + def __radd__(self, other): + return other + chr(self.code) + + def __repr__(self): + return "typing.Char({})".format(self.code) + +typing.Char = Char + + +MultiMap = typing.DefaultDict[str, typing.List[str]] + +# ulong_max is only 32 bit on windows. +ulong_max = 2*sys.maxsize+1 if len(struct.pack("L", 1)) != 4 else 0xffffffff +ushort_max = 0xffff + +GL_COLOR_BUFFER_BIT = 0x00004000 +GL_NEAREST = 0x2600 + +WId = int + +# from 5.9 +GL_TEXTURE_2D = 0x0DE1 +GL_RGBA = 0x1908 + + +class _NotCalled(str): + """ + Wrap some text with semantics + + This class is wrapped around text in order to avoid calling it. + There are three reasons for this: + + - some instances cannot be created since they are abstract, + - some can only be created after qApp was created, + - some have an ugly __repr__ with angle brackets in it. + + By using derived classes, good looking instances can be created + which can be used to generate source code or .pyi files. When the + real object is needed, the wrapper can simply be called. + """ + def __repr__(self): + return "{}({})".format(type(self).__name__, self) + + def __call__(self): + from shibokensupport.signature.mapping import __dict__ as namespace + text = self if self.endswith(")") else self + "()" + return eval(text, namespace) + +USE_PEP563 = sys.version_info[:2] >= (3, 7) + + +# Some types are abstract. They just show their name. +class Virtual(_NotCalled): + pass + +# Other types I simply could not find. +class Missing(_NotCalled): + if not USE_PEP563: + # The string must be quoted, because the object does not exist. + def __repr__(self): + return '{}("{}")'.format(type(self).__name__, self) + + +class Invalid(_NotCalled): + pass + +# Helper types +class Default(_NotCalled): + pass + + +class Instance(_NotCalled): + pass + + +class Reloader(object): + """ + Reloder class + + This is a singleton class which provides the update function for the + shiboken and PySide classes. + """ + _uninitialized = "Shiboken minimal sample other smart".split() + _prefixes = [""] + try: + import PySide2 + _uninitialized += PySide2.__all__ + ["testbinding"] + _prefixes += ["PySide2."] + except ImportError: + pass + + def __init__(self): + self.sys_module_count = 0 + self.uninitialized = self._uninitialized def update(self): - Sbk_Reloader.update(self, globals()) + """ + update is responsible to import all modules from shiboken and PySide + which are already in sys.modules. + The purpose is to follow all user imports without introducing new + ones. + This function is called by pyside_type_init to adapt imports + when the number of imported modules has changed. + """ + if self.sys_module_count == len(sys.modules): + return + self.sys_module_count = len(sys.modules) + g = globals() + for mod_name in self.uninitialized[:]: + for prefix in self._prefixes: + import_name = prefix + mod_name + if import_name in sys.modules: + # check if this is a real module + check_module(sys.modules[import_name]) + # module is real + self.uninitialized.remove(mod_name) + proc_name = "init_" + mod_name + if proc_name in g: + # Do the 'import {import_name}' first. + # 'top' is PySide2 when we do 'import PySide.QtCore' + # or Shiboken if we do 'import Shiboken'. + # Convince yourself that these two lines below have the same + # global effect as "import Shiboken" or "import PySide2.QtCore". + top = __import__(import_name) + g[top.__name__] = top + # Modules are in place, we can update the type_map. + g.update(g[proc_name]()) + +def check_module(mod): + # During a build, there exist the modules already as directories, + # although the '*.so' was not yet created. This causes a problem + # in Python 3, because it accepts folders as namespace modules + # without enforcing an '__init__.py'. + if not getattr(mod, "__file__", None) or os.path.isdir(mod.__file__): + mod_name = mod.__name__ + raise ImportError("Module '{mod_name}' is at most a namespace!" + .format(**locals())) + update_mapping = Reloader().update -namespace = globals() # our module's __dict__, updated +type_map = {} +namespace = globals() # our module's __dict__ + +type_map.update({ + "QList": typing.List, + "QVector": typing.List, + "QSet": typing.Set, + "QPair": Pair, + }) + +# The Shiboken Part +def init_Shiboken(): + type_map.update({ + "shiboken2.bool": bool, + "size_t": int, + "PyType": type, + }) + return locals() + + +def init_minimal(): + type_map.update({ + "MinBool": bool, + }) + return locals() + + +def init_sample(): + import datetime + type_map.update({ + "double": float, + "sample.int": int, + "Complex": complex, + "sample.OddBool": bool, + "sample.bool": bool, + "sample.PStr": str, + "OddBool": bool, + "PStr": str, + "char": Char, + "sample.char": Char, + "sample.Point": Point, + "sample.ObjectType": object, + "std.string": str, + "HANDLE": int, + "Foo.HANDLE": int, + "sample.Photon.TemplateBase": Missing("sample.Photon.TemplateBase"), + "ObjectType.Identifier": Missing("sample.ObjectType.Identifier"), + "zero(HANDLE)": 0, + "Null": None, + "zero(sample.ObjectType)": None, + "std.size_t": int, + 'Str("<unknown>")': "<unknown>", + 'Str("<unk")': "<unk", + 'Str("nown>")': "nown>", + "zero(sample.ObjectModel)": None, + "sample.unsigned char": Char, + "sample.double": float, + "zero(sample.bool)": False, + "PyDate": datetime.date, + "ZeroIn": 0, + }) + return locals() + + +def init_other(): + import numbers + type_map.update({ + "other.Number": numbers.Number, + "other.ExtendsNoImplicitConversion": Missing("other.ExtendsNoImplicitConversion"), + }) + return locals() + + +def init_smart(): + type_map.update({ + "smart.SharedPtr": Missing("smart.SharedPtr"), # bad object "SharedPtr<Obj >" + "smart.Smart.Integer2": int, + }) + return locals() +# The PySide Part def init_QtCore(): from PySide2.QtCore import Qt, QUrl, QDir from PySide2.QtCore import QRect, QSize, QPoint, QLocale, QByteArray diff --git a/sources/shiboken2/shibokenmodule/support/signature/parser.py b/sources/shiboken2/shibokenmodule/files.dir/shibokensupport/signature/parser.py index 5c9a1e4f1..09e78f1b0 100644 --- a/sources/shiboken2/shibokenmodule/support/signature/parser.py +++ b/sources/shiboken2/shibokenmodule/files.dir/shibokensupport/signature/parser.py @@ -1,6 +1,6 @@ ############################################################################# ## -## Copyright (C) 2018 The Qt Company Ltd. +## Copyright (C) 2019 The Qt Company Ltd. ## Contact: https://www.qt.io/licensing/ ## ## This file is part of Qt for Python. @@ -45,8 +45,8 @@ import warnings import types import keyword import functools -from signature_loader.mapping import (type_map, update_mapping, namespace, - typing, _NotCalled) +from shibokensupport.signature.mapping import (type_map, update_mapping, + namespace, typing, _NotCalled) _DEBUG = False LIST_KEYWORDS = False diff --git a/sources/shiboken2/shibokenmodule/support/signature/qt_attribution.json b/sources/shiboken2/shibokenmodule/files.dir/shibokensupport/signature/qt_attribution.json index 491ae8054..fbe4c51ab 100644 --- a/sources/shiboken2/shibokenmodule/support/signature/qt_attribution.json +++ b/sources/shiboken2/shibokenmodule/files.dir/shibokensupport/signature/qt_attribution.json @@ -3,7 +3,7 @@ "Name": "Python", "QDocModule": "QtForPython", "QtUsage": "Used for Qt for Python in the signature extension.", - "Description": "Qt for Python is an add-on for Python. The signature packages of PySide uses certain copied and adapted source files (backport_inspect.py, typing27.py). See the folder sources/pyside2/PySide2/support/signature .", + "Description": "Qt for Python is an add-on for Python. The signature packages of PySide uses certain copied and adapted source files (backport_inspect.py, typing27.py). See the folder sources/shiboken2/files.dir/shibokensupport/signature .", "Homepage": "http://www.python.org/", "Version": "3.7.0", "LicenseId": "Python-2.0", diff --git a/sources/shiboken2/shibokenmodule/support/signature/typing27.py b/sources/shiboken2/shibokenmodule/files.dir/shibokensupport/typing27.py index 5d1c6058b..dba8f8c77 100644 --- a/sources/shiboken2/shibokenmodule/support/signature/typing27.py +++ b/sources/shiboken2/shibokenmodule/files.dir/shibokensupport/typing27.py @@ -3,7 +3,7 @@ ############################################################################# ## -## Copyright (C) 2018 The Qt Company Ltd. +## Copyright (C) 2019 The Qt Company Ltd. ## Contact: https://www.qt.io/licensing/ ## ## This file is part of Qt for Python. diff --git a/sources/shiboken2/shibokenmodule/support/__init__.py b/sources/shiboken2/shibokenmodule/support/__init__.py deleted file mode 100644 index 760d89571..000000000 --- a/sources/shiboken2/shibokenmodule/support/__init__.py +++ /dev/null @@ -1,40 +0,0 @@ -############################################################################# -## -## Copyright (C) 2017 The Qt Company Ltd. -## Contact: https://www.qt.io/licensing/ -## -## This file is part of Qt for Python. -## -## $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$ -## -############################################################################# - -# this file intentionally left blank diff --git a/sources/shiboken2/shibokenmodule/support/signature/__init__.py b/sources/shiboken2/shibokenmodule/support/signature/__init__.py deleted file mode 100644 index d0791df04..000000000 --- a/sources/shiboken2/shibokenmodule/support/signature/__init__.py +++ /dev/null @@ -1,47 +0,0 @@ -############################################################################# -## -## Copyright (C) 2018 The Qt Company Ltd. -## Contact: https://www.qt.io/licensing/ -## -## This file is part of Qt for Python. -## -## $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$ -## -############################################################################# - -from __future__ import print_function, absolute_import - -# Trigger initialization phase 2. -_ = type.__signature__ - -## from signature_loader import get_signature, inspect, typing -# This causes a recursion in Python 2! -# We do everything from signature_loader, instead. diff --git a/sources/shiboken2/shibokenmodule/support/signature/contextlib36.py b/sources/shiboken2/shibokenmodule/support/signature/contextlib36.py deleted file mode 100644 index d416eef27..000000000 --- a/sources/shiboken2/shibokenmodule/support/signature/contextlib36.py +++ /dev/null @@ -1,472 +0,0 @@ -# This Python file uses the following encoding: utf-8 -# It has been edited by fix-complaints.py . - -############################################################################# -## -## Copyright (C) 2019 The Qt Company Ltd. -## Contact: https://www.qt.io/licensing/ -## -## This file is part of Qt for Python. -## -## $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$ -## -############################################################################# - -""" -PSF LICENSE AGREEMENT FOR PYTHON 3.7.0 - -1. This LICENSE AGREEMENT is between the Python Software Foundation ("PSF"), and - the Individual or Organization ("Licensee") accessing and otherwise using Python - 3.7.0 software in source or binary form and its associated documentation. - -2. Subject to the terms and conditions of this License Agreement, PSF hereby - grants Licensee a nonexclusive, royalty-free, world-wide license to reproduce, - analyze, test, perform and/or display publicly, prepare derivative works, - distribute, and otherwise use Python 3.7.0 alone or in any derivative - version, provided, however, that PSF's License Agreement and PSF's notice of - copyright, i.e., "Copyright © 2001-2018 Python Software Foundation; All Rights - Reserved" are retained in Python 3.7.0 alone or in any derivative version - prepared by Licensee. - -3. In the event Licensee prepares a derivative work that is based on or - incorporates Python 3.7.0 or any part thereof, and wants to make the - derivative work available to others as provided herein, then Licensee hereby - agrees to include in any such work a brief summary of the changes made to Python - 3.7.0. - -4. PSF is making Python 3.7.0 available to Licensee on an "AS IS" basis. - PSF MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED. BY WAY OF - EXAMPLE, BUT NOT LIMITATION, PSF MAKES NO AND DISCLAIMS ANY REPRESENTATION OR - WARRANTY OF MERCHANTABILITY OR FITNESS FOR ANY PARTICULAR PURPOSE OR THAT THE - USE OF PYTHON 3.7.0 WILL NOT INFRINGE ANY THIRD PARTY RIGHTS. - -5. PSF SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF PYTHON 3.7.0 - FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS AS A RESULT OF - MODIFYING, DISTRIBUTING, OR OTHERWISE USING PYTHON 3.7.0, OR ANY DERIVATIVE - THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF. - -6. This License Agreement will automatically terminate upon a material breach of - its terms and conditions. - -7. Nothing in this License Agreement shall be deemed to create any relationship - of agency, partnership, or joint venture between PSF and Licensee. This License - Agreement does not grant permission to use PSF trademarks or trade name in a - trademark sense to endorse or promote products or services of Licensee, or any - third party. - -8. By copying, installing or otherwise using Python 3.7.0, Licensee agrees - to be bound by the terms and conditions of this License Agreement. -""" - -"""Utilities for with-statement contexts. See PEP 343.""" -import abc -import sys -import _collections_abc -from collections import deque -from functools import wraps - -__all__ = ["contextmanager", "closing", "AbstractContextManager", - "ContextDecorator", "ExitStack", "redirect_stdout", - "redirect_stderr", "suppress"] - - -class AbstractContextManager(abc.ABC): - - """An abstract base class for context managers.""" - - def __enter__(self): - """Return `self` upon entering the runtime context.""" - return self - - @abc.abstractmethod - def __exit__(self, exc_type, exc_value, traceback): - """Raise any exception triggered within the runtime context.""" - return None - - @classmethod - def __subclasshook__(cls, C): - if cls is AbstractContextManager: - return _collections_abc._check_methods(C, "__enter__", "__exit__") - return NotImplemented - - -class ContextDecorator(object): - "A base class or mixin that enables context managers to work as decorators." - - def _recreate_cm(self): - """Return a recreated instance of self. - - Allows an otherwise one-shot context manager like - _GeneratorContextManager to support use as - a decorator via implicit recreation. - - This is a private interface just for _GeneratorContextManager. - See issue #11647 for details. - """ - return self - - def __call__(self, func): - @wraps(func) - def inner(*args, **kwds): - with self._recreate_cm(): - return func(*args, **kwds) - return inner - - -class _GeneratorContextManager(ContextDecorator, AbstractContextManager): - """Helper for @contextmanager decorator.""" - - def __init__(self, func, args, kwds): - self.gen = func(*args, **kwds) - self.func, self.args, self.kwds = func, args, kwds - # Issue 19330: ensure context manager instances have good docstrings - doc = getattr(func, "__doc__", None) - if doc is None: - doc = type(self).__doc__ - self.__doc__ = doc - # Unfortunately, this still doesn't provide good help output when - # inspecting the created context manager instances, since pydoc - # currently bypasses the instance docstring and shows the docstring - # for the class instead. - # See http://bugs.python.org/issue19404 for more details. - - def _recreate_cm(self): - # _GCM instances are one-shot context managers, so the - # CM must be recreated each time a decorated function is - # called - return self.__class__(self.func, self.args, self.kwds) - - def __enter__(self): - try: - return next(self.gen) - except StopIteration: - raise RuntimeError("generator didn't yield") from None - - def __exit__(self, type, value, traceback): - if type is None: - try: - next(self.gen) - except StopIteration: - return False - else: - raise RuntimeError("generator didn't stop") - else: - if value is None: - # Need to force instantiation so we can reliably - # tell if we get the same exception back - value = type() - try: - self.gen.throw(type, value, traceback) - except StopIteration as exc: - # Suppress StopIteration *unless* it's the same exception that - # was passed to throw(). This prevents a StopIteration - # raised inside the "with" statement from being suppressed. - return exc is not value - except RuntimeError as exc: - # Don't re-raise the passed in exception. (issue27122) - if exc is value: - return False - # Likewise, avoid suppressing if a StopIteration exception - # was passed to throw() and later wrapped into a RuntimeError - # (see PEP 479). - if type is StopIteration and exc.__cause__ is value: - return False - raise - except: - # only re-raise if it's *not* the exception that was - # passed to throw(), because __exit__() must not raise - # an exception unless __exit__() itself failed. But throw() - # has to raise the exception to signal propagation, so this - # fixes the impedance mismatch between the throw() protocol - # and the __exit__() protocol. - # - if sys.exc_info()[1] is value: - return False - raise - raise RuntimeError("generator didn't stop after throw()") - - -def contextmanager(func): - """@contextmanager decorator. - - Typical usage: - - @contextmanager - def some_generator(<arguments>): - <setup> - try: - yield <value> - finally: - <cleanup> - - This makes this: - - with some_generator(<arguments>) as <variable>: - <body> - - equivalent to this: - - <setup> - try: - <variable> = <value> - <body> - finally: - <cleanup> - - """ - @wraps(func) - def helper(*args, **kwds): - return _GeneratorContextManager(func, args, kwds) - return helper - - -class closing(AbstractContextManager): - """Context to automatically close something at the end of a block. - - Code like this: - - with closing(<module>.open(<arguments>)) as f: - <block> - - is equivalent to this: - - f = <module>.open(<arguments>) - try: - <block> - finally: - f.close() - - """ - def __init__(self, thing): - self.thing = thing - def __enter__(self): - return self.thing - def __exit__(self, *exc_info): - self.thing.close() - - -class _RedirectStream(AbstractContextManager): - - _stream = None - - def __init__(self, new_target): - self._new_target = new_target - # We use a list of old targets to make this CM re-entrant - self._old_targets = [] - - def __enter__(self): - self._old_targets.append(getattr(sys, self._stream)) - setattr(sys, self._stream, self._new_target) - return self._new_target - - def __exit__(self, exctype, excinst, exctb): - setattr(sys, self._stream, self._old_targets.pop()) - - -class redirect_stdout(_RedirectStream): - """Context manager for temporarily redirecting stdout to another file. - - # How to send help() to stderr - with redirect_stdout(sys.stderr): - help(dir) - - # How to write help() to a file - with open('help.txt', 'w') as f: - with redirect_stdout(f): - help(pow) - """ - - _stream = "stdout" - - -class redirect_stderr(_RedirectStream): - """Context manager for temporarily redirecting stderr to another file.""" - - _stream = "stderr" - - -class suppress(AbstractContextManager): - """Context manager to suppress specified exceptions - - After the exception is suppressed, execution proceeds with the next - statement following the with statement. - - with suppress(FileNotFoundError): - os.remove(somefile) - # Execution still resumes here if the file was already removed - """ - - def __init__(self, *exceptions): - self._exceptions = exceptions - - def __enter__(self): - pass - - def __exit__(self, exctype, excinst, exctb): - # Unlike isinstance and issubclass, CPython exception handling - # currently only looks at the concrete type hierarchy (ignoring - # the instance and subclass checking hooks). While Guido considers - # that a bug rather than a feature, it's a fairly hard one to fix - # due to various internal implementation details. suppress provides - # the simpler issubclass based semantics, rather than trying to - # exactly reproduce the limitations of the CPython interpreter. - # - # See http://bugs.python.org/issue12029 for more details - return exctype is not None and issubclass(exctype, self._exceptions) - - -# Inspired by discussions on http://bugs.python.org/issue13585 -class ExitStack(AbstractContextManager): - """Context manager for dynamic management of a stack of exit callbacks - - For example: - - with ExitStack() as stack: - files = [stack.enter_context(open(fname)) for fname in filenames] - # All opened files will automatically be closed at the end of - # the with statement, even if attempts to open files later - # in the list raise an exception - - """ - def __init__(self): - self._exit_callbacks = deque() - - def pop_all(self): - """Preserve the context stack by transferring it to a new instance""" - new_stack = type(self)() - new_stack._exit_callbacks = self._exit_callbacks - self._exit_callbacks = deque() - return new_stack - - def _push_cm_exit(self, cm, cm_exit): - """Helper to correctly register callbacks to __exit__ methods""" - def _exit_wrapper(*exc_details): - return cm_exit(cm, *exc_details) - _exit_wrapper.__self__ = cm - self.push(_exit_wrapper) - - def push(self, exit): - """Registers a callback with the standard __exit__ method signature - - Can suppress exceptions the same way __exit__ methods can. - - Also accepts any object with an __exit__ method (registering a call - to the method instead of the object itself) - """ - # We use an unbound method rather than a bound method to follow - # the standard lookup behavior for special methods - _cb_type = type(exit) - try: - exit_method = _cb_type.__exit__ - except AttributeError: - # Not a context manager, so assume its a callable - self._exit_callbacks.append(exit) - else: - self._push_cm_exit(exit, exit_method) - return exit # Allow use as a decorator - - def callback(self, callback, *args, **kwds): - """Registers an arbitrary callback and arguments. - - Cannot suppress exceptions. - """ - def _exit_wrapper(exc_type, exc, tb): - callback(*args, **kwds) - # We changed the signature, so using @wraps is not appropriate, but - # setting __wrapped__ may still help with introspection - _exit_wrapper.__wrapped__ = callback - self.push(_exit_wrapper) - return callback # Allow use as a decorator - - def enter_context(self, cm): - """Enters the supplied context manager - - If successful, also pushes its __exit__ method as a callback and - returns the result of the __enter__ method. - """ - # We look up the special methods on the type to match the with statement - _cm_type = type(cm) - _exit = _cm_type.__exit__ - result = _cm_type.__enter__(cm) - self._push_cm_exit(cm, _exit) - return result - - def close(self): - """Immediately unwind the context stack""" - self.__exit__(None, None, None) - - def __exit__(self, *exc_details): - received_exc = exc_details[0] is not None - - # We manipulate the exception state so it behaves as though - # we were actually nesting multiple with statements - frame_exc = sys.exc_info()[1] - def _fix_exception_context(new_exc, old_exc): - # Context may not be correct, so find the end of the chain - while 1: - exc_context = new_exc.__context__ - if exc_context is old_exc: - # Context is already set correctly (see issue 20317) - return - if exc_context is None or exc_context is frame_exc: - break - new_exc = exc_context - # Change the end of the chain to point to the exception - # we expect it to reference - new_exc.__context__ = old_exc - - # Callbacks are invoked in LIFO order to match the behavior of - # nested context managers - suppressed_exc = False - pending_raise = False - while self._exit_callbacks: - cb = self._exit_callbacks.pop() - try: - if cb(*exc_details): - suppressed_exc = True - pending_raise = False - exc_details = (None, None, None) - except: - new_exc_details = sys.exc_info() - # simulate the stack of exceptions by setting the context - _fix_exception_context(new_exc_details[1], exc_details[1]) - pending_raise = True - exc_details = new_exc_details - if pending_raise: - try: - # bare "raise exc_details[1]" replaces our carefully - # set-up context - fixed_ctx = exc_details[1].__context__ - raise exc_details[1] - except BaseException: - exc_details[1].__context__ = fixed_ctx - raise - return received_exc and suppressed_exc diff --git a/sources/shiboken2/shibokenmodule/support/signature/loader.py b/sources/shiboken2/shibokenmodule/support/signature/loader.py deleted file mode 100644 index 458759845..000000000 --- a/sources/shiboken2/shibokenmodule/support/signature/loader.py +++ /dev/null @@ -1,221 +0,0 @@ -############################################################################# -## -## Copyright (C) 2018 The Qt Company Ltd. -## Contact: https://www.qt.io/licensing/ -## -## This file is part of Qt for Python. -## -## $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$ -## -############################################################################# - -from __future__ import print_function, absolute_import - -""" -loader.py - -The loader has to lazy-load the signature module and also provides a few -Python modules to support Python 2.7 . - -This file was originally directly embedded into the C source. -After it grew more and more, I now prefer to have it as Python file. -The remaining stub loader in the C source is now only a short string. - -This version does no longer use an embedded .zip file but is a package. -The old code without a package but with zip compression can still be found -at https://codereview.qt-project.org/#/c/203533/ for reference. -""" - -import sys -import os -import traceback -import types -from contextlib import contextmanager - -""" -A note on the import problem (solved): - -During the tests, the shiboken build structure has the layout - - shiboken2/shibokenmodule/shiboken2.abi3.so - -and the name "shiboken2" in sys.modules points directly to the binary -file, hiding the outer shiboken2 module. - -To fix that, we temporarily remove the binary from sys.path, -do the needed imports and then restore the binary. -This action was put into a context manager for readability. -""" - -# On Python 2, we only have ImportError, which is way too coarse. -# When problems occour, please use Python 3, because it has the finer -# ModuleNotFoundError. - -try: - ModuleNotFoundError -except NameError: - ModuleNotFoundError = ImportError - -@contextmanager -def ensure_import_support(): - # Make sure that we always have the shiboken containing package first. - # This is sometimes hidden by the ctest paths. - # We adjust the path in a way that the support folder comes first. - # This can be in "shiboken2/support" or in "shibokenmodule/support", - # so we use the "support" folder as toplevel. - sbk_support_dir = os.path.abspath(os.path.join(__file__, "..", "..", "..")) - sys.path.insert(0, sbk_support_dir) - sbk = "shiboken2" - save_sbk = sys.modules.pop(sbk) if sbk in sys.modules else None - # make sure that we get at the support folder - try: - import support - yield - except Exception as e: - print("Problem importing support:") - print(e) - traceback.print_exc() - sys.stdout.flush() - sys.exit(-1) - if save_sbk: - sys.modules[sbk] = save_sbk - sys.path.pop(0) - - -# patching inspect's formatting to keep the word "typing": -def formatannotation(annotation, base_module=None): - # if getattr(annotation, '__module__', None) == 'typing': - # return repr(annotation).replace('typing.', '') - if isinstance(annotation, type): - if annotation.__module__ in ('builtins', base_module): - return annotation.__qualname__ - return annotation.__module__+'.'+annotation.__qualname__ - return repr(annotation) - -# patching __repr__ to disable the __repr__ of typing.TypeVar: -""" - def __repr__(self): - if self.__covariant__: - prefix = '+' - elif self.__contravariant__: - prefix = '-' - else: - prefix = '~' - return prefix + self.__name__ -""" -def _typevar__repr__(self): - return "typing." + self.__name__ - -# Note also that during the tests we have a different encoding that would -# break the Python license decorated files without an encoding line. - -# name used in signature.cpp -def create_signature(props, key): - return layout.create_signature(props, key) - -# name used in signature.cpp -def seterror_argument(args, func_name): - return errorhandler.seterror_argument(args, func_name) - -# name used in signature.cpp -def make_helptext(func): - return errorhandler.make_helptext(func) - -with ensure_import_support(): - # We store all needed modules in signature_loader. - # This way, they are always accessible. - import signature_loader - - if sys.version_info >= (3,): - import typing - import inspect - inspect.formatannotation = formatannotation - else: - import inspect - namespace = inspect.__dict__ - from support.signature import typing27 as typing - typing.__name__ = "typing" - # Fix the module names in typing if possible. This is important since - # the typing names should be I/O compatible, so that typing.Dict - # shows itself as "typing.Dict". - for name, obj in typing.__dict__.items(): - if hasattr(obj, "__module__"): - try: - obj.__module__ = "typing" - except (TypeError, AttributeError): - pass - from support.signature import backport_inspect as inspect - _doc = inspect.__doc__ - inspect.__dict__.update(namespace) - inspect.__doc__ += _doc - # force inspect to find all attributes. See "heuristic" in pydoc.py! - inspect.__all__ = list(x for x in dir(inspect) if not x.startswith("_")) - typing.TypeVar.__repr__ = _typevar__repr__ - - def put_into_loader_package(module, loader=signature_loader): - # Note: the "with" statement hides that we are no longer in a - # global context, but inside ensure_import_support. Therefore, - # we need to explicitly pass the signature_loader in. - - # take the last component of the module name - name = module.__name__.rsplit(".", 1)[-1] - # allow access as signature_loader.typing - setattr(loader, name, module) - # put into sys.modules as a package to allow all import options - fullname = "{}.{}".format(loader.__name__, name) - sys.modules[fullname] = module - - put_into_loader_package(typing) - put_into_loader_package(inspect) - from support.signature import mapping as sbk_mapping - sbk_mapping.__name__ = "sbk_mapping" - put_into_loader_package(sbk_mapping) - # We may or may not use PySide. - try: - from PySide2.support.signature import mapping - except ModuleNotFoundError: - mapping = sbk_mapping - mapping.__name__ = "mapping" - put_into_loader_package(mapping) - from support.signature import errorhandler - put_into_loader_package(errorhandler) - from support.signature import layout - put_into_loader_package(layout) - from support.signature.lib import enum_sig - put_into_loader_package(enum_sig) - from support.signature.parser import pyside_type_init - put_into_loader_package(pyside_type_init) - put_into_loader_package(create_signature) - put_into_loader_package(seterror_argument) - put_into_loader_package(make_helptext) - - -# end of file diff --git a/sources/shiboken2/shibokenmodule/support/signature/mapping.py b/sources/shiboken2/shibokenmodule/support/signature/mapping.py deleted file mode 100644 index d4c630aca..000000000 --- a/sources/shiboken2/shibokenmodule/support/signature/mapping.py +++ /dev/null @@ -1,347 +0,0 @@ -############################################################################# -## -## Copyright (C) 2018 The Qt Company Ltd. -## Contact: https://www.qt.io/licensing/ -## -## This file is part of Qt for Python. -## -## $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$ -## -############################################################################# - -from __future__ import print_function, absolute_import - -""" -mapping.py - -This module has the mapping from the pyside C-modules view of signatures -to the Python representation. - -The PySide modules are not loaded in advance, but only after they appear -in sys.modules. This minimizes the loading overhead. -""" - -import sys -import struct -import os -import pkgutil - -from signature_loader import typing -from signature_loader.typing import TypeVar, Generic - -class ellipsis(object): - def __repr__(self): - return "..." - -ellipsis = ellipsis() -StringList = typing.List[str] -IntList = typing.List[int] -Point = typing.Tuple[float, float] -PointList = typing.List[Point] -IntMatrix = typing.List[IntList] -Variant = typing.Any -ModelIndexList = typing.List[int] -QImageCleanupFunction = typing.Callable - -# First time installing our own Pair type into typing. -T = TypeVar('T') -S = TypeVar('S') - -class Pair(Generic[T, S]): - __module__ = "typing" - -typing.Pair = Pair - - -# Building our own Char type, which is much nicer than -# Char = typing.Union[str, int] # how do I model the limitation to 1 char? - -# Copied from the six module: -def with_metaclass(meta, *bases): - """Create a base class with a metaclass.""" - # This requires a bit of explanation: the basic idea is to make a dummy - # metaclass for one level of class instantiation that replaces itself with - # the actual metaclass. - class metaclass(type): - - def __new__(cls, name, this_bases, d): - return meta(name, bases, d) - - @classmethod - def __prepare__(cls, name, this_bases): - return meta.__prepare__(name, bases) - return type.__new__(metaclass, 'temporary_class', (), {}) - -class _CharMeta(type): - def __repr__(self): - return '%s.%s' % (self.__module__, self.__name__) - - -class Char(with_metaclass(_CharMeta)): - """ - From http://doc.qt.io/qt-5/qchar.html : - - In Qt, Unicode characters are 16-bit entities without any markup or - structure. This class represents such an entity. It is lightweight, - so it can be used everywhere. Most compilers treat it like an - unsigned short. - - Here, we provide a simple implementation just to avoid long aliases. - """ - __module__ = "typing" - - def __init__(self, code): - if isinstance(code, int): - self.code = code & 0xffff - else: - self.code = ord(code) - - def __add__(self, other): - return chr(self.code) + other - - def __radd__(self, other): - return other + chr(self.code) - - def __repr__(self): - return "typing.Char({})".format(self.code) - -typing.Char = Char - - -MultiMap = typing.DefaultDict[str, typing.List[str]] - -# ulong_max is only 32 bit on windows. -ulong_max = 2*sys.maxsize+1 if len(struct.pack("L", 1)) != 4 else 0xffffffff -ushort_max = 0xffff - -GL_COLOR_BUFFER_BIT = 0x00004000 -GL_NEAREST = 0x2600 - -WId = int - -# from 5.9 -GL_TEXTURE_2D = 0x0DE1 -GL_RGBA = 0x1908 - - -class _NotCalled(str): - """ - Wrap some text with semantics - - This class is wrapped around text in order to avoid calling it. - There are three reasons for this: - - - some instances cannot be created since they are abstract, - - some can only be created after qApp was created, - - some have an ugly __repr__ with angle brackets in it. - - By using derived classes, good looking instances can be created - which can be used to generate source code or .pyi files. When the - real object is needed, the wrapper can simply be called. - """ - def __repr__(self): - suppress = "support.signature.typing27." - text = self[len(suppress):] if self.startswith(suppress) else self - return "{}({})".format(type(self).__name__, text) - - def __call__(self): - from signature_loader.mapping import __dict__ as namespace - text = self if self.endswith(")") else self + "()" - return eval(text, namespace) - -USE_PEP563 = sys.version_info[:2] >= (3, 7) - - -# Some types are abstract. They just show their name. -class Virtual(_NotCalled): - pass - -# Other types I simply could not find. -class Missing(_NotCalled): - if not USE_PEP563: - # The string must be quoted, because the object does not exist. - def __repr__(self): - return '{}("{}")'.format(type(self).__name__, self) - - -class Invalid(_NotCalled): - pass - -# Helper types -class Default(_NotCalled): - pass - - -class Instance(_NotCalled): - pass - - -class Reloader(object): - """ - Reloder class - - This is a singleton class which provides the update function for the - shiboken and PySide classes. - """ - ## Note: We needed to rename shiboken2 in order to avoid a name clash. - _uninitialized = "Shiboken minimal sample other smart".split() - _prefixes = [""] - - def __init__(self): - self.sys_module_count = 0 - self.uninitialized = self._uninitialized - - def update(self, g=None): - """ - update is responsible to import all modules from shiboken and PySide - which are already in sys.modules. - The purpose is to follow all user imports without introducing new - ones. - This function is called by pyside_type_init to adapt imports - when the number of imported modules has changed. - """ - if self.sys_module_count == len(sys.modules): - return - self.sys_module_count = len(sys.modules) - if g is None: - g = globals() - for mod_name in self.uninitialized[:]: - for prefix in self._prefixes: - import_name = prefix + mod_name - if import_name in sys.modules: - # check if this is a real module - check_module(sys.modules[import_name]) - # module is real - self.uninitialized.remove(mod_name) - proc_name = "init_" + mod_name - if proc_name in g: - # Do the 'import {import_name}' first. - # 'top' is PySide2 when we do 'import PySide.QtCore' - # or Shiboken if we do 'import Shiboken'. - # Convince yourself that these two lines below have the same - # global effect as "import Shiboken" or "import PySide2.QtCore". - top = __import__(import_name) - g[top.__name__] = top - # Modules are in place, we can update the type_map. - g.update(g[proc_name]()) - -def check_module(mod): - # During a build, there exist the modules already as directories, - # although the '*.so' was not yet created. This causes a problem - # in Python 3, because it accepts folders as namespace modules - # without enforcing an '__init__.py'. - if not getattr(mod, "__file__", None) or os.path.isdir(mod.__file__): - mod_name = mod.__name__ - raise ImportError("Module '{mod_name}' is at most a namespace!" - .format(**locals())) - - -update_mapping = Reloader().update -type_map = {} -namespace = globals() # our module's __dict__ - -type_map.update({ - "QList": typing.List, - "QVector": typing.List, - "QSet": typing.Set, - "QPair": Pair, - }) - - -def init_Shiboken(): - type_map.update({ - "shiboken2.bool": bool, - "size_t": int, - "PyType": type, - }) - return locals() - - -def init_minimal(): - type_map.update({ - "MinBool": bool, - }) - return locals() - - -def init_sample(): - import datetime - type_map.update({ - "double": float, - "sample.int": int, - "Complex": complex, - "sample.OddBool": bool, - "sample.bool": bool, - "sample.PStr": str, - "OddBool": bool, - "PStr": str, - "char": Char, - "sample.char": Char, - "sample.Point": Point, - "sample.ObjectType": object, - "std.string": str, - "HANDLE": int, - "Foo.HANDLE": int, - "sample.Photon.TemplateBase": Missing("sample.Photon.TemplateBase"), - "ObjectType.Identifier": Missing("sample.ObjectType.Identifier"), - "zero(HANDLE)": 0, - "Null": None, - "zero(sample.ObjectType)": None, - "std.size_t": int, - 'Str("<unknown>")': "<unknown>", - 'Str("<unk")': "<unk", - 'Str("nown>")': "nown>", - "zero(sample.ObjectModel)": None, - "sample.unsigned char": Char, - "sample.double": float, - "zero(sample.bool)": False, - "PyDate": datetime.date, - "ZeroIn": 0, - }) - return locals() - - -def init_other(): - import numbers - type_map.update({ - "other.Number": numbers.Number, - "other.ExtendsNoImplicitConversion": Missing("other.ExtendsNoImplicitConversion"), - }) - return locals() - - -def init_smart(): - type_map.update({ - "smart.SharedPtr": Missing("smart.SharedPtr"), # bad object "SharedPtr<Obj >" - }) - return locals() - -# end of file |