diff options
author | Friedemann Kleint <Friedemann.Kleint@qt.io> | 2019-12-05 18:36:06 +0100 |
---|---|---|
committer | Friedemann Kleint <Friedemann.Kleint@qt.io> | 2019-12-05 18:36:06 +0100 |
commit | da5b3470a0ce57f8441485c7b146cdb3c1d2f331 (patch) | |
tree | 030a47ff04145b05eb8160575243a73230dc24a0 /sources | |
parent | d0fbcc90bd02090f921313dafecba20065fb2eb5 (diff) | |
parent | 37a1e27d49a6a1f7e45621e93a0f13a63fb20d9e (diff) |
Merge remote-tracking branch 'origin/5.14' into 5.15
Change-Id: I779defc33a4bab15cfde1e276d6d78c476a47e0f
Diffstat (limited to 'sources')
42 files changed, 1044 insertions, 666 deletions
diff --git a/sources/pyside2/PySide2/QtQml/pysideqmlregistertype.cpp b/sources/pyside2/PySide2/QtQml/pysideqmlregistertype.cpp index 6427e5198..fb9a5a0cf 100644 --- a/sources/pyside2/PySide2/QtQml/pysideqmlregistertype.cpp +++ b/sources/pyside2/PySide2/QtQml/pysideqmlregistertype.cpp @@ -236,7 +236,7 @@ void propListTpFree(void *self) static PyType_Slot PropertyListType_slots[] = { {Py_tp_init, (void *)propListTpInit}, {Py_tp_free, (void *)propListTpFree}, - {Py_tp_dealloc, (void *)object_dealloc}, + {Py_tp_dealloc, (void *)Sbk_object_dealloc}, {0, 0} }; static PyType_Spec PropertyListType_spec = { @@ -450,7 +450,7 @@ static PyType_Slot QtQml_VolatileBoolType_slots[] = { {Py_tp_str, (void *)reinterpret_cast<reprfunc>(QtQml_VolatileBoolObject_str)}, {Py_tp_methods, (void *)QtQml_VolatileBoolObject_methods}, {Py_tp_new, (void *)QtQml_VolatileBoolObject_new}, - {Py_tp_dealloc, (void *)object_dealloc}, + {Py_tp_dealloc, (void *)Sbk_object_dealloc}, {0, 0} }; static PyType_Spec QtQml_VolatileBoolType_spec = { diff --git a/sources/pyside2/doc/CMakeLists.txt b/sources/pyside2/doc/CMakeLists.txt index ee0fc0c51..8eb4eca06 100644 --- a/sources/pyside2/doc/CMakeLists.txt +++ b/sources/pyside2/doc/CMakeLists.txt @@ -137,19 +137,9 @@ add_dependencies(apidoc docrsts licensedocrsts) add_dependencies(licensedocrsts docrsts) add_dependencies(docrsts qdoc) -# #create devhelp file -# add_custom_target(apidevhelp -# COMMAND python;${CMAKE_CURRENT_SOURCE_DIR}/pyhtml2devhelp.py;${CMAKE_BINARY_DIR}/apidoc/html;index.html > -# ${CMAKE_BINARY_DIR}/apidoc/html/PySide.devhelp;${BINDING_API_VERSION}&&; -# gzip;-9v;-f;${CMAKE_BINARY_DIR}/apidoc/html/PySide.devhelp -# COMMAND ${CMAKE_COMMAND} -E make_directory "${CMAKE_INSTALL_PREFIX}/share/devhelp/books" -# COMMAND ${CMAKE_COMMAND} -E create_symlink "${CMAKE_INSTALL_PREFIX}/share/doc/${BINDING_NAME}/html" "${CMAKE_INSTALL_PREFIX}/share/devhelp/books/${BINDING_NAME}" -# ) #install files add_custom_target(apidocinstall COMMAND mkdir -p ${CMAKE_INSTALL_PREFIX}/share/doc/PySide2-${BINDING_API_VERSION} && cp -rv ${CMAKE_CURRENT_BINARY_DIR}/html/* ${CMAKE_INSTALL_PREFIX}/share/doc/PySide-${BINDING_API_VERSION} ) add_dependencies(apidocinstall apidoc) -# add_dependencies(apidocinstall apidevhelp) - diff --git a/sources/pyside2/doc/_themes/pysidedocs/static/pyside.css b/sources/pyside2/doc/_themes/pysidedocs/static/pyside.css index 23e460262..19275b545 100644 --- a/sources/pyside2/doc/_themes/pysidedocs/static/pyside.css +++ b/sources/pyside2/doc/_themes/pysidedocs/static/pyside.css @@ -1020,7 +1020,8 @@ body { color:#404244; } ol,ul { - list-style:none + list-style-type: square; + color: #17a81a; } .body ol,.body ul { margin-top:0.75em; @@ -1463,7 +1464,7 @@ div.pre { height:auto } pre, .LegaleseLeft { - background-color:#3a4055; + background-color:#222840; color:#fff; display:block; font-family:"Droid Sans Mono"; @@ -1544,6 +1545,13 @@ pre span.wrap { margin:4px; opacity:0.65 } + +span.pre { + color: #09102d; + background-color: #e4e4e4; + padding: 3px; +} + span.wrap:hover { opacity:1 } @@ -2013,3 +2021,52 @@ a.plink, a.headerlink { a.plink::before { content:'\00B6' } + +table.special { + border: 3px; + padding: 0px; + border-collapse: separate; + border-spacing: 20px; + line-height: 1.5em; +} + +.special p { + text-align: center; + color: #3a4055; +} + +.special a { + display: block; + border-bottom: 0; + text-decoration: none; +} + +.special a:hover { + border-bottom: 0; + text-decoration: none; +} + +.special strong { + color: #17a81a; + font-size: 110%; + font-weight: normal; +} + +table.special th, +table.special td { + border: 1px solid #888; + padding-top: 14px; + padding-bottom: 14px; + padding-left: 6px; + padding-right: 5px; + border-radius: 5px; + -moz-border-radius: 5px; + -webkit-border-radius: 5px; + -khtml-border-radius: 5px; +} + +.special td:hover { + padding-top: 2px; + padding-bottom: 2px; + border-bottom: 4px solid #41cd52; +} diff --git a/sources/pyside2/doc/api.rst b/sources/pyside2/doc/api.rst new file mode 100644 index 000000000..34d065f49 --- /dev/null +++ b/sources/pyside2/doc/api.rst @@ -0,0 +1,67 @@ +.. _pyside-api: +|project| Modules +================= + +Basic modules +------------- + These are the main modules that will help you build a Widget based UI. + + :mod:`Qt Core <PySide2.QtCore>` + Provides core non-GUI functionality, like signal and slots, properties, base classes of item models, serialization, etc. + :mod:`Qt GUI <PySide2.QtGui>` + Extends QtCore with GUI functionality: Events, windows and screens, OpenGL and raster-based 2D painting, images. + :mod:`Qt Widgets <PySide2.QtWidgets>` + Ready to use Widgets for your application, including also graphical elements for your UI. + +QML and Qt Quick +---------------- + If you want to use the `QML Language <https://doc.qt.io/qt-5.qmlapplications>`, these + modules will help you interact with it from Python. + + :mod:`Qt QML <PySide2.QtQml>` + Base Python API to interact with the QML module. + :mod:`Qt Quick <PySide2.QtQuick>` + Provides classes for embedding Qt Quick in Qt applications. + :mod:`Qt QuickWidgets <PySide2.QtQuickWidgets>` + Provides the QQuickWidget class for embedding Qt Quick in widget-based applications. + +Data visualization +------------------ + + Charts and diagrams: these modules provide a large amount + of classes that can help you include these elements in your UI. + + :mod:`Qt Charts <PySide2.QtCharts>` + Provides a set of easy to use chart components. + :mod:`Qt DataVisualization <PySide2.QtDataVisualization>` + Provides a way to visualize data in 3D as bar, scatter, and surface graphs. + +Multimedia +----------- + + Audio, video, and hardware interaction: check these modules if you are + looking for multimedia solutions. + + :mod:`Qt Multimedia <PySide2.QtMultimedia>` + Provides low-level multimedia functionality. + :mod:`Qt MultimediaWidgets <PySide2.QtMultimediaWidgets>` + Provides the widget-based multimedia API. + +WebEngine +--------- + + If your project is based on a browser or the features around web + based applications, these modules will help you to interact with them. + + :mod:`Qt WebEngineWidgets <PySide2.QtWebEngineWidgets>` + Provides widgets that can handle web content. + :mod:`Qt WebChannel <PySide2.QtWebChannel>` + Enables peer-to-peer communication between a server and a client + (HTML/JavaScript or QML application). + +All the modules +--------------- + + Here is a complete list of modules supported by |pymodname|. + + :doc:`Modules <modules>` diff --git a/sources/pyside2/doc/considerations.rst b/sources/pyside2/doc/considerations.rst new file mode 100644 index 000000000..cf08947af --- /dev/null +++ b/sources/pyside2/doc/considerations.rst @@ -0,0 +1,85 @@ +.. _pysideapi2: + +|project| Considerations +========================= + +API Changes +----------- + +One of the goals of |pymodname| is to be API compatible with PyQt5, +with certain exceptions. + +The latest considerations and known issues will be also reported +in the `wiki <https://wiki.qt.io/Qt_for_Python/Considerations>`_. + +__hash__() function return value +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The hash value returned for the classes :class:`PySide2.QtCore.QDate`, +:class:`PySide2.QtCore.QDateTime`, :class:`PySide2.QtCore.QTime`, :class:`PySide2.QtCore.QUrl` +will be based on their string representations, thus objects with the same value will produce the +same hash. + + +QString +~~~~~~~~ + +Methods and functions that change the contents of a QString argument were modified to receive an +immutable Python Unicode (or str) and return another Python Unicode/str as the modified string. + +The following methods had their return types modified this way: + +**Classes:** QAbstractSpinBox, QDateTimeEdit, QDoubleSpinBox, QSpinBox, QValidator + +* ``fixup(string): string`` +* ``validate(string, int): [QValidator.State, string, int]`` + +**Classes:** QDoubleValidator, QIntValidator, QRegExpValidator + +* ``validate(string, int): [QValidator.State, string, int]`` + +**Class:** QClipboard + +* ``text(string, QClipboard.Mode mode=QClipboard.Clipboard): [string, string]`` + +**Class:** QFileDialog + +Instead of ``getOpenFileNameAndFilter()``, ``getOpenFileNamesAndFilter()`` and +``getSaveFileNameAndFilter()`` like PyQt does, PySide has modified the original methods to return +a tuple. + +* ``getOpenFileName(QWidget parent=None, str caption=None, str dir=None, str filter=None, QFileDialog.Options options=0): [string, filter]`` +* ``getOpenFileNames(QWidget parent=None, str caption=None, str dir=None, str filter=None, QFileDialog.Options options=0): [list(string), filter]`` +* ``getSaveFileName(QWidget parent=None, str caption=None, str dir=None, str filter=None, QFileDialog.Options options=0): [string, filter]`` + +**Class:** QWebPage + +* ``javaScriptPrompt(QWebFrame, string, string): [bool, string]`` + +**Classes:** QFontMetrics and QFontMetricsF + +They had two new methods added. Both take a string of one character and convert to a QChar +(to call the C++ counterpart): + +* ``widthChar(string)`` +* ``boundingRectChar(string)`` + + +QTextStream +~~~~~~~~~~~ + +Inside this class some renames were applied to avoid clashes with native Python functions. +They are: ``bin_()``, ``hex_()`` and ``oct_()``. +The only modification was the addition of '_' character. + + +QVariant +~~~~~~~~ + +As ``QVariant`` was removed, any function expecting it can receive any Python object (``None`` is +an invalid ``QVariant``). +The same rule is valid when returning something: the returned ``QVariant`` will be converted to +the its original Python object type. + +When a method expects a ``QVariant::Type`` the programmer can use a string (the type name) or the +type itself. diff --git a/sources/pyside2/doc/contents.rst b/sources/pyside2/doc/contents.rst index c4867f250..2a6f08266 100644 --- a/sources/pyside2/doc/contents.rst +++ b/sources/pyside2/doc/contents.rst @@ -4,14 +4,15 @@ .. toctree:: :maxdepth: 2 - overview.rst - faq.rst + quickstart.rst gettingstarted.rst + api.rst tutorials/index.rst + examples/index.rst + videos.rst deployment.rst - pysideapi2.rst - licenses.rst - modules.rst + considerations.rst + shiboken2/index.rst Module Index ============ diff --git a/sources/pyside2/doc/deployment.rst b/sources/pyside2/doc/deployment.rst index c81e85c61..f33e3cac0 100644 --- a/sources/pyside2/doc/deployment.rst +++ b/sources/pyside2/doc/deployment.rst @@ -1,5 +1,5 @@ -Deployment -########## +|project| Deployment +==================== Deploying or freezing an application is a crucial part of many Python projects. Most large projects are not based on a single Python file, so @@ -10,23 +10,18 @@ Here are a few distribution options that you could use: 2. Building a proper `Python package (wheel) <https://packaging.python.org/>`_. 3. Freezing the application into a single binary file or a directory. -.. _fbs: https://build-system.fman.io/ - -.. _pyinstaller: https://www.pyinstaller.org/ - -.. _cxfreeze: https://anthony-tuininga.github.io/cx_Freeze/ - -.. _py2exe: http://www.py2exe.org/ - -.. _py2app: https://py2app.readthedocs.io/en/latest/ - If you choose the **third** option, consider using one of these tools: * `fbs`_ - * `PyInstaller <pyinstaller>`_ - * `cx_Freeze <cxfreeze>`_ + * `PyInstaller`_ + * `cx_Freeze`_ * `py2exe`_ * `py2app`_ +.. _fbs: https://build-system.fman.io/ +.. _PyInstaller: https://www.pyinstaller.org/ +.. _cx_Freeze: https://anthony-tuininga.github.io/cx_Freeze/ +.. _py2exe: http://www.py2exe.org/ +.. _py2app: https://py2app.readthedocs.io/en/latest/ |project| is a cross-platform framework, so we would like to focus on solutions that work on the three @@ -34,15 +29,56 @@ major platforms supported by Qt: Linux, macOS, and Windows. The following table summarizes the platform support for those packaging tools: -=========== ======= ===== ===== ======= -Name License Linux macOS Windows -=========== ======= ===== ===== ======= -fbs GPL yes yes yes -PyInstaller GPL yes yes yes -cx_Freeze MIT yes yes yes -py2exe MIT no no yes -py2app MIT no yes no -=========== ======= ===== ===== ======= +.. raw:: html + + <table class="docutils align-default"> + <thead> + <tr> + <th class="head">Name</th> + <th class="head">License</th> + <th class="head">Linux</th> + <th class="head">macOS</th> + <th class="head">Windows</th> + </tr> + </thead> + <tbody> + <tr> + <td><p>fbs</p></td> + <td><p>GPL</p></td> + <td><p style="color: green;">yes</p></td> + <td><p style="color: green;">yes</p></td> + <td><p style="color: green;">yes</p></td> + </tr> + <tr> + <td><p>PyInstaller</p></td> + <td><p>GPL</p></td> + <td><p style="color: green;">yes</p></td> + <td><p style="color: green;">yes</p></td> + <td><p style="color: green;">yes</p></td> + </tr> + <tr> + <td><p>cx_Freeze</p></td> + <td><p>MIT</p></td> + <td><p style="color: green;">yes</p></td> + <td><p style="color: green;">yes</p></td> + <td><p style="color: green;">yes</p></td> + </tr> + <tr> + <td><p>py2exe</p></td> + <td><p>MIT</p></td> + <td><p style="color: red;">no</p></td> + <td><p style="color: red;">no</p></td> + <td><p style="color: green;">yes</p></td> + </tr> + <tr> + <td><p>py2app</p></td> + <td><p>MIT</p></td> + <td><p style="color: red;">no</p></td> + <td><p style="color: green;">yes</p></td> + <td><p style="color: red;">no</p></td> + </tr> + </tbody> + </table> According to this table, only *fbs*, *cx_Freeze*, and *PyInstaller* meets our cross-platform requirement. @@ -57,7 +93,7 @@ to update your application packages. To create update packages, use the `PyUpdater <https://www.pyupdater.org/>`_, which is built around PyInstaller. -The `fbs <https://build-system.fman.io>`_ tool offers a nice UI +The `fbs`_ tool offers a nice UI that allows the user to install the application step-by-step. Here you can find a set of tutorials on how to use the previously diff --git a/sources/pyside2/doc/tutorials/examples/images/tabbedbrowser.png b/sources/pyside2/doc/examples/images/tabbedbrowser.png Binary files differindex 27c3daa09..27c3daa09 100644 --- a/sources/pyside2/doc/tutorials/examples/images/tabbedbrowser.png +++ b/sources/pyside2/doc/examples/images/tabbedbrowser.png diff --git a/sources/pyside2/doc/examples/index.rst b/sources/pyside2/doc/examples/index.rst new file mode 100644 index 000000000..6d2b56dca --- /dev/null +++ b/sources/pyside2/doc/examples/index.rst @@ -0,0 +1,14 @@ +|project| Examples +=================== + +A collection of examples are provided with |project| to help new users +to understand different use cases of the module. +You can find all the examples inside the ``pyside-setup`` on the ``examples`` +directory, or you can access them after installing |pymodname| from ``pip`` +inside the ``site-packages/PySide2/examples`` directory. + +.. toctree:: + :maxdepth: 1 + + tabbedbrowser.rst + ../pyside-examples/all-pyside-examples.rst diff --git a/sources/pyside2/doc/tutorials/examples/tabbedbrowser.rst b/sources/pyside2/doc/examples/tabbedbrowser.rst index c34c50647..c34c50647 100644 --- a/sources/pyside2/doc/tutorials/examples/tabbedbrowser.rst +++ b/sources/pyside2/doc/examples/tabbedbrowser.rst diff --git a/sources/pyside2/doc/faq.rst b/sources/pyside2/doc/faq.rst deleted file mode 100644 index aabd017e9..000000000 --- a/sources/pyside2/doc/faq.rst +++ /dev/null @@ -1,49 +0,0 @@ -Frequently Asked Questions -========================== - -**When was PySide2 adopted by The Qt Company?** - During April 2016 `The Qt Company <https://qt.io>`_ decided to properly support the port - (`see details <https://groups.google.com/forum/#!topic/pyside-dev/pqwzngAGLWE>`_). - -**PySide? Qt for Python? what is the name?** - The name of the project is Qt for Python and the name of the module is PySide2. - -**Why PySide2 and not just PySide?** - Since PySide was developed for Qt4, when the port was made to support Qt5, - the name is changed to PySide2 to imply that it was a newer version. - -**Where I can find information about the old PySide project?** - The old wiki page of the project is available on PySide, but the project is deprecated - and there is no official support for it. We highly recommend not to use it. - -**My project is using PySide, how hard would it be to adapt it to PySide2?** - The changes are the same as between Qt4 and Qt5, and for PySide users it mostly means - adapting the import statements since many classes were moved from QtGui to QtWidgets. - Qt 5 is highly compatible with Qt 4. It is possible for developers of Qt 4 applications to - seamlessly move to Qt 5 with their current functionality and gradually develop new things, - leveraging all the great items Qt 5 makes possible. - -**Does PySide2 support Android and iOS development / deployment?** - At the moment there is no support for mobile platforms. - -**Does PySide2 have support for embedded Linux (Raspberry Pi, i.MX6 etc)?** - Not at the moment. - -**There are three wheels (pyside2, shiboken2, and shiboken2_generator), what is the different between them?** - - Before the official release, everything was in one big wheel, but it made sense to split - the projects in three different wheels: - - * **pyside2**: contains all the PySide2 modules to use the Qt framework. - Also depends on the shiboken2 module. - * **shiboken2**: contains the shiboken2 module with helper functions for PySide2. - * **shiboken2_generator**: contains the generator binary that can work with a C++ project - and a typesystem to generate Python bindings. - Take into account that if you want to generate bindings for a Qt/C++ project, - the linking to the Qt shared libraries will be missing, and you will need to do this by hand. - We recommend to build PySide2 from scratch to have everything properly linked. - -**Why shiboken2_generator is not installed automatically?** - It's not necessary to install it to use PySide2. - The package is the result of the wheel splitting process. - To use the generator, it's recommended to build it from scratch to have the proper Qt-linking. diff --git a/sources/pyside2/doc/gettingstarted-linux.rst b/sources/pyside2/doc/gettingstarted-linux.rst new file mode 100644 index 000000000..fd5b83223 --- /dev/null +++ b/sources/pyside2/doc/gettingstarted-linux.rst @@ -0,0 +1,94 @@ +Getting Started on Linux +========================== + +Requirements +------------ + + * Qt package from `here`_ or a custom build of Qt (preferably Qt 5.12 or greater) + * A Python interpreter (version Python 3.5+ or Python 2.7). + + * You can use the one provided by your OS, or you can get python from the `official website`_. + * GCC, + * `CMake`_ version 3.1 or greater + * Git version 2 or greater + * `libclang_` from your system or from the `precompiled Qt packages`_ is recommended. + * ``virtualenv`` is strongly recommended, but optional. + * ``sphinx`` package for the documentation (optional). + * Depending on your OS, other dependencies packages might be required: + + * ``libgl-dev, python-dev, python-distutils, and python-setuptools``. + +.. _here: https://qt.io/download +.. _official website: https://www.python.org/downloads/ +.. _CMake: https://cmake.org/download/ +.. _libclang: http://download.qt.io/development_releases/prebuilt/libclang/ + + +Building from source +-------------------- + +Creating a virtual environment +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +``virtualenv`` allows you to create a local, user-writeable copy of a python environment into +which arbitrary modules can be installed and which can be removed after use:: + + virtualenv testenv + source testenv/bin/activate + pip install sphinx # optional: documentation + pip install numpy PyOpenGL # optional: for examples + +will create and use a new virtual environment, which is indicated by the command prompt changing. + +Setting up CLANG +~~~~~~~~~~~~~~~~ + +If you don't have libclang already in your system, you can download from the Qt servers:: + + wget https://download.qt.io/development_releases/prebuilt/libclang/libclang-release_60-linux-Rhel7.2-gcc5.3-x86_64-clazy.7z + +Extract the files, and leave it on any desired path, and then set these two required +environment variables:: + + 7z x libclang-release_60-linux-Rhel7.2-gcc5.3-x86_64-clazy.7z + export CLANG_INSTALL_DIR=$PWD/libclang + +Getting PySide2 +~~~~~~~~~~~~~~~ + +Cloning the official repository can be done by:: + + git clone --recursive https://code.qt.io/pyside/pyside-setup + +Checking out the version that we want to build, e.g. 5.14:: + + cd pyside-setup && git checkout 5.14 + +.. note:: Keep in mind you need to use the same version as your Qt installation. + Additionally, ``git checkout -b 5.14 --track origin/5.14`` could be a better option + in case you want to work on it. + +Building PySide2 +~~~~~~~~~~~~~~~~ + +Check your Qt installation path, to specifically use that version of qmake to build PySide2. +e.g. ``/opt/Qt/5.14.0/gcc_64/bin/qmake``. + +Build can take a few minutes, so it is recommended to use more than one CPU core:: + + python setup.py build --qmake=/opt/Qt/5.14.0/gcc_64/bin/qmake --build-tests --ignore-git --parallel=8 + +Installing PySide2 +~~~~~~~~~~~~~~~~~~ + +To install on the current directory, just run:: + + python setup.py install --qmake=/opt/Qt/5.14.0/gcc_64/bin/qmake --build-tests --ignore-git --parallel=8 + +Test installation +~~~~~~~~~~~~~~~~~ + +You can execute one of the examples to verify the process is properly working. +Remember to properly set the environment variables for Qt and PySide2:: + + python examples/widgets/widgets/tetrix.py diff --git a/sources/pyside2/doc/gettingstarted-macOS.rst b/sources/pyside2/doc/gettingstarted-macOS.rst new file mode 100644 index 000000000..11305247f --- /dev/null +++ b/sources/pyside2/doc/gettingstarted-macOS.rst @@ -0,0 +1,93 @@ +Getting Started on macOS +======================== + +Requirements +------------ + + * Qt package from `here`_ or a custom build of Qt (preferably Qt 5.12 or greater) + * A Python interpreter (version Python 3.5+ or Python 2.7). + + * You can use the one provided by HomeBrew, or you can get python from the `official website`_. + * `XCode`_ 8.2 (macOS 10.11), 8.3.3 (macOS 10.12), 9 (macOS 10.13), 10.1 (macOS 10.14) + * `CMake`_ version 3.1 or greater + * Git version 2 or greater + * `libclang_` from your system or from the `precompiled Qt packages`_ is recommended. + * ``virtualenv`` is strongly recommended, but optional. + * ``sphinx`` package for the documentation (optional). + * Depending on your OS, other dependencies packages might be required: + + * ``libgl-dev, python-dev, python-distutils, and python-setuptools``. + +.. _XCode: https://developer.apple.com/xcode/ +.. _here: https://qt.io/download +.. _official website: https://www.python.org/downloads/ +.. _CMake: https://cmake.org/download/ +.. _libclang: http://download.qt.io/development_releases/prebuilt/libclang/ + + +Building from source +-------------------- + +Creating a virtual environment +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +``virtualenv`` allows you to create a local, user-writeable copy of a python environment into +which arbitrary modules can be installed and which can be removed after use:: + + virtualenv testenv + source testenv/bin/activate + pip install sphinx # optional: documentation + pip install numpy PyOpenGL # optional: for examples + +will create and use a new virtual environment, which is indicated by the command prompt changing. + +Setting up CLANG +~~~~~~~~~~~~~~~~ + +If you don't have libclang already in your system, you can download from the Qt servers:: + + wget https://download.qt.io/development_releases/prebuilt/libclang/libclang-release_60-mac-clazy.7z + +Extract the files, and leave it on any desired path, and then set these two required +environment variables:: + + 7z x libclang-release_60-linux-Rhel7.2-gcc5.3-x86_64-clazy.7z + export CLANG_INSTALL_DIR=$PWD/libclang + +Getting PySide2 +~~~~~~~~~~~~~~~ + +Cloning the official repository can be done by:: + + git clone --recursive https://code.qt.io/pyside/pyside-setup + +Checking out the version that we want to build, e.g. 5.14:: + + cd pyside-setup && git checkout 5.14 + +.. note:: Keep in mind you need to use the same version as your Qt installation + +Building PySide2 +~~~~~~~~~~~~~~~~ + +Check your Qt installation path, to specifically use that version of qmake to build PySide2. +e.g. ``/opt/Qt/5.14.0/gcc_64/bin/qmake``. + +Build can take a few minutes, so it is recommended to use more than one CPU core:: + + python setup.py build --qmake=/opt/Qt/5.14.0/gcc_64/bin/qmake --build-tests --ignore-git --parallel=8 + +Installing PySide2 +~~~~~~~~~~~~~~~~~~ + +To install on the current directory, just run:: + + python setup.py install --qmake=/opt/Qt/5.14.0/gcc_64/bin/qmake --build-tests --ignore-git --parallel=8 + +Test installation +~~~~~~~~~~~~~~~~~ + +You can execute one of the examples to verify the process is properly working. +Remember to properly set the environment variables for Qt and PySide2:: + + python examples/widgets/widgets/tetrix.py diff --git a/sources/pyside2/doc/gettingstarted-windows.rst b/sources/pyside2/doc/gettingstarted-windows.rst new file mode 100644 index 000000000..dea781545 --- /dev/null +++ b/sources/pyside2/doc/gettingstarted-windows.rst @@ -0,0 +1,104 @@ +Getting Started on Windows +========================== + +The Qt library has to be built with the same version of MSVC as Python and PySide2, this can be +selected when using the online installer. + +Requirements +------------ + + * Qt package from `here`_ or a custom build of Qt (preferably Qt 5.12 or greater) + * A Python interpreter (version Python 3.5+). + + * Preferably get python from the `official website`_. + + .. note:: Python 2.7 interpreter is not supported. + The official Python 2.7 binary package which can be downloaded at + https://www.python.org/downloads/ is built using MSVC 2007, while + the Qt libraries are built using MSVC 2015/2017. + Note that if you build your own custom Python2.7 interpreter with + an MSVC version equivalent to the one that Qt was built with, + you can safely build and use Qt for Python against that interpreter. + + * `MSVC2017`_ (or MSVC2019) for Python 3 on Windows, + * `CMake`_ version 3.1 or greater + * `Git`_ version 2 or greater + * `libclang_` from the `precompiled Qt packages`_ is recommended. + * `OpenSSL`_ (optional for SSL support, Qt must have been configured using the same SSL library) + * ``virtualenv`` is strongly recommended, but optional. + * ``sphinx`` package for the documentation (optional). + +.. _here: https://qt.io/download +.. _official website: https://www.python.org/downloads/ +.. _MSVC2017: https://visualstudio.microsoft.com/thank-you-downloading-visual-studio/?sku=BuildTools +.. _CMake: https://cmake.org/download/ +.. _Git: https://git-scm.com/download/win +.. _libclang: http://download.qt.io/development_releases/prebuilt/libclang/ +.. _OpenSSL: https://sourceforge.net/projects/openssl/ + + +Building from source on Windows 10 +---------------------------------- + +Creating a virtual environment +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +``virtualenv`` allows you to create a local, user-writeable copy of a python environment into +which arbitrary modules can be installed and which can be removed after use:: + + virtualenv testenv + call testenv\scripts\activate + pip install sphinx # optional: documentation + pip install numpy PyOpenGL # optional: for examples + +will create and use a new virtual environment, which is indicated by the command prompt changing. + +Setting up CLANG +~~~~~~~~~~~~~~~~ + +If you don't have libclang already in your system, you can download from the Qt servers, +e.g. ``libclang-release_60-windows-vs2015_64-clazy.7z``. + +Extract the files, and leave it on any desired path, e.g ``c:\``, and then set these two required +environment variables:: + + set LLVM_INSTALL_DIR=c:\libclang + set PATH=C:\libclang\bin;%PATH% + +Getting PySide2 +~~~~~~~~~~~~~~~ + +Cloning the official repository can be done by:: + + git clone --recursive https://code.qt.io/pyside/pyside-setup + +Checking out the version that we want to build, e.g. 5.14:: + + cd pyside-setup && git checkout 5.14 + +.. note:: Keep in mind you need to use the same version as your Qt installation + +Building PySide2 +~~~~~~~~~~~~~~~~ + +Check your Qt installation path, to specifically use that version of qmake to build PySide2. +e.g. ``E:\Qt\5.12.0\msvc2015_64\bin\qmake.exe``. + +Build can take a few minutes, so it is recommended to use more than one CPU core:: + + python setup.py build --qmake=c:\path\to\qmake.exe --openssl=c:\path\to\openssl\bin --build-tests --ignore-git --parallel=8 + +Installing PySide2 +~~~~~~~~~~~~~~~~~~ + +To install on the current directory, just run:: + + python setup.py install --qmake=c:\path\to\qmake.exe --openssl=c:\path\to\openssl\bin --build-tests --ignore-git --parallel=8 + +Test installation +~~~~~~~~~~~~~~~~~ + +You can execute one of the examples to verify the process is properly working. +Remember to properly set the environment variables for Qt and PySide2:: + + python examples/widgets/widgets/tetrix.py diff --git a/sources/pyside2/doc/gettingstarted.rst b/sources/pyside2/doc/gettingstarted.rst index 0ee6a9173..5d3ea3c31 100644 --- a/sources/pyside2/doc/gettingstarted.rst +++ b/sources/pyside2/doc/gettingstarted.rst @@ -1,115 +1,111 @@ -=============== -Getting Started -=============== +|project| Getting Started +========================== -To develop with |project|, you must install Python, Clang, and |project|. +This page is focused on building |project| from source, if you just want to install |pymodname| +with ``pip`` you need to run:: -Preparing for the Installation -============================== + pip install pyside2 -Before you can install |project|, you must install the following software: +for more details, refer to our `Quick Start`_ guide. -* Python 3.5+ or 2.7 -* libclang 5.0+ (for Qt 5.11) or 6.0+ (for Qt 5.12) -* Recommended: a virtual environment, such as `venv <https://docs.python.org/3/library/venv.html>`_ or `virtualenv <https://virtualenv.pypa.io/en/stable/installation>`_ +.. _Quick Start: quickstart.html -Installing |project| -==================== +General Requirements +-------------------- -After you have installed the required software, you are ready to install the |project| -packages using the pip wheel. Run the following command from your command -prompt to install:: + * **Python**: 3.5+ and 2.7 + * **Qt:** 5.12+ is recommended + * **libclang:** The libclang library, recommended: version 6 for PySide2 5.12. + Prebuilt versions of it can be `downloaded here`_. + * **CMake:** 3.1+ is needed. - pip install PySide2 # For the latest version on PyPi +.. _downloaded here: http://download.qt.io/development_releases/prebuilt/libclang/ -or:: +Guides per platform +------------------- - pip install --index-url=http://download.qt.io/snapshots/ci/pyside/5.12/latest pyside2 --trusted-host download.qt.io +You can refer to the following pages for platform specific instructions: -Testing the Installation -======================== + * `Windows`_, + * `macOS`_, + * `Linux`_, + * Mobile platforms (iOS/Android) **(no support)** + * Embedded platforms **(no official support)** -Now that you have |project| installed, you can test your setup by running the following Python -constructs to print version information:: + .. note:: Most Linux-based embedded OS provide PySide2 with their official + package manager (e.g. `Raspbian`_ and `ArchlinuxARM`_). - import PySide2.QtCore +.. _Windows: gettingstarted-windows.html +.. _macOS: gettingstarted-macOS.html +.. _Linux: gettingstarted-linux.html +.. _Raspbian: https://www.raspbian.org/ +.. _ArchlinuxARM: https://archlinuxarm.org/ - # Prints PySide2 version - # e.g. 5.11.1a1 - print(PySide2.__version__) +A normal building command will look like this:: - # Gets a tuple with each version component - # e.g. (5, 11, 1, 'a', 1) - print(PySide2.__version_info__) + python setup.py install --qmake=/path/to/qmake \ + --ignore-git \ + --debug \ + --build-tests \ + --parallel=8 \ + --make-spec=ninja \ + --verbose-build \ + --module-subset=Core,Gui,Widgets - # Prints the Qt version used to compile PySide2 - # e.g. "5.11.2" - print(PySide2.QtCore.__version__) +Which will build and install the project with **debug** symbols, including the **tests**, +using **ninja** (instead of make), and considering only the **module subset** of QtCore, QtGUI +and QtWidgets. - # Gets a tuple with each version components of Qt used to compile PySide2 - # e.g. (5, 11, 2) - print(PySide2.QtCore.__version_info__) +Other important options to consider are: + * ``--cmake``, to specify the path to the cmake binary, + * ``--reuse-build``, to rebuild only the modified files, + * ``--openssl=/path/to/openssl/bin``, to use a different path for OpenSSL, + * ``--standalone``, to copy over the Qt libraries into the final package + to make it work on other machines. -Creating a Simple Application -============================= +Testing the installation +------------------------- -Your |project| setup is ready, so try exploring it further by developing a simple application -that prints "Hello World" in several languages. The following instructions will -guide you through the development process: +Once the installation finishes, you will be able to execute any of our examples:: -* Create a new file named :code:`hello_world.py`, and add the following imports to it. + python examples/widgets/widgets/tetrix.py - :: +Running Tests +-------------- - import sys - import random - from PySide2 import QtCore, QtWidgets, QtGui +Using the ``--build-tests`` option will enable us to run all the auto tests inside the project:: - The |pymodname| Python module provides access to the Qt APIs as its submodule. - In this case, you are importing the :code:`QtCore`, :code:`QtWidgets`, and :code:`QtGui` submodules. + python testrunner.py test > testlog.txt -* Define a class named :code:`MyWidget`, which extends QWidget and includes a QPushButton and QLabel. +.. note:: On Windows, don't forget to have qmake in your path + (``set PATH=E:\Path\to\Qt\5.14\msvc2017_64\bin;%PATH%``) - :: +You can also run a specific test (for example ``qpainter_test``) by running:: - class MyWidget(QtWidgets.QWidget): - def __init__(self): - super().__init__() + ctest -R qpainter_test --verbose - self.hello = ["Hallo Welt", "Hei maailma", "Hola Mundo", "Привет мир"] +Building the documentation +--------------------------- - self.button = QtWidgets.QPushButton("Click me!") - self.text = QtWidgets.QLabel("Hello World") - self.text.setAlignment(QtCore.Qt.AlignCenter) +The documentation is being generated using **qdoc** to get the API information, and also **sphinx** +for the local Python related notes. - self.layout = QtWidgets.QVBoxLayout() - self.layout.addWidget(self.text) - self.layout.addWidget(self.button) - self.setLayout(self.layout) +The system required ``libxml2`` and `libxslt``, also on the Python environment, ``sphinx`` and +``graphviz`` need to be installed before running the installation process:: - self.button.clicked.connect(self.magic) + pip install graphviz sphinx +After installing ``graphviz`, the ``dot`` command needs to be in PATH, otherwise, +the process will fail. Installing ``graphviz`` system-wide is also an option. - def magic(self): - self.text.setText(random.choice(self.hello)) +Since the process rely on a Qt installation, you need to specify where the ``qtbase`` directory +you will use with your ``qmake`` is located:: - The MyWidget class has the :code:`magic` member function that - randomly chooses an item from the list :code:`hello`. This function - is called when you click the button. + export QT_SRC_DIR=/path/to/qtbase -* Now, add a main function where you instantiate :code:`MyWidget` and - :code:`show` it. +Once the build process finishes, you can go to the generated ``*_build/*_release/pyside2`` +directory, and run:: - :: + make apidoc - if __name__ == "__main__": - app = QtWidgets.QApplication([]) - - widget = MyWidget() - widget.resize(800, 600) - widget.show() - - sys.exit(app.exec_()) - -Your example is ready to be run. Try clicking the button at the bottom -and see which greeting you get. +Finally, you will get a ``html`` directory containing all the generated documentation. diff --git a/sources/pyside2/doc/index.rst b/sources/pyside2/doc/index.rst index acc1d6d40..5ffe405a5 100644 --- a/sources/pyside2/doc/index.rst +++ b/sources/pyside2/doc/index.rst @@ -1,87 +1,42 @@ |project| -************* - -|project| offers Python bindings for Qt, enabling the use of Qt5 APIs in Python -applications. It lets Python developers utilize the full potential of Qt, using -the |pymodname| module. - -The |pymodname| module provides access to the individual -Qt modules such as QtCore, QtGui, and so on. |project| also comes with the -:doc:`Shiboken2 <shiboken2:index>` CPython binding code generator, which can be -used to generate Python bindings for your C or C++ code. - -.. toctree:: - :name: mastertoc - :maxdepth: 2 - - contents.rst - Known issues <https://wiki.qt.io/Qt_for_Python/Considerations> - -Qt Modules -=========== - -Basic modules -------------- - These are the main modules that will help you build a Widget based UI. - - :mod:`Qt Core <PySide2.QtCore>` - Provides core non-GUI functionality, like signal and slots, properties, base classes of item models, serialization, etc. - :mod:`Qt Gui <PySide2.QtGui>` - Extends QtCore with GUI functionality: Events, windows and screens, OpenGL and raster-based 2D painting, images. - :mod:`Qt Widgets <PySide2.QtWidgets>` - Ready to use Widgets for your application, including also graphical elements for your UI. - -QML and Qt Quick ----------------- - If you want to use the `Qml Language <https://doc.qt.io/qt-5.qmlapplications>`, these - modules will help you interact with it from Python. - - :mod:`Qt Qml <PySide2.QtQml>` - Base Python API to interact with the QML module. - :mod:`Qt Quick <PySide2.QtQuick>` - Provides classes for embedding Qt Quick in Qt applications. - :mod:`Qt QuickWidgets <PySide2.QtQuickWidgets>` - Provides the QQuickWidget class for embedding Qt Quick in widget-based applications. - -Data visualization ------------------- - - Charts, diagrams, animations: these modules provide a large amount - of classes that can help you include these elements in your UI. - - :mod:`Qt Charts <PySide2.QtCharts>` - Provides a set of easy to use chart components. - :mod:`Qt DataVisualization <PySide2.QtDataVisualization>` - Provides a way to visualize data in 3D as bar, scatter, and surface graphs. - -Multimedia ------------ - - Audio, video, and hardware interaction: check these modules if you are - looking for multimedia solutions. - - :mod:`Qt Multimedia <PySide2.QtMultimedia>` - Provides low-level multimedia functionality. - :mod:`Qt MultimediaWidgets <PySide2.QtMultimediaWidgets>` - Provides the widget-based multimedia API. - -WebEngine ---------- - - If your project is based on a browser or the features around web - based applications, these modules will help you to interact with them. - - :mod:`Qt WebEngineWidgets <PySide2.QtWebEngineWidgets>` - Provides widgets that can handle web content. - :mod:`Qt WebChannel <PySide2.QtWebChannel>` - Enables peer-to-peer communication between a server and a client - (HTML/JavaScript or QML application). - -All the modules ---------------- - - There are many other modules currently supported by |pymodname|, - here you can find a complete list of them. - - :doc:`Check all the modules <modules>` - Display a table with all the currently supported Qt modules. +********* + +**Qt for Python** offers the official Python bindings for `Qt`_ (`PySide2`_), +enabling the use of its APIs in Python applications, and a binding generator tool (`Shiboken2`_) +which can be used to expose C++ projects into Python. + +|project| is available under the LGPLv3/GPLv3 and the Qt commercial license. + +.. _Qt: https://doc.qt.io +.. _PySide2: quickstart.html +.. _Shiboken2: shiboken2/index.html + +Documentation +============= + +.. raw:: html + + <table class="special"> + <colgroup> + <col style="width: 33%" /> + <col style="width: 33%" /> + <col style="width: 33%" /> + </colgroup> + <tr> + <td><a href="quickstart.html"><p><strong>Check It Out!</strong><br/>Write your first Qt app.</p></a></td> + <td><a href="gettingstarted.html"><p><strong>Getting Started</strong><br/>Install and build from source.</p></a></td> + <td><a href="api.html"><p><strong>API Docs</strong><br/>Qt for Python API reference.</p></a></td> + </tr> + + <tr> + <td><a href="tutorials/index.html"><p><strong>Tutorials</strong><br/>Learn with step-by-step guides.</p></a></td> + <td><a href="examples/index.html"><p><strong>Examples</strong><br/>Check all the available examples.</p></a></td> + <td><a href="videos.html"><p><strong>Videos</strong><br/>Watch webinars, Talks, and more.</p></a></td> + </tr> + + <tr> + <td><a href="deployment.html" style="display: block;"><p><strong>Deployment</strong><br/>Learn to deploy your apps.</p></a></td> + <td><a href="considerations.html" style="display: block;"><p><strong>Considerations</strong><br/>API differences and known issues.</p></a></td> + <td><a href="shiboken2/index.html" style="display: block;"><p><strong>Shiboken</strong><br/>Generate C++ to Python binding.</p></a></td> + </tr> + </table> diff --git a/sources/pyside2/doc/overview.rst b/sources/pyside2/doc/overview.rst deleted file mode 100644 index 88f03c4eb..000000000 --- a/sources/pyside2/doc/overview.rst +++ /dev/null @@ -1,24 +0,0 @@ -Overview -========= - -The |project| project provides a complete port of the PySide module to Qt 5. Development started on -GitHub in May 2015. Since then, the project has ported PySide to Qt 5.3, 5.4, and 5.5. - -In June 2018, the `PySide2` module was released as a Technical Preview (supporting Qt 5.11); it's -been fully supported since Qt 5.12. - -|project| is available under LGPLv3/GPLv2 and commercial license for the following platforms: - -+-------------+--------+--------+--------+--------+---------+---------+ -| | Linux | macOS | Windows | -+=============+========+========+========+========+=========+=========+ -| | 32bit | 64bit | 32bit | 64bit | 32bit | 64bit | -+-------------+--------+--------+--------+--------+---------+---------+ -| Python 2.7 | No (*) | Yes | No (*) | Yes | No (**) | No (**) | -+-------------+--------+--------+--------+--------+---------+---------+ -| Python 3.5+ | No (*) | Yes | No (*) | Yes | Yes | Yes | -+-------------+--------+--------+--------+--------+---------+---------+ - - * (*): `No Qt release <https://wiki.qt.io/Qt_5.12_Tools_and_Versions#Software_configurations_for_Qt_5.12.0>`_ - * (**): `MSVC issue with Python 2.7 and Qt <https://wiki.qt.io/Qt_for_Python/Considerations#Missing_Windows_.2F_Python_2.7_release>`_ - diff --git a/sources/pyside2/doc/pyhtml2devhelp.py b/sources/pyside2/doc/pyhtml2devhelp.py deleted file mode 100644 index aa39036d3..000000000 --- a/sources/pyside2/doc/pyhtml2devhelp.py +++ /dev/null @@ -1,256 +0,0 @@ -#! /usr/bin/python - -############################################################################# -## -## Copyright (C) 2016 The Qt Company Ltd. -## Copyright (C) 2009 Matthias Klose <doko@debian.org> -## Contact: https://www.qt.io/licensing/ -## -## This file is part of Qt for Python tools. -## -## $QT_BEGIN_LICENSE:GPL-EXCEPT$ -## 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 General Public License Usage -## Alternatively, this file may be used under the terms of the GNU -## General Public License version 3 as published by the Free Software -## Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -## 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-3.0.html. -## -## $QT_END_LICENSE$ -## -############################################################################# - -""" - This script is based on Python2.6 Ubuntu package script -""" - -import formatter, htmllib -import os, sys, re - -class PyHTMLParser(htmllib.HTMLParser): - pages_to_include = set(('index.html', 'PySide/QtHelp/index.html', 'PySide/QtSvg/index.html', - 'PySide/QtGui/index.html', 'PySide/QtNetwork/index.html', 'PySide/QtWebKit/index.html', - 'PySide/QtUiTools/index.html', 'PySide/QtXml/index.html', 'PySide/QtCore/index.html', - 'PySide/QtScriptTools/index.html', 'PySide/QtOpenGL/index.html', 'PySide/QtScript/index.html', - 'PySide/QtSql/index.html', 'howto-build/index.html')) - - def __init__(self, formatter, basedir, fn, indent, parents=set()): - htmllib.HTMLParser.__init__(self, formatter) - self.basedir = basedir - self.dir, self.fn = os.path.split(fn) - self.data = '' - self.parents = parents - self.link = {} - self.indent = indent - self.last_indent = indent - 1 - self.sub_indent = 0 - self.sub_count = 0 - self.next_link = False - - def process_link(self): - new_href = os.path.join(self.dir, self.link['href']) - text = self.link['text'] - indent = self.indent + self.sub_indent - if self.last_indent == indent: - print '%s</sub>' % (' ' * self.last_indent) - self.sub_count -= 1 - print '%s<sub link="%s" name="%s">' % (' ' * indent, new_href, text) - self.sub_count += 1 - self.last_indent = self.indent + self.sub_indent - - def start_li(self, attrs): - self.sub_indent += 1 - self.next_link = True - - def end_li(self): - indent = self.indent + self.sub_indent - if self.sub_count > 0: - print '%s</sub>' % (' ' * self.last_indent) - self.sub_count -= 1 - self.last_indent -= 1 - self.sub_indent -= 1 - - def start_a(self, attrs): - self.link = {} - for attr in attrs: - self.link[attr[0]] = attr[1] - self.data = '' - - def end_a(self): - process = False - text = self.data.replace('\t', '').replace('\n', ' ').replace('&', '&').replace('<', '<').replace('>', '>') - self.link['text'] = text - # handle a tag without href attribute - try: - href = self.link['href'] - except KeyError: - return - - abs_href = os.path.join(self.basedir, href) - if abs_href in self.parents: - return - if href.startswith('..') or href.startswith('http:') \ - or href.startswith('mailto:') or href.startswith('news:'): - return - if href in ('', 'about.html', 'modindex.html', 'genindex.html', 'glossary.html', - 'search.html', 'contents.html', 'download.html', 'bugs.html', - 'license.html', 'copyright.html'): - return - - if self.link.has_key('class'): - if self.link['class'] in ('biglink'): - process = True - if self.link['class'] in ('reference external'): - if self.next_link: - process = True - next_link = False - - if process == True: - self.process_link() - if href in self.pages_to_include: - self.parse_file(os.path.join(self.dir, href)) - - def finish(self): - if self.sub_count > 0: - print '%s</sub>' % (' ' * self.last_indent) - - def handle_data(self, data): - self.data += data - - def parse_file(self, href): - # TODO basedir bestimmen - parent = os.path.join(self.basedir, self.fn) - self.parents.add(parent) - parser = PyHTMLParser(formatter.NullFormatter(), - self.basedir, href, self.indent + 1, - self.parents) - text = file(self.basedir + '/' + href).read() - parser.feed(text) - parser.finish() - parser.close() - if parent in self.parents: - self.parents.remove(parent) - -class PyIdxHTMLParser(htmllib.HTMLParser): - def __init__(self, formatter, basedir, fn, indent): - htmllib.HTMLParser.__init__(self, formatter) - self.basedir = basedir - self.dir, self.fn = os.path.split(fn) - self.data = '' - self.link = {} - self.indent = indent - self.active = False - self.indented = False - self.nolink = False - self.header = '' - self.last_letter = 'Z' - self.last_text = '' - - def process_link(self): - new_href = os.path.join(self.dir, self.link['href']) - text = self.link['text'] - if not self.active: - return - if text.startswith('['): - return - if self.link.get('rel', None) in ('prev', 'parent', 'next', 'contents', 'index'): - return - if self.indented: - text = self.last_text + ' ' + text - else: - # Save it in case we need it again - self.last_text = re.sub(' \([\w\-\.\s]+\)', '', text) - indent = self.indent - print '%s<function link="%s" name="%s"/>' % (' ' * indent, new_href, text) - - def start_dl(self, attrs): - if self.last_text: - # Looks like we found the second part to a command - self.indented = True - - def end_dl(self): - self.indented = False - - def start_dt(self, attrs): - self.data = '' - self.nolink = True - - def end_dt(self): - if not self.active: - return - if self.nolink == True: - # Looks like we found the first part to a command - self.last_text = re.sub(' \([\w\-\.\s]+\)', '', self.data) - self.nolink = False - - def start_h2(self, attrs): - for k, v in attrs: - if k == 'id': - self.header = v - if v == '_': - self.active = True - - def start_td(self, attrs): - self.indented = False - self.last_text = '' - - def start_table(self, attrs): - pass - - def end_table(self): - if self.header == self.last_letter: - self.active = False - - def start_a(self, attrs): - self.nolink = False - self.link = {} - for attr in attrs: - self.link[attr[0]] = attr[1] - self.data = '' - - def end_a(self): - text = self.data.replace('\t', '').replace('\n', ' ').replace('&', '&').replace('<', '<').replace('>', '>') - self.link['text'] = text - # handle a tag without href attribute - try: - href = self.link['href'] - except KeyError: - return - self.process_link() - - def handle_data(self, data): - self.data += data - -def main(): - base = sys.argv[1] - fn = sys.argv[2] - - parser = PyHTMLParser(formatter.NullFormatter(), base, fn, indent=0) - print '<?xml version="1.0" encoding="iso-8859-1"?>' - print '<book title="PySide %s Documentation" name="PySide" version="%s" link="index.html">' % (sys.argv[3], sys.argv[3]) - print '<chapters>' - parser.parse_file(fn) - print '</chapters>' - - print '<functions>' - - fn = 'genindex.html' - parser = PyIdxHTMLParser(formatter.NullFormatter(), base, fn, indent=1) - text = file(base + '/' + fn).read() - parser.feed(text) - parser.close() - - print '</functions>' - print '</book>' - -main() - diff --git a/sources/pyside2/doc/pyside-examples/images/screenshot_hello.png b/sources/pyside2/doc/pyside-examples/images/screenshot_hello.png Binary files differnew file mode 100644 index 000000000..41ebbf01b --- /dev/null +++ b/sources/pyside2/doc/pyside-examples/images/screenshot_hello.png diff --git a/sources/pyside2/doc/pysideapi2.rst b/sources/pyside2/doc/pysideapi2.rst deleted file mode 100644 index e552bf21d..000000000 --- a/sources/pyside2/doc/pysideapi2.rst +++ /dev/null @@ -1,84 +0,0 @@ -.. _pysideapi2: - -Qt for Python API -******************* - -One of the goals of |pymodname| is to be API compatible with PyQt5, -with certain exceptions. For example, |pymodname| will not export C++ components -that are marked as deprecated by Qt. - -The latest considerations and known issues will be also reported -in the `wiki <https://wiki.qt.io/Qt_for_Python/Considerations>`_. - -__hash__() function return value -================================ - -The hash value returned for the classes :class:`PySide2.QtCore.QDate`, :class:`PySide2.QtCore.QDateTime`, :class:`PySide2.QtCore.QTime`, :class:`PySide2.QtCore.QUrl` will be -based on their string representations, thus objects with the same value will -produce the same hash. - - -QString -======= - -Methods that change QString arguments -------------------------------------- - -Methods and functions that change the contents of a QString argument were -modified to receive an immutable Python unicode (or str) and return another -Python unicode/str as the modified string. - -The following methods had their return types modified this way: - -**Classes:** QAbstractSpinBox, QDateTimeEdit, QDoubleSpinBox, QSpinBox, QValidator - -- *fixup(string)*: string -- *validate(string, int)*: [QValidator.State, string, int] - - -**Classes:** QDoubleValidator, QIntValidator, QRegExpValidator - -- *validate(string, int)*: [QValidator.State, string, int] - -**Class:** QClipboard - -- *text(string, QClipboard.Mode mode=QClipboard.Clipboard)*: [string, string] - - -**Class:** QFileDialog - -Instead of *getOpenFileNameAndFilter()*, *getOpenFileNamesAndFilter()* and *getSaveFileNameAndFilter()* like PyQt4 does, -PySide has modified the original methods to return a tuple. - -- *getOpenFileName(QWidget parent=None, str caption=None, str dir=None, str filter=None, QFileDialog.Options options=0)*: [string, filter] -- *getOpenFileNames(QWidget parent=None, str caption=None, str dir=None, str filter=None, QFileDialog.Options options=0)*: [list(string), filter] -- *getSaveFileName(QWidget parent=None, str caption=None, str dir=None, str filter=None, QFileDialog.Options options=0)*: [string, filter] - -**Class:** QWebPage - -- *javaScriptPrompt(QWebFrame, string, string)*: [bool, string] - -Other QString related changes ------------------------------ - -**Classes:** QFontMetrics and QFontMetricsF - -They had two new methods added. Both take a string of one character and convert to a QChar (to call the C++ counterpart): - -- widthChar(string) -- boundingRectChar(string) - - -QTextStream -=========== - -Inside this class some renames were applied to avoid clashes with native Python functions. They are: *bin_()*, *hex_()* and *oct_()*. -The only modification was the addition of '_' character. - - -QVariant -======== - -As QVariant was removed, any function expecting it can receive any Python object (None is an invalid QVariant). The same rule is valid when returning something: the returned QVariant will be converted to the its original Python object type. - -When a method expects a *QVariant::Type* the programmer can use a string (the type name) or the type itself. diff --git a/sources/pyside2/doc/quickstart.rst b/sources/pyside2/doc/quickstart.rst new file mode 100644 index 000000000..5d8ddfe2d --- /dev/null +++ b/sources/pyside2/doc/quickstart.rst @@ -0,0 +1,107 @@ +|project| Quick start +====================== + +Requirements +------------ + +Before you can install |project|, first you must install the following software: + + * Python 2.7 or 3.5+, + * We recommend using a virtual environment, such as + `venv <https://docs.python.org/3/library/venv.html>`_ or + `virtualenv <https://virtualenv.pypa.io/en/stable/installation>`_ + +Installation +------------ + +Now you are ready to install the |project| packages using ``pip``. +From the terminal, run the following command:: + + pip install PySide2 # For the latest version on PyPi + +or:: + + pip install --index-url=http://download.qt.io/snapshots/ci/pyside/5.14/latest pyside2 --trusted-host download.qt.io + +Test your Installation +---------------------- + +Now that you have |project| installed, you can test your setup by running the following Python +constructs to print version information:: + + import PySide2.QtCore + + # Prints PySide2 version + # e.g. 5.11.1a1 + print(PySide2.__version__) + + # Gets a tuple with each version component + # e.g. (5, 11, 1, 'a', 1) + print(PySide2.__version_info__) + + # Prints the Qt version used to compile PySide2 + # e.g. "5.11.2" + print(PySide2.QtCore.__version__) + + # Gets a tuple with each version components of Qt used to compile PySide2 + # e.g. (5, 11, 2) + print(PySide2.QtCore.__version_info__) + +Create a Simple Application +--------------------------- + +Your |project| setup is ready. You can explore it further by developing a simple application +that prints "Hello World" in several languages. The following instructions will +guide you through the development process: + +1. Create a new file named :code:`hello_world.py`, and add the following imports to it.:: + + import sys + import random + from PySide2 import QtCore, QtWidgets, QtGui + + The |pymodname| Python module provides access to the Qt APIs as its submodule. + In this case, you are importing the :code:`QtCore`, :code:`QtWidgets`, and :code:`QtGui` submodules. + +2. Define a class named :code:`MyWidget`, which extends QWidget and includes a QPushButton and + QLabel.:: + + class MyWidget(QtWidgets.QWidget): + def __init__(self): + super().__init__() + + self.hello = ["Hallo Welt", "Hei maailma", "Hola Mundo", "Привет мир"] + + self.button = QtWidgets.QPushButton("Click me!") + self.text = QtWidgets.QLabel("Hello World") + self.text.setAlignment(QtCore.Qt.AlignCenter) + + self.layout = QtWidgets.QVBoxLayout() + self.layout.addWidget(self.text) + self.layout.addWidget(self.button) + self.setLayout(self.layout) + + self.button.clicked.connect(self.magic) + + + def magic(self): + self.text.setText(random.choice(self.hello)) + + The MyWidget class has the :code:`magic` member function that randomly chooses an item from the + :code:`hello` list. When you click the button, the :code:`magic` function is called. + +3. Now, add a main function where you instantiate :code:`MyWidget` and :code:`show` it.:: + + if __name__ == "__main__": + app = QtWidgets.QApplication([]) + + widget = MyWidget() + widget.resize(800, 600) + widget.show() + + sys.exit(app.exec_()) + +Run your example. Try clicking the button at the bottom to see which greeting you get. + +.. image:: pyside-examples/images/screenshot_hello.png + :alt: Hello World application diff --git a/sources/pyside2/doc/tutorials/index.rst b/sources/pyside2/doc/tutorials/index.rst index 5b8fe9361..7486554f9 100644 --- a/sources/pyside2/doc/tutorials/index.rst +++ b/sources/pyside2/doc/tutorials/index.rst @@ -1,23 +1,12 @@ -Qt for Python examples and tutorials -************************************* +|project| Tutorials +==================== -A collection of examples and tutorials with "walkthrough" guides are +A collection of tutorials with "walkthrough" guides are provided with |project| to help new users get started. These documents were ported from C++ to Python and cover a range of topics, from basic use of widgets to step-by-step tutorials that show how an application is put together. -Examples and demos -=================== - -.. toctree:: - :maxdepth: 1 - - examples/tabbedbrowser.rst - ../pyside-examples/all-pyside-examples.rst - -Tutorials -========== .. toctree:: :maxdepth: 2 diff --git a/sources/pyside2/doc/videos.rst b/sources/pyside2/doc/videos.rst new file mode 100644 index 000000000..cda84f419 --- /dev/null +++ b/sources/pyside2/doc/videos.rst @@ -0,0 +1,28 @@ +|project| Videos +================ + +Webinar: Creating user interfaces with Qt for Python +---------------------------------------------------- + +.. 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/wKqLaNqxgas" frameborder="0" + allowfullscreen style="position: absolute; top: 0; left: 0; + width: 100%; height: 100%;"> + </iframe> + </div> + +Webinar: Develop your first Qt for Python 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/HDBjmSiOBxY" frameborder="0" + allowfullscreen style="position: absolute; top: 0; left: 0; + width: 100%; height: 100%;"> + </iframe> + </div> diff --git a/sources/pyside2/libpyside/pysideclassinfo.cpp b/sources/pyside2/libpyside/pysideclassinfo.cpp index fe5ca8765..c4bace77e 100644 --- a/sources/pyside2/libpyside/pysideclassinfo.cpp +++ b/sources/pyside2/libpyside/pysideclassinfo.cpp @@ -60,7 +60,7 @@ static PyType_Slot PySideClassInfoType_slots[] = { {Py_tp_init, (void *)classInfoTpInit}, {Py_tp_new, (void *)classInfoTpNew}, {Py_tp_free, (void *)classInfoFree}, - {Py_tp_dealloc, (void *)object_dealloc}, + {Py_tp_dealloc, (void *)Sbk_object_dealloc}, {0, 0} }; static PyType_Spec PySideClassInfoType_spec = { diff --git a/sources/pyside2/libpyside/pysidemetafunction.cpp b/sources/pyside2/libpyside/pysidemetafunction.cpp index e0e0c439b..637aa0598 100644 --- a/sources/pyside2/libpyside/pysidemetafunction.cpp +++ b/sources/pyside2/libpyside/pysidemetafunction.cpp @@ -62,7 +62,7 @@ static PyType_Slot PySideMetaFunctionType_slots[] = { {Py_tp_call, (void *)functionCall}, {Py_tp_new, (void *)PyType_GenericNew}, {Py_tp_free, (void *)functionFree}, - {Py_tp_dealloc, (void *)object_dealloc}, + {Py_tp_dealloc, (void *)Sbk_object_dealloc}, {0, 0} }; static PyType_Spec PySideMetaFunctionType_spec = { diff --git a/sources/pyside2/libpyside/pysideproperty.cpp b/sources/pyside2/libpyside/pysideproperty.cpp index d9d15eb3b..009a17a3e 100644 --- a/sources/pyside2/libpyside/pysideproperty.cpp +++ b/sources/pyside2/libpyside/pysideproperty.cpp @@ -210,6 +210,11 @@ int qpropertyTpInit(PyObject *self, PyObject *args, PyObject *kwds) void qpropertyDeAlloc(PyObject *self) { qpropertyClear(self); + if (PepRuntime_38_flag) { + // PYSIDE-939: Handling references correctly. + // This was not needed before Python 3.8 (Python issue 35810) + Py_DECREF(Py_TYPE(self)); + } Py_TYPE(self)->tp_free(self); } diff --git a/sources/pyside2/libpyside/pysideqflags.cpp b/sources/pyside2/libpyside/pysideqflags.cpp index fd0ed005f..33351440a 100644 --- a/sources/pyside2/libpyside/pysideqflags.cpp +++ b/sources/pyside2/libpyside/pysideqflags.cpp @@ -152,7 +152,7 @@ namespace QFlags #endif {Py_tp_new, (void *)PySideQFlagsNew}, {Py_tp_richcompare, (void *)PySideQFlagsRichCompare}, - {Py_tp_dealloc, (void *)object_dealloc}, + {Py_tp_dealloc, (void *)Sbk_object_dealloc}, {0, 0} }; static PyType_Spec SbkNewQFlagsType_spec = { diff --git a/sources/pyside2/libpyside/pysidesignal.cpp b/sources/pyside2/libpyside/pysidesignal.cpp index ed1dcb729..ee435ab37 100644 --- a/sources/pyside2/libpyside/pysidesignal.cpp +++ b/sources/pyside2/libpyside/pysidesignal.cpp @@ -110,7 +110,7 @@ static PyType_Slot PySideMetaSignalType_slots[] = { {Py_tp_methods, (void *)MetaSignal_methods}, {Py_tp_base, (void *)&PyType_Type}, {Py_tp_free, (void *)PyObject_GC_Del}, - {Py_tp_dealloc, (void *)object_dealloc}, + {Py_tp_dealloc, (void *)Sbk_object_dealloc}, {0, 0} }; static PyType_Spec PySideMetaSignalType_spec = { @@ -142,7 +142,7 @@ static PyType_Slot PySideSignalType_slots[] = { {Py_tp_init, (void *)signalTpInit}, {Py_tp_new, (void *)PyType_GenericNew}, {Py_tp_free, (void *)signalFree}, - {Py_tp_dealloc, (void *)object_dealloc}, + {Py_tp_dealloc, (void *)Sbk_object_dealloc}, {0, 0} }; static PyType_Spec PySideSignalType_spec = { @@ -181,7 +181,7 @@ static PyType_Slot PySideSignalInstanceType_slots[] = { {Py_tp_methods, (void *)SignalInstance_methods}, {Py_tp_new, (void *)PyType_GenericNew}, {Py_tp_free, (void *)signalInstanceFree}, - {Py_tp_dealloc, (void *)object_dealloc}, + {Py_tp_dealloc, (void *)Sbk_object_dealloc}, {0, 0} }; static PyType_Spec PySideSignalInstanceType_spec = { @@ -619,7 +619,7 @@ void init(PyObject *module) { if (SbkSpecial_Type_Ready(module, PySideMetaSignalTypeF(), MetaSignal_SignatureStrings) < 0) return; - Py_INCREF(PySideSignalTypeF()); + Py_INCREF(PySideMetaSignalTypeF()); PyModule_AddObject(module, "MetaSignal", reinterpret_cast<PyObject *>(PySideMetaSignalTypeF())); if (SbkSpecial_Type_Ready(module, PySideSignalTypeF(), Signal_SignatureStrings) < 0) diff --git a/sources/pyside2/libpyside/pysideslot.cpp b/sources/pyside2/libpyside/pysideslot.cpp index 204253aa2..04212a64e 100644 --- a/sources/pyside2/libpyside/pysideslot.cpp +++ b/sources/pyside2/libpyside/pysideslot.cpp @@ -71,7 +71,7 @@ static PyType_Slot PySideSlotType_slots[] = { {Py_tp_call, (void *)slotCall}, {Py_tp_init, (void *)slotTpInit}, {Py_tp_new, (void *)PyType_GenericNew}, - {Py_tp_dealloc, (void *)object_dealloc}, + {Py_tp_dealloc, (void *)Sbk_object_dealloc}, {0, 0} }; static PyType_Spec PySideSlotType_spec = { diff --git a/sources/pyside2/libpyside/pysideweakref.cpp b/sources/pyside2/libpyside/pysideweakref.cpp index 2b27f9545..faa3abe82 100644 --- a/sources/pyside2/libpyside/pysideweakref.cpp +++ b/sources/pyside2/libpyside/pysideweakref.cpp @@ -53,7 +53,7 @@ static PyObject *CallableObject_call(PyObject *callable_object, PyObject *args, static PyType_Slot PySideCallableObjectType_slots[] = { {Py_tp_call, (void *)CallableObject_call}, - {Py_tp_dealloc, (void *)object_dealloc}, + {Py_tp_dealloc, (void *)Sbk_object_dealloc}, {0, 0} }; static PyType_Spec PySideCallableObjectType_spec = { @@ -94,9 +94,15 @@ PyObject *create(PyObject *obj, PySideWeakRefFunction func, void *userData) PyType_Ready(PySideCallableObjectTypeF()); } - PySideCallableObject *callable = PyObject_New(PySideCallableObject, PySideCallableObjectTypeF()); + PyTypeObject *type = PySideCallableObjectTypeF(); + PySideCallableObject *callable = PyObject_New(PySideCallableObject, type); if (!callable || PyErr_Occurred()) return 0; + if (!PepRuntime_38_flag) { + // PYSIDE-939: Handling references correctly. + // Workaround for Python issue 35810; no longer necessary in Python 3.8 + Py_INCREF(type); + } PyObject *weak = PyWeakref_NewRef(obj, reinterpret_cast<PyObject *>(callable)); if (!weak || PyErr_Occurred()) diff --git a/sources/pyside2/tests/signals/bug_79.py b/sources/pyside2/tests/signals/bug_79.py index 9eb783d77..4a595912c 100644 --- a/sources/pyside2/tests/signals/bug_79.py +++ b/sources/pyside2/tests/signals/bug_79.py @@ -56,13 +56,15 @@ class ConnectTest(unittest.TestCase): # if this is no debug build, then we check at least that # we do not crash any longer. if not skiptest: - total = sys.gettotalrefcount() + total = gettotalrefcount() for idx in range(1000): o.selectionModel().destroyed.connect(self.callback) o.selectionModel().destroyed.disconnect(self.callback) gc.collect() if not skiptest: - self.assertTrue(abs(gettotalrefcount() - total) < 10) + delta = gettotalrefcount() - total + print("delta total refcount =", delta) + self.assertTrue(abs(delta) < 10) if __name__ == '__main__': diff --git a/sources/shiboken2/doc/_themes/pysidedocs/static/pyside.css b/sources/shiboken2/doc/_themes/pysidedocs/static/pyside.css index 23e460262..19275b545 100644 --- a/sources/shiboken2/doc/_themes/pysidedocs/static/pyside.css +++ b/sources/shiboken2/doc/_themes/pysidedocs/static/pyside.css @@ -1020,7 +1020,8 @@ body { color:#404244; } ol,ul { - list-style:none + list-style-type: square; + color: #17a81a; } .body ol,.body ul { margin-top:0.75em; @@ -1463,7 +1464,7 @@ div.pre { height:auto } pre, .LegaleseLeft { - background-color:#3a4055; + background-color:#222840; color:#fff; display:block; font-family:"Droid Sans Mono"; @@ -1544,6 +1545,13 @@ pre span.wrap { margin:4px; opacity:0.65 } + +span.pre { + color: #09102d; + background-color: #e4e4e4; + padding: 3px; +} + span.wrap:hover { opacity:1 } @@ -2013,3 +2021,52 @@ a.plink, a.headerlink { a.plink::before { content:'\00B6' } + +table.special { + border: 3px; + padding: 0px; + border-collapse: separate; + border-spacing: 20px; + line-height: 1.5em; +} + +.special p { + text-align: center; + color: #3a4055; +} + +.special a { + display: block; + border-bottom: 0; + text-decoration: none; +} + +.special a:hover { + border-bottom: 0; + text-decoration: none; +} + +.special strong { + color: #17a81a; + font-size: 110%; + font-weight: normal; +} + +table.special th, +table.special td { + border: 1px solid #888; + padding-top: 14px; + padding-bottom: 14px; + padding-left: 6px; + padding-right: 5px; + border-radius: 5px; + -moz-border-radius: 5px; + -webkit-border-radius: 5px; + -khtml-border-radius: 5px; +} + +.special td:hover { + padding-top: 2px; + padding-bottom: 2px; + border-bottom: 4px solid #41cd52; +} diff --git a/sources/shiboken2/generator/shiboken2/cppgenerator.cpp b/sources/shiboken2/generator/shiboken2/cppgenerator.cpp index db05b21d6..fb84b7d23 100644 --- a/sources/shiboken2/generator/shiboken2/cppgenerator.cpp +++ b/sources/shiboken2/generator/shiboken2/cppgenerator.cpp @@ -3871,7 +3871,7 @@ void CppGenerator::writeClassDefinition(QTextStream &s, if (metaClass->isNamespace() || metaClass->hasPrivateDestructor()) { tp_dealloc = metaClass->hasPrivateDestructor() ? QLatin1String("SbkDeallocWrapperWithPrivateDtor") : - QLatin1String("object_dealloc /* PYSIDE-832: Prevent replacement of \"0\" with subtype_dealloc. */"); + QLatin1String("Sbk_object_dealloc /* PYSIDE-832: Prevent replacement of \"0\" with subtype_dealloc. */"); tp_init.clear(); } else { QString deallocClassName; diff --git a/sources/shiboken2/libshiboken/basewrapper.cpp b/sources/shiboken2/libshiboken/basewrapper.cpp index 000035627..dd5dc43e9 100644 --- a/sources/shiboken2/libshiboken/basewrapper.cpp +++ b/sources/shiboken2/libshiboken/basewrapper.cpp @@ -58,6 +58,10 @@ #include "qapp_macro.h" #include "voidptr.h" +#if defined(__APPLE__) +#include <dlfcn.h> +#endif + namespace { void _destroyParentInfo(SbkObject *obj, bool keepReference); } @@ -74,6 +78,17 @@ static void callDestructor(const Shiboken::DtorAccumulatorVisitor::DestructorEnt extern "C" { +// PYSIDE-939: A general replacement for object_dealloc. +void Sbk_object_dealloc(PyObject *self) +{ + if (PepRuntime_38_flag) { + // PYSIDE-939: Handling references correctly. + // This was not needed before Python 3.8 (Python issue 35810) + Py_DECREF(Py_TYPE(self)); + } + Py_TYPE(self)->tp_free(self); +} + static void SbkObjectTypeDealloc(PyObject *pyObj); static PyObject *SbkObjectTypeTpNew(PyTypeObject *metatype, PyObject *args, PyObject *kwds); @@ -309,8 +324,32 @@ static void SbkDeallocWrapperCommon(PyObject *pyObj, bool canDelete) // Need to decref the type if this is the dealloc func; if type // is subclassed, that dealloc func will decref (see subtype_dealloc // in typeobject.c in the python sources) - bool needTypeDecref = (PyType_GetSlot(pyType, Py_tp_dealloc) == SbkDeallocWrapper + bool needTypeDecref = (false + || PyType_GetSlot(pyType, Py_tp_dealloc) == SbkDeallocWrapper || PyType_GetSlot(pyType, Py_tp_dealloc) == SbkDeallocWrapperWithPrivateDtor); + if (PepRuntime_38_flag) { + // PYSIDE-939: Additional rule: Also when a subtype is heap allocated, + // then the subtype_dealloc deref will be suppressed, and we need again + // to supply a decref. + needTypeDecref |= (pyType->tp_base->tp_flags & Py_TPFLAGS_HEAPTYPE) != 0; + } + +#if defined(__APPLE__) + // Just checking once that our assumptions are right. + if (false) { + void *p = PyType_GetSlot(pyType, Py_tp_dealloc); + Dl_info dl_info; + dladdr(p, &dl_info); + fprintf(stderr, "tp_dealloc is %s\n", dl_info.dli_sname); + } + // Gives one of our functions + // "Sbk_object_dealloc" + // "SbkDeallocWrapperWithPrivateDtor" + // "SbkDeallocQAppWrapper" + // "SbkDeallocWrapper" + // but for typedealloc_test.py we get + // "subtype_dealloc" +#endif // Ensure that the GC is no longer tracking this object to avoid a // possible reentrancy problem. Since there are multiple steps involved @@ -369,6 +408,11 @@ static void SbkDeallocWrapperCommon(PyObject *pyObj, bool canDelete) if (needTypeDecref) Py_DECREF(pyType); + if (PepRuntime_38_flag) { + // PYSIDE-939: Handling references correctly. + // This was not needed before Python 3.8 (Python issue 35810) + Py_DECREF(pyType); + } } void SbkDeallocWrapper(PyObject *pyObj) @@ -412,6 +456,11 @@ void SbkObjectTypeDealloc(PyObject *pyObj) #ifndef Py_LIMITED_API Py_TRASHCAN_SAFE_END(pyObj); #endif + if (PepRuntime_38_flag) { + // PYSIDE-939: Handling references correctly. + // This was not needed before Python 3.8 (Python issue 35810) + Py_DECREF(Py_TYPE(pyObj)); + } } PyObject *SbkObjectTypeTpNew(PyTypeObject *metatype, PyObject *args, PyObject *kwds) @@ -453,7 +502,16 @@ PyObject *SbkObjectTypeTpNew(PyTypeObject *metatype, PyObject *args, PyObject *k // The meta type creates a new type when the Python programmer extends a wrapped C++ class. auto type_new = reinterpret_cast<newfunc>(PyType_Type.tp_new); + + // PYSIDE-939: This is a temporary patch that circumvents the problem + // with Py_TPFLAGS_METHOD_DESCRIPTOR until this is finally solved. + PyObject *ob_PyType_Type = reinterpret_cast<PyObject *>(&PyType_Type); + static PyObject *mro = PyObject_GetAttr(ob_PyType_Type, Shiboken::PyName::mro()); + auto hold = Py_TYPE(mro)->tp_flags; + Py_TYPE(mro)->tp_flags &= ~Py_TPFLAGS_METHOD_DESCRIPTOR; auto *newType = reinterpret_cast<SbkObjectType *>(type_new(metatype, args, kwds)); + Py_TYPE(mro)->tp_flags = hold; + if (!newType) return nullptr; #if PY_VERSION_HEX < 0x03000000 @@ -554,12 +612,6 @@ PyObject *SbkQAppTpNew(PyTypeObject *subtype, PyObject *, PyObject *) return self == nullptr ? nullptr : _setupNew(self, subtype); } -void -object_dealloc(PyObject *self) -{ - Py_TYPE(self)->tp_free(self); -} - PyObject * SbkDummyNew(PyTypeObject *type, PyObject *, PyObject *) { diff --git a/sources/shiboken2/libshiboken/basewrapper.h b/sources/shiboken2/libshiboken/basewrapper.h index 7faf223bd..813870dac 100644 --- a/sources/shiboken2/libshiboken/basewrapper.h +++ b/sources/shiboken2/libshiboken/basewrapper.h @@ -64,6 +64,9 @@ struct LIBSHIBOKEN_API SbkObject }; +/// PYSIDE-939: A general replacement for object_dealloc. +LIBSHIBOKEN_API void Sbk_object_dealloc(PyObject *self); + /// Dealloc the python object \p pyObj and the C++ object represented by it. LIBSHIBOKEN_API void SbkDeallocWrapper(PyObject *pyObj); LIBSHIBOKEN_API void SbkDeallocQAppWrapper(PyObject *pyObj); @@ -116,7 +119,7 @@ LIBSHIBOKEN_API PyObject *SbkQAppTpNew(PyTypeObject *subtype, PyObject *args, Py * nullptr. But the default before conversion to heaptypes was to assign * object_dealloc. This seems to be a bug in the Limited API. */ -LIBSHIBOKEN_API void object_dealloc(PyObject *); +/// PYSIDE-939: Replaced by Sbk_object_dealloc. LIBSHIBOKEN_API PyObject *SbkDummyNew(PyTypeObject *type, PyObject *, PyObject *); } // extern "C" diff --git a/sources/shiboken2/libshiboken/pep384impl.cpp b/sources/shiboken2/libshiboken/pep384impl.cpp index 5729100bf..41d56cba1 100644 --- a/sources/shiboken2/libshiboken/pep384impl.cpp +++ b/sources/shiboken2/libshiboken/pep384impl.cpp @@ -41,6 +41,8 @@ #include "autodecref.h" #include "sbkstaticstrings.h" #include "sbkstaticstrings_p.h" +#include <stdlib.h> + extern "C" { @@ -161,7 +163,8 @@ check_PyTypeObject_valid() || probe_tp_free != check->tp_free || probe_tp_is_gc != check->tp_is_gc || probe_tp_bases != typetype->tp_bases - || probe_tp_mro != typetype->tp_mro) + || probe_tp_mro != typetype->tp_mro + || Py_TPFLAGS_DEFAULT != (check->tp_flags & Py_TPFLAGS_DEFAULT)) Py_FatalError("The structure of type objects has changed!"); Py_DECREF(check); Py_DECREF(probe_tp_base); @@ -669,6 +672,25 @@ _Pep_PrivateMangle(PyObject *self, PyObject *name) /***************************************************************************** * + * Runtime support for Python 3.8 incompatibilities + * + */ + +int PepRuntime_38_flag = 0; + +static void +init_PepRuntime() +{ + // We expect a string of the form "\d\.\d+\." + const char *version = Py_GetVersion(); + if (version[0] < '3') + return; + if (std::atoi(version + 2) >= 8) + PepRuntime_38_flag = 1; +} + +/***************************************************************************** + * * Module Initialization * */ @@ -677,6 +699,7 @@ void Pep384_Init() { check_PyTypeObject_valid(); + init_PepRuntime(); #ifdef Py_LIMITED_API Pep_GetVerboseFlag(); PepMethod_TypePtr = getMethodType(); diff --git a/sources/shiboken2/libshiboken/pep384impl.h b/sources/shiboken2/libshiboken/pep384impl.h index 1aa7e6fc0..e9f65e446 100644 --- a/sources/shiboken2/libshiboken/pep384impl.h +++ b/sources/shiboken2/libshiboken/pep384impl.h @@ -89,7 +89,7 @@ typedef struct _typeobject { Py_ssize_t tp_basicsize; void *X03; // Py_ssize_t tp_itemsize; void *X04; // destructor tp_dealloc; - void *X05; // printfunc tp_print; + void *X05; // Py_ssize_t tp_vectorcall_offset; void *X06; // getattrfunc tp_getattr; void *X07; // setattrfunc tp_setattr; void *X08; // PyAsyncMethods *tp_as_async; @@ -103,7 +103,7 @@ typedef struct _typeobject { void *X16; // getattrofunc tp_getattro; void *X17; // setattrofunc tp_setattro; void *X18; // PyBufferProcs *tp_as_buffer; - void *X19; // unsigned long tp_flags; + unsigned long tp_flags; void *X20; // const char *tp_doc; traverseproc tp_traverse; inquiry tp_clear; @@ -129,6 +129,13 @@ typedef struct _typeobject { } PyTypeObject; +#ifndef PyObject_IS_GC +/* Test if an object has a GC head */ +#define PyObject_IS_GC(o) \ + (PyType_IS_GC(Py_TYPE(o)) \ + && (Py_TYPE(o)->tp_is_gc == NULL || Py_TYPE(o)->tp_is_gc(o))) +#endif + // This was a macro error in the limited API from the beginning. // It was fixed in Python master, but did make it only in Python 3.8 . #define PY_ISSUE33738_SOLVED 0x03080000 @@ -292,7 +299,7 @@ LIBSHIBOKEN_API PyObject *PyRun_String(const char *, int, PyObject *, PyObject * // But this is no problem as we check it's validity for every version. #define PYTHON_BUFFER_VERSION_COMPATIBLE (PY_VERSION_HEX >= 0x03030000 && \ - PY_VERSION_HEX < 0x0307FFFF) + PY_VERSION_HEX < 0x0308FFFF) #if !PYTHON_BUFFER_VERSION_COMPATIBLE # error Please check the buffer compatibility for this python version! #endif @@ -488,6 +495,19 @@ extern LIBSHIBOKEN_API PyTypeObject *PepMethodDescr_TypePtr; /***************************************************************************** * + * Runtime support for Python 3.8 incompatibilities + * + */ + +#ifndef Py_TPFLAGS_METHOD_DESCRIPTOR +/* Objects behave like an unbound method */ +#define Py_TPFLAGS_METHOD_DESCRIPTOR (1UL << 17) +#endif + +extern LIBSHIBOKEN_API int PepRuntime_38_flag; + +/***************************************************************************** + * * Module Initialization * */ diff --git a/sources/shiboken2/libshiboken/sbkenum.cpp b/sources/shiboken2/libshiboken/sbkenum.cpp index 71fcf5f64..db390802a 100644 --- a/sources/shiboken2/libshiboken/sbkenum.cpp +++ b/sources/shiboken2/libshiboken/sbkenum.cpp @@ -321,6 +321,11 @@ void SbkEnumTypeDealloc(PyObject *pyObj) #ifndef Py_LIMITED_API Py_TRASHCAN_SAFE_END(pyObj); #endif + if (PepRuntime_38_flag) { + // PYSIDE-939: Handling references correctly. + // This was not needed before Python 3.8 (Python issue 35810) + Py_DECREF(Py_TYPE(pyObj)); + } } PyObject *SbkEnumTypeTpNew(PyTypeObject *metatype, PyObject *args, PyObject *kwds) @@ -512,7 +517,7 @@ static PyType_Slot SbkNewType_slots[] = { {Py_nb_index, (void *)enum_int}, {Py_tp_richcompare, (void *)enum_richcompare}, {Py_tp_hash, (void *)enum_hash}, - {Py_tp_dealloc, (void *)object_dealloc}, + {Py_tp_dealloc, (void *)Sbk_object_dealloc}, {0, nullptr} }; static PyType_Spec SbkNewType_spec = { diff --git a/sources/shiboken2/libshiboken/sbkstaticstrings.cpp b/sources/shiboken2/libshiboken/sbkstaticstrings.cpp index 3727eb494..42d20d133 100644 --- a/sources/shiboken2/libshiboken/sbkstaticstrings.cpp +++ b/sources/shiboken2/libshiboken/sbkstaticstrings.cpp @@ -61,6 +61,7 @@ STATIC_STRING_IMPL(compile, "compile"); STATIC_STRING_IMPL(function, "function") STATIC_STRING_IMPL(marshal, "marshal") STATIC_STRING_IMPL(method, "method") +STATIC_STRING_IMPL(mro, "mro") STATIC_STRING_IMPL(overload, "overload") STATIC_STRING_IMPL(staticmethod, "staticmethod") } // namespace PyName diff --git a/sources/shiboken2/libshiboken/sbkstaticstrings_p.h b/sources/shiboken2/libshiboken/sbkstaticstrings_p.h index 42c5585fa..12c11376f 100644 --- a/sources/shiboken2/libshiboken/sbkstaticstrings_p.h +++ b/sources/shiboken2/libshiboken/sbkstaticstrings_p.h @@ -49,6 +49,7 @@ PyObject *compile(); PyObject *function(); PyObject *marshal(); PyObject *method(); +PyObject *mro(); PyObject *overload(); PyObject *staticmethod(); } // namespace PyName diff --git a/sources/shiboken2/libshiboken/typespec.cpp b/sources/shiboken2/libshiboken/typespec.cpp index 510ed51e6..902ed55af 100644 --- a/sources/shiboken2/libshiboken/typespec.cpp +++ b/sources/shiboken2/libshiboken/typespec.cpp @@ -714,7 +714,7 @@ PyType_FromSpecWithBases(PyType_Spec *spec, PyObject *bases) if (PyType_Ready(type) < 0) goto fail; - // no ht_hached_keys in Python 2 + // no ht_cached_keys in Python 2 // if (type->tp_dictoffset) { // res->ht_cached_keys = _PyDict_NewKeysForClass(); // } diff --git a/sources/shiboken2/libshiboken/voidptr.cpp b/sources/shiboken2/libshiboken/voidptr.cpp index d4ce58c87..46f49b67e 100644 --- a/sources/shiboken2/libshiboken/voidptr.cpp +++ b/sources/shiboken2/libshiboken/voidptr.cpp @@ -335,7 +335,7 @@ static PyType_Slot SbkVoidPtrType_slots[] = { {Py_tp_richcompare, (void *)SbkVoidPtrObject_richcmp}, {Py_tp_init, (void *)SbkVoidPtrObject_init}, {Py_tp_new, (void *)SbkVoidPtrObject_new}, - {Py_tp_dealloc, (void *)object_dealloc}, + {Py_tp_dealloc, (void *)Sbk_object_dealloc}, {Py_tp_methods, (void *)SbkVoidPtrObject_methods}, {0, nullptr} }; |