diff options
94 files changed, 5455 insertions, 2303 deletions
diff --git a/build_scripts/main.py b/build_scripts/main.py index 26fc191c5..f288756c1 100644 --- a/build_scripts/main.py +++ b/build_scripts/main.py @@ -64,7 +64,7 @@ def get_package_version(): d['major_version'], d['minor_version'], d['patch_version']) pre_release_version_type = d['pre_release_version_type'] pre_release_version = d['pre_release_version'] - if pre_release_version and pre_release_version: + if pre_release_version and pre_release_version_type: final_version += pre_release_version_type + pre_release_version # Add the current timestamp to the version number, to suggest it @@ -73,6 +73,18 @@ def get_package_version(): final_version += ".dev{}".format(get_package_timestamp()) return final_version +def get_setuptools_extension_modules(): + # Setting py_limited_api on the extension is the "correct" thing + # to do, but it doesn't actually do anything, because we + # override build_ext. So this is just foolproofing for the + # future. + extension_args = ('QtCore', []) + extension_kwargs = {} + if OPTION_LIMITED_API: + extension_kwargs['py_limited_api'] = True + extension_modules = [Extension(*extension_args, **extension_kwargs)] + return extension_modules + # Buildable extensions. contained_modules = ['shiboken2', 'pyside2', 'pyside2-tools'] @@ -113,19 +125,12 @@ from setuptools.command.bdist_egg import bdist_egg as _bdist_egg from setuptools.command.develop import develop as _develop from setuptools.command.build_py import build_py as _build_py -wheel_module_exists = False -try: - from wheel.bdist_wheel import bdist_wheel as _bdist_wheel - from wheel.bdist_wheel import safer_name as _safer_name - wheel_module_exists = True -except ImportError: - pass - from .qtinfo import QtInfo from .utils import rmtree, detect_clang, copyfile, copydir, run_process_output, run_process from .utils import update_env_path, init_msvc_env, filter_match, macos_fix_rpaths_for_library from .platforms.unix import prepare_packages_posix from .platforms.windows_desktop import prepare_packages_win32 +from .wheel_override import wheel_module_exists, get_bdist_wheel_override from textwrap import dedent @@ -378,35 +383,7 @@ class PysideBuildExt(_build_ext): def run(self): pass -if wheel_module_exists: - class PysideBuildWheel(_bdist_wheel): - def __init__(self, *args, **kwargs): - _bdist_wheel.__init__(self, *args, **kwargs) - - @property - def wheel_dist_name(self): - # Slightly modified version of wheel's wheel_dist_name - # method, to add the Qt version as well. - # Example: - # PySide2-5.6-5.6.4-cp27-cp27m-macosx_10_10_intel.whl - # The PySide2 version is "5.6". - # The Qt version built against is "5.6.4". - qt_version = get_qt_version() - package_version = get_package_version() - wheel_version = "{}-{}".format(package_version, qt_version) - components = (_safer_name(self.distribution.get_name()), - wheel_version) - if self.build_number: - components += (self.build_number,) - return '-'.join(components) - - def finalize_options(self): - if sys.platform == 'darwin': - # Override the platform name to contain the correct - # minimum deployment target. - # This is used in the final wheel name. - self.plat_name = PysideBuild.macos_plat_name() - _bdist_wheel.finalize_options(self) + # pyside_build_py and pyside_install_lib are reimplemented to preserve # symlinks when distutils / setuptools copy files to various @@ -985,6 +962,16 @@ class PysideBuild(_build): cmake_cmd.append("-DPYTHON_DEBUG_LIBRARY={}".format( self.py_library)) + if OPTION_LIMITED_API == "yes": + cmake_cmd.append("-DFORCE_LIMITED_API=yes") + elif OPTION_LIMITED_API == "no": + cmake_cmd.append("-DFORCE_LIMITED_API=no") + elif not OPTION_LIMITED_API: + pass + else: + raise DistutilsSetupError("option limited-api must be 'yes' or 'no' " + "(default yes if applicable, i.e. python version >= 3.5)") + if OPTION_VERBOSE_BUILD: cmake_cmd.append("-DCMAKE_VERBOSE_MAKEFILE:BOOL=ON") @@ -1309,4 +1296,11 @@ cmd_class_dict = { 'install_lib': PysideInstallLib } if wheel_module_exists: - cmd_class_dict['bdist_wheel'] = PysideBuildWheel + params = {} + params['qt_version'] = get_qt_version() + params['package_version'] = get_package_version() + if sys.platform == 'darwin': + params['macos_plat_name'] = PysideBuild.macos_plat_name() + pyside_bdist_wheel = get_bdist_wheel_override(params) + if pyside_bdist_wheel: + cmd_class_dict['bdist_wheel'] = pyside_bdist_wheel diff --git a/build_scripts/options.py b/build_scripts/options.py index 80c9041e4..d7174feff 100644 --- a/build_scripts/options.py +++ b/build_scripts/options.py @@ -80,4 +80,4 @@ OPTION_QT_SRC = option_value("qt-src-dir") OPTION_VERBOSE_BUILD = has_option("verbose-build") OPTION_SANITIZE_ADDRESS = has_option("sanitize-address") OPTION_SNAPSHOT_BUILD = has_option("snapshot-build") - +OPTION_LIMITED_API = option_value("limited-api") diff --git a/build_scripts/wheel_override.py b/build_scripts/wheel_override.py new file mode 100644 index 000000000..ee8bd8382 --- /dev/null +++ b/build_scripts/wheel_override.py @@ -0,0 +1,200 @@ +############################################################################# +## +## Copyright (C) 2018 The Qt Company Ltd. +## Contact: https://www.qt.io/licensing/ +## +## This file is part of Qt for Python. +## +## $QT_BEGIN_LICENSE:LGPL$ +## Commercial License Usage +## Licensees holding valid commercial Qt licenses may use this file in +## accordance with the commercial license agreement provided with the +## Software or, alternatively, in accordance with the terms contained in +## a written agreement between you and The Qt Company. For licensing terms +## and conditions see https://www.qt.io/terms-conditions. For further +## information use the contact form at https://www.qt.io/contact-us. +## +## GNU Lesser General Public License Usage +## Alternatively, this file may be used under the terms of the GNU Lesser +## General Public License version 3 as published by the Free Software +## Foundation and appearing in the file LICENSE.LGPL3 included in the +## packaging of this file. Please review the following information to +## ensure the GNU Lesser General Public License version 3 requirements +## will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +## +## GNU General Public License Usage +## Alternatively, this file may be used under the terms of the GNU +## General Public License version 2.0 or (at your option) the GNU General +## Public license version 3 or any later version approved by the KDE Free +## Qt Foundation. The licenses are as published by the Free Software +## Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +## included in the packaging of this file. Please review the following +## information to ensure the GNU General Public License requirements will +## be met: https://www.gnu.org/licenses/gpl-2.0.html and +## https://www.gnu.org/licenses/gpl-3.0.html. +## +## $QT_END_LICENSE$ +## +############################################################################# + + +wheel_module_exists = False + +try: + import os, sys + + from distutils import log + from wheel import pep425tags + from wheel.bdist_wheel import bdist_wheel as _bdist_wheel + from wheel.bdist_wheel import safer_name as _safer_name + from wheel.pep425tags import get_abbr_impl, get_impl_ver, get_abi_tag + from wheel.pep425tags import get_platform as wheel_get_platform + from email.generator import Generator + from wheel import __version__ as wheel_version + + from .options import * + + wheel_module_exists = True +except Exception as e: + print('***** Exception while trying to prepare bdist_wheel override class: {}. Skipping wheel overriding.'.format(e)) + +def get_bdist_wheel_override(params): + if wheel_module_exists: + class PysideBuildWheelDecorated(PysideBuildWheel): + def __init__(self, *args, **kwargs): + self.params = params + PysideBuildWheel.__init__(self, *args, **kwargs) + return PysideBuildWheelDecorated + else: + return None + +if wheel_module_exists: + class PysideBuildWheel(_bdist_wheel): + def __init__(self, *args, **kwargs): + self.pyside_params = None + _bdist_wheel.__init__(self, *args, **kwargs) + + @property + def wheel_dist_name(self): + # Slightly modified version of wheel's wheel_dist_name + # method, to add the Qt version as well. + # Example: + # PySide2-5.6-5.6.4-cp27-cp27m-macosx_10_10_intel.whl + # The PySide2 version is "5.6". + # The Qt version built against is "5.6.4". + qt_version = self.params['qt_version'] + package_version = self.params['package_version'] + wheel_version = "{}-{}".format(package_version, qt_version) + components = (_safer_name(self.distribution.get_name()), + wheel_version) + if self.build_number: + components += (self.build_number,) + return '-'.join(components) + + # Copy of get_tag from bdist_wheel.py, to allow setting a + # multi-python impl tag, by removing an assert. Otherwise we + # would have to rename wheels manually for limited api + # packages. Also we set "none" abi tag on Windows, because + # pip does not yet support "abi3" tag, leading to + # installation failure when tried. + def get_tag(self): + # bdist sets self.plat_name if unset, we should only use + # it for purepy wheels if the user supplied it. + if self.plat_name_supplied: + plat_name = self.plat_name + elif self.root_is_pure: + plat_name = 'any' + else: + plat_name = self.plat_name or wheel_get_platform() + if plat_name in ('linux-x86_64', 'linux_x86_64') and sys.maxsize == 2147483647: + plat_name = 'linux_i686' + + # To allow uploading to pypi, we need the wheel name + # to contain 'manylinux1'. + # The wheel which will be uploaded to pypi will be + # built on RHEL7, so it doesn't completely qualify for + # manylinux1 support, but it's the minimum requirement + # for building Qt. We only enable this for x64 limited + # api builds (which are the only ones uploaded to + # pypi). + # TODO: Add actual distro detection, instead of + # relying on limited_api option. + if plat_name in ('linux-x86_64', 'linux_x86_64') and sys.maxsize > 2147483647 \ + and self.py_limited_api: + plat_name = 'manylinux1_x86_64' + plat_name = plat_name.replace('-', '_').replace('.', '_') + + if self.root_is_pure: + if self.universal: + impl = 'py2.py3' + else: + impl = self.python_tag + tag = (impl, 'none', plat_name) + else: + impl_name = get_abbr_impl() + impl_ver = get_impl_ver() + impl = impl_name + impl_ver + # We don't work on CPython 3.1, 3.0. + if self.py_limited_api and (impl_name + impl_ver).startswith('cp3'): + impl = self.py_limited_api + if sys.platform == "win32": + abi_tag = 'none' + else: + abi_tag = 'abi3' + else: + abi_tag = str(get_abi_tag()).lower() + tag = (impl, abi_tag, plat_name) + supported_tags = pep425tags.get_supported( + supplied_platform=plat_name if self.plat_name_supplied else None) + # XXX switch to this alternate implementation for + # non-pure: + if not self.py_limited_api: + assert tag == supported_tags[0], "%s != %s" % (tag, supported_tags[0]) + assert tag in supported_tags, \ + "would build wheel with unsupported tag {}".format(tag) + return tag + + # Copy of get_tag from bdist_wheel.py, to write a triplet Tag + # only once for the limited_api case. + def write_wheelfile(self, wheelfile_base, generator='bdist_wheel (' + wheel_version + ')'): + from email.message import Message + msg = Message() + msg['Wheel-Version'] = '1.0' # of the spec + msg['Generator'] = generator + msg['Root-Is-Purelib'] = str(self.root_is_pure).lower() + if self.build_number is not None: + msg['Build'] = self.build_number + + # Doesn't work for bdist_wininst + impl_tag, abi_tag, plat_tag = self.get_tag() + limited_api_enabled = OPTION_LIMITED_API and sys.version_info[0] >= 3 + + def writeTag(impl): + for abi in abi_tag.split('.'): + for plat in plat_tag.split('.'): + msg['Tag'] = '-'.join((impl, abi, plat)) + if limited_api_enabled: + writeTag(impl_tag) + else: + for impl in impl_tag.split('.'): + writeTag(impl) + + wheelfile_path = os.path.join(wheelfile_base, 'WHEEL') + log.info('creating %s', wheelfile_path) + with open(wheelfile_path, 'w') as f: + Generator(f, maxheaderlen=0).flatten(msg) + + def finalize_options(self): + if sys.platform == 'darwin': + # Override the platform name to contain the correct + # minimum deployment target. + # This is used in the final wheel name. + self.plat_name = self.params['macos_plat_name'] + + # When limited API is requested, notify bdist_wheel to + # create a properly named package. + limited_api_enabled = OPTION_LIMITED_API and sys.version_info[0] >= 3 + if limited_api_enabled: + self.py_limited_api = "cp35.cp36.cp37.cp38" + + _bdist_wheel.finalize_options(self) diff --git a/coin_build_instructions.py b/coin_build_instructions.py index 4608c890c..91a900518 100644 --- a/coin_build_instructions.py +++ b/coin_build_instructions.py @@ -42,6 +42,7 @@ from build_scripts.utils import install_pip_dependencies from build_scripts.utils import get_qtci_virtualEnv from build_scripts.utils import run_instruction from build_scripts.utils import rmtree +from build_scripts.utils import get_python_dict import os # Values must match COIN thrift @@ -60,6 +61,36 @@ if _ci_features is not None: CI_FEATURES.append(f) CI_RELEASE_CONF = has_option("packaging") +def get_current_script_path(): + """ Returns the absolute path containing this script. """ + try: + this_file = __file__ + except NameError: + this_file = sys.argv[0] + this_file = os.path.abspath(this_file) + return os.path.dirname(this_file) + +def is_snapshot_build(): + """ + Returns True if project needs to be built with --snapshot-build + + This is true if the version found in pyside_version.py is not a + pre-release version (no alphas, betas). + + This eliminates the need to remove the --snapshot-build option + on a per-release branch basis (less things to remember to do + for a release). + """ + setup_script_dir = get_current_script_path() + pyside_version_py = os.path.join( + setup_script_dir, "sources", "pyside2", "pyside_version.py") + d = get_python_dict(pyside_version_py) + + pre_release_version_type = d['pre_release_version_type'] + pre_release_version = d['pre_release_version'] + if pre_release_version or pre_release_version_type: + return True + return False def call_setup(python_ver): _pExe, _env, env_pip, env_python = get_qtci_virtualEnv(python_ver, CI_HOST_OS, CI_HOST_ARCH, CI_TARGET_ARCH) @@ -83,8 +114,11 @@ def call_setup(python_ver): cmd += ["--qmake=" + CI_ENV_INSTALL_DIR + "/bin/qmake"] cmd += ["--build-tests", "--jobs=4", - "--verbose-build", - "--snapshot-build"] + "--verbose-build"] + if python_ver == "3": + cmd += ["--limited-api=yes"] + if is_snapshot_build(): + cmd += ["--snapshot-build"] run_instruction(cmd, "Failed to run setup.py") diff --git a/examples/webenginewidgets/tabbedbrowser/bookmarkwidget.py b/examples/webenginewidgets/tabbedbrowser/bookmarkwidget.py index 0224c4518..01a69b921 100644 --- a/examples/webenginewidgets/tabbedbrowser/bookmarkwidget.py +++ b/examples/webenginewidgets/tabbedbrowser/bookmarkwidget.py @@ -47,11 +47,11 @@ from PySide2.QtGui import QIcon, QPixmap, QStandardItem, QStandardItemModel from PySide2.QtWidgets import (QAction, QDockWidget, QMenu, QMessageBox, QToolBar, QTreeView, QWidget) -_urlRole = Qt.UserRole + 1 +_url_role = Qt.UserRole + 1 # Default bookmarks as an array of arrays which is the form # used to read from/write to a .json bookmarks file -_defaultBookMarks = [ +_default_bookmarks = [ ['Tool Bar'], ['http://qt.io', 'Qt', ':/qt-project.org/qmessagebox/images/qtlogo-64.png'], ['https://download.qt.io/snapshots/ci/pyside/', 'Downloads'], @@ -62,60 +62,60 @@ _defaultBookMarks = [ ['Other Bookmarks'] ] -def _configDir(): +def _config_dir(): return '{}/QtForPythonBrowser'.format( QStandardPaths.writableLocation(QStandardPaths.ConfigLocation)) -_bookmarkFile = 'bookmarks.json' +_bookmark_file = 'bookmarks.json' -def _createFolderItem(title): +def _create_folder_item(title): result = QStandardItem(title) result.setFlags(Qt.ItemIsEnabled | Qt.ItemIsSelectable) return result -def _createItem(url, title, icon): +def _create_item(url, title, icon): result = QStandardItem(title) result.setFlags(Qt.ItemIsEnabled | Qt.ItemIsSelectable) - result.setData(url, _urlRole) + result.setData(url, _url_role) if icon is not None: result.setIcon(icon) return result # Create the model from an array of arrays -def _createModel(parent, serializedBookmarks): +def _create_model(parent, serialized_bookmarks): result = QStandardItemModel(0, 1, parent) - lastFolderItem = None - for entry in serializedBookmarks: + last_folder_item = None + for entry in serialized_bookmarks: if len(entry) == 1: - lastFolderItem = _createFolderItem(entry[0]) - result.appendRow(lastFolderItem) + last_folder_item = _create_folder_item(entry[0]) + result.appendRow(last_folder_item) else: url = QUrl.fromUserInput(entry[0]) title = entry[1] icon = QIcon(entry[2]) if len(entry) > 2 and entry[2] else None - lastFolderItem.appendRow(_createItem(url, title, icon)) + last_folder_item.appendRow(_create_item(url, title, icon)) return result # Serialize model into an array of arrays, writing out the icons # into .png files under directory in the process -def _serializeModel(model, directory): +def _serialize_model(model, directory): result = [] - folderCount = model.rowCount() - for f in range(0, folderCount): - folderItem = model.item(f) - result.append([folderItem.text()]) - itemCount = folderItem.rowCount() - for i in range(0, itemCount): - item = folderItem.child(i) - entry = [item.data(_urlRole).toString(), item.text()] + folder_count = model.rowCount() + for f in range(0, folder_count): + folder_item = model.item(f) + result.append([folder_item.text()]) + item_count = folder_item.rowCount() + for i in range(0, item_count): + item = folder_item.child(i) + entry = [item.data(_url_role).toString(), item.text()] icon = item.icon() if not icon.isNull(): - iconSizes = icon.availableSizes() - largestSize = iconSizes[len(iconSizes) - 1] - iconFileName = '{}/icon{:02}_{:02}_{}.png'.format(directory, - f, i, largestSize.width()) - icon.pixmap(largestSize).save(iconFileName, 'PNG') - entry.append(iconFileName) + icon_sizes = icon.availableSizes() + largest_size = icon_sizes[len(icon_sizes) - 1] + icon_file_name = '{}/icon{:02}_{:02}_{}.png'.format(directory, + f, i, largest_size.width()) + icon.pixmap(largest_size).save(icon_file_name, 'PNG') + entry.append(icon_file_name) result.append(entry) return result @@ -123,8 +123,8 @@ def _serializeModel(model, directory): # functionality to persist and populate tool bars and menus. class BookmarkWidget(QTreeView): - openBookmark = QtCore.Signal(QUrl) - openBookmarkInNewTab = QtCore.Signal(QUrl) + open_bookmark = QtCore.Signal(QUrl) + open_bookmark_in_new_tab = QtCore.Signal(QUrl) changed = QtCore.Signal() def __init__(self): @@ -132,7 +132,7 @@ class BookmarkWidget(QTreeView): self.setRootIsDecorated(False) self.setUniformRowHeights(True) self.setHeaderHidden(True) - self._model = _createModel(self, self._readBookmarks()) + self._model = _create_model(self, self._read_bookmarks()) self.setModel(self._model) self.expandAll() self.activated.connect(self._activated) @@ -147,120 +147,120 @@ class BookmarkWidget(QTreeView): def _activated(self, index): item = self._model.itemFromIndex(index) - self.openBookmark.emit(item.data(_urlRole)) + self.open_bookmark.emit(item.data(_url_role)) - def _actionActivated(self, index): + def _action_activated(self, index): action = self.sender() - self.openBookmark.emit(action.data()) + self.open_bookmark.emit(action.data()) - def _toolBarItem(self): + def _tool_bar_item(self): return self._model.item(0, 0) - def _otherItem(self): + def _other_item(self): return self._model.item(1, 0) - def addBookmark(self, url, title, icon): - self._otherItem().appendRow(_createItem(url, title, icon)) + def add_bookmark(self, url, title, icon): + self._other_item().appendRow(_create_item(url, title, icon)) - def addToolBarBookmark(self, url, title, icon): - self._toolBarItem().appendRow(_createItem(url, title, icon)) + def add_tool_bar_bookmark(self, url, title, icon): + self._tool_bar_item().appendRow(_create_item(url, title, icon)) - # Synchronize the bookmarks under parentItem to a targetObject + # Synchronize the bookmarks under parent_item to a target_object # like QMenu/QToolBar, which has a list of actions. Update # the existing actions, append new ones if needed or hide # superfluous ones - def _populateActions(self, parentItem, targetObject, firstAction): - existingActions = targetObject.actions() - existingActionCount = len(existingActions) - a = firstAction - rowCount = parentItem.rowCount() - for r in range(0, rowCount): - item = parentItem.child(r) + def _populate_actions(self, parent_item, target_object, first_action): + existing_actions = target_object.actions() + existing_action_count = len(existing_actions) + a = first_action + row_count = parent_item.rowCount() + for r in range(0, row_count): + item = parent_item.child(r) title = item.text() icon = item.icon() - url = item.data(_urlRole) - if a < existingActionCount: - action = existingActions[a] + url = item.data(_url_role) + if a < existing_action_count: + action = existing_actions[a] if (title != action.toolTip()): - action.setText(BookmarkWidget.shortTitle(title)) + action.setText(BookmarkWidget.short_title(title)) action.setIcon(icon) action.setToolTip(title) action.setData(url) action.setVisible(True) else: - action = targetObject.addAction(icon, BookmarkWidget.shortTitle(title)) + action = target_object.addAction(icon, BookmarkWidget.short_title(title)) action.setToolTip(title) action.setData(url) - action.triggered.connect(self._actionActivated) + action.triggered.connect(self._action_activated) a = a + 1 - while a < existingActionCount: - existingActions[a].setVisible(False) + while a < existing_action_count: + existing_actions[a].setVisible(False) a = a + 1 - def populateToolBar(self, toolBar): - self._populateActions(self._toolBarItem(), toolBar, 0) + def populate_tool_bar(self, tool_bar): + self._populate_actions(self._tool_bar_item(), tool_bar, 0) - def populateOther(self, menu, firstAction): - self._populateActions(self._otherItem(), menu, firstAction) + def populate_other(self, menu, first_action): + self._populate_actions(self._other_item(), menu, first_action) - def _currentItem(self): + def _current_item(self): index = self.currentIndex() if index.isValid(): item = self._model.itemFromIndex(index) - if item.parent(): # Exclude top level items + if item.parent(): # exclude top level items return item return None - def contextMenuEvent(self, event): - contextMenu = QMenu() - openInNewTabAction = contextMenu.addAction("Open in New Tab") - removeAction = contextMenu.addAction("Remove...") - currentItem = self._currentItem() - openInNewTabAction.setEnabled(currentItem is not None) - removeAction.setEnabled(currentItem is not None) - chosenAction = contextMenu.exec_(event.globalPos()) - if chosenAction == openInNewTabAction: - self.openBookmarkInNewTab.emit(currentItem.data(_urlRole)) - elif chosenAction == removeAction: - self._removeItem(currentItem) + def context_menu_event(self, event): + context_menu = QMenu() + open_in_new_tab_action = context_menu.addAction("Open in New Tab") + remove_action = context_menu.addAction("Remove...") + current_item = self._current_item() + open_in_new_tab_action.setEnabled(current_item is not None) + remove_action.setEnabled(current_item is not None) + chosen_action = context_menu.exec_(event.globalPos()) + if chosen_action == open_in_new_tab_action: + self.open_bookmarkInNewTab.emit(current_item.data(_url_role)) + elif chosen_action == remove_action: + self._remove_item(current_item) - def _removeItem(self, item): + def _remove_item(self, item): button = QMessageBox.question(self, "Remove", "Would you like to remove \"{}\"?".format(item.text()), QMessageBox.Yes | QMessageBox.No) if button == QMessageBox.Yes: item.parent().removeRow(item.row()) - def writeBookmarks(self): + def write_bookmarks(self): if not self._modified: return - dirPath = _configDir() - nativeDirPath = QDir.toNativeSeparators(dirPath) - dir = QFileInfo(dirPath) + dir_path = _config_dir() + native_dir_path = QDir.toNativeSeparators(dir_path) + dir = QFileInfo(dir_path) if not dir.isDir(): - print('Creating {}...'.format(nativeDirPath)) + print('Creating {}...'.format(native_dir_path)) if not QDir(dir.absolutePath()).mkpath(dir.fileName()): - warnings.warn('Cannot create {}.'.format(nativeDirPath), + warnings.warn('Cannot create {}.'.format(native_dir_path), RuntimeWarning) return - serializedModel = _serializeModel(self._model, dirPath) - bookmarkFileName = os.path.join(nativeDirPath, _bookmarkFile) - print('Writing {}...'.format(bookmarkFileName)) - with open(bookmarkFileName, 'w') as bookmarkFile: - json.dump(serializedModel, bookmarkFile, indent = 4) + serialized_model = _serialize_model(self._model, dir_path) + bookmark_file_name = os.path.join(native_dir_path, _bookmark_file) + print('Writing {}...'.format(bookmark_file_name)) + with open(bookmark_file_name, 'w') as bookmark_file: + json.dump(serialized_model, bookmark_file, indent = 4) - def _readBookmarks(self): - bookmarkFileName = os.path.join(QDir.toNativeSeparators(_configDir()), - _bookmarkFile) - if os.path.exists(bookmarkFileName): - print('Reading {}...'.format(bookmarkFileName)) - return json.load(open(bookmarkFileName)) - return _defaultBookMarks + def _read_bookmarks(self): + bookmark_file_name = os.path.join(QDir.toNativeSeparators(_config_dir()), + _bookmark_file) + if os.path.exists(bookmark_file_name): + print('Reading {}...'.format(bookmark_file_name)) + return json.load(open(bookmark_file_name)) + return _default_bookmarks # Return a short title for a bookmark action, # "Qt | Cross Platform.." -> "Qt" @staticmethod - def shortTitle(t): + def short_title(t): i = t.find(' | ') if i == -1: i = t.find(' - ') diff --git a/examples/webenginewidgets/tabbedbrowser/browsertabwidget.py b/examples/webenginewidgets/tabbedbrowser/browsertabwidget.py index 29e3d6a22..d9263be08 100644 --- a/examples/webenginewidgets/tabbedbrowser/browsertabwidget.py +++ b/examples/webenginewidgets/tabbedbrowser/browsertabwidget.py @@ -51,41 +51,41 @@ from PySide2.QtWebEngineWidgets import (QWebEngineDownloadItem, class BrowserTabWidget(QTabWidget): - urlChanged = QtCore.Signal(QUrl) - enabledChanged = QtCore.Signal(QWebEnginePage.WebAction, bool) - downloadRequested = QtCore.Signal(QWebEngineDownloadItem) + url_changed = QtCore.Signal(QUrl) + enabled_changed = QtCore.Signal(QWebEnginePage.WebAction, bool) + download_requested = QtCore.Signal(QWebEngineDownloadItem) - def __init__(self, windowFactoryFunction): + def __init__(self, window_factory_function): super(BrowserTabWidget, self).__init__() self.setTabsClosable(True) - self._windowFactoryFunction = windowFactoryFunction + self._window_factory_function = window_factory_function self._webengineviews = [] - self.currentChanged.connect(self._currentChanged) - self.tabCloseRequested.connect(self.handleTabCloseRequest) - self._actionsEnabled = {} - for webAction in WebEngineView.webActions(): - self._actionsEnabled[webAction] = False - - tabBar = self.tabBar() - tabBar.setSelectionBehaviorOnRemove(QTabBar.SelectPreviousTab) - tabBar.setContextMenuPolicy(Qt.CustomContextMenu) - tabBar.customContextMenuRequested.connect(self._handleTabContextMenu) - - def addBrowserTab(self): - factoryFunc = partial(BrowserTabWidget.addBrowserTab, self) - webEngineView = WebEngineView(factoryFunc, self._windowFactoryFunction) + self.currentChanged.connect(self._current_changed) + self.tabCloseRequested.connect(self.handle_tab_close_request) + self._actions_enabled = {} + for web_action in WebEngineView.web_actions(): + self._actions_enabled[web_action] = False + + tab_bar = self.tabBar() + tab_bar.setSelectionBehaviorOnRemove(QTabBar.SelectPreviousTab) + tab_bar.setContextMenuPolicy(Qt.CustomContextMenu) + tab_bar.customContextMenuRequested.connect(self._handle_tab_context_menu) + + def add_browser_tab(self): + factory_func = partial(BrowserTabWidget.add_browser_tab, self) + web_engine_view = WebEngineView(factory_func, self._window_factory_function) index = self.count() - self._webengineviews.append(webEngineView) + self._webengineviews.append(web_engine_view) title = 'Tab {}'.format(index + 1) - self.addTab(webEngineView, title) - page = webEngineView.page() - page.titleChanged.connect(self._titleChanged) - page.iconChanged.connect(self._iconChanged) - page.profile().downloadRequested.connect(self._downloadRequested) - webEngineView.urlChanged.connect(self._urlChanged) - webEngineView.enabledChanged.connect(self._enabledChanged) + self.addTab(web_engine_view, title) + page = web_engine_view.page() + page.titleChanged.connect(self._title_changed) + page.iconChanged.connect(self._icon_changed) + page.profile().downloadRequested.connect(self._download_requested) + web_engine_view.urlChanged.connect(self._url_changed) + web_engine_view.enabled_changed.connect(self._enabled_changed) self.setCurrentIndex(index) - return webEngineView + return web_engine_view def load(self, url): index = self.currentIndex() @@ -101,120 +101,120 @@ class BrowserTabWidget(QTabWidget): index = self.currentIndex() return self._webengineviews[index].url() if index >= 0 else QUrl() - def _urlChanged(self, url): + def _url_changed(self, url): index = self.currentIndex() if index >= 0 and self._webengineviews[index] == self.sender(): - self.urlChanged.emit(url) + self.url_changed.emit(url) - def _titleChanged(self, title): - index = self._indexOfPage(self.sender()) + def _title_changed(self, title): + index = self._index_of_page(self.sender()) if (index >= 0): - self.setTabText(index, BookmarkWidget.shortTitle(title)) + self.setTabText(index, BookmarkWidget.short_title(title)) - def _iconChanged(self, icon): - index = self._indexOfPage(self.sender()) + def _icon_changed(self, icon): + index = self._index_of_page(self.sender()) if (index >= 0): self.setTabIcon(index, icon) - def _enabledChanged(self, webAction, enabled): + def _enabled_changed(self, web_action, enabled): index = self.currentIndex() if index >= 0 and self._webengineviews[index] == self.sender(): - self._checkEmitEnabledChanged(webAction, enabled) + self._check_emit_enabled_changed(web_action, enabled) - def _checkEmitEnabledChanged(self, webAction, enabled): - if enabled != self._actionsEnabled[webAction]: - self._actionsEnabled[webAction] = enabled - self.enabledChanged.emit(webAction, enabled) + def _check_emit_enabled_changed(self, web_action, enabled): + if enabled != self._actions_enabled[web_action]: + self._actions_enabled[web_action] = enabled + self.enabled_changed.emit(web_action, enabled) - def _currentChanged(self, index): - self._updateActions(index) - self.urlChanged.emit(self.url()) + def _current_changed(self, index): + self._update_actions(index) + self.url_changed.emit(self.url()) - def _updateActions(self, index): + def _update_actions(self, index): if index >= 0 and index < len(self._webengineviews): view = self._webengineviews[index] - for webAction in WebEngineView.webActions(): - enabled = view.isWebActionEnabled(webAction) - self._checkEmitEnabledChanged(webAction, enabled) + for web_action in WebEngineView.web_actions(): + enabled = view.is_web_action_enabled(web_action) + self._check_emit_enabled_changed(web_action, enabled) def back(self): - self._triggerAction(QWebEnginePage.Back) + self._trigger_action(QWebEnginePage.Back) def forward(self): - self._triggerAction(QWebEnginePage.Forward) + self._trigger_action(QWebEnginePage.Forward) def reload(self): - self._triggerAction(QWebEnginePage.Reload) + self._trigger_action(QWebEnginePage.Reload) def undo(self): - self._triggerAction(QWebEnginePage.Undo) + self._trigger_action(QWebEnginePage.Undo) def redo(self): - self._triggerAction(QWebEnginePage.Redo) + self._trigger_action(QWebEnginePage.Redo) def cut(self): - self._triggerAction(QWebEnginePage.Cut) + self._trigger_action(QWebEnginePage.Cut) def copy(self): - self._triggerAction(QWebEnginePage.Copy) + self._trigger_action(QWebEnginePage.Copy) def paste(self): - self._triggerAction(QWebEnginePage.Paste) + self._trigger_action(QWebEnginePage.Paste) - def selectAll(self): - self._triggerAction(QWebEnginePage.SelectAll) + def select_all(self): + self._trigger_action(QWebEnginePage.SelectAll) - def zoomFactor(self): + def zoom_factor(self): return self._webengineviews[0].zoomFactor() if self._webengineviews else 1.0 - def setZoomFactor(self, z): + def set_zoom_factor(self, z): for w in self._webengineviews: w.setZoomFactor(z) - def _handleTabContextMenu(self, point): + def _handle_tab_context_menu(self, point): index = self.tabBar().tabAt(point) if index < 0: return - tabCount = len(self._webengineviews) - contextMenu = QMenu() - duplicateTabAction = contextMenu.addAction("Duplicate Tab") - closeOtherTabsAction = contextMenu.addAction("Close Other Tabs") - closeOtherTabsAction.setEnabled(tabCount > 1) - closeTabsToTheRightAction = contextMenu.addAction("Close Tabs to the Right") - closeTabsToTheRightAction.setEnabled(index < tabCount - 1) - closeTabAction = contextMenu.addAction("&Close Tab") - chosenAction = contextMenu.exec_(self.tabBar().mapToGlobal(point)) - if chosenAction == duplicateTabAction: - currentUrl = self.url() - self.addBrowserTab().load(currentUrl) - elif chosenAction == closeOtherTabsAction: - for t in range(tabCount - 1, -1, -1): + tab_count = len(self._webengineviews) + context_menu = QMenu() + duplicate_tab_action = context_menu.addAction("Duplicate Tab") + close_other_tabs_action = context_menu.addAction("Close Other Tabs") + close_other_tabs_action.setEnabled(tab_count > 1) + close_tabs_to_the_right_action = context_menu.addAction("Close Tabs to the Right") + close_tabs_to_the_right_action.setEnabled(index < tab_count - 1) + close_tab_action = context_menu.addAction("&Close Tab") + chosen_action = context_menu.exec_(self.tabBar().mapToGlobal(point)) + if chosen_action == duplicate_tab_action: + current_url = self.url() + self.add_browser_tab().load(current_url) + elif chosen_action == close_other_tabs_action: + for t in range(tab_count - 1, -1, -1): if t != index: - self.handleTabCloseRequest(t) - elif chosenAction == closeTabsToTheRightAction: - for t in range(tabCount - 1, index, -1): - self.handleTabCloseRequest(t) - elif chosenAction == closeTabAction: - self.handleTabCloseRequest(index) - - def handleTabCloseRequest(self, index): + self.handle_tab_close_request(t) + elif chosen_action == close_tabs_to_the_right_action: + for t in range(tab_count - 1, index, -1): + self.handle_tab_close_request(t) + elif chosen_action == close_tab_action: + self.handle_tab_close_request(index) + + def handle_tab_close_request(self, index): if (index >= 0 and self.count() > 1): self._webengineviews.remove(self._webengineviews[index]) self.removeTab(index) - def closeCurrentTab(self): - self.handleTabCloseRequest(self.currentIndex()) + def close_current_tab(self): + self.handle_tab_close_request(self.currentIndex()) - def _triggerAction(self, action): + def _trigger_action(self, action): index = self.currentIndex() if index >= 0: self._webengineviews[index].page().triggerAction(action) - def _indexOfPage(self, webPage): + def _index_of_page(self, web_page): for p in range(0, len(self._webengineviews)): - if (self._webengineviews[p].page() == webPage): + if (self._webengineviews[p].page() == web_page): return p return -1 - def _downloadRequested(self, item): + def _download_requested(self, item): self.downloadRequested.emit(item) diff --git a/examples/webenginewidgets/tabbedbrowser/downloadwidget.py b/examples/webenginewidgets/tabbedbrowser/downloadwidget.py index bcfc7a5ed..030dfc14b 100644 --- a/examples/webenginewidgets/tabbedbrowser/downloadwidget.py +++ b/examples/webenginewidgets/tabbedbrowser/downloadwidget.py @@ -50,95 +50,95 @@ from PySide2.QtWebEngineWidgets import QWebEngineDownloadItem class DownloadWidget(QProgressBar): finished = QtCore.Signal() - removeRequested = QtCore.Signal() + remove_requested = QtCore.Signal() - def __init__(self, downloadItem): + def __init__(self, download_item): super(DownloadWidget, self).__init__() - self._downloadItem = downloadItem - downloadItem.finished.connect(self._finished) - downloadItem.downloadProgress.connect(self._downloadProgress) - downloadItem.stateChanged.connect(self._updateToolTip()) - path = downloadItem.path() + self._download_item = download_item + download_item.finished.connect(self._finished) + download_item.downloadProgress.connect(self._download_progress) + download_item.stateChanged.connect(self._update_tool_tip()) + path = download_item.path() self.setMaximumWidth(300) # Shorten 'PySide2-5.11.0a1-5.11.0-cp36-cp36m-linux_x86_64.whl'... description = QFileInfo(path).fileName() - descriptionLength = len(description) - if descriptionLength > 30: - description = '{}...{}'.format(description[0:10], description[descriptionLength - 10:]) + description_length = len(description) + if description_length > 30: + description = '{}...{}'.format(description[0:10], description[description_length - 10:]) self.setFormat('{} %p%'.format(description)) self.setOrientation(Qt.Horizontal) self.setMinimum(0) self.setValue(0) self.setMaximum(100) - self._updateToolTip() + self._update_tool_tip() # Force progress bar text to be shown on macoS by using 'fusion' style if sys.platform == 'darwin': self.setStyle(QStyleFactory.create('fusion')) @staticmethod - def openFile(file): + def open_file(file): QDesktopServices.openUrl(QUrl.fromLocalFile(file)) @staticmethod - def openDownloadDirectory(): + def open_download_directory(): path = QStandardPaths.writableLocation(QStandardPaths.DownloadLocation) - DownloadWidget.openFile(path) + DownloadWidget.open_file(path) def state(self): - return self._downloadItem.state() + return self._download_item.state() - def _updateToolTip(self): - path = self._downloadItem.path() - toolTip = "{}\n{}".format(self._downloadItem.url().toString(), + def _update_tool_tip(self): + path = self._download_item.path() + tool_tip = "{}\n{}".format(self._download_item.url().toString(), QDir.toNativeSeparators(path)) - totalBytes = self._downloadItem.totalBytes() - if totalBytes > 0: - toolTip += "\n{}K".format(totalBytes / 1024) + total_bytes = self._download_item.total_bytes() + if total_bytes > 0: + tool_tip += "\n{}K".format(total_bytes / 1024) state = self.state() if state == QWebEngineDownloadItem.DownloadRequested: - toolTip += "\n(requested)" + tool_tip += "\n(requested)" elif state == QWebEngineDownloadItem.DownloadInProgress: - toolTip += "\n(downloading)" + tool_tip += "\n(downloading)" elif state == QWebEngineDownloadItem.DownloadCompleted: - toolTip += "\n(completed)" + tool_tip += "\n(completed)" elif state == QWebEngineDownloadItem.DownloadCancelled: - toolTip += "\n(cancelled)" + tool_tip += "\n(cancelled)" else: - toolTip += "\n(interrupted)" - self.setToolTip(toolTip) + tool_tip += "\n(interrupted)" + self.setToolTip(tool_tip) - def _downloadProgress(self, bytesReceived, bytesTotal): - self.setValue(int(100 * bytesReceived / bytesTotal)) + def _download_progress(self, bytes_received, bytes_total): + self.setValue(int(100 * bytes_received / bytes_total)) def _finished(self): - self._updateToolTip() + self._update_tool_tip() self.finished.emit() def _launch(self): - DownloadWidget.openFile(self._downloadItem.path()) + DownloadWidget.open_file(self._download_item.path()) - def mouseDoubleClickEvent(self, event): + def mouse_double_click_event(self, event): if self.state() == QWebEngineDownloadItem.DownloadCompleted: self._launch() - def contextMenuEvent(self, event): + def context_menu_event(self, event): state = self.state() - contextMenu = QMenu() - launchAction = contextMenu.addAction("Launch") - launchAction.setEnabled(state == QWebEngineDownloadItem.DownloadCompleted) - showInFolderAction = contextMenu.addAction("Show in Folder") - showInFolderAction.setEnabled(state == QWebEngineDownloadItem.DownloadCompleted) - cancelAction = contextMenu.addAction("Cancel") - cancelAction.setEnabled(state == QWebEngineDownloadItem.DownloadInProgress) - removeAction = contextMenu.addAction("Remove") - removeAction.setEnabled(state != QWebEngineDownloadItem.DownloadInProgress) + context_menu = QMenu() + launch_action = context_menu.addAction("Launch") + launch_action.setEnabled(state == QWebEngineDownloadItem.DownloadCompleted) + show_in_folder_action = context_menu.addAction("Show in Folder") + show_in_folder_action.setEnabled(state == QWebEngineDownloadItem.DownloadCompleted) + cancel_action = context_menu.addAction("Cancel") + cancel_action.setEnabled(state == QWebEngineDownloadItem.DownloadInProgress) + remove_action = context_menu.addAction("Remove") + remove_action.setEnabled(state != QWebEngineDownloadItem.DownloadInProgress) - chosenAction = contextMenu.exec_(event.globalPos()) - if chosenAction == launchAction: + chosen_action = context_menu.exec_(event.globalPos()) + if chosen_action == launch_action: self._launch() - elif chosenAction == showInFolderAction: - DownloadWidget.openFile(QFileInfo(self._downloadItem.path()).absolutePath()) - elif chosenAction == cancelAction: - self._downloadItem.cancel() - elif chosenAction == removeAction: - self.removeRequested.emit() + elif chosen_action == show_in_folder_action: + DownloadWidget.open_file(QFileInfo(self._download_item.path()).absolutePath()) + elif chosen_action == cancel_action: + self._download_item.cancel() + elif chosen_action == remove_action: + self.remove_requested.emit() diff --git a/examples/webenginewidgets/tabbedbrowser/findtoolbar.py b/examples/webenginewidgets/tabbedbrowser/findtoolbar.py index e862a5cf3..68a1fd595 100644 --- a/examples/webenginewidgets/tabbedbrowser/findtoolbar.py +++ b/examples/webenginewidgets/tabbedbrowser/findtoolbar.py @@ -52,25 +52,25 @@ class FindToolBar(QToolBar): def __init__(self): super(FindToolBar, self).__init__() - self._lineEdit = QLineEdit() - self._lineEdit.setClearButtonEnabled(True) - self._lineEdit.setPlaceholderText("Find...") - self._lineEdit.setMaximumWidth(300) - self._lineEdit.returnPressed.connect(self._findNext) - self.addWidget(self._lineEdit) + self._line_edit = QLineEdit() + self._line_edit.setClearButtonEnabled(True) + self._line_edit.setPlaceholderText("Find...") + self._line_edit.setMaximumWidth(300) + self._line_edit.returnPressed.connect(self._find_next) + self.addWidget(self._line_edit) - self._previousButton = QToolButton() - self._previousButton.setIcon(QIcon(':/qt-project.org/styles/commonstyle/images/up-32.png')) - self._previousButton.clicked.connect(self._findPrevious) - self.addWidget(self._previousButton) + self._previous_button = QToolButton() + self._previous_button.setIcon(QIcon(':/qt-project.org/styles/commonstyle/images/up-32.png')) + self._previous_button.clicked.connect(self._find_previous) + self.addWidget(self._previous_button) - self._nextButton = QToolButton() - self._nextButton.setIcon(QIcon(':/qt-project.org/styles/commonstyle/images/down-32.png')) - self._nextButton.clicked.connect(self._findNext) - self.addWidget(self._nextButton) + self._next_button = QToolButton() + self._next_button.setIcon(QIcon(':/qt-project.org/styles/commonstyle/images/down-32.png')) + self._next_button.clicked.connect(self._find_next) + self.addWidget(self._next_button) - self._caseSensitiveCheckBox = QCheckBox('Case Sensitive') - self.addWidget(self._caseSensitiveCheckBox) + self._case_sensitive_checkbox = QCheckBox('Case Sensitive') + self.addWidget(self._case_sensitive_checkbox) self._hideButton = QToolButton() self._hideButton.setShortcut(QKeySequence(Qt.Key_Escape)) @@ -78,21 +78,21 @@ class FindToolBar(QToolBar): self._hideButton.clicked.connect(self.hide) self.addWidget(self._hideButton) - def focusFind(self): - self._lineEdit.setFocus() + def focus_find(self): + self._line_edit.setFocus() - def _emitFind(self, backward): - needle = self._lineEdit.text().strip() + def _emit_find(self, backward): + needle = self._line_edit.text().strip() if needle: flags = QWebEnginePage.FindFlags() - if self._caseSensitiveCheckBox.isChecked(): + if self._case_sensitive_checkbox.isChecked(): flags |= QWebEnginePage.FindCaseSensitively if backward: flags |= QWebEnginePage.FindBackward self.find.emit(needle, flags) - def _findNext(self): - self._emitFind(False) + def _find_next(self): + self._emit_find(False) - def _findPrevious(self): - self._emitFind(True) + def _find_previous(self): + self._emit_find(True) diff --git a/examples/webenginewidgets/tabbedbrowser/main.py b/examples/webenginewidgets/tabbedbrowser/main.py index 58cc90346..12efdcd5c 100644 --- a/examples/webenginewidgets/tabbedbrowser/main.py +++ b/examples/webenginewidgets/tabbedbrowser/main.py @@ -57,326 +57,326 @@ from PySide2.QtWidgets import (qApp, QAction, QApplication, QDesktopWidget, from PySide2.QtWebEngineWidgets import (QWebEngineDownloadItem, QWebEnginePage, QWebEngineView) -mainWindows = [] +main_windows = [] -def createMainWindow(): - mainWin = MainWindow() - mainWindows.append(mainWin) - availableGeometry = app.desktop().availableGeometry(mainWin) - mainWin.resize(availableGeometry.width() * 2 / 3, availableGeometry.height() * 2 / 3) - mainWin.show() - return mainWin +def create_main_window(): + main_win = MainWindow() + main_windows.append(main_win) + available_geometry = app.desktop().availableGeometry(main_win) + main_win.resize(available_geometry.width() * 2 / 3, available_geometry.height() * 2 / 3) + main_win.show() + return main_win -def createMainWindowWithBrowser(): - mainWin = createMainWindow() - return mainWin.addBrowserTab() +def create_main_window_with_browser(): + main_win = create_main_window() + return main_win.add_browser_tab() class MainWindow(QMainWindow): def __init__(self): super(MainWindow, self).__init__() - self.setWindowTitle('PySide2 Tabbed Browser Example') + self.setWindowTitle('PySide2 tabbed browser Example') - self._tabWidget = BrowserTabWidget(createMainWindowWithBrowser) - self._tabWidget.enabledChanged.connect(self._enabledChanged) - self._tabWidget.downloadRequested.connect(self._downloadRequested) - self.setCentralWidget(self._tabWidget) - self.connect(self._tabWidget, QtCore.SIGNAL("urlChanged(QUrl)"), - self.urlChanged) + self._tab_widget = BrowserTabWidget(create_main_window_with_browser) + self._tab_widget.enabled_changed.connect(self._enabled_changed) + self._tab_widget.download_requested.connect(self._download_requested) + self.setCentralWidget(self._tab_widget) + self.connect(self._tab_widget, QtCore.SIGNAL("url_changed(QUrl)"), + self.url_changed) - self._bookmarkDock = QDockWidget() - self._bookmarkDock.setWindowTitle('Bookmarks') - self._bookmarkWidget = BookmarkWidget() - self._bookmarkWidget.openBookmark.connect(self.loadUrl) - self._bookmarkWidget.openBookmarkInNewTab.connect(self.loadUrlInNewTab) - self._bookmarkDock.setWidget(self._bookmarkWidget) - self.addDockWidget(Qt.LeftDockWidgetArea, self._bookmarkDock) + self._bookmark_dock = QDockWidget() + self._bookmark_dock.setWindowTitle('Bookmarks') + self._bookmark_widget = BookmarkWidget() + self._bookmark_widget.open_bookmark.connect(self.load_url) + self._bookmark_widget.open_bookmark_in_new_tab.connect(self.load_url_in_new_tab) + self._bookmark_dock.setWidget(self._bookmark_widget) + self.addDockWidget(Qt.LeftDockWidgetArea, self._bookmark_dock) - self._findToolBar = None + self._find_tool_bar = None self._actions = {} - self._createMenu() + self._create_menu() - self._toolBar = QToolBar() - self.addToolBar(self._toolBar) + self._tool_bar = QToolBar() + self.addToolBar(self._tool_bar) for action in self._actions.values(): if not action.icon().isNull(): - self._toolBar.addAction(action) + self._tool_bar.addAction(action) - self._addressLineEdit = QLineEdit() - self._addressLineEdit.setClearButtonEnabled(True) - self._addressLineEdit.returnPressed.connect(self.load) - self._toolBar.addWidget(self._addressLineEdit) - self._zoomLabel = QLabel() - self.statusBar().addPermanentWidget(self._zoomLabel) - self._updateZoomLabel() + self._addres_line_edit = QLineEdit() + self._addres_line_edit.setClearButtonEnabled(True) + self._addres_line_edit.returnPressed.connect(self.load) + self._tool_bar.addWidget(self._addres_line_edit) + self._zoom_label = QLabel() + self.statusBar().addPermanentWidget(self._zoom_label) + self._update_zoom_label() self._bookmarksToolBar = QToolBar() self.addToolBar(Qt.TopToolBarArea, self._bookmarksToolBar) self.insertToolBarBreak(self._bookmarksToolBar) - self._bookmarkWidget.changed.connect(self._updateBookmarks) - self._updateBookmarks() + self._bookmark_widget.changed.connect(self._update_bookmarks) + self._update_bookmarks() - def _updateBookmarks(self): - self._bookmarkWidget.populateToolBar(self._bookmarksToolBar) - self._bookmarkWidget.populateOther(self._bookmarkMenu, 3) + def _update_bookmarks(self): + self._bookmark_widget.populate_tool_bar(self._bookmarksToolBar) + self._bookmark_widget.populate_other(self._bookmark_menu, 3) - def _createMenu(self): - fileMenu = self.menuBar().addMenu("&File") - exitAction = QAction(QIcon.fromTheme("application-exit"), "E&xit", + def _create_menu(self): + file_menu = self.menuBar().addMenu("&File") + exit_action = QAction(QIcon.fromTheme("application-exit"), "E&xit", self, shortcut = "Ctrl+Q", triggered=qApp.quit) - fileMenu.addAction(exitAction) + file_menu.addAction(exit_action) - navigationMenu = self.menuBar().addMenu("&Navigation") + navigation_menu = self.menuBar().addMenu("&Navigation") - styleIcons = ':/qt-project.org/styles/commonstyle/images/' - backAction = QAction(QIcon.fromTheme("go-previous", - QIcon(styleIcons + 'left-32.png')), + style_icons = ':/qt-project.org/styles/commonstyle/images/' + back_action = QAction(QIcon.fromTheme("go-previous", + QIcon(style_icons + 'left-32.png')), "Back", self, shortcut = QKeySequence(QKeySequence.Back), - triggered = self._tabWidget.back) - self._actions[QWebEnginePage.Back] = backAction - backAction.setEnabled(False) - navigationMenu.addAction(backAction) - forwardAction = QAction(QIcon.fromTheme("go-next", - QIcon(styleIcons + 'right-32.png')), + triggered = self._tab_widget.back) + self._actions[QWebEnginePage.Back] = back_action + back_action.setEnabled(False) + navigation_menu.addAction(back_action) + forward_action = QAction(QIcon.fromTheme("go-next", + QIcon(style_icons + 'right-32.png')), "Forward", self, shortcut = QKeySequence(QKeySequence.Forward), - triggered = self._tabWidget.forward) - forwardAction.setEnabled(False) - self._actions[QWebEnginePage.Forward] = forwardAction + triggered = self._tab_widget.forward) + forward_action.setEnabled(False) + self._actions[QWebEnginePage.Forward] = forward_action - navigationMenu.addAction(forwardAction) - reloadAction = QAction(QIcon(styleIcons + 'refresh-32.png'), + navigation_menu.addAction(forward_action) + reload_action = QAction(QIcon(style_icons + 'refresh-32.png'), "Reload", self, shortcut = QKeySequence(QKeySequence.Refresh), - triggered = self._tabWidget.reload) - self._actions[QWebEnginePage.Reload] = reloadAction - reloadAction.setEnabled(False) - navigationMenu.addAction(reloadAction) + triggered = self._tab_widget.reload) + self._actions[QWebEnginePage.Reload] = reload_action + reload_action.setEnabled(False) + navigation_menu.addAction(reload_action) - navigationMenu.addSeparator() + navigation_menu.addSeparator() - newTabAction = QAction("New Tab", self, + new_tab_action = QAction("New Tab", self, shortcut = 'Ctrl+T', - triggered = self.addBrowserTab) - navigationMenu.addAction(newTabAction) + triggered = self.add_browser_tab) + navigation_menu.addAction(new_tab_action) - closeTabAction = QAction("Close Current Tab", self, + close_tab_action = QAction("Close Current Tab", self, shortcut = "Ctrl+W", - triggered = self._closeCurrentTab) - navigationMenu.addAction(closeTabAction) + triggered = self._close_current_tab) + navigation_menu.addAction(close_tab_action) - editMenu = self.menuBar().addMenu("&Edit") + edit_menu = self.menuBar().addMenu("&Edit") - findAction = QAction("Find", self, + find_action = QAction("Find", self, shortcut = QKeySequence(QKeySequence.Find), - triggered = self._showFind) - editMenu.addAction(findAction) + triggered = self._show_find) + edit_menu.addAction(find_action) - editMenu.addSeparator() - undoAction = QAction("Undo", self, + edit_menu.addSeparator() + undo_action = QAction("Undo", self, shortcut = QKeySequence(QKeySequence.Undo), - triggered = self._tabWidget.undo) - self._actions[QWebEnginePage.Undo] = undoAction - undoAction.setEnabled(False) - editMenu.addAction(undoAction) + triggered = self._tab_widget.undo) + self._actions[QWebEnginePage.Undo] = undo_action + undo_action.setEnabled(False) + edit_menu.addAction(undo_action) - redoAction = QAction("Redo", self, + redo_action = QAction("Redo", self, shortcut = QKeySequence(QKeySequence.Redo), - triggered = self._tabWidget.redo) - self._actions[QWebEnginePage.Redo] = redoAction - redoAction.setEnabled(False) - editMenu.addAction(redoAction) + triggered = self._tab_widget.redo) + self._actions[QWebEnginePage.Redo] = redo_action + redo_action.setEnabled(False) + edit_menu.addAction(redo_action) - editMenu.addSeparator() + edit_menu.addSeparator() - cutAction = QAction("Cut", self, + cut_action = QAction("Cut", self, shortcut = QKeySequence(QKeySequence.Cut), - triggered = self._tabWidget.cut) - self._actions[QWebEnginePage.Cut] = cutAction - cutAction.setEnabled(False) - editMenu.addAction(cutAction) + triggered = self._tab_widget.cut) + self._actions[QWebEnginePage.Cut] = cut_action + cut_action.setEnabled(False) + edit_menu.addAction(cut_action) - copyAction = QAction("Copy", self, + copy_action = QAction("Copy", self, shortcut = QKeySequence(QKeySequence.Copy), - triggered = self._tabWidget.copy) - self._actions[QWebEnginePage.Copy] = copyAction - copyAction.setEnabled(False) - editMenu.addAction(copyAction) + triggered = self._tab_widget.copy) + self._actions[QWebEnginePage.Copy] = copy_action + copy_action.setEnabled(False) + edit_menu.addAction(copy_action) - pasteAction = QAction("Paste", self, + paste_action = QAction("Paste", self, shortcut = QKeySequence(QKeySequence.Paste), - triggered = self._tabWidget.paste) - self._actions[QWebEnginePage.Paste] = pasteAction - pasteAction.setEnabled(False) - editMenu.addAction(pasteAction) + triggered = self._tab_widget.paste) + self._actions[QWebEnginePage.Paste] = paste_action + paste_action.setEnabled(False) + edit_menu.addAction(paste_action) - editMenu.addSeparator() + edit_menu.addSeparator() - selectAllAction = QAction("Select All", self, + select_all_action = QAction("Select All", self, shortcut = QKeySequence(QKeySequence.SelectAll), - triggered = self._tabWidget.selectAll) - self._actions[QWebEnginePage.SelectAll] = selectAllAction - selectAllAction.setEnabled(False) - editMenu.addAction(selectAllAction) + triggered = self._tab_widget.select_all) + self._actions[QWebEnginePage.SelectAll] = select_all_action + select_all_action.setEnabled(False) + edit_menu.addAction(select_all_action) - self._bookmarkMenu = self.menuBar().addMenu("&Bookmarks") - addBookmarkAction = QAction("&Add Bookmark", self, - triggered = self._addBookmark) - self._bookmarkMenu.addAction(addBookmarkAction) - addToolBarBookmarkAction = QAction("&Add Bookmark to Tool Bar", self, - triggered = self._addToolBarBookmark) - self._bookmarkMenu.addAction(addToolBarBookmarkAction) - self._bookmarkMenu.addSeparator() + self._bookmark_menu = self.menuBar().addMenu("&Bookmarks") + add_bookmark_action = QAction("&Add Bookmark", self, + triggered = self._add_bookmark) + self._bookmark_menu.addAction(add_bookmark_action) + add_tool_bar_bookmark_action = QAction("&Add Bookmark to Tool Bar", self, + triggered = self._add_tool_bar_bookmark) + self._bookmark_menu.addAction(add_tool_bar_bookmark_action) + self._bookmark_menu.addSeparator() - toolsMenu = self.menuBar().addMenu("&Tools") - downloadAction = QAction("Open Downloads", self, - triggered = DownloadWidget.openDownloadDirectory) - toolsMenu.addAction(downloadAction) + tools_menu = self.menuBar().addMenu("&Tools") + download_action = QAction("Open Downloads", self, + triggered = DownloadWidget.open_download_directory) + tools_menu.addAction(download_action) - windowMenu = self.menuBar().addMenu("&Window") + window_menu = self.menuBar().addMenu("&Window") - windowMenu.addAction(self._bookmarkDock.toggleViewAction()) + window_menu.addAction(self._bookmark_dock.toggleViewAction()) - windowMenu.addSeparator() + window_menu.addSeparator() - zoomInAction = QAction(QIcon.fromTheme("zoom-in"), + zoom_in_action = QAction(QIcon.fromTheme("zoom-in"), "Zoom In", self, shortcut = QKeySequence(QKeySequence.ZoomIn), - triggered = self._zoomIn) - windowMenu.addAction(zoomInAction) - zoomOutAction = QAction(QIcon.fromTheme("zoom-out"), + triggered = self._zoom_in) + window_menu.addAction(zoom_in_action) + zoom_out_action = QAction(QIcon.fromTheme("zoom-out"), "Zoom Out", self, shortcut = QKeySequence(QKeySequence.ZoomOut), - triggered = self._zoomOut) - windowMenu.addAction(zoomOutAction) + triggered = self._zoom_out) + window_menu.addAction(zoom_out_action) - resetZoomAction = QAction(QIcon.fromTheme("zoom-original"), + reset_zoom_action = QAction(QIcon.fromTheme("zoom-original"), "Reset Zoom", self, shortcut = "Ctrl+0", - triggered = self._resetZoom) - windowMenu.addAction(resetZoomAction) + triggered = self._reset_zoom) + window_menu.addAction(reset_zoom_action) - aboutMenu = self.menuBar().addMenu("&About") - aboutAction = QAction("About Qt", self, + about_menu = self.menuBar().addMenu("&About") + about_action = QAction("About Qt", self, shortcut = QKeySequence(QKeySequence.HelpContents), triggered=qApp.aboutQt) - aboutMenu.addAction(aboutAction) + about_menu.addAction(about_action) - def addBrowserTab(self): - return self._tabWidget.addBrowserTab() + def add_browser_tab(self): + return self._tab_widget.add_browser_tab() - def _closeCurrentTab(self): - if self._tabWidget.count() > 1: - self._tabWidget.closeCurrentTab() + def _close_current_tab(self): + if self._tab_widget.count() > 1: + self._tab_widget.close_current_tab() else: self.close() - def closeEvent(self, event): - mainWindows.remove(self) + def close_event(self, event): + main_windows.remove(self) event.accept() def load(self): - urlString = self._addressLineEdit.text().strip() - if urlString: - self.loadUrlString(urlString) + url_string = self._addres_line_edit.text().strip() + if url_string: + self.load_url_string(url_string) - def loadUrlString(self, urlS): - url = QUrl.fromUserInput(urlS) + def load_url_string(self, url_s): + url = QUrl.fromUserInput(url_s) if (url.isValid()): - self.loadUrl(url) + self.load_url(url) - def loadUrl(self, url): - self._tabWidget.load(url) + def load_url(self, url): + self._tab_widget.load(url) - def loadUrlInNewTab(self, url): - self.addBrowserTab().load(url) + def load_url_in_new_tab(self, url): + self.add_browser_tab().load(url) - def urlChanged(self, url): - self._addressLineEdit.setText(url.toString()) + def url_changed(self, url): + self._addres_line_edit.setText(url.toString()) - def _enabledChanged(self, webAction, enabled): - action = self._actions[webAction] + def _enabled_changed(self, web_action, enabled): + action = self._actions[web_action] if action: action.setEnabled(enabled) - def _addBookmark(self): - index = self._tabWidget.currentIndex() + def _add_bookmark(self): + index = self._tab_widget.currentIndex() if index >= 0: - url = self._tabWidget.url() - title = self._tabWidget.tabText(index) - icon = self._tabWidget.tabIcon(index) - self._bookmarkWidget.addBookmark(url, title, icon) + url = self._tab_widget.url() + title = self._tab_widget.tabText(index) + icon = self._tab_widget.tabIcon(index) + self._bookmark_widget.add_bookmark(url, title, icon) - def _addToolBarBookmark(self): - index = self._tabWidget.currentIndex() + def _add_tool_bar_bookmark(self): + index = self._tab_widget.currentIndex() if index >= 0: - url = self._tabWidget.url() - title = self._tabWidget.tabText(index) - icon = self._tabWidget.tabIcon(index) - self._bookmarkWidget.addToolBarBookmark(url, title, icon) - - def _zoomIn(self): - newZoom = self._tabWidget.zoomFactor() * 1.5 - if (newZoom <= WebEngineView.maximumZoomFactor()): - self._tabWidget.setZoomFactor(newZoom) - self._updateZoomLabel() - - def _zoomOut(self): - newZoom = self._tabWidget.zoomFactor() / 1.5 - if (newZoom >= WebEngineView.minimumZoomFactor()): - self._tabWidget.setZoomFactor(newZoom) - self._updateZoomLabel() - - def _resetZoom(self): - self._tabWidget.setZoomFactor(1) - self._updateZoomLabel() - - def _updateZoomLabel(self): - percent = int(self._tabWidget.zoomFactor() * 100) - self._zoomLabel.setText("{}%".format(percent)) - - def _downloadRequested(self, item): + url = self._tab_widget.url() + title = self._tab_widget.tabText(index) + icon = self._tab_widget.tabIcon(index) + self._bookmark_widget.add_tool_bar_bookmark(url, title, icon) + + def _zoom_in(self): + new_zoom = self._tab_widget.zoom_factor() * 1.5 + if (new_zoom <= WebEngineView.maximum_zoom_factor()): + self._tab_widget.set_zoom_factor(new_zoom) + self._update_zoom_label() + + def _zoom_out(self): + new_zoom = self._tab_widget.zoom_factor() / 1.5 + if (new_zoom >= WebEngineView.minimum_zoom_factor()): + self._tab_widget.set_zoom_factor(new_zoom) + self._update_zoom_label() + + def _reset_zoom(self): + self._tab_widget.set_zoom_factor(1) + self._update_zoom_label() + + def _update_zoom_label(self): + percent = int(self._tab_widget.zoom_factor() * 100) + self._zoom_label.setText("{}%".format(percent)) + + def _download_requested(self, item): # Remove old downloads before opening a new one - for oldDownload in self.statusBar().children(): - if type(oldDownload).__name__ == 'DownloadWidget' and \ - oldDownload.state() != QWebEngineDownloadItem.DownloadInProgress: - self.statusBar().removeWidget(oldDownload) - del oldDownload + for old_download in self.statusBar().children(): + if type(old_download).__name__ == 'download_widget' and \ + old_download.state() != QWebEngineDownloadItem.DownloadInProgress: + self.statusBar().removeWidget(old_download) + del old_download item.accept() - downloadWidget = DownloadWidget(item) - downloadWidget.removeRequested.connect(self._removeDownloadRequested, + download_widget = download_widget(item) + download_widget.removeRequested.connect(self._remove_download_requested, Qt.QueuedConnection) - self.statusBar().addWidget(downloadWidget) - - def _removeDownloadRequested(self): - downloadWidget = self.sender() - self.statusBar().removeWidget(downloadWidget) - del downloadWidget - - def _showFind(self): - if self._findToolBar is None: - self._findToolBar = FindToolBar() - self._findToolBar.find.connect(self._tabWidget.find) - self.addToolBar(Qt.BottomToolBarArea, self._findToolBar) + self.statusBar().addWidget(download_widget) + + def _remove_download_requested(self): + download_widget = self.sender() + self.statusBar().removeWidget(download_widget) + del download_widget + + def _show_find(self): + if self._find_tool_bar is None: + self._find_tool_bar = FindToolBar() + self._find_tool_bar.find.connect(self._tab_widget.find) + self.addToolBar(Qt.BottomToolBarArea, self._find_tool_bar) else: - self._findToolBar.show() - self._findToolBar.focusFind() + self._find_tool_bar.show() + self._find_tool_bar.focus_find() - def writeBookmarks(self): - self._bookmarkWidget.writeBookmarks() + def write_bookmarks(self): + self._bookmark_widget.write_bookmarks() if __name__ == '__main__': app = QApplication(sys.argv) - mainWin = createMainWindow() - initialUrls = sys.argv[1:] - if not initialUrls: - initialUrls.append('http://qt.io') - for url in initialUrls: - mainWin.loadUrlInNewTab(QUrl.fromUserInput(url)) - exitCode = app.exec_() - mainWin.writeBookmarks() - sys.exit(exitCode) + main_win = create_main_window() + initial_urls = sys.argv[1:] + if not initial_urls: + initial_urls.append('http://qt.io') + for url in initial_urls: + main_win.load_url_in_new_tab(QUrl.fromUserInput(url)) + exit_code = app.exec_() + main_win.write_bookmarks() + sys.exit(exit_code) diff --git a/examples/webenginewidgets/tabbedbrowser/webengineview.py b/examples/webenginewidgets/tabbedbrowser/webengineview.py index 7bef74dfe..7b5775bc8 100644 --- a/examples/webenginewidgets/tabbedbrowser/webengineview.py +++ b/examples/webenginewidgets/tabbedbrowser/webengineview.py @@ -43,7 +43,7 @@ from PySide2.QtWebEngineWidgets import QWebEnginePage, QWebEngineView from PySide2 import QtCore -_webActions = [QWebEnginePage.Back, QWebEnginePage.Forward, +_web_actions = [QWebEnginePage.Back, QWebEnginePage.Forward, QWebEnginePage.Reload, QWebEnginePage.Undo, QWebEnginePage.Redo, QWebEnginePage.Cut, QWebEnginePage.Copy, @@ -51,40 +51,40 @@ _webActions = [QWebEnginePage.Back, QWebEnginePage.Forward, class WebEngineView(QWebEngineView): - enabledChanged = QtCore.Signal(QWebEnginePage.WebAction, bool) + enabled_changed = QtCore.Signal(QWebEnginePage.WebAction, bool) @staticmethod - def webActions(): - return _webActions + def web_actions(): + return _web_actions @staticmethod - def minimumZoomFactor(): + def minimum_zoom_factor(): return 0.25 @staticmethod - def maximumZoomFactor(): + def maximum_zoom_factor(): return 5 - def __init__(self, tabFactoryFunc, windowFactoryFunc): + def __init__(self, tab_factory_func, window_factory_func): super(WebEngineView, self).__init__() - self._tabFactoryFunc = tabFactoryFunc - self._windowFactoryFunc = windowFactoryFunc + self._tab_factory_func = tab_factory_func + self._window_factory_func = window_factory_func page = self.page() self._actions = {} - for webAction in WebEngineView.webActions(): - action = page.action(webAction) - action.changed.connect(self._enabledChanged) - self._actions[action] = webAction + for web_action in WebEngineView.web_actions(): + action = page.action(web_action) + action.changed.connect(self._enabled_changed) + self._actions[action] = web_action - def isWebActionEnabled(self, webAction): - return self.page().action(webAction).isEnabled() + def is_web_action_enabled(self, web_action): + return self.page().action(web_action).isEnabled() - def createWindow(self, windowType): - if windowType == QWebEnginePage.WebBrowserTab or windowType == QWebEnginePage.WebBrowserBackgroundTab: - return self._tabFactoryFunc() - return self._windowFactoryFunc() + def create_window(self, window_type): + if window_type == QWebEnginePage.WebBrowserTab or window_type == QWebEnginePage.WebBrowserBackgroundTab: + return self._tab_factory_func() + return self._window_factory_func() - def _enabledChanged(self): + def _enabled_changed(self): action = self.sender() - webAction = self._actions[action] - self.enabledChanged.emit(webAction, action.isEnabled()) + web_action = self._actions[action] + self.enabled_changed.emit(web_action, action.isEnabled()) @@ -136,6 +136,8 @@ using `setup.py build`: --sanitize-address will build the project with address sanitizer enabled (Linux or macOS only). --skip-docs skip the documentation generation. + --limited-api=yes|no default yes if applicable + Set or clear the limited API flag. Ignored for Python 2. REQUIREMENTS: @@ -217,7 +219,7 @@ this_file = os.path.abspath(this_file) if os.path.dirname(this_file): os.chdir(os.path.dirname(this_file)) -from build_scripts.main import get_package_version +from build_scripts.main import get_package_version, get_setuptools_extension_modules from build_scripts.main import pyside_package_dir_name from build_scripts.main import cmd_class_dict from build_scripts.main import README, CHANGES @@ -227,6 +229,8 @@ from setuptools import setup, Extension # used as a value source. __version__ = get_package_version() +extension_modules = get_setuptools_extension_modules() + setup( name = "PySide2", version = get_package_version(), @@ -249,7 +253,6 @@ setup( 'Programming Language :: C++', 'Programming Language :: Python', 'Programming Language :: Python :: 2', - 'Programming Language :: Python :: 2.6', 'Programming Language :: Python :: 2.7', 'Programming Language :: Python :: 3', 'Programming Language :: Python :: 3.3', @@ -285,6 +288,6 @@ setup( # are overriding the build command to do it using cmake) so things # like bdist_egg will know that there are extension modules and # will name the dist with the full platform info. - ext_modules = [Extension('QtCore', [])], + ext_modules = extension_modules, ext_package = 'PySide2', ) diff --git a/sources/pyside2/CMakeLists.txt b/sources/pyside2/CMakeLists.txt index 77382480d..d5cf26612 100644 --- a/sources/pyside2/CMakeLists.txt +++ b/sources/pyside2/CMakeLists.txt @@ -69,6 +69,50 @@ if (NOT PYTHON_EXTENSION_SUFFIX) get_python_extension_suffix() endif() +# On Windows, PYTHON_LIBRARIES can be a list. Example: +# optimized;C:/Python36/libs/python36.lib;debug;C:/Python36/libs/python36_d.lib +# On other platforms, this result is not used at all. +execute_process( + COMMAND ${PYTHON_EXECUTABLE} -c "if True: + for lib in '${PYTHON_LIBRARIES}'.split(';'): + if '/' in lib: + prefix, py = lib.rsplit( '/', 1) + if py.startswith('python3'): + print(prefix + '/python3.lib') + break + " + OUTPUT_VARIABLE PYTHON_LIMITED_LIBRARIES + OUTPUT_STRIP_TRAILING_WHITESPACE) + +if (WIN32) + set(PATH_SEP "\;") +else() + set(PATH_SEP ":") +endif() + +option(FORCE_LIMITED_API "Enable the limited API." "yes") + +set(PYTHON_LIMITED_API 0) +if(FORCE_LIMITED_API STREQUAL "yes") + # GREATER_EQUAL is available only from cmake 3.7 on. We mean python 3.5 . + if (${PYTHON_VERSION_MAJOR} EQUAL 3 AND ${PYTHON_VERSION_MINOR} GREATER 4) + add_definitions("-DPy_LIMITED_API=0x03050000") + set(PYTHON_LIMITED_API 1) + endif() +endif() +if (CMAKE_BUILD_TYPE STREQUAL "Release") + add_definitions("-DNDEBUG") +endif() + +if (PYTHON_LIMITED_API) + if (WIN32 AND NOT EXISTS "${PYTHON_LIMITED_LIBRARIES}") + message(FATAL_ERROR "The Limited API was enabled, but ${PYTHON_LIMITED_LIBRARIES} was not found!") + endif() + message(STATUS "******************************************************") + message(STATUS "** Limited API enabled ${PYTHON_LIMITED_LIBRARIES}") + message(STATUS "******************************************************") +endif() + if (NOT PYTHON_CONFIG_SUFFIX) if (PYTHON_VERSION_MAJOR EQUAL 2) set(PYTHON_CONFIG_SUFFIX "-python${PYTHON_VERSION_MAJOR}.${PYTHON_VERSION_MINOR}") @@ -76,6 +120,13 @@ if (NOT PYTHON_CONFIG_SUFFIX) set(PYTHON_CONFIG_SUFFIX "${PYTHON_CONFIG_SUFFIX}${PYTHON_EXTENSION_SUFFIX}") endif() elseif (PYTHON_VERSION_MAJOR EQUAL 3) + if (PYTHON_LIMITED_API) + if(WIN32) + set(PYTHON_EXTENSION_SUFFIX "") + else() + set(PYTHON_EXTENSION_SUFFIX ".abi3") + endif() + endif() set(PYTHON_CONFIG_SUFFIX "${PYTHON_EXTENSION_SUFFIX}") endif() endif() @@ -400,12 +451,6 @@ else() endif() message(STATUS "Detected OS: ${AUTO_OS}") -if (WIN32) - set(PATH_SEP "\;") -else() - set(PATH_SEP ":") -endif() - # Define supported Qt Version set(SUPPORTED_QT_VERSION "${QT_VERSION_MAJOR}.${QT_VERSION_MINOR}") diff --git a/sources/pyside2/PySide2/QtCore/glue/qbytearray_bufferprotocol.cpp b/sources/pyside2/PySide2/QtCore/glue/qbytearray_bufferprotocol.cpp index 22825a5cb..ed5fef3ae 100644 --- a/sources/pyside2/PySide2/QtCore/glue/qbytearray_bufferprotocol.cpp +++ b/sources/pyside2/PySide2/QtCore/glue/qbytearray_bufferprotocol.cpp @@ -47,7 +47,7 @@ extern "C" { static Py_ssize_t SbkQByteArray_segcountproc(PyObject* self, Py_ssize_t* lenp) { if (lenp) - *lenp = self->ob_type->tp_as_sequence->sq_length(self); + *lenp = Py_TYPE(self)->tp_as_sequence->sq_length(self); return 1; } diff --git a/sources/pyside2/PySide2/QtCore/glue/qbytearray_mgetitem.cpp b/sources/pyside2/PySide2/QtCore/glue/qbytearray_mgetitem.cpp index 6a997c852..f1d5a6bfc 100644 --- a/sources/pyside2/PySide2/QtCore/glue/qbytearray_mgetitem.cpp +++ b/sources/pyside2/PySide2/QtCore/glue/qbytearray_mgetitem.cpp @@ -82,6 +82,6 @@ if (PyIndex_Check(_key)) { } else { PyErr_Format(PyExc_TypeError, "list indices must be integers or slices, not %.200s", - _key->ob_type->tp_name); + PepType((Py_TYPE(_key)))->tp_name); return NULL; } diff --git a/sources/pyside2/PySide2/QtCore/glue/qeasingcurve_glue.cpp b/sources/pyside2/PySide2/QtCore/glue/qeasingcurve_glue.cpp index 5d28fbf41..46a69be31 100644 --- a/sources/pyside2/PySide2/QtCore/glue/qeasingcurve_glue.cpp +++ b/sources/pyside2/PySide2/QtCore/glue/qeasingcurve_glue.cpp @@ -37,7 +37,7 @@ ** ****************************************************************************/ -#include <Python.h> +#include <sbkpython.h> #include <shiboken.h> #include <pysideweakref.h> #include <QEasingCurve> diff --git a/sources/pyside2/PySide2/QtCore/glue/qeasingcurve_glue.h b/sources/pyside2/PySide2/QtCore/glue/qeasingcurve_glue.h index 7053d808c..358ea9eec 100644 --- a/sources/pyside2/PySide2/QtCore/glue/qeasingcurve_glue.h +++ b/sources/pyside2/PySide2/QtCore/glue/qeasingcurve_glue.h @@ -40,7 +40,7 @@ #ifndef __QEASINGCURVE_GLUE__ #define __QEASINGCURVE_GLUE__ -#include <Python.h> +#include <sbkpython.h> #include <QEasingCurve> class PySideEasingCurveFunctor diff --git a/sources/pyside2/PySide2/QtCore/glue/qobject_connect.cpp b/sources/pyside2/PySide2/QtCore/glue/qobject_connect.cpp index ed37cef34..20f3720bf 100644 --- a/sources/pyside2/PySide2/QtCore/glue/qobject_connect.cpp +++ b/sources/pyside2/PySide2/QtCore/glue/qobject_connect.cpp @@ -43,8 +43,7 @@ static bool isDecorator(PyObject* method, PyObject* self) if (!PyObject_HasAttr(self, methodName)) return true; Shiboken::AutoDecRef otherMethod(PyObject_GetAttr(self, methodName)); - return reinterpret_cast<PyMethodObject*>(otherMethod.object())->im_func != \ - reinterpret_cast<PyMethodObject*>(method)->im_func; + return PyMethod_GET_FUNCTION(otherMethod.object()) != PyMethod_GET_FUNCTION(method); } static bool getReceiver(QObject *source, const char* signal, PyObject* callback, QObject** receiver, PyObject** self, QByteArray* callbackSig) diff --git a/sources/pyside2/PySide2/QtCore/glue/qobject_findchild.cpp b/sources/pyside2/PySide2/QtCore/glue/qobject_findchild.cpp index 464fb68b1..b32d104fd 100644 --- a/sources/pyside2/PySide2/QtCore/glue/qobject_findchild.cpp +++ b/sources/pyside2/PySide2/QtCore/glue/qobject_findchild.cpp @@ -41,7 +41,7 @@ static QObject* _findChildHelper(const QObject* parent, const QString& name, PyT { foreach(QObject* child, parent->children()) { Shiboken::AutoDecRef pyChild(%CONVERTTOPYTHON[QObject*](child)); - if (PyType_IsSubtype(pyChild->ob_type, desiredType) + if (PyType_IsSubtype(Py_TYPE(pyChild), desiredType) && (name.isNull() || name == child->objectName())) { return child; } @@ -71,7 +71,7 @@ static void _findChildrenHelper(const QObject* parent, const T& name, PyTypeObje { foreach(const QObject* child, parent->children()) { Shiboken::AutoDecRef pyChild(%CONVERTTOPYTHON[QObject*](child)); - if (PyType_IsSubtype(pyChild->ob_type, desiredType) && _findChildrenComparator(child, name)) + if (PyType_IsSubtype(Py_TYPE(pyChild), desiredType) && _findChildrenComparator(child, name)) PyList_Append(result, pyChild); _findChildrenHelper(child, name, desiredType, result); } diff --git a/sources/pyside2/PySide2/QtCore/typesystem_core_common.xml b/sources/pyside2/PySide2/QtCore/typesystem_core_common.xml index 994bc10c8..ed577b098 100644 --- a/sources/pyside2/PySide2/QtCore/typesystem_core_common.xml +++ b/sources/pyside2/PySide2/QtCore/typesystem_core_common.xml @@ -291,12 +291,18 @@ </native-to-target> <target-to-native> <add-conversion type="PyUnicode"> - Py_UNICODE *unicode = PyUnicode_AS_UNICODE(%in); - #if defined(Py_UNICODE_WIDE) + #ifndef Py_LIMITED_API + Py_UNICODE* unicode = PyUnicode_AS_UNICODE(%in); + # if defined(Py_UNICODE_WIDE) // cast as Py_UNICODE can be a different type %out = QString::fromUcs4((const uint*)unicode); - #else + # else %out = QString::fromUtf16((const ushort*)unicode, PyUnicode_GET_SIZE(%in)); + # endif + #else + wchar_t *temp = PyUnicode_AsWideCharString(%in, NULL); + %out = QString::fromWCharArray(temp); + PyMem_Free(temp); #endif </add-conversion> <add-conversion type="PyString" check="py2kStrCheck(%in)"> @@ -410,7 +416,7 @@ <add-conversion type="SbkObject"> // a class supported by QVariant? int typeCode; - const char *typeName = QVariant_resolveMetaType(%in->ob_type, &typeCode); + const char *typeName = QVariant_resolveMetaType(Py_TYPE(%in), &typeCode); if (!typeCode || !typeName) return; QVariant var(typeCode, (void*)0); @@ -435,9 +441,9 @@ <inject-code class="native" position="beginning"> static const char *QVariant_resolveMetaType(PyTypeObject *type, int *typeId) { - if (PyObject_TypeCheck(type, &SbkObjectType_Type)) { - SbkObjectType *sbkType = (SbkObjectType*)type; - const char *typeName = Shiboken::ObjectType::getOriginalName(sbkType); + if (PyObject_TypeCheck(type, SbkObjectType_TypeF())) { + SbkObjectType* sbkType = (SbkObjectType*)type; + const char* typeName = Shiboken::ObjectType::getOriginalName(sbkType); if (!typeName) return 0; bool valueType = '*' != typeName[qstrlen(typeName) - 1]; @@ -456,15 +462,16 @@ // tp_base does not always point to the first base class, but rather to the first // that has added any python fields or slots to its object layout. // See https://mail.python.org/pipermail/python-list/2009-January/520733.html - if (type->tp_bases) { - for (int i = 0; i < PyTuple_GET_SIZE(type->tp_bases); ++i) { - const char *derivedName = QVariant_resolveMetaType((PyTypeObject*)PyTuple_GET_ITEM(type->tp_bases, i), typeId); + if (PepType(type)->tp_bases) { + for (int i = 0; i < PyTuple_GET_SIZE(PepType(type)->tp_bases); ++i) { + const char *derivedName = QVariant_resolveMetaType((PyTypeObject*)PyTuple_GET_ITEM( + PepType(type)->tp_bases, i), typeId); if (derivedName) return derivedName; } } - else if (type->tp_base) { - return QVariant_resolveMetaType(type->tp_base, typeId); + else if (PepType(type)->tp_base) { + return QVariant_resolveMetaType(PepType(type)->tp_base, typeId); } } *typeId = 0; @@ -563,16 +570,16 @@ </add-conversion> <add-conversion type="PyTypeObject"> const char *typeName; - if (Shiboken::String::checkType((PyTypeObject*)%in)) + if (Shiboken::String::checkType(reinterpret_cast<PyTypeObject*>(%in))) typeName = "QString"; else if (%in == reinterpret_cast<PyObject*>(&PyFloat_Type)) typeName = "double"; // float is a UserType in QVariant. else if (%in == reinterpret_cast<PyObject*>(&PyLong_Type)) typeName = "int"; // long is a UserType in QVariant. - else if (%in->ob_type == &SbkObjectType_Type) + else if (Py_TYPE(%in) == SbkObjectType_TypeF()) typeName = Shiboken::ObjectType::getOriginalName((SbkObjectType*)%in); else - typeName = (reinterpret_cast<PyTypeObject*>(%in))->tp_name; + typeName = PepType((reinterpret_cast<PyTypeObject*>(%in)))->tp_name; %out = QVariant::nameToType(typeName); </add-conversion> <add-conversion type="PyString" check="Shiboken::String::check(%in)"> @@ -2592,7 +2599,7 @@ <add-function signature="__repr__" return-type="PyObject*"> <inject-code class="target" position="beginning"> - QByteArray b((reinterpret_cast<PyObject*>(%PYSELF))->ob_type->tp_name); + QByteArray b(PepType(Py_TYPE(%PYSELF))->tp_name); PyObject *aux = Shiboken::String::fromStringAndSize(%CPPSELF.constData(), %CPPSELF.size()); if (PyUnicode_CheckExact(aux)) { PyObject *tmp = PyUnicode_AsASCIIString(aux); @@ -3100,7 +3107,7 @@ <inject-code> Py_ssize_t size; uchar *ptr = reinterpret_cast<uchar*>(Shiboken::Buffer::getPointer(%PYARG_1, &size)); - %RETURN_TYPE %0 = %CPPSELF.%FUNCTION_NAME(const_cast<const uchar*>(ptr), size); + %RETURN_TYPE %0 = %CPPSELF.%FUNCTION_NAME(const_cast<const uchar*>(ptr), size); %PYARG_0 = %CONVERTTOPYTHON[%RETURN_TYPE](%0); </inject-code> </modify-function> @@ -3126,8 +3133,8 @@ // %FUNCTION_NAME() - disable generation of c++ function call (void) %2; // remove warning about unused variable Shiboken::AutoDecRef emptyTuple(PyTuple_New(0)); - PyObject *pyTimer = Shiboken::SbkType<QTimer>()->tp_new(Shiboken::SbkType<QTimer>(), emptyTuple, 0); - Shiboken::SbkType<QTimer>()->tp_init(pyTimer, emptyTuple, 0); + PyObject *pyTimer = PepType(Shiboken::SbkType<QTimer>())->tp_new(Shiboken::SbkType<QTimer>(), emptyTuple, 0); + PepType(Shiboken::SbkType<QTimer>())->tp_init(pyTimer, emptyTuple, 0); QTimer* timer = %CONVERTTOCPP[QTimer*](pyTimer); Shiboken::AutoDecRef result( @@ -3150,14 +3157,14 @@ <inject-code class="target" position="beginning"> // %FUNCTION_NAME() - disable generation of c++ function call Shiboken::AutoDecRef emptyTuple(PyTuple_New(0)); - PyObject *pyTimer = Shiboken::SbkType<QTimer>()->tp_new(Shiboken::SbkType<QTimer>(), emptyTuple, 0); - Shiboken::SbkType<QTimer>()->tp_init(pyTimer, emptyTuple, 0); + PyObject *pyTimer = PepType(Shiboken::SbkType<QTimer>())->tp_new(Shiboken::SbkType<QTimer>(), emptyTuple, 0); + PepType(Shiboken::SbkType<QTimer>())->tp_init(pyTimer, emptyTuple, 0); QTimer* timer = %CONVERTTOCPP[QTimer*](pyTimer); timer->setSingleShot(true); - if (PyObject_TypeCheck(%2, &PySideSignalInstanceType)) { + if (PyObject_TypeCheck(%2, PySideSignalInstanceTypeF())) { PySideSignalInstance *signalInstance = reinterpret_cast<PySideSignalInstance*>(%2); - Shiboken::AutoDecRef signalSignature(Shiboken::String::fromFormat("2%s",PySide::Signal::getSignature(signalInstance))); + Shiboken::AutoDecRef signalSignature(Shiboken::String::fromFormat("2%s", PySide::Signal::getSignature(signalInstance))); Shiboken::AutoDecRef result( PyObject_CallMethod(pyTimer, const_cast<char*>("connect"), @@ -4038,7 +4045,7 @@ s1.addTransition(button.clicked, s1h)</code> <replace-default-expression with="0" /> </modify-argument> <inject-code> - if (PyObject_TypeCheck(%1, &PySideSignalInstanceType)) { + if (PyObject_TypeCheck(%1, PySideSignalInstanceTypeF())) { PyObject *dataSource = PySide::Signal::getObject((PySideSignalInstance*)%PYARG_1); Shiboken::AutoDecRef obType(PyObject_Type(dataSource)); QObject* sender = %CONVERTTOCPP[QObject*](dataSource); @@ -4094,11 +4101,11 @@ s1.addTransition(button.clicked, s1h)</code> // since it refers to a name very tied to the generator implementation. // Check bug #362 for more information on this // http://bugs.openbossa.org/show_bug.cgi?id=362 - if (!PyObject_TypeCheck(%1, &PySideSignalInstanceType)) + if (!PyObject_TypeCheck(%1, PySideSignalInstanceTypeF())) goto Sbk_%TYPEFunc_%FUNCTION_NAME_TypeError; PySideSignalInstance *signalInstance = reinterpret_cast<PySideSignalInstance*>(%1); QObject* sender = %CONVERTTOCPP[QObject*](PySide::Signal::getObject(signalInstance)); - QSignalTransition*%0 = %CPPSELF->%FUNCTION_NAME(sender,PySide::Signal::getSignature(signalInstance),%2); + QSignalTransition *%0 = %CPPSELF->%FUNCTION_NAME(sender, PySide::Signal::getSignature(signalInstance),%2); %PYARG_0 = %CONVERTTOPYTHON[QSignalTransition*](%0); </inject-code> </add-function> diff --git a/sources/pyside2/PySide2/QtGui/typesystem_gui_common.xml b/sources/pyside2/PySide2/QtGui/typesystem_gui_common.xml index 47bf62992..eee22b55c 100644 --- a/sources/pyside2/PySide2/QtGui/typesystem_gui_common.xml +++ b/sources/pyside2/PySide2/QtGui/typesystem_gui_common.xml @@ -1752,7 +1752,7 @@ PyErr_Format(PyExc_TypeError, "Invalid return value in function %s, expected %s, got %s.", "QValidator.validate", "PySide2.QtGui.QValidator.State, (PySide2.QtGui.QValidator.State,), (PySide2.QtGui.QValidator.State, unicode) or (PySide2.QtGui.QValidator.State, unicode, int)", - pyResult->ob_type->tp_name); + PepType((Py_TYPE(pyResult)))->tp_name); return QValidator::State(); } </template> diff --git a/sources/pyside2/PySide2/QtQml/pysideqmlregistertype.cpp b/sources/pyside2/PySide2/QtQml/pysideqmlregistertype.cpp index d95ae2259..fa9eb6349 100644 --- a/sources/pyside2/PySide2/QtQml/pysideqmlregistertype.cpp +++ b/sources/pyside2/PySide2/QtQml/pysideqmlregistertype.cpp @@ -120,9 +120,9 @@ int PySide::qmlRegisterType(PyObject *pyObj, const char *uri, int versionMajor, } PyTypeObject *pyObjType = reinterpret_cast<PyTypeObject *>(pyObj); - if (!PySequence_Contains(pyObjType->tp_mro, reinterpret_cast<PyObject *>(qobjectType))) { + if (!PySequence_Contains(PepType(pyObjType)->tp_mro, reinterpret_cast<PyObject *>(qobjectType))) { PyErr_Format(PyExc_TypeError, "A type inherited from %s expected, got %s.", - qobjectType->tp_name, pyObjType->tp_name); + PepType(qobjectType)->tp_name, PepType(pyObjType)->tp_name); return -1; } @@ -229,57 +229,34 @@ void propListTpFree(void* self) PySideProperty* pySelf = reinterpret_cast<PySideProperty*>(self); delete reinterpret_cast<QmlListProperty*>(PySide::Property::userData(pySelf)); // calls base type constructor - Py_TYPE(pySelf)->tp_base->tp_free(self); + PepType(PepType(Py_TYPE(pySelf))->tp_base)->tp_free(self); } -PyTypeObject PropertyListType = { - PyVarObject_HEAD_INIT(0, 0) - "ListProperty", /*tp_name*/ - sizeof(PySideProperty), /*tp_basicsize*/ - 0, /*tp_itemsize*/ - 0, /*tp_dealloc*/ - 0, /*tp_print*/ - 0, /*tp_getattr*/ - 0, /*tp_setattr*/ - 0, /*tp_compare*/ - 0, /*tp_repr*/ - 0, /*tp_as_number*/ - 0, /*tp_as_sequence*/ - 0, /*tp_as_mapping*/ - 0, /*tp_hash */ - 0, /*tp_call*/ - 0, /*tp_str*/ - 0, /*tp_getattro*/ - 0, /*tp_setattro*/ - 0, /*tp_as_buffer*/ - Py_TPFLAGS_DEFAULT, /*tp_flags*/ - 0, /*tp_doc */ - 0, /*tp_traverse */ - 0, /*tp_clear */ - 0, /*tp_richcompare */ - 0, /*tp_weaklistoffset */ - 0, /*tp_iter */ - 0, /*tp_iternext */ - 0, /*tp_methods */ - 0, /*tp_members */ - 0, /*tp_getset */ - &PySidePropertyType, /*tp_base */ - 0, /*tp_dict */ - 0, /*tp_descr_get */ - 0, /*tp_descr_set */ - 0, /*tp_dictoffset */ - propListTpInit, /*tp_init */ - 0, /*tp_alloc */ - 0, /*tp_new */ - propListTpFree, /*tp_free */ - 0, /*tp_is_gc */ - 0, /*tp_bases */ - 0, /*tp_mro */ - 0, /*tp_cache */ - 0, /*tp_subclasses */ - 0, /*tp_weaklist */ - 0, /*tp_del */ +static PyType_Slot PropertyListType_slots[] = { + {Py_tp_init, (void *)propListTpInit}, + {Py_tp_free, (void *)propListTpFree}, + {Py_tp_dealloc, (void *)SbkDummyDealloc}, + {0, 0} }; +static PyType_Spec PropertyListType_spec = { + "PySide2.QtQml.ListProperty", + sizeof(PySideProperty), + 0, + Py_TPFLAGS_DEFAULT, + PropertyListType_slots, +}; + + +PyTypeObject *PropertyListTypeF(void) +{ + static PyTypeObject *type = nullptr; + if (!type) { + PyObject *bases = Py_BuildValue("(O)", PySidePropertyTypeF()); + type = (PyTypeObject *)PyType_FromSpecWithBases(&PropertyListType_spec, bases); + Py_XDECREF(bases); + } + return type; +} } // extern "C" @@ -312,7 +289,7 @@ int propListCount(QQmlListProperty<QObject> *propList) // Check return type int cppResult = 0; - PythonToCppFunc pythonToCpp; + PythonToCppFunc pythonToCpp = 0; if (PyErr_Occurred()) PyErr_Print(); else if ((pythonToCpp = Shiboken::Conversions::isPythonToCppConvertible(Shiboken::Conversions::PrimitiveTypeConverter<int>(), retVal))) @@ -387,7 +364,7 @@ QtQml_VolatileBoolObject_new(PyTypeObject *type, PyObject *args, PyObject *kwds) return Q_NULLPTR; QtQml_VolatileBoolObject *self - = reinterpret_cast<QtQml_VolatileBoolObject *>(type->tp_alloc(type, 0)); + = reinterpret_cast<QtQml_VolatileBoolObject *>(PepType(type)->tp_alloc(type, 0)); if (self != Q_NULLPTR) self->flag = ok; @@ -444,10 +421,10 @@ QtQml_VolatileBoolObject_repr(QtQml_VolatileBoolObject *self) if (self->flag) s = PyBytes_FromFormat("%s(True)", - Py_TYPE(self)->tp_name); + PepType((Py_TYPE(self)))->tp_name); else s = PyBytes_FromFormat("%s(False)", - Py_TYPE(self)->tp_name); + PepType((Py_TYPE(self)))->tp_name); Py_XINCREF(s); return s; } @@ -459,87 +436,61 @@ QtQml_VolatileBoolObject_str(QtQml_VolatileBoolObject *self) if (self->flag) s = PyBytes_FromFormat("%s(True) -> %p", - Py_TYPE(self)->tp_name, &(self->flag)); + PepType((Py_TYPE(self)))->tp_name, &(self->flag)); else s = PyBytes_FromFormat("%s(False) -> %p", - Py_TYPE(self)->tp_name, &(self->flag)); + PepType((Py_TYPE(self)))->tp_name, &(self->flag)); Py_XINCREF(s); return s; } -PyTypeObject QtQml_VolatileBoolType = { - PyVarObject_HEAD_INIT(Q_NULLPTR, 0) /*ob_size*/ - "VolatileBool", /*tp_name*/ - sizeof(QtQml_VolatileBoolObject), /*tp_basicsize*/ - 0, /*tp_itemsize*/ - 0, /*tp_dealloc*/ - 0, /*tp_print*/ - 0, /*tp_getattr*/ - 0, /*tp_setattr*/ - 0, /*tp_compare*/ - reinterpret_cast<reprfunc>(QtQml_VolatileBoolObject_repr), /*tp_repr*/ - 0, /*tp_as_number*/ - 0, /*tp_as_sequence*/ - 0, /*tp_as_mapping*/ - 0, /*tp_hash */ - 0, /*tp_call*/ - reinterpret_cast<reprfunc>(QtQml_VolatileBoolObject_str), /*tp_str*/ - 0, /*tp_getattro*/ - 0, /*tp_setattro*/ - 0, /*tp_as_buffer*/ - Py_TPFLAGS_DEFAULT, /*tp_flags*/ - "VolatileBool objects contain a C++ volatile bool", /* tp_doc */ - 0, /* tp_traverse */ - 0, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - 0, /* tp_iter */ - 0, /* tp_iternext */ - QtQml_VolatileBoolObject_methods, /* tp_methods */ - 0, /* tp_members */ - 0, /* tp_getset */ - 0, /* tp_base */ - 0, /* tp_dict */ - 0, /* tp_descr_get */ - 0, /* tp_descr_set */ - 0, /* tp_dictoffset */ - 0, /* tp_init */ - 0, /* tp_alloc */ - QtQml_VolatileBoolObject_new, /* tp_new */ - 0, /* tp_free */ - 0, /* tp_is_gc */ - 0, /* tp_bases */ - 0, /* tp_mro */ - 0, /* tp_cache */ - 0, /* tp_subclasses */ - 0, /* tp_weaklist */ - 0, /* tp_del */ - 0, /* tp_version_tag */ -#if PY_MAJOR_VERSION > 3 || PY_MAJOR_VERSION == 3 && PY_MINOR_VERSION >= 4 - 0 /* tp_finalize */ -#endif +static PyType_Slot QtQml_VolatileBoolType_slots[] = { + {Py_tp_repr, (void *)reinterpret_cast<reprfunc>(QtQml_VolatileBoolObject_repr)}, + {Py_tp_str, (void *)reinterpret_cast<reprfunc>(QtQml_VolatileBoolObject_str)}, + {Py_tp_methods, (void *)QtQml_VolatileBoolObject_methods}, + {Py_tp_new, (void *)QtQml_VolatileBoolObject_new}, + {Py_tp_dealloc, (void *)SbkDummyDealloc}, + {0, 0} }; +static PyType_Spec QtQml_VolatileBoolType_spec = { + "PySide2.QtQml.VolatileBool", + sizeof(QtQml_VolatileBoolObject), + 0, + Py_TPFLAGS_DEFAULT, + QtQml_VolatileBoolType_slots, +}; + + +PyTypeObject *QtQml_VolatileBoolTypeF(void) +{ + static PyTypeObject *type = nullptr; + if (!type) + type = (PyTypeObject *)PyType_FromSpec(&QtQml_VolatileBoolType_spec); + return type; +} void PySide::initQmlSupport(PyObject* module) { ElementFactory<PYSIDE_MAX_QML_TYPES - 1>::init(); // Export QmlListProperty type - if (PyType_Ready(&PropertyListType) < 0) { + if (PyType_Ready(PropertyListTypeF()) < 0) { + PyErr_Print(); qWarning() << "Error initializing PropertyList type."; return; } - Py_INCREF(reinterpret_cast<PyObject *>(&PropertyListType)); - PyModule_AddObject(module, PropertyListType.tp_name, - reinterpret_cast<PyObject *>(&PropertyListType)); + Py_INCREF(reinterpret_cast<PyObject *>(PropertyListTypeF())); + PyModule_AddObject(module, PepType_GetNameStr(PropertyListTypeF()), + reinterpret_cast<PyObject *>(PropertyListTypeF())); - if (PyType_Ready(&QtQml_VolatileBoolType) < 0) { + if (PyType_Ready(QtQml_VolatileBoolTypeF()) < 0) { + PyErr_Print(); qWarning() << "Error initializing VolatileBool type."; return; } - Py_INCREF(&QtQml_VolatileBoolType); - PyModule_AddObject(module, QtQml_VolatileBoolType.tp_name, - reinterpret_cast<PyObject *>(&QtQml_VolatileBoolType)); + Py_INCREF(QtQml_VolatileBoolTypeF()); + PyModule_AddObject(module, PepType_GetNameStr(QtQml_VolatileBoolTypeF()), + reinterpret_cast<PyObject *>(QtQml_VolatileBoolTypeF())); } diff --git a/sources/pyside2/PySide2/QtQml/pysideqmlregistertype.h b/sources/pyside2/PySide2/QtQml/pysideqmlregistertype.h index a4ee7309a..0ef6539a5 100644 --- a/sources/pyside2/PySide2/QtQml/pysideqmlregistertype.h +++ b/sources/pyside2/PySide2/QtQml/pysideqmlregistertype.h @@ -40,7 +40,7 @@ #ifndef PYSIDEQMLREGISTERTYPE_H #define PYSIDEQMLREGISTERTYPE_H -#include <Python.h> +#include <sbkpython.h> struct SbkObjectType; @@ -78,8 +78,8 @@ typedef struct { volatile bool flag; } QtQml_VolatileBoolObject; -PyAPI_DATA(PyTypeObject) QtQml_VolatileBoolType; +PyAPI_FUNC(PyTypeObject *) QtQml_VolatileBoolTypeF(void); -#define VolatileBool_Check(op) (Py_TYPE(op) == &QtQml_VolatileBoolType) +#define VolatileBool_Check(op) (Py_TYPE(op) == QtQml_VolatileBoolTypeF()) #endif diff --git a/sources/pyside2/PySide2/QtQuick/pysidequickregistertype.cpp b/sources/pyside2/PySide2/QtQuick/pysidequickregistertype.cpp index 594fa8015..67ef53551 100644 --- a/sources/pyside2/PySide2/QtQuick/pysidequickregistertype.cpp +++ b/sources/pyside2/PySide2/QtQuick/pysidequickregistertype.cpp @@ -106,11 +106,11 @@ struct ElementFactory<0> : ElementFactoryBase<0> typePointerName, typeListName, \ typeMetaObject, type, registered) -bool pyTypeObjectInheritsFromClass(const PyTypeObject *pyObjType, QByteArray className) +bool pyTypeObjectInheritsFromClass(PyTypeObject *pyObjType, QByteArray className) { className.append('*'); PyTypeObject *classPyType = Shiboken::Conversions::getPythonTypeObject(className.constData()); - bool isDerived = PySequence_Contains(pyObjType->tp_mro, + bool isDerived = PySequence_Contains(PepType(pyObjType)->tp_mro, reinterpret_cast<PyObject *>(classPyType)); return isDerived; } @@ -118,7 +118,7 @@ bool pyTypeObjectInheritsFromClass(const PyTypeObject *pyObjType, QByteArray cla template <class WrapperClass> void registerTypeIfInheritsFromClass( QByteArray className, - const PyTypeObject *typeToRegister, + PyTypeObject *typeToRegister, const QByteArray &typePointerName, const QByteArray &typeListName, QMetaObject *typeMetaObject, @@ -190,7 +190,7 @@ bool quickRegisterType(PyObject *pyObj, const char *uri, int versionMajor, int v PyTypeObject *pyObjType = reinterpret_cast<PyTypeObject *>(pyObj); PyTypeObject *qQuickItemPyType = Shiboken::Conversions::getPythonTypeObject("QQuickItem*"); - bool isQuickItem = PySequence_Contains(pyObjType->tp_mro, + bool isQuickItem = PySequence_Contains(PepType(pyObjType)->tp_mro, reinterpret_cast<PyObject *>(qQuickItemPyType)); // Register only classes that inherit QQuickItem or its children. diff --git a/sources/pyside2/PySide2/QtQuick/pysidequickregistertype.h b/sources/pyside2/PySide2/QtQuick/pysidequickregistertype.h index 35d3edecb..1955413b2 100644 --- a/sources/pyside2/PySide2/QtQuick/pysidequickregistertype.h +++ b/sources/pyside2/PySide2/QtQuick/pysidequickregistertype.h @@ -40,7 +40,7 @@ #ifndef PYSIDE_QUICK_REGISTER_TYPE_H #define PYSIDE_QUICK_REGISTER_TYPE_H -#include <Python.h> +#include <sbkpython.h> struct SbkObjectType; diff --git a/sources/pyside2/PySide2/QtScript/typesystem_script.xml b/sources/pyside2/PySide2/QtScript/typesystem_script.xml index ccb2e3ab7..dc089a300 100644 --- a/sources/pyside2/PySide2/QtScript/typesystem_script.xml +++ b/sources/pyside2/PySide2/QtScript/typesystem_script.xml @@ -84,11 +84,12 @@ <add-function signature="__repr__" return-type="PyObject*"> <inject-code class="target" position="beginning"> if (%CPPSELF.isVariant() || %CPPSELF.isString()) { - QString format = QString().sprintf("%s(\"%s\")", ((PyObject*)%PYSELF)->ob_type->tp_name, qPrintable(%CPPSELF.toString())); + QString format = QString().sprintf("%s(\"%s\")", + PepType(Py_TYPE(%PYSELF))->tp_name, + qPrintable(%CPPSELF.toString())); %PYARG_0 = Shiboken::String::fromCString(qPrintable(format)); } else { - %PYARG_0 = Shiboken::String::fromCString( - ((PyObject* )%PYSELF)->ob_type->tp_name); + %PYARG_0 = Shiboken::String::fromCString(PepType(Py_TYPE(%PYSELF))->tp_name); } </inject-code> </add-function> diff --git a/sources/pyside2/PySide2/QtWebEngineWidgets/CMakeLists.txt b/sources/pyside2/PySide2/QtWebEngineWidgets/CMakeLists.txt index f04394de9..e0648c491 100644 --- a/sources/pyside2/PySide2/QtWebEngineWidgets/CMakeLists.txt +++ b/sources/pyside2/PySide2/QtWebEngineWidgets/CMakeLists.txt @@ -8,9 +8,11 @@ ${QtWebEngineWidgets_GEN_DIR}/qwebenginehistoryitem_wrapper.cpp ${QtWebEngineWidgets_GEN_DIR}/qwebenginepage_wrapper.cpp ${QtWebEngineWidgets_GEN_DIR}/qwebengineprofile_wrapper.cpp ${QtWebEngineWidgets_GEN_DIR}/qwebenginescript_wrapper.cpp -#${QtWebEngineWidgets_GEN_DIR}/qwebenginescriptcollection_wrapper.cpp -#${QtWebEngineWidgets_GEN_DIR}/qwebenginesettings_wrapper.cpp +${QtWebEngineWidgets_GEN_DIR}/qwebenginescriptcollection_wrapper.cpp +${QtWebEngineWidgets_GEN_DIR}/qwebenginesettings_wrapper.cpp ${QtWebEngineWidgets_GEN_DIR}/qwebengineview_wrapper.cpp +${QtWebEngineWidgets_GEN_DIR}/qwebenginecontextmenudata_wrapper.cpp +${QtWebEngineWidgets_GEN_DIR}/qwebenginefullscreenrequest_wrapper.cpp # module is always needed ${QtWebEngineWidgets_GEN_DIR}/qtwebenginewidgets_module_wrapper.cpp ) diff --git a/sources/pyside2/PySide2/QtWebEngineWidgets/typesystem_webenginewidgets.xml b/sources/pyside2/PySide2/QtWebEngineWidgets/typesystem_webenginewidgets.xml index addbf222a..6e7418426 100644 --- a/sources/pyside2/PySide2/QtWebEngineWidgets/typesystem_webenginewidgets.xml +++ b/sources/pyside2/PySide2/QtWebEngineWidgets/typesystem_webenginewidgets.xml @@ -53,6 +53,7 @@ </object-type> <object-type name="QWebEngineDownloadItem"> + <enum-type name="DownloadInterruptReason"/> <enum-type name="DownloadState" /> <enum-type name="SavePageFormat"/> </object-type> @@ -71,6 +72,7 @@ <enum-type name="Feature" /> <enum-type name="FileSelectionMode" /> <enum-type name="JavaScriptConsoleMessageLevel" /> + <enum-type name="RenderProcessTerminationStatus"/> </object-type> <object-type name="QWebEngineProfile"> @@ -83,16 +85,23 @@ <enum-type name="ScriptWorldId" /> </value-type> - <!-- TODO: Deal with private constructor - <value-type name="QWebEngineScriptCollection" /> --> + <object-type name="QWebEngineScriptCollection"/> - <!-- TODO: Deal with private constructor - <value-type name="QWebEngineSettings"> - <enum-type name="FontFamily" /> - <enum-type name="WebAttribute" /> - <enum-type name="FontSize" /> - </value-type> --> + <object-type name="QWebEngineSettings"> + <enum-type name="FontFamily"/> + <enum-type name="FontSize"/> + <enum-type name="UnknownUrlSchemePolicy" since="5.11"/> + <enum-type name="WebAttribute"/> + </object-type> <object-type name="QWebEngineView" /> + <value-type name="QWebEngineContextMenuData"> + <enum-type name="EditFlag" flags="EditFlags" since="5.11"/> + <enum-type name="MediaFlag" flags="MediaFlags" since="5.11"/> + <enum-type name="MediaType"/> + </value-type> + + <object-type name="QWebEngineFullScreenRequest"/> + </typesystem> diff --git a/sources/pyside2/PySide2/QtWidgets/glue/qmenu_glue.cpp b/sources/pyside2/PySide2/QtWidgets/glue/qmenu_glue.cpp index 8a4b7e628..4e9c8c3b7 100644 --- a/sources/pyside2/PySide2/QtWidgets/glue/qmenu_glue.cpp +++ b/sources/pyside2/PySide2/QtWidgets/glue/qmenu_glue.cpp @@ -50,7 +50,11 @@ inline PyObject* addActionWithPyObject(QMenu* self, const QIcon& icon, const QSt self->addAction(act); PyObject* pyAct = %CONVERTTOPYTHON[QAction*](act); - Shiboken::AutoDecRef result(PyObject_CallMethod(pyAct, "connect", "OsO", pyAct, SIGNAL(triggered()), callback)); + Shiboken::AutoDecRef result(PyObject_CallMethod(pyAct, + const_cast<char *>("connect"), + const_cast<char *>("OsO"), + pyAct, + SIGNAL(triggered()), callback)); if (result.isNull()) { Py_DECREF(pyAct); return 0; diff --git a/sources/pyside2/PySide2/QtWidgets/glue/qmenubar_glue.cpp b/sources/pyside2/PySide2/QtWidgets/glue/qmenubar_glue.cpp index fdd621128..8cdbc2e01 100644 --- a/sources/pyside2/PySide2/QtWidgets/glue/qmenubar_glue.cpp +++ b/sources/pyside2/PySide2/QtWidgets/glue/qmenubar_glue.cpp @@ -45,7 +45,10 @@ addActionWithPyObject(QMenuBar* self, const QString& text, PyObject* callback) self->addAction(act); PyObject* pyAct = %CONVERTTOPYTHON[QAction*](act); - PyObject* result = PyObject_CallMethod(pyAct, "connect", "OsO", pyAct, + PyObject* result = PyObject_CallMethod(pyAct, + const_cast<char *>("connect"), + const_cast<char *>("OsO"), + pyAct, SIGNAL(triggered(bool)), callback); if (result == 0 || result == Py_False) { diff --git a/sources/pyside2/PySide2/QtWidgets/typesystem_widgets_common.xml b/sources/pyside2/PySide2/QtWidgets/typesystem_widgets_common.xml index b4a6c2453..11e6a9f7a 100644 --- a/sources/pyside2/PySide2/QtWidgets/typesystem_widgets_common.xml +++ b/sources/pyside2/PySide2/QtWidgets/typesystem_widgets_common.xml @@ -269,7 +269,7 @@ <enum-type name="PanelModality" since="4.6"/> <inject-code class="target" position="end"> PyObject *userTypeConstant = PyInt_FromLong(QGraphicsItem::UserType); - PyDict_SetItemString(Sbk_QGraphicsItem_Type.super.ht_type.tp_dict, "UserType", userTypeConstant); + PyDict_SetItemString(PepType(Sbk_QGraphicsItem_TypeF())->tp_dict, "UserType", userTypeConstant); </inject-code> <modify-function signature="setParentItem(QGraphicsItem*)"> <modify-argument index="this"> @@ -1022,7 +1022,11 @@ %0 = new %TYPE(%1, %2); </inject-code> <inject-code class="target" position="end"> - Shiboken::AutoDecRef result(PyObject_CallMethod(%PYSELF, "connect", "OsO", %PYSELF, SIGNAL(activated()), %PYARG_3)); + Shiboken::AutoDecRef result(PyObject_CallMethod(%PYSELF, + const_cast<char *>("connect"), + const_cast<char *>("OsO"), + %PYSELF, SIGNAL(activated()), %PYARG_3) + ); if (!result.isNull()) Shiboken::Object::setParent(%PYARG_2, %PYSELF); </inject-code> @@ -3029,7 +3033,11 @@ <inject-code> QAction *action = %CPPSELF.addAction(%1, %2); %PYARG_0 = %CONVERTTOPYTHON[QAction*](action); - Shiboken::AutoDecRef result(PyObject_CallMethod(%PYARG_0, "connect", "OsO", %PYARG_0, SIGNAL(triggered()), %PYARG_3)); + Shiboken::AutoDecRef result(PyObject_CallMethod(%PYARG_0, + const_cast<char *>("connect"), + const_cast<char *>("OsO"), + %PYARG_0, SIGNAL(triggered()), %PYARG_3) + ); </inject-code> </modify-function> <modify-function signature="addAction(QString,const QObject*,const char*)"> @@ -3045,7 +3053,11 @@ <inject-code> QAction *action = %CPPSELF.addAction(%1); %PYARG_0 = %CONVERTTOPYTHON[QAction*](action); - Shiboken::AutoDecRef result(PyObject_CallMethod(%PYARG_0, "connect", "OsO", %PYARG_0, SIGNAL(triggered()), %PYARG_2)); + Shiboken::AutoDecRef result(PyObject_CallMethod(%PYARG_0, + const_cast<char *>("connect"), + const_cast<char *>("OsO"), + %PYARG_0, SIGNAL(triggered()), %PYARG_2) + ); </inject-code> </modify-function> <modify-function signature="addAction(const QString&)"> diff --git a/sources/pyside2/PySide2/typesystem_templates.xml b/sources/pyside2/PySide2/typesystem_templates.xml index 798d02ddb..103d773cf 100644 --- a/sources/pyside2/PySide2/typesystem_templates.xml +++ b/sources/pyside2/PySide2/typesystem_templates.xml @@ -314,11 +314,12 @@ <!-- templates for __repr__ --> <template name="repr_code"> - QString format = QString().sprintf("%s(%REPR_FORMAT)", ((PyObject*)%PYSELF)->ob_type->tp_name, %REPR_ARGS); + QString format = QString().sprintf("%s(%REPR_FORMAT)", + PepType(Py_TYPE(%PYSELF))->tp_name, %REPR_ARGS); %PYARG_0 = Shiboken::String::fromCString(qPrintable(format)); </template> <template name="repr_code_matrix"> - QString format= QString("%1((").arg(((PyObject*)%PYSELF)->ob_type->tp_name); + QString format= QString("%1((").arg(PepType(Py_TYPE(%PYSELF))->tp_name); QList< %MATRIX_TYPE > cppArgs; %MATRIX_TYPE data[%MATRIX_SIZE]; diff --git a/sources/pyside2/doc/qtattributionsscannertorst.py b/sources/pyside2/doc/qtattributionsscannertorst.py index ac651ca8d..54982c1a0 100644 --- a/sources/pyside2/doc/qtattributionsscannertorst.py +++ b/sources/pyside2/doc/qtattributionsscannertorst.py @@ -41,7 +41,7 @@ Tool to run qtattributionsscanner and convert its output to rst """ -import os, json, subprocess, sys +import os, json, subprocess, sys, warnings def indent(lines, indent): result = '' @@ -76,38 +76,21 @@ licensed under third-party open-source licenses: """ -rstEntryFormat = """{} +def rstHeadline(title): + return '{}\n{}\n'.format(title, '-' * len(title)) -{} +def rstUrl(title, url): + return '`{} <{}>`_'.format(title, url) -{} +def rstLiteralBlock(lines): + return '::\n\n' + indent(lines, ' ') + '\n\n' -{} +def rstLiteralBlockFromText(text): + return rstLiteralBlock(text.strip().split('\n')) -`Project Homepage <{}>`_ , upstream version: {} - -:: - -{} - - -""" - -# Extract the license which is embedded in triple quotes -def extractLicense(fileName): - result = [] +def readFile(fileName): with open(fileName, 'r') as file: - recording = False - for line in file.readlines(): - line = line.strip("\n\r\xc2\xb6") - if line == '"""': - if recording: - break - else: - recording = True - elif recording: - result.append(line) - return result + return file.readlines() def runScanner(directory, targetFileName): # qtattributionsscanner recursively searches for qt_attribution.json files @@ -120,17 +103,25 @@ def runScanner(directory, targetFileName): with open(targetFileName, 'w') as targetFile: targetFile.write(rstHeader) for entry in json.loads(jsonS.decode('utf-8')): - name = entry['Name'] - title = "{}\n{}".format(name, '-' * len(name)) - brief = entry['License'] + content = '{}\n{}\n{}\n\n'.format(rstHeadline(entry['Name']), + entry['Description'], entry['QtUsage']) url = entry['Homepage'] version = entry['Version'] - description = entry['Description'] - qtUsage = entry['QtUsage'] - content = extractLicense(entry['LicenseFile']) - rst = rstEntryFormat.format(title, brief, description, qtUsage, - url, version, indent(content, ' ')) - targetFile.write(rst) + if url and version: + content += '{}, upstream version: {}\n\n'.format( + rstUrl('Project Homepage', url), version) + copyright = entry['Copyright'] + if copyright: + content += rstLiteralBlockFromText(copyright) + content += entry['License'] + '\n\n' + licenseFile = entry['LicenseFile'] + if licenseFile: + if os.path.isfile(licenseFile): + content += rstLiteralBlock(readFile(licenseFile)) + else: + warnings.warn('"{}" is not a file'.format(licenseFile), + RuntimeWarning) + targetFile.write(content) if len(sys.argv) < 3: print("Usage: qtattributionsscannertorst [directory] [file]'") diff --git a/sources/pyside2/libpyside/dynamicqmetaobject.cpp b/sources/pyside2/libpyside/dynamicqmetaobject.cpp index 63b52744f..5b426ae8e 100644 --- a/sources/pyside2/libpyside/dynamicqmetaobject.cpp +++ b/sources/pyside2/libpyside/dynamicqmetaobject.cpp @@ -388,7 +388,7 @@ DynamicQMetaObject::DynamicQMetaObject(PyTypeObject* type, const QMetaObject* ba d.relatedMetaObjects = NULL; d.static_metacall = NULL; - m_d->m_className = QByteArray(type->tp_name).split('.').last(); + m_d->m_className = QByteArray(PepType(type)->tp_name).split('.').last(); m_d->m_methodOffset = base->methodCount() - 1; m_d->m_propertyOffset = base->propertyCount() - 1; parsePythonType(type); @@ -591,14 +591,14 @@ void DynamicQMetaObject::parsePythonType(PyTypeObject *type) // This enforces registering of all signals and slots at type parsing time, and not later at // signal connection time, thus making sure no method indices change which would break // existing connections. - const PyObject *mro = type->tp_mro; + const PyObject *mro = PepType(type)->tp_mro; const Py_ssize_t basesCount = PyTuple_GET_SIZE(mro); PyTypeObject *qObjectType = Shiboken::Conversions::getPythonTypeObject("QObject*"); QVector<PyTypeObject *> basesToCheck; for (Py_ssize_t i = 0; i < basesCount; ++i) { PyTypeObject *baseType = reinterpret_cast<PyTypeObject *>(PyTuple_GET_ITEM(mro, i)); if (PyType_IsSubtype(baseType, qObjectType) - || baseType == reinterpret_cast<PyTypeObject *>(&SbkObject_Type) + || baseType == reinterpret_cast<PyTypeObject *>(SbkObject_TypeF()) || baseType == reinterpret_cast<PyTypeObject *>(&PyBaseObject_Type)) { continue; } else { @@ -611,7 +611,7 @@ void DynamicQMetaObject::parsePythonType(PyTypeObject *type) // PYSIDE-315: Handle all signals first, in all involved types. for (int baseIndex = 0, baseEnd = basesToCheck.size(); baseIndex < baseEnd; ++baseIndex) { PyTypeObject *baseType = basesToCheck[baseIndex]; - PyObject *attrs = baseType->tp_dict; + PyObject *attrs = PepType(baseType)->tp_dict; PyObject *key = 0; PyObject *value = 0; Py_ssize_t pos = 0; @@ -643,7 +643,7 @@ void DynamicQMetaObject::parsePythonType(PyTypeObject *type) // We check for this using "is_sorted()". Sorting no longer happens at all. for (int baseIndex = 0, baseEnd = basesToCheck.size(); baseIndex < baseEnd; ++baseIndex) { PyTypeObject *baseType = basesToCheck[baseIndex]; - PyObject *attrs = baseType->tp_dict; + PyObject *attrs = PepType(baseType)->tp_dict; PyObject *key = 0; PyObject *value = 0; Py_ssize_t pos = 0; diff --git a/sources/pyside2/libpyside/globalreceiverv2.h b/sources/pyside2/libpyside/globalreceiverv2.h index af860fe1d..880719d6f 100644 --- a/sources/pyside2/libpyside/globalreceiverv2.h +++ b/sources/pyside2/libpyside/globalreceiverv2.h @@ -140,7 +140,6 @@ private: DynamicQMetaObject m_metaObject; DynamicSlotDataV2 *m_data; QList<const QObject*> m_refs; - int m_ref; SharedMap m_sharedMap; }; diff --git a/sources/pyside2/libpyside/pyside.cpp b/sources/pyside2/libpyside/pyside.cpp index 6bdaf65f2..15be38760 100644 --- a/sources/pyside2/libpyside/pyside.cpp +++ b/sources/pyside2/libpyside/pyside.cpp @@ -265,7 +265,7 @@ PyObject* getMetaDataFromQObject(QObject* cppSelf, PyObject* self, PyObject* nam } //mutate native signals to signal instance type - if (attr && PyObject_TypeCheck(attr, &PySideSignalType)) { + if (attr && PyObject_TypeCheck(attr, PySideSignalTypeF())) { PyObject* signal = reinterpret_cast<PyObject*>(Signal::initialize(reinterpret_cast<PySideSignal*>(attr), name, self)); PyObject_SetAttr(self, name, reinterpret_cast<PyObject*>(signal)); return signal; @@ -309,10 +309,10 @@ PyObject* getMetaDataFromQObject(QObject* cppSelf, PyObject* self, PyObject* nam bool inherits(PyTypeObject* objType, const char* class_name) { - if (strcmp(objType->tp_name, class_name) == 0) + if (strcmp(PepType(objType)->tp_name, class_name) == 0) return true; - PyTypeObject* base = (objType)->tp_base; + PyTypeObject* base = PepType(objType)->tp_base; if (base == 0) return false; @@ -400,7 +400,7 @@ QString pyStringToQString(PyObject *str) { #ifdef IS_PY3K if (PyUnicode_Check(str)) { - const char *unicodeBuffer = _PyUnicode_AsString(str); + const char *unicodeBuffer = _PepUnicode_AsString(str); if (unicodeBuffer) return QString::fromUtf8(unicodeBuffer); } diff --git a/sources/pyside2/libpyside/pysideclassinfo.cpp b/sources/pyside2/libpyside/pysideclassinfo.cpp index c5e0b5484..5e0ffed39 100644 --- a/sources/pyside2/libpyside/pysideclassinfo.cpp +++ b/sources/pyside2/libpyside/pysideclassinfo.cpp @@ -55,55 +55,30 @@ static int classInfoTpInit(PyObject*, PyObject*, PyObject*); static void classInfoFree(void*); static PyObject* classCall(PyObject*, PyObject*, PyObject*); -PyTypeObject PySideClassInfoType = { - PyVarObject_HEAD_INIT(0, 0) - "PySide2.QtCore." CLASSINFO_CLASS_NAME, /*tp_name*/ - sizeof(PySideClassInfo), /*tp_basicsize*/ - 0, /*tp_itemsize*/ - 0, /*tp_dealloc*/ - 0, /*tp_print*/ - 0, /*tp_getattr*/ - 0, /*tp_setattr*/ - 0, /*tp_compare*/ - 0, /*tp_repr*/ - 0, /*tp_as_number*/ - 0, /*tp_as_sequence*/ - 0, /*tp_as_mapping*/ - 0, /*tp_hash */ - classCall, /*tp_call*/ - 0, /*tp_str*/ - 0, /*tp_getattro*/ - 0, /*tp_setattro*/ - 0, /*tp_as_buffer*/ - Py_TPFLAGS_DEFAULT, /*tp_flags*/ - 0, /*tp_doc */ - 0, /*tp_traverse */ - 0, /*tp_clear */ - 0, /*tp_richcompare */ - 0, /*tp_weaklistoffset */ - 0, /*tp_iter */ - 0, /*tp_iternext */ - 0, /*tp_methods */ - 0, /*tp_members */ - 0, /*tp_getset */ - 0, /*tp_base */ - 0, /*tp_dict */ - 0, /*tp_descr_get */ - 0, /*tp_descr_set */ - 0, /*tp_dictoffset */ - classInfoTpInit, /*tp_init */ - 0, /*tp_alloc */ - classInfoTpNew, /*tp_new */ - classInfoFree, /*tp_free */ - 0, /*tp_is_gc */ - 0, /*tp_bases */ - 0, /*tp_mro */ - 0, /*tp_cache */ - 0, /*tp_subclasses */ - 0, /*tp_weaklist */ - 0, /*tp_del */ - 0, /*tp_version_tag */ +static PyType_Slot PySideClassInfoType_slots[] = { + {Py_tp_call, (void *)classCall}, + {Py_tp_init, (void *)classInfoTpInit}, + {Py_tp_new, (void *)classInfoTpNew}, + {Py_tp_free, (void *)classInfoFree}, + {Py_tp_dealloc, (void *)SbkDummyDealloc}, + {0, 0} }; +static PyType_Spec PySideClassInfoType_spec = { + "PySide2.QtCore." CLASSINFO_CLASS_NAME, + sizeof(PySideClassInfo), + 0, + Py_TPFLAGS_DEFAULT, + PySideClassInfoType_slots, +}; + + +PyTypeObject *PySideClassInfoTypeF(void) +{ + static PyTypeObject *type = nullptr; + if (!type) + type = (PyTypeObject *)PyType_FromSpec(&PySideClassInfoType_spec); + return type; +} PyObject *classCall(PyObject *self, PyObject *args, PyObject * /* kw */) { @@ -152,7 +127,7 @@ PyObject *classCall(PyObject *self, PyObject *args, PyObject * /* kw */) static PyObject *classInfoTpNew(PyTypeObject *subtype, PyObject * /* args */, PyObject * /* kwds */) { - PySideClassInfo* me = reinterpret_cast<PySideClassInfo*>(subtype->tp_alloc(subtype, 0)); + PySideClassInfo* me = reinterpret_cast<PySideClassInfo*>(PepType(subtype)->tp_alloc(subtype, 0)); me->d = new PySideClassInfoPrivate; me->d->m_alreadyWrapped = false; @@ -195,7 +170,7 @@ void classInfoFree(void *self) PySideClassInfo* data = reinterpret_cast<PySideClassInfo*>(self); delete data->d; - pySelf->ob_type->tp_base->tp_free(self); + PepType(PepType(Py_TYPE(pySelf))->tp_base)->tp_free(self); } @@ -206,17 +181,17 @@ namespace PySide { namespace ClassInfo { void init(PyObject* module) { - if (PyType_Ready(&PySideClassInfoType) < 0) + if (PyType_Ready(PySideClassInfoTypeF()) < 0) return; - Py_INCREF(&PySideClassInfoType); - PyModule_AddObject(module, CLASSINFO_CLASS_NAME, reinterpret_cast<PyObject *>(&PySideClassInfoType)); + Py_INCREF(PySideClassInfoTypeF()); + PyModule_AddObject(module, CLASSINFO_CLASS_NAME, reinterpret_cast<PyObject *>(PySideClassInfoTypeF())); } bool checkType(PyObject* pyObj) { if (pyObj) - return PyType_IsSubtype(pyObj->ob_type, &PySideClassInfoType); + return PyType_IsSubtype(Py_TYPE(pyObj), PySideClassInfoTypeF()); return false; } diff --git a/sources/pyside2/libpyside/pysideclassinfo.h b/sources/pyside2/libpyside/pysideclassinfo.h index 91e014715..910dd9f82 100644 --- a/sources/pyside2/libpyside/pysideclassinfo.h +++ b/sources/pyside2/libpyside/pysideclassinfo.h @@ -47,7 +47,7 @@ extern "C" { - extern PYSIDE_API PyTypeObject PySideClassInfoType; + extern PYSIDE_API PyTypeObject *PySideClassInfoTypeF(void); struct PySideClassInfoPrivate; struct PYSIDE_API PySideClassInfo diff --git a/sources/pyside2/libpyside/pysidemetafunction.cpp b/sources/pyside2/libpyside/pysidemetafunction.cpp index a0f4b0561..9839a1098 100644 --- a/sources/pyside2/libpyside/pysidemetafunction.cpp +++ b/sources/pyside2/libpyside/pysidemetafunction.cpp @@ -58,55 +58,29 @@ struct PySideMetaFunctionPrivate static void functionFree(void*); static PyObject* functionCall(PyObject*, PyObject*, PyObject*); -PyTypeObject PySideMetaFunctionType = { - PyVarObject_HEAD_INIT(0, 0) - /*tp_name*/ "PySide.MetaFunction", - /*tp_basicsize*/ sizeof(PySideMetaFunction), - /*tp_itemsize*/ 0, - /*tp_dealloc*/ 0, - /*tp_print*/ 0, - /*tp_getattr*/ 0, - /*tp_setattr*/ 0, - /*tp_compare*/ 0, - /*tp_repr*/ 0, - /*tp_as_number*/ 0, - /*tp_as_sequence*/ 0, - /*tp_as_mapping*/ 0, - /*tp_hash*/ 0, - /*tp_call*/ functionCall, - /*tp_str*/ 0, - /*tp_getattro*/ 0, - /*tp_setattro*/ 0, - /*tp_as_buffer*/ 0, - /*tp_flags*/ Py_TPFLAGS_DEFAULT, - /*tp_doc*/ "MetaFunction", - /*tp_traverse*/ 0, - /*tp_clear*/ 0, - /*tp_richcompare*/ 0, - /*tp_weaklistoffset*/ 0, - /*tp_iter*/ 0, - /*tp_iternext*/ 0, - /*tp_methods*/ 0, - /*tp_members*/ 0, - /*tp_getset*/ 0, - /*tp_base*/ 0, - /*tp_dict*/ 0, - /*tp_descr_get*/ 0, - /*tp_descr_set*/ 0, - /*tp_dictoffset*/ 0, - /*tp_init*/ 0, - /*tp_alloc*/ 0, - /*tp_new*/ PyType_GenericNew, - /*tp_free*/ functionFree, - /*tp_is_gc*/ 0, - /*tp_bases*/ 0, - /*tp_mro*/ 0, - /*tp_cache*/ 0, - /*tp_subclasses*/ 0, - /*tp_weaklist*/ 0, - /*tp_del*/ 0, - /*tp_version_tag*/ 0 +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 *)SbkDummyDealloc}, + {0, 0} }; +static PyType_Spec PySideMetaFunctionType_spec = { + "PySide.MetaFunction", + sizeof(PySideMetaFunction), + 0, + Py_TPFLAGS_DEFAULT, + PySideMetaFunctionType_slots, +}; + + +PyTypeObject *PySideMetaFunctionTypeF(void) +{ + static PyTypeObject *type = nullptr; + if (!type) + type = (PyTypeObject *)PyType_FromSpec(&PySideMetaFunctionType_spec); + return type; +} void functionFree(void *self) { @@ -130,10 +104,10 @@ namespace PySide { namespace MetaFunction { void init(PyObject* module) { - if (PyType_Ready(&PySideMetaFunctionType) < 0) + if (PyType_Ready(PySideMetaFunctionTypeF()) < 0) return; - PyModule_AddObject(module, "MetaFunction", reinterpret_cast<PyObject *>(&PySideMetaFunctionType)); + PyModule_AddObject(module, "MetaFunction", reinterpret_cast<PyObject *>(PySideMetaFunctionTypeF())); } PySideMetaFunction* newObject(QObject* source, int methodIndex) @@ -144,7 +118,7 @@ PySideMetaFunction* newObject(QObject* source, int methodIndex) QMetaMethod method = source->metaObject()->method(methodIndex); if ((method.methodType() == QMetaMethod::Slot) || (method.methodType() == QMetaMethod::Method)) { - PySideMetaFunction* function = PyObject_New(PySideMetaFunction, &PySideMetaFunctionType); + PySideMetaFunction* function = PyObject_New(PySideMetaFunction, PySideMetaFunctionTypeF()); function->d = new PySideMetaFunctionPrivate(); function->d->qobject = source; function->d->methodIndex = methodIndex; diff --git a/sources/pyside2/libpyside/pysidemetafunction.h b/sources/pyside2/libpyside/pysidemetafunction.h index 9a4072dec..020f02d49 100644 --- a/sources/pyside2/libpyside/pysidemetafunction.h +++ b/sources/pyside2/libpyside/pysidemetafunction.h @@ -49,7 +49,7 @@ extern "C" { - extern PYSIDE_API PyTypeObject PySideMetaFunctionType; + extern PYSIDE_API PyTypeObject *PySideMetaFunctionTypeF(void); struct PySideMetaFunctionPrivate; struct PYSIDE_API PySideMetaFunction diff --git a/sources/pyside2/libpyside/pysideproperty.cpp b/sources/pyside2/libpyside/pysideproperty.cpp index de85686ce..ccec8a2cb 100644 --- a/sources/pyside2/libpyside/pysideproperty.cpp +++ b/sources/pyside2/libpyside/pysideproperty.cpp @@ -72,55 +72,33 @@ static PyMethodDef PySidePropertyMethods[] = { {0, 0, 0, 0} }; -PyTypeObject PySidePropertyType = { - PyVarObject_HEAD_INIT(0, 0) - QPROPERTY_CLASS_NAME, /*tp_name*/ - sizeof(PySideProperty), /*tp_basicsize*/ - 0, /*tp_itemsize*/ - qpropertyDeAlloc, /*tp_dealloc*/ - 0, /*tp_print*/ - 0, /*tp_getattr*/ - 0, /*tp_setattr*/ - 0, /*tp_compare*/ - 0, /*tp_repr*/ - 0, /*tp_as_number*/ - 0, /*tp_as_sequence*/ - 0, /*tp_as_mapping*/ - 0, /*tp_hash */ - qPropertyCall, /*tp_call*/ - 0, /*tp_str*/ - 0, /*tp_getattro*/ - 0, /*tp_setattro*/ - 0, /*tp_as_buffer*/ - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /*tp_flags*/ - 0, /*tp_doc */ - qpropertyTraverse, /*tp_traverse */ - qpropertyClear, /*tp_clear */ - 0, /*tp_richcompare */ - 0, /*tp_weaklistoffset */ - 0, /*tp_iter */ - 0, /*tp_iternext */ - PySidePropertyMethods, /*tp_methods */ - 0, /*tp_members */ - 0, /*tp_getset */ - 0, /*tp_base */ - 0, /*tp_dict */ - 0, /*tp_descr_get */ - 0, /*tp_descr_set */ - 0, /*tp_dictoffset */ - qpropertyTpInit, /*tp_init */ - 0, /*tp_alloc */ - qpropertyTpNew, /*tp_new */ - 0, /*tp_free */ - 0, /*tp_is_gc */ - 0, /*tp_bases */ - 0, /*tp_mro */ - 0, /*tp_cache */ - 0, /*tp_subclasses */ - 0, /*tp_weaklist */ - 0, /*tp_del */ - 0 /*tp_version_tag */ +static PyType_Slot PySidePropertyType_slots[] = { + {Py_tp_dealloc, (void *)qpropertyDeAlloc}, + {Py_tp_call, (void *)qPropertyCall}, + {Py_tp_traverse, (void *)qpropertyTraverse}, + {Py_tp_clear, (void *)qpropertyClear}, + {Py_tp_methods, (void *)PySidePropertyMethods}, + {Py_tp_init, (void *)qpropertyTpInit}, + {Py_tp_new, (void *)qpropertyTpNew}, + {0, 0} }; +// Dotted modulename is crucial for PyType_FromSpec to work. Is this name right? +static PyType_Spec PySidePropertyType_spec = { + "PySide2.QtCore." QPROPERTY_CLASS_NAME, + sizeof(PySideProperty), + 0, + Py_TPFLAGS_DEFAULT|Py_TPFLAGS_HAVE_GC|Py_TPFLAGS_BASETYPE, + PySidePropertyType_slots, +}; + + +PyTypeObject *PySidePropertyTypeF(void) +{ + static PyTypeObject *type = nullptr; + if (!type) + type = (PyTypeObject *)PyType_FromSpec(&PySidePropertyType_spec); + return type; +} static void qpropertyMetaCall(PySideProperty* pp, PyObject* self, QMetaObject::Call call, void** args) { @@ -174,7 +152,7 @@ static void qpropertyMetaCall(PySideProperty* pp, PyObject* self, QMetaObject::C static PyObject *qpropertyTpNew(PyTypeObject *subtype, PyObject * /* args */, PyObject * /* kwds */) { - PySideProperty* me = reinterpret_cast<PySideProperty*>(subtype->tp_alloc(subtype, 0)); + PySideProperty* me = reinterpret_cast<PySideProperty*>(PepType(subtype)->tp_alloc(subtype, 0)); me->d = new PySidePropertyPrivate; memset(me->d, 0, sizeof(PySidePropertyPrivate)); PySidePropertyPrivate* pData = me->d; @@ -232,7 +210,7 @@ int qpropertyTpInit(PyObject* self, PyObject* args, PyObject* kwds) void qpropertyDeAlloc(PyObject* self) { qpropertyClear(self); - Py_TYPE(self)->tp_free(self); + PepType(Py_TYPE(self))->tp_free(self); } PyObject *qPropertyCall(PyObject *self, PyObject *args, PyObject * /* kw */) @@ -329,9 +307,9 @@ namespace { static PyObject* getFromType(PyTypeObject* type, PyObject* name) { PyObject* attr = 0; - attr = PyDict_GetItem(type->tp_dict, name); + attr = PyDict_GetItem(PepType(type)->tp_dict, name); if (!attr) { - PyObject* bases = type->tp_bases; + PyObject* bases = PepType(type)->tp_bases; int size = PyTuple_GET_SIZE(bases); for(int i=0; i < size; i++) { PyObject* base = PyTuple_GET_ITEM(bases, i); @@ -350,17 +328,17 @@ namespace PySide { namespace Property { void init(PyObject* module) { - if (PyType_Ready(&PySidePropertyType) < 0) + if (PyType_Ready(PySidePropertyTypeF()) < 0) return; - Py_INCREF(&PySidePropertyType); - PyModule_AddObject(module, QPROPERTY_CLASS_NAME, reinterpret_cast<PyObject *>(&PySidePropertyType)); + Py_INCREF(PySidePropertyTypeF()); + PyModule_AddObject(module, QPROPERTY_CLASS_NAME, reinterpret_cast<PyObject *>(PySidePropertyTypeF())); } bool checkType(PyObject* pyObj) { if (pyObj) { - return PyType_IsSubtype(pyObj->ob_type, &PySidePropertyType); + return PyType_IsSubtype(Py_TYPE(pyObj), PySidePropertyTypeF()); } return false; } @@ -427,7 +405,7 @@ PySideProperty* getObject(PyObject* source, PyObject* name) attr = PyDict_GetItem(dict, name); } - attr = getFromType(source->ob_type, name); + attr = getFromType(Py_TYPE(source), name); if (attr && checkType(attr)) { Py_INCREF(attr); return reinterpret_cast<PySideProperty*>(attr); diff --git a/sources/pyside2/libpyside/pysideproperty.h b/sources/pyside2/libpyside/pysideproperty.h index d8cafc6c2..d77416abe 100644 --- a/sources/pyside2/libpyside/pysideproperty.h +++ b/sources/pyside2/libpyside/pysideproperty.h @@ -46,7 +46,7 @@ extern "C" { - extern PYSIDE_API PyTypeObject PySidePropertyType; + extern PYSIDE_API PyTypeObject *PySidePropertyTypeF(void); struct PySidePropertyPrivate; struct PYSIDE_API PySideProperty diff --git a/sources/pyside2/libpyside/pysideqflags.cpp b/sources/pyside2/libpyside/pysideqflags.cpp index d38069850..11db70bb5 100644 --- a/sources/pyside2/libpyside/pysideqflags.cpp +++ b/sources/pyside2/libpyside/pysideqflags.cpp @@ -44,14 +44,17 @@ extern "C" { struct SbkConverter; + struct PySideQFlagsTypePrivate + { + SbkConverter** converterPtr; + SbkConverter* converter; + }; /** * Type of all QFlags */ struct PySideQFlagsType { - PyHeapTypeObject super; - SbkConverter** converterPtr; - SbkConverter* converter; + PepTypeObject type; }; #define PYSIDE_QFLAGS(X) reinterpret_cast<PySideQFlagsObject*>(X) @@ -131,20 +134,61 @@ namespace PySide { namespace QFlags { - PyTypeObject* create(const char* name, PyNumberMethods* numberMethods) + static PyType_Slot SbkNewQFlagsType_slots[] = { +#ifdef IS_PY3K + {Py_nb_bool, 0}, +#else + {Py_nb_nonzero, 0}, + {Py_nb_long, 0}, +#endif + {Py_nb_invert, 0}, + {Py_nb_and, 0}, + {Py_nb_xor, 0}, + {Py_nb_or, 0}, + {Py_nb_int, 0}, +#ifndef IS_PY3K + {Py_nb_long, 0}, +#endif + {Py_tp_new, (void *)PySideQFlagsNew}, + {Py_tp_richcompare, (void *)PySideQFlagsRichCompare}, + {Py_tp_dealloc, (void *)SbkDummyDealloc}, + {0, 0} + }; + static PyType_Spec SbkNewQFlagsType_spec = { + "missing QFlags name", // to be inserted later + sizeof(PySideQFlagsObject), + 0, + Py_TPFLAGS_DEFAULT|Py_TPFLAGS_CHECKTYPES, + SbkNewQFlagsType_slots, + }; + + PyTypeObject *create(const char* name, PyType_Slot numberMethods[]) { - PyTypeObject* type = reinterpret_cast<PyTypeObject*>(new PySideQFlagsType); - ::memset(type, 0, sizeof(PySideQFlagsType)); + char qualname[200]; + strcpy(qualname, "PySide2.libpyside."); + strcat(qualname, name); + // Careful: PyType_FromSpec does not allocate the string. + PyType_Spec *newspec = new PyType_Spec; + newspec->name = strdup(qualname); + newspec->basicsize = SbkNewQFlagsType_spec.basicsize; + newspec->itemsize = SbkNewQFlagsType_spec.itemsize; + newspec->flags = SbkNewQFlagsType_spec.flags; + int idx = -1; +#ifdef IS_PY3K +# define SLOT slot +#else +# define SLOT slot_ +#endif + while (numberMethods[++idx].SLOT) { + assert(SbkNewQFlagsType_slots[idx].SLOT == numberMethods[idx].SLOT); + SbkNewQFlagsType_slots[idx].pfunc = numberMethods[idx].pfunc; + } + newspec->slots = SbkNewQFlagsType_spec.slots; + PyTypeObject *type = (PyTypeObject *)PyType_FromSpec(newspec); Py_TYPE(type) = &PyType_Type; - type->tp_basicsize = sizeof(PySideQFlagsObject); - type->tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_CHECKTYPES; - type->tp_name = name; - type->tp_new = &PySideQFlagsNew; - type->tp_as_number = numberMethods; - type->tp_richcompare = &PySideQFlagsRichCompare; PySideQFlagsType* flagsType = reinterpret_cast<PySideQFlagsType*>(type); - flagsType->converterPtr = &flagsType->converter; + PepType_PFTP(flagsType)->converterPtr = &PepType_PFTP(flagsType)->converter; if (PyType_Ready(type) < 0) return 0; diff --git a/sources/pyside2/libpyside/pysideqflags.h b/sources/pyside2/libpyside/pysideqflags.h index e0598798d..71f30808d 100644 --- a/sources/pyside2/libpyside/pysideqflags.h +++ b/sources/pyside2/libpyside/pysideqflags.h @@ -63,7 +63,7 @@ namespace QFlags /** * Creates a new QFlags type. */ - PYSIDE_API PyTypeObject* create(const char* name, PyNumberMethods* numberMethods); + PYSIDE_API PyTypeObject *create(const char* name, PyType_Slot *numberMethods); /** * Creates a new QFlags instance of type \p type and value \p value. */ diff --git a/sources/pyside2/libpyside/pysidesignal.cpp b/sources/pyside2/libpyside/pysidesignal.cpp index 76ef65b5e..483e9e050 100644 --- a/sources/pyside2/libpyside/pysidesignal.cpp +++ b/sources/pyside2/libpyside/pysidesignal.cpp @@ -93,117 +93,73 @@ static PyObject* signalCall(PyObject*, PyObject*, PyObject*); static PyObject* metaSignalCheck(PyObject*, PyObject*); -static PyMappingMethods Signal_as_mapping = { - 0, - signalGetItem, - 0 -}; static PyMethodDef Signal_methods[] = { {"__instancecheck__", (PyCFunction)metaSignalCheck, METH_O, NULL}, {0, 0, 0, 0} }; -PyTypeObject PySideSignalMetaType = { - PyVarObject_HEAD_INIT(0, 0) - /*tp_name*/ "PySide2.QtCore.MetaSignal", - /*tp_basicsize*/ sizeof(PyTypeObject), - /*tp_itemsize*/ 0, - /*tp_dealloc*/ 0, - /*tp_print*/ 0, - /*tp_getattr*/ 0, - /*tp_setattr*/ 0, - /*tp_compare*/ 0, - /*tp_repr*/ 0, - /*tp_as_number*/ 0, - /*tp_as_sequence*/ 0, - /*tp_as_mapping*/ 0, - /*tp_hash*/ 0, - /*tp_call*/ 0, - /*tp_str*/ 0, - /*tp_getattro*/ 0, - /*tp_setattro*/ 0, - /*tp_as_buffer*/ 0, - /*tp_flags*/ Py_TPFLAGS_DEFAULT, - /*tp_doc*/ 0, - /*tp_traverse*/ 0, - /*tp_clear*/ 0, - /*tp_richcompare*/ 0, - /*tp_weaklistoffset*/ 0, - /*tp_iter*/ 0, - /*tp_iternext*/ 0, - /*tp_methods*/ Signal_methods, - /*tp_members*/ 0, - /*tp_getset*/ 0, - /*tp_base*/ &PyType_Type, - /*tp_dict*/ 0, - /*tp_descr_get*/ 0, - /*tp_descr_set*/ 0, - /*tp_dictoffset*/ 0, - /*tp_init*/ 0, - /*tp_alloc*/ 0, - /*tp_new*/ 0, - /*tp_free*/ 0, - /*tp_is_gc*/ 0, - /*tp_bases*/ 0, - /*tp_mro*/ 0, - /*tp_cache*/ 0, - /*tp_subclasses*/ 0, - /*tp_weaklist*/ 0, - /*tp_del*/ 0, - /*tp_version_tag*/ 0 +static PyType_Slot PySideSignalMetaType_slots[] = { + {Py_tp_methods, (void *)Signal_methods}, + {Py_tp_base, (void *)&PyType_Type}, + {Py_tp_free, (void *)PyObject_GC_Del}, + {Py_tp_dealloc, (void *)SbkDummyDealloc}, + {0, 0} +}; +static PyType_Spec PySideSignalMetaType_spec = { + "PySide2.QtCore.MetaSignal", + 0, + // sizeof(PyHeapTypeObject) is filled in by PyType_FromSpecWithBases + // which calls PyType_Ready which calls inherit_special. + 0, + Py_TPFLAGS_DEFAULT, + PySideSignalMetaType_slots, }; -PyTypeObject PySideSignalType = { - PyVarObject_HEAD_INIT(&PySideSignalMetaType, 0) - /*tp_name*/ "PySide2.QtCore." SIGNAL_CLASS_NAME, - /*tp_basicsize*/ sizeof(PySideSignal), - /*tp_itemsize*/ 0, - /*tp_dealloc*/ 0, - /*tp_print*/ 0, - /*tp_getattr*/ 0, - /*tp_setattr*/ 0, - /*tp_compare*/ 0, - /*tp_repr*/ 0, - /*tp_as_number*/ 0, - /*tp_as_sequence*/ 0, - /*tp_as_mapping*/ &Signal_as_mapping, - /*tp_hash*/ 0, - /*tp_call*/ signalCall, - /*tp_str*/ signalToString, - /*tp_getattro*/ 0, - /*tp_setattro*/ 0, - /*tp_as_buffer*/ 0, - /*tp_flags*/ Py_TPFLAGS_DEFAULT, - /*tp_doc*/ SIGNAL_CLASS_NAME, - /*tp_traverse*/ 0, - /*tp_clear*/ 0, - /*tp_richcompare*/ 0, - /*tp_weaklistoffset*/ 0, - /*tp_iter*/ 0, - /*tp_iternext*/ 0, - /*tp_methods*/ 0, - /*tp_members*/ 0, - /*tp_getset*/ 0, - /*tp_base*/ 0, - /*tp_dict*/ 0, - /*tp_descr_get*/ 0, - /*tp_descr_set*/ 0, - /*tp_dictoffset*/ 0, - /*tp_init*/ signalTpInit, - /*tp_alloc*/ 0, - /*tp_new*/ PyType_GenericNew, - /*tp_free*/ signalFree, - /*tp_is_gc*/ 0, - /*tp_bases*/ 0, - /*tp_mro*/ 0, - /*tp_cache*/ 0, - /*tp_subclasses*/ 0, - /*tp_weaklist*/ 0, - /*tp_del*/ 0, - /*tp_version_tag*/ 0 + +PyTypeObject *PySideSignalMetaTypeF(void) +{ + static PyTypeObject *type = nullptr; + if (!type) { + PyObject *bases = Py_BuildValue("(O)", &PyType_Type); + type = (PyTypeObject *)PyType_FromSpecWithBases(&PySideSignalMetaType_spec, bases); + Py_XDECREF(bases); + } + return type; +} + +static PyType_Slot PySideSignalType_slots[] = { + {Py_mp_subscript, (void *)signalGetItem}, + {Py_tp_call, (void *)signalCall}, + {Py_tp_str, (void *)signalToString}, + {Py_tp_init, (void *)signalTpInit}, + {Py_tp_new, (void *)PyType_GenericNew}, + {Py_tp_free, (void *)signalFree}, + {Py_tp_dealloc, (void *)SbkDummyDealloc}, + {0, 0} +}; +static PyType_Spec PySideSignalType_spec = { + "PySide2.QtCore." SIGNAL_CLASS_NAME, + sizeof(PySideSignal), + 0, + Py_TPFLAGS_DEFAULT, + PySideSignalType_slots, }; + +PyTypeObject *PySideSignalTypeF(void) +{ + static PyTypeObject *type = nullptr; + if (!type) { + type = (PyTypeObject *)PyType_FromSpec(&PySideSignalType_spec); + PyTypeObject *hold = Py_TYPE(type); + Py_TYPE(type) = PySideSignalMetaTypeF(); + Py_INCREF(Py_TYPE(type)); + Py_DECREF(hold); + } + return type; +} + static PyMethodDef SignalInstance_methods[] = { {"connect", (PyCFunction)signalInstanceConnect, METH_VARARGS|METH_KEYWORDS, 0}, {"disconnect", signalInstanceDisconnect, METH_VARARGS, 0}, @@ -211,61 +167,31 @@ static PyMethodDef SignalInstance_methods[] = { {0, 0, 0, 0} /* Sentinel */ }; -static PyMappingMethods SignalInstance_as_mapping = { +static PyType_Slot PySideSignalInstanceType_slots[] = { + //{Py_tp_as_mapping, (void *)&SignalInstance_as_mapping}, + {Py_mp_subscript, (void *)signalInstanceGetItem}, + {Py_tp_call, (void *)signalInstanceCall}, + {Py_tp_methods, (void *)SignalInstance_methods}, + {Py_tp_new, (void *)PyType_GenericNew}, + {Py_tp_free, (void *)signalInstanceFree}, + {Py_tp_dealloc, (void *)SbkDummyDealloc}, + {0, 0} +}; +static PyType_Spec PySideSignalInstanceType_spec = { + "PySide2.QtCore." SIGNAL_INSTANCE_NAME, + sizeof(PySideSignalInstance), 0, - signalInstanceGetItem, - 0 + Py_TPFLAGS_DEFAULT, + PySideSignalInstanceType_slots, }; -PyTypeObject PySideSignalInstanceType = { - PyVarObject_HEAD_INIT(0, 0) - /*tp_name*/ "PySide2.QtCore." SIGNAL_INSTANCE_NAME, - /*tp_basicsize*/ sizeof(PySideSignalInstance), - /*tp_itemsize*/ 0, - /*tp_dealloc*/ 0, - /*tp_print*/ 0, - /*tp_getattr*/ 0, - /*tp_setattr*/ 0, - /*tp_compare*/ 0, - /*tp_repr*/ 0, - /*tp_as_number*/ 0, - /*tp_as_sequence*/ 0, - /*tp_as_mapping*/ &SignalInstance_as_mapping, - /*tp_hash*/ 0, - /*tp_call*/ signalInstanceCall, - /*tp_str*/ 0, - /*tp_getattro*/ 0, - /*tp_setattro*/ 0, - /*tp_as_buffer*/ 0, - /*tp_flags*/ Py_TPFLAGS_DEFAULT, - /*tp_doc*/ SIGNAL_INSTANCE_NAME, - /*tp_traverse*/ 0, - /*tp_clear*/ 0, - /*tp_richcompare*/ 0, - /*tp_weaklistoffset*/ 0, - /*tp_iter*/ 0, - /*tp_iternext*/ 0, - /*tp_methods*/ SignalInstance_methods, - /*tp_members*/ 0, - /*tp_getset*/ 0, - /*tp_base*/ 0, - /*tp_dict*/ 0, - /*tp_descr_get*/ 0, - /*tp_descr_set*/ 0, - /*tp_dictoffset*/ 0, - /*tp_init*/ 0, - /*tp_alloc*/ 0, - /*tp_new*/ PyType_GenericNew, - /*tp_free*/ signalInstanceFree, - /*tp_is_gc*/ 0, - /*tp_bases*/ 0, - /*tp_mro*/ 0, - /*tp_cache*/ 0, - /*tp_subclasses*/ 0, - /*tp_weaklist*/ 0, - /*tp_del*/ 0, - /*tp_version_tag*/ 0 -}; + +PyTypeObject *PySideSignalInstanceTypeF(void) +{ + static PyTypeObject *type = + (PyTypeObject *)PyType_FromSpec(&PySideSignalInstanceType_spec); + return type; +} int signalTpInit(PyObject* self, PyObject* args, PyObject* kwds) { @@ -327,7 +253,7 @@ void signalFree(void* self) Py_XDECREF(data->homonymousMethod); data->homonymousMethod = 0; - pySelf->ob_type->tp_base->tp_free(self); + PepType(PepType(Py_TYPE(pySelf))->tp_base)->tp_free(self); } PyObject* signalGetItem(PyObject* self, PyObject* key) @@ -372,7 +298,7 @@ void signalInstanceFree(void* self) } delete dataPvt; data->d = 0; - pySelf->ob_type->tp_base->tp_free(self); + PepType(PepType(Py_TYPE(pySelf))->tp_base)->tp_free(self); } PyObject* signalInstanceConnect(PyObject* self, PyObject* args, PyObject* kwds) @@ -389,7 +315,7 @@ PyObject* signalInstanceConnect(PyObject* self, PyObject* args, PyObject* kwds) Shiboken::AutoDecRef pyArgs(PyList_New(0)); bool match = false; - if (slot->ob_type == &PySideSignalInstanceType) { + if (Py_TYPE(slot) == PySideSignalInstanceTypeF()) { PySideSignalInstance* sourceWalk = source; PySideSignalInstance* targetWalk; @@ -427,9 +353,9 @@ PyObject* signalInstanceConnect(PyObject* self, PyObject* args, PyObject* kwds) PyObject *function = isMethod ? PyMethod_GET_FUNCTION(slot) : slot; PyCodeObject *objCode = reinterpret_cast<PyCodeObject *>(PyFunction_GET_CODE(function)); PyFunctionObject *function_obj = reinterpret_cast<PyFunctionObject *>(function); - functionName = Shiboken::String::toCString(function_obj->func_name); + functionName = Shiboken::String::toCString(PepFunction_GetName(function_obj)); useSelf = isMethod; - slotArgs = objCode->co_flags & CO_VARARGS ? -1 : objCode->co_argcount; + slotArgs = PepCode_GET_FLAGS(objCode) & CO_VARARGS ? -1 : PepCode_GET_ARGCOUNT(objCode); if (useSelf) slotArgs -= 1; @@ -574,7 +500,7 @@ PyObject* signalInstanceDisconnect(PyObject* self, PyObject* args) slot = Py_None; bool match = false; - if (slot->ob_type == &PySideSignalInstanceType) { + if (Py_TYPE(slot) == PySideSignalInstanceTypeF()) { PySideSignalInstance* target = reinterpret_cast<PySideSignalInstance*>(slot); if (QMetaObject::checkConnectArgs(source->d->signature, target->d->signature)) { PyList_Append(pyArgs, source->d->source); @@ -626,7 +552,7 @@ PyObject* signalCall(PyObject* self, PyObject* args, PyObject* kw) return 0; } - descrgetfunc getDescriptor = signal->homonymousMethod->ob_type->tp_descr_get; + descrgetfunc getDescriptor = PepType(Py_TYPE(signal->homonymousMethod))->tp_descr_get; // Check if there exists a method with the same name as the signal, which is also a static // method in C++ land. @@ -637,7 +563,7 @@ PyObject* signalCall(PyObject* self, PyObject* args, PyObject* kw) } // Assumes homonymousMethod is not a static method. - ternaryfunc callFunc = signal->homonymousMethod->ob_type->tp_call; + ternaryfunc callFunc = PepType(Py_TYPE(signal->homonymousMethod))->tp_call; return callFunc(homonymousMethod, args, kw); } @@ -649,14 +575,14 @@ PyObject* signalInstanceCall(PyObject* self, PyObject* args, PyObject* kw) return 0; } - descrgetfunc getDescriptor = PySideSignal->d->homonymousMethod->ob_type->tp_descr_get; + descrgetfunc getDescriptor = PepType(Py_TYPE(PySideSignal->d->homonymousMethod))->tp_descr_get; Shiboken::AutoDecRef homonymousMethod(getDescriptor(PySideSignal->d->homonymousMethod, PySideSignal->d->source, 0)); return PyCFunction_Call(homonymousMethod, args, kw); } static PyObject *metaSignalCheck(PyObject * /* klass */, PyObject* args) { - if (PyType_IsSubtype(args->ob_type, &PySideSignalInstanceType)) + if (PyType_IsSubtype(Py_TYPE(args), PySideSignalInstanceTypeF())) Py_RETURN_TRUE; else Py_RETURN_FALSE; @@ -669,25 +595,25 @@ namespace Signal { void init(PyObject* module) { - if (PyType_Ready(&PySideSignalMetaType) < 0) + if (PyType_Ready(PySideSignalMetaTypeF()) < 0) return; - if (PyType_Ready(&PySideSignalType) < 0) + if (PyType_Ready(PySideSignalTypeF()) < 0) return; - Py_INCREF(&PySideSignalType); - PyModule_AddObject(module, SIGNAL_CLASS_NAME, reinterpret_cast<PyObject *>(&PySideSignalType)); + Py_INCREF(PySideSignalTypeF()); + PyModule_AddObject(module, SIGNAL_CLASS_NAME, reinterpret_cast<PyObject *>(PySideSignalTypeF())); - if (PyType_Ready(&PySideSignalInstanceType) < 0) + if (PyType_Ready(PySideSignalInstanceTypeF()) < 0) return; - Py_INCREF(&PySideSignalInstanceType); + Py_INCREF(PySideSignalInstanceTypeF()); } bool checkType(PyObject* pyObj) { if (pyObj) - return PyType_IsSubtype(pyObj->ob_type, &PySideSignalType); + return PyType_IsSubtype(Py_TYPE(pyObj), PySideSignalTypeF()); return false; } @@ -699,9 +625,9 @@ void updateSourceObject(PyObject* source) PyObject* value; PyObject* key; - while (PyDict_Next(objType->tp_dict, &pos, &key, &value)) { - if (PyObject_TypeCheck(value, &PySideSignalType)) { - Shiboken::AutoDecRef signalInstance(reinterpret_cast<PyObject *>(PyObject_New(PySideSignalInstance, &PySideSignalInstanceType))); + while (PyDict_Next(PepType(objType)->tp_dict, &pos, &key, &value)) { + if (PyObject_TypeCheck(value, PySideSignalTypeF())) { + Shiboken::AutoDecRef signalInstance(reinterpret_cast<PyObject *>(PyObject_New(PySideSignalInstance, PySideSignalInstanceTypeF()))); instanceInitialize(signalInstance.cast<PySideSignalInstance*>(), key, reinterpret_cast<PySideSignal*>(value), source, 0); PyObject_SetAttr(source, key, signalInstance); } @@ -714,7 +640,8 @@ char* getTypeName(PyObject* type) { if (PyType_Check(type)) { char* typeName = NULL; - if (PyType_IsSubtype(reinterpret_cast<PyTypeObject*>(type), reinterpret_cast<PyTypeObject*>(&SbkObject_Type))) { + if (PyType_IsSubtype(reinterpret_cast<PyTypeObject*>(type), + reinterpret_cast<PyTypeObject*>(SbkObject_TypeF()))) { SbkObjectType* objType = reinterpret_cast<SbkObjectType*>(type); typeName = strdup(Shiboken::ObjectType::getOriginalName(objType)); } else { @@ -730,7 +657,7 @@ char* getTypeName(PyObject* type) typeName = strdup("double"); else if (objType == &PyBool_Type) typeName = strdup("bool"); - else if (Py_TYPE(objType) == &SbkEnumType_Type) + else if (Py_TYPE(objType) == SbkEnumType_TypeF()) typeName = strdup(Shiboken::Enum::getCppName(objType)); else typeName = strdup("PyObject"); @@ -763,7 +690,7 @@ char* parseSignature(PyObject* args) return getTypeName(args); for (Py_ssize_t i = 0, i_max = PySequence_Size(args); i < i_max; i++) { - Shiboken::AutoDecRef arg(PySequence_ITEM(args, i)); + Shiboken::AutoDecRef arg(PySequence_GetItem(args, i)); char* typeName = getTypeName(arg); if (typeName) { if (signature) { @@ -796,7 +723,7 @@ void appendSignature(PySideSignal* self, const SignalSignature &signature) PySideSignalInstance* initialize(PySideSignal* self, PyObject* name, PyObject* object) { - PySideSignalInstance* instance = PyObject_New(PySideSignalInstance, &PySideSignalInstanceType); + PySideSignalInstance* instance = PyObject_New(PySideSignalInstance, PySideSignalInstanceTypeF()); SbkObject* sbkObj = reinterpret_cast<SbkObject*>(object); if (!Shiboken::Object::wasCreatedByPython(sbkObj)) Py_INCREF(object); // PYSIDE-79: this flag was crucial for a wrapper call. @@ -827,7 +754,7 @@ void instanceInitialize(PySideSignalInstance* self, PyObject* name, PySideSignal index++; if (index < data->signaturesSize) { - selfPvt->next = PyObject_New(PySideSignalInstance, &PySideSignalInstanceType); + selfPvt->next = PyObject_New(PySideSignalInstance, PySideSignalInstanceTypeF()); instanceInitialize(selfPvt->next, name, data, source, index); } } @@ -854,7 +781,7 @@ PySideSignalInstance* newObjectFromMethod(PyObject* source, const QList<QMetaMet PySideSignalInstance* root = 0; PySideSignalInstance* previous = 0; foreach (const QMetaMethod &m, methodList) { - PySideSignalInstance* item = PyObject_New(PySideSignalInstance, &PySideSignalInstanceType); + PySideSignalInstance* item = PyObject_New(PySideSignalInstance, PySideSignalInstanceTypeF()); if (!root) root = item; @@ -881,7 +808,7 @@ PySideSignal* newObject(const char* name, ...) { va_list listSignatures; char* sig = 0; - PySideSignal* self = PyObject_New(PySideSignal, &PySideSignalType); + PySideSignal* self = PyObject_New(PySideSignal, PySideSignalTypeF()); self->signalName = strdup(name); self->signaturesSize = 0; self->signatures = 0; @@ -928,7 +855,7 @@ static typename T::value_type join(T t, const char* sep) static void _addSignalToWrapper(SbkObjectType* wrapperType, const char* signalName, PySideSignal* signal) { - PyObject* typeDict = wrapperType->super.ht_type.tp_dict; + PyObject* typeDict = PepType(wrapperType)->tp_dict; PyObject* homonymousMethod; if ((homonymousMethod = PyDict_GetItemString(typeDict, signalName))) { Py_INCREF(homonymousMethod); @@ -964,7 +891,7 @@ void registerSignals(SbkObjectType* pyObj, const QMetaObject* metaObject) SignalSigMap::Iterator it = signalsFound.begin(); SignalSigMap::Iterator end = signalsFound.end(); for (; it != end; ++it) { - PySideSignal* self = PyObject_New(PySideSignal, &PySideSignalType); + PySideSignal* self = PyObject_New(PySideSignal, PySideSignalTypeF()); self->signalName = strdup(it.key().constData()); self->signaturesSize = 0; self->signatures = 0; @@ -1047,14 +974,14 @@ QString getCallbackSignature(const char* signal, QObject* receiver, PyObject* ca if (isMethod || isFunction) { PyObject* function = isMethod ? PyMethod_GET_FUNCTION(callback) : callback; PyCodeObject* objCode = reinterpret_cast<PyCodeObject*>(PyFunction_GET_CODE(function)); - functionName = Shiboken::String::toCString(reinterpret_cast<PyFunctionObject*>(function)->func_name); + functionName = Shiboken::String::toCString(PepFunction_GetName(function)); useSelf = isMethod; - numArgs = objCode->co_flags & CO_VARARGS ? -1 : objCode->co_argcount; + numArgs = PepCode_GET_FLAGS(objCode) & CO_VARARGS ? -1 : PepCode_GET_ARGCOUNT(objCode); } else if (PyCFunction_Check(callback)) { const PyCFunctionObject *funcObj = reinterpret_cast<const PyCFunctionObject *>(callback); - functionName = funcObj->m_ml->ml_name; - useSelf = funcObj->m_self; - const int flags = funcObj->m_ml->ml_flags; + functionName = PepCFunction_GET_NAMESTR(funcObj); + useSelf = PyCFunction_GET_SELF(funcObj); + const int flags = PyCFunction_GET_FLAGS(funcObj); if (receiver) { //Search for signature on metaobject diff --git a/sources/pyside2/libpyside/pysidesignal.h b/sources/pyside2/libpyside/pysidesignal.h index f5365098f..abbefbb1a 100644 --- a/sources/pyside2/libpyside/pysidesignal.h +++ b/sources/pyside2/libpyside/pysidesignal.h @@ -50,8 +50,8 @@ extern "C" { - extern PYSIDE_API PyTypeObject PySideSignalType; - extern PYSIDE_API PyTypeObject PySideSignalInstanceType; + extern PYSIDE_API PyTypeObject *PySideSignalTypeF(void); + extern PYSIDE_API PyTypeObject *PySideSignalInstanceTypeF(void); // Internal object struct PYSIDE_API PySideSignal; diff --git a/sources/pyside2/libpyside/pysidesignal_p.h b/sources/pyside2/libpyside/pysidesignal_p.h index e2e28b3dd..24cbde505 100644 --- a/sources/pyside2/libpyside/pysidesignal_p.h +++ b/sources/pyside2/libpyside/pysidesignal_p.h @@ -44,7 +44,7 @@ extern "C" { - extern PyTypeObject PySideSignalType; + extern PyTypeObject *PySideSignalTypeF(void); struct PySideSignal { PyObject_HEAD diff --git a/sources/pyside2/libpyside/pysideslot.cpp b/sources/pyside2/libpyside/pysideslot.cpp index 8f307260d..db1a7d9ed 100644 --- a/sources/pyside2/libpyside/pysideslot.cpp +++ b/sources/pyside2/libpyside/pysideslot.cpp @@ -62,55 +62,29 @@ static int slotTpInit(PyObject*, PyObject*, PyObject*); static PyObject* slotCall(PyObject*, PyObject*, PyObject*); // Class Definition ----------------------------------------------- -static PyTypeObject PySideSlotType = { - PyVarObject_HEAD_INIT(0, 0) - "PySide2.QtCore." SLOT_DEC_NAME, /*tp_name*/ - sizeof(PySideSlot), /*tp_basicsize*/ - 0, /*tp_itemsize*/ - 0, /*tp_dealloc*/ - 0, /*tp_print*/ - 0, /*tp_getattr*/ - 0, /*tp_setattr*/ - 0, /*tp_compare*/ - 0, /*tp_repr*/ - 0, /*tp_as_number*/ - 0, /*tp_as_sequence*/ - 0, /*tp_as_mapping*/ - 0, /*tp_hash */ - slotCall, /*tp_call*/ - 0, /*tp_str*/ - 0, /*tp_getattro*/ - 0, /*tp_setattro*/ - 0, /*tp_as_buffer*/ - Py_TPFLAGS_DEFAULT, /*tp_flags*/ - SLOT_DEC_NAME, /*tp_doc */ - 0, /*tp_traverse */ - 0, /*tp_clear */ - 0, /*tp_richcompare */ - 0, /*tp_weaklistoffset */ - 0, /*tp_iter */ - 0, /*tp_iternext */ - 0, /*tp_methods */ - 0, /*tp_members */ - 0, /*tp_getset */ - 0, /*tp_base */ - 0, /*tp_dict */ - 0, /*tp_descr_get */ - 0, /*tp_descr_set */ - 0, /*tp_dictoffset */ - slotTpInit, /*tp_init */ - 0, /*tp_alloc */ - PyType_GenericNew, /*tp_new */ - 0, /*tp_free */ - 0, /*tp_is_gc */ - 0, /*tp_bases */ - 0, /*tp_mro */ - 0, /*tp_cache */ - 0, /*tp_subclasses */ - 0, /*tp_weaklist */ - 0, /*tp_del */ - 0 /*tp_version_tag*/ +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 *)SbkDummyDealloc}, + {0, 0} }; +static PyType_Spec PySideSlotType_spec = { + "PySide2.QtCore." SLOT_DEC_NAME, + sizeof(PySideSlot), + 0, + Py_TPFLAGS_DEFAULT, + PySideSlotType_slots, +}; + + +static PyTypeObject *PySideSlotTypeF(void) +{ + static PyTypeObject *type = nullptr; + if (!type) + type = (PyTypeObject *)PyType_FromSpec(&PySideSlotType_spec); + return type; +} int slotTpInit(PyObject *self, PyObject *args, PyObject *kw) { @@ -139,7 +113,7 @@ int slotTpInit(PyObject *self, PyObject *args, PyObject *kw) data->args = typeName; } } else { - PyErr_Format(PyExc_TypeError, "Unknown signal argument type: %s", argType->ob_type->tp_name); + PyErr_Format(PyExc_TypeError, "Unknown signal argument type: %s", PepType((Py_TYPE(argType)))->tp_name); return -1; } } @@ -166,7 +140,7 @@ PyObject *slotCall(PyObject *self, PyObject *args, PyObject * /* kw */) PySideSlot *data = reinterpret_cast<PySideSlot*>(self); if (!data->slotName) { - PyObject *funcName = reinterpret_cast<PyFunctionObject*>(callback)->func_name; + PyObject *funcName = PepFunction_GetName(callback); data->slotName = strdup(Shiboken::String::toCString(funcName)); } @@ -209,11 +183,11 @@ namespace PySide { namespace Slot { void init(PyObject* module) { - if (PyType_Ready(&PySideSlotType) < 0) + if (PyType_Ready(PySideSlotTypeF()) < 0) return; - Py_INCREF(&PySideSlotType); - PyModule_AddObject(module, SLOT_DEC_NAME, reinterpret_cast<PyObject *>(&PySideSlotType)); + Py_INCREF(PySideSlotTypeF()); + PyModule_AddObject(module, SLOT_DEC_NAME, reinterpret_cast<PyObject *>(PySideSlotTypeF())); } } // namespace Slot diff --git a/sources/pyside2/libpyside/pysideweakref.cpp b/sources/pyside2/libpyside/pysideweakref.cpp index c31334ee5..906aafd7c 100644 --- a/sources/pyside2/libpyside/pysideweakref.cpp +++ b/sources/pyside2/libpyside/pysideweakref.cpp @@ -40,6 +40,7 @@ #include "pysideweakref.h" #include <sbkpython.h> +#include <shiboken.h> typedef struct { PyObject_HEAD @@ -50,56 +51,27 @@ typedef struct { static PyObject* CallableObject_call(PyObject* callable_object, PyObject* args, PyObject* kw); -static PyTypeObject PySideCallableObjectType = { - PyVarObject_HEAD_INIT(0, 0) +static PyType_Slot PySideCallableObjectType_slots[] = { + {Py_tp_call, (void *)CallableObject_call}, + {Py_tp_dealloc, (void *)SbkDummyDealloc}, + {0, 0} +}; +static PyType_Spec PySideCallableObjectType_spec = { const_cast<char*>("PySide.Callable"), - sizeof(PySideCallableObject), /*tp_basicsize*/ - 0, /*tp_itemsize*/ - 0, /*tp_dealloc*/ - 0, /*tp_print*/ - 0, /*tp_getattr*/ - 0, /*tp_setattr*/ - 0, /*tp_compare*/ - 0, /*tp_repr*/ - 0, /*tp_as_number*/ - 0, /*tp_as_sequence*/ - 0, /*tp_as_mapping*/ - 0, /*tp_hash */ - CallableObject_call, /*tp_call*/ - 0, /*tp_str*/ - 0, /*tp_getattro*/ - 0, /*tp_setattro*/ - 0, /*tp_as_buffer*/ - Py_TPFLAGS_DEFAULT, /*tp_flags*/ - 0, /* tp_doc */ - 0, /* tp_traverse */ - 0, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - 0, /* tp_iter */ - 0, /* tp_iternext */ - 0, /* tp_methods */ - 0, /* tp_members */ - 0, /* tp_getset */ - 0, /* tp_base */ - 0, /* tp_dict */ - 0, /* tp_descr_get */ - 0, /* tp_descr_set */ - 0, /* tp_dictoffset */ - 0, /* tp_init */ - 0, /* tp_alloc */ - 0, /* tp_new */ - 0, /* tp_free */ - 0, /* tp_is_gc */ - 0, /* tp_bases */ - 0, /* tp_mro */ - 0, /* tp_cache */ - 0, /* tp_subclasses */ - 0, /* tp_weaklist */ - 0, /* tp_del */ - 0 /* tp_version_tag */ + sizeof(PySideCallableObject), + 0, + Py_TPFLAGS_DEFAULT, + PySideCallableObjectType_slots, }; + +static PyTypeObject *PySideCallableObjectTypeF(void) +{ + static PyTypeObject *type = + (PyTypeObject *)PyType_FromSpec(&PySideCallableObjectType_spec); + return type; +} + static PyObject *CallableObject_call(PyObject *callable_object, PyObject *args, PyObject * /* kw */) { PySideCallableObject* obj = reinterpret_cast<PySideCallableObject *>(callable_object); @@ -116,13 +88,13 @@ PyObject* create(PyObject* obj, PySideWeakRefFunction func, void* userData) if (obj == Py_None) return 0; - if (Py_TYPE(&PySideCallableObjectType) == 0) + if (Py_TYPE(PySideCallableObjectTypeF()) == 0) { - Py_TYPE(&PySideCallableObjectType) = &PyType_Type; - PyType_Ready(&PySideCallableObjectType); + Py_TYPE(PySideCallableObjectTypeF()) = &PyType_Type; + PyType_Ready(PySideCallableObjectTypeF()); } - PySideCallableObject* callable = PyObject_New(PySideCallableObject, &PySideCallableObjectType); + PySideCallableObject* callable = PyObject_New(PySideCallableObject, PySideCallableObjectTypeF()); if (!callable || PyErr_Occurred()) return 0; diff --git a/sources/pyside2/libpyside/signalmanager.cpp.in b/sources/pyside2/libpyside/signalmanager.cpp.in index 50f436134..c67bc6369 100644 --- a/sources/pyside2/libpyside/signalmanager.cpp.in +++ b/sources/pyside2/libpyside/signalmanager.cpp.in @@ -590,7 +590,7 @@ int SignalManager::registerMetaMethodGetIndex(QObject* source, const char* signa // Create a instance meta object if (!dict || !PyDict_Contains(dict, metaObjectAttr)) { - dmo = new DynamicQMetaObject(pySelf->ob_type, metaObject); + dmo = new DynamicQMetaObject(Py_TYPE(pySelf), metaObject); #ifdef IS_PY3K PyObject* pyDmo = PyCapsule_New(dmo, 0, destroyMetaObject); #else diff --git a/sources/pyside2/libpyside/signalmanager.h b/sources/pyside2/libpyside/signalmanager.h index 4f286745f..5948a7df1 100644 --- a/sources/pyside2/libpyside/signalmanager.h +++ b/sources/pyside2/libpyside/signalmanager.h @@ -61,7 +61,6 @@ public: PyObjectWrapper& operator=(const PyObjectWrapper &other); private: PyObject* m_me; - void* m_data; //future }; PYSIDE_API QDataStream &operator<<(QDataStream& out, const PyObjectWrapper& myObj); diff --git a/sources/pyside2/plugins/customwidget.cpp b/sources/pyside2/plugins/customwidget.cpp index c2ed00bd0..bad05f2d3 100644 --- a/sources/pyside2/plugins/customwidget.cpp +++ b/sources/pyside2/plugins/customwidget.cpp @@ -51,7 +51,7 @@ PyCustomWidget::PyCustomWidget(PyObject* objectType) : m_data(new PyCustomWidgetPrivate()) { m_data->pyObject = objectType; - m_name = QString(reinterpret_cast<PyTypeObject*>(objectType)->tp_name); + m_name = QString(PepType(reinterpret_cast<PyTypeObject*>(objectType))->tp_name); } PyCustomWidget::~PyCustomWidget() diff --git a/sources/pyside2/tests/QtCore/qmimedatabase_test.py b/sources/pyside2/tests/QtCore/qmimedatabase_test.py index e523580ad..1e4e3b574 100644 --- a/sources/pyside2/tests/QtCore/qmimedatabase_test.py +++ b/sources/pyside2/tests/QtCore/qmimedatabase_test.py @@ -52,20 +52,20 @@ class QMimeDatabaseTest(unittest.TestCase): s1 = db.mimeTypeForName("text/plain") self.assertTrue(s1.isValid()) self.assertEqual(s1.name(), "text/plain") - # print("Comment is %s" % s1.comment()) krita = db.mimeTypeForName("application/x-krita") self.assertTrue(krita.isValid()) - # Test <comment> parsing with application/rdf+xml which has the english comment after the other ones rdf = db.mimeTypeForName("application/rdf+xml") self.assertTrue(rdf.isValid()) self.assertEqual(rdf.name(), "application/rdf+xml") - self.assertEqual(rdf.comment(), "RDF file") + if "en" in QLocale().name(): + self.assertEqual(rdf.comment(), "RDF file") bzip2 = db.mimeTypeForName("application/x-bzip2") self.assertTrue(bzip2.isValid()) - self.assertEqual(bzip2.comment(), "Bzip archive") + if "en" in QLocale().name(): + self.assertEqual(bzip2.comment(), "Bzip archive") defaultMime = db.mimeTypeForName("application/octet-stream") self.assertTrue(defaultMime.isValid()) diff --git a/sources/shiboken2/ApiExtractor/abstractmetabuilder.cpp b/sources/shiboken2/ApiExtractor/abstractmetabuilder.cpp index 23feeafad..d76c788ec 100644 --- a/sources/shiboken2/ApiExtractor/abstractmetabuilder.cpp +++ b/sources/shiboken2/ApiExtractor/abstractmetabuilder.cpp @@ -241,9 +241,8 @@ void AbstractMetaBuilderPrivate::checkFunctionModifications() AbstractMetaClass *AbstractMetaBuilderPrivate::argumentToClass(ArgumentModelItem argument) { AbstractMetaClass* returned = 0; - bool ok = false; - AbstractMetaType* type = translateType(argument->type(), &ok); - if (ok && type && type->typeEntry() && type->typeEntry()->isComplex()) { + AbstractMetaType *type = translateType(argument->type()); + if (type && type->typeEntry() && type->typeEntry()->isComplex()) { const TypeEntry *entry = type->typeEntry(); returned = AbstractMetaClass::findClass(m_metaClasses, entry->name()); } @@ -300,9 +299,8 @@ void AbstractMetaBuilderPrivate::traverseOperatorFunction(FunctionModelItem item baseoperandClass = argumentToClass(arguments.at(1)); firstArgumentIsSelf = false; } else { - bool ok; - AbstractMetaType* type = translateType(item->type(), &ok); - const TypeEntry* retType = ok ? type->typeEntry() : 0; + AbstractMetaType *type = translateType(item->type()); + const TypeEntry *retType = type ? type->typeEntry() : nullptr; AbstractMetaClass* otherArgClass = argumentToClass(arguments.at(1)); if (otherArgClass && retType && (retType->isValue() || retType->isObject()) @@ -1238,11 +1236,10 @@ AbstractMetaField *AbstractMetaBuilderPrivate::traverseField(VariableModelItem f metaField->setName(fieldName); metaField->setEnclosingClass(cls); - bool ok; TypeInfo fieldType = field->type(); - AbstractMetaType *metaType = translateType(fieldType, &ok); + AbstractMetaType *metaType = translateType(fieldType); - if (!metaType || !ok) { + if (!metaType) { const QString type = TypeInfo::resolveType(fieldType, currentScope()).qualifiedName().join(colonColon()); if (m_currentClass->typeEntry()->codeGeneration() & TypeEntry::GenerateTargetLang) { qCWarning(lcShiboken).noquote().nospace() @@ -1749,7 +1746,7 @@ AbstractMetaFunction* AbstractMetaBuilderPrivate::traverseFunction(const AddedFu AddedFunction::TypeInfo& typeInfo = args[i]; AbstractMetaArgument *metaArg = new AbstractMetaArgument; AbstractMetaType *type = translateType(typeInfo); - decideUsagePattern(type); + type->decideUsagePattern(); metaArg->setType(type); metaArg->setArgumentIndex(i); metaArg->setDefaultValueExpression(typeInfo.defaultValue); @@ -1963,9 +1960,8 @@ bool AbstractMetaBuilderPrivate::setArrayArgumentType(AbstractMetaFunction *func } TypeInfo elementType = functionItem->arguments().at(i)->type(); elementType.setIndirections(elementType.indirections() - 1); - bool ok; - AbstractMetaType *element = translateType(elementType, &ok); - if (element == nullptr || !ok) { + AbstractMetaType *element = translateType(elementType); + if (element == nullptr) { qCWarning(lcShiboken).noquote() << msgCannotSetArrayUsage(func->minimalSignature(), i, QLatin1String("Cannot translate element type ") + elementType.toString()); @@ -2068,16 +2064,17 @@ AbstractMetaFunction *AbstractMetaBuilderPrivate::traverseFunction(FunctionModel return nullptr; } - bool ok; - AbstractMetaType *type = translateType(returnType, &ok); - if (!ok) { - Q_ASSERT(type == 0); - const QString reason = msgUnmatchedReturnType(functionItem); - qCWarning(lcShiboken, "%s", - qPrintable(msgSkippingFunction(functionItem, originalQualifiedSignatureWithReturn, reason))); - m_rejectedFunctions.insert(originalQualifiedSignatureWithReturn, AbstractMetaBuilder::UnmatchedReturnType); - delete metaFunction; - return nullptr; + AbstractMetaType *type = nullptr; + if (!returnType.isVoid()) { + type = translateType(returnType); + if (!type) { + const QString reason = msgUnmatchedReturnType(functionItem); + qCWarning(lcShiboken, "%s", + qPrintable(msgSkippingFunction(functionItem, originalQualifiedSignatureWithReturn, reason))); + m_rejectedFunctions.insert(originalQualifiedSignatureWithReturn, AbstractMetaBuilder::UnmatchedReturnType); + delete metaFunction; + return nullptr; + } } metaFunction->setType(type); @@ -2105,9 +2102,8 @@ AbstractMetaFunction *AbstractMetaBuilderPrivate::traverseFunction(FunctionModel return nullptr; } - bool ok; - AbstractMetaType* metaType = translateType(arg->type(), &ok); - if (!ok) { + AbstractMetaType *metaType = translateType(arg->type()); + if (!metaType) { // If an invalid argument has a default value, simply remove it if (arg->defaultValue()) { if (!m_currentClass @@ -2316,21 +2312,14 @@ static const TypeEntry* findTypeEntryUsingContext(const AbstractMetaClass* metaC } AbstractMetaType *AbstractMetaBuilderPrivate::translateType(const TypeInfo &_typei, - bool *ok, bool resolveType, - bool resolveScope) + bool resolveType) { - Q_ASSERT(ok); - *ok = true; - // 1. Test the type info without resolving typedefs in case this is present in the // type system TypeInfo typei; if (resolveType) { - bool ok; - AbstractMetaType* t = translateType(_typei, &ok, false, resolveScope); - if (t && ok) - return t; - Q_ASSERT(t == 0); + if (AbstractMetaType *resolved = translateType(_typei, false)) + return resolved; } if (!resolveType) { @@ -2350,17 +2339,14 @@ AbstractMetaType *AbstractMetaBuilderPrivate::translateType(const TypeInfo &_typ } - if (typei.isFunctionPointer()) { - *ok = false; - return 0; - } + if (typei.isFunctionPointer()) + return nullptr; QString errorMessage; TypeParser::Info typeInfo = TypeParser::parse(typei.toString(), &errorMessage); if (typeInfo.is_busted) { qWarning().noquote().nospace() << "Unable to translate type \"" << _typei.toString() << "\": " << errorMessage; - *ok = false; return 0; } @@ -2395,9 +2381,9 @@ AbstractMetaType *AbstractMetaBuilderPrivate::translateType(const TypeInfo &_typ newInfo.setReferenceType(typei.referenceType()); newInfo.setVolatile(typei.isVolatile()); - AbstractMetaType* elementType = translateType(newInfo, ok); - if (!(*ok)) - return 0; + AbstractMetaType *elementType = translateType(newInfo); + if (!elementType) + return nullptr; for (int i = typeInfo.arrays.size() - 1; i >= 0; --i) { AbstractMetaType *arrayType = new AbstractMetaType; @@ -2409,7 +2395,7 @@ AbstractMetaType *AbstractMetaBuilderPrivate::translateType(const TypeInfo &_typ arrayType->setArrayElementCount(int(elems)); } arrayType->setTypeEntry(new ArrayTypeEntry(elementType->typeEntry() , elementType->typeEntry()->version())); - decideUsagePattern(arrayType); + arrayType->decideUsagePattern(); elementType = arrayType; } @@ -2421,17 +2407,12 @@ AbstractMetaType *AbstractMetaBuilderPrivate::translateType(const TypeInfo &_typ if (qualifierList.isEmpty()) { qCWarning(lcShiboken).noquote().nospace() << QStringLiteral("horribly broken type '%1'").arg(_typei.toString()); - *ok = false; - return 0; + return nullptr; } QString qualifiedName = qualifierList.join(colonColon()); QString name = qualifierList.takeLast(); - // 3. Special case 'void' type - if (name == QLatin1String("void") && !typeInfo.indirections) - return 0; - // 4. Special case QFlags (include instantiation in name) if (qualifiedName == QLatin1String("QFlags")) qualifiedName = typeInfo.toString(); @@ -2476,34 +2457,8 @@ AbstractMetaType *AbstractMetaBuilderPrivate::translateType(const TypeInfo &_typ } } - // 9. Try finding the type by prefixing it with the current - // context and all baseclasses of the current context - if (!type && !TypeDatabase::instance()->isClassRejected(qualifiedName) && m_currentClass && resolveScope) { - QStringList contexts; - contexts.append(m_currentClass->qualifiedCppName()); - contexts.append(currentScope()->qualifiedName().join(colonColon())); - - - TypeInfo info = typei; - bool subclassesDone = false; - while (!contexts.isEmpty() && !type) { - type = TypeDatabase::instance()->findType(contexts.at(0) + colonColon() + qualifiedName); - contexts.pop_front(); - - // 10. Last resort: Special cased prefix of Qt namespace since the meta object implicitly inherits this, so - // enum types from there may be addressed without any scope resolution in properties. - if (!contexts.size() && !subclassesDone) { - contexts << QLatin1String("Qt"); - subclassesDone = true; - } - } - - } - - if (!type) { - *ok = false; - return 0; - } + if (!type) + return nullptr; // Used to for diagnostics later... m_usedTypes << type; @@ -2527,10 +2482,10 @@ AbstractMetaType *AbstractMetaBuilderPrivate::translateType(const TypeInfo &_typ info.setFunctionPointer(false); info.setQualifiedName(ta.instantiationName().split(colonColon())); - AbstractMetaType* targType = translateType(info, ok); - if (!(*ok)) { + AbstractMetaType *targType = translateType(info); + if (!targType) { delete metaType; - return 0; + return nullptr; } metaType->addInstantiation(targType, true); @@ -2540,7 +2495,7 @@ AbstractMetaType *AbstractMetaBuilderPrivate::translateType(const TypeInfo &_typ // instantiations have been determined, or else the absence of // such instantiations will break the caching scheme of // AbstractMetaType::cppSignature(). - decideUsagePattern(metaType); + metaType->decideUsagePattern(); return metaType; } @@ -2583,11 +2538,6 @@ qint64 AbstractMetaBuilderPrivate::findOutValueFromString(const QString &stringV return 0; } -void AbstractMetaBuilderPrivate::decideUsagePattern(AbstractMetaType *metaType) -{ - metaType->decideUsagePattern(); -} - QString AbstractMetaBuilderPrivate::fixDefaultValue(ArgumentModelItem item, AbstractMetaType *type, AbstractMetaFunction *fnc, @@ -2697,7 +2647,7 @@ bool AbstractMetaBuilderPrivate::isQObject(const FileModelItem &dom, const QStri classItem = ns->findClass(names.at(names.size() - 1)); } - if (classItem == nullptr) + if (!classItem) return false; if (classItem->extendsClass(QLatin1String("QObject"))) @@ -2821,7 +2771,7 @@ AbstractMetaType* AbstractMetaBuilderPrivate::inheritTemplateType(const QVector< AbstractMetaType* t = returned->copy(); t->setTypeEntry(templateTypes.at(tae->ordinal())->typeEntry()); t->setIndirections(templateTypes.at(tae->ordinal())->indirections() + t->indirections() ? 1 : 0); - decideUsagePattern(t); + t->decideUsagePattern(); delete returned; returned = inheritTemplateType(templateTypes, t, ok); @@ -3003,7 +2953,6 @@ void AbstractMetaBuilderPrivate::parseQ_Property(AbstractMetaClass *metaClass, QStringList qualifiedScopeName = currentScope()->qualifiedName(); - bool ok = false; AbstractMetaType* type = 0; QString scope; for (int j = qualifiedScopeName.size(); j >= 0; --j) { @@ -3011,12 +2960,12 @@ void AbstractMetaBuilderPrivate::parseQ_Property(AbstractMetaClass *metaClass, TypeInfo info; info.setQualifiedName((scope + l.at(0)).split(colonColon())); - type = translateType(info, &ok); - if (type && ok) + type = translateType(info); + if (type) break; } - if (!type || !ok) { + if (!type) { qCWarning(lcShiboken).noquote().nospace() << QStringLiteral("Unable to decide type of property: '%1' in class '%2'") .arg(l.at(0), metaClass->name()); diff --git a/sources/shiboken2/ApiExtractor/abstractmetabuilder_p.h b/sources/shiboken2/ApiExtractor/abstractmetabuilder_p.h index 7becb2c34..959734462 100644 --- a/sources/shiboken2/ApiExtractor/abstractmetabuilder_p.h +++ b/sources/shiboken2/ApiExtractor/abstractmetabuilder_p.h @@ -120,14 +120,11 @@ public: AbstractMetaFunction *fnc, AbstractMetaClass *, int argumentIndex); AbstractMetaType *translateType(const AddedFunction::TypeInfo &typeInfo); - AbstractMetaType *translateType(const TypeInfo &type, bool *ok, - bool resolveType = true, - bool resolveScope = true); + AbstractMetaType *translateType(const TypeInfo &type, + bool resolveType = true); qint64 findOutValueFromString(const QString &stringValue, bool &ok); - void decideUsagePattern(AbstractMetaType *type); - AbstractMetaClass *findTemplateClass(const QString& name, const AbstractMetaClass *context, TypeParser::Info *info = Q_NULLPTR, ComplexTypeEntry **baseContainerType = Q_NULLPTR) const; diff --git a/sources/shiboken2/ApiExtractor/parser/codemodel.cpp b/sources/shiboken2/ApiExtractor/parser/codemodel.cpp index a06f56434..0af4905f4 100644 --- a/sources/shiboken2/ApiExtractor/parser/codemodel.cpp +++ b/sources/shiboken2/ApiExtractor/parser/codemodel.cpp @@ -146,6 +146,14 @@ TypeInfo TypeInfo::combine(const TypeInfo &__lhs, const TypeInfo &__rhs) return __result; } +bool TypeInfo::isVoid() const +{ + return m_indirections == 0 && m_referenceType == NoReference + && m_arguments.isEmpty() && m_arrayElements.isEmpty() + && m_qualifiedName.size() == 1 + && m_qualifiedName.constFirst() == QLatin1String("void"); +} + TypeInfo TypeInfo::resolveType(TypeInfo const &__type, CodeModelItem __scope) { CodeModel *__model = __scope->model(); diff --git a/sources/shiboken2/ApiExtractor/parser/codemodel.h b/sources/shiboken2/ApiExtractor/parser/codemodel.h index 9a77c5f43..d0d7b677c 100644 --- a/sources/shiboken2/ApiExtractor/parser/codemodel.h +++ b/sources/shiboken2/ApiExtractor/parser/codemodel.h @@ -111,6 +111,8 @@ public: m_qualifiedName = qualified_name; } + bool isVoid() const; + bool isConstant() const { return m_constant; diff --git a/sources/shiboken2/CMakeLists.txt b/sources/shiboken2/CMakeLists.txt index 60ab7878f..852e14c1a 100644 --- a/sources/shiboken2/CMakeLists.txt +++ b/sources/shiboken2/CMakeLists.txt @@ -234,6 +234,47 @@ if (NOT PYTHON_EXTENSION_SUFFIX) get_python_extension_suffix() endif() +option(FORCE_LIMITED_API "Enable the limited API." "yes") +set(PYTHON_LIMITED_API 0) + +# On Windows, PYTHON_LIBRARIES can be a list. Example: +# optimized;C:/Python36/libs/python36.lib;debug;C:/Python36/libs/python36_d.lib +# On other platforms, this result is not used at all. +execute_process( + COMMAND ${PYTHON_EXECUTABLE} -c "if True: + for lib in '${PYTHON_LIBRARIES}'.split(';'): + if '/' in lib: + prefix, py = lib.rsplit('/', 1) + if py.startswith('python3'): + print(prefix + '/python3.lib') + break + " + OUTPUT_VARIABLE PYTHON_LIMITED_LIBRARIES + OUTPUT_STRIP_TRAILING_WHITESPACE) + +if(FORCE_LIMITED_API STREQUAL "yes") + if (${PYTHON_VERSION_MAJOR} EQUAL 3 AND ${PYTHON_VERSION_MINOR} GREATER 4) + # GREATER_EQUAL is available only from cmake 3.7 on. We mean python 3.5 . + add_definitions("-DPy_LIMITED_API=0x03050000") + set(PYTHON_LIMITED_API 1) + endif() + if(WIN32) + if (${PYTHON_VERSION_MAJOR} EQUAL 3 AND ${PYTHON_VERSION_MINOR} GREATER 4) + # PYSIDE-560: XXX maybe add an option to setup.py as override + set(SBK_PYTHON_LIBRARIES ${PYTHON_LIMITED_LIBRARIES}) + endif() + endif() +endif() + +if (PYTHON_LIMITED_API) + if (WIN32 AND NOT EXISTS "${PYTHON_LIMITED_LIBRARIES}") + message(FATAL_ERROR "The Limited API was enabled, but ${PYTHON_LIMITED_LIBRARIES} was not found!") + endif() + message(STATUS "******************************************************") + message(STATUS "** Limited API enabled ${PYTHON_LIMITED_LIBRARIES}") + message(STATUS "******************************************************") +endif() + if (NOT PYTHON_CONFIG_SUFFIX) if (PYTHON_VERSION_MAJOR EQUAL 2) set(PYTHON_CONFIG_SUFFIX "-python${PYTHON_VERSION_MAJOR}.${PYTHON_VERSION_MINOR}") @@ -241,6 +282,13 @@ if (NOT PYTHON_CONFIG_SUFFIX) set(PYTHON_CONFIG_SUFFIX "${PYTHON_CONFIG_SUFFIX}${PYTHON_EXTENSION_SUFFIX}") endif() elseif (PYTHON_VERSION_MAJOR EQUAL 3) + if (PYTHON_LIMITED_API) + if(WIN32) + set(PYTHON_EXTENSION_SUFFIX "") + else() + set(PYTHON_EXTENSION_SUFFIX ".abi3") + endif() + endif() set(PYTHON_CONFIG_SUFFIX "${PYTHON_EXTENSION_SUFFIX}") endif() endif() @@ -335,18 +383,6 @@ if (SANITIZE_ADDRESS AND NOT MSVC) set(CMAKE_CXX_STANDARD_LIBRARIES "${CMAKE_STANDARD_LIBRARIES} -fsanitize=address") endif() -add_subdirectory(ApiExtractor) - -set(generator_plugin_DIR ${LIB_INSTALL_DIR}/generatorrunner${generator_SUFFIX}) - -# uninstall target -configure_file("${CMAKE_CURRENT_SOURCE_DIR}/cmake_uninstall.cmake" - "${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake" - IMMEDIATE @ONLY) -add_custom_target(uninstall "${CMAKE_COMMAND}" - -P "${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake") - - # Detect if the python libs were compiled in debug mode # On Linux distros there is no standard way to check that. execute_process( @@ -392,11 +428,13 @@ execute_process( set(SHIBOKEN_BUILD_TYPE "Release") -# We do not want to link against the python shared / static library on Linux And macOS. +# We do not want to link against the python shared / static library on Linux and macOS. # The dynamic linker will pick up the python symbols at runtime automatically. # On Windows we do need to link against the python.lib import library. +if (NOT SBK_PYTHON_LIBRARIES) + set(SBK_PYTHON_LIBRARIES "") +endif() -set(SBK_PYTHON_LIBRARIES "") if(CMAKE_BUILD_TYPE STREQUAL "Debug") if(NOT PYTHON_DEBUG_LIBRARIES) message(WARNING "Python debug shared library not found; assuming python was built with shared library support disabled.") @@ -416,27 +454,40 @@ if(CMAKE_BUILD_TYPE STREQUAL "Debug") set(SBK_PKG_CONFIG_PY_DEBUG_DEFINITION "${SBK_PKG_CONFIG_PY_DEBUG_DEFINITION} -DCOUNT_ALLOCS") endif() - if(WIN32) + if(WIN32 AND NOT SBK_PYTHON_LIBRARIES) set(SBK_PYTHON_LIBRARIES ${PYTHON_DEBUG_LIBRARIES}) endif() set(SHIBOKEN_BUILD_TYPE "Debug") -else() - if(WIN32) +endif() + +if(CMAKE_BUILD_TYPE STREQUAL "Release") + add_definitions("-DNDEBUG") + if(WIN32 AND NOT SBK_PYTHON_LIBRARIES) set(SBK_PYTHON_LIBRARIES ${PYTHON_LIBRARIES}) endif() - add_definitions("-DNDEBUG") endif() + if(APPLE) set(SBK_PYTHON_LIBRARIES "-undefined dynamic_lookup") endif() - if(CMAKE_VERSION VERSION_LESS 2.8) set(SBK_PYTHON_INCLUDE_DIR ${PYTHON_INCLUDE_PATH}) else() set(SBK_PYTHON_INCLUDE_DIR ${PYTHON_INCLUDE_DIRS}) endif() +add_subdirectory(ApiExtractor) + +set(generator_plugin_DIR ${LIB_INSTALL_DIR}/generatorrunner${generator_SUFFIX}) + +# uninstall target +configure_file("${CMAKE_CURRENT_SOURCE_DIR}/cmake_uninstall.cmake" + "${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake" + IMMEDIATE @ONLY) +add_custom_target(uninstall "${CMAKE_COMMAND}" + -P "${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake") + add_subdirectory(libshiboken) add_subdirectory(doc) diff --git a/sources/shiboken2/generator/shiboken2/cppgenerator.cpp b/sources/shiboken2/generator/shiboken2/cppgenerator.cpp index d7c04d3c9..bd654f17c 100644 --- a/sources/shiboken2/generator/shiboken2/cppgenerator.cpp +++ b/sources/shiboken2/generator/shiboken2/cppgenerator.cpp @@ -214,6 +214,8 @@ static QString chopType(QString s) { if (s.endsWith(QLatin1String("_Type"))) s.chop(5); + else if (s.endsWith(QLatin1String("_TypeF()"))) + s.chop(8); return s; } @@ -665,7 +667,7 @@ QString CppGenerator::getVirtualFunctionReturnTypeName(const AbstractMetaFunctio if (func->type()->isPrimitive()) return QLatin1Char('"') + func->type()->name() + QLatin1Char('"'); - return QString::fromLatin1("Shiboken::SbkType< %1 >()->tp_name").arg(func->type()->typeEntry()->qualifiedCppName()); + return QString::fromLatin1("PepType(Shiboken::SbkType< %1 >())->tp_name").arg(func->type()->typeEntry()->qualifiedCppName()); } void CppGenerator::writeVirtualMethodNative(QTextStream&s, const AbstractMetaFunction* func) @@ -892,7 +894,7 @@ void CppGenerator::writeVirtualMethodNative(QTextStream&s, const AbstractMetaFun s << INDENT << "Shiboken::warning(PyExc_RuntimeWarning, 2, "\ "\"Invalid return value in function %s, expected %s, got %s.\", \""; s << func->ownerClass()->name() << '.' << funcName << "\", " << getVirtualFunctionReturnTypeName(func); - s << ", " PYTHON_RETURN_VAR "->ob_type->tp_name);" << endl; + s << ", PepType(Py_TYPE(" PYTHON_RETURN_VAR "))->tp_name);" << endl; s << INDENT << "return " << defaultReturnExpr << ';' << endl; } s << INDENT << '}' << endl; @@ -912,7 +914,7 @@ void CppGenerator::writeVirtualMethodNative(QTextStream&s, const AbstractMetaFun s << INDENT << "Shiboken::warning(PyExc_RuntimeWarning, 2, "\ "\"Invalid return value in function %s, expected %s, got %s.\", \""; s << func->ownerClass()->name() << '.' << funcName << "\", " << getVirtualFunctionReturnTypeName(func); - s << ", " PYTHON_RETURN_VAR "->ob_type->tp_name);" << endl; + s << ", PepType(Py_TYPE(" PYTHON_RETURN_VAR "))->tp_name);" << endl; s << INDENT << "return " << defaultReturnExpr << ';' << endl; } s << INDENT << '}' << endl; @@ -1144,11 +1146,11 @@ void CppGenerator::writeConverterFunctions(QTextStream &s, const AbstractMetaCla QString targetTypeName = metaClass->name() + QLatin1String("_PTR"); QString code; QTextStream c(&code); - c << INDENT << "Shiboken::Conversions::pythonToCppPointer(&" << cpythonType << ", pyIn, cppOut);"; + c << INDENT << "Shiboken::Conversions::pythonToCppPointer(" << cpythonType << ", pyIn, cppOut);"; writePythonToCppFunction(s, code, sourceTypeName, targetTypeName); // "Is convertible" function for the Python object to C++ pointer conversion. - QString pyTypeCheck = QStringLiteral("PyObject_TypeCheck(pyIn, (PyTypeObject*)&%1)").arg(cpythonType); + QString pyTypeCheck = QStringLiteral("PyObject_TypeCheck(pyIn, (PyTypeObject*)%1)").arg(cpythonType); writeIsPythonConvertibleToCppFunction(s, sourceTypeName, targetTypeName, pyTypeCheck, QString(), true); s << endl; @@ -1157,7 +1159,7 @@ void CppGenerator::writeConverterFunctions(QTextStream &s, const AbstractMetaCla code.clear(); if (usePySideExtensions() && metaClass->isQObject()) { - c << INDENT << "return PySide::getWrapperForQObject((" << typeName << "*)cppIn, &" << cpythonType << ");" << endl; + c << INDENT << "return PySide::getWrapperForQObject((" << typeName << "*)cppIn, " << cpythonType << ");" << endl; } else { c << INDENT << "PyObject* pyOut = (PyObject*)Shiboken::BindingManager::instance().retrieveWrapper(cppIn);" << endl; c << INDENT << "if (pyOut) {" << endl; @@ -1168,7 +1170,7 @@ void CppGenerator::writeConverterFunctions(QTextStream &s, const AbstractMetaCla } c << INDENT << '}' << endl; c << INDENT << "const char* typeName = typeid(*((" << typeName << "*)cppIn)).name();" << endl; - c << INDENT << "return Shiboken::Object::newObject(&" << cpythonType; + c << INDENT << "return Shiboken::Object::newObject(" << cpythonType; c << ", const_cast<void*>(cppIn), false, false, typeName);"; } std::swap(targetTypeName, sourceTypeName); @@ -1197,7 +1199,7 @@ void CppGenerator::writeConverterFunctions(QTextStream &s, const AbstractMetaCla else computedWrapperName = wrapperName(classContext.preciseType()); - c << INDENT << "return Shiboken::Object::newObject(&" << cpythonType << ", new ::" << computedWrapperName; + c << INDENT << "return Shiboken::Object::newObject(" << cpythonType << ", new ::" << computedWrapperName; c << "(*((" << typeName << "*)cppIn)), true, true);"; writeCppToPythonFunction(s, code, sourceTypeName, targetTypeName); s << endl; @@ -1329,7 +1331,7 @@ void CppGenerator::writeConverterRegister(QTextStream &s, const AbstractMetaClas if (metaClass->isNamespace()) return; s << INDENT << "// Register Converter" << endl; - s << INDENT << "SbkConverter* converter = Shiboken::Conversions::createConverter(&"; + s << INDENT << "SbkConverter* converter = Shiboken::Conversions::createConverter("; s << cpythonTypeName(metaClass) << ',' << endl; { Indentation indent(INDENT); @@ -2324,7 +2326,7 @@ void CppGenerator::writePythonToCppTypeConversion(QTextStream& s, if (!defaultValue.isEmpty()) s << '{' << endl << INDENT; - s << "if (Shiboken::Conversions::isImplicitConversion(reinterpret_cast<const SbkObjectType *>(" + s << "if (Shiboken::Conversions::isImplicitConversion(reinterpret_cast<SbkObjectType *>(" << cpythonTypeNameExt(type) << "), " << pythonToCppFunc << "))" << endl; { Indentation indent(INDENT); @@ -2838,7 +2840,7 @@ void CppGenerator::writePythonToCppConversionFunctions(QTextStream& s, if (toNative->sourceType()) inType = cpythonTypeNameExt(toNative->sourceType()); else - inType = QString::fromLatin1("(&%1_Type)").arg(toNative->sourceTypeName()); + inType = QString::fromLatin1("(%1_TypeF())").arg(toNative->sourceTypeName()); code.replace(QLatin1String("%INTYPE"), inType); code.replace(QLatin1String("%OUTTYPE"), targetType->qualifiedCppName()); code.replace(QLatin1String("%in"), QLatin1String("pyIn")); @@ -3698,24 +3700,20 @@ void CppGenerator::writeClassDefinition(QTextStream &s, } if (!metaClass->baseClass()) - baseClassName = QLatin1String("reinterpret_cast<PyTypeObject*>(&SbkObject_Type)"); + baseClassName = QLatin1String("reinterpret_cast<PyTypeObject*>(SbkObject_TypeF())"); bool onlyPrivCtor = !metaClass->hasNonPrivateConstructor(); const AbstractMetaClass *qCoreApp = AbstractMetaClass::findClass(classes(), QLatin1String("QCoreApplication")); const bool isQApp = qCoreApp != Q_NULLPTR && metaClass->inheritsFrom(qCoreApp); + tp_flags = QLatin1String("Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE|Py_TPFLAGS_CHECKTYPES"); if (metaClass->isNamespace() || metaClass->hasPrivateDestructor()) { - tp_flags = QLatin1String("Py_TPFLAGS_DEFAULT|Py_TPFLAGS_CHECKTYPES"); tp_dealloc = metaClass->hasPrivateDestructor() ? - QLatin1String("SbkDeallocWrapperWithPrivateDtor") : QLatin1String("0"); + QLatin1String("SbkDeallocWrapperWithPrivateDtor") : + QLatin1String("SbkDummyDealloc /* PYSIDE-595: Prevent replacement of \"0\" with subtype_dealloc. */"); tp_init = QLatin1String("0"); } else { - if (onlyPrivCtor) - tp_flags = QLatin1String("Py_TPFLAGS_DEFAULT|Py_TPFLAGS_CHECKTYPES"); - else - tp_flags = QLatin1String("Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE|Py_TPFLAGS_CHECKTYPES"); - QString deallocClassName; if (shouldGenerateCppWrapper(metaClass)) deallocClassName = wrapperName(metaClass); @@ -3741,7 +3739,21 @@ void CppGenerator::writeClassDefinition(QTextStream &s, } if (metaClass->hasPrivateDestructor() || onlyPrivCtor) { - tp_new = QLatin1String("0"); + // tp_flags = QLatin1String("Py_TPFLAGS_DEFAULT|Py_TPFLAGS_CHECKTYPES"); + // This is not generally possible, because PySide does not care about + // privacy the same way. This worked before the heap types were used, + // because inheritance is not really checked for static types. + // Instead, we check this at runtime, see SbkObjectTypeTpNew. + if (metaClass->fullName().startsWith(QLatin1String("PySide2.Qt"))) { + // PYSIDE-595: No idea how to do non-inheritance correctly. + // Since that is only relevant in shiboken, I used a shortcut for + // PySide. + tp_new = QLatin1String("SbkObjectTpNew"); + } + else { + tp_new = QLatin1String("SbkDummyNew /* PYSIDE-595: Prevent replacement " + "of \"0\" with base->tp_new. */"); + } tp_flags.append(QLatin1String("|Py_TPFLAGS_HAVE_GC")); } else if (isQApp) { @@ -3782,6 +3794,9 @@ void CppGenerator::writeClassDefinition(QTextStream &s, s << endl; } + s << "// Class Definition -----------------------------------------------" << endl; + s << "extern \"C\" {" << endl; + if (!metaClass->typeEntry()->hashFunction().isEmpty()) tp_hash = QLatin1Char('&') + cpythonBaseName(metaClass) + QLatin1String("_HashFunc"); @@ -3789,83 +3804,65 @@ void CppGenerator::writeClassDefinition(QTextStream &s, if (callOp && !callOp->isModifiedRemoved()) tp_call = QLatin1Char('&') + cpythonFunctionName(callOp); - s << "// Class Definition -----------------------------------------------" << endl; - s << "extern \"C\" {" << endl; - - if (supportsNumberProtocol(metaClass)) { - s << "static PyNumberMethods " << className + QLatin1String("_TypeAsNumber") << ";" << endl; - s << endl; - } - - if (supportsSequenceProtocol(metaClass)) { - s << "static PySequenceMethods " << className + QLatin1String("_TypeAsSequence") << ";" << endl; - s << endl; - } - - if (supportsMappingProtocol(metaClass)) { - s << "static PyMappingMethods " << className + QLatin1String("_TypeAsMapping") << ";" << endl; - s << endl; - } - - s << "static SbkObjectType " << className + QLatin1String("_Type") << " = { { {" << endl; - s << INDENT << "PyVarObject_HEAD_INIT(&SbkObjectType_Type, 0)" << endl; QString computedClassTargetFullName; if (!classContext.forSmartPointer()) computedClassTargetFullName = getClassTargetFullName(metaClass); else computedClassTargetFullName = getClassTargetFullName(classContext.preciseType()); - s << INDENT << "/*tp_name*/ \"" << computedClassTargetFullName << "\"," << endl; - s << INDENT << "/*tp_basicsize*/ sizeof(SbkObject)," << endl; - s << INDENT << "/*tp_itemsize*/ 0," << endl; - s << INDENT << "/*tp_dealloc*/ " << tp_dealloc << ',' << endl; - s << INDENT << "/*tp_print*/ 0," << endl; - s << INDENT << "/*tp_getattr*/ 0," << endl; - s << INDENT << "/*tp_setattr*/ 0," << endl; - s << INDENT << "/*tp_compare*/ 0," << endl; - s << INDENT << "/*tp_repr*/ " << m_tpFuncs[QLatin1String("__repr__")] << "," << endl; - s << INDENT << "/*tp_as_number*/ 0," << endl; - s << INDENT << "/*tp_as_sequence*/ 0," << endl; - s << INDENT << "/*tp_as_mapping*/ 0," << endl; - s << INDENT << "/*tp_hash*/ " << tp_hash << ',' << endl; - s << INDENT << "/*tp_call*/ " << tp_call << ',' << endl; - s << INDENT << "/*tp_str*/ " << m_tpFuncs[QLatin1String("__str__")] << ',' << endl; - s << INDENT << "/*tp_getattro*/ " << tp_getattro << ',' << endl; - s << INDENT << "/*tp_setattro*/ " << tp_setattro << ',' << endl; - s << INDENT << "/*tp_as_buffer*/ 0," << endl; - s << INDENT << "/*tp_flags*/ " << tp_flags << ',' << endl; - s << INDENT << "/*tp_doc*/ 0," << endl; - s << INDENT << "/*tp_traverse*/ " << className << "_traverse," << endl; - s << INDENT << "/*tp_clear*/ " << className << "_clear," << endl; - s << INDENT << "/*tp_richcompare*/ " << tp_richcompare << ',' << endl; - s << INDENT << "/*tp_weaklistoffset*/ 0," << endl; - s << INDENT << "/*tp_iter*/ " << m_tpFuncs[QLatin1String("__iter__")] << ',' << endl; - s << INDENT << "/*tp_iternext*/ " << m_tpFuncs[QLatin1String("__next__")] << ',' << endl; - s << INDENT << "/*tp_methods*/ " << className << "_methods," << endl; - s << INDENT << "/*tp_members*/ 0," << endl; - s << INDENT << "/*tp_getset*/ " << tp_getset << ',' << endl; - s << INDENT << "/*tp_base*/ " << baseClassName << ',' << endl; - s << INDENT << "/*tp_dict*/ 0," << endl; - s << INDENT << "/*tp_descr_get*/ 0," << endl; - s << INDENT << "/*tp_descr_set*/ 0," << endl; - s << INDENT << "/*tp_dictoffset*/ 0," << endl; - s << INDENT << "/*tp_init*/ " << tp_init << ',' << endl; - s << INDENT << "/*tp_alloc*/ 0," << endl; - s << INDENT << "/*tp_new*/ " << tp_new << ',' << endl; - s << INDENT << "/*tp_free*/ 0," << endl; - s << INDENT << "/*tp_is_gc*/ 0," << endl; - s << INDENT << "/*tp_bases*/ 0," << endl; - s << INDENT << "/*tp_mro*/ 0," << endl; - s << INDENT << "/*tp_cache*/ 0," << endl; - s << INDENT << "/*tp_subclasses*/ 0," << endl; - s << INDENT << "/*tp_weaklist*/ 0" << endl; - s << "}, }," << endl; - s << INDENT << "/*priv_data*/ 0" << endl; - s << "};" << endl; QString suffix; if (isObjectType(metaClass)) suffix = QLatin1String("*"); - s << "} //extern" << endl; + const QString typePtr = QLatin1String("_") + className + + QLatin1String("_Type"); + s << "static SbkObjectType *" << typePtr << " = nullptr;" << endl; + s << "static SbkObjectType *" << className << "_TypeF(void)" << endl; + s << "{" << endl; + s << INDENT << "return " << typePtr << ";" << endl; + s << "}" << endl; + s << endl; + s << "static PyType_Slot " << className << "_slots[] = {" << endl; + s << INDENT << "{Py_tp_base, (void *)0}, // inserted by introduceWrapperType" << endl; + s << INDENT << "{Py_tp_dealloc, (void *)" << tp_dealloc << "}," << endl; + s << INDENT << "{Py_tp_repr, (void *)" << m_tpFuncs[QLatin1String("__repr__")] << "}," << endl; + s << INDENT << "{Py_tp_hash, (void *)" << tp_hash << "}," << endl; + s << INDENT << "{Py_tp_call, (void *)" << tp_call << "}," << endl; + s << INDENT << "{Py_tp_str, (void *)" << m_tpFuncs[QLatin1String("__str__")] << "}," << endl; + s << INDENT << "{Py_tp_getattro, (void *)" << tp_getattro << "}," << endl; + s << INDENT << "{Py_tp_setattro, (void *)" << tp_setattro << "}," << endl; + s << INDENT << "{Py_tp_traverse, (void *)" << className << "_traverse}," << endl; + s << INDENT << "{Py_tp_clear, (void *)" << className << "_clear}," << endl; + s << INDENT << "{Py_tp_richcompare, (void *)" << tp_richcompare << "}," << endl; + s << INDENT << "{Py_tp_iter, (void *)" << m_tpFuncs[QLatin1String("__iter__")] << "}," << endl; + s << INDENT << "{Py_tp_iternext, (void *)" << m_tpFuncs[QLatin1String("__next__")] << "}," << endl; + s << INDENT << "{Py_tp_methods, (void *)" << className << "_methods}," << endl; + s << INDENT << "{Py_tp_getset, (void *)" << tp_getset << "}," << endl; + s << INDENT << "{Py_tp_init, (void *)" << tp_init << "}," << endl; + s << INDENT << "{Py_tp_new, (void *)" << tp_new << "}," << endl; + if (supportsSequenceProtocol(metaClass)) { + s << INDENT << "// type supports sequence protocol" << endl; + writeTypeAsSequenceDefinition(s, metaClass); + } + if (supportsMappingProtocol(metaClass)) { + s << INDENT << "// type supports mapping protocol" << endl; + writeTypeAsMappingDefinition(s, metaClass); + } + if (supportsNumberProtocol(metaClass)) { + // This one must come last. See the function itself. + s << INDENT << "// type supports number protocol" << endl; + writeTypeAsNumberDefinition(s, metaClass); + } + s << INDENT << "{0, 0}" << endl; + s << "};" << endl; + s << "static PyType_Spec " << className << "_spec = {" << endl; + s << INDENT << "\"" << computedClassTargetFullName << "\"," << endl; + s << INDENT << "sizeof(SbkObject)," << endl; + s << INDENT << "0," << endl; + s << INDENT << tp_flags << "," << endl; + s << INDENT << className << "_slots" << endl; + s << "};" << endl; + s << endl; + s << "} //extern \"C\"" << endl; } void CppGenerator::writeMappingMethods(QTextStream &s, @@ -3943,14 +3940,13 @@ void CppGenerator::writeTypeAsSequenceDefinition(QTextStream& s, const AbstractM funcs[QLatin1String("__setitem__")] = baseName + QLatin1String("__setitem__"); } - s << INDENT << "memset(&" << baseName << "_TypeAsSequence, 0, sizeof(PySequenceMethods));" << endl; for (QHash<QString, QString>::const_iterator it = m_sqFuncs.cbegin(), end = m_sqFuncs.cend(); it != end; ++it) { const QString& sqName = it.key(); if (funcs[sqName].isEmpty()) continue; if (it.value() == QLatin1String("sq_slice")) s << "#ifndef IS_PY3K" << endl; - s << INDENT << baseName << "_TypeAsSequence." << it.value() << " = " << funcs[sqName] << ';' << endl; + s << INDENT << "{Py_" << it.value() << ", (void *)" << funcs[sqName] << "}," << endl; if (it.value() == QLatin1String("sq_slice")) s << "#endif" << endl; } @@ -3976,12 +3972,11 @@ void CppGenerator::writeTypeAsMappingDefinition(QTextStream& s, const AbstractMe } QString baseName = cpythonBaseName(metaClass); - s << INDENT << "memset(&" << baseName << "_TypeAsMapping, 0, sizeof(PyMappingMethods));" << endl; for (auto it = m_mpFuncs.cbegin(), end = m_mpFuncs.cend(); it != end; ++it) { const QString &mpName = it.key(); if (funcs[mpName].isEmpty()) continue; - s << INDENT << baseName << "_TypeAsMapping." << it.value() << " = " << funcs[mpName] << ';' << endl; + s << INDENT << "{Py_" << it.value() << ", (void *)" << funcs[mpName] << "}," << endl; } } @@ -4029,7 +4024,6 @@ void CppGenerator::writeTypeAsNumberDefinition(QTextStream& s, const AbstractMet nb[QLatin1String("bool")] = hasBoolCast(metaClass) ? baseName + QLatin1String("___nb_bool") : QString(); - s << INDENT << "memset(&" << baseName << "_TypeAsNumber, 0, sizeof(PyNumberMethods));" << endl; for (QHash<QString, QString>::const_iterator it = m_nbFuncs.cbegin(), end = m_nbFuncs.cend(); it != end; ++it) { const QString &nbName = it.key(); if (nb[nbName].isEmpty()) @@ -4038,21 +4032,29 @@ void CppGenerator::writeTypeAsNumberDefinition(QTextStream& s, const AbstractMet // bool is special because the field name differs on Python 2 and 3 (nb_nonzero vs nb_bool) // so a shiboken macro is used. if (nbName == QLatin1String("bool")) { - s << INDENT << "SBK_NB_BOOL(" << baseName << "_TypeAsNumber) = " << nb[nbName] << ';' << endl; + s << "#ifdef IS_PY3K" << endl; + s << INDENT << "{Py_nb_bool, (void *)" << nb[nbName] << "}," << endl; + s << "#else" << endl; + s << INDENT << "{Py_nb_nonzero, (void *)" << nb[nbName] << "}," << endl; + s << "#endif" << endl; } else { bool excludeFromPy3K = nbName == QLatin1String("__div__") || nbName == QLatin1String("__idiv__"); - if (excludeFromPy3K) { - s << "#ifdef IS_PY3K" << endl; - s << INDENT << "SBK_UNUSED(&" << nb[nbName] << ");" << endl; - s << "#else" << endl; - } - s << INDENT << baseName << "_TypeAsNumber." << it.value() << " = " << nb[nbName] << ';' << endl; - if (excludeFromPy3K) - s << "#endif" << endl; + if (!excludeFromPy3K) + s << INDENT << "{Py_" << it.value() << ", (void *)" << nb[nbName] << "}," << endl; } } - if (!nb[QLatin1String("__div__")].isEmpty()) - s << INDENT << baseName << "_TypeAsNumber.nb_true_divide = " << nb[QLatin1String("__div__")] << ';' << endl; + if (!nb[QLatin1String("__div__")].isEmpty()) { + s << INDENT << "{Py_nb_true_divide, (void *)" << nb[QLatin1String("__div__")] << "}," << endl; + s << "#ifndef IS_PY3K" << endl; + s << INDENT << "{Py_nb_divide, (void *)" << nb[QLatin1String("__div__")] << "}," << endl; + s << "#endif" << endl; + } + if (!nb[QLatin1String("__idiv__")].isEmpty()) { + s << INDENT << "// This function is unused in Python 3. We reference it here." << endl; + s << INDENT << "{0, (void *)" << nb[QLatin1String("__idiv__")] << "}," << endl; + s << INDENT << "// This list is ending at the first 0 entry." << endl; + s << INDENT << "// Therefore, we need to put the unused functions at the very end." << endl; + } } void CppGenerator::writeTpTraverseFunction(QTextStream& s, const AbstractMetaClass* metaClass) @@ -4061,7 +4063,7 @@ void CppGenerator::writeTpTraverseFunction(QTextStream& s, const AbstractMetaCla s << "static int "; s << baseName << "_traverse(PyObject* " PYTHON_SELF_VAR ", visitproc visit, void* arg)" << endl; s << '{' << endl; - s << INDENT << "return reinterpret_cast<PyTypeObject*>(&SbkObject_Type)->tp_traverse(" PYTHON_SELF_VAR ", visit, arg);" << endl; + s << INDENT << "return PepType(reinterpret_cast<PyTypeObject*>(SbkObject_TypeF()))->tp_traverse(" PYTHON_SELF_VAR ", visit, arg);" << endl; s << '}' << endl; } @@ -4071,7 +4073,7 @@ void CppGenerator::writeTpClearFunction(QTextStream& s, const AbstractMetaClass* s << "static int "; s << baseName << "_clear(PyObject* " PYTHON_SELF_VAR ")" << endl; s << '{' << endl; - s << INDENT << "return reinterpret_cast<PyTypeObject*>(&SbkObject_Type)->tp_clear(" PYTHON_SELF_VAR ");" << endl; + s << INDENT << "return PepType(reinterpret_cast<PyTypeObject*>(SbkObject_TypeF()))->tp_clear(" PYTHON_SELF_VAR ");" << endl; s << '}' << endl; } @@ -4147,7 +4149,7 @@ void CppGenerator::writeGetterFunction(QTextStream &s, { Indentation indent(INDENT); s << INDENT << "pyOut = reinterpret_cast<PyObject *>(Shiboken::Object::findColocatedChild(" - << "reinterpret_cast<SbkObject *>(self), reinterpret_cast<const SbkObjectType *>(" + << "reinterpret_cast<SbkObject *>(self), reinterpret_cast<SbkObjectType *>(" << cpythonTypeNameExt(fieldType) << ")));\n"; s << INDENT << "if (pyOut) {Py_IncRef(pyOut); return pyOut;}\n"; @@ -4474,7 +4476,7 @@ void CppGenerator::writeEnumInitialization(QTextStream& s, const AbstractMetaEnu const EnumTypeEntry *enumTypeEntry = cppEnum->typeEntry(); QString enclosingObjectVariable; if (enclosingClass) - enclosingObjectVariable = QLatin1Char('&') + cpythonTypeName(enclosingClass); + enclosingObjectVariable = cpythonTypeName(enclosingClass); else if (hasUpperEnclosingClass) enclosingObjectVariable = QLatin1String("enclosingClass"); else @@ -4488,8 +4490,8 @@ void CppGenerator::writeEnumInitialization(QTextStream& s, const AbstractMetaEnu if (!cppEnum->isAnonymous()) { FlagsTypeEntry* flags = enumTypeEntry->flags(); if (flags) { - s << INDENT << cpythonTypeNameExt(flags) << " = PySide::QFlags::create(\"" << flags->flagsName() << "\", &" - << cpythonEnumName(cppEnum) << "_as_number);" << endl; + s << INDENT << cpythonTypeNameExt(flags) << " = PySide::QFlags::create(\"" << flags->flagsName() << "\", " + << cpythonEnumName(cppEnum) << "_number_slots);" << endl; } enumVarTypeObj = cpythonTypeNameExt(enumTypeEntry); @@ -4539,8 +4541,8 @@ void CppGenerator::writeEnumInitialization(QTextStream& s, const AbstractMetaEnu { Indentation indent(INDENT); s << INDENT << "PyObject* anonEnumItem = PyInt_FromLong(" << enumValueText << ");" << endl; - s << INDENT << "if (PyDict_SetItemString(reinterpret_cast<SbkObjectType *>(" << enclosingObjectVariable - << ")->super.ht_type.tp_dict, \"" << enumValue->name() << "\", anonEnumItem) < 0)" << endl; + s << INDENT << "if (PyDict_SetItemString(PepType(reinterpret_cast<SbkObjectType *>(" << enclosingObjectVariable + << "))->tp_dict, \"" << enumValue->name() << "\", anonEnumItem) < 0)" << endl; { Indentation indent(INDENT); s << INDENT << "return " << m_currentErrorCode << ';' << endl; @@ -4609,7 +4611,7 @@ void CppGenerator::writeSignalInitialization(QTextStream& s, const AbstractMetaC } } - s << INDENT << "PySide::Signal::registerSignals(&" << cpythonTypeName(metaClass) << ", &::" + s << INDENT << "PySide::Signal::registerSignals(" << cpythonTypeName(metaClass) << ", &::" << metaClass->qualifiedCppName() << "::staticMetaObject);" << endl; } @@ -4659,57 +4661,22 @@ void CppGenerator::writeFlagsNumberMethodsDefinition(QTextStream& s, const Abstr { QString cpythonName = cpythonEnumName(cppEnum); - s << "static PyNumberMethods " << cpythonName << "_as_number = {" << endl; - s << INDENT << "/*nb_add*/ 0," << endl; - s << INDENT << "/*nb_subtract*/ 0," << endl; - s << INDENT << "/*nb_multiply*/ 0," << endl; - s << INDENT << "#ifndef IS_PY3K" << endl; - s << INDENT << "/* nb_divide */ 0," << endl; - s << INDENT << "#endif" << endl; - s << INDENT << "/*nb_remainder*/ 0," << endl; - s << INDENT << "/*nb_divmod*/ 0," << endl; - s << INDENT << "/*nb_power*/ 0," << endl; - s << INDENT << "/*nb_negative*/ 0," << endl; - s << INDENT << "/*nb_positive*/ 0," << endl; - s << INDENT << "/*nb_absolute*/ 0," << endl; - s << INDENT << "/*nb_nonzero*/ " << cpythonName << "__nonzero," << endl; - s << INDENT << "/*nb_invert*/ (unaryfunc)" << cpythonName << "___invert__," << endl; - s << INDENT << "/*nb_lshift*/ 0," << endl; - s << INDENT << "/*nb_rshift*/ 0," << endl; - s << INDENT << "/*nb_and*/ (binaryfunc)" << cpythonName << "___and__," << endl; - s << INDENT << "/*nb_xor*/ (binaryfunc)" << cpythonName << "___xor__," << endl; - s << INDENT << "/*nb_or*/ (binaryfunc)" << cpythonName << "___or__," << endl; - s << INDENT << "#ifndef IS_PY3K" << endl; - s << INDENT << "/* nb_coerce */ 0," << endl; - s << INDENT << "#endif" << endl; - s << INDENT << "/*nb_int*/ " << cpythonName << "_long," << endl; - s << INDENT << "#ifdef IS_PY3K" << endl; - s << INDENT << "/*nb_reserved*/ 0," << endl; - s << INDENT << "/*nb_float*/ 0," << endl; - s << INDENT << "#else" << endl; - s << INDENT << "/*nb_long*/ " << cpythonName << "_long," << endl; - s << INDENT << "/*nb_float*/ 0," << endl; - s << INDENT << "/*nb_oct*/ 0," << endl; - s << INDENT << "/*nb_hex*/ 0," << endl; - s << INDENT << "#endif" << endl; - s << INDENT << "/*nb_inplace_add*/ 0," << endl; - s << INDENT << "/*nb_inplace_subtract*/ 0," << endl; - s << INDENT << "/*nb_inplace_multiply*/ 0," << endl; - s << INDENT << "#ifndef IS_PY3K" << endl; - s << INDENT << "/*nb_inplace_divide*/ 0," << endl; - s << INDENT << "#endif" << endl; - s << INDENT << "/*nb_inplace_remainder*/ 0," << endl; - s << INDENT << "/*nb_inplace_power*/ 0," << endl; - s << INDENT << "/*nb_inplace_lshift*/ 0," << endl; - s << INDENT << "/*nb_inplace_rshift*/ 0," << endl; - s << INDENT << "/*nb_inplace_and*/ 0," << endl; - s << INDENT << "/*nb_inplace_xor*/ 0," << endl; - s << INDENT << "/*nb_inplace_or*/ 0," << endl; - s << INDENT << "/*nb_floor_divide*/ 0," << endl; - s << INDENT << "/*nb_true_divide*/ 0," << endl; - s << INDENT << "/*nb_inplace_floor_divide*/ 0," << endl; - s << INDENT << "/*nb_inplace_true_divide*/ 0," << endl; - s << INDENT << "/*nb_index*/ 0" << endl; + s << "static PyType_Slot " << cpythonName << "_number_slots[] = {" << endl; + s << "#ifdef IS_PY3K" << endl; + s << INDENT << "{Py_nb_bool, (void *)" << cpythonName << "__nonzero}," << endl; + s << "#else" << endl; + s << INDENT << "{Py_nb_nonzero, (void *)" << cpythonName << "__nonzero}," << endl; + s << INDENT << "{Py_nb_long, (void *)" << cpythonName << "_long}," << endl; + s << "#endif" << endl; + s << INDENT << "{Py_nb_invert, (void *)" << cpythonName << "___invert__}," << endl; + s << INDENT << "{Py_nb_and, (void *)" << cpythonName << "___and__}," << endl; + s << INDENT << "{Py_nb_xor, (void *)" << cpythonName << "___xor__}," << endl; + s << INDENT << "{Py_nb_or, (void *)" << cpythonName << "___or__}," << endl; + s << INDENT << "{Py_nb_int, (void *)" << cpythonName << "_long}," << endl; + s << "#ifndef IS_PY3K" << endl; + s << INDENT << "{Py_nb_long, (void *)" << cpythonName << "_long}," << endl; + s << "#endif" << endl; + s << INDENT << "{0, 0} // sentinel" << endl; s << "};" << endl << endl; } @@ -4803,37 +4770,8 @@ void CppGenerator::writeClassRegister(QTextStream &s, s << "(PyObject* " << enclosingObjectVariable << ")" << endl; s << '{' << endl; - if (supportsNumberProtocol(metaClass)) { - s << INDENT << "// type has number operators" << endl; - writeTypeAsNumberDefinition(s, metaClass); - s << INDENT << pyTypeName << ".super.ht_type.tp_as_number = &" << pyTypeName << "AsNumber;" << endl; - s << endl; - } - - if (supportsSequenceProtocol(metaClass)) { - s << INDENT << "// type supports sequence protocol" << endl; - writeTypeAsSequenceDefinition(s, metaClass); - s << INDENT << pyTypeName << ".super.ht_type.tp_as_sequence = &" << pyTypeName << "AsSequence;" << endl; - s << endl; - } - - if (supportsMappingProtocol(metaClass)) { - s << INDENT << "// type supports mapping protocol" << endl; - writeTypeAsMappingDefinition(s, metaClass); - s << INDENT << pyTypeName << ".super.ht_type.tp_as_mapping = &" << pyTypeName << "AsMapping;" << endl; - s << endl; - } - - if (!classContext.forSmartPointer()) - s << INDENT << cpythonTypeNameExt(classTypeEntry) << endl; - else - s << INDENT << cpythonTypeNameExt(classContext.preciseType()) << endl; - - s << INDENT << " = reinterpret_cast<PyTypeObject*>(&" << pyTypeName << ");" << endl; - s << endl; - // Multiple inheritance - QString pyTypeBasesVariable = pyTypeName + QLatin1String("_bases"); + QString pyTypeBasesVariable = chopType(pyTypeName) + QLatin1String("_Type_bases"); const AbstractMetaClassList baseClasses = getBaseClasses(metaClass); if (metaClass->baseClassNames().size() > 1) { s << INDENT << "PyObject* " << pyTypeBasesVariable << " = PyTuple_Pack(" << baseClasses.size() << ',' << endl; @@ -4848,28 +4786,42 @@ void CppGenerator::writeClassRegister(QTextStream &s, } // Create type and insert it in the module or enclosing class. - s << INDENT << "if (!Shiboken::ObjectType::introduceWrapperType(" << enclosingObjectVariable; - QString typeName; - if (!classContext.forSmartPointer()) - typeName = metaClass->name(); - else - typeName = classContext.preciseType()->cppSignature(); - - s << ", \"" << typeName << "\", \""; + const QString typePtr = QLatin1String("_") + chopType(pyTypeName) + + QLatin1String("_Type"); - // Original name - if (!classContext.forSmartPointer()) - s << metaClass->qualifiedCppName() << (isObjectType(classTypeEntry) ? "*" : ""); - else - s << classContext.preciseType()->cppSignature(); - - s << "\"," << endl; + s << INDENT << typePtr << " = Shiboken::ObjectType::introduceWrapperType(" << endl; { Indentation indent(INDENT); - s << INDENT << "&" << pyTypeName << "," << endl; - s << INDENT << initFunctionName << "_SignaturesString"; + // 1:enclosingObject + s << INDENT << enclosingObjectVariable << "," << endl; + QString typeName; + if (!classContext.forSmartPointer()) + typeName = metaClass->name(); + else + typeName = classContext.preciseType()->cppSignature(); + + // 2:typeName + s << INDENT << "\"" << typeName << "\"," << endl; + + // 3:originalName + s << INDENT << "\""; + if (!classContext.forSmartPointer()) { + s << metaClass->qualifiedCppName(); + if (isObjectType(classTypeEntry)) + s << '*'; + } else { + s << classContext.preciseType()->cppSignature(); + } + + s << "\"," << endl; + // 4:typeSpec + s << INDENT << '&' << chopType(pyTypeName) << "_spec," << endl; - // Set destructor function + // 5:signaturesString + s << INDENT << initFunctionName << "_SignaturesString," << endl; + + // 6:cppObjDtor + s << INDENT; if (!metaClass->isNamespace() && !metaClass->hasPrivateDestructor()) { QString dtorClassName = metaClass->qualifiedCppName(); if ((avoidProtectedHack() && metaClass->hasProtectedDestructor()) || classTypeEntry->isValue()) @@ -4877,28 +4829,37 @@ void CppGenerator::writeClassRegister(QTextStream &s, if (classContext.forSmartPointer()) dtorClassName = wrapperName(classContext.preciseType()); - s << ", &Shiboken::callCppDestructor< ::" << dtorClassName << " >"; - } else if (metaClass->baseClass() || hasEnclosingClass) { - s << ", 0"; + s << "&Shiboken::callCppDestructor< ::" << dtorClassName << " >," << endl; + } else { + s << "0," << endl; } - // Base type + // 7:baseType if (metaClass->baseClass()) { - s << ", reinterpret_cast<SbkObjectType *>(" << cpythonTypeNameExt(metaClass->baseClass()->typeEntry()) << ')'; - // The other base types - if (metaClass->baseClassNames().size() > 1) - s << ", " << pyTypeBasesVariable; - else if (hasEnclosingClass) - s << ", 0"; - } else if (hasEnclosingClass) { - s << ", 0, 0"; - } - if (hasEnclosingClass) - s << ", true"; - s << ")) {" << endl; - s << INDENT << "return;" << endl; + s << INDENT << "reinterpret_cast<SbkObjectType *>(" + << cpythonTypeNameExt(metaClass->baseClass()->typeEntry()) << ")," << endl; + } else { + s << INDENT << "0," << endl; + } + + // 8:baseTypes + if (metaClass->baseClassNames().size() > 1) + s << INDENT << pyTypeBasesVariable << ',' << endl; + else + s << INDENT << "0," << endl; + + // 9:isInnerClass + s << INDENT << (hasEnclosingClass ? "true" : "false") << endl; } - s << INDENT << '}' << endl << endl; + s << INDENT << ");" << endl; + s << INDENT << endl; + + if (!classContext.forSmartPointer()) + s << INDENT << cpythonTypeNameExt(classTypeEntry) << endl; + else + s << INDENT << cpythonTypeNameExt(classContext.preciseType()) << endl; + s << INDENT << " = reinterpret_cast<PyTypeObject*>(" << pyTypeName << ");" << endl; + s << endl; // Register conversions for the type. writeConverterRegister(s, metaClass, classContext); @@ -4920,15 +4881,15 @@ void CppGenerator::writeClassRegister(QTextStream &s, s << "Shiboken::ObjectType::getMultipleIheritanceFunction(reinterpret_cast<SbkObjectType*>("; s << cpythonTypeNameExt(miClass->typeEntry()) << "));" << endl; } - s << INDENT << "Shiboken::ObjectType::setMultipleIheritanceFunction(&"; + s << INDENT << "Shiboken::ObjectType::setMultipleInheritanceFunction("; s << cpythonTypeName(metaClass) << ", func);" << endl; - s << INDENT << "Shiboken::ObjectType::setCastFunction(&" << cpythonTypeName(metaClass); + s << INDENT << "Shiboken::ObjectType::setCastFunction(" << cpythonTypeName(metaClass); s << ", &" << cpythonSpecialCastFunctionName(metaClass) << ");" << endl; } // Set typediscovery struct or fill the struct of another one if (metaClass->isPolymorphic() && metaClass->baseClass()) { - s << INDENT << "Shiboken::ObjectType::setTypeDiscoveryFunctionV2(&" << cpythonTypeName(metaClass); + s << INDENT << "Shiboken::ObjectType::setTypeDiscoveryFunctionV2(" << cpythonTypeName(metaClass); s << ", &" << cpythonBaseName(metaClass) << "_typeDiscovery);" << endl << endl; } @@ -4948,7 +4909,7 @@ void CppGenerator::writeClassRegister(QTextStream &s, for (const AbstractMetaField *field : fields) { if (!field->isStatic()) continue; - s << INDENT << QLatin1String("PyDict_SetItemString(") + cpythonTypeName(metaClass) + QLatin1String(".super.ht_type.tp_dict, \""); + s << INDENT << QLatin1String("PyDict_SetItemString(PepType(") + cpythonTypeName(metaClass) + QLatin1String(")->tp_dict, \""); s << field->name() << "\", "; writeToPythonConversion(s, field->type(), metaClass, metaClass->qualifiedCppName() + QLatin1String("::") + field->name()); s << ");" << endl; @@ -4969,8 +4930,8 @@ void CppGenerator::writeClassRegister(QTextStream &s, } if (usePySideExtensions() && metaClass->isQObject()) { - s << INDENT << "Shiboken::ObjectType::setSubTypeInitHook(&" << pyTypeName << ", &PySide::initQObjectSubType);" << endl; - s << INDENT << "PySide::initDynamicMetaObject(&" << pyTypeName << ", &::" << metaClass->qualifiedCppName() + s << INDENT << "Shiboken::ObjectType::setSubTypeInitHook(" << pyTypeName << ", &PySide::initQObjectSubType);" << endl; + s << INDENT << "PySide::initDynamicMetaObject(" << pyTypeName << ", &::" << metaClass->qualifiedCppName() << "::staticMetaObject, sizeof(::" << metaClass->qualifiedCppName() << "));" << endl; } @@ -5163,7 +5124,7 @@ void CppGenerator::writeGetattroFunction(QTextStream& s, GeneratorContext &conte s << INDENT << "if (Shiboken::Object::isUserType(" PYTHON_SELF_VAR ")) {" << endl; { Indentation indent(INDENT); - s << INDENT << "PyObject* meth = PyDict_GetItem(" PYTHON_SELF_VAR "->ob_type->tp_dict, name);" << endl; + s << INDENT << "PyObject* meth = PyDict_GetItem(PepType(Py_TYPE(" PYTHON_SELF_VAR "))->tp_dict, name);" << endl; s << INDENT << "if (meth)" << endl; { Indentation indent(INDENT); @@ -5228,7 +5189,7 @@ void CppGenerator::writeGetattroFunction(QTextStream& s, GeneratorContext &conte s << INDENT << "PyTypeObject *tp = Py_TYPE(self);" << endl; s << INDENT << "PyErr_Format(PyExc_AttributeError," << endl; s << INDENT << " \"'%.50s' object has no attribute '%.400s'\"," << endl; - s << INDENT << " tp->tp_name, PyBytes_AS_STRING(name));" << endl; + s << INDENT << " PepType(tp)->tp_name, PyBytes_AS_STRING(name));" << endl; s << INDENT << "return NULL;" << endl; } s << INDENT << "} else {" << endl; @@ -5308,7 +5269,7 @@ bool CppGenerator::finishGeneration() QString defineStr = QLatin1String("init_") + cls->qualifiedCppName().replace(QLatin1String("::"), QLatin1String("_")); if (cls->enclosingClass() && (cls->enclosingClass()->typeEntry()->codeGeneration() != TypeEntry::GenerateForSubclass)) - defineStr += QLatin1Char('(') + cpythonTypeNameExt(cls->enclosingClass()->typeEntry()) + QLatin1String("->tp_dict);"); + defineStr += QLatin1String("(PepType(") + cpythonTypeNameExt(cls->enclosingClass()->typeEntry()) + QLatin1String(")->tp_dict);"); else defineStr += QLatin1String("(module);"); s_classPythonDefines << INDENT << defineStr << endl; @@ -5854,10 +5815,12 @@ QString CppGenerator::writeReprFunction(QTextStream &s, GeneratorContext &contex s << INDENT << "if (idx >= 0)" << endl; { Indentation indent(INDENT); - s << INDENT << "str.replace(0, idx, Py_TYPE(self)->tp_name);" << endl; + s << INDENT << "str.replace(0, idx, PepType((Py_TYPE(self)))->tp_name);" << endl; } - s << INDENT << "PyObject* mod = PyDict_GetItemString(Py_TYPE(self)->tp_dict, \"__module__\");" << endl; - s << INDENT << "if (mod)" << endl; + s << INDENT << "PyObject* mod = PyDict_GetItemString(PepType(Py_TYPE(self))->tp_dict, \"__module__\");" << endl; + // PYSIDE-595: The introduction of heap types has the side effect that the module name + // is always prepended to the type name. Therefore the strchr check: + s << INDENT << "if (mod && !strchr(str, '.'))" << endl; { Indentation indent(INDENT); s << INDENT << "return Shiboken::String::fromFormat(\"<%s.%s at %p>\", Shiboken::String::toCString(mod), str.constData(), self);" << endl; diff --git a/sources/shiboken2/generator/shiboken2/shibokengenerator.cpp b/sources/shiboken2/generator/shiboken2/shibokengenerator.cpp index 6165ef009..976b34141 100644 --- a/sources/shiboken2/generator/shiboken2/shibokengenerator.cpp +++ b/sources/shiboken2/generator/shiboken2/shibokengenerator.cpp @@ -804,7 +804,7 @@ QString ShibokenGenerator::cpythonTypeName(const AbstractMetaClass* metaClass) QString ShibokenGenerator::cpythonTypeName(const TypeEntry* type) { - return cpythonBaseName(type) + QLatin1String("_Type"); + return cpythonBaseName(type) + QLatin1String("_TypeF()"); } QString ShibokenGenerator::cpythonTypeNameExt(const TypeEntry* type) @@ -838,7 +838,7 @@ QString ShibokenGenerator::converterObject(const TypeEntry* type) if (isCppPrimitive(type)) return QString::fromLatin1("Shiboken::Conversions::PrimitiveTypeConverter<%1>()").arg(type->qualifiedCppName()); if (isWrapperType(type) || type->isEnum() || type->isFlags()) - return QString::fromLatin1("SBK_CONVERTER(%1)").arg(cpythonTypeNameExt(type)); + return QString::fromLatin1("*PepType_SGTP(%1)->converter").arg(cpythonTypeNameExt(type)); if (type->isArray()) { qDebug() << "Warning: no idea how to handle the Qt5 type " << type->qualifiedCppName(); @@ -1164,7 +1164,7 @@ QString ShibokenGenerator::cpythonCheckFunction(const AbstractMetaType* metaType if (isPointerToWrapperType(type)) { typeCheck += QString::fromLatin1("checkSequenceTypes(%1, ").arg(cpythonTypeNameExt(type)); } else if (isWrapperType(type)) { - typeCheck += QLatin1String("convertibleSequenceTypes(reinterpret_cast<const SbkObjectType *>("); + typeCheck += QLatin1String("convertibleSequenceTypes(reinterpret_cast<SbkObjectType *>("); typeCheck += cpythonTypeNameExt(type); typeCheck += QLatin1String("), "); } else { @@ -1287,7 +1287,7 @@ QString ShibokenGenerator::cpythonIsConvertibleFunction(const AbstractMetaType* result += QLatin1String("isPythonToCppReferenceConvertible"); else result += QLatin1String("isPythonToCppValueConvertible"); - result += QLatin1String("(reinterpret_cast<const SbkObjectType *>(") + result += QLatin1String("(reinterpret_cast<SbkObjectType *>(") + cpythonTypeNameExt(metaType) + QLatin1String("), "); return result; } @@ -1341,7 +1341,7 @@ QString ShibokenGenerator::cpythonToPythonConversionFunction(const AbstractMetaT else conversion = QLatin1String("pointer"); QString result = QLatin1String("Shiboken::Conversions::") + conversion - + QLatin1String("ToPython(reinterpret_cast<const SbkObjectType *>(") + + QLatin1String("ToPython(reinterpret_cast<SbkObjectType *>(") + cpythonTypeNameExt(type) + QLatin1String("), "); if (conversion != QLatin1String("pointer")) result += QLatin1Char('&'); @@ -1362,7 +1362,7 @@ QString ShibokenGenerator::cpythonToPythonConversionFunction(const TypeEntry* ty if (isWrapperType(type)) { const QString conversion = type->isValue() ? QLatin1String("copy") : QLatin1String("pointer"); QString result = QLatin1String("Shiboken::Conversions::") + conversion - + QLatin1String("ToPython(reinterpret_cast<const SbkObjectType *>(") + cpythonTypeNameExt(type) + + QLatin1String("ToPython(reinterpret_cast<SbkObjectType *>(") + cpythonTypeNameExt(type) + QLatin1String("), "); if (conversion != QLatin1String("pointer")) result += QLatin1Char('&'); @@ -1625,7 +1625,7 @@ void ShibokenGenerator::processCodeSnip(QString& code, const AbstractMetaClass* // Replace template variable by the Python Type object // for the class context in which the variable is used. code.replace(QLatin1String("%PYTHONTYPEOBJECT"), - cpythonTypeName(context) + QLatin1String(".super.ht_type")); + cpythonTypeName(context) + QLatin1String("->type")); code.replace(QLatin1String("%TYPE"), wrapperName(context)); code.replace(QLatin1String("%CPPTYPE"), context->name()); } @@ -1856,7 +1856,7 @@ void ShibokenGenerator::writeCodeSnips(QTextStream& s, // class implementing the method in which the code snip is written if (func->isStatic()) { code.replace(QLatin1String("%PYTHONTYPEOBJECT"), - cpythonTypeName(func->implementingClass()) + QLatin1String(".super.ht_type")); + cpythonTypeName(func->implementingClass()) + QLatin1String("->type")); } else { code.replace(QLatin1String("%PYTHONTYPEOBJECT."), pySelf + QLatin1String("->ob_type->")); code.replace(QLatin1String("%PYTHONTYPEOBJECT"), pySelf + QLatin1String("->ob_type")); diff --git a/sources/shiboken2/libshiboken/CMakeLists.txt b/sources/shiboken2/libshiboken/CMakeLists.txt index e87cf07fd..b5ba78e15 100644 --- a/sources/shiboken2/libshiboken/CMakeLists.txt +++ b/sources/shiboken2/libshiboken/CMakeLists.txt @@ -48,7 +48,10 @@ threadstatesaver.cpp shibokenbuffer.cpp signature.cpp qapp_macro.cpp +pep384impl.cpp voidptr.cpp +typespec.cpp +bufferprocs27.cpp ) get_numpy_location() @@ -89,9 +92,12 @@ install(FILES threadstatesaver.h shibokenbuffer.h sbkpython.h + pep384impl.h signature.h qapp_macro.h voidptr.h + typespec.h + bufferprocs27.h "${CMAKE_CURRENT_BINARY_DIR}/sbkversion.h" DESTINATION include/shiboken2${shiboken2_SUFFIX}) install(TARGETS libshiboken EXPORT shiboken2 diff --git a/sources/shiboken2/libshiboken/autodecref.h b/sources/shiboken2/libshiboken/autodecref.h index 1f3f41eab..7b6aa47da 100644 --- a/sources/shiboken2/libshiboken/autodecref.h +++ b/sources/shiboken2/libshiboken/autodecref.h @@ -79,7 +79,9 @@ public: /// Returns the pointer of the Python object being held. inline PyObject* object() { return m_pyObj; } inline operator PyObject*() { return m_pyObj; } +#ifndef Py_LIMITED_API inline operator PyTupleObject*() { return reinterpret_cast<PyTupleObject*>(m_pyObj); } +#endif inline operator bool() const { return m_pyObj != 0; } inline PyObject* operator->() { return m_pyObj; } diff --git a/sources/shiboken2/libshiboken/basewrapper.cpp b/sources/shiboken2/libshiboken/basewrapper.cpp index 21f6933d2..0e2712ec8 100644 --- a/sources/shiboken2/libshiboken/basewrapper.cpp +++ b/sources/shiboken2/libshiboken/basewrapper.cpp @@ -66,55 +66,34 @@ extern "C" static void SbkObjectTypeDealloc(PyObject* pyObj); static PyObject* SbkObjectTypeTpNew(PyTypeObject* metatype, PyObject* args, PyObject* kwds); -PyTypeObject SbkObjectType_Type = { - PyVarObject_HEAD_INIT(0, 0) - /*tp_name*/ "Shiboken.ObjectType", - /*tp_basicsize*/ sizeof(SbkObjectType), - /*tp_itemsize*/ 0, - /*tp_dealloc*/ SbkObjectTypeDealloc, - /*tp_print*/ 0, - /*tp_getattr*/ 0, - /*tp_setattr*/ 0, - /*tp_compare*/ 0, - /*tp_repr*/ 0, - /*tp_as_number*/ 0, - /*tp_as_sequence*/ 0, - /*tp_as_mapping*/ 0, - /*tp_hash*/ 0, - /*tp_call*/ 0, - /*tp_str*/ 0, - /*tp_getattro*/ 0, - /*tp_setattro*/ PyObject_GenericSetAttr, - /*tp_as_buffer*/ 0, - /*tp_flags*/ Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE, - /*tp_doc*/ 0, - /*tp_traverse*/ 0, - /*tp_clear*/ 0, - /*tp_richcompare*/ 0, - /*tp_weaklistoffset*/ 0, - /*tp_iter*/ 0, - /*tp_iternext*/ 0, - /*tp_methods*/ 0, - /*tp_members*/ 0, - /*tp_getset*/ 0, - /*tp_base*/ &PyType_Type, - /*tp_dict*/ 0, - /*tp_descr_get*/ 0, - /*tp_descr_set*/ 0, - /*tp_dictoffset*/ 0, - /*tp_init*/ 0, - /*tp_alloc*/ PyType_GenericAlloc, - /*tp_new*/ SbkObjectTypeTpNew, - /*tp_free*/ PyObject_GC_Del, - /*tp_is_gc*/ 0, - /*tp_bases*/ 0, - /*tp_mro*/ 0, - /*tp_cache*/ 0, - /*tp_subclasses*/ 0, - /*tp_weaklist*/ 0, - /*tp_del*/ 0, - /*tp_version_tag*/ 0 +static PyType_Slot SbkObjectType_Type_slots[] = { + {Py_tp_dealloc, (void *)SbkObjectTypeDealloc}, + {Py_tp_setattro, (void *)PyObject_GenericSetAttr}, + {Py_tp_base, (void *)&PyType_Type}, + {Py_tp_alloc, (void *)PyType_GenericAlloc}, + {Py_tp_new, (void *)SbkObjectTypeTpNew}, + {Py_tp_free, (void *)PyObject_GC_Del}, + {0, 0} }; +static PyType_Spec SbkObjectType_Type_spec = { + "Shiboken.ObjectType", + 0, // basicsize (inserted later) + sizeof(PyMemberDef), + Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE, + SbkObjectType_Type_slots, +}; + + +PyTypeObject *SbkObjectType_TypeF(void) +{ + static PyTypeObject *type = nullptr; + if (!type) { + SbkObjectType_Type_spec.basicsize = + PepHeapType_SIZE + sizeof(SbkObjectTypePrivate); + type = reinterpret_cast<PyTypeObject *>(PyType_FromSpec(&SbkObjectType_Type_spec)); + } + return type; +} static PyObject *SbkObjectGetDict(PyObject* pObj, void *) { @@ -176,57 +155,36 @@ static int SbkObject_clear(PyObject* self) return 0; } -SbkObjectType SbkObject_Type = { { { - PyVarObject_HEAD_INIT(&SbkObjectType_Type, 0) - /*tp_name*/ "Shiboken.Object", - /*tp_basicsize*/ sizeof(SbkObject), - /*tp_itemsize*/ 0, - /*tp_dealloc*/ SbkDeallocWrapperWithPrivateDtor, - /*tp_print*/ 0, - /*tp_getattr*/ 0, - /*tp_setattr*/ 0, - /*tp_compare*/ 0, - /*tp_repr*/ 0, - /*tp_as_number*/ 0, - /*tp_as_sequence*/ 0, - /*tp_as_mapping*/ 0, - /*tp_hash*/ 0, - /*tp_call*/ 0, - /*tp_str*/ 0, - /*tp_getattro*/ 0, - /*tp_setattro*/ 0, - /*tp_as_buffer*/ 0, - /*tp_flags*/ Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE|Py_TPFLAGS_HAVE_GC, - /*tp_doc*/ 0, - /*tp_traverse*/ SbkObject_traverse, - /*tp_clear*/ SbkObject_clear, - /*tp_richcompare*/ 0, - /*tp_weaklistoffset*/ offsetof(SbkObject, weakreflist), - /*tp_iter*/ 0, - /*tp_iternext*/ 0, - /*tp_methods*/ 0, - /*tp_members*/ 0, - /*tp_getset*/ SbkObjectGetSetList, - /*tp_base*/ 0, - /*tp_dict*/ 0, - /*tp_descr_get*/ 0, - /*tp_descr_set*/ 0, - /*tp_dictoffset*/ offsetof(SbkObject, ob_dict), - /*tp_init*/ 0, - /*tp_alloc*/ 0, - /*tp_new*/ 0, - /*tp_free*/ 0, - /*tp_is_gc*/ 0, - /*tp_bases*/ 0, - /*tp_mro*/ 0, - /*tp_cache*/ 0, - /*tp_subclasses*/ 0, - /*tp_weaklist*/ 0, - /*tp_del*/ 0, - /*tp_version_tag*/ 0 -}, }, - /*priv_data*/ 0 +static PyType_Slot SbkObject_Type_slots[] = { + {Py_tp_dealloc, (void *)SbkDeallocWrapperWithPrivateDtor}, + {Py_tp_traverse, (void *)SbkObject_traverse}, + {Py_tp_clear, (void *)SbkObject_clear}, + // unsupported: {Py_tp_weaklistoffset, (void *)offsetof(SbkObject, weakreflist)}, + {Py_tp_getset, (void *)SbkObjectGetSetList}, + // unsupported: {Py_tp_dictoffset, (void *)offsetof(SbkObject, ob_dict)}, + {0, 0} }; +static PyType_Spec SbkObject_Type_spec = { + "Shiboken.Object", + sizeof(SbkObject), + 0, + Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE|Py_TPFLAGS_HAVE_GC, + SbkObject_Type_slots, +}; + + +SbkObjectType *SbkObject_TypeF(void) +{ + static PyTypeObject *type = nullptr; + if (!type) { + type = reinterpret_cast<PyTypeObject *>(PyType_FromSpec(&SbkObject_Type_spec)); + Py_TYPE(type) = SbkObjectType_TypeF(); + Py_INCREF(Py_TYPE(type)); + PepType(type)->tp_weaklistoffset = offsetof(SbkObject, weakreflist); + PepType(type)->tp_dictoffset = offsetof(SbkObject, ob_dict); + } + return reinterpret_cast<SbkObjectType *>(type); +} static void SbkDeallocWrapperCommon(PyObject* pyObj, bool canDelete) @@ -237,8 +195,8 @@ 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->tp_dealloc == SbkDeallocWrapper - || pyType->tp_dealloc == SbkDeallocWrapperWithPrivateDtor); + bool needTypeDecref = (PyType_GetSlot(pyType, Py_tp_dealloc) == SbkDeallocWrapper + || PyType_GetSlot(pyType, Py_tp_dealloc) == SbkDeallocWrapperWithPrivateDtor); // Ensure that the GC is no longer tracking this object to avoid a // possible reentrancy problem. Since there are multiple steps involved @@ -257,10 +215,10 @@ static void SbkDeallocWrapperCommon(PyObject* pyObj, bool canDelete) // If I have ownership and is valid delete C++ pointer if (canDelete && sbkObj->d->hasOwnership && sbkObj->d->validCppObject) { - SbkObjectType* sbkType = reinterpret_cast<SbkObjectType*>(pyType); - if (sbkType->d->is_multicpp) { + SbkObjectTypePrivate *sotp = PepType_SOTP(pyType); + if (sotp->is_multicpp) { Shiboken::DeallocVisitor visitor(sbkObj); - Shiboken::walkThroughClassHierarchy(pyObj->ob_type, &visitor); + Shiboken::walkThroughClassHierarchy(Py_TYPE(pyObj), &visitor); } else { void* cptr = sbkObj->d->cptr[0]; Shiboken::Object::deallocData(sbkObj, true); @@ -268,7 +226,7 @@ static void SbkDeallocWrapperCommon(PyObject* pyObj, bool canDelete) Shiboken::ThreadStateSaver threadSaver; if (Py_IsInitialized()) threadSaver.save(); - sbkType->d->cpp_dtor(cptr); + sotp->cpp_dtor(cptr); } } else { Shiboken::Object::deallocData(sbkObj, true); @@ -297,91 +255,103 @@ void SbkDeallocWrapperWithPrivateDtor(PyObject* self) void SbkObjectTypeDealloc(PyObject* pyObj) { - SbkObjectType* sbkType = reinterpret_cast<SbkObjectType*>(pyObj); + SbkObjectTypePrivate *sotp = PepType_SOTP(pyObj); + PyTypeObject *type = reinterpret_cast<PyTypeObject*>(pyObj); PyObject_GC_UnTrack(pyObj); Py_TRASHCAN_SAFE_BEGIN(pyObj); - if (sbkType->d) { - if(sbkType->d->user_data && sbkType->d->d_func) { - sbkType->d->d_func(sbkType->d->user_data); - sbkType->d->user_data = 0; + if (sotp) { + if (sotp->user_data && sotp->d_func) { + sotp->d_func(sotp->user_data); + sotp->user_data = nullptr; } - free(sbkType->d->original_name); - sbkType->d->original_name = 0; - if (!Shiboken::ObjectType::isUserType(reinterpret_cast<PyTypeObject*>(sbkType))) - Shiboken::Conversions::deleteConverter(sbkType->d->converter); - delete sbkType->d; - sbkType->d = 0; + free(sotp->original_name); + sotp->original_name = nullptr; + if (!Shiboken::ObjectType::isUserType(type)) + Shiboken::Conversions::deleteConverter(sotp->converter); + delete sotp; + sotp = nullptr; } Py_TRASHCAN_SAFE_END(pyObj); } PyObject* SbkObjectTypeTpNew(PyTypeObject* metatype, PyObject* args, PyObject* kwds) { -#ifndef IS_PY3K // Check if all bases are new style before calling type.tp_new // Was causing gc assert errors in test_bug704.py when // this check happened after creating the type object. // Argument parsing take from type.tp_new code. + + // PYSIDE-595: Also check if all bases allow inheritance. + // Before we changed to heap types, it was sufficient to remove the + // Py_TPFLAGS_BASETYPE flag. That does not work, because PySide does + // not respect this flag itself! PyObject* name; PyObject* pyBases; PyObject* dict; static const char* kwlist[] = { "name", "bases", "dict", 0}; - if (!PyArg_ParseTupleAndKeywords(args, kwds, "SO!O!:sbktype", (char**)kwlist, + if (!PyArg_ParseTupleAndKeywords(args, kwds, "sO!O!:sbktype", (char**)kwlist, &name, &PyTuple_Type, &pyBases, &PyDict_Type, &dict)) return NULL; - for(int i=0, i_max=PyTuple_GET_SIZE(pyBases); i < i_max; i++) { + for (int i=0, i_max=PyTuple_GET_SIZE(pyBases); i < i_max; i++) { PyObject* baseType = PyTuple_GET_ITEM(pyBases, i); +#ifndef IS_PY3K if (PyClass_Check(baseType)) { - PyErr_Format(PyExc_TypeError, "Invalid base class used in type %s. PySide only support multiple inheritance from python new style class.", metatype->tp_name); + PyErr_Format(PyExc_TypeError, "Invalid base class used in type %s. " + "PySide only support multiple inheritance from python new style class.", PepType(metatype)->tp_name); return 0; } - } #endif + if (PepType(reinterpret_cast<PyTypeObject*>(baseType))->tp_new == SbkDummyNew) { + // PYSIDE-595: A base class does not allow inheritance. + return SbkDummyNew(metatype, args, kwds); + } + } // The meta type creates a new type when the Python programmer extends a wrapped C++ class. - SbkObjectType* newType = reinterpret_cast<SbkObjectType*>(PyType_Type.tp_new(metatype, args, kwds)); + newfunc type_new = reinterpret_cast<newfunc>(PepType(&PyType_Type)->tp_new); + SbkObjectType *newType = reinterpret_cast<SbkObjectType*>(type_new(metatype, args, kwds)); if (!newType) return 0; Shiboken::ObjectType::initPrivateData(newType); - SbkObjectTypePrivate* d = newType->d; + SbkObjectTypePrivate *sotp = PepType_SOTP(newType); std::list<SbkObjectType*> bases = Shiboken::getCppBaseClasses(reinterpret_cast<PyTypeObject*>(newType)); if (bases.size() == 1) { - SbkObjectTypePrivate* parentType = bases.front()->d; - d->mi_offsets = parentType->mi_offsets; - d->mi_init = parentType->mi_init; - d->mi_specialcast = parentType->mi_specialcast; - d->type_discovery = parentType->type_discovery; - d->cpp_dtor = parentType->cpp_dtor; - d->is_multicpp = 0; - d->converter = parentType->converter; + SbkObjectTypePrivate *parentType = PepType_SOTP(bases.front()); + sotp->mi_offsets = parentType->mi_offsets; + sotp->mi_init = parentType->mi_init; + sotp->mi_specialcast = parentType->mi_specialcast; + sotp->type_discovery = parentType->type_discovery; + sotp->cpp_dtor = parentType->cpp_dtor; + sotp->is_multicpp = 0; + sotp->converter = parentType->converter; } else { - d->mi_offsets = 0; - d->mi_init = 0; - d->mi_specialcast = 0; - d->type_discovery = 0; - d->cpp_dtor = 0; - d->is_multicpp = 1; - d->converter = 0; + sotp->mi_offsets = nullptr; + sotp->mi_init = nullptr; + sotp->mi_specialcast = nullptr; + sotp->type_discovery = nullptr; + sotp->cpp_dtor = nullptr; + sotp->is_multicpp = 1; + sotp->converter = nullptr; } if (bases.size() == 1) - d->original_name = strdup(bases.front()->d->original_name); + sotp->original_name = strdup(PepType_SOTP(bases.front())->original_name); else - d->original_name = strdup("object"); - d->user_data = 0; - d->d_func = 0; - d->is_user_type = 1; + sotp->original_name = strdup("object"); + sotp->user_data = nullptr; + sotp->d_func = nullptr; + sotp->is_user_type = 1; std::list<SbkObjectType*>::const_iterator it = bases.begin(); for (; it != bases.end(); ++it) { - if ((*it)->d->subtype_init) - (*it)->d->subtype_init(newType, args, kwds); + if (PepType_SOTP(*it)->subtype_init) + PepType_SOTP(*it)->subtype_init(newType, args, kwds); } return reinterpret_cast<PyObject*>(newType); @@ -392,18 +362,19 @@ static PyObject *_setupNew(SbkObject *self, PyTypeObject *subtype) Py_INCREF(reinterpret_cast<PyObject*>(subtype)); SbkObjectPrivate* d = new SbkObjectPrivate; - SbkObjectType* sbkType = reinterpret_cast<SbkObjectType*>(subtype); - int numBases = ((sbkType->d && sbkType->d->is_multicpp) ? Shiboken::getNumberOfCppBaseClasses(subtype) : 1); + SbkObjectTypePrivate * sotp = PepType_SOTP(subtype); + int numBases = ((sotp && sotp->is_multicpp) ? + Shiboken::getNumberOfCppBaseClasses(subtype) : 1); d->cptr = new void*[numBases]; - std::memset(d->cptr, 0, sizeof(void*)*numBases); + std::memset(d->cptr, 0, sizeof(void*) * size_t(numBases)); d->hasOwnership = 1; d->containsCppWrapper = 0; d->validCppObject = 0; - d->parentInfo = 0; - d->referredObjects = 0; + d->parentInfo = nullptr; + d->referredObjects = nullptr; d->cppObjectCreated = 0; - self->ob_dict = 0; - self->weakreflist = 0; + self->ob_dict = nullptr; + self->weakreflist = nullptr; self->d = d; return reinterpret_cast<PyObject*>(self); } @@ -422,18 +393,37 @@ PyObject* SbkQAppTpNew(PyTypeObject* subtype, PyObject *, PyObject *) // For qApp, we need to create a singleton Python object. // We cannot track this with the GC, because it is a static variable! - // Python2 has a weird handling of flags in derived classes that Python3 + // Python 2 has a weird handling of flags in derived classes that Python 3 // does not have. Observed with bug_307.py. // But it could theoretically also happen with Python3. // Therefore we enforce that there is no GC flag, ever! + + // PYSIDE-560: + // We avoid to use this in Python 3, because we have a hard time to get + // write access to these flags +#ifndef IS_PY3K if (PyType_HasFeature(subtype, Py_TPFLAGS_HAVE_GC)) { subtype->tp_flags &= ~Py_TPFLAGS_HAVE_GC; subtype->tp_free = PyObject_Del; } +#endif SbkObject* self = reinterpret_cast<SbkObject*>(MakeSingletonQAppWrapper(subtype)); return self == 0 ? 0 : _setupNew(self, subtype); } +void +SbkDummyDealloc(PyObject *) +{} + +PyObject * +SbkDummyNew(PyTypeObject *type, PyObject*, PyObject*) +{ + // PYSIDE-595: Give the same error as type_call does when tp_new is NULL. + PyErr_Format(PyExc_TypeError, + "cannot create '%.100s' instances ¯\\_(ツ)_/¯", + PepType(type)->tp_name); + return nullptr; +} } //extern "C" @@ -464,16 +454,16 @@ static void decRefPyObjectList(const std::list<PyObject*> &pyObj, PyObject* skip static void _walkThroughClassHierarchy(PyTypeObject* currentType, HierarchyVisitor* visitor) { - PyObject* bases = currentType->tp_bases; + PyObject* bases = PepType(currentType)->tp_bases; Py_ssize_t numBases = PyTuple_GET_SIZE(bases); for (int i = 0; i < numBases; ++i) { PyTypeObject* type = reinterpret_cast<PyTypeObject*>(PyTuple_GET_ITEM(bases, i)); - if (!PyType_IsSubtype(type, reinterpret_cast<PyTypeObject*>(&SbkObject_Type))) { + if (!PyType_IsSubtype(type, reinterpret_cast<PyTypeObject*>(SbkObject_TypeF()))) { continue; } else { SbkObjectType* sbkType = reinterpret_cast<SbkObjectType*>(type); - if (sbkType->d->is_user_type) + if (PepType_SOTP(sbkType)->is_user_type) _walkThroughClassHierarchy(type, visitor); else visitor->visit(sbkType); @@ -532,7 +522,7 @@ void DtorCallerVisitor::done() for (; it != m_ptrs.end(); ++it) { Shiboken::ThreadStateSaver threadSaver; threadSaver.save(); - it->second->d->cpp_dtor(it->first); + PepType_SOTP(it->second)->cpp_dtor(it->first); } } @@ -555,15 +545,17 @@ void init() PyEval_InitThreads(); //Init private data - Shiboken::ObjectType::initPrivateData(&SbkObject_Type); + Pep_Init(); + + Shiboken::ObjectType::initPrivateData(SbkObject_TypeF()); - if (PyType_Ready(&SbkEnumType_Type) < 0) + if (PyType_Ready(SbkEnumType_TypeF()) < 0) Py_FatalError("[libshiboken] Failed to initialise Shiboken.SbkEnumType metatype."); - if (PyType_Ready(&SbkObjectType_Type) < 0) + if (PyType_Ready(SbkObjectType_TypeF()) < 0) Py_FatalError("[libshiboken] Failed to initialise Shiboken.BaseWrapperType metatype."); - if (PyType_Ready(reinterpret_cast<PyTypeObject *>(&SbkObject_Type)) < 0) + if (PyType_Ready(reinterpret_cast<PyTypeObject *>(SbkObject_TypeF())) < 0) Py_FatalError("[libshiboken] Failed to initialise Shiboken.BaseWrapper type."); VoidPtr::init(); @@ -581,10 +573,10 @@ void setErrorAboutWrongArguments(PyObject* args, const char* funcName, const cha if (i) params += ", "; PyObject* arg = PyTuple_GET_ITEM(args, i); - params += arg->ob_type->tp_name; + params += PepType((Py_TYPE(arg)))->tp_name; } } else { - params = args->ob_type->tp_name; + params = PepType((Py_TYPE(args)))->tp_name; } } @@ -660,12 +652,12 @@ namespace ObjectType bool checkType(PyTypeObject* type) { - return PyType_IsSubtype(type, reinterpret_cast<PyTypeObject*>(&SbkObject_Type)) != 0; + return PyType_IsSubtype(type, reinterpret_cast<PyTypeObject*>(SbkObject_TypeF())) != 0; } bool isUserType(PyTypeObject* type) { - return checkType(type) && reinterpret_cast<SbkObjectType*>(type)->d->is_user_type; + return checkType(type) && PepType_SOTP(type)->is_user_type; } bool canCallConstructor(PyTypeObject* myType, PyTypeObject* ctorType) @@ -673,7 +665,7 @@ bool canCallConstructor(PyTypeObject* myType, PyTypeObject* ctorType) FindBaseTypeVisitor visitor(ctorType); walkThroughClassHierarchy(myType, &visitor); if (!visitor.found()) { - PyErr_Format(PyExc_TypeError, "%s isn't a direct base class of %s", ctorType->tp_name, myType->tp_name); + PyErr_Format(PyExc_TypeError, "%s isn't a direct base class of %s", PepType(ctorType)->tp_name, PepType(myType)->tp_name); return false; } return true; @@ -681,114 +673,133 @@ bool canCallConstructor(PyTypeObject* myType, PyTypeObject* ctorType) bool hasCast(SbkObjectType* type) { - return type->d->mi_specialcast != 0; + return PepType_SOTP(type)->mi_specialcast != 0; } void* cast(SbkObjectType* sourceType, SbkObject* obj, PyTypeObject* targetType) { - return sourceType->d->mi_specialcast(Object::cppPointer(obj, targetType), reinterpret_cast<SbkObjectType*>(targetType)); + return PepType_SOTP(sourceType)->mi_specialcast(Object::cppPointer(obj, targetType), + reinterpret_cast<SbkObjectType*>(targetType)); } void setCastFunction(SbkObjectType* type, SpecialCastFunction func) { - type->d->mi_specialcast = func; + PepType_SOTP(type)->mi_specialcast = func; } -void setOriginalName(SbkObjectType* self, const char* name) +void setOriginalName(SbkObjectType* type, const char* name) { - if (self->d->original_name) - free(self->d->original_name); - self->d->original_name = strdup(name); + SbkObjectTypePrivate *sotp = PepType_SOTP(type); + if (sotp->original_name) + free(sotp->original_name); + sotp->original_name = strdup(name); } -const char* getOriginalName(SbkObjectType* self) +const char* getOriginalName(SbkObjectType* type) { - return self->d->original_name; + return PepType_SOTP(type)->original_name; } -void setTypeDiscoveryFunctionV2(SbkObjectType* self, TypeDiscoveryFuncV2 func) +void setTypeDiscoveryFunctionV2(SbkObjectType* type, TypeDiscoveryFuncV2 func) { - self->d->type_discovery = func; + PepType_SOTP(type)->type_discovery = func; } -void copyMultimpleheritance(SbkObjectType* self, SbkObjectType* other) +void copyMultimpleheritance(SbkObjectType* type, SbkObjectType* other) { - self->d->mi_init = other->d->mi_init; - self->d->mi_offsets = other->d->mi_offsets; - self->d->mi_specialcast = other->d->mi_specialcast; + PepType_SOTP(type)->mi_init = PepType_SOTP(other)->mi_init; + PepType_SOTP(type)->mi_offsets = PepType_SOTP(other)->mi_offsets; + PepType_SOTP(type)->mi_specialcast = PepType_SOTP(other)->mi_specialcast; } -void setMultipleIheritanceFunction(SbkObjectType* self, MultipleInheritanceInitFunction function) +void setMultipleInheritanceFunction(SbkObjectType* type, MultipleInheritanceInitFunction function) { - self->d->mi_init = function; + PepType_SOTP(type)->mi_init = function; } -MultipleInheritanceInitFunction getMultipleIheritanceFunction(SbkObjectType* self) +MultipleInheritanceInitFunction getMultipleIheritanceFunction(SbkObjectType* type) { - return self->d->mi_init; + return PepType_SOTP(type)->mi_init; } -void setDestructorFunction(SbkObjectType* self, ObjectDestructor func) +void setDestructorFunction(SbkObjectType* type, ObjectDestructor func) { - self->d->cpp_dtor = func; + PepType_SOTP(type)->cpp_dtor = func; } -void initPrivateData(SbkObjectType* self) +void initPrivateData(SbkObjectType* type) { - self->d = new SbkObjectTypePrivate; - memset(self->d, 0, sizeof(SbkObjectTypePrivate)); + PepType_SOTP(type) = new SbkObjectTypePrivate; + memset(PepType_SOTP(type), 0, sizeof(SbkObjectTypePrivate)); } -bool introduceWrapperType(PyObject *enclosingObject, - const char *typeName, const char *originalName, - SbkObjectType *type, - const char *signaturesString, - ObjectDestructor cppObjDtor, - SbkObjectType *baseType, PyObject *baseTypes, - bool isInnerClass) +SbkObjectType * +introduceWrapperType(PyObject *enclosingObject, + const char *typeName, + const char *originalName, + PyType_Spec *typeSpec, + const char *signaturesString, + ObjectDestructor cppObjDtor, + SbkObjectType *baseType, + PyObject *baseTypes, + bool isInnerClass) { - initPrivateData(type); - setOriginalName(type, originalName); - setDestructorFunction(type, cppObjDtor); - if (baseType) { - type->super.ht_type.tp_base = reinterpret_cast<PyTypeObject *>(baseType); + typeSpec->slots[0].pfunc = reinterpret_cast<void *>(baseType); + } + else { + typeSpec->slots[0].pfunc = reinterpret_cast<void *>(SbkObject_TypeF()); + } + PyObject *heaptype = PyType_FromSpecWithBases(typeSpec, baseTypes); + Py_TYPE(heaptype) = SbkObjectType_TypeF(); + Py_INCREF(Py_TYPE(heaptype)); + SbkObjectType *type = reinterpret_cast<SbkObjectType *>(heaptype); + if (baseType) { if (baseTypes) { for (int i = 0; i < PySequence_Fast_GET_SIZE(baseTypes); ++i) BindingManager::instance().addClassInheritance(reinterpret_cast<SbkObjectType *>(PySequence_Fast_GET_ITEM(baseTypes, i)), type); - type->super.ht_type.tp_bases = baseTypes; } else { BindingManager::instance().addClassInheritance(baseType, type); } } - - // PySide-510 - // here is the single change to support signatures. + // PYSIDE-510: Here is the single change to support signatures. if (SbkSpecial_Type_Ready(enclosingObject, reinterpret_cast<PyTypeObject *>(type), signaturesString) < 0) - return false; + return nullptr; - if (isInnerClass) - return PyDict_SetItemString(enclosingObject, typeName, reinterpret_cast<PyObject *>(type)) == 0; + initPrivateData(type); + setOriginalName(type, originalName); + setDestructorFunction(type, cppObjDtor); + + if (isInnerClass) { + if (PyDict_SetItemString(enclosingObject, typeName, reinterpret_cast<PyObject *>(type)) == 0) + return type; + else + return nullptr; + } //PyModule_AddObject steals type's reference. Py_INCREF(reinterpret_cast<PyObject *>(type)); - return PyModule_AddObject(enclosingObject, typeName, reinterpret_cast<PyObject *>(type)) == 0; + if (PyModule_AddObject(enclosingObject, typeName, reinterpret_cast<PyObject *>(type)) == 0) { + return type; + } + return nullptr; } -void setSubTypeInitHook(SbkObjectType* self, SubTypeInitHook func) +void setSubTypeInitHook(SbkObjectType* type, SubTypeInitHook func) { - self->d->subtype_init = func; + PepType_SOTP(type)->subtype_init = func; } -void* getTypeUserData(SbkObjectType* self) +void* getTypeUserData(SbkObjectType* type) { - return self->d->user_data; + return PepType_SOTP(type)->user_data; } -void setTypeUserData(SbkObjectType* self, void* userData, DeleteUserDataFunc d_func) +void setTypeUserData(SbkObjectType* type, void* userData, DeleteUserDataFunc d_func) { - self->d->user_data = userData; - self->d->d_func = d_func; + SbkObjectTypePrivate *sotp = PepType_SOTP(type); + sotp->user_data = userData; + sotp->d_func = d_func; } } // namespace ObjectType @@ -801,12 +812,12 @@ static void recursive_invalidate(SbkObject* self, std::set<SbkObject*>& seen); bool checkType(PyObject* pyObj) { - return ObjectType::checkType(pyObj->ob_type); + return ObjectType::checkType(Py_TYPE(pyObj)); } bool isUserType(PyObject* pyObj) { - return ObjectType::isUserType(pyObj->ob_type); + return ObjectType::isUserType(Py_TYPE(pyObj)); } Py_hash_t hash(PyObject* pyObj) @@ -858,14 +869,15 @@ bool wasCreatedByPython(SbkObject* pyObj) void callCppDestructors(SbkObject* pyObj) { - SbkObjectType* sbkType = reinterpret_cast<SbkObjectType*>(Py_TYPE(pyObj)); - if (sbkType->d->is_multicpp) { + PyTypeObject *type = Py_TYPE(pyObj); + SbkObjectTypePrivate * sotp = PepType_SOTP(type); + if (sotp->is_multicpp) { Shiboken::DtorCallerVisitor visitor(pyObj); - Shiboken::walkThroughClassHierarchy(Py_TYPE(pyObj), &visitor); + Shiboken::walkThroughClassHierarchy(type, &visitor); } else { Shiboken::ThreadStateSaver threadSaver; threadSaver.save(); - sbkType->d->cpp_dtor(pyObj->d->cptr[0]); + sotp->cpp_dtor(pyObj->d->cptr[0]); } /* invalidate needs to be called before deleting pointer array because @@ -916,7 +928,7 @@ void releaseOwnership(SbkObject* self) { // skip if the ownership have already moved to c++ SbkObjectType* selfType = reinterpret_cast<SbkObjectType*>(Py_TYPE(self)); - if (!self->d->hasOwnership || Shiboken::Conversions::pythonTypeIsValueType(selfType->d->converter)) + if (!self->d->hasOwnership || Shiboken::Conversions::pythonTypeIsValueType(PepType_SOTP(selfType)->converter)) return; // remove object ownership @@ -1037,7 +1049,7 @@ void* cppPointer(SbkObject* pyObj, PyTypeObject* desiredType) { PyTypeObject* type = Py_TYPE(pyObj); int idx = 0; - if (reinterpret_cast<SbkObjectType*>(type)->d->is_multicpp) + if (PepType_SOTP(reinterpret_cast<SbkObjectType*>(type))->is_multicpp) idx = getTypeIndexOnHierarchy(type, desiredType); if (pyObj->d->cptr) return pyObj->d->cptr[idx]; @@ -1057,8 +1069,9 @@ std::vector<void*> cppPointers(SbkObject* pyObj) bool setCppPointer(SbkObject* sbkObj, PyTypeObject* desiredType, void* cptr) { int idx = 0; - if (reinterpret_cast<SbkObjectType*>(Py_TYPE(sbkObj))->d->is_multicpp) - idx = getTypeIndexOnHierarchy(Py_TYPE(sbkObj), desiredType); + PyTypeObject *type = Py_TYPE(sbkObj); + if (PepType_SOTP(type)->is_multicpp) + idx = getTypeIndexOnHierarchy(type, desiredType); const bool alreadyInitialized = sbkObj->d->cptr[idx] != 0; if (alreadyInitialized) @@ -1073,19 +1086,21 @@ bool setCppPointer(SbkObject* sbkObj, PyTypeObject* desiredType, void* cptr) bool isValid(PyObject* pyObj) { if (!pyObj || pyObj == Py_None - || Py_TYPE(pyObj->ob_type) != &SbkObjectType_Type) { + || Py_TYPE(Py_TYPE(pyObj)) != SbkObjectType_TypeF()) { return true; } SbkObjectPrivate* priv = reinterpret_cast<SbkObject*>(pyObj)->d; if (!priv->cppObjectCreated && isUserType(pyObj)) { - PyErr_Format(PyExc_RuntimeError, "'__init__' method of object's base class (%s) not called.", pyObj->ob_type->tp_name); + PyErr_Format(PyExc_RuntimeError, "'__init__' method of object's base class (%s) not called.", + PepType((Py_TYPE(pyObj)))->tp_name); return false; } if (!priv->validCppObject) { - PyErr_Format(PyExc_RuntimeError, "Internal C++ object (%s) already deleted.", pyObj->ob_type->tp_name); + PyErr_Format(PyExc_RuntimeError, "Internal C++ object (%s) already deleted.", + PepType((Py_TYPE(pyObj)))->tp_name); return false; } @@ -1100,13 +1115,15 @@ bool isValid(SbkObject* pyObj, bool throwPyError) SbkObjectPrivate* priv = pyObj->d; if (!priv->cppObjectCreated && isUserType(reinterpret_cast<PyObject*>(pyObj))) { if (throwPyError) - PyErr_Format(PyExc_RuntimeError, "Base constructor of the object (%s) not called.", Py_TYPE(pyObj)->tp_name); + PyErr_Format(PyExc_RuntimeError, "Base constructor of the object (%s) not called.", + PepType((Py_TYPE(pyObj)))->tp_name); return false; } if (!priv->validCppObject) { if (throwPyError) - PyErr_Format(PyExc_RuntimeError, "Internal C++ object (%s) already deleted.", Py_TYPE(pyObj)->tp_name); + PyErr_Format(PyExc_RuntimeError, "Internal C++ object (%s) already deleted.", + PepType((Py_TYPE(pyObj)))->tp_name); return false; } @@ -1116,7 +1133,7 @@ bool isValid(SbkObject* pyObj, bool throwPyError) bool isValid(PyObject* pyObj, bool throwPyError) { if (!pyObj || pyObj == Py_None || - !PyType_IsSubtype(pyObj->ob_type, reinterpret_cast<PyTypeObject*>(&SbkObject_Type))) { + !PyType_IsSubtype(Py_TYPE(pyObj), reinterpret_cast<PyTypeObject*>(SbkObject_TypeF()))) { return true; } return isValid(reinterpret_cast<SbkObject*>(pyObj), throwPyError); @@ -1384,24 +1401,25 @@ void deallocData(SbkObject* self, bool cleanup) } delete self->d; // PYSIDE-205: always delete d. Py_XDECREF(self->ob_dict); + // PYSIDE-571: qApp is no longer allocated. - if (PyObject_IS_GC((PyObject*)self)) - Py_TYPE(self)->tp_free(self); + if (PyObject_IS_GC(reinterpret_cast<PyObject*>(self))) + PepType(Py_TYPE(self))->tp_free(self); } void setTypeUserData(SbkObject* wrapper, void* userData, DeleteUserDataFunc d_func) { - SbkObjectType* ob_type = reinterpret_cast<SbkObjectType*>(Py_TYPE(wrapper)); - if (ob_type->d->user_data) - ob_type->d->d_func(ob_type->d->user_data); + SbkObjectTypePrivate *sotp = PepType_SOTP(Py_TYPE(wrapper)); + if (sotp->user_data) + sotp->d_func(sotp->user_data); - ob_type->d->d_func = d_func; - ob_type->d->user_data = userData; + sotp->d_func = d_func; + sotp->user_data = userData; } void* getTypeUserData(SbkObject* wrapper) { - return reinterpret_cast<SbkObjectType*>(Py_TYPE(wrapper))->d->user_data; + return PepType_SOTP(Py_TYPE(wrapper))->user_data; } void keepReference(SbkObject* self, const char* key, PyObject* referredObject, bool append) @@ -1483,7 +1501,7 @@ std::string info(SbkObject* self) s << "C++ address....... "; std::list<SbkObjectType*>::const_iterator it = bases.begin(); for (int i = 0; it != bases.end(); ++it, ++i) - s << reinterpret_cast<PyTypeObject *>(*it)->tp_name << '/' << self->d->cptr[i] << ' '; + s << PepType((reinterpret_cast<PyTypeObject*>(*it)))->tp_name << '/' << self->d->cptr[i] << ' '; s << "\n"; } else { diff --git a/sources/shiboken2/libshiboken/basewrapper.h b/sources/shiboken2/libshiboken/basewrapper.h index fc553cf8c..755058e8b 100644 --- a/sources/shiboken2/libshiboken/basewrapper.h +++ b/sources/shiboken2/libshiboken/basewrapper.h @@ -93,22 +93,34 @@ typedef void (*ObjectDestructor)(void*); typedef void (*SubTypeInitHook)(SbkObjectType*, PyObject*, PyObject*); -extern LIBSHIBOKEN_API PyTypeObject SbkObjectType_Type; -extern LIBSHIBOKEN_API SbkObjectType SbkObject_Type; +extern LIBSHIBOKEN_API PyTypeObject *SbkObjectType_TypeF(void); +extern LIBSHIBOKEN_API SbkObjectType *SbkObject_TypeF(void); struct SbkObjectTypePrivate; /// PyTypeObject extended with C++ multiple inheritance information. struct LIBSHIBOKEN_API SbkObjectType { - PyHeapTypeObject super; - SbkObjectTypePrivate* d; + PepTypeObject type; }; LIBSHIBOKEN_API PyObject* SbkObjectTpNew(PyTypeObject* subtype, PyObject*, PyObject*); // the special case of a switchable singleton LIBSHIBOKEN_API PyObject* SbkQAppTpNew(PyTypeObject *subtype, PyObject *args, PyObject *kwds); +/** + * PYSIDE-595: Use a null deallocator instead of nullptr. + * + * When moving to heaptypes, we were struck by a special default behavior of + * PyType_FromSpecWithBases that inserts subtype_dealloc when tp_dealloc is + * nullptr. To prevent inserting this, we use a null deallocator that is there + * as a placeholder. + * + * The same holds for a null tp_new. We use one that raises the right error. + */ +LIBSHIBOKEN_API void SbkDummyDealloc(PyObject*); +LIBSHIBOKEN_API PyObject *SbkDummyNew(PyTypeObject *type, PyObject*, PyObject*); + } // extern "C" namespace Shiboken @@ -173,7 +185,7 @@ LIBSHIBOKEN_API const char* getOriginalName(SbkObjectType* self); LIBSHIBOKEN_API void setTypeDiscoveryFunctionV2(SbkObjectType* self, TypeDiscoveryFuncV2 func); LIBSHIBOKEN_API void copyMultimpleheritance(SbkObjectType* self, SbkObjectType* other); -LIBSHIBOKEN_API void setMultipleIheritanceFunction(SbkObjectType* self, MultipleInheritanceInitFunction func); +LIBSHIBOKEN_API void setMultipleInheritanceFunction(SbkObjectType* self, MultipleInheritanceInitFunction func); LIBSHIBOKEN_API MultipleInheritanceInitFunction getMultipleIheritanceFunction(SbkObjectType* self); LIBSHIBOKEN_API void setDestructorFunction(SbkObjectType* self, ObjectDestructor func); @@ -197,13 +209,15 @@ LIBSHIBOKEN_API void initPrivateData(SbkObjectType* self); * wrapper type. * \returns true if the initialization went fine, false otherwise. */ -LIBSHIBOKEN_API bool introduceWrapperType(PyObject* enclosingObject, - const char* typeName, const char* originalName, - SbkObjectType* type, - const char* signaturesString, - ObjectDestructor cppObjDtor = 0, - SbkObjectType* baseType = 0, PyObject* baseTypes = 0, - bool isInnerClass = false); +LIBSHIBOKEN_API SbkObjectType *introduceWrapperType(PyObject *enclosingObject, + const char *typeName, + const char *originalName, + PyType_Spec *typeSpec, + const char *signaturesString, + ObjectDestructor cppObjDtor, + SbkObjectType *baseType, + PyObject *baseTypes, + bool isInnerClass); /** * Set the subtype init hook for a type. diff --git a/sources/shiboken2/libshiboken/bindingmanager.cpp b/sources/shiboken2/libshiboken/bindingmanager.cpp index de3458ab5..5a3283ab5 100644 --- a/sources/shiboken2/libshiboken/bindingmanager.cpp +++ b/sources/shiboken2/libshiboken/bindingmanager.cpp @@ -83,8 +83,10 @@ public: SbkObjectType* node1 = i->first; const NodeList& nodeList = i->second; NodeList::const_iterator j = nodeList.begin(); - for (; j != nodeList.end(); ++j) - file << '"' << (*j)->super.ht_type.tp_name << "\" -> \"" << node1->super.ht_type.tp_name << "\"\n"; + for (; j != nodeList.end(); ++j) { + file << '"' << PepType(*j)->tp_name << "\" -> \"" + << PepType(node1)->tp_name << "\"\n"; + } } file << "}\n"; } @@ -102,7 +104,10 @@ public: return newType; } } - void* typeFound = ((type->d && type->d->type_discovery) ? type->d->type_discovery(*cptr, baseType) : 0); + void *typeFound = nullptr; + if (PepType_SOTP(type) && PepType_SOTP(type)->type_discovery) { + typeFound = PepType_SOTP(type)->type_discovery(*cptr, baseType); + } if (typeFound) { // This "typeFound != type" is needed for backwards compatibility with old modules using a newer version of // libshiboken because old versions of type_discovery function used to return a SbkObjectType* instead of @@ -111,7 +116,7 @@ public: *cptr = typeFound; return type; } else { - return 0; + return nullptr; } } }; @@ -128,7 +133,7 @@ static void showWrapperMap(const WrapperMap& wrapperMap) const SbkObject *sbkObj = iter->second; fprintf(stderr, "key: %p, value: %p (%s, refcnt: %d)\n", iter->first, static_cast<const void *>(sbkObj), - Py_TYPE(sbkObj)->tp_name, + PepType((Py_TYPE(sbkObj)))->tp_name, int(reinterpret_cast<const PyObject *>(sbkObj)->ob_refcnt)); } fprintf(stderr, "-------------------------------\n"); @@ -210,7 +215,7 @@ bool BindingManager::hasWrapper(const void* cptr) void BindingManager::registerWrapper(SbkObject* pyObj, void* cptr) { SbkObjectType* instanceType = reinterpret_cast<SbkObjectType*>(Py_TYPE(pyObj)); - SbkObjectTypePrivate* d = instanceType->d; + SbkObjectTypePrivate* d = PepType_SOTP(instanceType); if (!d) return; @@ -231,7 +236,7 @@ void BindingManager::registerWrapper(SbkObject* pyObj, void* cptr) void BindingManager::releaseWrapper(SbkObject* sbkObj) { SbkObjectType* sbkType = reinterpret_cast<SbkObjectType*>(Py_TYPE(sbkObj)); - SbkObjectTypePrivate* d = sbkType->d; + SbkObjectTypePrivate* d = PepType_SOTP(sbkType); int numBases = ((d && d->is_multicpp) ? getNumberOfCppBaseClasses(Py_TYPE(sbkObj)) : 1); void** cptrs = reinterpret_cast<SbkObject*>(sbkObj)->d->cptr; @@ -278,17 +283,17 @@ PyObject* BindingManager::getOverride(const void* cptr, const char* methodName) PyObject *method = PyObject_GetAttr(reinterpret_cast<PyObject *>(wrapper), pyMethodName); if (method && PyMethod_Check(method) - && reinterpret_cast<PyMethodObject*>(method)->im_self == reinterpret_cast<PyObject*>(wrapper)) { + && PyMethod_GET_SELF(method) == reinterpret_cast<PyObject*>(wrapper)) { PyObject* defaultMethod; - PyObject* mro = Py_TYPE(wrapper)->tp_mro; + PyObject* mro = PepType(Py_TYPE(wrapper))->tp_mro; // The first class in the mro (index 0) is the class being checked and it should not be tested. // The last class in the mro (size - 1) is the base Python object class which should not be tested also. for (int i = 1; i < PyTuple_GET_SIZE(mro) - 1; i++) { PyTypeObject* parent = reinterpret_cast<PyTypeObject*>(PyTuple_GET_ITEM(mro, i)); - if (parent->tp_dict) { - defaultMethod = PyDict_GetItem(parent->tp_dict, pyMethodName); - if (defaultMethod && reinterpret_cast<PyMethodObject*>(method)->im_func != defaultMethod) { + if (PepType(parent)->tp_dict) { + defaultMethod = PyDict_GetItem(PepType(parent)->tp_dict, pyMethodName); + if (defaultMethod && PyMethod_GET_FUNCTION(method) != defaultMethod) { Py_DECREF(pyMethodName); return method; } diff --git a/sources/shiboken2/libshiboken/bufferprocs27.cpp b/sources/shiboken2/libshiboken/bufferprocs27.cpp new file mode 100644 index 000000000..168a28a96 --- /dev/null +++ b/sources/shiboken2/libshiboken/bufferprocs27.cpp @@ -0,0 +1,397 @@ +/**************************************************************************** +** +** Copyright (C) 2018 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt for Python. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/***************************************************************************** + * + * Copied from abstract.c + * + * Py_buffer has been replaced by Pep_buffer + * + */ + +#ifdef Py_LIMITED_API + +#include "pep384impl.h" +/* Buffer C-API for Python 3.0 */ + +int +PyObject_GetBuffer(PyObject *obj, Pep_buffer *view, int flags) +{ + PyBufferProcs *pb = PepType_AS_BUFFER(Py_TYPE(obj)); + + if (pb == NULL || pb->bf_getbuffer == NULL) { + PyErr_Format(PyExc_TypeError, + "a bytes-like object is required, not '%.100s'", + PepType((Py_TYPE(obj)))->tp_name); + return -1; + } + return (*pb->bf_getbuffer)(obj, view, flags); +} + +static int +_IsFortranContiguous(const Pep_buffer *view) +{ + Py_ssize_t sd, dim; + int i; + + /* 1) len = product(shape) * itemsize + 2) itemsize > 0 + 3) len = 0 <==> exists i: shape[i] = 0 */ + if (view->len == 0) return 1; + if (view->strides == NULL) { /* C-contiguous by definition */ + /* Trivially F-contiguous */ + if (view->ndim <= 1) return 1; + + /* ndim > 1 implies shape != NULL */ + assert(view->shape != NULL); + + /* Effectively 1-d */ + sd = 0; + for (i=0; i<view->ndim; i++) { + if (view->shape[i] > 1) sd += 1; + } + return sd <= 1; + } + + /* strides != NULL implies both of these */ + assert(view->ndim > 0); + assert(view->shape != NULL); + + sd = view->itemsize; + for (i=0; i<view->ndim; i++) { + dim = view->shape[i]; + if (dim > 1 && view->strides[i] != sd) { + return 0; + } + sd *= dim; + } + return 1; +} + +static int +_IsCContiguous(const Pep_buffer *view) +{ + Py_ssize_t sd, dim; + int i; + + /* 1) len = product(shape) * itemsize + 2) itemsize > 0 + 3) len = 0 <==> exists i: shape[i] = 0 */ + if (view->len == 0) return 1; + if (view->strides == NULL) return 1; /* C-contiguous by definition */ + + /* strides != NULL implies both of these */ + assert(view->ndim > 0); + assert(view->shape != NULL); + + sd = view->itemsize; + for (i=view->ndim-1; i>=0; i--) { + dim = view->shape[i]; + if (dim > 1 && view->strides[i] != sd) { + return 0; + } + sd *= dim; + } + return 1; +} + +int +PyBuffer_IsContiguous(const Pep_buffer *view, char order) +{ + + if (view->suboffsets != NULL) return 0; + + if (order == 'C') + return _IsCContiguous(view); + else if (order == 'F') + return _IsFortranContiguous(view); + else if (order == 'A') + return (_IsCContiguous(view) || _IsFortranContiguous(view)); + return 0; +} + + +void* +PyBuffer_GetPointer(Pep_buffer *view, Py_ssize_t *indices) +{ + char* pointer; + int i; + pointer = (char *)view->buf; + for (i = 0; i < view->ndim; i++) { + pointer += view->strides[i]*indices[i]; + if ((view->suboffsets != NULL) && (view->suboffsets[i] >= 0)) { + pointer = *((char**)pointer) + view->suboffsets[i]; + } + } + return (void*)pointer; +} + + +void +_Py_add_one_to_index_F(int nd, Py_ssize_t *index, const Py_ssize_t *shape) +{ + int k; + + for (k=0; k<nd; k++) { + if (index[k] < shape[k]-1) { + index[k]++; + break; + } + else { + index[k] = 0; + } + } +} + +void +_Py_add_one_to_index_C(int nd, Py_ssize_t *index, const Py_ssize_t *shape) +{ + int k; + + for (k=nd-1; k>=0; k--) { + if (index[k] < shape[k]-1) { + index[k]++; + break; + } + else { + index[k] = 0; + } + } +} + +int +PyBuffer_FromContiguous(Pep_buffer *view, void *buf, Py_ssize_t len, char fort) +{ + int k; + void (*addone)(int, Py_ssize_t *, const Py_ssize_t *); + Py_ssize_t *indices, elements; + char *src, *ptr; + + if (len > view->len) { + len = view->len; + } + + if (PyBuffer_IsContiguous(view, fort)) { + /* simplest copy is all that is needed */ + memcpy(view->buf, buf, len); + return 0; + } + + /* Otherwise a more elaborate scheme is needed */ + + /* view->ndim <= 64 */ + indices = (Py_ssize_t *)PyMem_Malloc(sizeof(Py_ssize_t)*(view->ndim)); + if (indices == NULL) { + PyErr_NoMemory(); + return -1; + } + for (k=0; k<view->ndim;k++) { + indices[k] = 0; + } + + if (fort == 'F') { + addone = _Py_add_one_to_index_F; + } + else { + addone = _Py_add_one_to_index_C; + } + src = (char *)buf; // patched by CT + /* XXX : This is not going to be the fastest code in the world + several optimizations are possible. + */ + elements = len / view->itemsize; + while (elements--) { + ptr = (char *)PyBuffer_GetPointer(view, indices); // patched by CT + memcpy(ptr, src, view->itemsize); + src += view->itemsize; + addone(view->ndim, indices, view->shape); + } + + PyMem_Free(indices); + return 0; +} + +int PyObject_CopyData(PyObject *dest, PyObject *src) +{ + Pep_buffer view_dest, view_src; + int k; + Py_ssize_t *indices, elements; + char *dptr, *sptr; + + if (!PyObject_CheckBuffer(dest) || + !PyObject_CheckBuffer(src)) { + PyErr_SetString(PyExc_TypeError, + "both destination and source must be "\ + "bytes-like objects"); + return -1; + } + + if (PyObject_GetBuffer(dest, &view_dest, PyBUF_FULL) != 0) return -1; + if (PyObject_GetBuffer(src, &view_src, PyBUF_FULL_RO) != 0) { + PyBuffer_Release(&view_dest); + return -1; + } + + if (view_dest.len < view_src.len) { + PyErr_SetString(PyExc_BufferError, + "destination is too small to receive data from source"); + PyBuffer_Release(&view_dest); + PyBuffer_Release(&view_src); + return -1; + } + + if ((PyBuffer_IsContiguous(&view_dest, 'C') && + PyBuffer_IsContiguous(&view_src, 'C')) || + (PyBuffer_IsContiguous(&view_dest, 'F') && + PyBuffer_IsContiguous(&view_src, 'F'))) { + /* simplest copy is all that is needed */ + memcpy(view_dest.buf, view_src.buf, view_src.len); + PyBuffer_Release(&view_dest); + PyBuffer_Release(&view_src); + return 0; + } + + /* Otherwise a more elaborate copy scheme is needed */ + + /* XXX(nnorwitz): need to check for overflow! */ + indices = (Py_ssize_t *)PyMem_Malloc(sizeof(Py_ssize_t)*view_src.ndim); + if (indices == NULL) { + PyErr_NoMemory(); + PyBuffer_Release(&view_dest); + PyBuffer_Release(&view_src); + return -1; + } + for (k=0; k<view_src.ndim;k++) { + indices[k] = 0; + } + elements = 1; + for (k=0; k<view_src.ndim; k++) { + /* XXX(nnorwitz): can this overflow? */ + elements *= view_src.shape[k]; + } + while (elements--) { + _Py_add_one_to_index_C(view_src.ndim, indices, view_src.shape); + dptr = (char *)PyBuffer_GetPointer(&view_dest, indices); // patched by CT + sptr = (char *)PyBuffer_GetPointer(&view_src, indices); // patched by CT + memcpy(dptr, sptr, view_src.itemsize); + } + PyMem_Free(indices); + PyBuffer_Release(&view_dest); + PyBuffer_Release(&view_src); + return 0; +} + +void +PyBuffer_FillContiguousStrides(int nd, Py_ssize_t *shape, + Py_ssize_t *strides, int itemsize, + char fort) +{ + int k; + Py_ssize_t sd; + + sd = itemsize; + if (fort == 'F') { + for (k=0; k<nd; k++) { + strides[k] = sd; + sd *= shape[k]; + } + } + else { + for (k=nd-1; k>=0; k--) { + strides[k] = sd; + sd *= shape[k]; + } + } + return; +} + +int +PyBuffer_FillInfo(Pep_buffer *view, PyObject *obj, void *buf, Py_ssize_t len, + int readonly, int flags) +{ + if (view == NULL) { + PyErr_SetString(PyExc_BufferError, + "PyBuffer_FillInfo: view==NULL argument is obsolete"); + return -1; + } + + if (((flags & PyBUF_WRITABLE) == PyBUF_WRITABLE) && + (readonly == 1)) { + PyErr_SetString(PyExc_BufferError, + "Object is not writable."); + return -1; + } + + view->obj = obj; + if (obj) + Py_INCREF(obj); + view->buf = buf; + view->len = len; + view->readonly = readonly; + view->itemsize = 1; + view->format = NULL; + if ((flags & PyBUF_FORMAT) == PyBUF_FORMAT) + view->format = (char *)"B"; // patched by CT + view->ndim = 1; + view->shape = NULL; + if ((flags & PyBUF_ND) == PyBUF_ND) + view->shape = &(view->len); + view->strides = NULL; + if ((flags & PyBUF_STRIDES) == PyBUF_STRIDES) + view->strides = &(view->itemsize); + view->suboffsets = NULL; + view->internal = NULL; + return 0; +} + +void +PyBuffer_Release(Pep_buffer *view) +{ + PyObject *obj = view->obj; + PyBufferProcs *pb; + if (obj == NULL) + return; + pb = PepType_AS_BUFFER(Py_TYPE(obj)); + if (pb && pb->bf_releasebuffer) + pb->bf_releasebuffer(obj, view); + view->obj = NULL; + Py_DECREF(obj); +} + +#endif // Py_LIMITED_API diff --git a/sources/shiboken2/libshiboken/bufferprocs27.h b/sources/shiboken2/libshiboken/bufferprocs27.h new file mode 100644 index 000000000..83c4a4750 --- /dev/null +++ b/sources/shiboken2/libshiboken/bufferprocs27.h @@ -0,0 +1,144 @@ +/**************************************************************************** +** +** Copyright (C) 2018 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt for Python. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/* +PSF LICENSE AGREEMENT FOR PYTHON 3.6.5¶ +1. This LICENSE AGREEMENT is between the Python Software Foundation ("PSF"), and + the Individual or Organization ("Licensee") accessing and otherwise using Python + 3.6.2 software in source or binary form and its associated documentation. + +2. Subject to the terms and conditions of this License Agreement, PSF hereby + grants Licensee a nonexclusive, royalty-free, world-wide license to reproduce, + analyze, test, perform and/or display publicly, prepare derivative works, + distribute, and otherwise use Python 3.6.2 alone or in any derivative + version, provided, however, that PSF's License Agreement and PSF's notice of + copyright, i.e., "Copyright © 2001-2017 Python Software Foundation; All Rights + Reserved" are retained in Python 3.6.2 alone or in any derivative version + prepared by Licensee. + +3. In the event Licensee prepares a derivative work that is based on or + incorporates Python 3.6.2 or any part thereof, and wants to make the + derivative work available to others as provided herein, then Licensee hereby + agrees to include in any such work a brief summary of the changes made to Python + 3.6.2. + +4. PSF is making Python 3.6.2 available to Licensee on an "AS IS" basis. + PSF MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED. BY WAY OF + EXAMPLE, BUT NOT LIMITATION, PSF MAKES NO AND DISCLAIMS ANY REPRESENTATION OR + WARRANTY OF MERCHANTABILITY OR FITNESS FOR ANY PARTICULAR PURPOSE OR THAT THE + USE OF PYTHON 3.6.2 WILL NOT INFRINGE ANY THIRD PARTY RIGHTS. + +5. PSF SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF PYTHON 3.6.2 + FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS AS A RESULT OF + MODIFYING, DISTRIBUTING, OR OTHERWISE USING PYTHON 3.6.2, OR ANY DERIVATIVE + THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF. + +6. This License Agreement will automatically terminate upon a material breach of + its terms and conditions. + +7. Nothing in this License Agreement shall be deemed to create any relationship + of agency, partnership, or joint venture between PSF and Licensee. This License + Agreement does not grant permission to use PSF trademarks or trade name in a + trademark sense to endorse or promote products or services of Licensee, or any + third party. + +8. By copying, installing or otherwise using Python 3.6.2, Licensee agrees + to be bound by the terms and conditions of this License Agreement. +*/ + +#ifndef BUFFER_REENABLE_H +#define BUFFER_REENABLE_H + +/* buffer interface */ +// This has been renamed to Pep_buffer and will be used. +typedef struct bufferinfo { + void *buf; + PyObject *obj; /* owned reference */ + Py_ssize_t len; + Py_ssize_t itemsize; /* This is Py_ssize_t so it can be + pointed to by strides in simple case.*/ + int readonly; + int ndim; + char *format; + Py_ssize_t *shape; + Py_ssize_t *strides; + Py_ssize_t *suboffsets; + void *internal; +} Pep_buffer; + +typedef int (*getbufferproc)(PyObject *, Pep_buffer *, int); +typedef void (*releasebufferproc)(PyObject *, Pep_buffer *); + +/* Maximum number of dimensions */ +#define PyBUF_MAX_NDIM 64 + +/* Flags for getting buffers */ +#define PyBUF_SIMPLE 0 +#define PyBUF_WRITABLE 0x0001 +/* we used to include an E, backwards compatible alias */ +#define PyBUF_WRITEABLE PyBUF_WRITABLE +#define PyBUF_FORMAT 0x0004 +#define PyBUF_ND 0x0008 +#define PyBUF_STRIDES (0x0010 | PyBUF_ND) +#define PyBUF_C_CONTIGUOUS (0x0020 | PyBUF_STRIDES) +#define PyBUF_F_CONTIGUOUS (0x0040 | PyBUF_STRIDES) +#define PyBUF_ANY_CONTIGUOUS (0x0080 | PyBUF_STRIDES) +#define PyBUF_INDIRECT (0x0100 | PyBUF_STRIDES) + +#define PyBUF_CONTIG (PyBUF_ND | PyBUF_WRITABLE) +#define PyBUF_CONTIG_RO (PyBUF_ND) + +#define PyBUF_STRIDED (PyBUF_STRIDES | PyBUF_WRITABLE) +#define PyBUF_STRIDED_RO (PyBUF_STRIDES) + +#define PyBUF_RECORDS (PyBUF_STRIDES | PyBUF_WRITABLE | PyBUF_FORMAT) +#define PyBUF_RECORDS_RO (PyBUF_STRIDES | PyBUF_FORMAT) + +#define PyBUF_FULL (PyBUF_INDIRECT | PyBUF_WRITABLE | PyBUF_FORMAT) +#define PyBUF_FULL_RO (PyBUF_INDIRECT | PyBUF_FORMAT) + + +#define PyBUF_READ 0x100 +#define PyBUF_WRITE 0x200 + +/* End buffer interface */ +LIBSHIBOKEN_API PyObject *PyMemoryView_FromBuffer(Pep_buffer *info); +#define Py_buffer Pep_buffer + +#endif // BUFFER_REENABLE_H diff --git a/sources/shiboken2/libshiboken/pep384impl.cpp b/sources/shiboken2/libshiboken/pep384impl.cpp new file mode 100644 index 000000000..2707d3716 --- /dev/null +++ b/sources/shiboken2/libshiboken/pep384impl.cpp @@ -0,0 +1,924 @@ +/**************************************************************************** +** +** Copyright (C) 2018 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt for Python. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "pep384impl.h" + +extern "C" +{ + +/********************************************************************** + ********************************************************************** + + + The New Type API + ================ + + After converting everything but the "object.h" file, we could not + believe our eyes: it suddenly was clear that we would have no more + access to type objects, and even more scary that all types which we + use have to be heap types, only! + + For PySide with it's intense use of heap type extensions in various + flavors, it seemed to be quite unsolvable. In the end, it was + nicely solved, but it took almost 3.5 months to get that right. + + Before we see how this is done, we will explain the differences + between the APIs and their consequences. + + + The Interface + ------------- + + The old type API of Python knows static types and heap types. + Static types are written down as a declaration of a PyTypeObject + structure with all its fields filled in. Here is for example + the definition of the Python type "object": + + PyTypeObject PyBaseObject_Type = { + PyVarObject_HEAD_INIT(&PyType_Type, 0) + "object", |* tp_name *| + sizeof(PyObject), |* tp_basicsize *| + 0, |* tp_itemsize *| + object_dealloc, |* tp_dealloc *| + 0, |* tp_print *| + 0, |* tp_getattr *| + 0, |* tp_setattr *| + 0, |* tp_reserved *| + object_repr, |* tp_repr *| + 0, |* tp_as_number *| + 0, |* tp_as_sequence *| + 0, |* tp_as_mapping *| + (hashfunc)_Py_HashPointer, |* tp_hash *| + 0, |* tp_call *| + object_str, |* tp_str *| + PyObject_GenericGetAttr, |* tp_getattro *| + PyObject_GenericSetAttr, |* tp_setattro *| + 0, |* tp_as_buffer *| + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, |* tp_flags *| + PyDoc_STR("object()\n--\n\nThe most base type"), |* tp_doc *| + 0, |* tp_traverse *| + 0, |* tp_clear *| + object_richcompare, |* tp_richcompare *| + 0, |* tp_weaklistoffset *| + 0, |* tp_iter *| + 0, |* tp_iternext *| + object_methods, |* tp_methods *| + 0, |* tp_members *| + object_getsets, |* tp_getset *| + 0, |* tp_base *| + 0, |* tp_dict *| + 0, |* tp_descr_get *| + 0, |* tp_descr_set *| + 0, |* tp_dictoffset *| + object_init, |* tp_init *| + PyType_GenericAlloc, |* tp_alloc *| + object_new, |* tp_new *| + PyObject_Del, |* tp_free *| + }; + + We can write the same structure in form of a PyType_Spec structure, + and there is even a tool that does this for us, but I had to fix a + few things because there is little support for this. + + The tool is XXX go home and continue..... + + + + + The Transition To Simpler Types + =============================== + + After all code has been converted to the limited API, there is the + PyHeapTypeObject remaining as a problem. + + Why a problem? Well, all the type structures in shiboken use + special extra fields at the end of the heap type object. This + currently enforces knowledge at compile time about how large the + heap type object is. In a clean implementation, we would only use + the PyTypeObject itself and access the fields "behind" the type + by a pointer that is computed at runtime. + + + Excursion: PepTypeObject + ------------------------ + + Before we are going into details, let us motivate the existence of + the PepTypeObject, an alias to PyTypeObject: + + Originally, we wanted to use PyTypeObject as an opaque type and + restrict ourselves to only use the access function PyType_GetSlot. + This function allows access to all fields which are supported by + the limited API. + + But this is a restriction, because we get no access to tp_dict, + which we need to support the signature extension. But we can work + around that. + + The real restriction is that PyType_GetSlot only works for heap + types. This makes the function quite useless, because we have + no access to PyType_Type, which is the most important type "type" + in Python. We need that for instance to compute the size of + PyHeapTypeObject dynamically. + + With much effort, it is possible to clone PyType_Type as a heap + type. But due to a bug in the Pep 384 support, we need + access to the nb_index field of a normal type. Cloning does not + help because PyNumberMethods fields are not inherited. + + After I realized this dead end, I changed the concept and did not + use PyType_GetSlot at all (except in function copyNumberMethods), + but created PepTypeObject as a remake of PyTypeObject with only + those fields defined that are needed in PySide. + + Is this breakage of the limited API? I don't think so. A special + function runs on program startup that checks the correct position + of the fields of PepHeapType, although a change in those fields is + more than unlikely. + The really crucial thing is to no longer use PyHeapTypeObject + explicitly because that _does_ change its layout over time. + + + Diversification + --------------- + + There are multiple SbkXXX structures which all use a "d" field + for their private data. This makes it not easy to find the right + fields when switching between types and objects. + + struct LIBSHIBOKEN_API SbkObjectType + { + PyHeapTypeObject super; + SbkObjectTypePrivate *d; + }; + + struct LIBSHIBOKEN_API SbkObject + { + PyObject_HEAD + PyObject* ob_dict; + PyObject* weakreflist; + SbkObjectPrivate* d; + }; + + The first step was to rename the SbkObjectTypePrivate from "d" to + "sotp". It was chosen to be short but easy to remember. + + + Abstraction + ----------- + + After renaming the type extension pointers to "sotp", I replaced + them by function-like macros which did the special access "behind" + the types, instead of those explicit fields. For instance, the + expression + + type->sotp->converter + + became + + PepType_SOTP(type)->converter + + The macro expression can be seen here: + + #define _genericTypeExtender(etype) \ + (reinterpret_cast<char*>(etype) + \ + (reinterpret_cast<PepTypeObject*>(&PyType_Type))->tp_basicsize) + + #define PepType_SOTP(etype) \ + (*reinterpret_cast<SbkObjectTypePrivate**>(_genericTypeExtender(etype))) + + It looks complicated, but in the end there is only a single new + indirection via PyType_Type, which happens at runtime. This is the + key to fulfil what Pep 384 wants: No version-dependent fields. + + + Simplification + -------------- + + After all type extension fields were replaced by macro calls, we + could remove the version dependent definition + + typedef struct _pepheaptypeobject { + union { + PepTypeObject ht_type; + void *opaque[PY_HEAPTYPE_SIZE]; + }; + } PepHeapTypeObject; + + and the version dependent structure + + struct LIBSHIBOKEN_API SbkObjectType + { + PepHeapTypeObject super; + SbkObjectTypePrivate *sotp; + }; + + could be replaced by the simplified + + struct LIBSHIBOKEN_API SbkObjectType + { + PepTypeObject type; + }; + + which is no longer version-dependent. + + + Verification Of PepTypeObject + ============================= + + We have introduced PepTypeObject as a new alias for PyTypeObject, + and now we need to prove that we are allowed to do so. + + When using the limited API as intended, then types are completely + opaque, and access is only through PyType_FromSpec and (from + version 3.5 upwards) through PyType_GetSlot. + + Python then uses all the slot definitions in the type description + and produces a regular type object. + + + Unused Information + ------------------ + + But we know many things about types that are not explicitly said, + but they are inherently clear: + + a) The basic structure of a type is always the same, regardless + if it is a static type or a heap type. + + b) types are evolving very slowly, and a field is never replaced + by another field with different semantics. + + Inherent rule a) gives us the following information: If we calculate + the offsets of the fields, then this info is also usable for non- + -heap types. + + The validation checks if rule b) is still valid. + + + How it Works + ------------ + + The basic idea of the validation is to produce a new type using + PyType_FromSpec and to see where in the type structure these fields + show up. So we build a PyType_Slot structure with all the fields we + are using and make sure that these values are all unique in the + type. + + Most fields are not investigated by PyType_FromSpec, and so we + simply used some numeric value. Some fields are interpreted, like + tp_members. This field must really be a PyMemberDef. And there are + tp_base and tp_bases which have to be type objects and lists + thereof. It was easiest to not produce these fields from scratch + but use them from the "type" object PyType_Type. + + Then one would think to write a function that searches the known + values in the opaque type structure. + + But we can do better and use optimistically the observation (b): + We simply use the PepTypeObject structure and assume that every + field lands exactly where we are awaiting it. + + And that is the whole proof: If we find all the disjoint values at + the places where we expect them, thenthis is q.e.d. :) + + + About tp_dict + ------------- + + One word about the tp_dict field: This field is a bit special in + the proof, since it does not appear in the spec and cannot easily + be checked by "type.__dict__" because that creates a dictproxy + object. So how do we proove that is really the right dict? + + We have to create that PyMethodDef structure anyway, and instead of + leaving it empty, we insert a dummy function. Then we ask the + tp_dict field if it has that object in it, and that's q.e.d. + + + *********/ + + +/***************************************************************************** + * + * Support for object.h + * + */ + +/* + * Here is the verification code for PepTypeObject. + * We create a type object and check if its fields + * appear at the right offsets. + */ + +#define make_dummy_int(x) (x * sizeof(void*)) +#define make_dummy(x) (reinterpret_cast<void*>(make_dummy_int(x))) + +#ifdef Py_LIMITED_API +datetime_struc *PyDateTimeAPI = NULL; +#endif + +static PyObject * +dummy_func(PyObject *self, PyObject *args) +{ + Py_RETURN_NONE; +} + +static struct PyMethodDef probe_methoddef[] = { + {"dummy", dummy_func, METH_NOARGS}, + {0} +}; + +#define probe_tp_call make_dummy(1) +#define probe_tp_str make_dummy(2) +#define probe_tp_traverse make_dummy(3) +#define probe_tp_clear make_dummy(4) +#define probe_tp_methods probe_methoddef +#define probe_tp_descr_get make_dummy(6) +#define probe_tp_init make_dummy(7) +#define probe_tp_alloc make_dummy(8) +#define probe_tp_new make_dummy(9) +#define probe_tp_free make_dummy(10) +#define probe_tp_is_gc make_dummy(11) + +#define probe_tp_name "type.probe" +#define probe_tp_basicsize make_dummy_int(42) + +static PyType_Slot typeprobe_slots[] = { + {Py_tp_call, probe_tp_call}, + {Py_tp_str, probe_tp_str}, + {Py_tp_traverse, probe_tp_traverse}, + {Py_tp_clear, probe_tp_clear}, + {Py_tp_methods, probe_tp_methods}, + {Py_tp_descr_get, probe_tp_descr_get}, + {Py_tp_init, probe_tp_init}, + {Py_tp_alloc, probe_tp_alloc}, + {Py_tp_new, probe_tp_new}, + {Py_tp_free, probe_tp_free}, + {Py_tp_is_gc, probe_tp_is_gc}, + {0, 0} +}; +static PyType_Spec typeprobe_spec = { + probe_tp_name, + probe_tp_basicsize, + 0, + Py_TPFLAGS_DEFAULT, + typeprobe_slots, +}; + +static void +check_PepTypeObject_valid(void) +{ + PyObject *obtype = reinterpret_cast<PyObject*>(&PyType_Type); + PyTypeObject *probe_tp_base = reinterpret_cast<PyTypeObject*>( + PyObject_GetAttrString(obtype, "__base__")); + PyObject *probe_tp_bases = PyObject_GetAttrString(obtype, "__bases__"); + PepTypeObject *check = reinterpret_cast<PepTypeObject*>( + PyType_FromSpecWithBases(&typeprobe_spec, probe_tp_bases)); + PepTypeObject *typetype = reinterpret_cast<PepTypeObject*>(obtype); + PyObject *w = PyObject_GetAttrString(obtype, "__weakrefoffset__"); + long probe_tp_weakrefoffset = PyLong_AsLong(w); + PyObject *d = PyObject_GetAttrString(obtype, "__dictoffset__"); + long probe_tp_dictoffset = PyLong_AsLong(d); + PyObject *probe_tp_mro = PyObject_GetAttrString(obtype, "__mro__"); + if (false + || probe_tp_name != check->tp_name + || probe_tp_basicsize != check->tp_basicsize + || probe_tp_call != check->tp_call + || probe_tp_str != check->tp_str + || probe_tp_traverse != check->tp_traverse + || probe_tp_clear != check->tp_clear + || probe_tp_weakrefoffset != typetype->tp_weaklistoffset + || probe_tp_methods != check->tp_methods + || probe_tp_base != typetype->tp_base + || !PyDict_Check(check->tp_dict) + || !PyDict_GetItemString(check->tp_dict, "dummy") + || probe_tp_descr_get != check->tp_descr_get + || probe_tp_dictoffset != typetype->tp_dictoffset + || probe_tp_init != check->tp_init + || probe_tp_alloc != check->tp_alloc + || probe_tp_new != check->tp_new + || 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) + Py_FatalError("The structure of type objects has changed!"); + Py_DECREF(check); + Py_DECREF(probe_tp_base); + Py_DECREF(w); + Py_DECREF(d); + Py_DECREF(probe_tp_bases); + Py_DECREF(probe_tp_mro); +} + + +#ifdef Py_LIMITED_API + +// This structure is only here because Python 3 has an error. +// I will fix that. + +typedef struct { + /* Number implementations must check *both* + arguments for proper type and implement the necessary conversions + in the slot functions themselves. */ + + binaryfunc nb_add; + binaryfunc nb_subtract; + binaryfunc nb_multiply; + binaryfunc nb_remainder; + binaryfunc nb_divmod; + ternaryfunc nb_power; + unaryfunc nb_negative; + unaryfunc nb_positive; + unaryfunc nb_absolute; + inquiry nb_bool; + unaryfunc nb_invert; + binaryfunc nb_lshift; + binaryfunc nb_rshift; + binaryfunc nb_and; + binaryfunc nb_xor; + binaryfunc nb_or; + unaryfunc nb_int; + void *nb_reserved; /* the slot formerly known as nb_long */ + unaryfunc nb_float; + + binaryfunc nb_inplace_add; + binaryfunc nb_inplace_subtract; + binaryfunc nb_inplace_multiply; + binaryfunc nb_inplace_remainder; + ternaryfunc nb_inplace_power; + binaryfunc nb_inplace_lshift; + binaryfunc nb_inplace_rshift; + binaryfunc nb_inplace_and; + binaryfunc nb_inplace_xor; + binaryfunc nb_inplace_or; + + binaryfunc nb_floor_divide; + binaryfunc nb_true_divide; + binaryfunc nb_inplace_floor_divide; + binaryfunc nb_inplace_true_divide; + + unaryfunc nb_index; + + binaryfunc nb_matrix_multiply; + binaryfunc nb_inplace_matrix_multiply; +} PyNumberMethods; + +// temporary structure until we have a generator for the offsets +typedef struct _oldtypeobject { + PyVarObject ob_base; + void *X01; // const char *tp_name; + void *X02; // Py_ssize_t tp_basicsize; + void *X03; // Py_ssize_t tp_itemsize; + void *X04; // destructor tp_dealloc; + void *X05; // printfunc tp_print; + void *X06; // getattrfunc tp_getattr; + void *X07; // setattrfunc tp_setattr; + void *X08; // PyAsyncMethods *tp_as_async; + void *X09; // reprfunc tp_repr; + PyNumberMethods *tp_as_number; + +} PyOldTypeObject; + +// There is a bug in Python 3.6 that turned the Index_Check function +// into a macro without taking care of the limited API. +// This leads to the single problem that we don't have +// access to PyLong_Type's nb_index field which is no heap type. +// We cannot easily create this function by inheritance since it is +// not inherited. +// +// Simple solution: Create the structure and write such a function. +// Long term: Submit a patch to python.org . + +unaryfunc +PepType_nb_index(PyTypeObject *type) +{ + return reinterpret_cast<PyOldTypeObject*>(type)->tp_as_number->nb_index; +} + +int PyIndex_Check(PyObject *obj) +{ + PyOldTypeObject *type = reinterpret_cast<PyOldTypeObject*>(Py_TYPE(obj)); + return type->tp_as_number != NULL && + type->tp_as_number->nb_index != NULL; +} + +/***************************************************************************** + * + * Support for unicodeobject.h + * + */ + +char * +_PepUnicode_AsString(PyObject *str) +{ + /* + * We need to keep the string alive but cannot borrow the Python object. + * Ugly easy way out: We re-code as an interned bytes string. This + * produces a pseudo-leak as long there are new strings. + * Typically, this function is used for name strings, and the dict size + * will not grow so much. + */ +#define STRINGIFY(x) #x +#define TOSTRING(x) STRINGIFY(x) +#define AT __FILE__ ":" TOSTRING(__LINE__) + + static PyObject *cstring_dict = NULL; + if (cstring_dict == NULL) { + cstring_dict = PyDict_New(); + if (cstring_dict == NULL) + Py_FatalError("Error in " AT); + } + PyObject *bytesStr = PyUnicode_AsEncodedString(str, "utf8", NULL); + PyObject *entry = PyDict_GetItem(cstring_dict, bytesStr); + if (entry == NULL) { + int e = PyDict_SetItem(cstring_dict, bytesStr, bytesStr); + if (e != 0) + Py_FatalError("Error in " AT); + entry = bytesStr; + } + else + Py_DECREF(bytesStr); + return PyBytes_AsString(entry); +} + +/***************************************************************************** + * + * Support for longobject.h + * + */ + +/* + * This is the original Python function _PyLong_AsInt() from longobject.c . + * We define it here because we are not allowed to use the function + * from Python with an underscore. + */ + +/* Get a C int from an int object or any object that has an __int__ + method. Return -1 and set an error if overflow occurs. */ + +int +_PepLong_AsInt(PyObject *obj) +{ + int overflow; + long result = PyLong_AsLongAndOverflow(obj, &overflow); + if (overflow || result > INT_MAX || result < INT_MIN) { + /* XXX: could be cute and give a different + message for overflow == -1 */ + PyErr_SetString(PyExc_OverflowError, + "Python int too large to convert to C int"); + return -1; + } + return (int)result; +} + +/***************************************************************************** + * + * Support for pydebug.h + * + */ +static PyObject *sys_flags = NULL; + +int +Pep_GetFlag(const char *name) +{ + static int initialized = 0; + int ret = -1; + + if (!initialized) { + sys_flags = PySys_GetObject("flags"); + // func gives no error if NULL is returned and does not incref. + Py_XINCREF(sys_flags); + initialized = 1; + } + if (sys_flags != NULL) { + PyObject *ob_ret = PyObject_GetAttrString(sys_flags, name); + if (ob_ret != NULL) { + long long_ret = PyLong_AsLong(ob_ret); + Py_DECREF(ob_ret); + ret = (int) long_ret; + } + } + return ret; +} + +int +Pep_GetVerboseFlag() +{ + static int initialized = 0; + static int verbose_flag = -1; + + if (!initialized) { + verbose_flag = Pep_GetFlag("verbose"); + if (verbose_flag != -1) + initialized = 1; + } + return verbose_flag; +} + +/***************************************************************************** + * + * Support for code.h + * + */ + +int +PepCode_Get(PyCodeObject *co, const char *name) +{ + PyObject *ob = (PyObject *)co; + PyObject *ob_ret; + int ret = -1; + + ob_ret = PyObject_GetAttrString(ob, name); + if (ob_ret != NULL) { + long long_ret = PyLong_AsLong(ob_ret); + Py_DECREF(ob_ret); + ret = (int) long_ret; + } + return ret; +} + +/***************************************************************************** + * + * Support for datetime.h + * + */ + +static PyTypeObject *dt_getCheck(const char *name) +{ + PyObject *op = PyObject_GetAttrString(PyDateTimeAPI->module, name); + if (op == NULL) { + fprintf(stderr, "datetime.%s not found\n", name); + Py_FatalError("aborting"); + } + return (PyTypeObject *)op; +} + +// init_DateTime is called earlier than our module init. +// We use the provided PyDateTime_IMPORT machinery. +datetime_struc * +init_DateTime(void) +{ + static int initialized = 0; + if (!initialized) { + PyDateTimeAPI = (datetime_struc *)malloc(sizeof(datetime_struc)); + if (PyDateTimeAPI == NULL) + Py_FatalError("PyDateTimeAPI malloc error, aborting"); + PyDateTimeAPI->module = PyImport_ImportModule("datetime"); + if (PyDateTimeAPI->module == NULL) + Py_FatalError("datetime module not found, aborting"); + PyDateTimeAPI->DateType = dt_getCheck("date"); + PyDateTimeAPI->DateTimeType = dt_getCheck("datetime"); + PyDateTimeAPI->TimeType = dt_getCheck("time"); + PyDateTimeAPI->DeltaType = dt_getCheck("timedelta"); + PyDateTimeAPI->TZInfoType = dt_getCheck("tzinfo"); + initialized = 1; + } + return PyDateTimeAPI; +} + +int +PyDateTime_Get(PyObject *ob, const char *name) +{ + PyObject *ob_ret; + int ret = -1; + + ob_ret = PyObject_GetAttrString(ob, name); + if (ob_ret != NULL) { + long long_ret = PyLong_AsLong(ob_ret); + Py_DECREF(ob_ret); + ret = (int) long_ret; + } + return ret; +} + +PyObject * +PyDate_FromDate(int year, int month, int day) +{ + return PyObject_CallFunction((PyObject *)PyDateTimeAPI->DateType, + (char *)"(iii)", year, month, day); +} + +PyObject * +PyDateTime_FromDateAndTime(int year, int month, int day, + int hour, int min, int sec, int usec) +{ + return PyObject_CallFunction((PyObject *)PyDateTimeAPI->DateTimeType, + (char *)"(iiiiiii)", year, month, day, + hour, min, sec, usec); +} + +PyObject * +PyTime_FromTime(int hour, int min, int sec, int usec) +{ + return PyObject_CallFunction((PyObject *)PyDateTimeAPI->TimeType, + (char *)"(iiii)", hour, min, sec, usec); +} + +/***************************************************************************** + * + * Support for pythonrun.h + * + */ + +// Flags are ignored in these simple helpers. +PyObject * +PyRun_String(const char *str, int start, PyObject *globals, PyObject *locals) +{ + PyObject* code = Py_CompileString(str, "pyscript", start); + PyObject* ret = NULL; + + if (code != NULL) { + ret = PyEval_EvalCode(code, globals, locals); + } + Py_XDECREF(code); + return ret; +} + +// This is only a simple local helper that returns a computed variable. +static PyObject * +PepRun_GetResult(const char *command, const char *resvar) +{ + PyObject *d, *v, *res; + + d = PyDict_New(); + if (d == NULL || PyDict_SetItemString(d, "__builtins__", + PyEval_GetBuiltins()) < 0) + return NULL; + v = PyRun_String(command, Py_file_input, d, d); + res = v ? PyDict_GetItemString(d, resvar) : NULL; + Py_XDECREF(v); + Py_DECREF(d); + return res; +} + +/***************************************************************************** + * + * Support for classobject.h + * + */ + +PyTypeObject *PepMethod_TypePtr = NULL; + +static PyTypeObject *getMethodType(void) +{ + static const char prog[] = + "class _C:\n" + " def _m(self): pass\n" + "MethodType = type(_C()._m)\n"; + return (PyTypeObject *) PepRun_GetResult(prog, "MethodType"); +} + +// We have no access to PyMethod_New and must call types.MethodType, instead. +PyObject * +PyMethod_New(PyObject *func, PyObject *self) +{ + return PyObject_CallFunction((PyObject *)PepMethod_TypePtr, + (char *)"(OO)", func, self); +} + +PyObject * +PyMethod_Function(PyObject *im) +{ + PyObject *ret = PyObject_GetAttrString(im, "__func__"); + + // We have to return a borrowed reference. + Py_DECREF(ret); + return ret; +} + +PyObject * +PyMethod_Self(PyObject *im) +{ + PyObject *ret = PyObject_GetAttrString(im, "__self__"); + + // We have to return a borrowed reference. + // If we don't obey that here, then we get a test error! + Py_DECREF(ret); + return ret; +} + +/***************************************************************************** + * + * Support for funcobject.h + * + */ + +PyObject * +PepFunction_Get(PyObject *ob, const char *name) +{ + PyObject *ret; + + // We have to return a borrowed reference. + ret = PyObject_GetAttrString(ob, name); + Py_XDECREF(ret); + return ret; +} + +/***************************************************************************** + * + * Support for funcobject.h + * + */ + +// this became necessary after Windows was activated. + +PyTypeObject *PepFunction_TypePtr = NULL; + +static PyTypeObject *getFunctionType(void) +{ + static const char prog[] = + "from types import FunctionType\n"; + return (PyTypeObject *) PepRun_GetResult(prog, "FunctionType"); +} + +/***************************************************************************** + * + * Extra support for signature.cpp + * + */ + +PyTypeObject *PepStaticMethod_TypePtr = NULL; + +static PyTypeObject *getStaticMethodType(void) +{ + static const char prog[] = + "StaticMethodType = type(str.__dict__['maketrans'])\n"; + return (PyTypeObject *) PepRun_GetResult(prog, "StaticMethodType"); +} + +#endif // Py_LIMITED_API + +/***************************************************************************** + * + * Common newly needed functions + * + */ + +// The introduction of heaptypes converted many type names to the +// dotted form, since PyType_FromSpec uses it to compute the module +// name. This function reverts this effect. +const char * +PepType_GetNameStr(PyTypeObject *type) +{ + const char *ret = PepType(type)->tp_name; + const char *nodots = strrchr(ret, '.'); + if (nodots) + ret = nodots + 1; + return ret; +} + +/***************************************************************************** + * + * Module Initialization + * + */ + +void +Pep_Init() +{ + check_PepTypeObject_valid(); +#ifdef Py_LIMITED_API + Pep_GetVerboseFlag(); + PepMethod_TypePtr = getMethodType(); + PepFunction_TypePtr = getFunctionType(); + PepStaticMethod_TypePtr = getStaticMethodType(); +#endif +} + +} // extern "C" diff --git a/sources/shiboken2/libshiboken/pep384impl.h b/sources/shiboken2/libshiboken/pep384impl.h new file mode 100644 index 000000000..fc0e3b40e --- /dev/null +++ b/sources/shiboken2/libshiboken/pep384impl.h @@ -0,0 +1,571 @@ +/**************************************************************************** +** +** Copyright (C) 2018 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt for Python. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef PEP384IMPL_H +#define PEP384IMPL_H + +#include "sbkpython.h" + +extern "C" +{ + +/***************************************************************************** + * + * RESOLVED: memoryobject.h + * + */ + +// Extracted into bufferprocs27.h +#ifdef Py_LIMITED_API +#include "bufferprocs27.h" +#endif + +/***************************************************************************** + * + * RESOLVED: object.h + * + */ +#ifdef Py_LIMITED_API +// Why the hell is this useful debugging function not allowed? +LIBSHIBOKEN_API void _PyObject_Dump(PyObject *); +#endif + +/* + * There are a few structures that are needed, but cannot be used without + * breaking the API. We use some heuristics to get those fields anyway + * and validate that we really found them, see Pepresolve.cpp . + */ + +// PepType is just a typecast that allows direct access. This is +// often better to read than the reversal via the former macro +// functions PepType_tp_xxx. +#define PepType(o) (reinterpret_cast<PepTypeObject*>(o)) + +#ifdef Py_LIMITED_API + +/* + * These are the type object fields that we use. + * We will verify that they never change. + * The unused fields are intentionally named as "void *Xnn" because + * the chance is smaller to forget to validate a field. + * When we need more fields, we replace it back and add it to the + * validation. + */ +typedef struct _peptypeobject { + PyVarObject ob_base; + const char *tp_name; + Py_ssize_t tp_basicsize; + void *X03; // Py_ssize_t tp_itemsize; + void *X04; // destructor tp_dealloc; + void *X05; // printfunc tp_print; + void *X06; // getattrfunc tp_getattr; + void *X07; // setattrfunc tp_setattr; + void *X08; // PyAsyncMethods *tp_as_async; + void *X09; // reprfunc tp_repr; + void *X10; // PyNumberMethods *tp_as_number; + void *X11; // PySequenceMethods *tp_as_sequence; + void *X12; // PyMappingMethods *tp_as_mapping; + void *X13; // hashfunc tp_hash; + ternaryfunc tp_call; + reprfunc tp_str; + void *X16; // getattrofunc tp_getattro; + void *X17; // setattrofunc tp_setattro; + void *X18; // PyBufferProcs *tp_as_buffer; + void *X19; // unsigned long tp_flags; + void *X20; // const char *tp_doc; + traverseproc tp_traverse; + inquiry tp_clear; + void *X23; // richcmpfunc tp_richcompare; + Py_ssize_t tp_weaklistoffset; + void *X25; // getiterfunc tp_iter; + void *X26; // iternextfunc tp_iternext; + struct PyMethodDef *tp_methods; + void *X28; // struct PyMemberDef *tp_members; + void *X29; // struct PyGetSetDef *tp_getset; + struct _typeobject *tp_base; + PyObject *tp_dict; + descrgetfunc tp_descr_get; + void *X33; // descrsetfunc tp_descr_set; + Py_ssize_t tp_dictoffset; + initproc tp_init; + allocfunc tp_alloc; + newfunc tp_new; + freefunc tp_free; + inquiry tp_is_gc; /* For PyObject_IS_GC */ + PyObject *tp_bases; + PyObject *tp_mro; /* method resolution order */ + +} PepTypeObject; + +LIBSHIBOKEN_API unaryfunc PepType_nb_index(PyTypeObject *type); + +#undef PyIndex_Check + +LIBSHIBOKEN_API int PyIndex_Check(PyObject *obj); + +#undef PyObject_IS_GC +#define PyObject_IS_GC(o) (PyType_IS_GC(Py_TYPE(o)) && \ + ( PepType(Py_TYPE(o))->tp_is_gc == NULL || \ + PepType(Py_TYPE(o))->tp_is_gc(o) )) + +#else +#define PepTypeObject PyTypeObject +#define PepType_nb_index(o) (PepType(o)->nb_index) +#endif // Py_LIMITED_API + +struct SbkObjectTypePrivate; +struct PySideQFlagsTypePrivate; +struct _SbkGenericTypePrivate; + +#define PepHeapType_SIZE \ + (reinterpret_cast<PepTypeObject*>(&PyType_Type)->tp_basicsize) + +#define _genericTypeExtender(etype) \ + (reinterpret_cast<char*>(etype) + PepHeapType_SIZE) + +#define PepType_SOTP(etype) \ + (*reinterpret_cast<SbkObjectTypePrivate**>(_genericTypeExtender(etype))) + +#define PepType_SETP(etype) \ + (reinterpret_cast<SbkEnumTypePrivate*>(_genericTypeExtender(etype))) + +#define PepType_PFTP(etype) \ + (reinterpret_cast<PySideQFlagsTypePrivate*>(_genericTypeExtender(etype))) + +#define PepType_SGTP(etype) \ + (reinterpret_cast<_SbkGenericTypePrivate*>(_genericTypeExtender(etype))) + +// functions used everywhere +LIBSHIBOKEN_API const char *PepType_GetNameStr(PyTypeObject *type); + +/***************************************************************************** + * + * RESOLVED: longobject.h + * + */ +#ifdef Py_LIMITED_API +LIBSHIBOKEN_API int _PepLong_AsInt(PyObject *); +#else +#define _PepLong_AsInt _PyLong_AsInt +#endif + +/***************************************************************************** + * + * RESOLVED: pydebug.h + * + */ +#ifdef Py_LIMITED_API +/* + * We have no direct access to Py_VerboseFlag because debugging is not + * supported. The python developers are partially a bit too rigorous. + * Instead, we compute the value and use a function call macro. + * Was before: extern LIBSHIBOKEN_API int Py_VerboseFlag; + */ +LIBSHIBOKEN_API int Pep_GetFlag(const char *name); +LIBSHIBOKEN_API int Pep_GetVerboseFlag(void); +#define Py_VerboseFlag Pep_GetVerboseFlag() +#endif + +/***************************************************************************** + * + * RESOLVED: unicodeobject.h + * + */ +#ifdef Py_LIMITED_API + +LIBSHIBOKEN_API char *_PepUnicode_AsString(PyObject *); + +#define PyUnicode_GET_SIZE(op) PyUnicode_GetSize((PyObject *)(op)) + +#else +#define _PepUnicode_AsString PyUnicode_AsUTF8 +#endif + +/***************************************************************************** + * + * RESOLVED: bytesobject.h + * + */ +#ifdef Py_LIMITED_API +#define PyBytes_AS_STRING(op) PyBytes_AsString(op) +#define PyBytes_GET_SIZE(op) PyBytes_Size(op) +#endif + +/***************************************************************************** + * + * RESOLVED: floatobject.h + * + */ +#ifdef Py_LIMITED_API +#define PyFloat_AS_DOUBLE(op) PyFloat_AsDouble(op) +#endif + +/***************************************************************************** + * + * RESOLVED: tupleobject.h + * + */ +#ifdef Py_LIMITED_API +#define PyTuple_GET_ITEM(op, i) PyTuple_GetItem((PyObject *)op, i) +#define PyTuple_GET_SIZE(op) PyTuple_Size((PyObject *)op) +#define PyTuple_SET_ITEM(op, i, v) PyTuple_SetItem(op, i, v) +#endif + +/***************************************************************************** + * + * RESOLVED: listobject.h + * + */ +#ifdef Py_LIMITED_API +#define PyList_GET_ITEM(op, i) PyList_GetItem(op, i) +#define PyList_SET_ITEM(op, i, v) PyList_SetItem(op, i, v) +#define PyList_GET_SIZE(op) PyList_Size(op) +#endif + +/***************************************************************************** + * + * RESOLVED: methodobject.h + * + */ + +#ifdef Py_LIMITED_API + +typedef struct _pycfunc PyCFunctionObject; +#define PyCFunction_GET_FUNCTION(func) PyCFunction_GetFunction((PyObject *)func) +#define PyCFunction_GET_SELF(func) PyCFunction_GetSelf((PyObject *)func) +#define PyCFunction_GET_FLAGS(func) PyCFunction_GetFlags((PyObject *)func) +#define PepCFunction_GET_NAMESTR(func) \ + _PepUnicode_AsString(PyObject_GetAttrString((PyObject *)func, "__name__")) +#else +#define PepCFunction_GET_NAMESTR(func) ((func)->m_ml->ml_name) +#endif + +/***************************************************************************** + * + * RESOLVED: descrobject.h + * + */ +#ifdef Py_LIMITED_API +typedef struct _methoddescr PyMethodDescrObject; +#endif + +/***************************************************************************** + * + * RESOLVED: pystate.h + * + */ + +/* + * pystate provides the data structure that is needed for the trashcan + * algorithm. Unfortunately, it is not included in the limited API. + * We have two options: + * + * (1) ignore trashcan and live without secured deeply nested structures, + * (2) maintain the structure ourselves and make sure it does not change. + * + * I have chosen the second option. + * + * When a new python version appears, you need to check compatibility of + * the PyThreadState structure (pystate.h) and the trashcan macros at the + * end of object.h . + */ + +#ifdef Py_LIMITED_API + +#define Py_TRASH_MIN_COMPATIBLE 0x03020400 +#define Py_TRASH_MAX_COMPATIBLE 0x030700A0 + +#if PY_VERSION_HEX >= Py_TRASH_MIN_COMPATIBLE && \ + PY_VERSION_HEX <= Py_TRASH_MAX_COMPATIBLE +typedef int (*Py_tracefunc)(PyObject *, struct _frame *, int, PyObject *); + +// This structure has the trashcan variables since Python 3.2.4. +// We renamed all but the trashcan fields to make sure that we don't use +// anything else somewhere. + +typedef struct _ts { + struct _ts *Pep_prev; + struct _ts *Pep_next; + PyInterpreterState *Pep_interp; + + struct _frame *Pep_frame; + int Pep_recursion_depth; + char Pep_overflowed; + char Pep_recursion_critical; + + int Pep_tracing; + int Pep_use_tracing; + + Py_tracefunc Pep_c_profilefunc; + Py_tracefunc Pep_c_tracefunc; + PyObject *Pep_c_profileobj; + PyObject *Pep_c_traceobj; + + PyObject *Pep_curexc_type; + PyObject *Pep_curexc_value; + PyObject *Pep_curexc_traceback; + + PyObject *Pep_exc_type; + PyObject *Pep_exc_value; + PyObject *Pep_exc_traceback; + + PyObject *Pep_dict; + + int Pep_gilstate_counter; + + PyObject *Pep_async_exc; + long Pep_thread_id; + // These two variables only are of interest to us. + int trash_delete_nesting; + PyObject *trash_delete_later; + // Here we cut away the rest of the reduced structure. +} PyThreadState; +#else +#error *** Please check compatibility of the trashcan code, see Pep.h *** +#endif + +#endif // Py_LIMITED_API + +/***************************************************************************** + * + * RESOLVED: pythonrun.h + * + */ +#ifdef Py_LIMITED_API +LIBSHIBOKEN_API PyObject *PyRun_String(const char *, int, PyObject *, PyObject *); +#endif + +/***************************************************************************** + * + * RESOLVED: abstract.h + * + */ +#ifdef Py_LIMITED_API + +// This definition breaks the limited API a little, because it re-enables the +// buffer functions. +// 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 < 0X0306FFFF) +#if !PYTHON_BUFFER_VERSION_COMPATIBLE +# error Please check the buffer compatibility for this python version! +#endif + +typedef struct { + getbufferproc bf_getbuffer; + releasebufferproc bf_releasebuffer; +} PyBufferProcs; + +typedef struct _Pepbuffertype { + PyVarObject ob_base; + void *skip[17]; + PyBufferProcs *tp_as_buffer; +} PepBufferType; + +#define PepType_AS_BUFFER(type) \ + reinterpret_cast<PepBufferType *>(type)->tp_as_buffer + +#define PyObject_CheckBuffer(obj) \ + ((PepType_AS_BUFFER(Py_TYPE(obj)) != NULL) && \ + (PepType_AS_BUFFER(Py_TYPE(obj))->bf_getbuffer != NULL)) + +LIBSHIBOKEN_API int PyObject_GetBuffer(PyObject *ob, Pep_buffer *view, int flags); +LIBSHIBOKEN_API void PyBuffer_Release(Pep_buffer *view); + +#else + +#define Pep_buffer Py_buffer + +#endif /* Py_LIMITED_API */ + +/***************************************************************************** + * + * RESOLVED: funcobject.h + * + */ +#ifdef Py_LIMITED_API +typedef struct _func PyFunctionObject; + +extern LIBSHIBOKEN_API PyTypeObject *PepFunction_TypePtr; +LIBSHIBOKEN_API PyObject *PepFunction_Get(PyObject *, const char *); + +#define PyFunction_Check(op) (Py_TYPE(op) == PepFunction_TypePtr) +#define PyFunction_GET_CODE(func) PyFunction_GetCode(func) + +#define PyFunction_GetCode(func) PepFunction_Get((PyObject *)func, "__code__") +#define PepFunction_GetName(func) PepFunction_Get((PyObject *)func, "__name__") +#else +#define PepFunction_GetName(func) (((PyFunctionObject *)func)->func_name) +#endif + +/***************************************************************************** + * + * RESOLVED: classobject.h + * + */ +#ifdef Py_LIMITED_API + +typedef struct _meth PyMethodObject; + +extern LIBSHIBOKEN_API PyTypeObject *PepMethod_TypePtr; + +LIBSHIBOKEN_API PyObject *PyMethod_New(PyObject *, PyObject *); +LIBSHIBOKEN_API PyObject *PyMethod_Function(PyObject *); +LIBSHIBOKEN_API PyObject *PyMethod_Self(PyObject *); + +#define PyMethod_Check(op) ((op)->ob_type == PepMethod_TypePtr) + +#define PyMethod_GET_SELF(op) PyMethod_Self(op) +#define PyMethod_GET_FUNCTION(op) PyMethod_Function(op) +#endif + +/***************************************************************************** + * + * RESOLVED: code.h + * + */ +#ifdef Py_LIMITED_API +/* Bytecode object */ + // we have to grab the code object from python +typedef struct _code PyCodeObject; + +LIBSHIBOKEN_API int PepCode_Get(PyCodeObject *co, const char *name); + +#define PepCode_GET_FLAGS(o) PepCode_Get(o, "co_flags") +#define PepCode_GET_ARGCOUNT(o) PepCode_Get(o, "co_argcount") + +/* Masks for co_flags above */ +#define CO_OPTIMIZED 0x0001 +#define CO_NEWLOCALS 0x0002 +#define CO_VARARGS 0x0004 +#define CO_VARKEYWORDS 0x0008 +#define CO_NESTED 0x0010 +#define CO_GENERATOR 0x0020 +#else +#define PepCode_GET_FLAGS(o) ((o)->co_flags) +#define PepCode_GET_ARGCOUNT(o) ((o)->co_argcount) +#endif + +/***************************************************************************** + * + * RESOLVED: datetime.h + * + */ +#ifdef Py_LIMITED_API + +LIBSHIBOKEN_API int PyDateTime_Get(PyObject *ob, const char *name); + +#define PyDateTime_GetYear(o) PyDateTime_Get(o, "year") +#define PyDateTime_GetMonth(o) PyDateTime_Get(o, "month") +#define PyDateTime_GetDay(o) PyDateTime_Get(o, "day") +#define PyDateTime_GetHour(o) PyDateTime_Get(o, "hour") +#define PyDateTime_GetMinute(o) PyDateTime_Get(o, "minute") +#define PyDateTime_GetSecond(o) PyDateTime_Get(o, "second") +#define PyDateTime_GetMicrosecond(o) PyDateTime_Get(o, "microsecond") +#define PyDateTime_GetFold(o) PyDateTime_Get(o, "fold") + +#define PyDateTime_GET_YEAR(o) PyDateTime_GetYear(o) +#define PyDateTime_GET_MONTH(o) PyDateTime_GetMonth(o) +#define PyDateTime_GET_DAY(o) PyDateTime_GetDay(o) + +#define PyDateTime_DATE_GET_HOUR(o) PyDateTime_GetHour(o) +#define PyDateTime_DATE_GET_MINUTE(o) PyDateTime_GetMinute(o) +#define PyDateTime_DATE_GET_SECOND(o) PyDateTime_GetSecond(o) +#define PyDateTime_DATE_GET_MICROSECOND(o) PyDateTime_GetMicrosecond(o) +#define PyDateTime_DATE_GET_FOLD(o) PyDateTime_GetFold(o) + +#define PyDateTime_TIME_GET_HOUR(o) PyDateTime_GetHour(o) +#define PyDateTime_TIME_GET_MINUTE(o) PyDateTime_GetMinute(o) +#define PyDateTime_TIME_GET_SECOND(o) PyDateTime_GetSecond(o) +#define PyDateTime_TIME_GET_MICROSECOND(o) PyDateTime_GetMicrosecond(o) +#define PyDateTime_TIME_GET_FOLD(o) PyDateTime_GetFold(o) + +/* Define structure slightly similar to C API. */ +typedef struct { + PyObject *module; + /* type objects */ + PyTypeObject *DateType; + PyTypeObject *DateTimeType; + PyTypeObject *TimeType; + PyTypeObject *DeltaType; + PyTypeObject *TZInfoType; +} datetime_struc; + +LIBSHIBOKEN_API datetime_struc *init_DateTime(void); + +#define PyDateTime_IMPORT PyDateTimeAPI = init_DateTime() + +extern LIBSHIBOKEN_API datetime_struc *PyDateTimeAPI; + +#define PyDate_Check(op) PyObject_TypeCheck(op, PyDateTimeAPI->DateType) +#define PyDateTime_Check(op) PyObject_TypeCheck(op, PyDateTimeAPI->DateTimeType) +#define PyTime_Check(op) PyObject_TypeCheck(op, PyDateTimeAPI->TimeType) + +LIBSHIBOKEN_API PyObject *PyDate_FromDate(int year, int month, int day); +LIBSHIBOKEN_API PyObject *PyDateTime_FromDateAndTime( + int year, int month, int day, int hour, int min, int sec, int usec); +LIBSHIBOKEN_API PyObject *PyTime_FromTime( + int hour, int minute, int second, int usecond); + +#endif /* Py_LIMITED_API */ + +/***************************************************************************** + * + * Extra support for signature.cpp + * + */ + +#ifdef Py_LIMITED_API +extern LIBSHIBOKEN_API PyTypeObject *PepStaticMethod_TypePtr; +#else +#define PepStaticMethod_TypePtr &PyStaticMethod_Type +#endif + +/***************************************************************************** + * + * Module Initialization + * + */ + +LIBSHIBOKEN_API void Pep_Init(void); + +} // extern "C" + +#endif // PEP384IMPL_H diff --git a/sources/shiboken2/libshiboken/python25compat.h b/sources/shiboken2/libshiboken/python25compat.h index 42f78481d..fc25aa3e5 100644 --- a/sources/shiboken2/libshiboken/python25compat.h +++ b/sources/shiboken2/libshiboken/python25compat.h @@ -39,7 +39,7 @@ #ifndef PYTHON25COMPAT_H #define PYTHON25COMPAT_H -#include <Python.h> +#include "sbkpython.h" #include <cstring> /* diff --git a/sources/shiboken2/libshiboken/qapp_macro.cpp b/sources/shiboken2/libshiboken/qapp_macro.cpp index e6a877a32..f69d0f937 100644 --- a/sources/shiboken2/libshiboken/qapp_macro.cpp +++ b/sources/shiboken2/libshiboken/qapp_macro.cpp @@ -119,8 +119,8 @@ MakeSingletonQAppWrapper(PyTypeObject *type) if (type == NULL) type = Py_NONE_TYPE; if (!(type == Py_NONE_TYPE || Py_TYPE(qApp_content) == Py_NONE_TYPE)) { - const char *res_name = strrchr(Py_TYPE(qApp_content)->tp_name, '.')+1; - const char *type_name = strrchr(type->tp_name, '.')+1; + const char *res_name = PepType_GetNameStr(Py_TYPE(qApp_content)); + const char *type_name = PepType_GetNameStr(type); PyErr_Format(PyExc_RuntimeError, "Please destroy the %s singleton before" " creating a new %s instance.", res_name, type_name); return NULL; diff --git a/sources/shiboken2/libshiboken/qt_attribution.json b/sources/shiboken2/libshiboken/qt_attribution.json new file mode 100644 index 000000000..a90cc604b --- /dev/null +++ b/sources/shiboken2/libshiboken/qt_attribution.json @@ -0,0 +1,12 @@ +{ + "Id": "python", + "Name": "Python", + "QDocModule": "QtForPython", + "QtUsage": "Used for Qt for Python in the signature extension.", + "Description": "Qt for Python is an add-on for Python. The libshiboken packages of PySide uses certain parts of the source files (typespec.cpp, typespec.h, bufferprocs27.cpp, bufferprocs27.h). See the folder sources/shiboken2/libshiboken .", + "Homepage": "http://www.python.org/", + "Version": "3.6.5", + "License": "PSF LICENSE AGREEMENT FOR PYTHON 3.6.5", + "LicenseFile": "bufferprocs27.h", + "Copyright": "© Copyright 2001-2018, Python Software Foundation." +} diff --git a/sources/shiboken2/libshiboken/sbkarrayconverter.cpp b/sources/shiboken2/libshiboken/sbkarrayconverter.cpp index 1646c9117..58e0b18a8 100644 --- a/sources/shiboken2/libshiboken/sbkarrayconverter.cpp +++ b/sources/shiboken2/libshiboken/sbkarrayconverter.cpp @@ -162,7 +162,7 @@ static void sequenceToCppIntArray(PyObject *pyIn, void *cppOut) { ArrayHandle<int> *handle = reinterpret_cast<ArrayHandle<int> *>(cppOut); handle->allocate(PySequence_Size(pyIn)); - convertPySequence(pyIn, _PyLong_AsInt, handle->data()); + convertPySequence(pyIn, _PepLong_AsInt, handle->data()); } static PythonToCppFunc sequenceToCppIntArrayCheck(PyObject *pyIn, int dim1, int /* dim2 */) diff --git a/sources/shiboken2/libshiboken/sbkconverter.cpp b/sources/shiboken2/libshiboken/sbkconverter.cpp index 64884d601..d4d3ac899 100644 --- a/sources/shiboken2/libshiboken/sbkconverter.cpp +++ b/sources/shiboken2/libshiboken/sbkconverter.cpp @@ -112,6 +112,8 @@ SbkConverter *createConverterObject(PyTypeObject *type, { SbkConverter* converter = new SbkConverter; converter->pythonType = type; + // PYSIDE-595: All types are heaptypes now, so provide reference. + Py_XINCREF(type); converter->pointerToPython = pointerToPythonFunc; converter->copyToPython = copyToPythonFunc; @@ -133,7 +135,7 @@ SbkConverter* createConverter(SbkObjectType* type, createConverterObject(reinterpret_cast<PyTypeObject *>(type), toCppPointerConvFunc, toCppPointerCheckFunc, pointerToPythonFunc, copyToPythonFunc); - type->d->converter = converter; + PepType_SOTP(type)->converter = converter; return converter; } @@ -172,12 +174,12 @@ void addPythonToCppValueConversion(SbkObjectType* type, PythonToCppFunc pythonToCppFunc, IsConvertibleToCppFunc isConvertibleToCppFunc) { - addPythonToCppValueConversion(type->d->converter, pythonToCppFunc, isConvertibleToCppFunc); + addPythonToCppValueConversion(PepType_SOTP(type)->converter, pythonToCppFunc, isConvertibleToCppFunc); } -PyObject* pointerToPython(const SbkObjectType *type, const void *cppIn) +PyObject* pointerToPython(SbkObjectType *type, const void *cppIn) { - return pointerToPython(type->d->converter, cppIn); + return pointerToPython(PepType_SOTP(type)->converter, cppIn); } PyObject* pointerToPython(const SbkConverter *converter, const void *cppIn) @@ -187,15 +189,15 @@ PyObject* pointerToPython(const SbkConverter *converter, const void *cppIn) Py_RETURN_NONE; if (!converter->pointerToPython) { warning(PyExc_RuntimeWarning, 0, "pointerToPython(): SbkConverter::pointerToPython is null for \"%s\".", - converter->pythonType->tp_name); + PepType(converter->pythonType)->tp_name); Py_RETURN_NONE; } return converter->pointerToPython(cppIn); } -PyObject* referenceToPython(const SbkObjectType *type, const void *cppIn) +PyObject* referenceToPython(SbkObjectType *type, const void *cppIn) { - return referenceToPython(type->d->converter, cppIn); + return referenceToPython(PepType_SOTP(type)->converter, cppIn); } PyObject* referenceToPython(const SbkConverter *converter, const void *cppIn) @@ -209,7 +211,7 @@ PyObject* referenceToPython(const SbkConverter *converter, const void *cppIn) } if (!converter->pointerToPython) { warning(PyExc_RuntimeWarning, 0, "referenceToPython(): SbkConverter::pointerToPython is null for \"%s\".", - converter->pythonType->tp_name); + PepType(converter->pythonType)->tp_name); Py_RETURN_NONE; } return converter->pointerToPython(cppIn); @@ -221,24 +223,24 @@ static inline PyObject* CopyCppToPython(const SbkConverter *converter, const voi Py_RETURN_NONE; if (!converter->copyToPython) { warning(PyExc_RuntimeWarning, 0, "CopyCppToPython(): SbkConverter::copyToPython is null for \"%s\".", - converter->pythonType->tp_name); + PepType(converter->pythonType)->tp_name); Py_RETURN_NONE; } return converter->copyToPython(cppIn); } -PyObject* copyToPython(const SbkObjectType *type, const void *cppIn) +PyObject* copyToPython(SbkObjectType *type, const void *cppIn) { - return CopyCppToPython(type->d->converter, cppIn); + return CopyCppToPython(PepType_SOTP(type)->converter, cppIn); } PyObject* copyToPython(const SbkConverter *converter, const void *cppIn) { return CopyCppToPython(converter, cppIn); } -PythonToCppFunc isPythonToCppPointerConvertible(const SbkObjectType *type, PyObject *pyIn) +PythonToCppFunc isPythonToCppPointerConvertible(SbkObjectType *type, PyObject *pyIn) { assert(pyIn); - return type->d->converter->toCppPointerConversion.first(pyIn); + return PepType_SOTP(type)->converter->toCppPointerConversion.first(pyIn); } static inline PythonToCppFunc IsPythonToCppConvertible(const SbkConverter *converter, PyObject *pyIn) @@ -252,9 +254,9 @@ static inline PythonToCppFunc IsPythonToCppConvertible(const SbkConverter *conve } return 0; } -PythonToCppFunc isPythonToCppValueConvertible(const SbkObjectType *type, PyObject *pyIn) +PythonToCppFunc isPythonToCppValueConvertible(SbkObjectType *type, PyObject *pyIn) { - return IsPythonToCppConvertible(type->d->converter, pyIn); + return IsPythonToCppConvertible(PepType_SOTP(type)->converter, pyIn); } PythonToCppFunc isPythonToCppConvertible(const SbkConverter *converter, PyObject *pyIn) { @@ -272,7 +274,7 @@ PythonToCppFunc isPythonToCppConvertible(const SbkArrayConverter *converter, return nullptr; } -PythonToCppFunc isPythonToCppReferenceConvertible(const SbkObjectType *type, PyObject *pyIn) +PythonToCppFunc isPythonToCppReferenceConvertible(SbkObjectType *type, PyObject *pyIn) { if (pyIn != Py_None) { PythonToCppFunc toCpp = isPythonToCppPointerConvertible(type, pyIn); @@ -329,10 +331,10 @@ static void _pythonToCppCopy(const SbkConverter *converter, PyObject *pyIn, void toCpp(pyIn, cppOut); } -void pythonToCppCopy(const SbkObjectType *type, PyObject *pyIn, void *cppOut) +void pythonToCppCopy(SbkObjectType *type, PyObject *pyIn, void *cppOut) { assert(type); - _pythonToCppCopy(type->d->converter, pyIn, cppOut); + _pythonToCppCopy(PepType_SOTP(type)->converter, pyIn, cppOut); } void pythonToCppCopy(const SbkConverter *converter, PyObject *pyIn, void *cppOut) @@ -340,16 +342,16 @@ void pythonToCppCopy(const SbkConverter *converter, PyObject *pyIn, void *cppOut _pythonToCppCopy(converter, pyIn, cppOut); } -bool isImplicitConversion(const SbkObjectType *type, PythonToCppFunc toCppFunc) +bool isImplicitConversion(SbkObjectType *type, PythonToCppFunc toCppFunc) { // This is the Object Type or Value Type conversion that only // retrieves the C++ pointer held in the Python wrapper. - if (toCppFunc == type->d->converter->toCppPointerConversion.second) + if (toCppFunc == PepType_SOTP(type)->converter->toCppPointerConversion.second) return false; // Object Types doesn't have any kind of value conversion, // only C++ pointer retrieval. - if (type->d->converter->toCppConversions.empty()) + if (PepType_SOTP(type)->converter->toCppConversions.empty()) return false; // The first conversion of the non-pointer conversion list is @@ -359,7 +361,7 @@ bool isImplicitConversion(const SbkObjectType *type, PythonToCppFunc toCppFunc) // Note that we don't check if the Python to C++ conversion is in // the list of the type's conversions, for it is expected that the // caller knows what he's doing. - ToCppConversionList::iterator conv = type->d->converter->toCppConversions.begin(); + ToCppConversionList::iterator conv = PepType_SOTP(type)->converter->toCppConversions.begin(); return toCppFunc != (*conv).second; } @@ -411,10 +413,10 @@ bool convertibleSequenceTypes(const SbkConverter *converter, PyObject *pyIn) } return true; } -bool convertibleSequenceTypes(const SbkObjectType *type, PyObject *pyIn) +bool convertibleSequenceTypes(SbkObjectType *type, PyObject *pyIn) { assert(type); - return convertibleSequenceTypes(type->d->converter, pyIn); + return convertibleSequenceTypes(PepType_SOTP(type)->converter, pyIn); } bool checkPairTypes(PyTypeObject* firstType, PyTypeObject* secondType, PyObject* pyIn) diff --git a/sources/shiboken2/libshiboken/sbkconverter.h b/sources/shiboken2/libshiboken/sbkconverter.h index da71db5b5..0effebf57 100644 --- a/sources/shiboken2/libshiboken/sbkconverter.h +++ b/sources/shiboken2/libshiboken/sbkconverter.h @@ -191,7 +191,7 @@ LIBSHIBOKEN_API void addPythonToCppValueConversion(SbkObjectType* type, * TYPE* var; * PyObject* pyVar = pointerToPython(SBKTYPE, &var); */ -LIBSHIBOKEN_API PyObject* pointerToPython(const SbkObjectType *type, const void *cppIn); +LIBSHIBOKEN_API PyObject* pointerToPython(SbkObjectType *type, const void *cppIn); LIBSHIBOKEN_API PyObject* pointerToPython(const SbkConverter *converter, const void *cppIn); /** @@ -203,7 +203,7 @@ LIBSHIBOKEN_API PyObject* pointerToPython(const SbkConverter *converter, const v * TYPE& var = SOMETHING; * PyObject* pyVar = referenceToPython(SBKTYPE, &var); */ -LIBSHIBOKEN_API PyObject* referenceToPython(const SbkObjectType *type, const void *cppIn); +LIBSHIBOKEN_API PyObject* referenceToPython(SbkObjectType *type, const void *cppIn); LIBSHIBOKEN_API PyObject* referenceToPython(const SbkConverter *converter, const void *cppIn); /** @@ -213,7 +213,7 @@ LIBSHIBOKEN_API PyObject* referenceToPython(const SbkConverter *converter, const * TYPE var; * PyObject* pyVar = copyToPython(SBKTYPE, &var); */ -LIBSHIBOKEN_API PyObject* copyToPython(const SbkObjectType *type, const void *cppIn); +LIBSHIBOKEN_API PyObject* copyToPython(SbkObjectType *type, const void *cppIn); LIBSHIBOKEN_API PyObject* copyToPython(const SbkConverter *converter, const void *cppIn); // Python -> C++ --------------------------------------------------------------------------- @@ -222,7 +222,7 @@ LIBSHIBOKEN_API PyObject* copyToPython(const SbkConverter *converter, const void * Returns a Python to C++ conversion function if the Python object is convertible to a C++ pointer. * It returns NULL if the Python object is not convertible to \p type. */ -LIBSHIBOKEN_API PythonToCppFunc isPythonToCppPointerConvertible(const SbkObjectType *type, PyObject *pyIn); +LIBSHIBOKEN_API PythonToCppFunc isPythonToCppPointerConvertible(SbkObjectType *type, PyObject *pyIn); /** * Returns a Python to C++ conversion function if the Python object is convertible to a C++ value. @@ -230,7 +230,7 @@ LIBSHIBOKEN_API PythonToCppFunc isPythonToCppPointerConvertible(const SbkObjectT * convert the object to the expected \p type. * It returns NULL if the Python object is not convertible to \p type. */ -LIBSHIBOKEN_API PythonToCppFunc isPythonToCppValueConvertible(const SbkObjectType *type, PyObject *pyIn); +LIBSHIBOKEN_API PythonToCppFunc isPythonToCppValueConvertible(SbkObjectType *type, PyObject *pyIn); /** * Returns a Python to C++ conversion function if the Python object is convertible to a C++ reference. @@ -238,7 +238,7 @@ LIBSHIBOKEN_API PythonToCppFunc isPythonToCppValueConvertible(const SbkObjectTyp * or a new C++ value if it must be a implicit conversion. * It returns NULL if the Python object is not convertible to \p type. */ -LIBSHIBOKEN_API PythonToCppFunc isPythonToCppReferenceConvertible(const SbkObjectType *type, PyObject *pyIn); +LIBSHIBOKEN_API PythonToCppFunc isPythonToCppReferenceConvertible(SbkObjectType *type, PyObject *pyIn); /// This is the same as isPythonToCppValueConvertible function. LIBSHIBOKEN_API PythonToCppFunc isPythonToCppConvertible(const SbkConverter *converter, PyObject *pyIn); @@ -257,7 +257,7 @@ LIBSHIBOKEN_API void pythonToCppPointer(SbkObjectType* type, PyObject* pyIn, voi LIBSHIBOKEN_API void pythonToCppPointer(const SbkConverter *converter, PyObject *pyIn, void *cppOut); /// Converts a Python object \p pyIn to C++, and copies the result in the C++ variable passed in \p cppOut. -LIBSHIBOKEN_API void pythonToCppCopy(const SbkObjectType *type, PyObject *pyIn, void *cppOut); +LIBSHIBOKEN_API void pythonToCppCopy(SbkObjectType *type, PyObject *pyIn, void *cppOut); LIBSHIBOKEN_API void pythonToCppCopy(const SbkConverter *converter, PyObject *pyIn, void *cppOut); /** @@ -271,7 +271,7 @@ LIBSHIBOKEN_API void nonePythonToCppNullPtr(PyObject*, void* cppOut); * It is used when C++ expects a reference argument, so it may be the same object received * from Python, or another created through implicit conversion. */ -LIBSHIBOKEN_API bool isImplicitConversion(const SbkObjectType *type, PythonToCppFunc toCpp); +LIBSHIBOKEN_API bool isImplicitConversion(SbkObjectType *type, PythonToCppFunc toCpp); /// Registers a converter with a type name that may be used to retrieve the converter. LIBSHIBOKEN_API void registerConverterName(SbkConverter* converter, const char* typeName); @@ -289,7 +289,7 @@ LIBSHIBOKEN_API bool checkSequenceTypes(PyTypeObject* type, PyObject* pyIn); LIBSHIBOKEN_API bool convertibleSequenceTypes(const SbkConverter *converter, PyObject *pyIn); /// Returns true if a Python sequence is comprised of objects of a type convertible to \p type. -LIBSHIBOKEN_API bool convertibleSequenceTypes(const SbkObjectType *type, PyObject *pyIn); +LIBSHIBOKEN_API bool convertibleSequenceTypes(SbkObjectType *type, PyObject *pyIn); /// Returns true if a Python sequence can be converted to a C++ pair. LIBSHIBOKEN_API bool checkPairTypes(PyTypeObject* firstType, PyTypeObject* secondType, PyObject* pyIn); @@ -394,8 +394,9 @@ template<> inline PyTypeObject* SbkType<unsigned short>() { return &PyInt_Type; #define PyObject_Check(X) true #define SbkChar_Check(X) (SbkNumber_Check(X) || Shiboken::String::checkChar(X)) -struct _SbkGenericType { PyHeapTypeObject super; SbkConverter** converter; }; -#define SBK_CONVERTER(pyType) (*reinterpret_cast<_SbkGenericType*>(pyType)->converter) +struct _SbkGenericTypePrivate { + SbkConverter** converter; +}; #endif // SBK_CONVERTER_H diff --git a/sources/shiboken2/libshiboken/sbkenum.cpp b/sources/shiboken2/libshiboken/sbkenum.cpp index 37649f6fa..5f753293c 100644 --- a/sources/shiboken2/libshiboken/sbkenum.cpp +++ b/sources/shiboken2/libshiboken/sbkenum.cpp @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2016 The Qt Company Ltd. +** Copyright (C) 2018 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qt for Python. @@ -54,14 +54,18 @@ extern "C" { -struct SbkEnumType +struct SbkEnumTypePrivate { - PyHeapTypeObject super; SbkConverter** converterPtr; SbkConverter* converter; const char* cppName; }; +struct SbkEnumType +{ + PepTypeObject type; +}; + struct SbkEnumObject { PyObject_HEAD @@ -73,21 +77,9 @@ static PyObject* SbkEnumObject_repr(PyObject* self) { const SbkEnumObject *enumObj = reinterpret_cast<SbkEnumObject *>(self); if (enumObj->ob_name) - return Shiboken::String::fromFormat("%s.%s", self->ob_type->tp_name, PyBytes_AS_STRING(enumObj->ob_name)); - else - return Shiboken::String::fromFormat("%s(%ld)", self->ob_type->tp_name, enumObj->ob_value); -} - -static int SbkEnumObject_print(PyObject* self, FILE* fp, int) -{ - Py_BEGIN_ALLOW_THREADS - const SbkEnumObject *enumObj = reinterpret_cast<SbkEnumObject *>(self); - if (enumObj->ob_name) - fprintf(fp, "%s.%s", self->ob_type->tp_name, PyBytes_AS_STRING(enumObj->ob_name)); + return Shiboken::String::fromFormat("%s.%s", PepType((Py_TYPE(self)))->tp_name, PyBytes_AS_STRING(enumObj->ob_name)); else - fprintf(fp, "%s(%ld)", self->ob_type->tp_name, enumObj->ob_value); - Py_END_ALLOW_THREADS - return 0; + return Shiboken::String::fromFormat("%s(%ld)", PepType((Py_TYPE(self)))->tp_name, enumObj->ob_value); } static PyObject* SbkEnumObject_name(PyObject* self, void*) @@ -266,114 +258,54 @@ static PyGetSetDef SbkEnumGetSetList[] = { {0, 0, 0, 0, 0} // Sentinel }; -static PyNumberMethods enum_as_number = { - /* nb_add */ enum_add, - /* nb_subtract */ enum_subtract, - /* nb_multiply */ enum_multiply, -#ifndef IS_PY3K - /* nb_divide */ enum_divide, -#endif - /* nb_remainder */ 0, - /* nb_divmod */ 0, - /* nb_power */ 0, - /* nb_negative */ 0, - /* nb_positive */ enum_int, - /* nb_absolute */ 0, - /* nb_bool/nb_nonzero */ enum_bool, - /* nb_invert */ 0, - /* nb_lshift */ 0, - /* nb_rshift */ 0, - /* nb_and */ enum_and, - /* nb_xor */ enum_xor, - /* nb_or */ enum_or, +static void SbkEnumTypeDealloc(PyObject* pyObj); +static PyObject* SbkEnumTypeTpNew(PyTypeObject* metatype, PyObject* args, PyObject* kwds); + +static PyType_Slot SbkEnumType_Type_slots[] = { + {Py_tp_dealloc, (void *)SbkEnumTypeDealloc}, + {Py_nb_add, (void *)enum_add}, + {Py_nb_subtract, (void *)enum_subtract}, + {Py_nb_multiply, (void *)enum_multiply}, #ifndef IS_PY3K - /* nb_coerce */ 0, + {Py_nb_divide, (void *)enum_divide}, #endif - /* nb_int */ enum_int, + {Py_nb_positive, (void *)enum_int}, #ifdef IS_PY3K - /* nb_reserved */ 0, - /* nb_float */ 0, + {Py_nb_bool, (void *)enum_bool}, #else - /* nb_long */ enum_int, - /* nb_float */ 0, - /* nb_oct */ 0, - /* nb_hex */ 0, -#endif - - /* nb_inplace_add */ 0, - /* nb_inplace_subtract */ 0, - /* nb_inplace_multiply */ 0, -#ifndef IS_PY3K - /* nb_inplace_div */ 0, + {Py_nb_nonzero, (void *)enum_bool}, + {Py_nb_long, (void *)enum_int}, #endif - /* nb_inplace_remainder */ 0, - /* nb_inplace_power */ 0, - /* nb_inplace_lshift */ 0, - /* nb_inplace_rshift */ 0, - /* nb_inplace_and */ 0, - /* nb_inplace_xor */ 0, - /* nb_inplace_or */ 0, - - /* nb_floor_divide */ 0, - /* nb_true_divide */ 0, - /* nb_inplace_floor_divide */ 0, - /* nb_inplace_true_divide */ 0, - - /* nb_index */ enum_int + {Py_nb_and, (void *)enum_and}, + {Py_nb_xor, (void *)enum_xor}, + {Py_nb_or, (void *)enum_or}, + {Py_nb_int, (void *)enum_int}, + {Py_nb_index, (void *)enum_int}, + {Py_tp_base, (void *)&PyType_Type}, + {Py_tp_alloc, (void *)PyType_GenericAlloc}, + {Py_tp_new, (void *)SbkEnumTypeTpNew}, + {Py_tp_free, (void *)PyObject_GC_Del}, + {0, 0} +}; +static PyType_Spec SbkEnumType_Type_spec = { + "Shiboken.EnumType", + 0, // filled in later + sizeof(PyMemberDef), + Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE|Py_TPFLAGS_CHECKTYPES, + SbkEnumType_Type_slots, }; -static void SbkEnumTypeDealloc(PyObject* pyObj); -static PyObject* SbkEnumTypeTpNew(PyTypeObject* metatype, PyObject* args, PyObject* kwds); -PyTypeObject SbkEnumType_Type = { - PyVarObject_HEAD_INIT(0, 0) - /*tp_name*/ "Shiboken.EnumType", - /*tp_basicsize*/ sizeof(SbkEnumType), - /*tp_itemsize*/ 0, - /*tp_dealloc*/ SbkEnumTypeDealloc, - /*tp_print*/ 0, - /*tp_getattr*/ 0, - /*tp_setattr*/ 0, - /*tp_compare*/ 0, - /*tp_repr*/ 0, - /*tp_as_number*/ &enum_as_number, - /*tp_as_sequence*/ 0, - /*tp_as_mapping*/ 0, - /*tp_hash*/ 0, - /*tp_call*/ 0, - /*tp_str*/ 0, - /*tp_getattro*/ 0, - /*tp_setattro*/ 0, - /*tp_as_buffer*/ 0, - /*tp_flags*/ Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE|Py_TPFLAGS_CHECKTYPES, - /*tp_doc*/ 0, - /*tp_traverse*/ 0, - /*tp_clear*/ 0, - /*tp_richcompare*/ 0, - /*tp_weaklistoffset*/ 0, - /*tp_iter*/ 0, - /*tp_iternext*/ 0, - /*tp_methods*/ 0, - /*tp_members*/ 0, - /*tp_getset*/ 0, - /*tp_base*/ &PyType_Type, - /*tp_dict*/ 0, - /*tp_descr_get*/ 0, - /*tp_descr_set*/ 0, - /*tp_dictoffset*/ 0, - /*tp_init*/ 0, - /*tp_alloc*/ PyType_GenericAlloc, - /*tp_new*/ SbkEnumTypeTpNew, - /*tp_free*/ PyObject_GC_Del, - /*tp_is_gc*/ 0, - /*tp_bases*/ 0, - /*tp_mro*/ 0, - /*tp_cache*/ 0, - /*tp_subclasses*/ 0, - /*tp_weaklist*/ 0, - /*tp_del*/ 0, - /*tp_version_tag*/ 0 -}; +PyTypeObject *SbkEnumType_TypeF(void) +{ + static PyTypeObject *type = nullptr; + if (!type) { + SbkEnumType_Type_spec.basicsize = + PepHeapType_SIZE + sizeof(SbkEnumTypePrivate); + type = (PyTypeObject *)PyType_FromSpec(&SbkEnumType_Type_spec); + } + return type; +} void SbkEnumTypeDealloc(PyObject* pyObj) { @@ -381,15 +313,16 @@ void SbkEnumTypeDealloc(PyObject* pyObj) PyObject_GC_UnTrack(pyObj); Py_TRASHCAN_SAFE_BEGIN(pyObj); - if (sbkType->converter) { - Shiboken::Conversions::deleteConverter(sbkType->converter); + if (PepType_SETP(sbkType)->converter) { + Shiboken::Conversions::deleteConverter(PepType_SETP(sbkType)->converter); } Py_TRASHCAN_SAFE_END(pyObj); } PyObject* SbkEnumTypeTpNew(PyTypeObject* metatype, PyObject* args, PyObject* kwds) { - SbkEnumType* newType = reinterpret_cast<SbkEnumType*>(PyType_Type.tp_new(metatype, args, kwds)); + newfunc type_new = reinterpret_cast<newfunc>(PyType_GetSlot(&PyType_Type, Py_tp_new)); + SbkEnumType *newType = reinterpret_cast<SbkEnumType*>(type_new(metatype, args, kwds)); if (!newType) return 0; return reinterpret_cast<PyObject*>(newType); @@ -417,14 +350,14 @@ namespace Enum { bool check(PyObject* pyObj) { - return Py_TYPE(pyObj->ob_type) == &SbkEnumType_Type; + return Py_TYPE(Py_TYPE(pyObj)) == SbkEnumType_TypeF(); } PyObject* getEnumItemFromValue(PyTypeObject* enumType, long itemValue) { PyObject *key, *value; Py_ssize_t pos = 0; - PyObject* values = PyDict_GetItemString(enumType->tp_dict, const_cast<char*>("values")); + PyObject *values = PyDict_GetItemString(PepType(enumType)->tp_dict, const_cast<char*>("values")); while (PyDict_Next(values, &pos, &key, &value)) { SbkEnumObject *obj = reinterpret_cast<SbkEnumObject *>(value); @@ -438,9 +371,7 @@ PyObject* getEnumItemFromValue(PyTypeObject* enumType, long itemValue) static PyTypeObject* createEnum(const char* fullName, const char* cppName, const char* shortName, PyTypeObject* flagsType) { - PyTypeObject* enumType = newTypeWithName(fullName, cppName); - if (flagsType) - enumType->tp_as_number = flagsType->tp_as_number; + PyTypeObject* enumType = newTypeWithName(fullName, cppName, flagsType); if (PyType_Ready(enumType) < 0) return 0; return enumType; @@ -451,7 +382,8 @@ PyTypeObject* createGlobalEnum(PyObject* module, const char* name, const char* f PyTypeObject* enumType = createEnum(fullName, cppName, name, flagsType); if (enumType && PyModule_AddObject(module, name, reinterpret_cast<PyObject *>(enumType)) < 0) return 0; - if (flagsType && PyModule_AddObject(module, flagsType->tp_name, reinterpret_cast<PyObject *>(flagsType)) < 0) + if (flagsType && PyModule_AddObject(module, PepType_GetNameStr(flagsType), + reinterpret_cast<PyObject *>(flagsType)) < 0) return 0; return enumType; } @@ -459,17 +391,20 @@ PyTypeObject* createGlobalEnum(PyObject* module, const char* name, const char* f PyTypeObject* createScopedEnum(SbkObjectType* scope, const char* name, const char* fullName, const char* cppName, PyTypeObject* flagsType) { PyTypeObject* enumType = createEnum(fullName, cppName, name, flagsType); - if (enumType && PyDict_SetItemString(scope->super.ht_type.tp_dict, name, reinterpret_cast<PyObject *>(enumType)) < 0) - return 0; - if (flagsType && PyDict_SetItemString(scope->super.ht_type.tp_dict, flagsType->tp_name, reinterpret_cast<PyObject *>(flagsType)) < 0) - return 0; + if (enumType && PyDict_SetItemString(PepType(scope)->tp_dict, name, + reinterpret_cast<PyObject *>(enumType)) < 0) + return nullptr; + if (flagsType && PyDict_SetItemString(PepType(scope)->tp_dict, + PepType_GetNameStr(flagsType), + reinterpret_cast<PyObject *>(flagsType)) < 0) + return nullptr; return enumType; } static PyObject* createEnumItem(PyTypeObject* enumType, const char* itemName, long itemValue) { PyObject* enumItem = newItem(enumType, itemValue, itemName); - if (PyDict_SetItemString(enumType->tp_dict, itemName, enumItem) < 0) + if (PyDict_SetItemString(PepType(enumType)->tp_dict, itemName, enumItem) < 0) return 0; Py_DECREF(enumItem); return enumItem; @@ -496,7 +431,7 @@ bool createScopedEnumItem(PyTypeObject *enumType, PyTypeObject *scope, const char *itemName, long itemValue) { if (PyObject *enumItem = createEnumItem(enumType, itemName, itemValue)) { - if (PyDict_SetItemString(scope->tp_dict, itemName, enumItem) < 0) + if (PyDict_SetItemString(PepType(scope)->tp_dict, itemName, enumItem) < 0) return false; Py_DECREF(enumItem); return true; @@ -506,15 +441,17 @@ bool createScopedEnumItem(PyTypeObject *enumType, PyTypeObject *scope, bool createScopedEnumItem(PyTypeObject* enumType, SbkObjectType* scope, const char* itemName, long itemValue) { - return createScopedEnumItem(enumType, &scope->super.ht_type, itemName, itemValue); + return createScopedEnumItem(enumType, reinterpret_cast<PyTypeObject *>(scope), itemName, itemValue); } -PyObject* newItem(PyTypeObject* enumType, long itemValue, const char* itemName) +PyObject * +newItem(PyTypeObject *enumType, long itemValue, const char *itemName) { bool newValue = true; SbkEnumObject* enumObj; if (!itemName) { - enumObj = reinterpret_cast<SbkEnumObject*>(getEnumItemFromValue(enumType, itemValue)); + enumObj = reinterpret_cast<SbkEnumObject*>( + getEnumItemFromValue(enumType, itemValue)); if (enumObj) return reinterpret_cast<PyObject*>(enumObj); @@ -529,10 +466,10 @@ PyObject* newItem(PyTypeObject* enumType, long itemValue, const char* itemName) enumObj->ob_value = itemValue; if (newValue) { - PyObject* values = PyDict_GetItemString(enumType->tp_dict, const_cast<char*>("values")); + PyObject* values = PyDict_GetItemString(PepType(enumType)->tp_dict, const_cast<char*>("values")); if (!values) { values = PyDict_New(); - PyDict_SetItemString(enumType->tp_dict, const_cast<char*>("values"), values); + PyDict_SetItemString(PepType(enumType)->tp_dict, const_cast<char*>("values"), values); Py_DECREF(values); // ^ values still alive, because setitemstring incref it } PyDict_SetItemString(values, itemName, reinterpret_cast<PyObject*>(enumObj)); @@ -541,39 +478,140 @@ PyObject* newItem(PyTypeObject* enumType, long itemValue, const char* itemName) return reinterpret_cast<PyObject*>(enumObj); } -PyTypeObject* newType(const char* name) -{ - return newTypeWithName(name, ""); -} +static PyType_Slot SbkNewType_slots[] = { + {Py_tp_repr, (void *)SbkEnumObject_repr}, + {Py_tp_str, (void *)SbkEnumObject_repr}, + {Py_tp_getset, (void *)SbkEnumGetSetList}, + {Py_tp_new, (void *)SbkEnum_tp_new}, + {Py_nb_add, (void *)enum_add}, + {Py_nb_subtract, (void *)enum_subtract}, + {Py_nb_multiply, (void *)enum_multiply}, +#ifndef IS_PY3K + {Py_nb_divide, (void *)enum_divide}, +#endif + {Py_nb_positive, (void *)enum_int}, +#ifdef IS_PY3K + {Py_nb_bool, (void *)enum_bool}, +#else + {Py_nb_nonzero, (void *)enum_bool}, + {Py_nb_long, (void *)enum_int}, +#endif + {Py_nb_and, (void *)enum_and}, + {Py_nb_xor, (void *)enum_xor}, + {Py_nb_or, (void *)enum_or}, + {Py_nb_int, (void *)enum_int}, + {Py_nb_index, (void *)enum_int}, + {Py_tp_richcompare, (void *)enum_richcompare}, + {Py_tp_hash, (void *)enum_hash}, + {Py_tp_dealloc, (void *)SbkDummyDealloc}, + {0, 0} +}; +static PyType_Spec SbkNewType_spec = { + "missing Enum name", // to be inserted later + sizeof(SbkEnumObject), + 0, + Py_TPFLAGS_DEFAULT|Py_TPFLAGS_CHECKTYPES, + SbkNewType_slots, +}; -PyTypeObject* newTypeWithName(const char* name, const char* cppName) +static void +copyNumberMethods(PyTypeObject *flagsType, + PyType_Slot number_slots[], + int *pidx) { - PyTypeObject* type = reinterpret_cast<PyTypeObject*>(new SbkEnumType); - ::memset(type, 0, sizeof(SbkEnumType)); - Py_TYPE(type) = &SbkEnumType_Type; - type->tp_basicsize = sizeof(SbkEnumObject); - type->tp_print = &SbkEnumObject_print; - type->tp_repr = &SbkEnumObject_repr; - type->tp_str = &SbkEnumObject_repr; - type->tp_flags = Py_TPFLAGS_DEFAULT|Py_TPFLAGS_CHECKTYPES; - type->tp_name = name; - type->tp_getset = SbkEnumGetSetList; - type->tp_new = SbkEnum_tp_new; - type->tp_as_number = &enum_as_number; - type->tp_richcompare = &enum_richcompare; - type->tp_hash = &enum_hash; + int idx = *pidx; +#ifdef IS_PY3K +# define SLOT slot +#else +# define SLOT slot_ +#endif +#define PUT_SLOT(name) \ + number_slots[idx].SLOT = (name); \ + number_slots[idx].pfunc = PyType_GetSlot(flagsType, (name)); \ + ++idx; + + PUT_SLOT(Py_nb_absolute); + PUT_SLOT(Py_nb_add); + PUT_SLOT(Py_nb_and); +#ifdef IS_PY3K + PUT_SLOT(Py_nb_bool); +#else + PUT_SLOT(Py_nb_nonzero); +#endif + PUT_SLOT(Py_nb_divmod); + PUT_SLOT(Py_nb_float); + PUT_SLOT(Py_nb_floor_divide); + PUT_SLOT(Py_nb_index); + PUT_SLOT(Py_nb_inplace_add); + PUT_SLOT(Py_nb_inplace_and); + PUT_SLOT(Py_nb_inplace_floor_divide); + PUT_SLOT(Py_nb_inplace_lshift); + PUT_SLOT(Py_nb_inplace_multiply); + PUT_SLOT(Py_nb_inplace_or); + PUT_SLOT(Py_nb_inplace_power); + PUT_SLOT(Py_nb_inplace_remainder); + PUT_SLOT(Py_nb_inplace_rshift); + PUT_SLOT(Py_nb_inplace_subtract); + PUT_SLOT(Py_nb_inplace_true_divide); + PUT_SLOT(Py_nb_inplace_xor); + PUT_SLOT(Py_nb_int); + PUT_SLOT(Py_nb_invert); + PUT_SLOT(Py_nb_lshift); + PUT_SLOT(Py_nb_multiply); + PUT_SLOT(Py_nb_negative); + PUT_SLOT(Py_nb_or); + PUT_SLOT(Py_nb_positive); + PUT_SLOT(Py_nb_power); + PUT_SLOT(Py_nb_remainder); + PUT_SLOT(Py_nb_rshift); + PUT_SLOT(Py_nb_subtract); + PUT_SLOT(Py_nb_true_divide); + PUT_SLOT(Py_nb_xor); +#ifndef IS_PY3K + PUT_SLOT(Py_nb_long); + PUT_SLOT(Py_nb_divide); +#endif +#undef PUT_SLOT + *pidx = idx; +} + +PyTypeObject * +newTypeWithName(const char* name, + const char* cppName, + PyTypeObject *numbers_fromFlag) +{ + // Careful: PyType_FromSpec does not allocate the string. + PyType_Slot newslots[99] = {}; // enough but not too big for the stack + PyType_Spec *newspec = new PyType_Spec; + newspec->name = strdup(name); + newspec->basicsize = SbkNewType_spec.basicsize; + newspec->itemsize = SbkNewType_spec.itemsize; + newspec->flags = SbkNewType_spec.flags; + // we must append all the number methods, so rebuild everything: + int idx = 0; + while (SbkNewType_slots[idx].SLOT) { + newslots[idx].SLOT = SbkNewType_slots[idx].SLOT; + newslots[idx].pfunc = SbkNewType_slots[idx].pfunc; + ++idx; + } + if (numbers_fromFlag) + copyNumberMethods(numbers_fromFlag, newslots, &idx); + newspec->slots = newslots; + PyTypeObject *type = reinterpret_cast<PyTypeObject *>(PyType_FromSpec(newspec)); + Py_TYPE(type) = SbkEnumType_TypeF(); + Py_INCREF(Py_TYPE(type)); SbkEnumType* enumType = reinterpret_cast<SbkEnumType*>(type); - enumType->cppName = cppName; - enumType->converterPtr = &enumType->converter; + PepType_SETP(enumType)->cppName = cppName; + PepType_SETP(enumType)->converterPtr = &PepType_SETP(enumType)->converter; DeclaredEnumTypes::instance().addEnumType(type); return type; } const char* getCppName(PyTypeObject* enumType) { - assert(Py_TYPE(enumType) == &SbkEnumType_Type); - return reinterpret_cast<SbkEnumType*>(enumType)->cppName;; + assert(Py_TYPE(enumType) == SbkEnumType_TypeF()); + return PepType_SETP(reinterpret_cast<SbkEnumType*>(enumType))->cppName; } long int getValue(PyObject* enumItem) @@ -585,13 +623,13 @@ long int getValue(PyObject* enumItem) void setTypeConverter(PyTypeObject* enumType, SbkConverter* converter) { //reinterpret_cast<SbkEnumType*>(enumType)->converter = converter; - SBK_CONVERTER(enumType) = converter; + *PepType_SGTP(enumType)->converter = converter; } SbkConverter* getTypeConverter(PyTypeObject* enumType) { //return reinterpret_cast<SbkEnumType*>(enumType)->converter; - return SBK_CONVERTER(enumType); + return *PepType_SGTP(enumType)->converter; } } // namespace Enum @@ -609,8 +647,17 @@ DeclaredEnumTypes::DeclaredEnumTypes() DeclaredEnumTypes::~DeclaredEnumTypes() { std::list<PyTypeObject*>::const_iterator it = m_enumTypes.begin(); - for (; it != m_enumTypes.end(); ++it) - delete *it; + for (; it != m_enumTypes.end(); ++it) { + /* + * PYSIDE-595: This was "delete *it;" before introducing 'PyType_FromSpec'. + * XXX what should I do now? + * Refcounts in tests are 30 or 0 at end. + * When I add the default tp_dealloc, we get negative refcounts! + * So right now I am doing nothing. Surely wrong but no crash. + * See also the comment in function 'createGlobalEnumItem'. + */ + //fprintf(stderr, "ttt %d %s\n", Py_REFCNT(*it), PepType(*it)->tp_name); + } m_enumTypes.clear(); } diff --git a/sources/shiboken2/libshiboken/sbkenum.h b/sources/shiboken2/libshiboken/sbkenum.h index 4e4665423..c1ec7c4c1 100644 --- a/sources/shiboken2/libshiboken/sbkenum.h +++ b/sources/shiboken2/libshiboken/sbkenum.h @@ -46,9 +46,11 @@ extern "C" { -extern LIBSHIBOKEN_API PyTypeObject SbkEnumType_Type; +extern LIBSHIBOKEN_API PyTypeObject *SbkEnumType_TypeF(void); struct SbkObjectType; struct SbkConverter; +struct SbkEnumType; +struct SbkEnumTypePrivate; } // extern "C" @@ -57,7 +59,7 @@ namespace Shiboken inline bool isShibokenEnum(PyObject* pyObj) { - return Py_TYPE(pyObj->ob_type) == &SbkEnumType_Type; + return Py_TYPE(Py_TYPE(pyObj)) == SbkEnumType_TypeF(); } namespace Enum @@ -101,9 +103,8 @@ namespace Enum LIBSHIBOKEN_API PyObject* newItem(PyTypeObject* enumType, long itemValue, const char* itemName = 0); - /// \deprecated Use 'newTypeWithName' - SBK_DEPRECATED(LIBSHIBOKEN_API PyTypeObject* newType(const char* name)); - LIBSHIBOKEN_API PyTypeObject* newTypeWithName(const char* name, const char* cppName); + LIBSHIBOKEN_API PyTypeObject* newTypeWithName(const char* name, const char* cppName, + PyTypeObject *numbers_fromFlag=nullptr); LIBSHIBOKEN_API const char* getCppName(PyTypeObject* type); LIBSHIBOKEN_API long getValue(PyObject* enumItem); diff --git a/sources/shiboken2/libshiboken/sbkpython.h b/sources/shiboken2/libshiboken/sbkpython.h index 6d90f4086..5fe364a29 100644 --- a/sources/shiboken2/libshiboken/sbkpython.h +++ b/sources/shiboken2/libshiboken/sbkpython.h @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2016 The Qt Company Ltd. +** Copyright (C) 2018 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qt for Python. @@ -40,8 +40,15 @@ #ifndef SBKPYTHON_H #define SBKPYTHON_H -#include "Python.h" +#include "sbkversion.h" + +#include <Python.h> +#include <structmember.h> +// Now we have the usual variables from Python.h . #include "python25compat.h" +#include "shibokenmacros.h" +#include "pep384impl.h" +#include "typespec.h" #if PY_MAJOR_VERSION >= 3 #define IS_PY3K diff --git a/sources/shiboken2/libshiboken/sbkstring.cpp b/sources/shiboken2/libshiboken/sbkstring.cpp index 58f58d286..b92674383 100644 --- a/sources/shiboken2/libshiboken/sbkstring.cpp +++ b/sources/shiboken2/libshiboken/sbkstring.cpp @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2016 The Qt Company Ltd. +** Copyright (C) 2018 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qt for Python. @@ -108,7 +108,7 @@ const char* toCString(PyObject* str, Py_ssize_t* len) } // Return unicode from str instead of uniStr, because the lifetime of the returned pointer // depends on the lifetime of str. - return _PyUnicode_AsString(str); + return _PepUnicode_AsString(str); } #endif if (PyBytes_Check(str)) { diff --git a/sources/shiboken2/libshiboken/sbkversion.h.in b/sources/shiboken2/libshiboken/sbkversion.h.in index 447376c1b..99ee7f93e 100644 --- a/sources/shiboken2/libshiboken/sbkversion.h.in +++ b/sources/shiboken2/libshiboken/sbkversion.h.in @@ -46,5 +46,8 @@ #define SHIBOKEN_MICRO_VERSION @shiboken_MICRO_VERSION@ #define SHIBOKEN_RELEASE_LEVEL "final" #define SHIBOKEN_SERIAL 0 +#define PYTHON_VERSION_MAJOR @PYTHON_VERSION_MAJOR@ +#define PYTHON_VERSION_MINOR @PYTHON_VERSION_MINOR@ +#define PYTHON_VERSION_PATCH @PYTHON_VERSION_PATCH@ #endif diff --git a/sources/shiboken2/libshiboken/shibokenbuffer.cpp b/sources/shiboken2/libshiboken/shibokenbuffer.cpp index 2404aeb66..05b68dade 100644 --- a/sources/shiboken2/libshiboken/shibokenbuffer.cpp +++ b/sources/shiboken2/libshiboken/shibokenbuffer.cpp @@ -84,7 +84,9 @@ PyObject* Shiboken::Buffer::newObject(void* memory, Py_ssize_t size, Type type) view.itemsize = sizeof(char); Py_ssize_t shape[] = { size }; view.shape = shape; - return PyMemoryView_FromBuffer(&view); + // Pep384: This is way too complicated and impossible with the limited api: + //return PyMemoryView_FromBuffer(&view); + return PyMemoryView_FromMemory((char *)view.buf, size, type == ReadOnly ? PyBUF_READ : PyBUF_WRITE); #else return type == ReadOnly ? PyBuffer_FromMemory(memory, size) : PyBuffer_FromReadWriteMemory(memory, size); #endif diff --git a/sources/shiboken2/libshiboken/signature.cpp b/sources/shiboken2/libshiboken/signature.cpp index b266784c0..fc83f89cd 100644 --- a/sources/shiboken2/libshiboken/signature.cpp +++ b/sources/shiboken2/libshiboken/signature.cpp @@ -114,7 +114,7 @@ extern "C" #if EXTENSION_ENABLED // These constants were needed in former versions of the module: -#define PYTHON_HAS_QUALNAME (PY_VERSION_HEX >= 0x03060000) +#define PYTHON_HAS_QUALNAME (PY_VERSION_HEX >= 0x03030000) #define PYTHON_HAS_UNICODE (PY_VERSION_HEX >= 0x03000000) #define PYTHON_HAS_WEAKREF_PYCFUNCTION (PY_VERSION_HEX >= 0x030500A0) #define PYTHON_IS_PYTHON3 (PY_VERSION_HEX >= 0x03000000) @@ -124,15 +124,16 @@ extern "C" #define PYTHON_HAS_METH_REDUCE (PYTHON_HAS_DESCR_REDUCE) #define PYTHON_NEEDS_ITERATOR_FLAG (!PYTHON_IS_PYTHON3) #define PYTHON_EXPOSES_METHODDESCR (PYTHON_IS_PYTHON3) +#define PYTHON_NO_TYPE_IN_FUNCTIONS (!PYTHON_IS_PYTHON3 || Py_LIMITED_API) // These constants are still in use: #define PYTHON_USES_D_COMMON (PY_VERSION_HEX >= 0x03020000) -#define PYTHON_NO_TYPE_IN_FUNCTIONS (!PYTHON_IS_PYTHON3) typedef struct safe_globals_struc { // init part 1: get arg_dict PyObject *helper_module; PyObject *arg_dict; + PyObject *map_dict; // init part 2: run module PyObject *sigparse_func; PyObject *createsig_func; @@ -164,9 +165,9 @@ CreateSignature(PyObject *props, const char *sig_kind) } static PyObject * -pyside_cf_get___signature__(PyCFunctionObject *func) +pyside_cf_get___signature__(PyObject *func) { - return GetSignature_Function(func); + return GetSignature_Function((PyCFunctionObject *)func); } static PyObject * @@ -180,22 +181,107 @@ pyside_sm_get___signature__(PyObject *sm) return ret; } +#ifdef Py_LIMITED_API + +static int +build_qualname_to_func(PyObject *obtype) +{ + PyTypeObject *type = (PyTypeObject *)obtype; + PyMethodDef *meth = PepType(type)->tp_methods; + + if (meth == 0) + return 0; + + for (; meth->ml_name != NULL; meth++) { + PyObject *func = PyCFunction_NewEx(meth, obtype, NULL); + PyObject *qualname = PyObject_GetAttrString(func, "__qualname__"); + if (func == NULL || qualname == NULL) { + return -1; + } + if (PyDict_SetItem(pyside_globals->map_dict, qualname, func) < 0) { + return -1; + } + Py_DECREF(func); + Py_DECREF(qualname); + } + return 0; +} + static PyObject * -pyside_md_get___signature__(PyMethodDescrObject *descr) +qualname_to_typename(PyObject *qualname) { - PyCFunctionObject *func; - PyObject *result; + PyObject *func = PyObject_GetAttrString(qualname, "split"); + PyObject *list = func ? PyObject_CallFunction(func, (char *)"(s)", ".") + : NULL; + PyObject *res = list ? PyList_GetItem(list, 0) : NULL; + Py_XINCREF(res); + Py_XDECREF(func); + Py_XDECREF(list); + return res; +} + +static PyObject * +qualname_to_func(PyObject *ob) +{ + /* + * If we have __qualname__, then we can easily build a mapping + * from __qualname__ to PyCFunction. This is necessary when + * the limited API does not let us go easily from descriptor + * to PyMethodDef. + */ + PyObject *ret; + PyObject *qualname = PyObject_GetAttrString((PyObject *)ob, + "__qualname__"); + if (qualname != NULL) { + ret = PyDict_GetItem(pyside_globals->map_dict, qualname); + if (ret == NULL) { + // do a lazy initialization + PyObject *type_name = qualname_to_typename(qualname); + PyObject *type = PyDict_GetItem(pyside_globals->map_dict, + type_name); + Py_XDECREF(type_name); + if (type == NULL) + Py_RETURN_NONE; + if (build_qualname_to_func(type) < 0) + return NULL; + ret = PyDict_GetItem(pyside_globals->map_dict, qualname); + } + Py_XINCREF(ret); + Py_DECREF(qualname); + } + else + Py_RETURN_NONE; + return ret; +} +#endif - func = (PyCFunctionObject *) - PyCFunction_NewEx(descr->d_method, -#if PYTHON_USES_D_COMMON - (PyObject *)descr->d_common.d_type, NULL +static PyObject * +pyside_md_get___signature__(PyObject *ob) +{ + PyObject *func; + PyObject *result; +#ifndef Py_LIMITED_API + PyMethodDescrObject *descr = (PyMethodDescrObject *)ob; + +# if PYTHON_USES_D_COMMON + func = PyCFunction_NewEx(descr->d_method, + (PyObject *)descr->d_common.d_type, NULL); +# else + func = PyCFunction_NewEx(descr->d_method, + (PyObject *)descr->d_type, NULL); +# endif #else - (PyObject *)descr->d_type, NULL + /* + * With limited access, we cannot use the fields of a method descriptor, + * but in Python 3 we have the __qualname__ field which allows us to + * grab the method object from our registry. + */ + func = qualname_to_func(ob); #endif - ); + if (func == Py_None) + return Py_None; if (func == NULL) - return NULL; + Py_FatalError("missing mapping in MethodDescriptor"); result = pyside_cf_get___signature__(func); Py_DECREF(func); return result; @@ -215,16 +301,15 @@ GetSignature_Function(PyCFunctionObject *func) const char *sig_kind; int flags; - selftype = func->m_self; - if (selftype == NULL) { -#if PYTHON_NO_TYPE_IN_FUNCTIONS - selftype = PyDict_GetItem(pyside_globals->arg_dict, (PyObject *)func); - } + selftype = PyCFunction_GET_SELF((PyObject *)func); + if (selftype == NULL) + selftype = PyDict_GetItem(pyside_globals->map_dict, (PyObject *)func); if (selftype == NULL) { -#endif if (!PyErr_Occurred()) { PyErr_Format(PyExc_SystemError, - "the signature for \"%s\" should exist", func->m_ml->ml_name); + "the signature for \"%s\" should exist", + PepCFunction_GET_NAMESTR(func) + ); } return NULL; } @@ -251,7 +336,7 @@ GetSignature_Function(PyCFunctionObject *func) props = PyDict_GetItem(dict, func_name); if (props == NULL) Py_RETURN_NONE; - flags = PyCFunction_GET_FLAGS(func); + flags = PyCFunction_GET_FLAGS((PyObject *)func); if (flags & METH_CLASS) sig_kind = "classmethod"; else if (flags & METH_STATIC) @@ -347,6 +432,11 @@ init_phase_1(void) goto error; Py_DECREF(v); + // build a dict for diverse mappings + p->map_dict = PyDict_New(); + if (p->map_dict == NULL) + goto error; + // Build a dict for the prepared arguments p->arg_dict = PyDict_New(); if (p->arg_dict == NULL) @@ -387,7 +477,7 @@ error: static int add_more_getsets(PyTypeObject *type, PyGetSetDef *gsp) { - PyObject *dict = type->tp_dict; + PyObject *dict = PepType(type)->tp_dict; for (; gsp->name != NULL; gsp++) { PyObject *descr; @@ -479,16 +569,17 @@ PySideType_Ready(PyTypeObject *type) // PyMethodDescr_Type 'type(str.__dict__["split"])' // PyClassMethodDescr_Type. 'type(dict.__dict__["fromkeys"])' // The latter is not needed until we use class methods in PySide. - md = PyDict_GetItemString(PyString_Type.tp_dict, "split"); + md = PyObject_GetAttrString((PyObject *)&PyString_Type, "split"); if (md == NULL || PyType_Ready(Py_TYPE(md)) < 0 || add_more_getsets(Py_TYPE(md), new_PyMethodDescr_getsets) < 0 || add_more_getsets(&PyCFunction_Type, new_PyCFunction_getsets) < 0 - || add_more_getsets(&PyStaticMethod_Type, new_PyStaticMethod_getsets) < 0 + || add_more_getsets(PepStaticMethod_TypePtr, new_PyStaticMethod_getsets) < 0 || add_more_getsets(&PyType_Type, new_PyType_getsets) < 0) return -1; + Py_DECREF(md); #ifndef _WIN32 - // we enable the stack trace in CI, only. + // We enable the stack trace in CI, only. const char *testEnv = getenv("QTEST_ENVIRONMENT"); if (testEnv && strstr(testEnv, "ci")) signal(SIGSEGV, handler); // install our handler @@ -498,20 +589,12 @@ PySideType_Ready(PyTypeObject *type) return PyType_Ready(type); } -#if PYTHON_NO_TYPE_IN_FUNCTIONS - -typedef struct { - PyObject_HEAD - PyObject *sm_callable; - PyObject *sm_dict; -} staticmethod; - static int build_func_to_type(PyObject *obtype) { PyTypeObject *type = (PyTypeObject *)obtype; - PyObject *dict = type->tp_dict; - PyMethodDef *meth = type->tp_methods; + PyObject *dict = PepType(type)->tp_dict; + PyMethodDef *meth = PepType(type)->tp_methods; if (meth == 0) return 0; @@ -521,19 +604,16 @@ build_func_to_type(PyObject *obtype) PyObject *descr = PyDict_GetItemString(dict, meth->ml_name); if (descr == NULL) return -1; - staticmethod *sm = (staticmethod *)descr; - PyObject *cfunc = sm->sm_callable; - if (cfunc == NULL) - return -1; - if (PyDict_SetItem(pyside_globals->arg_dict, cfunc, obtype) < 0) + PyObject *func = PyObject_GetAttrString(descr, "__func__"); + if (func == NULL || + PyDict_SetItem(pyside_globals->map_dict, func, obtype) < 0) return -1; + Py_DECREF(func); } } return 0; } -#endif - static int PySide_BuildSignatureArgs(PyObject *module, PyObject *type, const char *signatures) @@ -574,6 +654,12 @@ PySide_BuildSignatureArgs(PyObject *module, PyObject *type, return -1; if (PyDict_SetItem(pyside_globals->arg_dict, type_name, arg_tup) < 0) return -1; + /* + * We record also a mapping from type name to type. This helps to lazily + * initialize the Py_LIMITED_API in qualname_to_func(). + */ + if (PyDict_SetItem(pyside_globals->map_dict, type_name, type) < 0) + return -1; return 0; } @@ -650,13 +736,16 @@ PySide_FinishSignatures(PyObject *module, const char *signatures) if (PySide_BuildSignatureArgs(module, module, signatures) < 0) return -1; -#if PYTHON_NO_TYPE_IN_FUNCTIONS /* * Python2 does not abuse the 'm_self' field for the type. So we need to * supply this for all static methods. * * Note: This function crashed when called from PySide_BuildSignatureArgs. * Probably this was too early. + * + * Pep384: We need to switch this always on since we have no access + * to the PyCFunction attributes. Therefore I simplified things + * and always use our own mapping. */ { PyObject *key, *value; @@ -668,12 +757,12 @@ PySide_FinishSignatures(PyObject *module, const char *signatures) while (PyDict_Next(dict, &pos, &key, &value)) { if (PyType_Check(value)) { - if (build_func_to_type(value) < 0) + PyObject *type = value; + if (build_func_to_type(type) < 0) return -1; } } } -#endif return 0; } #endif // EXTENSION_ENABLED diff --git a/sources/shiboken2/libshiboken/tmp-referencetopython/sbkconverter.cpp b/sources/shiboken2/libshiboken/tmp-referencetopython/sbkconverter.cpp index 7c20b9b58..8e351cedd 100644 --- a/sources/shiboken2/libshiboken/tmp-referencetopython/sbkconverter.cpp +++ b/sources/shiboken2/libshiboken/tmp-referencetopython/sbkconverter.cpp @@ -180,7 +180,7 @@ void pythonToCppPointer(SbkObjectType* type, PyObject* pyIn, void* cppOut) { assert(pyIn); assert(cppOut); - SbkObjectType* inType = (SbkObjectType*)pyIn->ob_type; + SbkObjectType* inType = (SbkObjectType*)Py_TYPE(pyIn); if (ObjectType::hasCast(inType)) *((void**)cppOut) = ObjectType::cast(inType, (SbkObject*)pyIn, (PyTypeObject*)type); else diff --git a/sources/shiboken2/libshiboken/tmp-referencetopython/sbkconverter.h b/sources/shiboken2/libshiboken/tmp-referencetopython/sbkconverter.h index f139a491a..cc9ea7a19 100644 --- a/sources/shiboken2/libshiboken/tmp-referencetopython/sbkconverter.h +++ b/sources/shiboken2/libshiboken/tmp-referencetopython/sbkconverter.h @@ -41,7 +41,7 @@ #define SBK_CONVERTER_H #include <limits> -#include <Python.h> +#include "sbkpython.h" #include "shibokenmacros.h" #include "basewrapper.h" diff --git a/sources/shiboken2/libshiboken/typespec.cpp b/sources/shiboken2/libshiboken/typespec.cpp new file mode 100644 index 000000000..d532c97ed --- /dev/null +++ b/sources/shiboken2/libshiboken/typespec.cpp @@ -0,0 +1,776 @@ +/**************************************************************************** +** +** Copyright (C) 2018 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt for Python. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "typespec.h" +#include <structmember.h> + +#if PY_MAJOR_VERSION < 3 + +extern "C" +{ + +// for some reason python 2.7 needs this on Windows +#ifdef WIN32 +static PyGC_Head *_PyGC_generation0; +#endif + +// from pymacro.h +#ifndef Py_PYMACRO_H +#define Py_PYMACRO_H + +/* Minimum value between x and y */ +#define Py_MIN(x, y) (((x) > (y)) ? (y) : (x)) + +/* Maximum value between x and y */ +#define Py_MAX(x, y) (((x) > (y)) ? (x) : (y)) + +/* Absolute value of the number x */ +#define Py_ABS(x) ((x) < 0 ? -(x) : (x)) + +#define _Py_XSTRINGIFY(x) #x + +/* Convert the argument to a string. For example, Py_STRINGIFY(123) is replaced + with "123" by the preprocessor. Defines are also replaced by their value. + For example Py_STRINGIFY(__LINE__) is replaced by the line number, not + by "__LINE__". */ +#define Py_STRINGIFY(x) _Py_XSTRINGIFY(x) + +/* Get the size of a structure member in bytes */ +#define Py_MEMBER_SIZE(type, member) sizeof(((type *)0)->member) + +/* Argument must be a char or an int in [-128, 127] or [0, 255]. */ +#define Py_CHARMASK(c) ((unsigned char)((c) & 0xff)) + +/* Assert a build-time dependency, as an expression. + + Your compile will fail if the condition isn't true, or can't be evaluated + by the compiler. This can be used in an expression: its value is 0. + + Example: + + #define foo_to_char(foo) \ + ((char *)(foo) \ + + Py_BUILD_ASSERT_EXPR(offsetof(struct foo, string) == 0)) + + Written by Rusty Russell, public domain, http://ccodearchive.net/ */ +#define Py_BUILD_ASSERT_EXPR(cond) \ + (sizeof(char [1 - 2*!(cond)]) - 1) + +#define Py_BUILD_ASSERT(cond) do { \ + (void)Py_BUILD_ASSERT_EXPR(cond); \ + } while (0) + +/* Get the number of elements in a visible array + + This does not work on pointers, or arrays declared as [], or function + parameters. With correct compiler support, such usage will cause a build + error (see Py_BUILD_ASSERT_EXPR). + + Written by Rusty Russell, public domain, http://ccodearchive.net/ + + Requires at GCC 3.1+ */ +// Simplified by "0 &&" +#if 0 && (defined(__GNUC__) && !defined(__STRICT_ANSI__) && \ + (((__GNUC__ == 3) && (__GNU_MINOR__ >= 1)) || (__GNUC__ >= 4))) +/* Two gcc extensions. + &a[0] degrades to a pointer: a different type from an array */ +#define Py_ARRAY_LENGTH(array) \ + (sizeof(array) / sizeof((array)[0]) \ + + Py_BUILD_ASSERT_EXPR(!__builtin_types_compatible_p(typeof(array), \ + typeof(&(array)[0])))) +#else +#define Py_ARRAY_LENGTH(array) \ + (sizeof(array) / sizeof((array)[0])) +#endif + + +/* Define macros for inline documentation. */ +#define PyDoc_VAR(name) static char name[] +#define PyDoc_STRVAR(name,str) PyDoc_VAR(name) = PyDoc_STR(str) +#ifdef WITH_DOC_STRINGS +#define PyDoc_STR(str) str +#else +#define PyDoc_STR(str) "" +#endif + +/* Below "a" is a power of 2. */ +/* Round down size "n" to be a multiple of "a". */ +#define _Py_SIZE_ROUND_DOWN(n, a) ((size_t)(n) & ~(size_t)((a) - 1)) +/* Round up size "n" to be a multiple of "a". */ +#define _Py_SIZE_ROUND_UP(n, a) (((size_t)(n) + \ + (size_t)((a) - 1)) & ~(size_t)((a) - 1)) +/* Round pointer "p" down to the closest "a"-aligned address <= "p". */ +#define _Py_ALIGN_DOWN(p, a) ((void *)((uintptr_t)(p) & ~(uintptr_t)((a) - 1))) +/* Round pointer "p" up to the closest "a"-aligned address >= "p". */ +#define _Py_ALIGN_UP(p, a) ((void *)(((uintptr_t)(p) + \ + (uintptr_t)((a) - 1)) & ~(uintptr_t)((a) - 1))) +/* Check if pointer "p" is aligned to "a"-bytes boundary. */ +#define _Py_IS_ALIGNED(p, a) (!((uintptr_t)(p) & (uintptr_t)((a) - 1))) + +#ifdef __GNUC__ +#define Py_UNUSED(name) _unused_ ## name __attribute__((unused)) +#else +#define Py_UNUSED(name) _unused_ ## name +#endif + +#endif /* Py_PYMACRO_H */ + +// from typeobject.c +static int +extra_ivars(PyTypeObject *type, PyTypeObject *base) +{ + size_t t_size = type->tp_basicsize; + size_t b_size = base->tp_basicsize; + + assert(t_size >= b_size); /* Else type smaller than base! */ + if (type->tp_itemsize || base->tp_itemsize) { + /* If itemsize is involved, stricter rules */ + return t_size != b_size || + type->tp_itemsize != base->tp_itemsize; + } + if (type->tp_weaklistoffset && base->tp_weaklistoffset == 0 && + type->tp_weaklistoffset + sizeof(PyObject *) == t_size && + type->tp_flags & Py_TPFLAGS_HEAPTYPE) + t_size -= sizeof(PyObject *); + if (type->tp_dictoffset && base->tp_dictoffset == 0 && + type->tp_dictoffset + sizeof(PyObject *) == t_size && + type->tp_flags & Py_TPFLAGS_HEAPTYPE) + t_size -= sizeof(PyObject *); + + return t_size != b_size; +} + +static void +clear_slots(PyTypeObject *type, PyObject *self) +{ + Py_ssize_t i, n; + PyMemberDef *mp; + + n = Py_SIZE(type); + mp = PyHeapType_GET_MEMBERS((PyHeapTypeObject *)type); + for (i = 0; i < n; i++, mp++) { + if (mp->type == T_OBJECT_EX && !(mp->flags & READONLY)) { + char *addr = (char *)self + mp->offset; + PyObject *obj = *(PyObject **)addr; + if (obj != NULL) { + *(PyObject **)addr = NULL; + Py_DECREF(obj); + } + } + } +} + +static void +subtype_dealloc(PyObject *self) +{ + PyTypeObject *type, *base; + destructor basedealloc; + PyThreadState *tstate = PyThreadState_GET(); + + /* Extract the type; we expect it to be a heap type */ + type = Py_TYPE(self); + assert(type->tp_flags & Py_TPFLAGS_HEAPTYPE); + + /* Test whether the type has GC exactly once */ + + if (!PyType_IS_GC(type)) { + /* It's really rare to find a dynamic type that doesn't have + GC; it can only happen when deriving from 'object' and not + adding any slots or instance variables. This allows + certain simplifications: there's no need to call + clear_slots(), or DECREF the dict, or clear weakrefs. */ + + /* Maybe call finalizer; exit early if resurrected */ + if (type->tp_del) { + type->tp_del(self); + if (self->ob_refcnt > 0) + return; + } + + /* Find the nearest base with a different tp_dealloc */ + base = type; + while ((basedealloc = base->tp_dealloc) == subtype_dealloc) { + assert(Py_SIZE(base) == 0); + base = base->tp_base; + assert(base); + } + + /* Extract the type again; tp_del may have changed it */ + type = Py_TYPE(self); + + /* Call the base tp_dealloc() */ + assert(basedealloc); + basedealloc(self); + + /* Can't reference self beyond this point */ + Py_DECREF(type); + + /* Done */ + return; + } + + /* We get here only if the type has GC */ + + /* UnTrack and re-Track around the trashcan macro, alas */ + /* See explanation at end of function for full disclosure */ + PyObject_GC_UnTrack(self); + ++_PyTrash_delete_nesting; + ++ tstate->trash_delete_nesting; + Py_TRASHCAN_SAFE_BEGIN(self); + --_PyTrash_delete_nesting; + -- tstate->trash_delete_nesting; + /* DO NOT restore GC tracking at this point. weakref callbacks + * (if any, and whether directly here or indirectly in something we + * call) may trigger GC, and if self is tracked at that point, it + * will look like trash to GC and GC will try to delete self again. + */ + + /* Find the nearest base with a different tp_dealloc */ + base = type; + while ((basedealloc = base->tp_dealloc) == subtype_dealloc) { + base = base->tp_base; + assert(base); + } + + /* If we added a weaklist, we clear it. Do this *before* calling + the finalizer (__del__), clearing slots, or clearing the instance + dict. */ + + if (type->tp_weaklistoffset && !base->tp_weaklistoffset) + PyObject_ClearWeakRefs(self); + + /* Maybe call finalizer; exit early if resurrected */ + if (type->tp_del) { + _PyObject_GC_TRACK(self); + type->tp_del(self); + if (self->ob_refcnt > 0) + goto endlabel; /* resurrected */ + else + _PyObject_GC_UNTRACK(self); + /* New weakrefs could be created during the finalizer call. + If this occurs, clear them out without calling their + finalizers since they might rely on part of the object + being finalized that has already been destroyed. */ + if (type->tp_weaklistoffset && !base->tp_weaklistoffset) { + /* Modeled after GET_WEAKREFS_LISTPTR() */ + PyWeakReference **list = (PyWeakReference **) \ + PyObject_GET_WEAKREFS_LISTPTR(self); + while (*list) + _PyWeakref_ClearRef(*list); + } + } + + /* Clear slots up to the nearest base with a different tp_dealloc */ + base = type; + while (base->tp_dealloc == subtype_dealloc) { + if (Py_SIZE(base)) + clear_slots(base, self); + base = base->tp_base; + assert(base); + } + + /* If we added a dict, DECREF it */ + if (type->tp_dictoffset && !base->tp_dictoffset) { + PyObject **dictptr = _PyObject_GetDictPtr(self); + if (dictptr != NULL) { + PyObject *dict = *dictptr; + if (dict != NULL) { + Py_DECREF(dict); + *dictptr = NULL; + } + } + } + + /* Extract the type again; tp_del may have changed it */ + type = Py_TYPE(self); + + /* Call the base tp_dealloc(); first retrack self if + * basedealloc knows about gc. + */ + if (PyType_IS_GC(base)) + _PyObject_GC_TRACK(self); + assert(basedealloc); + basedealloc(self); + + /* Can't reference self beyond this point */ + Py_DECREF(type); + + endlabel: + ++_PyTrash_delete_nesting; + ++ tstate->trash_delete_nesting; + Py_TRASHCAN_SAFE_END(self); + --_PyTrash_delete_nesting; + -- tstate->trash_delete_nesting; + + /* Explanation of the weirdness around the trashcan macros: + + Q. What do the trashcan macros do? + + A. Read the comment titled "Trashcan mechanism" in object.h. + For one, this explains why there must be a call to GC-untrack + before the trashcan begin macro. Without understanding the + trashcan code, the answers to the following questions don't make + sense. + + Q. Why do we GC-untrack before the trashcan and then immediately + GC-track again afterward? + + A. In the case that the base class is GC-aware, the base class + probably GC-untracks the object. If it does that using the + UNTRACK macro, this will crash when the object is already + untracked. Because we don't know what the base class does, the + only safe thing is to make sure the object is tracked when we + call the base class dealloc. But... The trashcan begin macro + requires that the object is *untracked* before it is called. So + the dance becomes: + + GC untrack + trashcan begin + GC track + + Q. Why did the last question say "immediately GC-track again"? + It's nowhere near immediately. + + A. Because the code *used* to re-track immediately. Bad Idea. + self has a refcount of 0, and if gc ever gets its hands on it + (which can happen if any weakref callback gets invoked), it + looks like trash to gc too, and gc also tries to delete self + then. But we're already deleting self. Double deallocation is + a subtle disaster. + + Q. Why the bizarre (net-zero) manipulation of + _PyTrash_delete_nesting around the trashcan macros? + + A. Some base classes (e.g. list) also use the trashcan mechanism. + The following scenario used to be possible: + + - suppose the trashcan level is one below the trashcan limit + + - subtype_dealloc() is called + + - the trashcan limit is not yet reached, so the trashcan level + is incremented and the code between trashcan begin and end is + executed + + - this destroys much of the object's contents, including its + slots and __dict__ + + - basedealloc() is called; this is really list_dealloc(), or + some other type which also uses the trashcan macros + + - the trashcan limit is now reached, so the object is put on the + trashcan's to-be-deleted-later list + + - basedealloc() returns + + - subtype_dealloc() decrefs the object's type + + - subtype_dealloc() returns + + - later, the trashcan code starts deleting the objects from its + to-be-deleted-later list + + - subtype_dealloc() is called *AGAIN* for the same object + + - at the very least (if the destroyed slots and __dict__ don't + cause problems) the object's type gets decref'ed a second + time, which is *BAD*!!! + + The remedy is to make sure that if the code between trashcan + begin and end in subtype_dealloc() is called, the code between + trashcan begin and end in basedealloc() will also be called. + This is done by decrementing the level after passing into the + trashcan block, and incrementing it just before leaving the + block. + + But now it's possible that a chain of objects consisting solely + of objects whose deallocator is subtype_dealloc() will defeat + the trashcan mechanism completely: the decremented level means + that the effective level never reaches the limit. Therefore, we + *increment* the level *before* entering the trashcan block, and + matchingly decrement it after leaving. This means the trashcan + code will trigger a little early, but that's no big deal. + + Q. Are there any live examples of code in need of all this + complexity? + + A. Yes. See SF bug 668433 for code that crashed (when Python was + compiled in debug mode) before the trashcan level manipulations + were added. For more discussion, see SF patches 581742, 575073 + and bug 574207. + */ +} + +static PyTypeObject * +solid_base(PyTypeObject *type) +{ + PyTypeObject *base; + + if (type->tp_base) + base = solid_base(type->tp_base); + else + base = &PyBaseObject_Type; + if (extra_ivars(type, base)) + return type; + else + return base; +} + +/* Calculate the best base amongst multiple base classes. + This is the first one that's on the path to the "solid base". */ + +static PyTypeObject * +best_base(PyObject *bases) +{ + Py_ssize_t i, n; + PyTypeObject *base, *winner, *candidate, *base_i; + PyObject *base_proto; + + assert(PyTuple_Check(bases)); + n = PyTuple_GET_SIZE(bases); + assert(n > 0); + base = NULL; + winner = NULL; + for (i = 0; i < n; i++) { + base_proto = PyTuple_GET_ITEM(bases, i); + if (PyClass_Check(base_proto)) + continue; + if (!PyType_Check(base_proto)) { + PyErr_SetString( + PyExc_TypeError, + "bases must be types"); + return NULL; + } + base_i = (PyTypeObject *)base_proto; + if (base_i->tp_dict == NULL) { + if (PyType_Ready(base_i) < 0) + return NULL; + } + if (!PyType_HasFeature(base_i, Py_TPFLAGS_BASETYPE)) { + PyErr_Format(PyExc_TypeError, + "type '%.100s' is not an acceptable base type", + base_i->tp_name); + return NULL; + } + candidate = solid_base(base_i); + if (winner == NULL) { + winner = candidate; + base = base_i; + } + else if (PyType_IsSubtype(winner, candidate)) + ; + else if (PyType_IsSubtype(candidate, winner)) { + winner = candidate; + base = base_i; + } + else { + PyErr_SetString( + PyExc_TypeError, + "multiple bases have " + "instance lay-out conflict"); + return NULL; + } + } + if (base == NULL) + PyErr_SetString(PyExc_TypeError, + "a new-style class can't have only classic bases"); + return base; +} + +static const short slotoffsets[] = { + -1, /* invalid slot_ */ +/* Generated by typeslots.py */ +0, +0, +offsetof(PyHeapTypeObject, as_mapping.mp_ass_subscript), +offsetof(PyHeapTypeObject, as_mapping.mp_length), +offsetof(PyHeapTypeObject, as_mapping.mp_subscript), +offsetof(PyHeapTypeObject, as_number.nb_absolute), +offsetof(PyHeapTypeObject, as_number.nb_add), +offsetof(PyHeapTypeObject, as_number.nb_and), +offsetof(PyHeapTypeObject, as_number.nb_nonzero), +offsetof(PyHeapTypeObject, as_number.nb_divmod), +offsetof(PyHeapTypeObject, as_number.nb_float), +offsetof(PyHeapTypeObject, as_number.nb_floor_divide), +offsetof(PyHeapTypeObject, as_number.nb_index), +offsetof(PyHeapTypeObject, as_number.nb_inplace_add), +offsetof(PyHeapTypeObject, as_number.nb_inplace_and), +offsetof(PyHeapTypeObject, as_number.nb_inplace_floor_divide), +offsetof(PyHeapTypeObject, as_number.nb_inplace_lshift), +offsetof(PyHeapTypeObject, as_number.nb_inplace_multiply), +offsetof(PyHeapTypeObject, as_number.nb_inplace_or), +offsetof(PyHeapTypeObject, as_number.nb_inplace_power), +offsetof(PyHeapTypeObject, as_number.nb_inplace_remainder), +offsetof(PyHeapTypeObject, as_number.nb_inplace_rshift), +offsetof(PyHeapTypeObject, as_number.nb_inplace_subtract), +offsetof(PyHeapTypeObject, as_number.nb_inplace_true_divide), +offsetof(PyHeapTypeObject, as_number.nb_inplace_xor), +offsetof(PyHeapTypeObject, as_number.nb_int), +offsetof(PyHeapTypeObject, as_number.nb_invert), +offsetof(PyHeapTypeObject, as_number.nb_lshift), +offsetof(PyHeapTypeObject, as_number.nb_multiply), +offsetof(PyHeapTypeObject, as_number.nb_negative), +offsetof(PyHeapTypeObject, as_number.nb_or), +offsetof(PyHeapTypeObject, as_number.nb_positive), +offsetof(PyHeapTypeObject, as_number.nb_power), +offsetof(PyHeapTypeObject, as_number.nb_remainder), +offsetof(PyHeapTypeObject, as_number.nb_rshift), +offsetof(PyHeapTypeObject, as_number.nb_subtract), +offsetof(PyHeapTypeObject, as_number.nb_true_divide), +offsetof(PyHeapTypeObject, as_number.nb_xor), +offsetof(PyHeapTypeObject, as_sequence.sq_ass_item), +offsetof(PyHeapTypeObject, as_sequence.sq_concat), +offsetof(PyHeapTypeObject, as_sequence.sq_contains), +offsetof(PyHeapTypeObject, as_sequence.sq_inplace_concat), +offsetof(PyHeapTypeObject, as_sequence.sq_inplace_repeat), +offsetof(PyHeapTypeObject, as_sequence.sq_item), +offsetof(PyHeapTypeObject, as_sequence.sq_length), +offsetof(PyHeapTypeObject, as_sequence.sq_repeat), +offsetof(PyHeapTypeObject, ht_type.tp_alloc), +offsetof(PyHeapTypeObject, ht_type.tp_base), +offsetof(PyHeapTypeObject, ht_type.tp_bases), +offsetof(PyHeapTypeObject, ht_type.tp_call), +offsetof(PyHeapTypeObject, ht_type.tp_clear), +offsetof(PyHeapTypeObject, ht_type.tp_dealloc), +offsetof(PyHeapTypeObject, ht_type.tp_del), +offsetof(PyHeapTypeObject, ht_type.tp_descr_get), +offsetof(PyHeapTypeObject, ht_type.tp_descr_set), +offsetof(PyHeapTypeObject, ht_type.tp_doc), +offsetof(PyHeapTypeObject, ht_type.tp_getattr), +offsetof(PyHeapTypeObject, ht_type.tp_getattro), +offsetof(PyHeapTypeObject, ht_type.tp_hash), +offsetof(PyHeapTypeObject, ht_type.tp_init), +offsetof(PyHeapTypeObject, ht_type.tp_is_gc), +offsetof(PyHeapTypeObject, ht_type.tp_iter), +offsetof(PyHeapTypeObject, ht_type.tp_iternext), +offsetof(PyHeapTypeObject, ht_type.tp_methods), +offsetof(PyHeapTypeObject, ht_type.tp_new), +offsetof(PyHeapTypeObject, ht_type.tp_repr), +offsetof(PyHeapTypeObject, ht_type.tp_richcompare), +offsetof(PyHeapTypeObject, ht_type.tp_setattr), +offsetof(PyHeapTypeObject, ht_type.tp_setattro), +offsetof(PyHeapTypeObject, ht_type.tp_str), +offsetof(PyHeapTypeObject, ht_type.tp_traverse), +offsetof(PyHeapTypeObject, ht_type.tp_members), +offsetof(PyHeapTypeObject, ht_type.tp_getset), +offsetof(PyHeapTypeObject, ht_type.tp_free), +offsetof(PyHeapTypeObject, as_number.nb_long), +offsetof(PyHeapTypeObject, as_number.nb_divide), +offsetof(PyHeapTypeObject, as_sequence.sq_slice), +}; + +PyObject * +PyType_FromSpecWithBases(PyType_Spec *spec, PyObject *bases) +{ + PyHeapTypeObject *res = (PyHeapTypeObject*)PyType_GenericAlloc(&PyType_Type, 0); + PyTypeObject *type, *base; + PyObject *modname; + char *s; + char *res_start = (char*)res; + PyType_Slot *slot_; + + /* Set the type name and qualname */ + s = (char *)strrchr(spec->name, '.'); // C++11 + if (s == NULL) + s = (char*)spec->name; + else + s++; + + if (res == NULL) + return NULL; + type = &res->ht_type; + /* The flags must be initialized early, before the GC traverses us */ + type->tp_flags = spec->flags | Py_TPFLAGS_HEAPTYPE; + // was PyUnicode_FromString in Python 3 + res->ht_name = PyString_FromString(s); + if (!res->ht_name) + goto fail; + // no ht_qualname in Python 2 + // res->ht_qualname = res->ht_name; + // Py_INCREF(res->ht_qualname); + type->tp_name = spec->name; + if (!type->tp_name) + goto fail; + + /* Adjust for empty tuple bases */ + if (!bases) { + base = &PyBaseObject_Type; + /* See whether Py_tp_base(s) was specified */ + for (slot_ = spec->slots; slot_->slot_; slot_++) { + if (slot_->slot_ == Py_tp_base) + base = (PyTypeObject *)slot_->pfunc; // C++11 + else if (slot_->slot_ == Py_tp_bases) { + bases = (PyObject *)slot_->pfunc; // C++11 + Py_INCREF(bases); + } + } + if (!bases) + bases = PyTuple_Pack(1, base); + if (!bases) + goto fail; + } + else + Py_INCREF(bases); + + /* Calculate best base, and check that all bases are type objects */ + base = best_base(bases); + if (base == NULL) { + goto fail; + } + if (!PyType_HasFeature(base, Py_TPFLAGS_BASETYPE)) { + PyErr_Format(PyExc_TypeError, + "type '%.100s' is not an acceptable base type", + base->tp_name); + goto fail; + } + + /* Initialize essential fields */ + // no async in Python 2 + // type->tp_as_async = &res->as_async; + type->tp_as_number = &res->as_number; + type->tp_as_sequence = &res->as_sequence; + type->tp_as_mapping = &res->as_mapping; + type->tp_as_buffer = &res->as_buffer; + /* Set tp_base and tp_bases */ + type->tp_bases = bases; + bases = NULL; + Py_INCREF(base); + type->tp_base = base; + + type->tp_basicsize = spec->basicsize; + type->tp_itemsize = spec->itemsize; + + for (slot_ = spec->slots; slot_->slot_; slot_++) { + if (slot_->slot_ < 0 + || (size_t)slot_->slot_ >= Py_ARRAY_LENGTH(slotoffsets)) { + PyErr_SetString(PyExc_RuntimeError, "invalid slot_ offset"); + goto fail; + } + if (slot_->slot_ == Py_tp_base || slot_->slot_ == Py_tp_bases) + /* Processed above */ + continue; + *(void**)(res_start + slotoffsets[slot_->slot_]) = slot_->pfunc; + + /* need to make a copy of the docstring slot_, which usually + points to a static string literal */ + if (slot_->slot_ == Py_tp_doc) { + // No signature in Python 2 + // const char *old_doc = _PyType_DocWithoutSignature(type->tp_name, slot_->pfunc); + const char *old_doc = (const char *)slot_->pfunc; + size_t len = strlen(old_doc)+1; + char *tp_doc = (char *)PyObject_MALLOC(len); // C++11 + if (tp_doc == NULL) { + PyErr_NoMemory(); + goto fail; + } + memcpy(tp_doc, old_doc, len); + type->tp_doc = tp_doc; + } + } + if (type->tp_dealloc == NULL) { + /* It's a heap type, so needs the heap types' dealloc. + subtype_dealloc will call the base type's tp_dealloc, if + necessary. */ + type->tp_dealloc = subtype_dealloc; + } + + if (PyType_Ready(type) < 0) + goto fail; + + // no ht_hached_keys in Python 2 + // if (type->tp_dictoffset) { + // res->ht_cached_keys = _PyDict_NewKeysForClass(); + // } + + /* Set type.__module__ */ + s = (char *)strrchr(spec->name, '.'); // c++11 + if (s != NULL) { + int err; + // was PyUnicode_FromStringAndSize in Python 3 + modname = PyString_FromStringAndSize( + spec->name, (Py_ssize_t)(s - spec->name)); + if (modname == NULL) { + goto fail; + } + // no PyId_ things in Python 2 + // err = _PyDict_SetItemId(type->tp_dict, &PyId___module__, modname); + err = PyDict_SetItemString(type->tp_dict, "__module__", modname); + Py_DECREF(modname); + if (err != 0) + goto fail; + } else { + // no PyErr_WarnFormat in Python 2 + // if (PyErr_WarnFormat(PyExc_DeprecationWarning, 1, + // "builtin type %.200s has no __module__ attribute", + // spec->name)) + char msg[250]; + sprintf(msg, "builtin type %.200s has no __module__ attribute", spec->name); + if (PyErr_WarnEx(PyExc_DeprecationWarning, msg, 1)) + goto fail; + } + + return (PyObject*)res; + + fail: + Py_DECREF(res); + return NULL; +} + +PyObject * +PyType_FromSpec(PyType_Spec *spec) +{ + return PyType_FromSpecWithBases(spec, NULL); +} + +void * +PyType_GetSlot(PyTypeObject *type, int slot_) +{ + if (!PyType_HasFeature(type, Py_TPFLAGS_HEAPTYPE) || slot_ < 0) { + PyErr_BadInternalCall(); + return NULL; + } + if ((size_t)slot_ >= Py_ARRAY_LENGTH(slotoffsets)) { + /* Extension module requesting slot_ from a future version */ + return NULL; + } + return *(void**)(((char*)type) + slotoffsets[slot_]); +} + +} // extern "C" +#endif // PY_MAJOR_VERSION < 3 diff --git a/sources/shiboken2/libshiboken/typespec.h b/sources/shiboken2/libshiboken/typespec.h new file mode 100644 index 000000000..799fcb1b8 --- /dev/null +++ b/sources/shiboken2/libshiboken/typespec.h @@ -0,0 +1,153 @@ +/**************************************************************************** +** +** Copyright (C) 2018 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt for Python. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef TYPESPEC_H +#define TYPESPEC_H + +#include <Python.h> +#include "shibokenmacros.h" + +#if PY_MAJOR_VERSION < 3 +extern "C" +{ + +typedef struct{ + int slot_; // slot is somehow reserved in Qt /* slot id, see below */ + void *pfunc; /* function pointer */ +} PyType_Slot; + +typedef struct{ + const char* name; + int basicsize; + int itemsize; + unsigned int flags; + PyType_Slot *slots; /* terminated by slot==0. */ +} PyType_Spec; + +LIBSHIBOKEN_API PyObject *PyType_FromSpec(PyType_Spec*); +#if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 >= 0x03030000 +LIBSHIBOKEN_API PyObject *PyType_FromSpecWithBases(PyType_Spec*, PyObject*); +#endif +#if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 >= 0x03040000 +LIBSHIBOKEN_API void* PyType_GetSlot(PyTypeObject*, int); +#endif + +// from typeslots.h +/* Do not renumber the file; these numbers are part of the stable ABI. */ +/* Disabled, see #10181 */ +#undef Py_bf_getbuffer +#undef Py_bf_releasebuffer +#define Py_mp_ass_subscript 3 +#define Py_mp_length 4 +#define Py_mp_subscript 5 +#define Py_nb_absolute 6 +#define Py_nb_add 7 +#define Py_nb_and 8 +#define Py_nb_nonzero 9 +#define Py_nb_divmod 10 +#define Py_nb_float 11 +#define Py_nb_floor_divide 12 +#define Py_nb_index 13 +#define Py_nb_inplace_add 14 +#define Py_nb_inplace_and 15 +#define Py_nb_inplace_floor_divide 16 +#define Py_nb_inplace_lshift 17 +#define Py_nb_inplace_multiply 18 +#define Py_nb_inplace_or 19 +#define Py_nb_inplace_power 20 +#define Py_nb_inplace_remainder 21 +#define Py_nb_inplace_rshift 22 +#define Py_nb_inplace_subtract 23 +#define Py_nb_inplace_true_divide 24 +#define Py_nb_inplace_xor 25 +#define Py_nb_int 26 +#define Py_nb_invert 27 +#define Py_nb_lshift 28 +#define Py_nb_multiply 29 +#define Py_nb_negative 30 +#define Py_nb_or 31 +#define Py_nb_positive 32 +#define Py_nb_power 33 +#define Py_nb_remainder 34 +#define Py_nb_rshift 35 +#define Py_nb_subtract 36 +#define Py_nb_true_divide 37 +#define Py_nb_xor 38 +#define Py_sq_ass_item 39 +#define Py_sq_concat 40 +#define Py_sq_contains 41 +#define Py_sq_inplace_concat 42 +#define Py_sq_inplace_repeat 43 +#define Py_sq_item 44 +#define Py_sq_length 45 +#define Py_sq_repeat 46 +#define Py_tp_alloc 47 +#define Py_tp_base 48 +#define Py_tp_bases 49 +#define Py_tp_call 50 +#define Py_tp_clear 51 +#define Py_tp_dealloc 52 +#define Py_tp_del 53 +#define Py_tp_descr_get 54 +#define Py_tp_descr_set 55 +#define Py_tp_doc 56 +#define Py_tp_getattr 57 +#define Py_tp_getattro 58 +#define Py_tp_hash 59 +#define Py_tp_init 60 +#define Py_tp_is_gc 61 +#define Py_tp_iter 62 +#define Py_tp_iternext 63 +#define Py_tp_methods 64 +#define Py_tp_new 65 +#define Py_tp_repr 66 +#define Py_tp_richcompare 67 +#define Py_tp_setattr 68 +#define Py_tp_setattro 69 +#define Py_tp_str 70 +#define Py_tp_traverse 71 +#define Py_tp_members 72 +#define Py_tp_getset 73 +#define Py_tp_free 74 +#define Py_nb_long 75 +#define Py_nb_divide 76 +#define Py_sq_slice 77 +} // extern "C" +#endif // PY_MAJOR_VERSION < 3 +#endif // TYPESPEC_H diff --git a/sources/shiboken2/libshiboken/voidptr.cpp b/sources/shiboken2/libshiboken/voidptr.cpp index 790297595..afb3f4040 100644 --- a/sources/shiboken2/libshiboken/voidptr.cpp +++ b/sources/shiboken2/libshiboken/voidptr.cpp @@ -55,7 +55,8 @@ typedef struct { PyObject *SbkVoidPtrObject_new(PyTypeObject *type, PyObject *args, PyObject *kwds) { - SbkVoidPtrObject *self = reinterpret_cast<SbkVoidPtrObject *>(type->tp_alloc(type, 0)); + SbkVoidPtrObject *self = + reinterpret_cast<SbkVoidPtrObject *>(PepType(type)->tp_alloc); if (self != 0) { self->cptr = 0; @@ -66,7 +67,7 @@ PyObject *SbkVoidPtrObject_new(PyTypeObject *type, PyObject *args, PyObject *kwd return reinterpret_cast<PyObject *>(self); } -#define SbkVoidPtr_Check(op) (Py_TYPE(op) == &SbkVoidPtrType) +#define SbkVoidPtr_Check(op) (Py_TYPE(op) == SbkVoidPtrTypeF()) int SbkVoidPtrObject_init(PyObject *self, PyObject *args, PyObject *kwds) @@ -168,62 +169,6 @@ PyObject *SbkVoidPtrObject_int(PyObject *v) return PyLong_FromVoidPtr(sbkObject->cptr); } -static PyNumberMethods SbkVoidPtrObjectAsNumber = { - /* nb_add */ 0, - /* nb_subtract */ 0, - /* nb_multiply */ 0, -#ifndef IS_PY3K - /* nb_divide */ 0, -#endif - /* nb_remainder */ 0, - /* nb_divmod */ 0, - /* nb_power */ 0, - /* nb_negative */ 0, - /* nb_positive */ 0, - /* nb_absolute */ 0, - /* nb_bool/nb_nonzero */ 0, - /* nb_invert */ 0, - /* nb_lshift */ 0, - /* nb_rshift */ 0, - /* nb_and */ 0, - /* nb_xor */ 0, - /* nb_or */ 0, -#ifndef IS_PY3K - /* nb_coerce */ 0, -#endif - /* nb_int */ SbkVoidPtrObject_int, -#ifdef IS_PY3K - /* nb_reserved */ 0, - /* nb_float */ 0, -#else - /* nb_long */ 0, - /* nb_float */ 0, - /* nb_oct */ 0, - /* nb_hex */ 0, -#endif - - /* nb_inplace_add */ 0, - /* nb_inplace_subtract */ 0, - /* nb_inplace_multiply */ 0, -#ifndef IS_PY3K - /* nb_inplace_div */ 0, -#endif - /* nb_inplace_remainder */ 0, - /* nb_inplace_power */ 0, - /* nb_inplace_lshift */ 0, - /* nb_inplace_rshift */ 0, - /* nb_inplace_and */ 0, - /* nb_inplace_xor */ 0, - /* nb_inplace_or */ 0, - - /* nb_floor_divide */ 0, - /* nb_true_divide */ 0, - /* nb_inplace_floor_divide */ 0, - /* nb_inplace_true_divide */ 0, - - /* nb_index */ 0 -}; - static Py_ssize_t SbkVoidPtrObject_length(PyObject *v) { SbkVoidPtrObject *sbkObject = reinterpret_cast<SbkVoidPtrObject *>(v); @@ -235,19 +180,6 @@ static Py_ssize_t SbkVoidPtrObject_length(PyObject *v) return sbkObject->size; } -static PySequenceMethods SbkVoidPtrObjectAsSequence = { - /* sq_length */ SbkVoidPtrObject_length, - /* sq_concat */ 0, - /* sq_repeat */ 0, - /* sq_item */ 0, - /* sq_slice */ 0, - /* sq_ass_item */ 0, - /* sq_ass_slice */ 0, - /* sq_contains */ 0, - /* sq_inplace_concat */ 0, - /* sq_inplace_repeat */ 0 -}; - static const char trueString[] = "True" ; static const char falseString[] = "False" ; @@ -257,7 +189,7 @@ PyObject *SbkVoidPtrObject_repr(PyObject *v) SbkVoidPtrObject *sbkObject = reinterpret_cast<SbkVoidPtrObject *>(v); PyObject *s = PyBytes_FromFormat("%s(%p, %zd, %s)", - Py_TYPE(sbkObject)->tp_name, + PepType((Py_TYPE(sbkObject)))->tp_name, sbkObject->cptr, sbkObject->size, sbkObject->isWritable ? trueString : falseString); @@ -269,7 +201,7 @@ PyObject *SbkVoidPtrObject_str(PyObject *v) { SbkVoidPtrObject *sbkObject = reinterpret_cast<SbkVoidPtrObject *>(v); PyObject *s = PyBytes_FromFormat("%s(Address %p, Size %zd, isWritable %s)", - Py_TYPE(sbkObject)->tp_name, + PepType((Py_TYPE(sbkObject)))->tp_name, sbkObject->cptr, sbkObject->size, sbkObject->isWritable ? trueString : falseString); @@ -279,61 +211,35 @@ PyObject *SbkVoidPtrObject_str(PyObject *v) // Void pointer type definition. -PyTypeObject SbkVoidPtrType = { - PyVarObject_HEAD_INIT(&PyType_Type, 0) /*ob_size*/ - "VoidPtr", /*tp_name*/ - sizeof(SbkVoidPtrObject), /*tp_basicsize*/ - 0, /*tp_itemsize*/ - 0, /*tp_dealloc*/ - 0, /*tp_print*/ - 0, /*tp_getattr*/ - 0, /*tp_setattr*/ - 0, /*tp_compare*/ - SbkVoidPtrObject_repr, /*tp_repr*/ - &SbkVoidPtrObjectAsNumber, /*tp_as_number*/ - &SbkVoidPtrObjectAsSequence, /*tp_as_sequence*/ - 0, /*tp_as_mapping*/ - 0, /*tp_hash */ - 0, /*tp_call*/ - SbkVoidPtrObject_str, /*tp_str*/ - 0, /*tp_getattro*/ - 0, /*tp_setattro*/ - 0, /*tp_as_buffer*/ - Py_TPFLAGS_DEFAULT, /*tp_flags*/ - "Void pointer wrapper", /*tp_doc*/ - 0, /*tp_traverse*/ - 0, /*tp_clear*/ - SbkVoidPtrObject_richcmp, /*tp_richcompare*/ - 0, /*tp_weaklistoffset*/ - 0, /*tp_iter*/ - 0, /*tp_iternext*/ - 0, /*tp_methods*/ - 0, /*tp_members*/ - 0, /*tp_getset*/ - 0, /*tp_base*/ - 0, /*tp_dict*/ - 0, /*tp_descr_get*/ - 0, /*tp_descr_set*/ - 0, /*tp_dictoffset*/ - SbkVoidPtrObject_init, /*tp_init*/ - 0, /*tp_alloc*/ - SbkVoidPtrObject_new, /*tp_new*/ - 0, /*tp_free*/ - 0, /*tp_is_gc*/ - 0, /*tp_bases*/ - 0, /*tp_mro*/ - 0, /*tp_cache*/ - 0, /*tp_subclasses*/ - 0, /*tp_weaklist*/ - 0, /*tp_del*/ - 0, /*tp_version_tag*/ -#if PY_MAJOR_VERSION > 3 || PY_MAJOR_VERSION == 3 && PY_MINOR_VERSION >= 4 - 0 /*tp_finalize*/ -#endif +static PyType_Slot SbkVoidPtrType_slots[] = { + {Py_tp_repr, (void *)SbkVoidPtrObject_repr}, + {Py_nb_int, (void *)SbkVoidPtrObject_int}, + {Py_sq_length, (void *)SbkVoidPtrObject_length}, + {Py_tp_str, (void *)SbkVoidPtrObject_str}, + {Py_tp_richcompare, (void *)SbkVoidPtrObject_richcmp}, + {Py_tp_init, (void *)SbkVoidPtrObject_init}, + {Py_tp_new, (void *)SbkVoidPtrObject_new}, + {Py_tp_dealloc, (void *)SbkDummyDealloc}, + {0, 0} }; +static PyType_Spec SbkVoidPtrType_spec = { + "shiboken2.libshiboken.VoidPtr", + sizeof(SbkVoidPtrObject), + 0, + Py_TPFLAGS_DEFAULT, + SbkVoidPtrType_slots, +}; + } +PyTypeObject *SbkVoidPtrTypeF(void) +{ + static PyTypeObject *type = nullptr; + if (!type) + type = (PyTypeObject *)PyType_FromSpec(&SbkVoidPtrType_spec); + return type; +} namespace VoidPtr { @@ -341,7 +247,7 @@ static int voidPointerInitialized = false; void init() { - if (PyType_Ready(reinterpret_cast<PyTypeObject *>(&SbkVoidPtrType)) < 0) + if (PyType_Ready(reinterpret_cast<PyTypeObject *>(SbkVoidPtrTypeF())) < 0) Py_FatalError("[libshiboken] Failed to initialize Shiboken.VoidPtr type."); else voidPointerInitialized = true; @@ -350,9 +256,9 @@ void init() void addVoidPtrToModule(PyObject *module) { if (voidPointerInitialized) { - Py_INCREF(&SbkVoidPtrType); - PyModule_AddObject(module, SbkVoidPtrType.tp_name, - reinterpret_cast<PyObject *>(&SbkVoidPtrType)); + Py_INCREF(SbkVoidPtrTypeF()); + PyModule_AddObject(module, PepType_GetNameStr(SbkVoidPtrTypeF()), + reinterpret_cast<PyObject *>(SbkVoidPtrTypeF())); } } @@ -361,7 +267,7 @@ static PyObject *createVoidPtr(void *cppIn, Py_ssize_t size = 0, bool isWritable if (!cppIn) Py_RETURN_NONE; - SbkVoidPtrObject *result = PyObject_NEW(SbkVoidPtrObject, &SbkVoidPtrType); + SbkVoidPtrObject *result = PyObject_New(SbkVoidPtrObject, SbkVoidPtrTypeF()); if (!result) Py_RETURN_NONE; @@ -434,7 +340,7 @@ static PythonToCppFunc PythonBufferToCppIsConvertible(PyObject *pyIn) SbkConverter *createConverter() { - SbkConverter *converter = Shiboken::Conversions::createConverter(&SbkVoidPtrType, toPython); + SbkConverter *converter = Shiboken::Conversions::createConverter(SbkVoidPtrTypeF(), toPython); Shiboken::Conversions::addPythonToCppValueConversion(converter, VoidPtrToCpp, VoidPtrToCppIsConvertible); diff --git a/sources/shiboken2/libshiboken/voidptr.h b/sources/shiboken2/libshiboken/voidptr.h index 240895df8..e74c1045e 100644 --- a/sources/shiboken2/libshiboken/voidptr.h +++ b/sources/shiboken2/libshiboken/voidptr.h @@ -40,7 +40,7 @@ #ifndef VOIDPTR_H #define VOIDPTR_H -#include <Python.h> +#include "sbkpython.h" #include "shibokenmacros.h" #include "sbkconverter.h" @@ -48,7 +48,7 @@ extern "C" { // Void pointer type declaration. -extern LIBSHIBOKEN_API PyTypeObject SbkVoidPtrType; +extern LIBSHIBOKEN_API PyTypeObject *SbkVoidPtrTypeF(void); } // extern "C" diff --git a/sources/shiboken2/tests/minimalbinding/CMakeLists.txt b/sources/shiboken2/tests/minimalbinding/CMakeLists.txt index 7edb0290a..b8b6417d1 100644 --- a/sources/shiboken2/tests/minimalbinding/CMakeLists.txt +++ b/sources/shiboken2/tests/minimalbinding/CMakeLists.txt @@ -26,7 +26,8 @@ include_directories(${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_SOURCE_DIR} ${SBK_PYTHON_INCLUDE_DIR} ${libminimal_SOURCE_DIR} - ${libshiboken_SOURCE_DIR}) + ${libshiboken_SOURCE_DIR} + ${libshiboken_BINARY_DIR}) add_library(minimal MODULE ${minimal_SRC}) set_property(TARGET minimal PROPERTY PREFIX "") set_property(TARGET minimal PROPERTY OUTPUT_NAME "minimal${PYTHON_EXTENSION_SUFFIX}") diff --git a/sources/shiboken2/tests/otherbinding/CMakeLists.txt b/sources/shiboken2/tests/otherbinding/CMakeLists.txt index 7d4dd5b55..186766b41 100644 --- a/sources/shiboken2/tests/otherbinding/CMakeLists.txt +++ b/sources/shiboken2/tests/otherbinding/CMakeLists.txt @@ -32,7 +32,8 @@ include_directories(${CMAKE_CURRENT_SOURCE_DIR} ${libsample_SOURCE_DIR}/.. ${sample_BINARY_DIR} ${sample_BINARY_DIR}/sample - ${libshiboken_SOURCE_DIR}) + ${libshiboken_SOURCE_DIR} + ${libshiboken_BINARY_DIR}) add_library(other MODULE ${other_SRC}) set_property(TARGET other PROPERTY PREFIX "") set_property(TARGET other PROPERTY OUTPUT_NAME "other${PYTHON_EXTENSION_SUFFIX}") diff --git a/sources/shiboken2/tests/samplebinding/CMakeLists.txt b/sources/shiboken2/tests/samplebinding/CMakeLists.txt index 78ddfca0a..32117e44a 100644 --- a/sources/shiboken2/tests/samplebinding/CMakeLists.txt +++ b/sources/shiboken2/tests/samplebinding/CMakeLists.txt @@ -136,7 +136,8 @@ include_directories(${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_SOURCE_DIR} ${SBK_PYTHON_INCLUDE_DIR} ${libsample_SOURCE_DIR} - ${libshiboken_SOURCE_DIR}) + ${libshiboken_SOURCE_DIR} + ${libshiboken_BINARY_DIR}) add_library(sample MODULE ${sample_SRC}) set_property(TARGET sample PROPERTY PREFIX "") set_property(TARGET sample PROPERTY OUTPUT_NAME "sample${PYTHON_EXTENSION_SUFFIX}") diff --git a/sources/shiboken2/tests/samplebinding/bytearray_bufferprotocol.cpp b/sources/shiboken2/tests/samplebinding/bytearray_bufferprotocol.cpp index 8f01b4a0a..322387088 100644 --- a/sources/shiboken2/tests/samplebinding/bytearray_bufferprotocol.cpp +++ b/sources/shiboken2/tests/samplebinding/bytearray_bufferprotocol.cpp @@ -33,7 +33,7 @@ extern "C" { static Py_ssize_t SbkByteArray_segcountproc(PyObject* self, Py_ssize_t* lenp) { if (lenp) - *lenp = self->ob_type->tp_as_sequence->sq_length(self); + *lenp = Py_TYPE(self)->tp_as_sequence->sq_length(self); return 1; } static Py_ssize_t SbkByteArray_readbufferproc(PyObject* self, Py_ssize_t segment, void** ptrptr) diff --git a/sources/shiboken2/tests/samplebinding/namespace_test.py b/sources/shiboken2/tests/samplebinding/namespace_test.py index a5065c7a6..5fcdab974 100644 --- a/sources/shiboken2/tests/samplebinding/namespace_test.py +++ b/sources/shiboken2/tests/samplebinding/namespace_test.py @@ -33,12 +33,7 @@ import unittest from sample import * -from py3kcompat import IS_PY3K -if IS_PY3K: - TYPE_STR = "class" -else: - TYPE_STR = "type" class TestEnumUnderNamespace(unittest.TestCase): def testInvisibleNamespace(self): @@ -59,11 +54,16 @@ class TestClassesUnderNamespace(unittest.TestCase): self.assertEqual(res, 4) def testTpNames(self): - self.assertEqual(str(SampleNamespace.SomeClass), "<%s 'sample.SampleNamespace.SomeClass'>"%TYPE_STR) - self.assertEqual(str(SampleNamespace.SomeClass.ProtectedEnum), "<%s 'sample.SampleNamespace.SomeClass.ProtectedEnum'>"%TYPE_STR) - self.assertEqual(str(SampleNamespace.SomeClass.SomeInnerClass.ProtectedEnum), "<%s 'sample.SampleNamespace.SomeClass.SomeInnerClass.ProtectedEnum'>"%TYPE_STR) - self.assertEqual(str(SampleNamespace.SomeClass.SomeInnerClass.OkThisIsRecursiveEnough), "<%s 'sample.SampleNamespace.SomeClass.SomeInnerClass.OkThisIsRecursiveEnough'>"%TYPE_STR) - self.assertEqual(str(SampleNamespace.SomeClass.SomeInnerClass.OkThisIsRecursiveEnough.NiceEnum), "<%s 'sample.SampleNamespace.SomeClass.SomeInnerClass.OkThisIsRecursiveEnough.NiceEnum'>"%TYPE_STR) + self.assertEqual(str(SampleNamespace.SomeClass), + "<class 'sample.SampleNamespace.SomeClass'>") + self.assertEqual(str(SampleNamespace.SomeClass.ProtectedEnum), + "<class 'sample.SampleNamespace.SomeClass.ProtectedEnum'>") + self.assertEqual(str(SampleNamespace.SomeClass.SomeInnerClass.ProtectedEnum), + "<class 'sample.SampleNamespace.SomeClass.SomeInnerClass.ProtectedEnum'>") + self.assertEqual(str(SampleNamespace.SomeClass.SomeInnerClass.OkThisIsRecursiveEnough), + "<class 'sample.SampleNamespace.SomeClass.SomeInnerClass.OkThisIsRecursiveEnough'>") + self.assertEqual(str(SampleNamespace.SomeClass.SomeInnerClass.OkThisIsRecursiveEnough.NiceEnum), + "<class 'sample.SampleNamespace.SomeClass.SomeInnerClass.OkThisIsRecursiveEnough.NiceEnum'>") if __name__ == '__main__': unittest.main() diff --git a/sources/shiboken2/tests/samplebinding/typesystem_sample.xml b/sources/shiboken2/tests/samplebinding/typesystem_sample.xml index 3cc80860d..5f0a9206b 100644 --- a/sources/shiboken2/tests/samplebinding/typesystem_sample.xml +++ b/sources/shiboken2/tests/samplebinding/typesystem_sample.xml @@ -1666,7 +1666,7 @@ Tested in InjectCodeTest.testTypeNativeBeginning_TypeTargetBeginning: --> <inject-code class="target" position="beginning"> - %PYTHONTYPEOBJECT.tp_str = InjectCode_tpstr; + PepType(&%PYTHONTYPEOBJECT)->tp_str = InjectCode_tpstr; </inject-code> <!-- Tested in InjectCodeTest.testFunctionTargetBeginning_FunctionTargetEnd --> @@ -2178,7 +2178,7 @@ </add-function> <add-function signature="__repr__" return-type="PyObject*"> <inject-code class="target" position="beginning"> - ByteArray b(((PyObject*)%PYSELF)->ob_type->tp_name); + ByteArray b(PepType(Py_TYPE(%PYSELF))->tp_name); PyObject* aux = Shiboken::String::fromStringAndSize(%CPPSELF.data(), %CPPSELF.size()); if (PyUnicode_CheckExact(aux)) { PyObject* tmp = PyUnicode_AsASCIIString(aux); diff --git a/sources/shiboken2/tests/smartbinding/CMakeLists.txt b/sources/shiboken2/tests/smartbinding/CMakeLists.txt index aab2121d3..faaa797b6 100644 --- a/sources/shiboken2/tests/smartbinding/CMakeLists.txt +++ b/sources/shiboken2/tests/smartbinding/CMakeLists.txt @@ -27,7 +27,8 @@ include_directories(${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_SOURCE_DIR} ${SBK_PYTHON_INCLUDE_DIR} ${libsmart_SOURCE_DIR} - ${libshiboken_SOURCE_DIR}) + ${libshiboken_SOURCE_DIR} + ${libshiboken_BINARY_DIR}) add_library(smart MODULE ${smart_SRC}) set_property(TARGET smart PROPERTY PREFIX "") set_property(TARGET smart PROPERTY OUTPUT_NAME "smart${PYTHON_EXTENSION_SUFFIX}") |