From d4764a4c514ec15f4cd680143cbd189482af6251 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cristi=C3=A1n=20Maureira-Fredes?= Date: Tue, 26 Nov 2019 08:16:03 +0100 Subject: New documentation structure - New structure for the landing page, - Some rst were renamed to the new structure, - New sections "Videos", "Examples" and "Getting Started" were created, - Information from the wiki was used to create the Getting Started sections, - FAQ section was removed, - Removing pyhtml2devhelp.py since it is unused, - The new CSS modifications were copied over the Shiboken2 directory. Task-number: PYSIDE-1067 Change-Id: I1ba53cd0030d6d02449fecdfea70efb49421ad3b Reviewed-by: Friedemann Kleint Reviewed-by: Kavindra Palaraja --- sources/pyside2/doc/CMakeLists.txt | 10 - .../doc/_themes/pysidedocs/static/pyside.css | 61 ++++- sources/pyside2/doc/api.rst | 67 ++++++ sources/pyside2/doc/considerations.rst | 85 +++++++ sources/pyside2/doc/contents.rst | 11 +- sources/pyside2/doc/deployment.rst | 84 +++++-- .../pyside2/doc/examples/images/tabbedbrowser.png | Bin 0 -> 37147 bytes sources/pyside2/doc/examples/index.rst | 14 ++ sources/pyside2/doc/examples/tabbedbrowser.rst | 58 +++++ sources/pyside2/doc/faq.rst | 49 ---- sources/pyside2/doc/gettingstarted-linux.rst | 94 ++++++++ sources/pyside2/doc/gettingstarted-macOS.rst | 93 ++++++++ sources/pyside2/doc/gettingstarted-windows.rst | 104 +++++++++ sources/pyside2/doc/gettingstarted.rst | 156 ++++++------- sources/pyside2/doc/index.rst | 127 ++++------ sources/pyside2/doc/overview.rst | 24 -- sources/pyside2/doc/pyhtml2devhelp.py | 256 --------------------- sources/pyside2/doc/pysideapi2.rst | 84 ------- sources/pyside2/doc/quickstart.rst | 111 +++++++++ .../tutorials/examples/images/tabbedbrowser.png | Bin 37147 -> 0 bytes .../doc/tutorials/examples/tabbedbrowser.rst | 58 ----- sources/pyside2/doc/tutorials/index.rst | 17 +- sources/pyside2/doc/videos.rst | 28 +++ .../doc/_themes/pysidedocs/static/pyside.css | 61 ++++- 24 files changed, 958 insertions(+), 694 deletions(-) create mode 100644 sources/pyside2/doc/api.rst create mode 100644 sources/pyside2/doc/considerations.rst create mode 100644 sources/pyside2/doc/examples/images/tabbedbrowser.png create mode 100644 sources/pyside2/doc/examples/index.rst create mode 100644 sources/pyside2/doc/examples/tabbedbrowser.rst delete mode 100644 sources/pyside2/doc/faq.rst create mode 100644 sources/pyside2/doc/gettingstarted-linux.rst create mode 100644 sources/pyside2/doc/gettingstarted-macOS.rst create mode 100644 sources/pyside2/doc/gettingstarted-windows.rst delete mode 100644 sources/pyside2/doc/overview.rst delete mode 100644 sources/pyside2/doc/pyhtml2devhelp.py delete mode 100644 sources/pyside2/doc/pysideapi2.rst create mode 100644 sources/pyside2/doc/quickstart.rst delete mode 100644 sources/pyside2/doc/tutorials/examples/images/tabbedbrowser.png delete mode 100644 sources/pyside2/doc/tutorials/examples/tabbedbrowser.rst create mode 100644 sources/pyside2/doc/videos.rst (limited to 'sources') 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 ` + Provides core non-GUI functionality, like signal and slots, properties, base classes of item models, serialization, etc. + :mod:`Qt GUI ` + Extends QtCore with GUI functionality: Events, windows and screens, OpenGL and raster-based 2D painting, images. + :mod:`Qt Widgets ` + 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 `, these + modules will help you interact with it from Python. + + :mod:`Qt QML ` + Base Python API to interact with the QML module. + :mod:`Qt Quick ` + Provides classes for embedding Qt Quick in Qt applications. + :mod:`Qt QuickWidgets ` + 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 ` + Provides a set of easy to use chart components. + :mod:`Qt DataVisualization ` + 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 ` + Provides low-level multimedia functionality. + :mod:`Qt MultimediaWidgets ` + 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 ` + Provides widgets that can handle web content. + :mod:`Qt WebChannel ` + 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 ` 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 `_. + +__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) `_. 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 `_ - * `cx_Freeze `_ + * `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 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameLicenseLinuxmacOSWindows

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

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 `_, which is built around PyInstaller. -The `fbs `_ 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/examples/images/tabbedbrowser.png b/sources/pyside2/doc/examples/images/tabbedbrowser.png new file mode 100644 index 000000000..27c3daa09 Binary files /dev/null and b/sources/pyside2/doc/examples/images/tabbedbrowser.png differ 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/examples/tabbedbrowser.rst b/sources/pyside2/doc/examples/tabbedbrowser.rst new file mode 100644 index 000000000..c34c50647 --- /dev/null +++ b/sources/pyside2/doc/examples/tabbedbrowser.rst @@ -0,0 +1,58 @@ +********************** +Web Browser Example +********************** + +The example demonstrates the power and simplicity offered by |project| to developers. +It uses several |pymodname| submodules to offer a fluid and modern-looking UI that +is apt for a web browser. The application offers the following features: + + * Tab-based browsing experience using QTabWidget. + * Download manager using a QProgressBar and QWebEngineDownloadItem. + * Bookmark manager using QTreeView. + +.. image:: images/tabbedbrowser.png + +The application's code is organized in several parts for ease of maintenance. For example, +:code:`DownloadWidget` provides a widget to track progress of a download item. In the following +sections, these different parts are discussed briefly to help you understand the Python code behind +them a little better. + +BookmarkWidget or :code:`bookmarkwidget.py` +=========================================== + +This widget docks to the left of the main window by default. It inherits QTreeView and +loads a default set of bookmarks using a QStandardItemModel. The model is populated at startup +from a JSON file, which is updated when you add or remove bookmarks from the tree view. + +.. automodule:: bookmarkwidget + :members: + +DownloadWidget or :code:`downloadwidget.py` +============================================= + +The widget tracks progress of the download item. It inherits QProgressBar to display +progress of the QWebEngineDownloadItem instance, and offers a context-menu with actions such as Launch, +Show in folder, Cancel, and Remove. + +.. automodule:: downloadwidget + :members: + +BrowserTabWidget or :code:`browsertabwidget.py` +=============================================== + +The widget includes a QWebEngineView to enable viewing web content. It docks to the right +of BookmarkWidget in the main window. + +.. automodule:: browsertabwidget + :members: + +MainWindow or :code:`main.py` +============================= + +This is the parent window that collates all the other widgets together to offer the complete package. + +.. automodule:: main + :members: + + +Try running the example to explore it further. 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 `_ decided to properly support the port - (`see details `_). - -**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 `_ or `virtualenv `_ +.. _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 ` 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 - -Qt Modules -=========== - -Basic modules -------------- - These are the main modules that will help you build a Widget based UI. - - :mod:`Qt Core ` - Provides core non-GUI functionality, like signal and slots, properties, base classes of item models, serialization, etc. - :mod:`Qt Gui ` - Extends QtCore with GUI functionality: Events, windows and screens, OpenGL and raster-based 2D painting, images. - :mod:`Qt Widgets ` - 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 `, these - modules will help you interact with it from Python. - - :mod:`Qt Qml ` - Base Python API to interact with the QML module. - :mod:`Qt Quick ` - Provides classes for embedding Qt Quick in Qt applications. - :mod:`Qt QuickWidgets ` - 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 ` - Provides a set of easy to use chart components. - :mod:`Qt DataVisualization ` - 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 ` - Provides low-level multimedia functionality. - :mod:`Qt MultimediaWidgets ` - 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 ` - Provides widgets that can handle web content. - :mod:`Qt WebChannel ` - 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 ` - 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 + + + + + + + + + + + + + + + + + + + + + + + + +

Check It Out!
Write your first Qt app.

Getting Started
Install and build from source.

API Docs
Qt for Python API reference.

Tutorials
Learn with step-by-step guides.

Examples
Check all the available examples.

Videos
Watch webinars, Talks, and more.

Deployment
Learn to deploy your apps.

Considerations
API differences and known issues.

Shiboken
Generate C++ to Python binding.

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 `_ - * (**): `MSVC issue with Python 2.7 and Qt `_ - 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 -## 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' % (' ' * self.last_indent) - self.sub_count -= 1 - print '%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' % (' ' * 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' % (' ' * 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' % (' ' * 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 '' - print '' % (sys.argv[3], sys.argv[3]) - print '' - parser.parse_file(fn) - print '' - - print '' - - fn = 'genindex.html' - parser = PyIdxHTMLParser(formatter.NullFormatter(), base, fn, indent=1) - text = file(base + '/' + fn).read() - parser.feed(text) - parser.close() - - print '' - print '' - -main() - 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 `_. - -__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..a9288442f --- /dev/null +++ b/sources/pyside2/doc/quickstart.rst @@ -0,0 +1,111 @@ +|project| Quick start +====================== + +Requirements +------------ + +Before you can install |project|, you must install the following software: + + * Python 2.7 or 3.5+, + * Recommended: a virtual environment, such as + `venv `_ or + `virtualenv `_ + +Installation +------------ + +Run the following command from your command prompt to install:: + + 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 + +Testing the 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__) + +Creating a Simple Application +------------------------------ + +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: + +* 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. + +* 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 list :code:`hello`. This function + is called when you click the button. + +* 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_()) + +Your example is ready to be run. Try clicking the button at the bottom +and see which greeting you get. diff --git a/sources/pyside2/doc/tutorials/examples/images/tabbedbrowser.png b/sources/pyside2/doc/tutorials/examples/images/tabbedbrowser.png deleted file mode 100644 index 27c3daa09..000000000 Binary files a/sources/pyside2/doc/tutorials/examples/images/tabbedbrowser.png and /dev/null differ diff --git a/sources/pyside2/doc/tutorials/examples/tabbedbrowser.rst b/sources/pyside2/doc/tutorials/examples/tabbedbrowser.rst deleted file mode 100644 index c34c50647..000000000 --- a/sources/pyside2/doc/tutorials/examples/tabbedbrowser.rst +++ /dev/null @@ -1,58 +0,0 @@ -********************** -Web Browser Example -********************** - -The example demonstrates the power and simplicity offered by |project| to developers. -It uses several |pymodname| submodules to offer a fluid and modern-looking UI that -is apt for a web browser. The application offers the following features: - - * Tab-based browsing experience using QTabWidget. - * Download manager using a QProgressBar and QWebEngineDownloadItem. - * Bookmark manager using QTreeView. - -.. image:: images/tabbedbrowser.png - -The application's code is organized in several parts for ease of maintenance. For example, -:code:`DownloadWidget` provides a widget to track progress of a download item. In the following -sections, these different parts are discussed briefly to help you understand the Python code behind -them a little better. - -BookmarkWidget or :code:`bookmarkwidget.py` -=========================================== - -This widget docks to the left of the main window by default. It inherits QTreeView and -loads a default set of bookmarks using a QStandardItemModel. The model is populated at startup -from a JSON file, which is updated when you add or remove bookmarks from the tree view. - -.. automodule:: bookmarkwidget - :members: - -DownloadWidget or :code:`downloadwidget.py` -============================================= - -The widget tracks progress of the download item. It inherits QProgressBar to display -progress of the QWebEngineDownloadItem instance, and offers a context-menu with actions such as Launch, -Show in folder, Cancel, and Remove. - -.. automodule:: downloadwidget - :members: - -BrowserTabWidget or :code:`browsertabwidget.py` -=============================================== - -The widget includes a QWebEngineView to enable viewing web content. It docks to the right -of BookmarkWidget in the main window. - -.. automodule:: browsertabwidget - :members: - -MainWindow or :code:`main.py` -============================= - -This is the parent window that collates all the other widgets together to offer the complete package. - -.. automodule:: main - :members: - - -Try running the example to explore it further. 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 + +
+ +
+ +Webinar: Develop your first Qt for Python application +------------------------------------------------------ + +.. raw:: html + +
+ +
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; +} -- cgit v1.2.3 From 6f79beb23aace35170d155517b9d901567a7f675 Mon Sep 17 00:00:00 2001 From: Kavindra Palaraja Date: Fri, 15 Nov 2019 16:18:09 +0100 Subject: docs: Simplify the Quick Start topic Change-Id: I11651033783052591f38cd8eb02ec47719c91dbf Reviewed-by: Cristian Maureira-Fredes --- .../pyside-examples/images/screenshot_hello.png | Bin 0 -> 21193 bytes sources/pyside2/doc/quickstart.rst | 42 ++++++++++----------- 2 files changed, 19 insertions(+), 23 deletions(-) create mode 100644 sources/pyside2/doc/pyside-examples/images/screenshot_hello.png (limited to 'sources') diff --git a/sources/pyside2/doc/pyside-examples/images/screenshot_hello.png b/sources/pyside2/doc/pyside-examples/images/screenshot_hello.png new file mode 100644 index 000000000..41ebbf01b Binary files /dev/null and b/sources/pyside2/doc/pyside-examples/images/screenshot_hello.png differ diff --git a/sources/pyside2/doc/quickstart.rst b/sources/pyside2/doc/quickstart.rst index a9288442f..5d8ddfe2d 100644 --- a/sources/pyside2/doc/quickstart.rst +++ b/sources/pyside2/doc/quickstart.rst @@ -4,17 +4,18 @@ Requirements ------------ -Before you can install |project|, you must install the following software: +Before you can install |project|, first you must install the following software: * Python 2.7 or 3.5+, - * Recommended: a virtual environment, such as + * We recommend using a virtual environment, such as `venv `_ or `virtualenv `_ Installation ------------ -Run the following command from your command prompt to install:: +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 @@ -22,8 +23,8 @@ or:: pip install --index-url=http://download.qt.io/snapshots/ci/pyside/5.14/latest pyside2 --trusted-host download.qt.io -Testing the Installation -------------------------- +Test your Installation +---------------------- Now that you have |project| installed, you can test your setup by running the following Python constructs to print version information:: @@ -46,16 +47,14 @@ constructs to print version information:: # e.g. (5, 11, 2) print(PySide2.QtCore.__version_info__) -Creating a Simple Application ------------------------------- +Create a Simple Application +--------------------------- -Your |project| setup is ready, so try exploring it further by developing 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: -* Create a new file named :code:`hello_world.py`, and add the following imports to it. - - :: +1. Create a new file named :code:`hello_world.py`, and add the following imports to it.:: import sys import random @@ -64,9 +63,8 @@ guide you through the development process: 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. -* Define a class named :code:`MyWidget`, which extends QWidget and includes a QPushButton and QLabel. - - :: +2. Define a class named :code:`MyWidget`, which extends QWidget and includes a QPushButton and + QLabel.:: class MyWidget(QtWidgets.QWidget): def __init__(self): @@ -89,14 +87,10 @@ guide you through the development process: 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 list :code:`hello`. This function - is called when you click the button. + 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. -* Now, add a main function where you instantiate :code:`MyWidget` and - :code:`show` it. - - :: +3. Now, add a main function where you instantiate :code:`MyWidget` and :code:`show` it.:: if __name__ == "__main__": app = QtWidgets.QApplication([]) @@ -107,5 +101,7 @@ guide you through the development process: sys.exit(app.exec_()) -Your example is ready to be run. Try clicking the button at the bottom -and see which greeting you get. +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 -- cgit v1.2.3 From 45a3efb4e179e83f1bea69cccb190945fbc8c1f8 Mon Sep 17 00:00:00 2001 From: Christian Tismer Date: Tue, 26 Nov 2019 11:54:37 +0100 Subject: Fix Python 3.8 problems This patch fixes some refcounting problems with Python 3.8 . One incompatible change was announced in the what's new document, but actually there were two more problems which were not explicitly mentioned but took much time to sort out. The patch is compatible with the limited API changes (tested with debug build and API error disabled). It is also independent of the Python version which is full Limited API support. For more info, see the documentation mentioned below. The flag error is circumvented now! We either find a better solution or leave it as it is. For now this is ok. Fixes: PYSIDE-939 Change-Id: Iff4a9816857a6ebe86efd4b654d8921e4e464939 Reviewed-by: Qt CI Bot Reviewed-by: Cristian Maureira-Fredes --- .../PySide2/QtQml/pysideqmlregistertype.cpp | 4 +- sources/pyside2/libpyside/pysideclassinfo.cpp | 2 +- sources/pyside2/libpyside/pysidemetafunction.cpp | 2 +- sources/pyside2/libpyside/pysideproperty.cpp | 5 ++ sources/pyside2/libpyside/pysideqflags.cpp | 2 +- sources/pyside2/libpyside/pysidesignal.cpp | 8 +-- sources/pyside2/libpyside/pysideslot.cpp | 2 +- sources/pyside2/libpyside/pysideweakref.cpp | 10 +++- sources/pyside2/tests/signals/bug_79.py | 6 +- .../shiboken2/generator/shiboken2/cppgenerator.cpp | 2 +- sources/shiboken2/libshiboken/basewrapper.cpp | 66 +++++++++++++++++++--- sources/shiboken2/libshiboken/basewrapper.h | 5 +- sources/shiboken2/libshiboken/pep384impl.cpp | 25 +++++++- sources/shiboken2/libshiboken/pep384impl.h | 26 ++++++++- sources/shiboken2/libshiboken/sbkenum.cpp | 7 ++- sources/shiboken2/libshiboken/sbkstaticstrings.cpp | 1 + sources/shiboken2/libshiboken/sbkstaticstrings_p.h | 1 + sources/shiboken2/libshiboken/typespec.cpp | 2 +- sources/shiboken2/libshiboken/voidptr.cpp | 2 +- 19 files changed, 148 insertions(+), 30 deletions(-) (limited to 'sources') 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(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/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(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(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/generator/shiboken2/cppgenerator.cpp b/sources/shiboken2/generator/shiboken2/cppgenerator.cpp index 5460fd7c7..765657099 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..4030fe1c4 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 +#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(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(&PyType_Type); + 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(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 + 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); @@ -667,6 +670,25 @@ _Pep_PrivateMangle(PyObject *self, PyObject *name) #endif // Py_LIMITED_API } +/***************************************************************************** + * + * 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 @@ -486,6 +493,19 @@ extern LIBSHIBOKEN_API PyTypeObject *PepMethodDescr_TypePtr; #define PepMethodDescr_TypePtr &PyMethodDescr_Type #endif +/***************************************************************************** + * + * 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} }; -- cgit v1.2.3 From 37a1e27d49a6a1f7e45621e93a0f13a63fb20d9e Mon Sep 17 00:00:00 2001 From: Christian Tismer Date: Thu, 5 Dec 2019 11:08:50 +0100 Subject: Optimize the Python 3.8 refcount fix a tiny bit This change uses the fact that our workaround to temporarily remove the Py_TPFLAGS_METHOD_DESCRIPTOR flag uses the "mro" function of PyType_Type, which never will change. Therefore, the static keyword makes sure that this function lookup happens only once. Change-Id: I44b74556da1fac2596c81339af30cb66218276e2 Reviewed-by: Friedemann Kleint --- sources/shiboken2/libshiboken/basewrapper.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sources') diff --git a/sources/shiboken2/libshiboken/basewrapper.cpp b/sources/shiboken2/libshiboken/basewrapper.cpp index 4030fe1c4..dd5dc43e9 100644 --- a/sources/shiboken2/libshiboken/basewrapper.cpp +++ b/sources/shiboken2/libshiboken/basewrapper.cpp @@ -506,7 +506,7 @@ PyObject *SbkObjectTypeTpNew(PyTypeObject *metatype, PyObject *args, PyObject *k // 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(&PyType_Type); - PyObject *mro = PyObject_GetAttr(ob_PyType_Type, Shiboken::PyName::mro()); + 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(type_new(metatype, args, kwds)); -- cgit v1.2.3