diff options
47 files changed, 934 insertions, 371 deletions
diff --git a/.gitignore b/.gitignore index 34709d824..526bdb211 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,5 @@ -/build -/dist +/build_* +/dist_* /pyside*_build /pyside*_install /PySide diff --git a/build_scripts/build_scripts.pyproject b/build_scripts/build_scripts.pyproject new file mode 100644 index 000000000..604419c10 --- /dev/null +++ b/build_scripts/build_scripts.pyproject @@ -0,0 +1,9 @@ +{ + "files": ["main.py", "__init__.py", "config.py", "options.py", "qtinfo.py", + "setup_runner.py", "utils.py", "wheel_override.py", + "platforms/__init__.py", "platforms/linux.py", + "platforms/macos.py", "platforms/unix.py", + "platforms/windows_desktop.py", + "../setup.py", + "../coin_build_instructions.py", "../coin_test_instructions.py"] +} diff --git a/build_scripts/build_scripts.pyqtc b/build_scripts/build_scripts.pyqtc deleted file mode 100644 index 1fc1c9664..000000000 --- a/build_scripts/build_scripts.pyqtc +++ /dev/null @@ -1,18 +0,0 @@ -__init__.py -config.py -main.py -options.py -platforms -qtinfo.py -setup_runner.py -utils.py -wheel_override.py -platforms/__init__.py -platforms/linux.py -platforms/macos.py -platforms/unix.py -platforms/windows_desktop.py -../setup.py -../coin_build_instructions.py -../coin_test_instructions.py - diff --git a/build_scripts/qp5_tool.py b/build_scripts/qp5_tool.py new file mode 100644 index 000000000..aca8cf7f6 --- /dev/null +++ b/build_scripts/qp5_tool.py @@ -0,0 +1,261 @@ +############################################################################# +## +## Copyright (C) 2019 The Qt Company Ltd. +## Contact: https://www.qt.io/licensing/ +## +## This file is part of Qt for Python. +## +## $QT_BEGIN_LICENSE:LGPL$ +## Commercial License Usage +## Licensees holding valid commercial Qt licenses may use this file in +## accordance with the commercial license agreement provided with the +## Software or, alternatively, in accordance with the terms contained in +## a written agreement between you and The Qt Company. For licensing terms +## and conditions see https://www.qt.io/terms-conditions. For further +## information use the contact form at https://www.qt.io/contact-us. +## +## GNU Lesser General Public License Usage +## Alternatively, this file may be used under the terms of the GNU Lesser +## General Public License version 3 as published by the Free Software +## Foundation and appearing in the file LICENSE.LGPL3 included in the +## packaging of this file. Please review the following information to +## ensure the GNU Lesser General Public License version 3 requirements +## will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +## +## GNU General Public License Usage +## Alternatively, this file may be used under the terms of the GNU +## General Public License version 2.0 or (at your option) the GNU General +## Public license version 3 or any later version approved by the KDE Free +## Qt Foundation. The licenses are as published by the Free Software +## Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +## included in the packaging of this file. Please review the following +## information to ensure the GNU General Public License requirements will +## be met: https://www.gnu.org/licenses/gpl-2.0.html and +## https://www.gnu.org/licenses/gpl-3.0.html. +## +## $QT_END_LICENSE$ +## +############################################################################# + +from __future__ import print_function + +from argparse import ArgumentParser, RawTextHelpFormatter +import os +import re +import subprocess +import sys +import warnings + +desc = """ +Utility script for working with Qt for Python. + +Feel free to extend! + +qp5_tool.py can be configured by creating a configuration file +in the format key=value: + "%CONFIGFILE%" + +It is possible to use repository-specific values +by adding a key postfixed by a dash and the repository folder base name, eg: +Modules-pyside-setup512=Core,Gui,Widgets,Network,Test + +Configuration keys: +Modules Comma separated list of modules to be built + (for --module-subset=) +BuildArguments Arguments to setup.py +Python Python executable (Use python_d for debug builds on Windows) + +Arbitrary keys can be defined and referenced by $(name): + +MinimalModules=Core,Gui,Widgets,Network,Test +Modules=$(MinimalModules),Multimedia +Modules-pyside-setup-minimal=$(MinimalModules) +""" + +def which(needle): + """Perform a path search""" + needles = [needle] + if is_windows: + for ext in ("exe", "bat", "cmd"): + needles.append("{}.{}".format(needle, ext)) + + for path in os.environ.get("PATH", "").split(os.pathsep): + for n in needles: + binary = os.path.join(path, n) + if os.path.isfile(binary): + return binary + return None + +def execute(args): + """Execute a command and print to log""" + log_string = '[{}] {}'.format(os.path.basename(os.getcwd()), ' '.join(args)) + print(log_string) + exit_code = subprocess.call(args) + if exit_code != 0: + raise RuntimeError('FAIL({}): {}'.format(exit_code, log_string)) + +def run_git(args): + """Run git in the current directory and its submodules""" + args.insert(0, git) # run in repo + execute(args) # run for submodules + module_args = [git, "submodule", "foreach"] + module_args.extend(args) + execute(module_args) + +def expand_reference(dict, value): + """Expand references to other keys in config files $(name) by value.""" + pattern = re.compile(r"\$\([^)]+\)") + while True: + match = pattern.match(value) + if not match: + break + key = match.group(0)[2:-1] + value = value[:match.start(0)] + dict[key] + value[match.end(0):] + return value + +""" +Config file handling, cache and read function +""" + +config_dict = {} + +def read_config_file(fileName): + global config_dict + keyPattern = re.compile(r'^\s*([A-Za-z0-9\_\-]+)\s*=\s*(.*)$') + with open(config_file) as f: + while True: + line = f.readline().rstrip() + if not line: + break + match = keyPattern.match(line) + if match: + key = match.group(1) + value = match.group(2) + while value.endswith('\\'): + value = value.rstrip('\\') + value += f.readline().rstrip() + config_dict[key] = expand_reference(config_dict, value) + +def read_tool_config(key): + """ + Read a value from the '$HOME/.qp5_tool' configuration file. When given + a key 'key' for the repository directory '/foo/qt-5', check for the + repo-specific value 'key-qt5' and then for the general 'key'. + """ + if not config_dict: + read_config_file(config_file) + repo_value = config_dict.get(key + '-' + base_dir) + return repo_value if repo_value else config_dict.get(key) + +def read_config_build_arguments(): + value = read_tool_config('BuildArguments') + if value: + return re.split(r'\s+', value) + return default_build_args; + +def read_config_modules_argument(): + value = read_tool_config('Modules') + if value and value != '' and value != 'all': + return '--module-subset=' + value + return None + +def read_config_python_binary(): + binary = read_tool_config('Python') + return binary if binary else 'python' + +def get_config_file(): + home = os.getenv('HOME') + if is_windows: + # Set a HOME variable on Windows such that scp. etc. + # feel at home (locating .ssh). + if not home: + home = os.getenv('HOMEDRIVE') + os.getenv('HOMEPATH') + os.environ['HOME'] = home + user = os.getenv('USERNAME') + config_file = os.path.join(os.getenv('APPDATA'), config_file_name) + else: + user = os.getenv('USER') + config_dir = os.path.join(home, '.config') + if os.path.exists(config_dir): + config_file = os.path.join(config_dir, config_file_name) + else: + config_file = os.path.join(home, '.' + config_file_name) + return config_file + +def get_options(desc): + parser = ArgumentParser(description=desc, formatter_class=RawTextHelpFormatter) + parser.add_argument('--reset', '-r', action='store_true', + help='Git reset hard to upstream state') + parser.add_argument('--clean', '-c', action='store_true', + help='Git clean') + parser.add_argument('--pull', '-p', action='store_true', + help='Git pull') + parser.add_argument('--build', '-b', action='store_true', + help='Build (configure + build)') + parser.add_argument('--make', '-m', action='store_true', help='Make') + parser.add_argument('--Make', '-M', action='store_true', + help='cmake + Make (continue broken build)') + parser.add_argument('--version', '-v', action='version', version='%(prog)s 1.0') + + return parser.parse_args() + +if __name__ == '__main__': + + git = None + base_dir = None + default_build_args = ['--build-tests', '--skip-docs', '--quiet'] + is_windows = sys.platform == 'win32' + config_file_name = 'qp5_tool.conf' + config_file = None + user = None + default_config_file = """ + Modules=Core,Gui,Widgets,Network,Test,Qml,Quick,Multimedia,MultimediaWidgets + BuildArguments={} + # Python executable (python_d for debug builds) + Python=python + """ + + config_file = get_config_file() + desc = desc.replace('%CONFIGFILE%', config_file) + options = get_options(desc) + + git = which('git') + if git is None: + warnings.warn('Unable to find git', RuntimeWarning) + sys.exit(-1) + + if not os.path.exists(config_file): + print('Create initial config file ', config_file, " ..") + with open(config_file, 'w') as f: + f.write(default_config_file.format(' '.join(default_build_args))) + + while not os.path.exists('.gitmodules'): + cwd = os.getcwd() + if cwd == '/' or (is_windows and len(cwd) < 4): + warnings.warn('Unable to find git root', RuntimeWarning) + sys.exit(-1) + os.chdir(os.path.dirname(cwd)) + + base_dir = os.path.basename(os.getcwd()) + + if options.clean: + run_git(['clean', '-dxf']) + + if options.reset: + run_git(['reset', '--hard', '@{upstream}']) + + if options.pull: + run_git(['pull', '--rebase']) + + if options.build or options.make or options.Make: + arguments = [read_config_python_binary(), 'setup.py', 'install'] + arguments.extend(read_config_build_arguments()) + if options.make or options.Make: + arguments.extend(['--reuse-build', '--ignore-git']) + if not options.Make: + arguments.append('--skip-cmake') + modules = read_config_modules_argument() + if modules: + arguments.append(modules) + execute(arguments) + sys.exit(0) diff --git a/dist/changes-5.12.1 b/dist/changes-5.12.1 new file mode 100644 index 000000000..e0eeeff75 --- /dev/null +++ b/dist/changes-5.12.1 @@ -0,0 +1,45 @@ +Qt for Python 5.12.1 is a bug-fix release. + +For more details, refer to the online documentation included in this +distribution. The documentation is also available online: + +https://doc.qt.io/qtforpython/ + +Some of the changes listed in this file include issue tracking numbers +corresponding to tasks in the Qt Bug Tracker: + +https://bugreports.qt.io/ + +Each of these identifiers can be entered in the bug tracker to obtain more +information about a particular change. + +**************************************************************************** +* PySide2 * +**************************************************************************** + + - [PYSIDE-878] Added binding for QWebEngineUrlScheme which was missing + - Completed the signature introspection + - Activated existence_test.py for 5.12 + - [PYSIDE-868] Fixed a crash related to multiple inheritance + - [PYSIDE-886] Fixed crash when mixing static overloads with instance methods in derived classes + - [PYSIDE-892] Added free functions from namespace QtQml + - Fixed a rare type hint racing condition + - Used helper function for accessing the meta object in quick type registration for libpyside + - [PYSIDE-883] Fixed regression related to removing createIndex method that uses PyObject* + - [PYSIDE-882] Avoided the creation of empty build directories in the install tree + - Produced TypeError messages using the signature module + - Replaced nullptr by None in signatures in the documentation + - Updated and fixed the Slot documentation + - Added \nullptr macro definition in the documentation + - [PYSIDE-874] Fixed wrong METADATA for generated wheels + - [PYSIDE-898] Improved check when a QFlag<Enum> is found + - [PYSIDE-790] Fixed a crash when overriding QAbstractNativeEventFilter.QAbstractNativeEventFilter() + - Added support for the help() function using the signature module + - [PYSIDE-880] Fixed an issue on the setup.py when running under non-UTF8 locale + +**************************************************************************** +* Shiboken2 * +**************************************************************************** + + - Make signatures in overload decisor code more verbose in shiboken + - [PYSIDE-914] Included MSVC dlls in the shiboken module package diff --git a/dist/changes-5.12.2 b/dist/changes-5.12.2 new file mode 100644 index 000000000..39e845fb7 --- /dev/null +++ b/dist/changes-5.12.2 @@ -0,0 +1,48 @@ +Qt for Python 5.12.2 is a bug-fix release. + +For more details, refer to the online documentation included in this +distribution. The documentation is also available online: + +https://doc.qt.io/qtforpython/ + +Some of the changes listed in this file include issue tracking numbers +corresponding to tasks in the Qt Bug Tracker: + +https://bugreports.qt.io/ + +Each of these identifiers can be entered in the bug tracker to obtain more +information about a particular change. + +**************************************************************************** +* PySide2 * +**************************************************************************** + + - [PYSIDE-934] Added a method to VoidPtr called toBytes() to get the bytes representation. + - [PYSIDE-95] Added ownership transfer for QGraphicsItemGroup.addToGroup + - [PYSIDE-928][PYSIDE-937][PYSIDE-943] Fixing a refcounting bug shown by __doc__ handling + - [PYSIIDE-931] Added the attribute 'allow-thread' to the type system and class entries. + - [PYSIDE-947] Fixed conversions of list of smart pointers to python + - [PYSIDE-953] Preventing Python 3.5 from crashing the build + - [PYSIDE-940] Added setPageSize new signature to QPageSize + - [PYSIDE-950] Allowed subclassing PyCFunction in extension modules + - [PYSIDE-938] Set the proper parent when overloading QUiLoader.addAction() + - Added common QPrintSupport typesystem for QWebEngine + - [PYSIDE-942] Fixed an error when importing signatures in frozen executables + - [PYSIDE-948] Fixed problem when using smart pointers with namespaces + - [PYSIDE-45] Added support for using PyObject wrapper when an invalid QVariant is used + - [PYSIDE-922] Added pyObj check for the setSequenceOwnership + - [PYSIDE-919] Modernized the cmake build process + - [PYSIDE-924] Propagated Property attributes to the MetaObject + - Improved the type hints for containers + - [PYSIDE-906] Added missing classes QWebEngineHistory and WebEngineHistoryItem + - Added QtRemoteObject classes + - Added a script to generate a debug log in windows called debug_windows.py + +**************************************************************************** +* Shiboken2 * +**************************************************************************** + + - Fixed many build warnings on shiboken and pyside + - Extended the exception handling test in shiboken + - [PYSIDE-929] Added dependency version for shiboken2 + - [PYSIDE-914] Including MSVC dlls in the shiboken module package diff --git a/examples/charts/chartthemes/main.py b/examples/charts/chartthemes/main.py index 263259716..1ba725b7d 100644 --- a/examples/charts/chartthemes/main.py +++ b/examples/charts/chartthemes/main.py @@ -130,25 +130,23 @@ class ThemeWidget(QWidget): def populate_themebox(self): theme = self.ui.themeComboBox - qchart = QtCharts.QChart - theme.addItem("Light", qchart.ChartThemeLight) - theme.addItem("Blue Cerulean", qchart.ChartThemeBlueCerulean) - theme.addItem("Dark", qchart.ChartThemeDark) - theme.addItem("Brown Sand", qchart.ChartThemeBrownSand) - theme.addItem("Blue NCS", qchart.ChartThemeBlueNcs) - theme.addItem("High Contrast", qchart.ChartThemeHighContrast) - theme.addItem("Blue Icy", qchart.ChartThemeBlueIcy) - theme.addItem("Qt", qchart.ChartThemeQt) + theme.addItem("Light", QtCharts.QChart.ChartThemeLight) + theme.addItem("Blue Cerulean", QtCharts.QChart.ChartThemeBlueCerulean) + theme.addItem("Dark", QtCharts.QChart.ChartThemeDark) + theme.addItem("Brown Sand", QtCharts.QChart.ChartThemeBrownSand) + theme.addItem("Blue NCS", QtCharts.QChart.ChartThemeBlueNcs) + theme.addItem("High Contrast", QtCharts.QChart.ChartThemeHighContrast) + theme.addItem("Blue Icy", QtCharts.QChart.ChartThemeBlueIcy) + theme.addItem("Qt", QtCharts.QChart.ChartThemeQt) def populate_animationbox(self): animated = self.ui.animatedComboBox - qchart = QtCharts.QChart - animated.addItem("No Animations", qchart.NoAnimation) - animated.addItem("GridAxis Animations", qchart.GridAxisAnimations) - animated.addItem("Series Animations", qchart.SeriesAnimations) - animated.addItem("All Animations", qchart.AllAnimations) + animated.addItem("No Animations", QtCharts.QChart.NoAnimation) + animated.addItem("GridAxis Animations", QtCharts.QChart.GridAxisAnimations) + animated.addItem("Series Animations", QtCharts.QChart.SeriesAnimations) + animated.addItem("All Animations", QtCharts.QChart.AllAnimations) def populate_legendbox(self): legend = self.ui.legendComboBox @@ -294,47 +292,46 @@ class ThemeWidget(QWidget): idx = self.ui.themeComboBox.currentIndex() theme = self.ui.themeComboBox.itemData(idx) - qchart = QtCharts.QChart if len(self.charts): chart_theme = self.charts[0].chart().theme() if chart_theme != theme: for chart_view in self.charts: if theme == 0: - theme_name = qchart.ChartThemeLight + theme_name = QtCharts.QChart.ChartThemeLight elif theme == 1: - theme_name = qchart.ChartThemeBlueCerulean + theme_name = QtCharts.QChart.ChartThemeBlueCerulean elif theme == 2: - theme_name = qchart.ChartThemeDark + theme_name = QtCharts.QChart.ChartThemeDark elif theme == 3: - theme_name = qchart.ChartThemeBrownSand + theme_name = QtCharts.QChart.ChartThemeBrownSand elif theme == 4: - theme_name = qchart.ChartThemeBlueNcs + theme_name = QtCharts.QChart.ChartThemeBlueNcs elif theme == 5: - theme_name = qchart.ChartThemeHighContrast + theme_name = QtCharts.QChart.ChartThemeHighContrast elif theme == 6: - theme_name = qchart.ChartThemeBlueIcy + theme_name = QtCharts.QChart.ChartThemeBlueIcy elif theme == 7: - theme_name = qchart.ChartThemeQt + theme_name = QtCharts.QChart.ChartThemeQt else: - theme_name = qchart.ChartThemeLight + theme_name = QtCharts.QChart.ChartThemeLight chart_view.chart().setTheme(theme_name) # Set palette colors based on selected theme - if theme == qchart.ChartThemeLight: + if theme == QtCharts.QChart.ChartThemeLight: set_colors(QColor(0xf0f0f0), QColor(0x404044)) - elif theme == qchart.ChartThemeDark: + elif theme == QtCharts.QChart.ChartThemeDark: set_colors(QColor(0x121218), QColor(0xd6d6d6)) - elif theme == qchart.ChartThemeBlueCerulean: + elif theme == QtCharts.QChart.ChartThemeBlueCerulean: set_colors(QColor(0x40434a), QColor(0xd6d6d6)) - elif theme == qchart.ChartThemeBrownSand: + elif theme == QtCharts.QChart.ChartThemeBrownSand: set_colors(QColor(0x9e8965), QColor(0x404044)) - elif theme == qchart.ChartThemeBlueNcs: + elif theme == QtCharts.QChart.ChartThemeBlueNcs: set_colors(QColor(0x018bba), QColor(0x404044)) - elif theme == qchart.ChartThemeHighContrast: + elif theme == QtCharts.QChart.ChartThemeHighContrast: set_colors(QColor(0xffab03), QColor(0x181818)) - elif theme == qchart.ChartThemeBlueIcy: + elif theme == QtCharts.QChart.ChartThemeBlueIcy: set_colors(QColor(0xcee7f0), QColor(0x404044)) else: set_colors(QColor(0xf0f0f0), QColor(0x404044)) @@ -354,7 +351,16 @@ class ThemeWidget(QWidget): animation_options = chart.animationOptions() if animation_options != options: for chart_view in self.charts: - chart_view.chart().setAnimationOptions(options) + options_name = QtCharts.QChart.NoAnimation + if options == 0: + options_name = QtCharts.QChart.NoAnimation + elif options == 1: + options_name = QtCharts.QChart.GridAxisAnimations + elif options == 2: + options_name = QtCharts.QChart.SeriesAnimations + elif options == 3: + options_name = QtCharts.QChart.AllAnimations + chart_view.chart().setAnimationOptions(options_name) # Update legend alignment idx = self.ui.legendComboBox.currentIndex() @@ -365,7 +371,16 @@ class ThemeWidget(QWidget): chart_view.chart().legend().hide() else: for chart_view in self.charts: - chart_view.chart().legend().setAlignment(alignment) + alignment_name = Qt.AlignTop + if alignment == 32: + alignment_name = Qt.AlignTop + elif alignment == 64: + alignment_name = Qt.AlignBottom + elif alignment == 1: + alignment_name = Qt.AlignLeft + elif alignment == 2: + alignment_name = Qt.AlignRight + chart_view.chart().legend().setAlignment(alignment_name) chart_view.chart().legend().show() diff --git a/examples/examples.pyproject b/examples/examples.pyproject new file mode 100644 index 000000000..5c96e9978 --- /dev/null +++ b/examples/examples.pyproject @@ -0,0 +1,105 @@ +{ + "files": ["charts/memoryusage.py", + "corelib/threads/mandelbrot.py", + "corelib/tools/codecs/codecs.py", + "corelib/tools/regexp.py", + "corelib/tools/settingseditor/settingseditor.py", + "declarative/extending/chapter1-basics/basics.py", + "declarative/extending/chapter2-methods/methods.py", + "declarative/extending/chapter3-bindings/bindings.py", + "declarative/extending/chapter4-customPropertyTypes/customPropertyTypes.py", + "declarative/extending/chapter5-listproperties/listproperties.py", + "declarative/scrolling.py", + "declarative/signals/pytoqml1/main.py", + "declarative/signals/qmltopy1/main.py", + "declarative/signals/qmltopy2/main.py", + "declarative/signals/qmltopy3/main.py", + "declarative/signals/qmltopy4/main.py", + "declarative/usingmodel.py", + "macextras/macpasteboardmime.py", + "multimedia/audiooutput.py", + "multimedia/camera.py", + "multimedia/player.py", + "network/blockingfortuneclient.py", + "network/fortuneclient.py", + "network/fortuneserver.py", + "network/threadedfortuneserver.py", + "opengl/2dpainting.py", + "opengl/grabber.py", + "opengl/hellogl.py", + "opengl/overpainting.py", + "opengl/samplebuffers.py", + "opengl/textures/textures.py", + "script/helloscript.py", + "texttospeech/texttospeech.py", + "tutorial/t1.py", + "tutorial/t10.py", + "tutorial/t11.py", + "tutorial/t12.py", + "tutorial/t13.py", + "tutorial/t14.py", + "tutorial/t2.py", + "tutorial/t3.py", + "tutorial/t4.py", + "tutorial/t5.py", + "tutorial/t6.py", + "tutorial/t7.py", + "tutorial/t8.py", + "tutorial/t9.py", + "webenginewidgets/simplebrowser.py", + "widgets/animation/animatedtiles/animatedtiles.py", + "widgets/animation/appchooser/appchooser.py", + "widgets/animation/easing/easing.py", + "widgets/animation/states/states.py", + "widgets/dialogs/classwizard/classwizard.py", + "widgets/dialogs/extension.py", + "widgets/dialogs/findfiles.py", + "widgets/dialogs/standarddialogs.py", + "widgets/dialogs/trivialwizard.py", + "widgets/draganddrop/draggabletext/draggabletext.py", + "widgets/effects/lighting.py", + "widgets/graphicsview/anchorlayout.py", + "widgets/graphicsview/collidingmice/collidingmice.py", + "widgets/graphicsview/diagramscene/diagramscene.py", + "widgets/graphicsview/dragdroprobot/dragdroprobot.py", + "widgets/graphicsview/elasticnodes.py", + "widgets/itemviews/addressbook/adddialogwidget.py", + "widgets/itemviews/addressbook/addressbook.py", + "widgets/itemviews/addressbook/addresswidget.py", + "widgets/itemviews/addressbook/newaddresstab.py", + "widgets/itemviews/addressbook/tablemodel.py", + "widgets/itemviews/basicsortfiltermodel.py", + "widgets/itemviews/fetchmore.py", + "widgets/itemviews/stardelegate/stardelegate.py", + "widgets/itemviews/stardelegate/stareditor.py", + "widgets/itemviews/stardelegate/starrating.py", + "widgets/layouts/basiclayouts.py", + "widgets/layouts/dynamiclayouts.py", + "widgets/layouts/flowlayout.py", + "widgets/mainwindows/application/application.py", + "widgets/mainwindows/dockwidgets/dockwidgets.py", + "widgets/mainwindows/mdi/mdi.py", + "widgets/painting/basicdrawing/basicdrawing.py", + "widgets/painting/concentriccircles.py", + "widgets/richtext/orderform.py", + "widgets/richtext/syntaxhighlighter.py", + "widgets/richtext/syntaxhighlighter/syntaxhighlighter.py", + "widgets/richtext/textobject/textobject.py", + "widgets/state-machine/eventtrans.py", + "widgets/state-machine/factstates.py", + "widgets/state-machine/pingpong.py", + "widgets/state-machine/rogue.py", + "widgets/state-machine/trafficlight.py", + "widgets/state-machine/twowaybutton.py", + "widgets/tutorials/addressbook/part1.py", + "widgets/tutorials/addressbook/part2.py", + "widgets/tutorials/addressbook/part3.py", + "widgets/tutorials/addressbook/part4.py", + "widgets/tutorials/addressbook/part5.py", + "widgets/tutorials/addressbook/part6.py", + "widgets/tutorials/addressbook/part7.py", + "widgets/widgets/hellogl_openglwidget_legacy.py", + "widgets/widgets/tetrix.py", + "xml/dombookmarks/dombookmarks.py", + "xmlpatterns/schema/schema.py"] +} diff --git a/examples/examples.pyqtc b/examples/examples.pyqtc deleted file mode 100644 index eb0e35933..000000000 --- a/examples/examples.pyqtc +++ /dev/null @@ -1,103 +0,0 @@ -charts/memoryusage.py -corelib/threads/mandelbrot.py -corelib/tools/codecs/codecs.py -corelib/tools/regexp.py -corelib/tools/settingseditor/settingseditor.py -declarative/extending/chapter1-basics/basics.py -declarative/extending/chapter2-methods/methods.py -declarative/extending/chapter3-bindings/bindings.py -declarative/extending/chapter4-customPropertyTypes/customPropertyTypes.py -declarative/extending/chapter5-listproperties/listproperties.py -declarative/scrolling.py -declarative/signals/pytoqml1/main.py -declarative/signals/qmltopy1/main.py -declarative/signals/qmltopy2/main.py -declarative/signals/qmltopy3/main.py -declarative/signals/qmltopy4/main.py -declarative/usingmodel.py -macextras/macpasteboardmime.py -multimedia/audiooutput.py -multimedia/camera.py -multimedia/player.py -network/blockingfortuneclient.py -network/fortuneclient.py -network/fortuneserver.py -network/threadedfortuneserver.py -opengl/2dpainting.py -opengl/grabber.py -opengl/hellogl.py -opengl/overpainting.py -opengl/samplebuffers.py -opengl/textures/textures.py -script/helloscript.py -texttospeech/texttospeech.py -tutorial/t1.py -tutorial/t10.py -tutorial/t11.py -tutorial/t12.py -tutorial/t13.py -tutorial/t14.py -tutorial/t2.py -tutorial/t3.py -tutorial/t4.py -tutorial/t5.py -tutorial/t6.py -tutorial/t7.py -tutorial/t8.py -tutorial/t9.py -webenginewidgets/simplebrowser.py -widgets/animation/animatedtiles/animatedtiles.py -widgets/animation/appchooser/appchooser.py -widgets/animation/easing/easing.py -widgets/animation/states/states.py -widgets/dialogs/classwizard/classwizard.py -widgets/dialogs/extension.py -widgets/dialogs/findfiles.py -widgets/dialogs/standarddialogs.py -widgets/dialogs/trivialwizard.py -widgets/draganddrop/draggabletext/draggabletext.py -widgets/effects/lighting.py -widgets/graphicsview/anchorlayout.py -widgets/graphicsview/collidingmice/collidingmice.py -widgets/graphicsview/diagramscene/diagramscene.py -widgets/graphicsview/dragdroprobot/dragdroprobot.py -widgets/graphicsview/elasticnodes.py -widgets/itemviews/addressbook/adddialogwidget.py -widgets/itemviews/addressbook/addressbook.py -widgets/itemviews/addressbook/addresswidget.py -widgets/itemviews/addressbook/newaddresstab.py -widgets/itemviews/addressbook/tablemodel.py -widgets/itemviews/basicsortfiltermodel.py -widgets/itemviews/fetchmore.py -widgets/itemviews/stardelegate/stardelegate.py -widgets/itemviews/stardelegate/stareditor.py -widgets/itemviews/stardelegate/starrating.py -widgets/layouts/basiclayouts.py -widgets/layouts/dynamiclayouts.py -widgets/layouts/flowlayout.py -widgets/mainwindows/application/application.py -widgets/mainwindows/dockwidgets/dockwidgets.py -widgets/mainwindows/mdi/mdi.py -widgets/painting/basicdrawing/basicdrawing.py -widgets/painting/concentriccircles.py -widgets/richtext/orderform.py -widgets/richtext/syntaxhighlighter.py -widgets/richtext/syntaxhighlighter/syntaxhighlighter.py -widgets/richtext/textobject/textobject.py -widgets/state-machine/eventtrans.py -widgets/state-machine/factstates.py -widgets/state-machine/pingpong.py -widgets/state-machine/rogue.py -widgets/state-machine/trafficlight.py -widgets/state-machine/twowaybutton.py -widgets/tutorials/addressbook/part1.py -widgets/tutorials/addressbook/part2.py -widgets/tutorials/addressbook/part3.py -widgets/tutorials/addressbook/part4.py -widgets/tutorials/addressbook/part5.py -widgets/tutorials/addressbook/part6.py -widgets/tutorials/addressbook/part7.py -widgets/widgets/hellogl_openglwidget_legacy.py -widgets/widgets/tetrix.py -xml/dombookmarks/dombookmarks.py -xmlpatterns/schema/schema.py diff --git a/examples/webenginewidgets/tabbedbrowser/tabbedbrowser.pyproject b/examples/webenginewidgets/tabbedbrowser/tabbedbrowser.pyproject new file mode 100644 index 000000000..1d26848b0 --- /dev/null +++ b/examples/webenginewidgets/tabbedbrowser/tabbedbrowser.pyproject @@ -0,0 +1,5 @@ +{ + "files": ["main.py", "bookmarkwidget.py", "browsertabwidget.py", + "downloadwidget.py", "findtoolbar.py", "historywindow.py", + "webengineview.py"] +} diff --git a/examples/webenginewidgets/tabbedbrowser/tabbedbrowser.pyqtc b/examples/webenginewidgets/tabbedbrowser/tabbedbrowser.pyqtc deleted file mode 100644 index b5fbffa28..000000000 --- a/examples/webenginewidgets/tabbedbrowser/tabbedbrowser.pyqtc +++ /dev/null @@ -1,7 +0,0 @@ -main.py -bookmarkwidget.py -browsertabwidget.py -downloadwidget.py -findtoolbar.py -historywindow.py -webengineview.py diff --git a/examples/widgets/tutorials/addressbook/part2.py b/examples/widgets/tutorials/addressbook/part2.py index 92f362e78..772b4d463 100644 --- a/examples/widgets/tutorials/addressbook/part2.py +++ b/examples/widgets/tutorials/addressbook/part2.py @@ -89,7 +89,6 @@ class AddressBook(QtWidgets.QWidget): self.addressText.setReadOnly(True) self.addButton = QtWidgets.QPushButton("&Add") - self.addButton.show() self.submitButton = QtWidgets.QPushButton("&Submit") self.submitButton.hide() self.cancelButton = QtWidgets.QPushButton("&Cancel") diff --git a/examples/widgets/tutorials/addressbook/part3.py b/examples/widgets/tutorials/addressbook/part3.py index 7ef4d6f8d..835adb3c6 100644 --- a/examples/widgets/tutorials/addressbook/part3.py +++ b/examples/widgets/tutorials/addressbook/part3.py @@ -89,7 +89,6 @@ class AddressBook(QtWidgets.QWidget): self.addressText.setReadOnly(True) self.addButton = QtWidgets.QPushButton("&Add") - self.addButton.show() self.submitButton = QtWidgets.QPushButton("&Submit") self.submitButton.hide() self.cancelButton = QtWidgets.QPushButton("&Cancel") diff --git a/examples/widgets/tutorials/addressbook/part4.py b/examples/widgets/tutorials/addressbook/part4.py index 2eaa67879..93cd310be 100644 --- a/examples/widgets/tutorials/addressbook/part4.py +++ b/examples/widgets/tutorials/addressbook/part4.py @@ -92,7 +92,6 @@ class AddressBook(QtWidgets.QWidget): self.addressText.setReadOnly(True) self.addButton = QtWidgets.QPushButton("&Add") - self.addButton.show() self.editButton = QtWidgets.QPushButton("&Edit") self.editButton.setEnabled(False) self.removeButton = QtWidgets.QPushButton("&Remove") diff --git a/examples/widgets/tutorials/addressbook/part5.py b/examples/widgets/tutorials/addressbook/part5.py index 4531210a7..9ea5312db 100644 --- a/examples/widgets/tutorials/addressbook/part5.py +++ b/examples/widgets/tutorials/addressbook/part5.py @@ -92,7 +92,6 @@ class AddressBook(QtWidgets.QWidget): self.addressText.setReadOnly(True) self.addButton = QtWidgets.QPushButton("&Add") - self.addButton.show() self.editButton = QtWidgets.QPushButton("&Edit") self.editButton.setEnabled(False) self.removeButton = QtWidgets.QPushButton("&Remove") diff --git a/examples/widgets/tutorials/addressbook/part6.py b/examples/widgets/tutorials/addressbook/part6.py index f642e8616..6f0550440 100644 --- a/examples/widgets/tutorials/addressbook/part6.py +++ b/examples/widgets/tutorials/addressbook/part6.py @@ -94,7 +94,6 @@ class AddressBook(QtWidgets.QWidget): self.addressText.setReadOnly(True) self.addButton = QtWidgets.QPushButton("&Add") - self.addButton.show() self.editButton = QtWidgets.QPushButton("&Edit") self.editButton.setEnabled(False) self.removeButton = QtWidgets.QPushButton("&Remove") diff --git a/examples/widgets/tutorials/addressbook/part7.py b/examples/widgets/tutorials/addressbook/part7.py index e6cbe54d2..8ad2e35c0 100644 --- a/examples/widgets/tutorials/addressbook/part7.py +++ b/examples/widgets/tutorials/addressbook/part7.py @@ -94,7 +94,6 @@ class AddressBook(QtWidgets.QWidget): self.addressText.setReadOnly(True) self.addButton = QtWidgets.QPushButton("&Add") - self.addButton.show() self.editButton = QtWidgets.QPushButton("&Edit") self.editButton.setEnabled(False) self.removeButton = QtWidgets.QPushButton("&Remove") diff --git a/sources/pyside2/PySide2/QtUiTools/typesystem_uitools.xml b/sources/pyside2/PySide2/QtUiTools/typesystem_uitools.xml index 2cbe490aa..c3b800454 100644 --- a/sources/pyside2/PySide2/QtUiTools/typesystem_uitools.xml +++ b/sources/pyside2/PySide2/QtUiTools/typesystem_uitools.xml @@ -62,7 +62,7 @@ of the `.ui` file. (Remember that `duck punching virtual methods is an invitation for your own demise! - <http://www.pyside.org/docs/shiboken/wordsofadvice.html#duck-punching-and-virtual-methods>`_) + <https://doc.qt.io/qtforpython/shiboken2/wordsofadvice.html#duck-punching-and-virtual-methods>`_) Let's see an obvious example. If you want to create a new widget it's probable you'll end up overriding :class:`~PySide2.QtGui.QWidget`'s :meth:`~PySide2.QtGui.QWidget.paintEvent` method. diff --git a/sources/pyside2/PySide2/QtWidgets/typesystem_widgets_common.xml b/sources/pyside2/PySide2/QtWidgets/typesystem_widgets_common.xml index c2c36d60f..a41a27c33 100644 --- a/sources/pyside2/PySide2/QtWidgets/typesystem_widgets_common.xml +++ b/sources/pyside2/PySide2/QtWidgets/typesystem_widgets_common.xml @@ -610,7 +610,13 @@ <include file-name="QPair" location="global"/> </extra-includes> </object-type> - <object-type name="QGraphicsItemGroup"/> + <object-type name="QGraphicsItemGroup"> + <modify-function signature="addToGroup(QGraphicsItem*)"> + <modify-argument index="1"> + <parent index="this" action="add"/> + </modify-argument> + </modify-function> + </object-type> <object-type name="QGraphicsLineItem"/> <object-type name="QGraphicsPathItem"/> <object-type name="QGraphicsPixmapItem"> diff --git a/sources/pyside2/PySide2/glue/qtcore.cpp b/sources/pyside2/PySide2/glue/qtcore.cpp index 629484458..6259724c3 100644 --- a/sources/pyside2/PySide2/glue/qtcore.cpp +++ b/sources/pyside2/PySide2/glue/qtcore.cpp @@ -965,13 +965,33 @@ if (PyIndex_Check(_key)) { // @snippet qbytearray-msetitem // @snippet qbytearray-bufferprotocol -#if PY_VERSION_HEX < 0x03000000 - +extern "C" { // QByteArray buffer protocol functions // see: http://www.python.org/dev/peps/pep-3118/ -extern "C" { +static int SbkQByteArray_getbufferproc(PyObject* obj, Py_buffer *view, int flags) +{ + if (!view || !Shiboken::Object::isValid(obj)) + return -1; + + QByteArray* cppSelf = %CONVERTTOCPP[QByteArray*](obj); + view->obj = obj; + view->buf = reinterpret_cast<void*>(cppSelf->data()); + view->len = cppSelf->size(); + view->readonly = 0; + view->itemsize = 1; + view->format = const_cast<char*>("c"); + view->ndim = 1; + view->shape = NULL; + view->strides = &view->itemsize; + view->suboffsets = NULL; + view->internal = NULL; + + Py_XINCREF(obj); + return 0; +} +#if PY_VERSION_HEX < 0x03000000 static Py_ssize_t SbkQByteArray_segcountproc(PyObject* self, Py_ssize_t* lenp) { if (lenp) @@ -993,12 +1013,18 @@ PyBufferProcs SbkQByteArrayBufferProc = { /*bf_getreadbuffer*/ &SbkQByteArray_readbufferproc, /*bf_getwritebuffer*/ (writebufferproc) &SbkQByteArray_readbufferproc, /*bf_getsegcount*/ &SbkQByteArray_segcountproc, - /*bf_getcharbuffer*/ (charbufferproc) &SbkQByteArray_readbufferproc + /*bf_getcharbuffer*/ (charbufferproc) &SbkQByteArray_readbufferproc, + /*bf_getbuffer*/ (getbufferproc)SbkQByteArray_getbufferproc, }; +#else -} +static PyBufferProcs SbkQByteArrayBufferProc = { + /*bf_getbuffer*/ (getbufferproc)SbkQByteArray_getbufferproc, + /*bf_releasebuffer*/ (releasebufferproc)0, +}; #endif +} // @snippet qbytearray-bufferprotocol // @snippet qbytearray-operatorplus-1 @@ -1110,8 +1136,14 @@ if (PyBytes_Check(%PYARG_1)) { // @snippet qbytearray-py3 #if PY_VERSION_HEX < 0x03000000 - Shiboken::SbkType<QByteArray>()->tp_as_buffer = &SbkQByteArrayBufferProc; - Shiboken::SbkType<QByteArray>()->tp_flags |= Py_TPFLAGS_HAVE_GETCHARBUFFER; +Shiboken::SbkType<QByteArray>()->tp_as_buffer = &SbkQByteArrayBufferProc; +Shiboken::SbkType<QByteArray>()->tp_flags |= Py_TPFLAGS_HAVE_NEWBUFFER; +#else +#ifdef Py_LIMITED_API +PepType_AS_BUFFER(Shiboken::SbkType<QByteArray>()) = &SbkQByteArrayBufferProc; +#else +Shiboken::SbkType<QByteArray>()->tp_as_buffer = &SbkQByteArrayBufferProc; +#endif #endif // @snippet qbytearray-py3 diff --git a/sources/pyside2/PySide2/support/generate_pyi.py b/sources/pyside2/PySide2/support/generate_pyi.py index 21ef841fe..a92ee76f0 100644 --- a/sources/pyside2/PySide2/support/generate_pyi.py +++ b/sources/pyside2/PySide2/support/generate_pyi.py @@ -53,13 +53,6 @@ import re import subprocess import argparse import glob -# PYSIDE-953: Use a newer contextlib for Python 3.5 -skip_creation = False -if sys.version_info[:2] == (3, 5): - try: - import PySide2.support.signature # gets new contextlib - except: - skip_creation = True from contextlib import contextmanager from textwrap import dedent @@ -279,9 +272,6 @@ def single_process(lockdir): def generate_all_pyi(outpath, options): - if skip_creation: - logger.warn("Sorry, we cannot create .pyi files with Python 3.5 while PySide") - logger.warn(" is not installed. Please run it by hand!") ps = os.pathsep if options.sys_path: # make sure to propagate the paths from sys_path to subprocesses diff --git a/sources/pyside2/doc/CMakeLists.txt b/sources/pyside2/doc/CMakeLists.txt index eb5200e85..b5bde885a 100644 --- a/sources/pyside2/doc/CMakeLists.txt +++ b/sources/pyside2/doc/CMakeLists.txt @@ -28,6 +28,8 @@ configure_file("pyside-config.qdocconf.in" "${CMAKE_CURRENT_LIST_DIR}/pyside-con file(READ "${pyside2_BINARY_DIR}/pyside2_global.h" docHeaderContents) file(READ "typesystem_doc.xml.in" typeSystemDocXmlContents) +set(HAS_WEBENGINE_WIDGETS 0) + foreach(moduleIn ${all_module_shortnames}) string(TOLOWER "${moduleIn}" lowerModuleIn) set(docConf "${CMAKE_CURRENT_LIST_DIR}/qtmodules/pyside-qt${lowerModuleIn}.qdocconf.in") @@ -45,6 +47,7 @@ foreach(moduleIn ${all_module_shortnames}) set(modules Multimedia "${moduleIn}") elseif ("${moduleIn}" STREQUAL "WebEngineWidgets") set(modules WebEngine WebEngineCore "${moduleIn}") + set(HAS_WEBENGINE_WIDGETS 1) else() set(modules "${moduleIn}") endif() diff --git a/sources/pyside2/doc/conf.py.in b/sources/pyside2/doc/conf.py.in index 99b74deef..33f408354 100644 --- a/sources/pyside2/doc/conf.py.in +++ b/sources/pyside2/doc/conf.py.in @@ -18,7 +18,8 @@ import sys, os # documentation root, use os.path.abspath to make it absolute, like shown here. sys.path.append('@CMAKE_CURRENT_SOURCE_DIR@') sys.path.append('@pyside_BINARY_DIR@') -sys.path.append('@CMAKE_CURRENT_SOURCE_DIR@/../../../examples/webenginewidgets/tabbedbrowser') +if @HAS_WEBENGINE_WIDGETS@: + sys.path.append('@CMAKE_CURRENT_SOURCE_DIR@/../../../examples/webenginewidgets/tabbedbrowser') # -- General configuration ----------------------------------------------------- @@ -170,3 +171,5 @@ html_show_sourcelink = False # Link to the shiboken2 sphinx project to enable linking # between the two projects. intersphinx_mapping = {'shiboken2': ('shiboken2','@CMAKE_BINARY_DIR@/../shiboken2/doc/html/objects.inv')} + +add_module_names = False diff --git a/sources/pyside2/tests/registry/init_platform.py b/sources/pyside2/tests/registry/init_platform.py index 6031dd2ad..a324c36a2 100644 --- a/sources/pyside2/tests/registry/init_platform.py +++ b/sources/pyside2/tests/registry/init_platform.py @@ -55,8 +55,7 @@ shiboken and pysidetest projects. import sys import os import re -# PYSIDE-953: Use a newer contextlib for Python 3.5 -# from contextlib import contextmanager +from contextlib import contextmanager from textwrap import dedent script_dir = os.path.normpath(os.path.join(__file__, *".. .. .. .. ..".split())) @@ -118,9 +117,6 @@ sys.path[:0] = [os.path.join(shiboken_build_dir, "shibokenmodule"), pyside_build_dir] import PySide2 -# PYSIDE-953: Use a newer contextlib for Python 3.5 -import PySide2.support.signature # new contextlib -from contextlib import contextmanager all_modules = list("PySide2." + x for x in PySide2.__all__) diff --git a/sources/pyside2/tests/support/voidptr_test.py b/sources/pyside2/tests/support/voidptr_test.py index 330788c63..c04022489 100644 --- a/sources/pyside2/tests/support/voidptr_test.py +++ b/sources/pyside2/tests/support/voidptr_test.py @@ -38,9 +38,21 @@ class PySide2Support(unittest.TestCase): # a C++ object, a wrapped Shiboken Object type, # an object implementing the Python Buffer interface, # or another VoidPtr object. - ba = QByteArray(b"Hello world") - voidptr = VoidPtr(ba) - self.assertIsInstance(voidptr, shiboken.VoidPtr) + + # Original content + b = b"Hello world" + ba = QByteArray(b) + vp = VoidPtr(ba, ba.size()) + self.assertIsInstance(vp, shiboken.VoidPtr) + + # Create QByteArray from voidptr byte interpretation + nba = QByteArray.fromRawData(vp.toBytes()) + # Compare original bytes to toBytes() + self.assertTrue(b, vp.toBytes()) + # Compare original with new QByteArray data + self.assertTrue(b, nba.data()) + # Convert original and new to str + self.assertTrue(str(b), str(nba)) if __name__ == '__main__': unittest.main() diff --git a/sources/shiboken2/ApiExtractor/abstractmetabuilder.cpp b/sources/shiboken2/ApiExtractor/abstractmetabuilder.cpp index 37ff3b72c..0b11b1666 100644 --- a/sources/shiboken2/ApiExtractor/abstractmetabuilder.cpp +++ b/sources/shiboken2/ApiExtractor/abstractmetabuilder.cpp @@ -1840,34 +1840,27 @@ static inline AbstractMetaFunction::FunctionType functionTypeFromCodeModel(CodeM return result; } -bool AbstractMetaBuilderPrivate::setArrayArgumentType(AbstractMetaFunction *func, - const FunctionModelItem &functionItem, - int i) -{ - if (i < 0 || i >= func->arguments().size()) { - qCWarning(lcShiboken).noquote() - << msgCannotSetArrayUsage(func->minimalSignature(), i, - QLatin1String("Index out of range.")); - return false; - } - AbstractMetaType *metaType = func->arguments().at(i)->type(); - if (metaType->indirections() == 0) { - qCWarning(lcShiboken).noquote() - << msgCannotSetArrayUsage(func->minimalSignature(), i, - QLatin1String("Type does not have indirections.")); - return false; - } - TypeInfo elementType = functionItem->arguments().at(i)->type(); - elementType.setIndirections(elementType.indirections() - 1); - AbstractMetaType *element = translateType(elementType); - if (element == nullptr) { - qCWarning(lcShiboken).noquote() - << msgCannotSetArrayUsage(func->minimalSignature(), i, - QLatin1String("Cannot translate element type ") + elementType.toString()); - return false; +// Apply the <array> modifications of the arguments +static bool applyArrayArgumentModifications(const FunctionModificationList &functionMods, + AbstractMetaFunction *func, + QString *errorMessage) +{ + for (const FunctionModification &mod : functionMods) { + for (const ArgumentModification &argMod : mod.argument_mods) { + if (argMod.array) { + const int i = argMod.index - 1; + if (i < 0 || i >= func->arguments().size()) { + *errorMessage = msgCannotSetArrayUsage(func->minimalSignature(), i, + QLatin1String("Index out of range.")); + return false; + } + if (!func->arguments().at(i)->type()->applyArrayModification(errorMessage)) { + *errorMessage = msgCannotSetArrayUsage(func->minimalSignature(), i, *errorMessage); + return false; + } + } + } } - metaType->setArrayElementType(element); - metaType->setTypeUsagePattern(AbstractMetaType::NativePointerAsArrayPattern); return true; } @@ -2109,11 +2102,10 @@ AbstractMetaFunction *AbstractMetaBuilderPrivate::traverseFunction(const Functio if (!metaArguments.isEmpty()) { fixArgumentNames(metaFunction, functionMods); - for (const FunctionModification &mod : functionMods) { - for (const ArgumentModification &argMod : mod.argument_mods) { - if (argMod.array) - setArrayArgumentType(metaFunction, functionItem, argMod.index - 1); - } + QString errorMessage; + if (!applyArrayArgumentModifications(functionMods, metaFunction, &errorMessage)) { + qCWarning(lcShiboken, "While traversing %s: %s", + qPrintable(className), qPrintable(errorMessage)); } } @@ -2744,6 +2736,7 @@ bool AbstractMetaBuilderPrivate::inheritTemplate(AbstractMetaClass *subclass, { QVector<TypeInfo> targs = info.instantiations(); QVector<AbstractMetaType *> templateTypes; + QString errorMessage; if (subclass->isTypeDef()) { subclass->setHasCloneOperator(templateClass->hasCloneOperator()); @@ -2876,6 +2869,13 @@ bool AbstractMetaBuilderPrivate::inheritTemplate(AbstractMetaClass *subclass, te->addFunctionModification(mod); } + + if (!applyArrayArgumentModifications(f->modifications(subclass), f.data(), + &errorMessage)) { + qCWarning(lcShiboken, "While specializing %s (%s): %s", + qPrintable(subclass->name()), qPrintable(templateClass->name()), + qPrintable(errorMessage)); + } subclass->addFunction(f.take()); } diff --git a/sources/shiboken2/ApiExtractor/abstractmetabuilder_p.h b/sources/shiboken2/ApiExtractor/abstractmetabuilder_p.h index 226d6defd..185dd0e30 100644 --- a/sources/shiboken2/ApiExtractor/abstractmetabuilder_p.h +++ b/sources/shiboken2/ApiExtractor/abstractmetabuilder_p.h @@ -156,8 +156,6 @@ public: AbstractMetaArgumentList reverseList(const AbstractMetaArgumentList &list); void setInclude(TypeEntry *te, const QString &fileName) const; void fixArgumentNames(AbstractMetaFunction *func, const FunctionModificationList &mods); - bool setArrayArgumentType(AbstractMetaFunction *func, - const FunctionModelItem &functionItem, int i); void fillAddedFunctions(AbstractMetaClass *metaClass); diff --git a/sources/shiboken2/ApiExtractor/abstractmetalang.cpp b/sources/shiboken2/ApiExtractor/abstractmetalang.cpp index a10a15b08..95f8048cd 100644 --- a/sources/shiboken2/ApiExtractor/abstractmetalang.cpp +++ b/sources/shiboken2/ApiExtractor/abstractmetalang.cpp @@ -207,6 +207,35 @@ AbstractMetaType *AbstractMetaType::copy() const return cpy; } +// For applying the <array> function argument modification: change into a type +// where "int *" becomes "int[]". +bool AbstractMetaType::applyArrayModification(QString *errorMessage) +{ + if (m_pattern == AbstractMetaType::NativePointerAsArrayPattern) { + *errorMessage = QLatin1String("<array> modification already applied."); + return false; + } + if (m_arrayElementType != nullptr) { + QTextStream(errorMessage) << "The type \"" << cppSignature() + << "\" is an array of " << m_arrayElementType->name() << '.'; + return false; + } + if (m_indirections.isEmpty()) { + QTextStream(errorMessage) << "The type \"" << cppSignature() + << "\" does not have indirections."; + return false; + } + // Element type to be used for ArrayHandle<>, strip constness. + auto elementType = copy(); + elementType->m_indirections.pop_front(); + elementType->setConstant(false); + elementType->setVolatile(false); + elementType->decideUsagePattern(); + m_arrayElementType = elementType; + setTypeUsagePattern(AbstractMetaType::NativePointerAsArrayPattern); + return true; +} + AbstractMetaTypeCList AbstractMetaType::nestedArrayTypes() const { AbstractMetaTypeCList result; @@ -1256,6 +1285,8 @@ void AbstractMetaFunction::formatDebugVerbose(QDebug &d) const d << " [userAdded]"; if (m_explicit) d << " [explicit]"; + if (attributes().testFlag(AbstractMetaAttributes::Deprecated)) + d << " [deprecated]"; if (m_pointerOperator) d << " [operator->]"; if (m_isCallOperator) @@ -2608,6 +2639,8 @@ QDebug operator<<(QDebug d, const AbstractMetaClass *ac) d << '"' << ac->fullName() << '"'; if (ac->attributes() & AbstractMetaAttributes::FinalCppClass) d << " [final]"; + if (ac->attributes().testFlag(AbstractMetaAttributes::Deprecated)) + d << " [deprecated]"; if (ac->m_baseClass) d << ", inherits \"" << ac->m_baseClass->name() << '"'; if (ac->m_templateBaseClass) diff --git a/sources/shiboken2/ApiExtractor/abstractmetalang.h b/sources/shiboken2/ApiExtractor/abstractmetalang.h index 074adbe00..9d36706ac 100644 --- a/sources/shiboken2/ApiExtractor/abstractmetalang.h +++ b/sources/shiboken2/ApiExtractor/abstractmetalang.h @@ -488,6 +488,7 @@ public: QString cppSignature() const; AbstractMetaType *copy() const; + bool applyArrayModification(QString *errorMessage); const TypeEntry *typeEntry() const { diff --git a/sources/shiboken2/ApiExtractor/typesystem.h b/sources/shiboken2/ApiExtractor/typesystem.h index 36a75c599..96d0bb5fd 100644 --- a/sources/shiboken2/ApiExtractor/typesystem.h +++ b/sources/shiboken2/ApiExtractor/typesystem.h @@ -46,8 +46,6 @@ extern const char *TARGET_CONVERSION_RULE_FLAG; extern const char *NATIVE_CONVERSION_RULE_FLAG; -class Indentor; - class AbstractMetaType; QT_BEGIN_NAMESPACE class QDebug; diff --git a/sources/shiboken2/generator/generator.h b/sources/shiboken2/generator/generator.h index cdf6d89b3..04840427f 100644 --- a/sources/shiboken2/generator/generator.h +++ b/sources/shiboken2/generator/generator.h @@ -29,6 +29,7 @@ #ifndef GENERATOR_H #define GENERATOR_H +#include "indentor.h" #include <abstractmetalang_typedefs.h> #include <typedatabase_typedefs.h> #include <dependency.h> @@ -54,7 +55,6 @@ QT_END_NAMESPACE class PrimitiveTypeEntry; class ContainerTypeEntry; -class Indentor; QTextStream& formatCode(QTextStream &s, const QString& code, Indentor &indentor); void verifyDirectoryFor(const QString &file); @@ -417,41 +417,5 @@ Q_DECLARE_OPERATORS_FOR_FLAGS(Generator::Options) typedef QSharedPointer<Generator> GeneratorPtr; typedef QVector<GeneratorPtr> Generators; -/** -* Utility class to store the identation level, use it in a QTextStream. -*/ -class Indentor -{ -public: - Indentor() : indent(0) {} - int indent; -}; - -/** -* Class that use the RAII idiom to set and unset the identation level. -*/ -class Indentation -{ -public: - Indentation(Indentor &indentor) : indentor(indentor) - { - indentor.indent++; - } - ~Indentation() - { - indentor.indent--; - } - -private: - Indentor &indentor; -}; - -inline QTextStream &operator <<(QTextStream &s, const Indentor &indentor) -{ - for (int i = 0; i < indentor.indent; ++i) - s << " "; - return s; -} - #endif // GENERATOR_H diff --git a/sources/shiboken2/generator/indentor.h b/sources/shiboken2/generator/indentor.h new file mode 100644 index 000000000..111259f12 --- /dev/null +++ b/sources/shiboken2/generator/indentor.h @@ -0,0 +1,85 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt for Python. +** +** $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$ +** +****************************************************************************/ + +#ifndef INDENTOR_H +#define INDENTOR_H + +#include <QtCore/QTextStream> + +/** +* Utility class to store the indentation level, use it in a QTextStream. +*/ + +template <int tabWidth> +class IndentorBase +{ +public: + int total() const { return tabWidth * indent; } + + int indent = 0; +}; + +using Indentor = IndentorBase<4>; +using Indentor1 = IndentorBase<1>; + +/** +* Class that use the RAII idiom to set and unset the indentation level. +*/ + +template <int tabWidth> +class IndentationBase +{ +public: + using Indentor = IndentorBase<tabWidth>; + + IndentationBase(Indentor &indentor, int count = 1) : m_count(count), indentor(indentor) + { + indentor.indent += m_count; + } + + ~IndentationBase() + { + indentor.indent -= m_count; + } + +private: + const int m_count; + Indentor &indentor; +}; + +using Indentation = IndentationBase<4>; + +template <int tabWidth> +inline QTextStream &operator <<(QTextStream &s, const IndentorBase<tabWidth> &indentor) +{ + for (int i = 0, total = indentor.total(); i < total; ++i) + s << ' '; + return s; +} + +#endif // GENERATOR_H diff --git a/sources/shiboken2/generator/qtdoc/qtdocgenerator.cpp b/sources/shiboken2/generator/qtdoc/qtdocgenerator.cpp index c194c0ea4..9410bc158 100644 --- a/sources/shiboken2/generator/qtdoc/qtdocgenerator.cpp +++ b/sources/shiboken2/generator/qtdoc/qtdocgenerator.cpp @@ -55,6 +55,13 @@ static inline QString briefAttribute() { return QStringLiteral("brief"); } static inline QString none() { return QStringLiteral("None"); } +static void stripPythonQualifiers(QString *s) +{ + const int lastSep = s->lastIndexOf(QLatin1Char('.')); + if (lastSep != -1) + s->remove(0, lastSep + 1); +} + static bool shouldSkip(const AbstractMetaFunction* func) { // Constructors go to separate section @@ -167,12 +174,33 @@ static QTextStream &ensureEndl(QTextStream &s) return s; } -static void formatSince(QTextStream &s, const char *what, const TypeEntry *te) +static inline QVersionNumber versionOf(const TypeEntry *te) { - if (te && te->version() > QVersionNumber(0, 0)) { - s << ".. note:: This " << what << " was introduced in Qt " - << te->version().toString() << '.' << endl; + if (te) { + const auto version = te->version(); + if (!version.isNull() && version > QVersionNumber(0, 0)) + return version; } + return QVersionNumber(); +} + +struct rstVersionAdded +{ + explicit rstVersionAdded(const QVersionNumber &v) : m_version(v) {} + + const QVersionNumber m_version; +}; + +static QTextStream &operator<<(QTextStream &s, const rstVersionAdded &v) +{ + s << ".. versionadded:: "<< v.m_version.toString() << "\n\n"; + return s; +} + +static QByteArray rstDeprecationNote(const char *what) +{ + return QByteArrayLiteral(".. note:: This ") + + what + QByteArrayLiteral(" is deprecated.\n\n"); } // RST anchor string: Anything else but letters, numbers, '_' or '.' replaced by '-' @@ -1013,22 +1041,19 @@ static QString fixLinkText(const QtXmlToSphinx::LinkContext *linkContext, || linkContext->type == QtXmlToSphinx::LinkContext::Reference) { return linktext; } - // For the language reference documentation, clear the link text if it matches - // the function/class/enumeration name. - linktext.replace(QLatin1String("::"), QLatin1String(".")); + // For the language reference documentation, strip the module name. + // Clear the link text if that matches the function/class/enumeration name. + const int lastSep = linktext.lastIndexOf(QLatin1String("::")); + if (lastSep != -1) + linktext.remove(0, lastSep + 2); + else + stripPythonQualifiers(&linktext); if (linkContext->linkRef == linktext) return QString(); if ((linkContext->type & QtXmlToSphinx::LinkContext::FunctionMask) != 0 && (linkContext->linkRef + QLatin1String("()")) == linktext) { return QString(); } - const QStringRef item = linkContext->linkRef.splitRef(QLatin1Char('.')).constLast(); - if (item == linktext) - return QString(); - if ((linkContext->type & QtXmlToSphinx::LinkContext::FunctionMask) != 0 - && (item + QLatin1String("()")) == linktext) { - return QString(); - } return linktext; } @@ -1576,7 +1601,11 @@ void QtDocGenerator::generateClass(QTextStream &s, GeneratorContext &classContex writeInheritedByList(s, metaClass, classes()); - formatSince(s, "class", metaClass->typeEntry()); + const auto version = versionOf(metaClass->typeEntry()); + if (!version.isNull()) + s << rstVersionAdded(version); + if (metaClass->attributes().testFlag(AbstractMetaAttributes::Deprecated)) + s << rstDeprecationNote("class"); writeFunctionList(s, metaClass); @@ -1608,7 +1637,7 @@ void QtDocGenerator::generateClass(QTextStream &s, GeneratorContext &classContex else s << ".. method:: "; - writeFunction(s, true, metaClass, func); + writeFunction(s, metaClass, func); } writeInjectDocumentation(s, TypeSystem::DocModificationAppend, metaClass, 0); @@ -1697,7 +1726,9 @@ void QtDocGenerator::writeEnums(QTextStream& s, const AbstractMetaClass* cppClas for (AbstractMetaEnum *en : enums) { s << section_title << getClassTargetFullName(cppClass) << '.' << en->name() << endl << endl; writeFormattedText(s, en->documentation(), cppClass); - formatSince(s, "enum", en->typeEntry()); + const auto version = versionOf(en->typeEntry()); + if (!version.isNull()) + s << rstVersionAdded(version); } } @@ -1717,7 +1748,6 @@ void QtDocGenerator::writeFields(QTextStream& s, const AbstractMetaClass* cppCla void QtDocGenerator::writeConstructors(QTextStream& s, const AbstractMetaClass* cppClass) { static const QString sectionTitle = QLatin1String(".. class:: "); - static const QString sectionTitleSpace = QString(sectionTitle.size(), QLatin1Char(' ')); AbstractMetaFunctionList lst = cppClass->queryFunctions(AbstractMetaClass::Constructors | AbstractMetaClass::Visible); for (int i = lst.size() - 1; i >= 0; --i) { @@ -1728,14 +1758,23 @@ void QtDocGenerator::writeConstructors(QTextStream& s, const AbstractMetaClass* bool first = true; QHash<QString, AbstractMetaArgument*> arg_map; + IndentorBase<1> indent1; + indent1.indent = INDENT.total(); for (AbstractMetaFunction *func : qAsConst(lst)) { + s << indent1; if (first) { first = false; s << sectionTitle; - } else { - s << sectionTitleSpace; + indent1.indent += sectionTitle.size(); } - writeFunction(s, false, cppClass, func); + s << functionSignature(cppClass, func) << "\n\n"; + + const auto version = versionOf(func->typeEntry()); + if (!version.isNull()) + s << indent1 << rstVersionAdded(version); + if (func->attributes().testFlag(AbstractMetaAttributes::Deprecated)) + s << indent1 << rstDeprecationNote("constructor"); + const AbstractMetaArgumentList &arguments = func->arguments(); for (AbstractMetaArgument *arg : arguments) { if (!arg_map.contains(arg->name())) { @@ -1747,7 +1786,7 @@ void QtDocGenerator::writeConstructors(QTextStream& s, const AbstractMetaClass* s << endl; for (QHash<QString, AbstractMetaArgument*>::const_iterator it = arg_map.cbegin(), end = arg_map.cend(); it != end; ++it) { - Indentation indentation(INDENT); + Indentation indentation(INDENT, 2); writeParameterType(s, cppClass, it.value()); } @@ -1910,7 +1949,7 @@ bool QtDocGenerator::writeInjectDocumentation(QTextStream& s, return didSomething; } -void QtDocGenerator::writeFunctionSignature(QTextStream& s, const AbstractMetaClass* cppClass, const AbstractMetaFunction* func) +QString QtDocGenerator::functionSignature(const AbstractMetaClass* cppClass, const AbstractMetaFunction* func) { QString className; if (!func->isConstructor()) @@ -1922,23 +1961,25 @@ void QtDocGenerator::writeFunctionSignature(QTextStream& s, const AbstractMetaCl if (!funcName.startsWith(className)) funcName = className + funcName; - s << funcName << "(" << parseArgDocStyle(cppClass, func) << ")"; + return funcName + QLatin1Char('(') + parseArgDocStyle(cppClass, func) + + QLatin1Char(')'); } QString QtDocGenerator::translateToPythonType(const AbstractMetaType* type, const AbstractMetaClass* cppClass) { QString strType; - if (type->name() == QLatin1String("QString")) { + const QString name = type->name(); + if (name == QLatin1String("QString")) { strType = QLatin1String("unicode"); - } else if (type->name() == QLatin1String("QVariant")) { + } else if (name == QLatin1String("QVariant")) { strType = QLatin1String("object"); - } else if (type->name() == QLatin1String("QStringList")) { + } else if (name == QLatin1String("QStringList")) { strType = QLatin1String("list of strings"); - } else if (type->isConstant() && type->name() == QLatin1String("char") && type->indirections() == 1) { + } else if (type->isConstant() && name == QLatin1String("char") && type->indirections() == 1) { strType = QLatin1String("str"); - } else if (type->name().startsWith(QLatin1String("unsigned short"))) { + } else if (name.startsWith(QLatin1String("unsigned short"))) { strType = QLatin1String("int"); - } else if (type->name().startsWith(QLatin1String("unsigned "))) { // uint and ulong + } else if (name.startsWith(QLatin1String("unsigned "))) { // uint and ulong strType = QLatin1String("long"); } else if (type->isContainer()) { QString strType = translateType(type, cppClass, Options(ExcludeConst) | ExcludeReference); @@ -1962,7 +2003,7 @@ QString QtDocGenerator::translateToPythonType(const AbstractMetaType* type, cons refTag = QLatin1String("attr"); else refTag = QLatin1String("class"); - strType = QLatin1Char(':') + refTag + QLatin1String(":`") + type->fullName() + QLatin1Char('`'); + strType = QLatin1Char(':') + refTag + QLatin1String(":`") + name + QLatin1Char('`'); } return strType; } @@ -1976,8 +2017,6 @@ void QtDocGenerator::writeParameterType(QTextStream& s, const AbstractMetaClass* void QtDocGenerator::writeFunctionParametersType(QTextStream &s, const AbstractMetaClass *cppClass, const AbstractMetaFunction *func) { - Indentation indentation(INDENT); - s << endl; const AbstractMetaArgumentList &funcArgs = func->arguments(); for (AbstractMetaArgument *arg : funcArgs) { @@ -2009,22 +2048,25 @@ void QtDocGenerator::writeFunctionParametersType(QTextStream &s, const AbstractM s << endl; } -void QtDocGenerator::writeFunction(QTextStream& s, bool writeDoc, const AbstractMetaClass* cppClass, const AbstractMetaFunction* func) +void QtDocGenerator::writeFunction(QTextStream& s, const AbstractMetaClass* cppClass, + const AbstractMetaFunction* func) { - writeFunctionSignature(s, cppClass, func); - s << endl; - - formatSince(s, "method", func->typeEntry()); + s << functionSignature(cppClass, func) << "\n\n"; - if (writeDoc) { - s << endl; + { + Indentation indentation(INDENT); writeFunctionParametersType(s, cppClass, func); - s << endl; - writeInjectDocumentation(s, TypeSystem::DocModificationPrepend, cppClass, func); - if (!writeInjectDocumentation(s, TypeSystem::DocModificationReplace, cppClass, func)) - writeFormattedText(s, func->documentation(), cppClass); - writeInjectDocumentation(s, TypeSystem::DocModificationAppend, cppClass, func); + const auto version = versionOf(func->typeEntry()); + if (!version.isNull()) + s << INDENT << rstVersionAdded(version); + if (func->attributes().testFlag(AbstractMetaAttributes::Deprecated)) + s << INDENT << rstDeprecationNote("function"); } + + writeInjectDocumentation(s, TypeSystem::DocModificationPrepend, cppClass, func); + if (!writeInjectDocumentation(s, TypeSystem::DocModificationReplace, cppClass, func)) + writeFormattedText(s, func->documentation(), cppClass); + writeInjectDocumentation(s, TypeSystem::DocModificationAppend, cppClass, func); } static void writeFancyToc(QTextStream& s, const QStringList& items, int cols = 4) @@ -2159,7 +2201,7 @@ void QtDocGenerator::writeModuleDocumentation() Documentation moduleDoc = m_docParser->retrieveModuleDocumentation(it.key()); if (moduleDoc.format() == Documentation::Native) { QString context = it.key(); - context.remove(0, context.lastIndexOf(QLatin1Char('.')) + 1); + stripPythonQualifiers(&context); QtXmlToSphinx x(this, moduleDoc.value(), context); s << x; } else { diff --git a/sources/shiboken2/generator/qtdoc/qtdocgenerator.h b/sources/shiboken2/generator/qtdoc/qtdocgenerator.h index 5545de9a9..43345716d 100644 --- a/sources/shiboken2/generator/qtdoc/qtdocgenerator.h +++ b/sources/shiboken2/generator/qtdoc/qtdocgenerator.h @@ -239,8 +239,9 @@ private: void writeFields(QTextStream &s, const AbstractMetaClass *cppClass); void writeArguments(QTextStream &s, const AbstractMetaClass *cppClass, const AbstractMetaFunction *func); - void writeFunctionSignature(QTextStream& s, const AbstractMetaClass* cppClass, const AbstractMetaFunction* func); - void writeFunction(QTextStream& s, bool writeDoc, const AbstractMetaClass* cppClass, const AbstractMetaFunction* func); + QString functionSignature(const AbstractMetaClass* cppClass, const AbstractMetaFunction* func); + void writeFunction(QTextStream& s, const AbstractMetaClass* cppClass, + const AbstractMetaFunction* func); void writeFunctionParametersType(QTextStream &s, const AbstractMetaClass *cppClass, const AbstractMetaFunction* func); void writeFunctionList(QTextStream& s, const AbstractMetaClass* cppClass); diff --git a/sources/shiboken2/generator/shiboken2/cppgenerator.cpp b/sources/shiboken2/generator/shiboken2/cppgenerator.cpp index f2112e34f..86a632e78 100644 --- a/sources/shiboken2/generator/shiboken2/cppgenerator.cpp +++ b/sources/shiboken2/generator/shiboken2/cppgenerator.cpp @@ -2091,10 +2091,7 @@ void CppGenerator::writeCppSelfDefinition(QTextStream &s, QString checkFunc = cpythonCheckFunction(func->ownerClass()->typeEntry()); s << INDENT << "bool isReverse = " << checkFunc << PYTHON_ARG << ')' << endl; { - Indentation indent1(INDENT); - Indentation indent2(INDENT); - Indentation indent3(INDENT); - Indentation indent4(INDENT); + Indentation indent1(INDENT, 4); s << INDENT << "&& !" << checkFunc << "self);" << endl; } s << INDENT << "if (isReverse)" << endl; @@ -5536,7 +5533,7 @@ bool CppGenerator::finishGeneration() if (usePySideExtensions()) { s << "void cleanTypesAttributes(void) {" << endl; s << INDENT << "if (PY_VERSION_HEX >= 0x03000000 && PY_VERSION_HEX < 0x03060000)" << endl; - s << INDENT << " return; // testbinding crashes in Python 3.5 when hasattr touches types!" << endl; + s << INDENT << " return; // PYSIDE-953: testbinding crashes in Python 3.5 when hasattr touches types!" << endl; s << INDENT << "for (int i = 0, imax = SBK_" << moduleName() << "_IDX_COUNT; i < imax; i++) {" << endl; { Indentation indentation(INDENT); diff --git a/sources/shiboken2/generator/shiboken2/overloaddata.cpp b/sources/shiboken2/generator/shiboken2/overloaddata.cpp index a95603754..6a85bf7ef 100644 --- a/sources/shiboken2/generator/shiboken2/overloaddata.cpp +++ b/sources/shiboken2/generator/shiboken2/overloaddata.cpp @@ -30,6 +30,7 @@ #include <reporthandler.h> #include <graph.h> #include "overloaddata.h" +#include "indentor.h" #include "shibokengenerator.h" #include <QtCore/QDir> @@ -857,13 +858,14 @@ static inline QString toHtml(QString s) QString OverloadData::dumpGraph() const { - QString indent(4, QLatin1Char(' ')); + Indentor INDENT; + Indentation indent(INDENT); QString result; QTextStream s(&result); if (m_argPos == -1) { const AbstractMetaFunction* rfunc = referenceFunction(); s << "digraph OverloadedFunction {" << endl; - s << indent << "graph [fontsize=12 fontname=freemono labelloc=t splines=true overlap=false rankdir=LR];" << endl; + s << INDENT << "graph [fontsize=12 fontname=freemono labelloc=t splines=true overlap=false rankdir=LR];" << endl; // Shows all function signatures s << "legend [fontsize=9 fontname=freemono shape=rect label=\""; @@ -878,7 +880,7 @@ QString OverloadData::dumpGraph() const s << "\"];" << endl; // Function box title - s << indent << '"' << rfunc->name() << "\" [shape=plaintext style=\"filled,bold\" margin=0 fontname=freemono fillcolor=white penwidth=1 "; + s << INDENT << '"' << rfunc->name() << "\" [shape=plaintext style=\"filled,bold\" margin=0 fontname=freemono fillcolor=white penwidth=1 "; s << "label=<<table border=\"0\" cellborder=\"0\" cellpadding=\"3\" bgcolor=\"white\">"; s << "<tr><td bgcolor=\"black\" align=\"center\" cellpadding=\"6\" colspan=\"2\"><font color=\"white\">"; if (rfunc->ownerClass()) @@ -931,14 +933,14 @@ QString OverloadData::dumpGraph() const s << "</table>> ];" << endl; for (const OverloadData *pd : m_nextOverloadData) - s << indent << '"' << rfunc->name() << "\" -> " << pd->dumpGraph(); + s << INDENT << '"' << rfunc->name() << "\" -> " << pd->dumpGraph(); s << "}" << endl; } else { QString argId = QLatin1String("arg_") + QString::number(quintptr(this)); s << argId << ';' << endl; - s << indent << '"' << argId << "\" [shape=\"plaintext\" style=\"filled,bold\" margin=\"0\" fontname=\"freemono\" fillcolor=\"white\" penwidth=1 "; + s << INDENT << '"' << argId << "\" [shape=\"plaintext\" style=\"filled,bold\" margin=\"0\" fontname=\"freemono\" fillcolor=\"white\" penwidth=1 "; s << "label=<<table border=\"0\" cellborder=\"0\" cellpadding=\"3\" bgcolor=\"white\">"; // Argument box title @@ -982,7 +984,7 @@ QString OverloadData::dumpGraph() const s << "</table>>];" << endl; for (const OverloadData *pd : m_nextOverloadData) - s << indent << argId << " -> " << pd->dumpGraph(); + s << INDENT << argId << " -> " << pd->dumpGraph(); } return result; } diff --git a/sources/shiboken2/libshiboken/signature.cpp b/sources/shiboken2/libshiboken/signature.cpp index 61a097771..cd00a1482 100644 --- a/sources/shiboken2/libshiboken/signature.cpp +++ b/sources/shiboken2/libshiboken/signature.cpp @@ -167,8 +167,11 @@ _get_class_of_descr(PyObject *ob) static PyObject * GetClassOfFunc(PyObject *ob) { - if (PyType_Check(ob)) + if (PyType_Check(ob)) { + // PySide-928: The type case must do refcounting like the others as well. + Py_INCREF(ob); return ob; + } if (PyType_IsSubtype(Py_TYPE(ob), &PyCFunction_Type)) return _get_class_of_cf(ob); if (Py_TYPE(ob) == PepStaticMethod_TypePtr) @@ -535,6 +538,10 @@ error: static int _fixup_getset(PyTypeObject *type, const char *name, PyGetSetDef *new_gsp) { + /* + * This function pre-fills all fields of the new gsp. We then + * insert the changed values. + */ PyGetSetDef *gsp = type->tp_getset; if (gsp != nullptr) { for (; gsp->name != NULL; gsp++) { @@ -542,7 +549,7 @@ _fixup_getset(PyTypeObject *type, const char *name, PyGetSetDef *new_gsp) new_gsp->set = gsp->set; new_gsp->doc = gsp->doc; new_gsp->closure = gsp->closure; - return 1; + return 1; // success } } } diff --git a/sources/shiboken2/libshiboken/voidptr.cpp b/sources/shiboken2/libshiboken/voidptr.cpp index a306f7a9d..e55ccfab5 100644 --- a/sources/shiboken2/libshiboken/voidptr.cpp +++ b/sources/shiboken2/libshiboken/voidptr.cpp @@ -95,13 +95,6 @@ int SbkVoidPtrObject_init(PyObject *self, PyObject *args, PyObject *kwds) sbkSelf->size = sbkOther->size; sbkSelf->isWritable = sbkOther->isWritable; } - // Shiboken::Object wrapper. - else if (Shiboken::Object::checkType(addressObject)) { - SbkObject *sbkOther = reinterpret_cast<SbkObject *>(addressObject); - sbkSelf->cptr = sbkOther->d->cptr[0]; - sbkSelf->size = size; - sbkSelf->isWritable = isWritable > 0 ? true : false; - } // Python buffer interface. else if (PyObject_CheckBuffer(addressObject)) { Py_buffer bufferView; @@ -111,26 +104,41 @@ int SbkVoidPtrObject_init(PyObject *self, PyObject *args, PyObject *kwds) return 0; sbkSelf->cptr = bufferView.buf; - sbkSelf->size = bufferView.len; + sbkSelf->size = bufferView.len > 0 ? bufferView.len : size; sbkSelf->isWritable = bufferView.readonly > 0 ? false : true; // Release the buffer. PyBuffer_Release(&bufferView); } + // Shiboken::Object wrapper. + else if (Shiboken::Object::checkType(addressObject)) { + SbkObject *sbkOther = reinterpret_cast<SbkObject *>(addressObject); + sbkSelf->cptr = sbkOther->d->cptr[0]; + sbkSelf->size = size; + sbkSelf->isWritable = isWritable > 0 ? true : false; + } // An integer representing an address. else { - void *cptr = PyLong_AsVoidPtr(addressObject); - if (PyErr_Occurred()) { - PyErr_SetString(PyExc_TypeError, - "Creating a VoidPtr object requires an address of a C++ object, " - "a wrapped Shiboken Object type, " - "an object implementing the Python Buffer interface, " - "or another VoidPtr object."); - return -1; + if (addressObject == Py_None) { + sbkSelf->cptr = nullptr; + sbkSelf->size = 0; + sbkSelf->isWritable = false; + } + + else { + void *cptr = PyLong_AsVoidPtr(addressObject); + if (PyErr_Occurred()) { + PyErr_SetString(PyExc_TypeError, + "Creating a VoidPtr object requires an address of a C++ object, " + "a wrapped Shiboken Object type, " + "an object implementing the Python Buffer interface, " + "or another VoidPtr object."); + return -1; + } + sbkSelf->cptr = cptr; + sbkSelf->size = size; + sbkSelf->isWritable = isWritable > 0 ? true : false; } - sbkSelf->cptr = cptr; - sbkSelf->size = size; - sbkSelf->isWritable = isWritable > 0 ? true : false; } return 0; @@ -174,6 +182,24 @@ PyObject *SbkVoidPtrObject_int(PyObject *v) return PyLong_FromVoidPtr(sbkObject->cptr); } +PyObject *toBytes(PyObject *self, PyObject *args) +{ + SbkVoidPtrObject *sbkObject = reinterpret_cast<SbkVoidPtrObject *>(self); + if (sbkObject->size < 0) { + PyErr_SetString(PyExc_IndexError, "VoidPtr does not have a size set."); + return nullptr; + } + PyObject *bytes = PyBytes_FromStringAndSize(reinterpret_cast<const char*>(sbkObject->cptr), + sbkObject->size); + Py_XINCREF(bytes); + return bytes; +} + +static struct PyMethodDef SbkVoidPtrObject_methods[] = { + {"toBytes", toBytes, METH_NOARGS}, + {0} +}; + static Py_ssize_t SbkVoidPtrObject_length(PyObject *v) { SbkVoidPtrObject *sbkObject = reinterpret_cast<SbkVoidPtrObject *>(v); @@ -233,6 +259,7 @@ static PyType_Slot SbkVoidPtrType_slots[] = { {Py_tp_init, (void *)SbkVoidPtrObject_init}, {Py_tp_new, (void *)SbkVoidPtrObject_new}, {Py_tp_dealloc, (void *)object_dealloc}, + {Py_tp_methods, (void *)SbkVoidPtrObject_methods}, {0, 0} }; static PyType_Spec SbkVoidPtrType_spec = { diff --git a/sources/shiboken2/shibokenmodule/CMakeLists.txt b/sources/shiboken2/shibokenmodule/CMakeLists.txt index 952d31994..b37d0c941 100644 --- a/sources/shiboken2/shibokenmodule/CMakeLists.txt +++ b/sources/shiboken2/shibokenmodule/CMakeLists.txt @@ -70,10 +70,6 @@ configure_file("${CMAKE_CURRENT_SOURCE_DIR}/support/signature/lib/__init__.py" configure_file("${CMAKE_CURRENT_SOURCE_DIR}/support/signature/lib/enum_sig.py" "${CMAKE_CURRENT_BINARY_DIR}/support/signature/lib/enum_sig.py" COPYONLY) if (PYTHON_VERSION_MAJOR EQUAL 3) - if (PYTHON_VERSION_MINOR EQUAL 5) - configure_file("${CMAKE_CURRENT_SOURCE_DIR}/support/signature/contextlib36.py" - "${CMAKE_CURRENT_BINARY_DIR}/support/signature/contextlib36.py" COPYONLY) - endif() else() configure_file("${CMAKE_CURRENT_SOURCE_DIR}/support/signature/backport_inspect.py" "${CMAKE_CURRENT_BINARY_DIR}/support/signature/backport_inspect.py" COPYONLY) diff --git a/sources/shiboken2/shibokenmodule/support/signature/fix-complaints.py b/sources/shiboken2/shibokenmodule/support/signature/fix-complaints.py index ef18beb67..cdd84f9be 100644 --- a/sources/shiboken2/shibokenmodule/support/signature/fix-complaints.py +++ b/sources/shiboken2/shibokenmodule/support/signature/fix-complaints.py @@ -49,7 +49,7 @@ you are changing messages (what I did, of course :-) . import os -patched_modules = "backport_inspect typing27 contextlib36" +patched_modules = "backport_inspect typing27" offending_words = { "behavio""ur": "behavior", diff --git a/sources/shiboken2/shibokenmodule/support/signature/loader.py b/sources/shiboken2/shibokenmodule/support/signature/loader.py index 749229c3b..458759845 100644 --- a/sources/shiboken2/shibokenmodule/support/signature/loader.py +++ b/sources/shiboken2/shibokenmodule/support/signature/loader.py @@ -158,10 +158,6 @@ with ensure_import_support(): import typing import inspect inspect.formatannotation = formatannotation - if sys.version_info[:2] == (3, 5): - # PYSIDE-953: Use a newer contextlib. - from support.signature import contextlib36 as contextlib - sys.modules["contextlib"] = contextlib else: import inspect namespace = inspect.__dict__ diff --git a/sources/shiboken2/tests/libsample/nontypetemplate.h b/sources/shiboken2/tests/libsample/nontypetemplate.h index 4e2100626..5a9e670c6 100644 --- a/sources/shiboken2/tests/libsample/nontypetemplate.h +++ b/sources/shiboken2/tests/libsample/nontypetemplate.h @@ -37,6 +37,7 @@ template <int Size> class IntArray { public: + explicit IntArray(const int *data) { std::copy(data, data + Size, m_array); } explicit IntArray(int v) { std::fill(m_array, m_array + Size, v); } int sum() const { return std::accumulate(m_array, m_array + Size, int(0)); } diff --git a/sources/shiboken2/tests/samplebinding/nontypetemplate_test.py b/sources/shiboken2/tests/samplebinding/nontypetemplate_test.py index 9adfa2441..a7a4da72b 100644 --- a/sources/shiboken2/tests/samplebinding/nontypetemplate_test.py +++ b/sources/shiboken2/tests/samplebinding/nontypetemplate_test.py @@ -28,6 +28,14 @@ ## ############################################################################# +hasNumPy = False + +try: + import numpy + hasNumPy = True +except ImportError: + pass + import unittest from sample import IntArray2, IntArray3 @@ -40,5 +48,12 @@ class NonTypeTemplateTest(unittest.TestCase): array3 = IntArray3(5) self.assertEqual(array3.sum(), 15) + def testArrayInitializer(self): + if not hasNumPy: + return + array3 = IntArray3(numpy.array([1, 2, 3], dtype = 'int32')) + self.assertEqual(array3.sum(), 6) + + if __name__ == '__main__': unittest.main() diff --git a/sources/shiboken2/tests/samplebinding/typesystem_sample.xml b/sources/shiboken2/tests/samplebinding/typesystem_sample.xml index 9b967fc53..78ceaab43 100644 --- a/sources/shiboken2/tests/samplebinding/typesystem_sample.xml +++ b/sources/shiboken2/tests/samplebinding/typesystem_sample.xml @@ -521,8 +521,17 @@ </value-type> <value-type name="IntArray" generate="no"/> - <value-type name="IntArray2"/> - <value-type name="IntArray3"/> + <value-type name="IntArray2"> + <modify-function signature="IntArray2(const int*)"> + <modify-argument index="1"><array/></modify-argument> + </modify-function> + </value-type> + + <value-type name="IntArray3"> + <modify-function signature="IntArray3(const int*)"> + <modify-argument index="1"><array/></modify-argument> + </modify-function> + </value-type> <enum-type name="OverloadedFuncEnum"/> <!-- BUG: diff --git a/testing/runner.py b/testing/runner.py index baa29408c..3db84c0fc 100644 --- a/testing/runner.py +++ b/testing/runner.py @@ -102,7 +102,7 @@ class TestRunner(object): else: # We have probably forgotten to build the tests. # Give a nice error message with a shortened but exact path. - rel_path = os.path.relpath(make_path) + rel_path = os.path.relpath(file_name) msg = dedent("""\n {line} ** ctest is not in '{}'. diff --git a/testing/testing.pyproject b/testing/testing.pyproject new file mode 100644 index 000000000..22914e5a9 --- /dev/null +++ b/testing/testing.pyproject @@ -0,0 +1,4 @@ +{ + "files": ["../testrunner.py", "blacklist.py", "buildlog.py", "command.py", + "helper.py", "__init__.py", "parser.py", "runner.py", "wheel_tester.py"] +} diff --git a/testing/testing.pyqtc b/testing/testing.pyqtc deleted file mode 100644 index 5a89e69b8..000000000 --- a/testing/testing.pyqtc +++ /dev/null @@ -1,9 +0,0 @@ -../testrunner.py -blacklist.py -buildlog.py -command.py -helper.py -__init__.py -parser.py -runner.py -wheel_tester.py |