[neon/qt/pyside2/Neon/unstable] /: New upstream version 5.15.7
Dmitry Shachnev
null at kde.org
Thu Jun 15 10:12:12 BST 2023
Git commit feca35ce028387e3e2c07cc9581473fc0949a09a by Dmitry Shachnev.
Committed on 31/12/2022 at 18:05.
Pushed by carlosdem into branch 'Neon/unstable'.
New upstream version 5.15.7
M +3 -3 build_history/blacklist.txt
M +2 -1 build_scripts/config.py
M +26 -9 build_scripts/main.py
M +6 -1 build_scripts/platforms/windows_desktop.py
M +6 -1 build_scripts/setup_runner.py
M +10 -0 build_scripts/utils.py
M +1 -1 build_scripts/wheel_override.py
A +46 -0 coin/dependencies.yaml
M +7 -0 coin/instructions/common_environment.yaml
M +1 -1 coin/instructions/execute_build_instructions.yaml
M +6 -0 coin/instructions/execute_license_check.yaml
M +1 -1 coin/instructions/execute_test_instructions.yaml
M +7 -7 coin/instructions/relocate_pyside.yaml
M +9 -9 coin/module_config.yaml
M +5 -1 coin_build_instructions.py
M +3 -1 coin_test_instructions.py
A +46 -0 dist/changes-5.15.3
A +38 -0 dist/changes-5.15.4
A +30 -0 dist/changes-5.15.5
A +34 -0 dist/changes-5.15.6
A +33 -0 dist/changes-5.15.7
M +6 -8 examples/widgets/mainwindows/application/application.py
M +8 -10 examples/widgets/mainwindows/mdi/mdi.py
M +15 -8 examples/widgets/richtext/textobject/textobject.py
D +0 -3 product_dependencies.yaml
M +3 -1 sources/pyside2-tools/pyside_tool.py
M +1 -1 sources/pyside2/CMakeLists.txt
M +21 -1 sources/pyside2/PySide2/QtCore/typesystem_core_common.xml
M +65 -66 sources/pyside2/PySide2/QtDataVisualization/typesystem_datavisualization.xml
M +1 -1 sources/pyside2/PySide2/QtGui/CMakeLists.txt
M +38 -5 sources/pyside2/PySide2/QtGui/typesystem_gui_common.xml
M +2 -0 sources/pyside2/PySide2/QtNetwork/typesystem_network.xml
M +5 -1 sources/pyside2/PySide2/QtOpenGLFunctions/CMakeLists.txt
M +2 -0 sources/pyside2/PySide2/QtOpenGLFunctions/QtOpenGLFunctions_global.post.h.in
M +9 -0 sources/pyside2/PySide2/QtOpenGLFunctions/typesystem_openglfunctions.xml
M +3 -3 sources/pyside2/PySide2/QtQml/pysideqmlregistertype.cpp
M +8 -1 sources/pyside2/PySide2/QtQml/typesystem_qml.xml
M +1 -0 sources/pyside2/PySide2/QtTest/CMakeLists.txt
M +4 -0 sources/pyside2/PySide2/QtTest/typesystem_test.xml
M +4 -0 sources/pyside2/PySide2/QtWidgets/typesystem_widgets_common.xml
M +73 -35 sources/pyside2/PySide2/glue/qtcore.cpp
M +37 -0 sources/pyside2/PySide2/glue/qtdatavisualization.cpp
M +57 -0 sources/pyside2/PySide2/glue/qtgui.cpp
A +76 -0 sources/pyside2/PySide2/glue/qtopenglfunctions.cpp *
A +45 -0 sources/pyside2/PySide2/qopenglversionfunctionsfactory.h *
M +8 -12 sources/pyside2/PySide2/support/generate_pyi.py
M +22 -5 sources/pyside2/PySide2/templates/core_common.xml
M +2 -1 sources/pyside2/PySide2/templates/gui_common.xml
M +1 -0 sources/pyside2/doc/CMakeLists.txt
M +71 -3 sources/pyside2/doc/extras/QtCore.Property.rst
M +0 -6 sources/pyside2/doc/quickstart.rst
M +8 -0 sources/pyside2/doc/tutorials/basictutorial/uifiles.rst
M +21 -1 sources/pyside2/libpyside/feature_select.cpp
M +9 -8 sources/pyside2/libpyside/globalreceiverv2.cpp
M +39 -25 sources/pyside2/libpyside/pyside.cpp
M +6 -3 sources/pyside2/libpyside/pyside.h
M +1 -1 sources/pyside2/libpyside/pysideclassinfo.cpp
M +1 -1 sources/pyside2/libpyside/pysidemetafunction.cpp
M +7 -7 sources/pyside2/libpyside/pysideproperty.cpp
M +9 -4 sources/pyside2/libpyside/pysideqflags.cpp
M +5 -5 sources/pyside2/libpyside/pysidesignal.cpp
M +1 -1 sources/pyside2/libpyside/pysideslot.cpp
M +6 -0 sources/pyside2/libpyside/pysidestaticstrings.cpp
M +6 -0 sources/pyside2/libpyside/pysidestaticstrings.h
M +1 -1 sources/pyside2/pyside_version.py
M +1 -0 sources/pyside2/tests/QtCore/CMakeLists.txt
M +2 -0 sources/pyside2/tests/QtCore/bug_686.py
C +2 -24 sources/pyside2/tests/QtCore/feature_with_uic/__init__.py [from: sources/pyside2/tests/pysidetest/enum_test.py - 065% similarity]
A +81 -0 sources/pyside2/tests/QtCore/feature_with_uic/window.py
A +62 -0 sources/pyside2/tests/QtCore/feature_with_uic/window.ui
C +32 -24 sources/pyside2/tests/QtCore/feature_with_uic_test.py [from: sources/pyside2/tests/QtGui/qdatastream_gui_operators_test.py - 059% similarity]
M +7 -5 sources/pyside2/tests/QtCore/qflags_test.py
M +30 -0 sources/pyside2/tests/QtCore/qobject_parent_test.py
M +21 -3 sources/pyside2/tests/QtCore/qsettings_test.py
M +2 -0 sources/pyside2/tests/QtCore/snake_prop_feature_test.py
M +13 -0 sources/pyside2/tests/QtCore/translation_test.py
M +13 -0 sources/pyside2/tests/QtDataVisualization/datavisualization_test.py
M +5 -3 sources/pyside2/tests/QtGui/qdatastream_gui_operators_test.py
M +2 -26 sources/pyside2/tests/QtGui/qrasterwindow_test.py
M +3 -2 sources/pyside2/tests/QtWidgets/signature_test.py
M +32 -2 sources/pyside2/tests/pysidetest/constructor_properties_test.py
M +3 -4 sources/pyside2/tests/pysidetest/embedding_test.py
M +24 -0 sources/pyside2/tests/pysidetest/enum_test.py
M +11 -6 sources/shiboken2/ApiExtractor/abstractmetabuilder.cpp
M +17 -17 sources/shiboken2/ApiExtractor/abstractmetalang.cpp
M +4 -4 sources/shiboken2/ApiExtractor/abstractmetalang.h
M +19 -8 sources/shiboken2/ApiExtractor/clangparser/clangbuilder.cpp
M +12 -3 sources/shiboken2/ApiExtractor/clangparser/clangutils.cpp
M +6 -2 sources/shiboken2/ApiExtractor/clangparser/clangutils.h
M +28 -15 sources/shiboken2/ApiExtractor/clangparser/compilersupport.cpp
M +33 -3 sources/shiboken2/ApiExtractor/qtdocparser.cpp
M +4 -3 sources/shiboken2/ApiExtractor/tests/testmodifydocumentation.cpp
M +22 -11 sources/shiboken2/ApiExtractor/typesystemparser.cpp
M +30 -1 sources/shiboken2/CMakeLists.txt
T +1 -76 sources/shiboken2/data/docgenerator.1
M +1 -1 sources/shiboken2/data/shiboken_helpers.cmake
M +12 -8 sources/shiboken2/doc/typesystem_codeinjection.rst
M +4 -0 sources/shiboken2/doc/typesystem_conversionrule.rst
M +7 -5 sources/shiboken2/doc/typesystem_variables.rst
M +28 -14 sources/shiboken2/generator/generator.cpp
M +3 -0 sources/shiboken2/generator/generator.h
M +2 -3 sources/shiboken2/generator/main.cpp
M +9 -30 sources/shiboken2/generator/qtdoc/qtdocgenerator.cpp
M +148 -75 sources/shiboken2/generator/shiboken2/cppgenerator.cpp
M +5 -1 sources/shiboken2/generator/shiboken2/cppgenerator.h
M +13 -16 sources/shiboken2/generator/shiboken2/shibokengenerator.cpp
M +1 -5 sources/shiboken2/generator/shiboken2/shibokengenerator.h
M +23 -3 sources/shiboken2/libshiboken/CMakeLists.txt
M +94 -37 sources/shiboken2/libshiboken/basewrapper.cpp
M +21 -8 sources/shiboken2/libshiboken/basewrapper.h
M +3 -0 sources/shiboken2/libshiboken/basewrapper_p.h
M +7 -3 sources/shiboken2/libshiboken/bindingmanager.cpp
M +20 -2 sources/shiboken2/libshiboken/embed/embedding_generator.py
M +74 -20 sources/shiboken2/libshiboken/embed/signature_bootstrap.py
M +6 -4 sources/shiboken2/libshiboken/pep384impl.cpp
M +6 -1 sources/shiboken2/libshiboken/pep384impl.h
D +0 -100 sources/shiboken2/libshiboken/qapp_macro.cpp
D +0 -52 sources/shiboken2/libshiboken/qapp_macro.h
M +0 -1 sources/shiboken2/libshiboken/sbkarrayconverter.cpp
M +1 -1 sources/shiboken2/libshiboken/sbkconverter_p.h
M +68 -55 sources/shiboken2/libshiboken/sbkenum.cpp
M +3 -0 sources/shiboken2/libshiboken/sbkenum.h
M +4 -0 sources/shiboken2/libshiboken/sbkstaticstrings.cpp
M +4 -0 sources/shiboken2/libshiboken/sbkstaticstrings.h
M +1 -0 sources/shiboken2/libshiboken/sbkstaticstrings_p.h
M +1 -1 sources/shiboken2/libshiboken/sbkstring.cpp
M +23 -0 sources/shiboken2/libshiboken/shibokenbuffer.cpp
M +8 -0 sources/shiboken2/libshiboken/shibokenbuffer.h
M +1 -1 sources/shiboken2/libshiboken/signature.h
M +103 -4 sources/shiboken2/libshiboken/signature/signature.cpp
M +4 -1 sources/shiboken2/libshiboken/signature/signature_globals.cpp
M +1 -1 sources/shiboken2/shiboken_version.py
M +6 -31 sources/shiboken2/shibokenmodule/CMakeLists.txt
R +4 -7 sources/shiboken2/shibokenmodule/files.dir/shibokensupport/feature.py [from: sources/shiboken2/shibokenmodule/files.dir/shibokensupport/__feature__.py - 095% similarity]
M +22 -4 sources/shiboken2/shibokenmodule/files.dir/shibokensupport/signature/errorhandler.py
M +35 -25 sources/shiboken2/shibokenmodule/files.dir/shibokensupport/signature/lib/enum_sig.py
M +8 -0 sources/shiboken2/shibokenmodule/files.dir/shibokensupport/signature/lib/tool.py
M +19 -14 sources/shiboken2/shibokenmodule/files.dir/shibokensupport/signature/loader.py
M +7 -0 sources/shiboken2/shibokenmodule/files.dir/shibokensupport/signature/mapping.py
M +16 -15 sources/shiboken2/shibokenmodule/files.dir/shibokensupport/signature/parser.py
M +1 -0 sources/shiboken2/tests/samplebinding/time_test.py
M +2 -0 sources/shiboken2/tests/samplebinding/typesystem_sample.xml
M +11 -2 tools/create_changelog.py
A +122 -0 tools/debug_renamer.py
A +196 -0 tools/leak_finder.py
A +85 -0 tools/license_changer.py
C +29 -14 tools/license_check.py [from: sources/pyside2/pyside_version.py - 069% similarity]
A +123 -0 tools/uic_test.py
The files marked with a * at the end have a non valid license. Please read: https://community.kde.org/Policies/Licensing_Policy and use the headers which are listed at that page.
https://invent.kde.org/neon/qt/pyside2/-/commit/feca35ce028387e3e2c07cc9581473fc0949a09a
diff --git a/build_history/blacklist.txt b/build_history/blacklist.txt
index 9b63f978..827191a2 100644
--- a/build_history/blacklist.txt
+++ b/build_history/blacklist.txt
@@ -18,9 +18,6 @@
darwin py3
[QtCore::qfileread_test]
darwin
-# Nested exception in Python 3
-[QtCore::qflags_test]
- py3
[QtCore::qobject_connect_notify_test]
linux
darwin
@@ -96,3 +93,6 @@
# Open GL functions failures on macOS (2/2020)
[registry::existence_test]
darwin
+# Incomplehensible effect with feature switching on 3.6, qApp.process_events()
+[QtCore::feature_with_uic_test]
+ py3.6
diff --git a/build_scripts/config.py b/build_scripts/config.py
index b1b32068..00cbd3fc 100644
--- a/build_scripts/config.py
+++ b/build_scripts/config.py
@@ -93,6 +93,7 @@ class Config(object):
'Programming Language :: Python :: 3.7',
'Programming Language :: Python :: 3.8',
'Programming Language :: Python :: 3.9',
+ 'Programming Language :: Python :: 3.10',
]
self.setup_script_dir = None
@@ -135,7 +136,7 @@ class Config(object):
setup_kwargs['zip_safe'] = False
setup_kwargs['cmdclass'] = cmd_class_dict
setup_kwargs['version'] = package_version
- setup_kwargs['python_requires'] = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, <3.10"
+ setup_kwargs['python_requires'] = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, <3.11"
if quiet:
# Tells distutils / setuptools to be quiet, and only print warnings or errors.
diff --git a/build_scripts/main.py b/build_scripts/main.py
index ea91ef75..c7e67ac1 100644
--- a/build_scripts/main.py
+++ b/build_scripts/main.py
@@ -805,6 +805,8 @@ class PysideBuild(_build, DistUtilsCommandMixin):
# Add source location for generating documentation
cmake_src_dir = OPTION["QT_SRC"] if OPTION["QT_SRC"] else qt_src_dir
cmake_cmd.append("-DQT_SRC_DIR={}".format(cmake_src_dir))
+ if OPTION['SKIP_DOCS']:
+ cmake_cmd.append("-DSKIP_DOCS=yes")
log.info("Qt Source dir: {}".format(cmake_src_dir))
if self.build_type.lower() == 'debug':
@@ -900,16 +902,23 @@ class PysideBuild(_build, DistUtilsCommandMixin):
deployment_target = macos_pyside_min_deployment_target()
cmake_cmd.append("-DCMAKE_OSX_DEPLOYMENT_TARGET={}".format(deployment_target))
os.environ['MACOSX_DEPLOYMENT_TARGET'] = deployment_target
+ elif sys.platform == 'win32':
+ # Prevent cmake from auto-detecting clang if it is in path.
+ cmake_cmd.append("-DCMAKE_C_COMPILER=cl.exe")
+ cmake_cmd.append("-DCMAKE_CXX_COMPILER=cl.exe")
- if OPTION["DOC_BUILD_ONLINE"]:
- log.info("Output format will be HTML")
- cmake_cmd.append("-DDOC_OUTPUT_FORMAT=html")
- else:
- log.info("Output format will be qthelp")
- cmake_cmd.append("-DDOC_OUTPUT_FORMAT=qthelp")
+ if not OPTION["SKIP_DOCS"]:
+ # Build the whole documentation (rst + API) by default
+ cmake_cmd.append("-DFULLDOCSBUILD=1")
- # Build the whole documentation (rst + API) by default
- cmake_cmd.append("-DFULLDOCSBUILD=1")
+ if OPTION["DOC_BUILD_ONLINE"]:
+ log.info("Output format will be HTML")
+ cmake_cmd.append("-DDOC_OUTPUT_FORMAT=html")
+ else:
+ log.info("Output format will be qthelp")
+ cmake_cmd.append("-DDOC_OUTPUT_FORMAT=qthelp")
+ else:
+ cmake_cmd.append("-DSKIP_DOCS=1")
if not OPTION["SKIP_CMAKE"]:
log.info("Configuring module {} ({})...".format(extension, module_src_dir))
@@ -926,6 +935,13 @@ class PysideBuild(_build, DistUtilsCommandMixin):
if run_process(cmd_make) != 0:
raise DistutilsSetupError("Error compiling {}".format(extension))
+ if sys.version_info == (3, 6) and sys.platform == "darwin":
+ # Python 3.6 has a Sphinx problem because of docutils 0.17 .
+ # Instead of pinning v0.16, setting the default encoding fixes that.
+ # Since other platforms are not affected, we restrict this to macOS.
+ if "UTF-8" not in os.environ.get("LC_ALL", ""):
+ os.environ["LC_ALL"] = "en_US.UTF-8"
+
if not OPTION["SKIP_DOCS"]:
if extension.lower() == "shiboken2":
try:
@@ -940,6 +956,7 @@ class PysideBuild(_build, DistUtilsCommandMixin):
log.info("Sphinx not found, skipping documentation build")
else:
log.info("Skipped documentation generation")
+ cmake_cmd.append("-DSKIP_DOCS=1")
if not OPTION["SKIP_MAKE_INSTALL"]:
log.info("Installing module {}...".format(extension))
@@ -1039,7 +1056,7 @@ class PysideBuild(_build, DistUtilsCommandMixin):
OPTION["CMAKE"],
"-L", # Lists variables
"-N", # Just inspects the cache (faster)
- "--build", # Specifies the build dir
+ "-B", # Specifies the build dir
self.shiboken_build_dir
]
out = run_process_output(cmake_cmd)
diff --git a/build_scripts/platforms/windows_desktop.py b/build_scripts/platforms/windows_desktop.py
index 345847e2..6b92c082 100644
--- a/build_scripts/platforms/windows_desktop.py
+++ b/build_scripts/platforms/windows_desktop.py
@@ -270,7 +270,12 @@ def copy_msvc_redist_files(vars, redist_target_path):
zip_file = "pyside_qt_deps_64_2019.7z"
if "{target_arch}".format(**vars) == "32":
zip_file = "pyside_qt_deps_32_2019.7z"
- download_and_extract_7z(redist_url + zip_file, redist_target_path)
+ try:
+ download_and_extract_7z(redist_url + zip_file, redist_target_path)
+ except:
+ print("download.qt.io is down, try with mirror")
+ redist_url = "https://www.funet.fi/pub/mirrors/download.qt-project.org/development_releases/prebuilt/vcredist/"
+ download_and_extract_7z(redist_url + zip_file, redist_target_path)
else:
print("Qt dependency DLLs (MSVC redist) will not be downloaded and extracted.")
diff --git a/build_scripts/setup_runner.py b/build_scripts/setup_runner.py
index 57c8fbd1..3c7116b8 100644
--- a/build_scripts/setup_runner.py
+++ b/build_scripts/setup_runner.py
@@ -88,8 +88,13 @@ class SetupRunner(object):
internal_build_type_arg = self.construct_internal_build_type_cmd_line_argument(build_type)
setup_cmd = [sys.executable] + self.sub_argv + [internal_build_type_arg]
+ command = self.sub_argv[0]
+ if command == 'setup.py' and len(self.sub_argv) > 1:
+ command = self.sub_argv[1]
+
# Add --reuse-build option if requested and not already present.
- if reuse_build and not self.cmd_line_argument_is_in_args("reuse-build", self.sub_argv):
+ if (reuse_build and command in ('bdist_wheel', 'build', 'build_rst_docs', 'install')
+ and not self.cmd_line_argument_is_in_args("reuse-build", self.sub_argv)):
setup_cmd.append(self.construct_cmd_line_argument("reuse-build"))
self.invocations_list.append(setup_cmd)
diff --git a/build_scripts/utils.py b/build_scripts/utils.py
index 0782ae03..002d6ae5 100644
--- a/build_scripts/utils.py
+++ b/build_scripts/utils.py
@@ -691,6 +691,16 @@ def find_llvm_config():
return result
+# Expand the __ARCH_ place holder in the CLANG environment variables
+def expand_clang_variables(target_arch):
+ for var in 'LLVM_INSTALL_DIR', 'CLANG_INSTALL_DIR':
+ value = os.environ.get(var)
+ if value and '_ARCH_' in value:
+ value = value.replace('_ARCH_', target_arch)
+ os.environ[var] = value
+ print("{} = {}".format(var, value))
+
+
# Add Clang to path for Windows for the shiboken ApiExtractor tests.
# Revisit once Clang is bundled with Qt.
def detect_clang():
diff --git a/build_scripts/wheel_override.py b/build_scripts/wheel_override.py
index 66141763..3f3c12a2 100644
--- a/build_scripts/wheel_override.py
+++ b/build_scripts/wheel_override.py
@@ -90,7 +90,7 @@ class PysideBuildWheel(_bdist_wheel, DistUtilsCommandMixin):
limited_api_enabled = (OPTION["LIMITED_API"] == 'yes'
and sys.version_info[0] >= 3)
if limited_api_enabled:
- self.py_limited_api = "cp35.cp36.cp37.cp38.cp39"
+ self.py_limited_api = "cp35.cp36.cp37.cp38.cp39.cp310"
self._package_version = get_package_version()
diff --git a/coin/dependencies.yaml b/coin/dependencies.yaml
new file mode 100644
index 00000000..032c8c4b
--- /dev/null
+++ b/coin/dependencies.yaml
@@ -0,0 +1,46 @@
+product_dependency:
+ ../../qt/tqtc-qt5.git:
+ ref: "4f71992dd5c14023330332538c84cb5fb5ac5a14"
+dependency_source: supermodule
+dependencies: [
+ "../../qt/qt3d",
+ "../../qt/qtactiveqt",
+ "../../qt/qtandroidextras",
+ "../../qt/qtbase",
+ "../../qt/qtcharts",
+ "../../qt/qtconnectivity",
+ "../../qt/qtdatavis3d",
+ "../../qt/qtdeclarative",
+ "../../qt/qtdoc",
+ "../../qt/qtgamepad",
+ "../../qt/qtgraphicaleffects",
+ "../../qt/qtimageformats",
+ "../../qt/qtlocation",
+ "../../qt/qtlottie",
+ "../../qt/qtmacextras",
+ "../../qt/qtmultimedia",
+ "../../qt/qtnetworkauth",
+ "../../qt/qtpurchasing",
+ "../../qt/qtqa",
+ "../../qt/qtquick3d",
+ "../../qt/qtquickcontrols2",
+ "../../qt/qtquicktimeline",
+ "../../qt/qtremoteobjects",
+ "../../qt/qtscxml",
+ "../../qt/qtsensors",
+ "../../qt/qtserialbus",
+ "../../qt/qtserialport",
+ "../../qt/qtspeech",
+ "../../qt/qtsvg",
+ "../../qt/qttools",
+ "../../qt/qttranslations",
+ "../../qt/qtvirtualkeyboard",
+ "../../qt/qtwayland",
+ "../../qt/qtwebchannel",
+ "../../qt/qtwebengine",
+ "../../qt/qtwebglplugin",
+ "../../qt/qtwebsockets",
+ "../../qt/qtwebview",
+ "../../qt/qtwinextras",
+ "../../qt/qtx11extras"
+ ]
diff --git a/coin/instructions/common_environment.yaml b/coin/instructions/common_environment.yaml
index 2c660333..41ab0059 100644
--- a/coin/instructions/common_environment.yaml
+++ b/coin/instructions/common_environment.yaml
@@ -115,3 +115,10 @@ instructions:
condition: property
property: target.compiler
equals_value: ICC_18
+ - type: EnvironmentVariable
+ variableName: LLVM_INSTALL_DIR
+ variableValue: "{{.Env.LLVM_DYNAMIC_LIBS_100}}"
+ disable_if:
+ condition: property
+ property: host.osVersion
+ equals_value: openSUSE_15_1
diff --git a/coin/instructions/execute_build_instructions.yaml b/coin/instructions/execute_build_instructions.yaml
index 1a0c7306..e940e925 100644
--- a/coin/instructions/execute_build_instructions.yaml
+++ b/coin/instructions/execute_build_instructions.yaml
@@ -39,7 +39,7 @@ instructions:
property: host.os
equals_value: Windows
- type: ChangeDirectory
- directory: "{{.AgentWorkingDir}}\\pyside\\pyside-setup"
+ directory: "{{.AgentWorkingDir}}\\pyside\\tqtc-pyside-setup"
enable_if:
condition: property
property: host.os
diff --git a/coin/instructions/execute_license_check.yaml b/coin/instructions/execute_license_check.yaml
index 51027ba7..9b4d68d4 100644
--- a/coin/instructions/execute_license_check.yaml
+++ b/coin/instructions/execute_license_check.yaml
@@ -18,6 +18,12 @@ instructions:
directory: qt/qtqa-latest
userMessageOnFailure: >
Could not install source archive. Please investigate why.
+ - type: ExecuteCommand
+ command: /bin/mv pyside/tqtc-pyside-setup pyside/pyside-setup
+ maxTimeInSeconds: 300
+ maxTimeBetweenOutput: 120
+ userMessageOnFailure: >
+ Failed to rename tqtc-pyside-setup dir
- type: EnvironmentVariable
variableName: QT_MODULE_TO_TEST
variableValue: pyside/pyside-setup
diff --git a/coin/instructions/execute_test_instructions.yaml b/coin/instructions/execute_test_instructions.yaml
index 22a98066..f5dd7aa5 100644
--- a/coin/instructions/execute_test_instructions.yaml
+++ b/coin/instructions/execute_test_instructions.yaml
@@ -30,7 +30,7 @@ instructions:
- type: ExecuteCommand
command: "c:\\users\\qt\\MSVC.bat python -u coin_test_instructions.py --os={{.Env.CI_OS}} {{.Env.CI_PACKAGING_FEATURE}} --instdir=\\Users\\qt\\work\\install --targetOs={{.Env.CI_OS}} --hostArch=X86_64 --targetArch={{.Env.CI_TARGET_ARCHITECTURE}}"
maxTimeInSeconds: 14400
- maxTimeBetweenOutput: 600
+ maxTimeBetweenOutput: 1200
enable_if:
condition: property
property: host.os
diff --git a/coin/instructions/relocate_pyside.yaml b/coin/instructions/relocate_pyside.yaml
index afab83c7..d096acb1 100644
--- a/coin/instructions/relocate_pyside.yaml
+++ b/coin/instructions/relocate_pyside.yaml
@@ -11,7 +11,7 @@ instructions:
userMessageOnFailure: >
Failed to change to pyside dir
- type: ExecuteCommand
- command: c:\\users\\qt\\MSVC.bat rd /s /q pyside-setup
+ command: c:\\users\\qt\\MSVC.bat rd /s /q tqtc-pyside-setup
maxTimeInSeconds: 300
maxTimeBetweenOutput: 120
enable_if:
@@ -19,9 +19,9 @@ instructions:
property: host.os
equals_value: Windows
userMessageOnFailure: >
- Failed to remove pyside-setup dir
+ Failed to remove tqtc-pyside-setup dir
- type: ExecuteCommand
- command: /bin/rm -rf pyside-setup
+ command: /bin/rm -rf tqtc-pyside-setup
maxTimeInSeconds: 300
maxTimeBetweenOutput: 120
enable_if:
@@ -29,14 +29,14 @@ instructions:
property: host.os
not_equals_value: Windows
userMessageOnFailure: >
- Failed to remove pyside-setup dir
+ Failed to remove tqtc-pyside-setup dir
- type: InstallBinaryArchive
relativeStoragePath: "{{.Env.MODULE_ARTIFACTS_RELATIVE_STORAGE_PATH}}/artifacts.tar.gz"
directory: "pyside"
maxTimeInSeconds: 1200
maxTimeBetweenOutput: 1200
- type: ChangeDirectory
- directory: "{{.AgentWorkingDir}}\\pyside\\pyside-setup"
+ directory: "{{.AgentWorkingDir}}\\pyside\\tqtc-pyside-setup"
maxTimeInSeconds: 7200
maxTimeBetweenOutput: 120
enable_if:
@@ -46,7 +46,7 @@ instructions:
userMessageOnFailure: >
Failed to install binary artifacts
- type: ChangeDirectory
- directory: "{{.AgentWorkingDir}}/pyside/pyside-setup"
+ directory: "{{.AgentWorkingDir}}/pyside/tqtc-pyside-setup"
maxTimeInSeconds: 7200
maxTimeBetweenOutput: 120
enable_if:
@@ -54,4 +54,4 @@ instructions:
property: host.os
not_equals_value: Windows
userMessageOnFailure: >
- Failed to change to pyside-setup dir
+ Failed to change to tqtc-pyside-setup dir
diff --git a/coin/module_config.yaml b/coin/module_config.yaml
index fd80acf9..99778cce 100644
--- a/coin/module_config.yaml
+++ b/coin/module_config.yaml
@@ -18,7 +18,7 @@ accept_configuration:
not_contains_value: -no-gui
- condition: property # Following configs are not supported
property: target.osVersion
- not_in_values: [OPENSUSE_13_01, QEMU, WebAssembly, Ubuntu_18_04, SLES_12, SLES_15]
+ not_in_values: [OPENSUSE_13_01, QEMU, WebAssembly, Ubuntu_18_04, SLES_12, SLES_15, MacOS_10_15]
- condition: property # MibnGW and msvc2015 are not supported
property: target.compiler
not_in_values: [Mingw, MSVC2015]
@@ -55,14 +55,14 @@ upload_pyside: &upload_pyside
instructions:
LicenseCheck:
- - !include "{{pyside/pyside-setup}}/execute_license_check.yaml"
+ - !include "{{pyside/tqtc-pyside-setup}}/execute_license_check.yaml"
Build:
- - !include "{{pyside/pyside-setup}}/common_environment.yaml"
- - !include "{{pyside/pyside-setup}}/find_path_to_msvc_compiler.yaml"
- - !include "{{pyside/pyside-setup}}/execute_build_instructions.yaml"
+ - !include "{{pyside/tqtc-pyside-setup}}/common_environment.yaml"
+ - !include "{{pyside/tqtc-pyside-setup}}/find_path_to_msvc_compiler.yaml"
+ - !include "{{pyside/tqtc-pyside-setup}}/execute_build_instructions.yaml"
- *upload_pyside
Test:
- - !include "{{pyside/pyside-setup}}/common_environment.yaml"
- - !include "{{pyside/pyside-setup}}/find_path_to_msvc_compiler.yaml"
- - !include "{{pyside/pyside-setup}}/relocate_pyside.yaml"
- - !include "{{pyside/pyside-setup}}/execute_test_instructions.yaml"
+ - !include "{{pyside/tqtc-pyside-setup}}/common_environment.yaml"
+ - !include "{{pyside/tqtc-pyside-setup}}/find_path_to_msvc_compiler.yaml"
+ - !include "{{pyside/tqtc-pyside-setup}}/relocate_pyside.yaml"
+ - !include "{{pyside/tqtc-pyside-setup}}/execute_test_instructions.yaml"
diff --git a/coin_build_instructions.py b/coin_build_instructions.py
index 95d800b5..cf5dca62 100644
--- a/coin_build_instructions.py
+++ b/coin_build_instructions.py
@@ -38,7 +38,7 @@
#############################################################################
from build_scripts.options import has_option
from build_scripts.options import option_value
-from build_scripts.utils import install_pip_dependencies
+from build_scripts.utils import install_pip_dependencies, expand_clang_variables
from build_scripts.utils import get_qtci_virtualEnv
from build_scripts.utils import run_instruction
from build_scripts.utils import rmtree
@@ -143,6 +143,8 @@ def call_setup(python_ver, phase):
"--verbose-build"]
if python_ver == "3":
cmd += ["--limited-api=yes"]
+ else:
+ cmd += ["--skip-docs"] # Sphinx is broken in Python 2
if is_snapshot_build():
cmd += ["--snapshot-build"]
@@ -175,6 +177,8 @@ def run_build_instructions(phase):
if __name__ == "__main__":
# Remove some environment variables that impact cmake
+ arch = '32' if CI_TARGET_ARCH and CI_TARGET_ARCH == 'X86' else '64'
+ expand_clang_variables(arch)
for env_var in ['CC', 'CXX']:
if os.environ.get(env_var):
del os.environ[env_var]
diff --git a/coin_test_instructions.py b/coin_test_instructions.py
index 467f58d1..3b8f7e39 100644
--- a/coin_test_instructions.py
+++ b/coin_test_instructions.py
@@ -38,7 +38,7 @@
#############################################################################
from build_scripts.options import has_option
from build_scripts.options import option_value
-from build_scripts.utils import install_pip_dependencies
+from build_scripts.utils import install_pip_dependencies, expand_clang_variables
from build_scripts.utils import get_qtci_virtualEnv
from build_scripts.utils import run_instruction
from build_scripts.utils import rmtree
@@ -103,6 +103,8 @@ def call_testrunner(python_ver, buildnro):
def run_test_instructions():
# Remove some environment variables that impact cmake
+ arch = '32' if CI_TARGET_ARCH and CI_TARGET_ARCH == 'X86' else '64'
+ expand_clang_variables(arch)
for env_var in ['CC', 'CXX']:
if os.environ.get(env_var):
del os.environ[env_var]
diff --git a/dist/changes-5.15.3 b/dist/changes-5.15.3
new file mode 100644
index 00000000..fe795989
--- /dev/null
+++ b/dist/changes-5.15.3
@@ -0,0 +1,46 @@
+Qt for Python 5.15.3 is a bug-fix release.
+
+For more details, refer to the online documentation included in this
+distribution. The documentation is also available online:
+
+https://doc.qt.io/qtforpython/
+
+Some of the changes listed in this file include issue tracking numbers
+corresponding to tasks in the Qt Bug Tracker:
+
+https://bugreports.qt.io/
+
+Each of these identifiers can be entered in the bug tracker to obtain more
+information about a particular change.
+
+****************************************************************************
+* PySide2 *
+****************************************************************************
+
+ - [PYSIDE-454] namespace std is no longer rejected in the Qt typesystem
+ files.
+ - [PYSIDE-807] setup.py's 'clean' command has been fixed.
+ - [PYSIDE-1305] The error handling of constructor keyword arguments has been
+ fixed.
+ - [PYSIDE-1422] A crash related to Signal and __eq__ has been fixed.
+ - [PYSIDE-1432] An ownership issue in QLayout::replaceWidget() has been fixed.
+ - [PYSIDE-1442] QFlags operations have been fixed.
+ - [PYSIDE-1447] A crash related to qApp and Python 3.9 has been fixed.
+ - [PYSIDE-1449] QTestlib's QAbstractItemModelTester has been added.
+ - [PYSIDE-1460] An infinite loop changing up directories in the signature
+ bootstrap code has been fixed.
+ - [PYSIDE-1466] The newly introduced overload QSetting.value() taking a type
+ has been documentated.
+ - [PYSIDE-1478] A bug related to using QQmlContext.setContextProperty()
+ with the snake case feature has been fixed.
+
+****************************************************************************
+* Shiboken2 *
+****************************************************************************
+
+ - [PYSIDE-1347] Inheritance for enum types has been fixed.
+ - [PYSIDE-1448] Code injected at target/end being invoked for multiple
+ overload ids has been fixed.
+ - [PYSIDE-1470] shiboken.delete() can now be used to delete Q*Application.
+ - [PYSIDE-1501] The clang parser has been fixed to be able to handle some
+ Boost headers.
diff --git a/dist/changes-5.15.4 b/dist/changes-5.15.4
new file mode 100644
index 00000000..a97be5dc
--- /dev/null
+++ b/dist/changes-5.15.4
@@ -0,0 +1,38 @@
+Qt for Python 5.15.4 is a bug-fix release.
+
+For more details, refer to the online documentation included in this
+distribution. The documentation is also available online:
+
+https://doc.qt.io/qtforpython/
+
+Some of the changes listed in this file include issue tracking numbers
+corresponding to tasks in the Qt Bug Tracker:
+
+https://bugreports.qt.io/
+
+Each of these identifiers can be entered in the bug tracker to obtain more
+information about a particular change.
+
+****************************************************************************
+* PySide2 *
+****************************************************************************
+
+ - [PYSIDE-955] QOpenGLContext.versionFunctions() have been implemented.
+ Class QOpenGLVersionFunctionsFactory (from Qt 6) has also
+ been added.
+ - [PYSIDE-1409] signature: The decision heuristics of result tuples have
+ been refined.
+ - [PYSIDE-1438] Crashes in Qt Datavisualization's QBar/SurfaceDataProxy
+ add/set/insertRow() members have been fixed.
+ - [PYSIDE-1502] Import errors will now be properly reported.
+ - [PYSIDE-1513] Documentation on properties has been added.
+ - [PYSIDE-1538] signature: Unrecognized items will no longer raise
+ exceptions.
+ - [PYSIDE-1540] The performance of QPainter::drawPoints(QPolygon) has been
+ improved.
+
+****************************************************************************
+* Shiboken2 *
+****************************************************************************
+
+ - [PYSIDE-1529] Crashes when registering static fields have been fixed.
diff --git a/dist/changes-5.15.5 b/dist/changes-5.15.5
new file mode 100644
index 00000000..02c98b0d
--- /dev/null
+++ b/dist/changes-5.15.5
@@ -0,0 +1,30 @@
+Qt for Python 5.15.5 is a bug-fix release.
+
+For more details, refer to the online documentation included in this
+distribution. The documentation is also available online:
+
+https://doc.qt.io/qtforpython/
+
+Some of the changes listed in this file include issue tracking numbers
+corresponding to tasks in the Qt Bug Tracker:
+
+https://bugreports.qt.io/
+
+Each of these identifiers can be entered in the bug tracker to obtain more
+information about a particular change.
+
+****************************************************************************
+* PySide2 *
+****************************************************************************
+
+ - Crashes in QClipboard.mimeData(), QTextCursor.currentList() and
+ QTextCursor.currentTable() have been fixed.
+ - Fixed issues where __feature__ was affected by other imports.
+ - Fixed crashes on QImage(uchar *) constructors, related to GIL handling.
+ - QOpenGLPaintDevice has been added.
+
+****************************************************************************
+* Shiboken2 *
+****************************************************************************
+
+ - No changes
diff --git a/dist/changes-5.15.6 b/dist/changes-5.15.6
new file mode 100644
index 00000000..091adf2c
--- /dev/null
+++ b/dist/changes-5.15.6
@@ -0,0 +1,34 @@
+Qt for Python 5.15.6 is a bug-fix release.
+
+For more details, refer to the online documentation included in this
+distribution. The documentation is also available online:
+
+https://doc.qt.io/qtforpython/
+
+Some of the changes listed in this file include issue tracking numbers
+corresponding to tasks in the Qt Bug Tracker:
+
+https://bugreports.qt.io/
+
+Each of these identifiers can be entered in the bug tracker to obtain more
+information about a particular change.
+
+****************************************************************************
+* PySide2 *
+****************************************************************************
+
+ * [PYSIDE-131] The `tr` function now works also for
+ PySide derived Python class instances with the right context.
+ * [PYSIDE-1619][PYSIDE-1609] Fixed several crashes on QObject.findChild
+ and QSettings.value
+ * [PYSIDE-1639][PYSIDE-1640] Fixed locks on QInputDialog and QAbstractSocket.
+
+****************************************************************************
+* Shiboken2 *
+****************************************************************************
+
+ * [PYSIDE-1621] Embedding of supporting Python files
+ is now completely virtual. No FS files are involved any longer.
+ * [PYSIDE-1626] Coexistence of different feature
+ selections works now, especially for UIC files and inheritance.
+
diff --git a/dist/changes-5.15.7 b/dist/changes-5.15.7
new file mode 100644
index 00000000..44c467ca
--- /dev/null
+++ b/dist/changes-5.15.7
@@ -0,0 +1,33 @@
+Qt for Python 5.15.7 is a bug-fix release.
+
+For more details, refer to the online documentation included in this
+distribution. The documentation is also available online:
+
+https://doc.qt.io/qtforpython/
+
+Some of the changes listed in this file include issue tracking numbers
+corresponding to tasks in the Qt Bug Tracker:
+
+https://bugreports.qt.io/
+
+Each of these identifiers can be entered in the bug tracker to obtain more
+information about a particular change.
+
+****************************************************************************
+* PySide2 *
+****************************************************************************
+
+ - [PYSIDE-1647] A crash when constructing a QApplication in an embedded
+ application has been fixed.
+ - [PYSIDE-1659] QUiLoader restrictions wrt signal/slot connections have been
+ documented.
+ - [PYSIDE-1681] A hang in QQmlApplicationEngine functions when using a
+ message handler has been fixed.
+
+****************************************************************************
+* Shiboken2 *
+****************************************************************************
+
+ - [PYSIDE-1655] A stack-use-after-scope ASAN issue in TypeSystemParser
+ has been fixed.
+ - [PYSIDE-1686] shiboken has been adapted to LLVM 12.01.
diff --git a/examples/widgets/mainwindows/application/application.py b/examples/widgets/mainwindows/application/application.py
index 8c4626f9..5645a074 100644
--- a/examples/widgets/mainwindows/application/application.py
+++ b/examples/widgets/mainwindows/application/application.py
@@ -189,16 +189,14 @@ class MainWindow(QtWidgets.QMainWindow):
self.statusBar().showMessage("Ready")
def readSettings(self):
- settings = QtCore.QSettings("Trolltech", "Application Example")
- pos = settings.value("pos", QtCore.QPoint(200, 200))
- size = settings.value("size", QtCore.QSize(400, 400))
- self.resize(size)
- self.move(pos)
+ settings = QtCore.QSettings('QtProject', 'Application Example')
+ geometry = settings.value('geometry', QtCore.QByteArray())
+ if geometry.size():
+ self.restoreGeometry(geometry)
def writeSettings(self):
- settings = QtCore.QSettings("Trolltech", "Application Example")
- settings.setValue("pos", self.pos())
- settings.setValue("size", self.size())
+ settings = QtCore.QSettings('QtProject', 'Application Example')
+ settings.setValue('geometry', self.saveGeometry())
def maybeSave(self):
if self.textEdit.document().isModified():
diff --git a/examples/widgets/mainwindows/mdi/mdi.py b/examples/widgets/mainwindows/mdi/mdi.py
index 9daca826..9eca5fdb 100644
--- a/examples/widgets/mainwindows/mdi/mdi.py
+++ b/examples/widgets/mainwindows/mdi/mdi.py
@@ -42,8 +42,8 @@
"""PySide2 port of the widgets/draganddrop/draggabletext example from Qt v5.x, originating from PyQt"""
-from PySide2.QtCore import (QFile, QFileInfo, QPoint, QSettings, QSignalMapper,
- QSaveFile, QSize, QTextStream, Qt)
+from PySide2.QtCore import (QByteArray, QFile, QFileInfo, QPoint, QSettings,
+ QSignalMapper, QSaveFile, QSize, QTextStream, Qt)
from PySide2.QtGui import QIcon, QKeySequence
from PySide2.QtWidgets import (QAction, QApplication, QFileDialog, QMainWindow,
QMdiArea, QMessageBox, QTextEdit, QWidget)
@@ -405,16 +405,14 @@ class MainWindow(QMainWindow):
self.statusBar().showMessage("Ready")
def readSettings(self):
- settings = QSettings('Trolltech', 'MDI Example')
- pos = settings.value('pos', QPoint(200, 200))
- size = settings.value('size', QSize(400, 400))
- self.move(pos)
- self.resize(size)
+ settings = QSettings('QtProject', 'MDI Example')
+ geometry = settings.value('geometry', QByteArray())
+ if geometry.size():
+ self.restoreGeometry(geometry)
def writeSettings(self):
- settings = QSettings('Trolltech', 'MDI Example')
- settings.setValue('pos', self.pos())
- settings.setValue('size', self.size())
+ settings = QSettings('QtProject', 'MDI Example')
+ settings.setValue('geometry', self.saveGeometry())
def activeMdiChild(self):
activeSubWindow = self.mdiArea.activeSubWindow()
diff --git a/examples/widgets/richtext/textobject/textobject.py b/examples/widgets/richtext/textobject/textobject.py
index b828ea3d..e82ea95d 100644
--- a/examples/widgets/richtext/textobject/textobject.py
+++ b/examples/widgets/richtext/textobject/textobject.py
@@ -42,13 +42,17 @@
"""PySide2 port of the widgets/richtext/textobject example from Qt v5.x"""
+import os
+
from PySide2 import QtCore, QtGui, QtWidgets, QtSvg
-class SvgTextObject(QtCore.QObject, QtGui.QTextObjectInterface):
+class SvgTextObject(QtGui.QPyTextObject):
+ def __init__(self, parent=None):
+ super(SvgTextObject, self).__init__(parent)
def intrinsicSize(self, doc, posInDocument, format):
- renderer = QtSvg.QSvgRenderer(format.property(Window.SvgData).toByteArray())
+ renderer = QtSvg.QSvgRenderer(format.property(Window.SvgData))
size = renderer.defaultSize()
if size.height() > 25:
@@ -57,7 +61,7 @@ class SvgTextObject(QtCore.QObject, QtGui.QTextObjectInterface):
return QtCore.QSizeF(size)
def drawObject(self, painter, rect, doc, posInDocument, format):
- renderer = QtSvg.QSvgRenderer(format.property(Window.SvgData).toByteArray())
+ renderer = QtSvg.QSvgRenderer(format.property(Window.SvgData))
renderer.render(painter, rect)
@@ -80,8 +84,10 @@ class Window(QtWidgets.QWidget):
file = QtCore.QFile(fileName)
if not file.open(QtCore.QIODevice.ReadOnly):
- QtWidgets.QMessageBox.warning(self, self.tr("Error Opening File"),
- self.tr("Could not open '%1'").arg(fileName))
+ reason = file.errorString()
+ message = "Could not open '{}': {}".format(fileName, reason)
+ QtWidgets.QMessageBox.warning(self, "Error Opening File",
+ message.arg(fileName))
svgData = file.readAll()
@@ -90,7 +96,7 @@ class Window(QtWidgets.QWidget):
svgCharFormat.setProperty(Window.SvgData, svgData)
cursor = self.textEdit.textCursor()
- cursor.insertText(u"\uFFFD", svgCharFormat)
+ cursor.insertText(chr(0xfffc), svgCharFormat)
self.textEdit.setTextCursor(cursor)
def setupTextObject(self):
@@ -102,8 +108,9 @@ class Window(QtWidgets.QWidget):
self.fileNameLineEdit = QtWidgets.QLineEdit()
insertTextObjectButton = QtWidgets.QPushButton(self.tr("Insert Image"))
- self.fileNameLineEdit.setText('./files/heart.svg')
- QtCore.QObject.connect(insertTextObjectButton, QtCore.SIGNAL('clicked()'), self.insertTextObject)
+ file = os.path.join(os.path.dirname(__file__), 'files', 'heart.svg')
+ self.fileNameLineEdit.setText(file)
+ insertTextObjectButton.clicked.connect(self.insertTextObject)
bottomLayout = QtWidgets.QHBoxLayout()
bottomLayout.addWidget(fileNameLabel)
diff --git a/product_dependencies.yaml b/product_dependencies.yaml
deleted file mode 100644
index 29c4fb5d..00000000
--- a/product_dependencies.yaml
+++ /dev/null
@@ -1,3 +0,0 @@
-dependencies:
- ../../qt/qt5.git:
- ref: "5.15.2"
diff --git a/sources/pyside2-tools/pyside_tool.py b/sources/pyside2-tools/pyside_tool.py
index da2d7415..ec27a812 100755
--- a/sources/pyside2-tools/pyside_tool.py
+++ b/sources/pyside2-tools/pyside_tool.py
@@ -38,6 +38,8 @@
## $QT_END_LICENSE$
##
#############################################################################
+from __future__ import print_function
+
import sys
import os
import subprocess
@@ -66,7 +68,7 @@ def qt_tool_wrapper(qt_tool, args):
out, err = proc.communicate()
if err:
msg = err.decode("utf-8")
- print("Error: {}\nwhile executing '{}'".format(msg, ' '.join(cmd)))
+ print(msg, file=sys.stderr)
sys.exit(proc.returncode)
diff --git a/sources/pyside2/CMakeLists.txt b/sources/pyside2/CMakeLists.txt
index dc2beded..4336d6cc 100644
--- a/sources/pyside2/CMakeLists.txt
+++ b/sources/pyside2/CMakeLists.txt
@@ -268,7 +268,7 @@ endif ()
find_program(SPHINX_BUILD sphinx-build)
find_program(DOT_EXEC dot)
-if (QT_SRC_DIR AND SPHINX_BUILD AND DOT_EXEC)
+if (QT_SRC_DIR AND SPHINX_BUILD AND DOT_EXEC AND NOT SKIP_DOCS)
add_subdirectory(doc)
else ()
set(DOCS_TARGET_DISABLED_MESSAGE "apidoc generation targets disabled.")
diff --git a/sources/pyside2/PySide2/QtCore/typesystem_core_common.xml b/sources/pyside2/PySide2/QtCore/typesystem_core_common.xml
index 205e4ef0..89f5069d 100644
--- a/sources/pyside2/PySide2/QtCore/typesystem_core_common.xml
+++ b/sources/pyside2/PySide2/QtCore/typesystem_core_common.xml
@@ -112,7 +112,6 @@
<rejection class="QtPrivate"/>
<rejection class="QtSharedPointer"/>
<rejection class="QtStringBuilder"/>
- <rejection class="std"/>
<rejection class="QByteArray" field-name="MaxSize"/>
<rejection class="QChildEvent" field-name="c"/>
@@ -2608,6 +2607,27 @@
<modify-function signature="value(const QString&,const QVariant&)const" remove="all"/>
<add-function signature="value(const QString&, const QVariant& @defaultValue@ = 0, PyObject* @type@ = 0)" return-type="PyObject*">
<inject-code class="target" position="beginning" file="../glue/qtcore.cpp" snippet="qsettings-value"/>
+ <inject-documentation mode="append" format="target">
+ Custom overload that adds an optional named parameter to the function ``value()``
+ to automatically cast the type that is being returned by the function.
+
+ An example of this situation could be an ini file that contains
+ the value of a one-element list::
+
+ settings.setValue('var', ['a'])
+
+ The the ini file will be::
+
+ [General]
+ var=a # we cannot know that this is a list!
+
+ Once we read it, we could specify if we want
+ the default behavior, a str, or to cast the output
+ to a list.
+
+ settings.value('var') # Will get "a"
+ settings.value('var', type=list) # Will get ["a"]
+ </inject-documentation>
</add-function>
</object-type>
<object-type name="QEvent" polymorphic-id-expression="%1->type() == QEvent::None">
diff --git a/sources/pyside2/PySide2/QtDataVisualization/typesystem_datavisualization.xml b/sources/pyside2/PySide2/QtDataVisualization/typesystem_datavisualization.xml
index f10aeea3..5dc87a01 100644
--- a/sources/pyside2/PySide2/QtDataVisualization/typesystem_datavisualization.xml
+++ b/sources/pyside2/PySide2/QtDataVisualization/typesystem_datavisualization.xml
@@ -119,56 +119,43 @@
<parent index="this" action="add"/>
</modify-argument>
</modify-function>
- <modify-function signature="addRow(QVector<QtDataVisualization::QBarDataItem>*)">
- <modify-argument index="1">
- <parent index="this" action="add"/>
- </modify-argument>
- </modify-function>
- <modify-function signature="addRow(QVector<QtDataVisualization::QBarDataItem>*, const QString&)">
- <modify-argument index="1">
- <parent index="this" action="add"/>
- </modify-argument>
- </modify-function>
- <modify-function signature="addRows(const QtDataVisualization::QBarDataArray&)">
- <modify-argument index="1">
- <parent index="this" action="add"/>
- </modify-argument>
- </modify-function>
- <modify-function signature="addRows(const QtDataVisualization::QBarDataArray&, const QStringList&)">
- <modify-argument index="1">
- <parent index="this" action="add"/>
- </modify-argument>
- </modify-function>
- <modify-function signature="insertRow(int, QVector<QtDataVisualization::QBarDataItem>*)">
- <modify-argument index="2">
- <parent index="this" action="add"/>
- </modify-argument>
- </modify-function>
- <modify-function signature="insertRow(int, QVector<QtDataVisualization::QBarDataItem>*, const QString&)">
- <modify-argument index="2">
- <parent index="this" action="add"/>
- </modify-argument>
- </modify-function>
- <modify-function signature="insertRows(int, const QtDataVisualization::QBarDataArray&)">
- <modify-argument index="2">
- <parent index="this" action="add"/>
- </modify-argument>
- </modify-function>
- <modify-function signature="insertRows(int, const QtDataVisualization::QBarDataArray&, const QStringList&)">
- <modify-argument index="2">
- <parent index="this" action="add"/>
- </modify-argument>
- </modify-function>
- <modify-function signature="setRow(int, QVector<QtDataVisualization::QBarDataItem>*)">
- <modify-argument index="2">
- <parent index="this" action="add"/>
- </modify-argument>
- </modify-function>
- <modify-function signature="setRow(int, QVector<QtDataVisualization::QBarDataItem>*, const QString&)">
- <modify-argument index="2">
- <parent index="this" action="add"/>
- </modify-argument>
- </modify-function>
+
+ <!-- PYSIDE-1438: Replace all add/set/insertRow() taking a 'QVector*' by overloads
+ taking 'const QVector &' since an allocated list needs to be passed. -->
+ <modify-function signature="addRow(QVector<QtDataVisualization::QBarDataItem>*)" remove="all"/>
+ <add-function signature="addRow(const QVector<QtDataVisualization::QBarDataItem>&)" return-type="int">
+ <inject-code class="target" position="beginning" file="../glue/qtdatavisualization.cpp"
+ snippet="dataproxy-addrow"/>
+ </add-function>
+ <modify-function signature="addRow(QVector<QtDataVisualization::QBarDataItem>*,const QString&)" remove="all"/>
+ <add-function signature="addRow(const QVector<QtDataVisualization::QBarDataItem>&,const QString&)"
+ return-type="int">
+ <inject-code class="target" position="beginning" file="../glue/qtdatavisualization.cpp"
+ snippet="dataproxy-addrow-string"/>
+ </add-function>
+
+ <modify-function signature="insertRow(int,QVector<QtDataVisualization::QBarDataItem>*)" remove="all"/>
+ <add-function signature="insertRow(int,const QVector<QtDataVisualization::QBarDataItem>&)">
+ <inject-code class="target" position="beginning" file="../glue/qtdatavisualization.cpp"
+ snippet="dataproxy-insertrow"/>
+ </add-function>
+ <modify-function signature="insertRow(int,QVector<QtDataVisualization::QBarDataItem>*,const QString&)" remove="all"/>
+ <add-function signature="insertRow(int,const QVector<QtDataVisualization::QBarDataItem>&, const QString&)">
+ <inject-code class="target" position="beginning" file="../glue/qtdatavisualization.cpp"
+ snippet="dataproxy-insertrow-string"/>
+ </add-function>
+
+ <modify-function signature="setRow(int,QVector<QtDataVisualization::QBarDataItem>*)" remove="all"/>
+ <add-function signature="setRow(int,const QVector<QtDataVisualization::QBarDataItem>&)">
+ <inject-code class="target" position="beginning" file="../glue/qtdatavisualization.cpp"
+ snippet="dataproxy-setrow"/>
+ </add-function>
+ <modify-function signature="setRow(int,QVector<QtDataVisualization::QBarDataItem>*,const QString&)" remove="all"/>
+ <add-function signature="setRow(int,const QVector<QtDataVisualization::QBarDataItem>&,const QString&)">
+ <inject-code class="target" position="beginning" file="../glue/qtdatavisualization.cpp"
+ snippet="dataproxy-setrow-string"/>
+ </add-function>
+
<modify-function signature="setRows(int, const QtDataVisualization::QBarDataArray&)">
<modify-argument index="2">
<parent index="this" action="add"/>
@@ -182,7 +169,13 @@
</object-type>
<object-type name="QCustom3DItem"/>
<object-type name="QCustom3DLabel"/>
- <object-type name="QCustom3DVolume"/>
+ <object-type name="QCustom3DVolume">
+ <modify-function signature="setTextureData(QVector<uchar>*)" remove="all"/>
+ <add-function signature="setTextureData(const QVector<uchar>&)">
+ <inject-code class="target" position="beginning" file="../glue/qtdatavisualization.cpp"
+ snippet="qcustom3dvolume-settexturedata"/>
+ </add-function>
+ </object-type>
<object-type name="QHeightMapSurfaceDataProxy"/>
<object-type name="QItemModelBarDataProxy">
<enum-type name="MultiMatchBehavior"/>
@@ -251,21 +244,27 @@
</object-type>
<value-type name="QSurfaceDataItem"/>
<object-type name="QSurfaceDataProxy">
- <modify-function signature="addRow(QVector<QtDataVisualization::QSurfaceDataItem>*)">
- <modify-argument index="1">
- <parent index="this" action="add"/>
- </modify-argument>
- </modify-function>
- <modify-function signature="insertRow(int, QVector<QtDataVisualization::QSurfaceDataItem>*)">
- <modify-argument index="2">
- <parent index="this" action="add"/>
- </modify-argument>
- </modify-function>
- <modify-function signature="setRow(int, QVector<QtDataVisualization::QSurfaceDataItem>*)">
- <modify-argument index="2">
- <parent index="this" action="add"/>
- </modify-argument>
- </modify-function>
+
+ <!-- PYSIDE-1438: Replace all add/set/insertRow() taking a 'QVector*' by overloads
+ taking 'const QVector &' since an allocated list needs to be passed. -->
+ <modify-function signature="addRow(QVector<QtDataVisualization::QSurfaceDataItem>*)" remove="all"/>
+ <add-function signature="addRow(const QVector<QtDataVisualization::QSurfaceDataItem>&)" return-type="int">
+ <inject-code class="target" position="beginning" file="../glue/qtdatavisualization.cpp"
+ snippet="dataproxy-addrow"/>
+ </add-function>
+
+ <modify-function signature="insertRow(int,QVector<QtDataVisualization::QSurfaceDataItem>*)" remove="all"/>
+ <add-function signature="insertRow(int,const QVector<QtDataVisualization::QSurfaceDataItem>&)">
+ <inject-code class="target" position="beginning" file="../glue/qtdatavisualization.cpp"
+ snippet="dataproxy-insertrow"/>
+ </add-function>
+
+ <modify-function signature="setRow(int,QVector<QtDataVisualization::QSurfaceDataItem>*)" remove="all"/>
+ <add-function signature="setRow(int,const QVector<QtDataVisualization::QSurfaceDataItem>&)">
+ <inject-code class="target" position="beginning" file="../glue/qtdatavisualization.cpp"
+ snippet="dataproxy-setrow"/>
+ </add-function>
+
<modify-function signature="resetArray(QtDataVisualization::QSurfaceDataArray*)">
<modify-argument index="1">
<parent index="this" action="add"/>
diff --git a/sources/pyside2/PySide2/QtGui/CMakeLists.txt b/sources/pyside2/PySide2/QtGui/CMakeLists.txt
index c4a38a18..88d8be93 100644
--- a/sources/pyside2/PySide2/QtGui/CMakeLists.txt
+++ b/sources/pyside2/PySide2/QtGui/CMakeLists.txt
@@ -100,7 +100,7 @@ ${QtGui_GEN_DIR}/qopengldebugmessage_wrapper.cpp
${QtGui_GEN_DIR}/qopenglextrafunctions_wrapper.cpp
${QtGui_GEN_DIR}/qopenglframebufferobjectformat_wrapper.cpp
${QtGui_GEN_DIR}/qopenglfunctions_wrapper.cpp
-# Compile error on Windows: ${QtGui_GEN_DIR}/qopenglpaintdevice_wrapper.cpp
+${QtGui_GEN_DIR}/qopenglpaintdevice_wrapper.cpp
${QtGui_GEN_DIR}/qopenglpixeltransferoptions_wrapper.cpp
${QtGui_GEN_DIR}/qopenglshaderprogram_wrapper.cpp
${QtGui_GEN_DIR}/qopengltexture_wrapper.cpp
diff --git a/sources/pyside2/PySide2/QtGui/typesystem_gui_common.xml b/sources/pyside2/PySide2/QtGui/typesystem_gui_common.xml
index 04abbae5..e66ee48c 100644
--- a/sources/pyside2/PySide2/QtGui/typesystem_gui_common.xml
+++ b/sources/pyside2/PySide2/QtGui/typesystem_gui_common.xml
@@ -643,6 +643,16 @@
<define-ownership class="target" owner="default"/>
</modify-argument>
</modify-function>
+ <modify-function signature="currentTable()const">
+ <modify-argument index="return">
+ <define-ownership class="target" owner="default"/>
+ </modify-argument>
+ </modify-function>
+ <modify-function signature="currentList()const">
+ <modify-argument index="return">
+ <define-ownership class="target" owner="default"/>
+ </modify-argument>
+ </modify-function>
<modify-function signature="insertTable(int,int,const QTextTableFormat &)">
<modify-argument index="return">
<define-ownership class="target" owner="default"/>
@@ -758,6 +768,8 @@
<include file-name="QStringList" location="global"/>
<include file-name="QMatrix" location="global"/>
</extra-includes>
+ <inject-code class="native" position="beginning"
+ file="../glue/qtgui.cpp" snippet="qimage-decref-image-data"/>
<modify-function signature="load(const QString&, const char*)" allow-thread="yes"/>
<modify-function signature="load(QIODevice*,const char*)" allow-thread="yes"/>
@@ -1760,6 +1772,11 @@
</modify-argument>
<inject-code class="target" position="end" file="../glue/qtgui.cpp" snippet="qclipboard-text"/>
</modify-function>
+ <modify-function signature="mimeData(QClipboard::Mode)const">
+ <modify-argument index="return">
+ <define-ownership class="target" owner="default"/>
+ </modify-argument>
+ </modify-function>
</object-type>
<object-type name="QPaintEngineState">
<extra-includes>
@@ -1871,18 +1888,23 @@
<modify-function signature="drawRects(const QRect*,int)" remove="all"/>
<modify-function signature="drawRects(const QRectF*,int)" remove="all"/>
<!-- ### -->
+ <!-- PYSIDE-1540: Preferably use the QPolygon overloads first to avoid
+ a costly sequence type check on QPolygon. -->
<modify-function signature="drawPoints(const QPoint*,int)" remove="all"/>
- <add-function signature="drawPoints(QVector<QPoint>)">
+ <add-function signature="drawPoints(QVector<QPoint>)" overload-number="2">
<inject-code>
<insert-template name="qpainter_drawlist"/>
</inject-code>
</add-function>
<modify-function signature="drawPoints(const QPointF*,int)" remove="all"/>
- <add-function signature="drawPoints(QVector<QPointF>)">
+ <add-function signature="drawPoints(QVector<QPointF>)" overload-number="3">
<inject-code>
<insert-template name="qpainter_drawlist"/>
</inject-code>
</add-function>
+ <modify-function signature="drawPoints(const QPolygon&)" overload-number="0"/>
+ <modify-function signature="drawPoints(const QPolygonF&)" overload-number="1"/>
+
<modify-function signature="drawPolygon(const QPoint*,int,Qt::FillRule)" remove="all"/>
<add-function signature="drawPolygon(QVector<QPoint>,Qt::FillRule)">
<inject-code file="../glue/qtgui.cpp" snippet="qpainter-drawpolygon"/>
@@ -2601,6 +2623,10 @@
</object-type>
<object-type name="QOpenGLContext">
<enum-type name="OpenGLModuleType"/>
+ <modify-function signature="versionFunctions(const QOpenGLVersionProfile&) const">
+ <inject-code class="target" position="beginning" file="../glue/qtgui.cpp"
+ snippet="qopenglcontext-versionfunctions"/>
+ </modify-function>
</object-type>
<object-type name="QOpenGLContextGroup" since="5.0"/>
<object-type name="QOpenGLDebugLogger" since="5.1">
@@ -2616,9 +2642,7 @@
<enum-type name="FramebufferRestorePolicy" since="5.7"/>
</object-type>
<value-type name="QOpenGLFramebufferObjectFormat"/>
- <!-- Compile error on Windows: QOpenGLPaintDevice::QOpenGLPaintDevice(const QOpenGLPaintDevice &)': attempting to reference a deleted function
<object-type name="QOpenGLPaintDevice" since="5.0"/>
- -->
<object-type name="QOpenGLExtraFunctions" since="5.6">
<!-- Exlusions due to compile errors -->
<modify-function signature="glEndTransformFeedback()" remove="all"/>
@@ -2835,11 +2859,20 @@
<modify-argument index="return">
<replace-type modified-type="QString"/>
</modify-argument>
- <inject-code class="target" position="beginning" file="../glue/qtcore.cpp" snippet="qstring-return"/>
+ <inject-code class="target" position="end" file="../glue/qtgui.cpp"
+ snippet="glgetstring-return"/>
</modify-function>
</object-type>
<object-type name="QOpenGLFunctions" since="5.0">
<enum-type name="OpenGLFeature" flags="OpenGLFeatures"/>
+ <add-function signature="glGetShaderSource(unsigned int @shader@)" return-type="const char *">
+ <inject-code class="target" position="beginning" file="../glue/qtgui.cpp"
+ snippet="glgetshadersource"/>
+ </add-function>
+ <add-function signature="glShaderSource(unsigned int @shader@,const QString & @source@)">
+ <inject-code class="target" position="beginning" file="../glue/qtgui.cpp"
+ snippet="glshadersource"/>
+ </add-function>
<modify-function signature="glGetAttachedShaders(unsigned int,int,int*,unsigned int*)">
<modify-argument index="3"><array/></modify-argument>
<modify-argument index="4"><array/></modify-argument>
diff --git a/sources/pyside2/PySide2/QtNetwork/typesystem_network.xml b/sources/pyside2/PySide2/QtNetwork/typesystem_network.xml
index dc60a509..d91f0780 100644
--- a/sources/pyside2/PySide2/QtNetwork/typesystem_network.xml
+++ b/sources/pyside2/PySide2/QtNetwork/typesystem_network.xml
@@ -80,6 +80,8 @@
<modify-function signature="disconnectFromHost()" allow-thread="yes"/>
<modify-function signature="waitForConnected(int)" allow-thread="yes"/>
<modify-function signature="waitForDisconnected(int)" allow-thread="yes"/>
+ <modify-function signature="waitForBytesWritten(int)" allow-thread="yes"/>
+ <modify-function signature="waitForReadyRead(int)" allow-thread="yes"/>
</object-type>
<value-type name="QDnsDomainNameRecord"/>
diff --git a/sources/pyside2/PySide2/QtOpenGLFunctions/CMakeLists.txt b/sources/pyside2/PySide2/QtOpenGLFunctions/CMakeLists.txt
index 383afb68..62ed669c 100644
--- a/sources/pyside2/PySide2/QtOpenGLFunctions/CMakeLists.txt
+++ b/sources/pyside2/PySide2/QtOpenGLFunctions/CMakeLists.txt
@@ -42,7 +42,8 @@ else()
${QtOpenGLFunctions_GEN_DIR}/qopenglfunctions_4_4_compatibility_wrapper.cpp
${QtOpenGLFunctions_GEN_DIR}/qopenglfunctions_4_4_core_wrapper.cpp
${QtOpenGLFunctions_GEN_DIR}/qopenglfunctions_4_5_compatibility_wrapper.cpp
- ${QtOpenGLFunctions_GEN_DIR}/qopenglfunctions_4_5_core_wrapper.cpp)
+ ${QtOpenGLFunctions_GEN_DIR}/qopenglfunctions_4_5_core_wrapper.cpp
+ ${QtOpenGLFunctions_GEN_DIR}/qopenglversionfunctionsfactory_wrapper.cpp)
message(STATUS "Qt${QT_MAJOR_VERSION}OpenGLFunctions: Adding Desktop OpenGL classes")
endif()
@@ -71,3 +72,6 @@ create_pyside_module(NAME QtOpenGLFunctions
SOURCES QtOpenGLFunctions_SRC
TYPESYSTEM_NAME ${QtOpenGLFunctions_BINARY_DIR}/typesystem_openglfunctions.xml
DROPPED_ENTRIES QtOpenGLFunctions_DROPPED_ENTRIES)
+
+install(FILES ${pyside2_SOURCE_DIR}/qopenglversionfunctionsfactory.h
+ DESTINATION include/PySide2/QtOpenGLFunctions)
diff --git a/sources/pyside2/PySide2/QtOpenGLFunctions/QtOpenGLFunctions_global.post.h.in b/sources/pyside2/PySide2/QtOpenGLFunctions/QtOpenGLFunctions_global.post.h.in
index 6c8c7708..e43bc2b8 100644
--- a/sources/pyside2/PySide2/QtOpenGLFunctions/QtOpenGLFunctions_global.post.h.in
+++ b/sources/pyside2/PySide2/QtOpenGLFunctions/QtOpenGLFunctions_global.post.h.in
@@ -59,3 +59,5 @@
#if QT_CONFIG(opengles2)
# include <QtGui/qopenglfunctions_es2.h>
#endif
+
+#include "qopenglversionfunctionsfactory.h" // PySide class
diff --git a/sources/pyside2/PySide2/QtOpenGLFunctions/typesystem_openglfunctions.xml b/sources/pyside2/PySide2/QtOpenGLFunctions/typesystem_openglfunctions.xml
index 1d5b08ed..edb27136 100644
--- a/sources/pyside2/PySide2/QtOpenGLFunctions/typesystem_openglfunctions.xml
+++ b/sources/pyside2/PySide2/QtOpenGLFunctions/typesystem_openglfunctions.xml
@@ -404,6 +404,15 @@
&openglfunctions_modifications1_0;
&openglfunctions_modifications1_1;
</object-type>
+
+ <object-type name="QOpenGLVersionFunctionsFactory">
+ <modify-function signature="get(const QOpenGLVersionProfile&,QOpenGLContext*)"
+ return-type="QAbstractOpenGLFunctions*">
+ <inject-code class="target" position="beginning" file="../glue/qtopenglfunctions.cpp"
+ snippet="qopenglversionfunctionsfactory-get"/>
+ </modify-function>
+ </object-type>
+
<suppress-warning text="^There's no user provided way.*QOpenGLFunctions_\d_\d.*::glIndex.*$"/>
</typesystem>
diff --git a/sources/pyside2/PySide2/QtQml/pysideqmlregistertype.cpp b/sources/pyside2/PySide2/QtQml/pysideqmlregistertype.cpp
index 2b60c5c7..93133984 100644
--- a/sources/pyside2/PySide2/QtQml/pysideqmlregistertype.cpp
+++ b/sources/pyside2/PySide2/QtQml/pysideqmlregistertype.cpp
@@ -470,13 +470,13 @@ PyTypeObject *QtQml_VolatileBoolTypeF(void)
}
static const char *PropertyList_SignatureStrings[] = {
- "PySide2.QtQml.ListProperty(type:type,append:typing.Callable,"
+ "PySide2.QtQml.ListProperty(self,type:type,append:typing.Callable,"
"at:typing.Callable=None,clear:typing.Callable=None,count:typing.Callable=None)",
nullptr}; // Sentinel
static const char *VolatileBool_SignatureStrings[] = {
- "PySide2.QtQml.VolatileBool.get()->bool",
- "PySide2.QtQml.VolatileBool.set(a:object)",
+ "PySide2.QtQml.VolatileBool.get(self)->bool",
+ "PySide2.QtQml.VolatileBool.set(self,a:object)",
nullptr}; // Sentinel
void PySide::initQmlSupport(PyObject *module)
diff --git a/sources/pyside2/PySide2/QtQml/typesystem_qml.xml b/sources/pyside2/PySide2/QtQml/typesystem_qml.xml
index 0a12d44c..c237a9d5 100644
--- a/sources/pyside2/PySide2/QtQml/typesystem_qml.xml
+++ b/sources/pyside2/PySide2/QtQml/typesystem_qml.xml
@@ -116,7 +116,14 @@
<object-type name="QQmlAbstractUrlInterceptor">
<enum-type name="DataType"/>
</object-type>
- <object-type name="QQmlApplicationEngine"/>
+ <object-type name="QQmlApplicationEngine">
+ <!-- PYSIDE-1681: QQmlApplicationEngine constructor, load() and similar need
+ allow-thread in case there is a message handler installed
+ (qInstallMessageHandler) -->
+ <modify-function signature="^QQmlApplicationEngine\(.*\)$" allow-thread="yes"/>
+ <modify-function signature="load(const QString &)" allow-thread="yes"/>
+ <modify-function signature="load(const QUrl &)" allow-thread="yes"/>
+ </object-type>
<object-type name="QQmlComponent">
<enum-type name="CompilationMode"/>
<enum-type name="Status"/>
diff --git a/sources/pyside2/PySide2/QtTest/CMakeLists.txt b/sources/pyside2/PySide2/QtTest/CMakeLists.txt
index 04bb28cc..50b9e3e3 100644
--- a/sources/pyside2/PySide2/QtTest/CMakeLists.txt
+++ b/sources/pyside2/PySide2/QtTest/CMakeLists.txt
@@ -2,6 +2,7 @@ project(QtTest)
set(QtTest_SRC
${QtTest_GEN_DIR}/qtest_pysideqtoucheventsequence_wrapper.cpp
+${QtTest_GEN_DIR}/qabstractitemmodeltester_wrapper.cpp
${QtTest_GEN_DIR}/qtest_wrapper.cpp
# module is always needed
${QtTest_GEN_DIR}/qttest_module_wrapper.cpp
diff --git a/sources/pyside2/PySide2/QtTest/typesystem_test.xml b/sources/pyside2/PySide2/QtTest/typesystem_test.xml
index f7facaf7..5aa45feb 100644
--- a/sources/pyside2/PySide2/QtTest/typesystem_test.xml
+++ b/sources/pyside2/PySide2/QtTest/typesystem_test.xml
@@ -102,6 +102,10 @@
</object-type>
^^^ this is now moved into QtGui -->
+ <object-type name="QAbstractItemModelTester">
+ <enum-type name="FailureReportingMode"/>
+ </object-type>
+
<namespace-type name="QTest">
<!-- Qt5: private <enum-type name="AttributeIndex" since="4.6"/> -->
<enum-type name="KeyAction"/>
diff --git a/sources/pyside2/PySide2/QtWidgets/typesystem_widgets_common.xml b/sources/pyside2/PySide2/QtWidgets/typesystem_widgets_common.xml
index 155591b0..91458e31 100644
--- a/sources/pyside2/PySide2/QtWidgets/typesystem_widgets_common.xml
+++ b/sources/pyside2/PySide2/QtWidgets/typesystem_widgets_common.xml
@@ -1276,6 +1276,10 @@
<inject-code class="target" position="beginning" file="../glue/qtwidgets.cpp" snippet="removeownership-1"/>
</modify-function>
+ <modify-function signature="replaceWidget(QWidget*,QWidget*,QFlags<Qt::FindChildOption>)">
+ <inject-code class="target" position="beginning" file="../glue/qtwidgets.cpp" snippet="addownership-2"/>
+ </modify-function>
+
<modify-function signature="parentWidget()const">
<modify-argument index="this">
<parent index="return" action="add"/>
diff --git a/sources/pyside2/PySide2/glue/qtcore.cpp b/sources/pyside2/PySide2/glue/qtcore.cpp
index 306a2239..78de3d5d 100644
--- a/sources/pyside2/PySide2/glue/qtcore.cpp
+++ b/sources/pyside2/PySide2/glue/qtcore.cpp
@@ -76,7 +76,7 @@ if (kwds || numArgs > 1) {
PyTypeObject *typeObj = reinterpret_cast<PyTypeObject*>(%PYARG_3);
-if (typeObj) {
+if (typeObj && !Shiboken::ObjectType::checkType(typeObj)) {
if (typeObj == &PyList_Type) {
QByteArray out_ba = out.toByteArray();
if (!out_ba.isEmpty()) {
@@ -122,8 +122,14 @@ if (typeObj) {
Py_INCREF(Py_False);
%PYARG_0 = Py_False;
}
+ } else {
+ // TODO: PyDict_Type and PyTuple_Type
+ PyErr_SetString(PyExc_TypeError,
+ "Invalid type parameter.\n"
+ "\tUse 'list', 'bytes', 'str', 'int', 'float', 'bool', "
+ "or a Qt-derived type");
+ return nullptr;
}
- // TODO: PyDict_Type and PyTuple_Type
}
else {
if (!out.isValid()) {
@@ -793,12 +799,35 @@ qRegisterMetaType<QVector<int> >("QVector<int>");
// @snippet qobject-metaobject
// @snippet qobject-findchild-1
+static bool _findChildTypeMatch(const QObject *child, PyTypeObject *desiredType)
+{
+ auto *pyChildType = PySide::getTypeForQObject(child);
+ return pyChildType != nullptr && PyType_IsSubtype(pyChildType, desiredType);
+}
+
+static inline bool _findChildrenComparator(const QObject *child,
+ const QRegularExpression &name)
+{
+ return name.match(child->objectName()).hasMatch();
+}
+
+static inline bool _findChildrenComparator(const QObject *child,
+ const QString &name)
+{
+ return name.isNull() || name == child->objectName();
+}
+
+static inline bool _findChildrenComparator(const QObject *child,
+ const QRegExp &name)
+{
+ return name.indexIn(child->objectName()) != -1;
+}
+
static QObject *_findChildHelper(const QObject *parent, const QString &name, PyTypeObject *desiredType)
{
for (auto *child : parent->children()) {
- Shiboken::AutoDecRef pyChild(%CONVERTTOPYTHON[QObject *](child));
- if (PyType_IsSubtype(Py_TYPE(pyChild), desiredType)
- && (name.isNull() || name == child->objectName())) {
+ if (_findChildrenComparator(child, name)
+ && _findChildTypeMatch(child, desiredType)) {
return child;
}
}
@@ -811,28 +840,15 @@ static QObject *_findChildHelper(const QObject *parent, const QString &name, PyT
return nullptr;
}
-static inline bool _findChildrenComparator(const QObject *&child, const QRegExp &name)
-{
- return name.indexIn(child->objectName()) != -1;
-}
-
-static inline bool _findChildrenComparator(const QObject *&child, const QRegularExpression &name)
-{
- return name.match(child->objectName()).hasMatch();
-}
-
-static inline bool _findChildrenComparator(const QObject *&child, const QString &name)
-{
- return name.isNull() || name == child->objectName();
-}
-
-template<typename T>
+template<typename T> // QString/QRegularExpression/QRegExp
static void _findChildrenHelper(const QObject *parent, const T& name, PyTypeObject *desiredType, PyObject *result)
{
for (const auto *child : parent->children()) {
- Shiboken::AutoDecRef pyChild(%CONVERTTOPYTHON[QObject *](child));
- if (PyType_IsSubtype(Py_TYPE(pyChild), desiredType) && _findChildrenComparator(child, name))
+ if (_findChildrenComparator(child, name)
+ && _findChildTypeMatch(child, desiredType)) {
+ Shiboken::AutoDecRef pyChild(%CONVERTTOPYTHON[QObject *](child));
PyList_Append(result, pyChild);
+ }
_findChildrenHelper(child, name, desiredType, result);
}
}
@@ -848,19 +864,41 @@ QObject *child = _findChildHelper(%CPPSELF, %2, reinterpret_cast<PyTypeObject *>
_findChildrenHelper(%CPPSELF, %2, reinterpret_cast<PyTypeObject *>(%PYARG_1), %PYARG_0);
// @snippet qobject-findchildren
+//////////////////////////////////////////////////////////////////////////////
+// PYSIDE-131: Use the class name as context where the calling function is
+// living. Derived Python classes have the wrong context.
+//
+// The original patch uses Python introspection to look up the current
+// function (from the frame stack) in the class __dict__ along the mro.
+//
+// The problem is that looking into the frame stack works for Python
+// functions, only. For including builtin function callers, the following
+// approach turned out to be much simpler:
+//
+// Walk the __mro__
+// - translate the string
+// - if the translated string is changed:
+// - return the translation.
+
// @snippet qobject-tr
-QString result;
-if (QCoreApplication::instance()) {
- PyObject *klass = PyObject_GetAttr(%PYSELF, Shiboken::PyMagicName::class_());
- PyObject *cname = PyObject_GetAttr(klass, Shiboken::PyMagicName::name());
- result = QString(QCoreApplication::instance()->translate(Shiboken::String::toCString(cname),
- /* %1, %2, QCoreApplication::CodecForTr, %3)); */
- %1, %2, %3));
-
- Py_DECREF(klass);
- Py_DECREF(cname);
-} else {
- result = QString(QString::fromLatin1(%1));
+PyTypeObject *type = Py_TYPE(%PYSELF);
+PyObject *mro = type->tp_mro;
+auto len = PyTuple_GET_SIZE(mro);
+QString result = QString::fromUtf8(%1);
+QString oldResult = result;
+static auto *sbkObjectType = reinterpret_cast<PyTypeObject *>(SbkObject_TypeF());
+for (Py_ssize_t idx = 0; idx < len - 1; ++idx) {
+ // Skip the last class which is `object`.
+ auto *type = reinterpret_cast<PyTypeObject *>(PyTuple_GET_ITEM(mro, idx));
+ if (type == sbkObjectType)
+ continue;
+ const char *context = type->tp_name;
+ const char *dotpos = strrchr(context, '.');
+ if (dotpos != nullptr)
+ context = dotpos + 1;
+ result = QCoreApplication::translate(context, %1, %2, %3);
+ if (result != oldResult)
+ break;
}
%PYARG_0 = %CONVERTTOPYTHON[QString](result);
// @snippet qobject-tr
diff --git a/sources/pyside2/PySide2/glue/qtdatavisualization.cpp b/sources/pyside2/PySide2/glue/qtdatavisualization.cpp
index 119d79a4..ce5aa693 100644
--- a/sources/pyside2/PySide2/glue/qtdatavisualization.cpp
+++ b/sources/pyside2/PySide2/glue/qtdatavisualization.cpp
@@ -40,3 +40,40 @@
// @snippet releaseownership
Shiboken::Object::releaseOwnership(%PYARG_1);
// @snippet releaseownership
+
+// @snippet qcustom3dvolume-settexturedata
+using VectorType = decltype(%1);
+%CPPSELF.setTextureData(new VectorType(%1));
+// @snippet qcustom3dvolume-settexturedata
+
+// @snippet dataproxy-addrow
+using VectorType = decltype(%1);
+%RETURN_TYPE %0 = %CPPSELF.addRow(new VectorType(%1));
+%PYARG_0 = %CONVERTTOPYTHON[%RETURN_TYPE](%0);
+// @snippet dataproxy-addrow
+
+// @snippet dataproxy-addrow-string
+using VectorType = decltype(%1);
+%RETURN_TYPE %0 = %CPPSELF.addRow(new VectorType(%1), %2);
+%PYARG_0 = %CONVERTTOPYTHON[%RETURN_TYPE](%0);
+// @snippet dataproxy-addrow-string
+
+// @snippet dataproxy-insertrow
+using VectorType = decltype(%2);
+%CPPSELF.insertRow(%1, new VectorType(%2));
+// @snippet dataproxy-insertrow
+
+// @snippet dataproxy-insertrow-string
+using VectorType = decltype(%2);
+%CPPSELF.insertRow(%1, new VectorType(%2), %3);
+// @snippet dataproxy-insertrow-string
+
+// @snippet dataproxy-setrow
+using VectorType = decltype(%2);
+%CPPSELF.setRow(%1, new VectorType(%2));
+// @snippet dataproxy-setrow
+
+// @snippet dataproxy-setrow-string
+using VectorType = decltype(%2);
+%CPPSELF.setRow(%1, new VectorType(%2), %3);
+// @snippet dataproxy-setrow-string
diff --git a/sources/pyside2/PySide2/glue/qtgui.cpp b/sources/pyside2/PySide2/glue/qtgui.cpp
index a6b45b7c..00d04578 100644
--- a/sources/pyside2/PySide2/glue/qtgui.cpp
+++ b/sources/pyside2/PySide2/glue/qtgui.cpp
@@ -41,6 +41,53 @@
* INJECT CODE
********************************************************************/
+// @snippet qopenglcontext-versionfunctions
+
+// %CPPSELF.%FUNCTION_NAME(%1, %2); Pretend to shiboken we call the function
+
+// Import QtOpenGLFunctions and call the factory function
+// QOpenGLVersionFunctionsFactory.get()
+PyObject *module = PyImport_ImportModule("PySide2.QtOpenGLFunctions");
+if (module == nullptr)
+ return nullptr;
+PyObject *loc = PyModule_GetDict(module);
+static PyObject *const factoryName =
+ Shiboken::String::createStaticString("QOpenGLVersionFunctionsFactory");
+auto factory = PyDict_GetItem(loc, factoryName);
+if (factory == nullptr)
+ return nullptr;
+
+static PyObject *const getMethod = Shiboken::String::createStaticString("get");
+%PYARG_0 = PyObject_CallMethodObjArgs(factory, getMethod, pyArgs[0], %PYSELF,
+ nullptr);
+// @snippet qopenglcontext-versionfunctions
+
+// @snippet glgetshadersource
+GLsizei bufSize = 4096;
+GLsizei length = bufSize - 1;
+QByteArray buffer;
+for (; length == bufSize - 1; bufSize += 4096) {
+ buffer.resize(qsizetype(bufSize));
+ %CPPSELF->%FUNCTION_NAME(%1, bufSize, &length, buffer.data());
+ if (%CPPSELF->glGetError() != GL_NO_ERROR) {
+ buffer.clear();
+ break;
+ }
+}
+auto *data = buffer.constData();
+%PYARG_0 = %CONVERTTOPYTHON[char *](data);
+// @snippet glgetshadersource
+
+// @snippet glshadersource
+const QByteArray buffer = %2.toUtf8();
+const char *sources[] = {buffer.constData()};
+%CPPSELF->%FUNCTION_NAME(%1, 1, sources, nullptr);
+// @snippet glshadersource
+
+// @snippet glgetstring-return
+%PYARG_0 = %CONVERTTOPYTHON[const char *](%0);
+// @snippet glgetstring-return
+
// @snippet qtransform-quadtoquad
QTransform _result;
if (QTransform::quadToQuad(%1, %2, _result)) {
@@ -143,6 +190,16 @@ for (int i = 0, i_max = %CPPSELF.count(); i < i_max; ++i){
%0 = new %TYPE(QPixmap::fromImage(%1));
// @snippet qpixmap
+// @snippet qimage-decref-image-data
+static void imageDecrefDataHandler(void *data)
+{
+ // Avoid "Python memory allocator called without holding the GIL"
+ auto state = PyGILState_Ensure();
+ Py_DECREF(reinterpret_cast<PyObject *>(data));
+ PyGILState_Release(state);
+}
+// @snippet qimage-decref-image-data
+
// @snippet qimage-constbits
%PYARG_0 = Shiboken::Buffer::newObject(%CPPSELF.%FUNCTION_NAME(), %CPPSELF.byteCount());
// @snippet qimage-constbits
diff --git a/sources/pyside2/PySide2/glue/qtopenglfunctions.cpp b/sources/pyside2/PySide2/glue/qtopenglfunctions.cpp
new file mode 100644
index 00000000..c839ae44
--- /dev/null
+++ b/sources/pyside2/PySide2/glue/qtopenglfunctions.cpp
@@ -0,0 +1,76 @@
+/****************************************************************************
+**
+** Copyright (C) 2021 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt for Python.
+**
+** $QT_BEGIN_LICENSE:COMM$
+**
+** 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.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+// @snippet qopenglversionfunctionsfactory-get
+QAbstractOpenGLFunctions *af = %CPPSELF.%FUNCTION_NAME(%1, %2);
+if (auto *f = dynamic_cast<QOpenGLFunctions_4_5_Core *>(af)) {
+ %PYARG_0 = %CONVERTTOPYTHON[QOpenGLFunctions_4_5_Core *](f);
+} else if (auto *f = dynamic_cast<QOpenGLFunctions_4_5_Compatibility *>(af)) {
+ %PYARG_0 = %CONVERTTOPYTHON[QOpenGLFunctions_4_5_Compatibility *](f);
+} else if (auto *f = dynamic_cast<QOpenGLFunctions_4_4_Core *>(af)) {
+ %PYARG_0 = %CONVERTTOPYTHON[QOpenGLFunctions_4_4_Core *](f);
+} else if (auto *f = dynamic_cast<QOpenGLFunctions_4_4_Compatibility *>(af)) {
+ %PYARG_0 = %CONVERTTOPYTHON[QOpenGLFunctions_4_4_Compatibility *](f);
+} else if (auto *f = dynamic_cast<QOpenGLFunctions_4_3_Core *>(af)) {
+ %PYARG_0 = %CONVERTTOPYTHON[QOpenGLFunctions_4_3_Core *](f);
+} else if (auto *f = dynamic_cast<QOpenGLFunctions_4_2_Core *>(af)) {
+ %PYARG_0 = %CONVERTTOPYTHON[QOpenGLFunctions_4_2_Core *](f);
+} else if (auto *f = dynamic_cast<QOpenGLFunctions_4_1_Core *>(af)) {
+ %PYARG_0 = %CONVERTTOPYTHON[QOpenGLFunctions_4_1_Core *](f);
+} else if (auto *f = dynamic_cast<QOpenGLFunctions_4_0_Core *>(af)) {
+ %PYARG_0 = %CONVERTTOPYTHON[QOpenGLFunctions_4_0_Core *](f);
+} else if (auto *f = dynamic_cast<QOpenGLFunctions_4_0_Compatibility *>(af)) {
+ %PYARG_0 = %CONVERTTOPYTHON[QOpenGLFunctions_4_0_Compatibility *](f);
+} else if (auto *f = dynamic_cast<QOpenGLFunctions_3_3_Core *>(af)) {
+ %PYARG_0 = %CONVERTTOPYTHON[QOpenGLFunctions_3_3_Core *](f);
+} else if (auto *f = dynamic_cast<QOpenGLFunctions_3_3_Compatibility *>(af)) {
+ %PYARG_0 = %CONVERTTOPYTHON[QOpenGLFunctions_3_3_Compatibility *](f);
+} else if (auto *f = dynamic_cast<QOpenGLFunctions_3_2_Core *>(af)) {
+ %PYARG_0 = %CONVERTTOPYTHON[QOpenGLFunctions_3_2_Core *](f);
+} else if (auto *f = dynamic_cast<QOpenGLFunctions_3_2_Compatibility *>(af)) {
+ %PYARG_0 = %CONVERTTOPYTHON[QOpenGLFunctions_3_2_Compatibility *](f);
+} else if (auto *f = dynamic_cast<QOpenGLFunctions_3_1 *>(af)) {
+ %PYARG_0 = %CONVERTTOPYTHON[QOpenGLFunctions_3_1 *](f);
+} else if (auto *f = dynamic_cast<QOpenGLFunctions_3_0 *>(af)) {
+ %PYARG_0 = %CONVERTTOPYTHON[QOpenGLFunctions_3_0 *](f);
+} else if (auto *f = dynamic_cast<QOpenGLFunctions_2_1 *>(af)) {
+ %PYARG_0 = %CONVERTTOPYTHON[QOpenGLFunctions_2_1 *](f);
+} else if (auto *f = dynamic_cast<QOpenGLFunctions_2_0 *>(af)) {
+ %PYARG_0 = %CONVERTTOPYTHON[QOpenGLFunctions_2_0 *](f);
+} else if (auto *f = dynamic_cast<QOpenGLFunctions_1_5 *>(af)) {
+ %PYARG_0 = %CONVERTTOPYTHON[QOpenGLFunctions_1_5 *](f);
+} else if (auto *f = dynamic_cast<QOpenGLFunctions_1_4 *>(af)) {
+ %PYARG_0 = %CONVERTTOPYTHON[QOpenGLFunctions_1_4 *](f);
+} else if (auto *f = dynamic_cast<QOpenGLFunctions_1_3 *>(af)) {
+ %PYARG_0 = %CONVERTTOPYTHON[QOpenGLFunctions_1_3 *](f);
+} else if (auto *f = dynamic_cast<QOpenGLFunctions_1_2 *>(af)) {
+ %PYARG_0 = %CONVERTTOPYTHON[QOpenGLFunctions_1_2 *](f);
+} else if (auto *f = dynamic_cast<QOpenGLFunctions_1_1 *>(af)) {
+ %PYARG_0 = %CONVERTTOPYTHON[QOpenGLFunctions_1_1 *](f);
+} else if (auto *f = dynamic_cast<QOpenGLFunctions_1_0 *>(af)) {
+ %PYARG_0 = %CONVERTTOPYTHON[QOpenGLFunctions_1_0 *](f);
+} else {
+ QString message;
+ QDebug(&message) << "No OpenGL functions could be obtained for" << %1;
+ PyErr_SetString(PyExc_RuntimeError, message.toUtf8().constData());
+ %PYARG_0 = Py_None;
+}
+// @snippet qopenglversionfunctionsfactory-get
diff --git a/sources/pyside2/PySide2/qopenglversionfunctionsfactory.h b/sources/pyside2/PySide2/qopenglversionfunctionsfactory.h
new file mode 100644
index 00000000..27b8373f
--- /dev/null
+++ b/sources/pyside2/PySide2/qopenglversionfunctionsfactory.h
@@ -0,0 +1,45 @@
+/****************************************************************************
+**
+** Copyright (C) 2021 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt for Python.
+**
+** $QT_BEGIN_LICENSE:COMM$
+**
+** 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.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QOPENGLVERSIONFUNCTIONSFACTORY_H
+#define QOPENGLVERSIONFUNCTIONSFACTORY_H
+
+#include <QtGui/QOpenGLContext>
+
+QT_BEGIN_NAMESPACE
+
+class QOpenGLVersionProfile;
+
+class QOpenGLVersionFunctionsFactory
+{
+public:
+ static QAbstractOpenGLFunctions *get(const QOpenGLVersionProfile &versionProfile,
+ QOpenGLContext *context)
+ {
+ return context
+ ? context->versionFunctions(versionProfile)
+ : nullptr;
+ }
+};
+
+QT_END_NAMESPACE
+
+#endif // QOPENGLVERSIONFUNCTIONSFACTORY_H
diff --git a/sources/pyside2/PySide2/support/generate_pyi.py b/sources/pyside2/PySide2/support/generate_pyi.py
index d71ee338..9eb84de7 100644
--- a/sources/pyside2/PySide2/support/generate_pyi.py
+++ b/sources/pyside2/PySide2/support/generate_pyi.py
@@ -1,4 +1,6 @@
# This Python file uses the following encoding: utf-8
+from __future__ import print_function, absolute_import, unicode_literals
+LICENSE_TEXT = """
#############################################################################
##
## Copyright (C) 2020 The Qt Company Ltd.
@@ -37,8 +39,7 @@
## $QT_END_LICENSE$
##
#############################################################################
-
-from __future__ import print_function, absolute_import, unicode_literals
+"""
"""
generate_pyi.py
@@ -131,6 +132,7 @@ class Formatter(Writer):
self.optional_replacer = optional_replacer
# self.level is maintained by enum_sig.py
# self.after_enum() is a one-shot set by enum_sig.py .
+ # self.is_method() is true for non-plain functions.
@contextmanager
def module(self, mod_name):
@@ -187,7 +189,7 @@ class Formatter(Writer):
yield key
def _function(self, func_name, signature, spaces):
- if "self" not in tuple(signature.parameters.keys()):
+ if self.is_method() and "self" not in tuple(signature.parameters.keys()):
self.print('{spaces}@staticmethod'.format(**locals()))
signature = self.optional_replacer(signature)
self.print('{spaces}def {func_name}{signature}: ...'.format(**locals()))
@@ -200,14 +202,6 @@ class Formatter(Writer):
yield
-def get_license_text():
- with io.open(sourcepath) as f:
- lines = f.readlines()
- license_line = next((lno for lno, line in enumerate(lines)
- if "$QT_END_LICENSE$" in line))
- return "".join(lines[:license_line + 3])
-
-
def find_imports(text):
return [imp for imp in PySide2.__all__ if imp + "." in text]
@@ -227,7 +221,7 @@ def generate_pyi(import_name, outpath, options):
outfile = io.StringIO()
fmt = Formatter(outfile)
- fmt.print(get_license_text()) # which has encoding, already
+ fmt.print(LICENSE_TEXT.strip())
need_imports = not USE_PEP563
if USE_PEP563:
fmt.print("from __future__ import annotations")
@@ -306,6 +300,8 @@ def generate_all_pyi(outpath, options):
if __name__ == "__main__":
+ # PYSIDE-1621: Enforce embedding to ensure that it always works.
+ sys.pyside_uses_embedding = True
parser = argparse.ArgumentParser(
description="This script generates the .pyi file for all PySide modules.")
parser.add_argument("modules", nargs="+",
diff --git a/sources/pyside2/PySide2/templates/core_common.xml b/sources/pyside2/PySide2/templates/core_common.xml
index 6d02428a..b5d1f02e 100644
--- a/sources/pyside2/PySide2/templates/core_common.xml
+++ b/sources/pyside2/PySide2/templates/core_common.xml
@@ -114,35 +114,52 @@
<insert-template name="tuple_retval_ok"/>
</template>
+ <!-- QInputDialog: these should allow threads -->
<template name="fix_arg,arg,arg,arg,arg,arg,arg,bool*,arg">
bool ok_;
- %RETURN_TYPE retval_ = %CPPSELF.%FUNCTION_NAME(%1, %2, %3, %4, %5, %6, %7, &ok_, %9);
+ %RETURN_TYPE retval_;
+ Py_BEGIN_ALLOW_THREADS
+ retval_ = %CPPSELF.%FUNCTION_NAME(%1, %2, %3, %4, %5, %6, %7, &ok_, %9);
+ Py_END_ALLOW_THREADS
<insert-template name="tuple_retval_ok"/>
</template>
<template name="fix_arg,arg,arg,arg,arg,arg,arg,bool*,arg,arg">
bool ok_;
- %RETURN_TYPE retval_ = %CPPSELF.%FUNCTION_NAME(%1, %2, %3, %4, %5, %6, %7, &ok_, %9, %10);
+ %RETURN_TYPE retval_;
+ Py_BEGIN_ALLOW_THREADS
+ retval_ = %CPPSELF.%FUNCTION_NAME(%1, %2, %3, %4, %5, %6, %7, &ok_, %9, %10);
+ Py_END_ALLOW_THREADS
<insert-template name="tuple_retval_ok"/>
</template>
<template name="fix_arg,arg,arg,arg,arg,arg,bool*,arg">
bool ok_;
- %RETURN_TYPE retval_ = %CPPSELF.%FUNCTION_NAME(%1, %2, %3, %4, %5, %6, &ok_, %8);
+ %RETURN_TYPE retval_;
+ Py_BEGIN_ALLOW_THREADS
+ retval_ = %CPPSELF.%FUNCTION_NAME(%1, %2, %3, %4, %5, %6, &ok_, %8);
+ Py_END_ALLOW_THREADS
<insert-template name="tuple_retval_ok"/>
</template>
<template name="fix_arg,arg,arg,arg,arg,bool*,arg">
bool ok_;
- %RETURN_TYPE retval_ = %CPPSELF.%FUNCTION_NAME(%1, %2, %3, %4, %5, &ok_, %7);
+ %RETURN_TYPE retval_;
+ Py_BEGIN_ALLOW_THREADS
+ retval_ = %CPPSELF.%FUNCTION_NAME(%1, %2, %3, %4, %5, &ok_, %7);
+ Py_END_ALLOW_THREADS
<insert-template name="tuple_retval_ok"/>
</template>
<template name="fix_arg,arg,arg,arg,bool*,arg,arg">
bool ok_;
- %RETURN_TYPE retval_ = %CPPSELF.%FUNCTION_NAME(%1, %2, %3, %4, &ok_, %6, %7);
+ %RETURN_TYPE retval_;
+ Py_BEGIN_ALLOW_THREADS
+ retval_ = %CPPSELF.%FUNCTION_NAME(%1, %2, %3, %4, &ok_, %6, %7);
+ Py_END_ALLOW_THREADS
<insert-template name="tuple_retval_ok"/>
</template>
+ <!-- End of QInputDialog templates -->
<template name="fix_char*">
char val_{};
diff --git a/sources/pyside2/PySide2/templates/gui_common.xml b/sources/pyside2/PySide2/templates/gui_common.xml
index a139a5fe..1a740679 100644
--- a/sources/pyside2/PySide2/templates/gui_common.xml
+++ b/sources/pyside2/PySide2/templates/gui_common.xml
@@ -80,8 +80,9 @@
</template>
<template name="qimage_buffer_constructor">
+ Py_INCREF(%PYARG_1);
auto ptr = reinterpret_cast<uchar*>(Shiboken::Buffer::getPointer(%PYARG_1));
- %0 = new %TYPE(ptr, %ARGS);
+ %0 = new %TYPE(ptr, %ARGS, imageDecrefDataHandler, %PYARG_1);
</template>
<template name="qcolor_repr">
diff --git a/sources/pyside2/doc/CMakeLists.txt b/sources/pyside2/doc/CMakeLists.txt
index ab5d694e..950e4868 100644
--- a/sources/pyside2/doc/CMakeLists.txt
+++ b/sources/pyside2/doc/CMakeLists.txt
@@ -152,6 +152,7 @@ configure_file("conf.py.in" "rst/conf.py" @ONLY)
add_custom_target("docrsts"
COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR}/rst
COMMAND Shiboken2::shiboken2 --generator-set=qtdoc ${docHeader}
+ --enable-pyside-extensions
--include-paths="${QT_INCLUDE_DIR}${PATH_SEP}${pyside2_SOURCE_DIR}${PATH_SEP}${TS_ROOT}"
--api-version=${SUPPORTED_QT_VERSION}
--typesystem-paths="${QDOC_TYPESYSTEM_PATH}"
diff --git a/sources/pyside2/doc/extras/QtCore.Property.rst b/sources/pyside2/doc/extras/QtCore.Property.rst
index a10c9f80..6bcfc265 100644
--- a/sources/pyside2/doc/extras/QtCore.Property.rst
+++ b/sources/pyside2/doc/extras/QtCore.Property.rst
@@ -1,5 +1,6 @@
.. currentmodule:: PySide2.QtCore
.. _Property:
+
Property
********
@@ -8,7 +9,9 @@ Detailed Description
The Property function lets you declare properties that
behave both as Qt and Python properties, and have their
-setters and getters defined as Python functions.
+getters and setters defined as Python functions.
+
+They are equivalent to the ``Q_PROPERTY`` macro in the `Qt Docs`_.
Here is an example that illustrates how to use this
function:
@@ -19,14 +22,14 @@ function:
from PySide2.QtCore import QObject, Property
class MyObject(QObject):
- def __init__(self,startval=42):
+ def __init__(self, startval=42):
QObject.__init__(self)
self.ppval = startval
def readPP(self):
return self.ppval
- def setPP(self,val):
+ def setPP(self, val):
self.ppval = val
pp = Property(int, readPP, setPP)
@@ -35,6 +38,68 @@ function:
obj.pp = 47
print(obj.pp)
+The full options for ``QtCore.Property`` can be found with ``QtCore.Property.__doc__``:
+
+.. code-block::
+
+ Property(self, type: type,
+ fget: Optional[Callable] = None,
+ fset: Optional[Callable] = None,
+ freset: Optional[Callable] = None,
+ fdel: Optional[Callable] = None,
+ doc: str = '', notify: Optional[Callable] = None,
+ designable: bool = True, scriptable: bool = True,
+ stored: bool = True, user: bool = False,
+ constant: bool = False, final: bool = False) -> PySide2.QtCore.Property
+
+Normally, only ``type``, ``fget``and ``fset`` are used.
+
+
+Properties compared with Python properties
+------------------------------------------
+
+``Python`` has property objects very similar to ``QtCore.Property``.
+Despite the fact that the latter has an extra ``freset`` function, the usage
+of properties is almost the same. The main difference is that ``QtCore.Property``
+requires a ``type`` parameter.
+
+In the above example, the following lines would be equivalent properties:
+
+.. code-block::
+
+ pp = QtCore.Property(int, readPP, setPP) # PySide version
+ pp = property(readPP, setPP) # Python version
+
+As you know from the `Python Docs`_, ``Python`` allows to break the property
+creation into multiple steps, using the decorator syntax. We can do this in
+``PySide`` as well:
+
+.. code-block::
+ :linenos:
+
+ from PySide2.QtCore import QObject, Property
+
+ class MyObject(QObject):
+ def __init__(self, startval=42):
+ QObject.__init__(self)
+ self.ppval = startval
+
+ @Property(int)
+ def pp(self):
+ return self.ppval
+
+ @pp.setter
+ def pp(self, val):
+ self.ppval = val
+
+ obj = MyObject()
+ obj.pp = 47
+ print(obj.pp)
+
+Please be careful here: The two ``Python`` functions have the same name, intentionally.
+This is needed to let ``Python`` know that these functions belong to the same property.
+
+
Properties in QML expressions
-----------------------------
@@ -60,3 +125,6 @@ example illustrating how to do this:
pass
name = Property(str, _name, notify=name_changed)
+
+.. _`Python Docs`: https://docs.python.org/3/library/functions.html?highlight=property#property
+.. _`Qt Docs`: https://doc.qt.io/qt-5/properties.html
diff --git a/sources/pyside2/doc/quickstart.rst b/sources/pyside2/doc/quickstart.rst
index 87471a8a..db2e9328 100644
--- a/sources/pyside2/doc/quickstart.rst
+++ b/sources/pyside2/doc/quickstart.rst
@@ -52,12 +52,6 @@ constructs to print version information::
# Prints the Qt version used to compile PySide2
print(PySide2.QtCore.__version__)
-.. note::
-
- As it happened in 5.14.2, PySide had a couple of new releases to fix
- issues in 5.14.2, adding yet another version level. In that case, you
- will have different versions being shown for Qt and PySide.
-
Create a Simple Application
---------------------------
diff --git a/sources/pyside2/doc/tutorials/basictutorial/uifiles.rst b/sources/pyside2/doc/tutorials/basictutorial/uifiles.rst
index 98238462..8da69819 100644
--- a/sources/pyside2/doc/tutorials/basictutorial/uifiles.rst
+++ b/sources/pyside2/doc/tutorials/basictutorial/uifiles.rst
@@ -185,3 +185,11 @@ command prompt:
.. code-block:: python
python main.py
+
+.. note::
+
+ `QUiLoader` uses connect() calls taking the function signatures as string
+ arguments for signal/slot connections.
+ It is thus unable to handle Python types like `str` or `list` from
+ custom widgets written in Python since these types are internally mapped
+ to different C++ types.
diff --git a/sources/pyside2/libpyside/feature_select.cpp b/sources/pyside2/libpyside/feature_select.cpp
index 6a21d168..3011b358 100644
--- a/sources/pyside2/libpyside/feature_select.cpp
+++ b/sources/pyside2/libpyside/feature_select.cpp
@@ -255,6 +255,7 @@ static bool replaceClassDict(PyTypeObject *type)
// Replace `__dict__` which usually has refcount 1 (but see cyclic_test.py)
Py_DECREF(type->tp_dict);
type->tp_dict = new_dict;
+ setCurrentSelectId(type, select_id.object());
return true;
}
@@ -275,6 +276,7 @@ static bool addNewDict(PyTypeObject *type, PyObject *select_id)
setNextDict(dict, new_dict);
setNextDict(new_dict, next_dict);
type->tp_dict = new_dict;
+ setCurrentSelectId(type, select_id);
return true;
}
@@ -297,6 +299,7 @@ static bool moveToFeatureSet(PyTypeObject *type, PyObject *select_id)
}
} while (dict != initial_dict);
type->tp_dict = initial_dict;
+ setCurrentSelectId(type, getSelectId(initial_dict));
return false;
}
@@ -405,6 +408,8 @@ static inline PyObject *SelectFeatureSet(PyTypeObject *type)
if (!SelectFeatureSetSubtype(sub_type, select_id))
break;
}
+ // PYSIDE-1436: Clear all caches for the type and subtypes.
+ PyType_Modified(type);
}
return type->tp_dict;
}
@@ -418,6 +423,13 @@ void Select(PyObject *obj)
type->tp_dict = SelectFeatureSet(type);
}
+PyObject *Select(PyTypeObject *type)
+{
+ if (featurePointer != nullptr)
+ type->tp_dict = SelectFeatureSet(type);
+ return type->tp_dict;
+}
+
static bool feature_01_addLowerNames(PyTypeObject *type, PyObject *prev_dict, int id);
static bool feature_02_true_property(PyTypeObject *type, PyObject *prev_dict, int id);
static bool feature_04_addDummyNames(PyTypeObject *type, PyObject *prev_dict, int id);
@@ -446,11 +458,11 @@ void finalize()
}
static bool patch_property_impl();
+static bool is_initialized = false;
void init()
{
// This function can be called multiple times.
- static bool is_initialized = false;
if (!is_initialized) {
fast_id_array = &_fast_id_array[1];
for (int idx = -1; idx < 256; ++idx)
@@ -466,6 +478,14 @@ void init()
cached_globals = nullptr;
}
+void Enable(bool enable)
+{
+ if (!is_initialized)
+ return;
+ featurePointer = enable ? featureProcArray : nullptr;
+ initSelectableFeature(enable ? SelectFeatureSet : nullptr);
+}
+
//////////////////////////////////////////////////////////////////////////////
//
// PYSIDE-1019: Support switchable extensions
diff --git a/sources/pyside2/libpyside/globalreceiverv2.cpp b/sources/pyside2/libpyside/globalreceiverv2.cpp
index 0377f769..b16a923d 100644
--- a/sources/pyside2/libpyside/globalreceiverv2.cpp
+++ b/sources/pyside2/libpyside/globalreceiverv2.cpp
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2016 The Qt Company Ltd.
+** Copyright (C) 2020 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt for Python.
@@ -108,14 +108,14 @@ DynamicSlotDataV2::DynamicSlotDataV2(PyObject *callback, GlobalReceiverV2 *paren
//monitor class from method lifetime
m_weakRef = WeakRef::create(m_pythonSelf, DynamicSlotDataV2::onCallbackDestroyed, this);
- m_hash = QByteArray::number((qlonglong)PyObject_Hash(m_callback))
- + QByteArray::number((qlonglong)PyObject_Hash(m_pythonSelf));
-
+ // PYSIDE-1422: Avoid hash on self which might be unhashable.
+ m_hash = QByteArray::number(static_cast<qlonglong>(PyObject_Hash(m_callback)))
+ + QByteArray::number(reinterpret_cast<qlonglong>(m_pythonSelf));
} else {
m_callback = callback;
Py_INCREF(m_callback);
- m_hash = QByteArray::number((qlonglong)PyObject_Hash(m_callback));
+ m_hash = QByteArray::number(static_cast<qlonglong>(PyObject_Hash(m_callback)));
}
}
@@ -128,10 +128,11 @@ QByteArray DynamicSlotDataV2::hash(PyObject *callback)
{
Shiboken::GilState gil;
if (PyMethod_Check(callback)) {
- return QByteArray::number((qlonglong)PyObject_Hash(PyMethod_GET_FUNCTION(callback)))
- + QByteArray::number((qlonglong)PyObject_Hash(PyMethod_GET_SELF(callback)));
+ // PYSIDE-1422: Avoid hash on self which might be unhashable.
+ return QByteArray::number(static_cast<qlonglong>(PyObject_Hash(PyMethod_GET_FUNCTION(callback))))
+ + QByteArray::number(reinterpret_cast<qlonglong>(PyMethod_GET_SELF(callback)));
}
- return QByteArray::number(qlonglong(PyObject_Hash(callback)));
+ return QByteArray::number(static_cast<qlonglong>(PyObject_Hash(callback)));
}
PyObject *DynamicSlotDataV2::callback()
diff --git a/sources/pyside2/libpyside/pyside.cpp b/sources/pyside2/libpyside/pyside.cpp
index 219b99d4..7b01c5b8 100644
--- a/sources/pyside2/libpyside/pyside.cpp
+++ b/sources/pyside2/libpyside/pyside.cpp
@@ -58,7 +58,6 @@
#include <sbkconverter.h>
#include <sbkstring.h>
#include <sbkstaticstrings.h>
-#include <qapp_macro.h>
#include <QtCore/QByteArray>
#include <QtCore/QCoreApplication>
@@ -121,38 +120,36 @@ static bool _setProperty(PyObject *qObj, PyObject *name, PyObject *value, bool *
return true;
}
-bool fillQtProperties(PyObject *qObj, const QMetaObject *metaObj, PyObject *kwds, const char **blackList, unsigned int blackListSize)
+bool fillQtProperties(PyObject *qObj, const QMetaObject *metaObj, PyObject *kwds)
{
PyObject *key, *value;
Py_ssize_t pos = 0;
while (PyDict_Next(kwds, &pos, &key, &value)) {
- if (!blackListSize || !std::binary_search(blackList, blackList + blackListSize, std::string(Shiboken::String::toCString(key)))) {
- QByteArray propName(Shiboken::String::toCString(key));
- bool accept = false;
- if (metaObj->indexOfProperty(propName) != -1) {
- if (!_setProperty(qObj, key, value, &accept))
- return false;
- } else {
- propName.append("()");
- if (metaObj->indexOfSignal(propName) != -1) {
- accept = true;
- propName.prepend('2');
- if (!PySide::Signal::connect(qObj, propName, value))
- return false;
- }
- }
- if (!accept) {
- // PYSIDE-1019: Allow any existing attribute in the constructor.
- if (!_setProperty(qObj, key, value, &accept))
+ QByteArray propName(Shiboken::String::toCString(key));
+ bool accept = false;
+ if (metaObj->indexOfProperty(propName) != -1) {
+ if (!_setProperty(qObj, key, value, &accept))
+ return false;
+ } else {
+ propName.append("()");
+ if (metaObj->indexOfSignal(propName) != -1) {
+ accept = true;
+ propName.prepend('2');
+ if (!PySide::Signal::connect(qObj, propName, value))
return false;
}
- if (!accept) {
- PyErr_Format(PyExc_AttributeError, "'%s' is not a Qt property or a signal",
- propName.constData());
+ }
+ if (!accept) {
+ // PYSIDE-1019: Allow any existing attribute in the constructor.
+ if (!_setProperty(qObj, key, value, &accept))
return false;
- }
+ }
+ if (!accept) {
+ PyErr_Format(PyExc_AttributeError, "'%s' is not a Qt property or a signal",
+ propName.constData());
+ return false;
}
}
return true;
@@ -306,6 +303,9 @@ void initQApp()
*/
if (!qApp)
Py_DECREF(MakeQAppWrapper(nullptr));
+
+ // PYSIDE-1470: Register a function to destroy an application from shiboken.
+ setDestroyQApplication(destroyQCoreApplication);
}
PyObject *getMetaDataFromQObject(QObject *cppSelf, PyObject *self, PyObject *name)
@@ -412,7 +412,7 @@ static const char invalidatePropertyName[] = "_PySideInvalidatePtr";
// PYSIDE-1214, when creating new wrappers for classes inheriting QObject but
// not exposed to Python, try to find the best-matching (most-derived) Qt
// class by walking up the meta objects.
-static const char *typeName(QObject *cppSelf)
+static const char *typeName(const QObject *cppSelf)
{
const char *typeName = typeid(*cppSelf).name();
if (!Shiboken::Conversions::getConverter(typeName)) {
@@ -427,6 +427,20 @@ static const char *typeName(QObject *cppSelf)
return typeName;
}
+PyTypeObject *getTypeForQObject(const QObject *cppSelf)
+{
+ // First check if there are any instances of Python implementations
+ // inheriting a PySide class.
+ auto *existing = Shiboken::BindingManager::instance().retrieveWrapper(cppSelf);
+ if (existing != nullptr)
+ return reinterpret_cast<PyObject *>(existing)->ob_type;
+ // Find the best match (will return a PySide type)
+ auto *sbkObjectType = Shiboken::ObjectType::typeForTypeName(typeName(cppSelf));
+ if (sbkObjectType != nullptr)
+ return reinterpret_cast<PyTypeObject *>(sbkObjectType);
+ return nullptr;
+}
+
PyObject *getWrapperForQObject(QObject *cppSelf, SbkObjectType *sbk_type)
{
PyObject *pyOut = reinterpret_cast<PyObject *>(Shiboken::BindingManager::instance().retrieveWrapper(cppSelf));
diff --git a/sources/pyside2/libpyside/pyside.h b/sources/pyside2/libpyside/pyside.h
index c1a298cc..c72f37ae 100644
--- a/sources/pyside2/libpyside/pyside.h
+++ b/sources/pyside2/libpyside/pyside.h
@@ -71,12 +71,10 @@ inline Py_ssize_t hash(const T& value)
* Fill QObject properties and do signal connections using the values found in \p kwds dictonary.
* \param qObj PyObject fot the QObject.
* \param metaObj QMetaObject of \p qObj.
- * \param blackList keys to be ignored in kwds dictionary, this string list MUST be sorted.
- * \param blackListSize numbe rof elements in blackList.
* \param kwds key->value dictonary.
* \return True if everything goes well, false with a Python error setted otherwise.
*/
-PYSIDE_API bool fillQtProperties(PyObject *qObj, const QMetaObject *metaObj, PyObject *kwds, const char **blackList, unsigned int blackListSize);
+PYSIDE_API bool fillQtProperties(PyObject *qObj, const QMetaObject *metaObj, PyObject *kwds);
/**
* If the type \p T was registered on Qt meta type system with Q_DECLARE_METATYPE macro, this class will initialize
@@ -142,6 +140,11 @@ PYSIDE_API void setNextQObjectMemoryAddr(void *addr);
PYSIDE_API PyObject *getWrapperForQObject(QObject *cppSelf, SbkObjectType *sbk_type);
+/// Return the best-matching type for a QObject (Helper for QObject.findType())
+/// \param cppSelf QObject instance
+/// \return type object
+PYSIDE_API PyTypeObject *getTypeForQObject(const QObject *cppSelf);
+
#ifdef PYSIDE_QML_SUPPORT
// Used by QtQuick module to notify QtQml that custom QtQuick items can be registered.
typedef bool (*QuickRegisterItemFunction)(PyObject *pyObj, const char *uri, int versionMajor,
diff --git a/sources/pyside2/libpyside/pysideclassinfo.cpp b/sources/pyside2/libpyside/pysideclassinfo.cpp
index aa47f97c..098c391e 100644
--- a/sources/pyside2/libpyside/pysideclassinfo.cpp
+++ b/sources/pyside2/libpyside/pysideclassinfo.cpp
@@ -179,7 +179,7 @@ void classInfoFree(void *self)
namespace PySide { namespace ClassInfo {
static const char *ClassInfo_SignatureStrings[] = {
- "PySide2.QtCore.ClassInfo(**info:typing.Dict[str,str])",
+ "PySide2.QtCore.ClassInfo(self,**info:typing.Dict[str,str])",
nullptr}; // Sentinel
void init(PyObject *module)
diff --git a/sources/pyside2/libpyside/pysidemetafunction.cpp b/sources/pyside2/libpyside/pysidemetafunction.cpp
index afb3dbb1..63fed028 100644
--- a/sources/pyside2/libpyside/pysidemetafunction.cpp
+++ b/sources/pyside2/libpyside/pysidemetafunction.cpp
@@ -102,7 +102,7 @@ PyObject *functionCall(PyObject *self, PyObject *args, PyObject * /* kw */)
namespace PySide { namespace MetaFunction {
static const char *MetaFunction_SignatureStrings[] = {
- "PySide2.QtCore.MetaFunction.__call__(*args:typing.Any)->typing.Any",
+ "PySide2.QtCore.MetaFunction.__call__(self,*args:typing.Any)->typing.Any",
nullptr}; // Sentinel
void init(PyObject *module)
diff --git a/sources/pyside2/libpyside/pysideproperty.cpp b/sources/pyside2/libpyside/pysideproperty.cpp
index 97729d28..33b7c9c2 100644
--- a/sources/pyside2/libpyside/pysideproperty.cpp
+++ b/sources/pyside2/libpyside/pysideproperty.cpp
@@ -279,13 +279,13 @@ _property_copy(PyObject *old, PyObject *get, PyObject *set, PyObject *reset, PyO
Py_XDECREF(del);
del = pData->fdel ? pData->fdel : Py_None;
}
- if (pData->getter_doc && get != Py_None) {
- /* make _init use __doc__ from getter */
- doc = "";
- }
- else {
- doc = !pData->doc.isEmpty() ? pData->doc : "";
- }
+
+ // make _init use __doc__ from getter
+ if ((pData->getter_doc && get != Py_None) || pData->doc.isEmpty())
+ doc.clear();
+ else
+ doc = pData->doc;
+
auto notify = pData->notify ? pData->notify : Py_None;
PyObject *typeName = String::fromCString(pData->typeName);
diff --git a/sources/pyside2/libpyside/pysideqflags.cpp b/sources/pyside2/libpyside/pysideqflags.cpp
index b141ce15..8b224f2c 100644
--- a/sources/pyside2/libpyside/pysideqflags.cpp
+++ b/sources/pyside2/libpyside/pysideqflags.cpp
@@ -99,12 +99,17 @@ extern "C" {
return NULL;
}
- long valA = PYSIDE_QFLAGS(self)->ob_value;
- long valB = getNumberValue(other);
-
if (self == other) {
- result = 1;
+ switch (op) {
+ case Py_EQ:
+ case Py_LE:
+ case Py_GE:
+ result = 1;
+ break;
+ }
} else {
+ const long valA = PYSIDE_QFLAGS(self)->ob_value;
+ const long valB = getNumberValue(other);
switch (op) {
case Py_EQ:
result = (valA == valB);
diff --git a/sources/pyside2/libpyside/pysidesignal.cpp b/sources/pyside2/libpyside/pysidesignal.cpp
index 5c030316..b5069a00 100644
--- a/sources/pyside2/libpyside/pysidesignal.cpp
+++ b/sources/pyside2/libpyside/pysidesignal.cpp
@@ -624,17 +624,17 @@ namespace PySide {
namespace Signal {
static const char *MetaSignal_SignatureStrings[] = {
- "PySide2.QtCore.MetaSignal.__instancecheck__(object:object)->bool",
+ "PySide2.QtCore.MetaSignal.__instancecheck__(self,object:object)->bool",
nullptr}; // Sentinel
static const char *Signal_SignatureStrings[] = {
- "PySide2.QtCore.Signal(*types:type,name:str=nullptr,arguments:str=nullptr)",
+ "PySide2.QtCore.Signal(self,*types:type,name:str=nullptr,arguments:str=nullptr)",
nullptr}; // Sentinel
static const char *SignalInstance_SignatureStrings[] = {
- "PySide2.QtCore.SignalInstance.connect(slot:object,type:type=nullptr)",
- "PySide2.QtCore.SignalInstance.disconnect(slot:object=nullptr)",
- "PySide2.QtCore.SignalInstance.emit(*args:typing.Any)",
+ "PySide2.QtCore.SignalInstance.connect(self,slot:object,type:type=nullptr)",
+ "PySide2.QtCore.SignalInstance.disconnect(self,slot:object=nullptr)",
+ "PySide2.QtCore.SignalInstance.emit(self,*args:typing.Any)",
nullptr}; // Sentinel
void init(PyObject *module)
diff --git a/sources/pyside2/libpyside/pysideslot.cpp b/sources/pyside2/libpyside/pysideslot.cpp
index 1ec24ab2..7911b21d 100644
--- a/sources/pyside2/libpyside/pysideslot.cpp
+++ b/sources/pyside2/libpyside/pysideslot.cpp
@@ -183,7 +183,7 @@ namespace PySide {
namespace Slot {
static const char *Slot_SignatureStrings[] = {
- "PySide2.QtCore.Slot(*types:type,name:str=nullptr,result:str=nullptr)->typing.Callable[...,typing.Optional[str]]",
+ "PySide2.QtCore.Slot(self,*types:type,name:str=nullptr,result:str=nullptr)->typing.Callable[...,typing.Optional[str]]",
nullptr}; // Sentinel
void init(PyObject *module)
diff --git a/sources/pyside2/libpyside/pysidestaticstrings.cpp b/sources/pyside2/libpyside/pysidestaticstrings.cpp
index 760d7763..2dab2caa 100644
--- a/sources/pyside2/libpyside/pysidestaticstrings.cpp
+++ b/sources/pyside2/libpyside/pysidestaticstrings.cpp
@@ -60,4 +60,10 @@ STATIC_STRING_IMPL(name, "name")
STATIC_STRING_IMPL(property, "property")
STATIC_STRING_IMPL(select_id, "select_id")
} // namespace PyName
+namespace PyMagicName
+{
+STATIC_STRING_IMPL(doc, "__doc__")
+STATIC_STRING_IMPL(name, "__name__")
+STATIC_STRING_IMPL(property_methods, "__property_methods__")
+} // namespace PyMagicName
} // namespace PySide
diff --git a/sources/pyside2/libpyside/pysidestaticstrings.h b/sources/pyside2/libpyside/pysidestaticstrings.h
index 1222d8f4..54d1ab9c 100644
--- a/sources/pyside2/libpyside/pysidestaticstrings.h
+++ b/sources/pyside2/libpyside/pysidestaticstrings.h
@@ -55,6 +55,12 @@ PyObject *name();
PyObject *property();
PyObject *select_id();
} // namespace PyName
+namespace PyMagicName
+{
+PyObject *doc();
+PyObject *name();
+PyObject *property_methods();
+} // namespace PyMagicName
} // namespace PySide
#endif // PYSIDESTRINGS_H
diff --git a/sources/pyside2/pyside_version.py b/sources/pyside2/pyside_version.py
index 009db0bf..9ec9b0e7 100644
--- a/sources/pyside2/pyside_version.py
+++ b/sources/pyside2/pyside_version.py
@@ -39,7 +39,7 @@
major_version = "5"
minor_version = "15"
-patch_version = "2"
+patch_version = "7"
# For example: "a", "b", "rc"
# (which means "alpha", "beta", "release candidate").
diff --git a/sources/pyside2/tests/QtCore/CMakeLists.txt b/sources/pyside2/tests/QtCore/CMakeLists.txt
index 9d268e07..c7e50d64 100644
--- a/sources/pyside2/tests/QtCore/CMakeLists.txt
+++ b/sources/pyside2/tests/QtCore/CMakeLists.txt
@@ -37,6 +37,7 @@ PYSIDE_TEST(deletelater_test.py)
PYSIDE_TEST(destroysignal_test.py)
PYSIDE_TEST(duck_punching_test.py)
PYSIDE_TEST(emoji_string_test.py)
+PYSIDE_TEST(feature_with_uic_test.py)
PYSIDE_TEST(hash_test.py)
PYSIDE_TEST(inherits_test.py)
PYSIDE_TEST(max_signals.py)
diff --git a/sources/pyside2/tests/QtCore/bug_686.py b/sources/pyside2/tests/QtCore/bug_686.py
index 6e4f8994..d944cafe 100644
--- a/sources/pyside2/tests/QtCore/bug_686.py
+++ b/sources/pyside2/tests/QtCore/bug_686.py
@@ -49,6 +49,7 @@ class MyWriteThread(QThread):
self.started = True
while not self.lock.tryLockForWrite():
pass
+ self.lock.unlock()
self.canQuit = True
class MyReadThread(QThread):
@@ -62,6 +63,7 @@ class MyReadThread(QThread):
self.started = True
while not self.lock.tryLockForRead():
pass
+ self.lock.unlock()
self.canQuit = True
class MyMutexedThread(QThread):
diff --git a/sources/pyside2/tests/pysidetest/enum_test.py b/sources/pyside2/tests/QtCore/feature_with_uic/__init__.py
similarity index 65%
copy from sources/pyside2/tests/pysidetest/enum_test.py
copy to sources/pyside2/tests/QtCore/feature_with_uic/__init__.py
index d179d624..396f82fb 100644
--- a/sources/pyside2/tests/pysidetest/enum_test.py
+++ b/sources/pyside2/tests/QtCore/feature_with_uic/__init__.py
@@ -1,8 +1,6 @@
-# -*- coding: utf-8 -*-
-
#############################################################################
##
-## Copyright (C) 2016 The Qt Company Ltd.
+## Copyright (C) 2020 The Qt Company Ltd.
## Contact: https://www.qt.io/licensing/
##
## This file is part of the test suite of Qt for Python.
@@ -28,24 +26,4 @@
##
#############################################################################
-import os
-import sys
-import unittest
-
-sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
-from init_paths import init_test_paths
-init_test_paths(True)
-
-from testbinding import Enum1, TestObjectWithoutNamespace
-
-class ListConnectionTest(unittest.TestCase):
-
- def testEnumVisibility(self):
- self.assertEqual(Enum1.Option1, 1)
- self.assertEqual(Enum1.Option2, 2)
- self.assertEqual(TestObjectWithoutNamespace.Enum2.Option3, 3)
- self.assertEqual(TestObjectWithoutNamespace.Enum2.Option4, 4)
-
-if __name__ == '__main__':
- unittest.main()
-
+# this file intentionally left blank
diff --git a/sources/pyside2/tests/QtCore/feature_with_uic/window.py b/sources/pyside2/tests/QtCore/feature_with_uic/window.py
new file mode 100644
index 00000000..db0fbd03
--- /dev/null
+++ b/sources/pyside2/tests/QtCore/feature_with_uic/window.py
@@ -0,0 +1,81 @@
+# -*- coding: utf-8 -*-
+#############################################################################
+##
+## Copyright (C) 2021 The Qt Company Ltd.
+## Contact: https://www.qt.io/licensing/
+##
+## This file is part of the test suite of Qt for Python.
+##
+## $QT_BEGIN_LICENSE:GPL-EXCEPT$
+## Commercial License Usage
+## Licensees holding valid commercial Qt licenses may use this file in
+## accordance with the commercial license agreement provided with the
+## Software or, alternatively, in accordance with the terms contained in
+## a written agreement between you and The Qt Company. For licensing terms
+## and conditions see https://www.qt.io/terms-conditions. For further
+## information use the contact form at https://www.qt.io/contact-us.
+##
+## GNU General Public License Usage
+## Alternatively, this file may be used under the terms of the GNU
+## General Public License version 3 as published by the Free Software
+## Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+## included in the packaging of this file. Please review the following
+## information to ensure the GNU General Public License requirements will
+## be met: https://www.gnu.org/licenses/gpl-3.0.html.
+##
+## $QT_END_LICENSE$
+##
+#############################################################################
+
+################################################################################
+## Form generated from reading UI file 'window.ui'
+##
+## Created by: Qt User Interface Compiler version 5.15.2
+##
+## WARNING! All changes made in this file will be lost when recompiling UI file!
+################################################################################
+
+from PySide2.QtCore import *
+from PySide2.QtGui import *
+from PySide2.QtWidgets import *
+
+
+class Ui_MainWindow(object):
+ def setupUi(self, MainWindow):
+ if not MainWindow.objectName():
+ MainWindow.setObjectName(u"MainWindow")
+ MainWindow.resize(263, 196)
+ self.centralwidget = QWidget(MainWindow)
+ self.centralwidget.setObjectName(u"centralwidget")
+ self.horizontalLayout = QHBoxLayout(self.centralwidget)
+ self.horizontalLayout.setObjectName(u"horizontalLayout")
+ self.verticalLayout = QVBoxLayout()
+ self.verticalLayout.setObjectName(u"verticalLayout")
+ self.pushButton = QPushButton(self.centralwidget)
+ self.pushButton.setObjectName(u"pushButton")
+
+ self.verticalLayout.addWidget(self.pushButton)
+
+
+ self.horizontalLayout.addLayout(self.verticalLayout)
+
+ MainWindow.setCentralWidget(self.centralwidget)
+ self.menubar = QMenuBar(MainWindow)
+ self.menubar.setObjectName(u"menubar")
+ self.menubar.setGeometry(QRect(0, 0, 263, 23))
+ MainWindow.setMenuBar(self.menubar)
+ self.statusbar = QStatusBar(MainWindow)
+ self.statusbar.setObjectName(u"statusbar")
+ MainWindow.setStatusBar(self.statusbar)
+
+ self.retranslateUi(MainWindow)
+ self.pushButton.clicked.connect(MainWindow.close)
+
+ QMetaObject.connectSlotsByName(MainWindow)
+ # setupUi
+
+ def retranslateUi(self, MainWindow):
+ MainWindow.setWindowTitle(QCoreApplication.translate("MainWindow", u"MainWindow", None))
+ self.pushButton.setText(QCoreApplication.translate("MainWindow", u"PushButton", None))
+ # retranslateUi
+
diff --git a/sources/pyside2/tests/QtCore/feature_with_uic/window.ui b/sources/pyside2/tests/QtCore/feature_with_uic/window.ui
new file mode 100644
index 00000000..0b85824e
--- /dev/null
+++ b/sources/pyside2/tests/QtCore/feature_with_uic/window.ui
@@ -0,0 +1,62 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>MainWindow</class>
+ <widget class="QMainWindow" name="MainWindow">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>263</width>
+ <height>196</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>MainWindow</string>
+ </property>
+ <widget class="QWidget" name="centralwidget">
+ <layout class="QHBoxLayout" name="horizontalLayout">
+ <item>
+ <layout class="QVBoxLayout" name="verticalLayout">
+ <item>
+ <widget class="QPushButton" name="pushButton">
+ <property name="text">
+ <string>PushButton</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ <widget class="QMenuBar" name="menubar">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>263</width>
+ <height>23</height>
+ </rect>
+ </property>
+ </widget>
+ <widget class="QStatusBar" name="statusbar"/>
+ </widget>
+ <resources/>
+ <connections>
+ <connection>
+ <sender>pushButton</sender>
+ <signal>clicked()</signal>
+ <receiver>MainWindow</receiver>
+ <slot>close()</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>131</x>
+ <y>97</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>131</x>
+ <y>97</y>
+ </hint>
+ </hints>
+ </connection>
+ </connections>
+</ui>
diff --git a/sources/pyside2/tests/QtGui/qdatastream_gui_operators_test.py b/sources/pyside2/tests/QtCore/feature_with_uic_test.py
similarity index 59%
copy from sources/pyside2/tests/QtGui/qdatastream_gui_operators_test.py
copy to sources/pyside2/tests/QtCore/feature_with_uic_test.py
index c9b5c16a..64a620be 100644
--- a/sources/pyside2/tests/QtGui/qdatastream_gui_operators_test.py
+++ b/sources/pyside2/tests/QtCore/feature_with_uic_test.py
@@ -1,8 +1,6 @@
-# -*- coding: utf-8 -*-
-
#############################################################################
##
-## Copyright (C) 2016 The Qt Company Ltd.
+## Copyright (C) 2021 The Qt Company Ltd.
## Contact: https://www.qt.io/licensing/
##
## This file is part of the test suite of Qt for Python.
@@ -28,6 +26,16 @@
##
#############################################################################
+"""
+feature_with_uic_test.py
+------------------------
+
+Check if feature switching works with a normal UIC file.
+This crashed due to callbacks into QApplication.
+
+PYSIDE-1626: Switch early in `BindingManager::getOverride`.
+"""
+
import os
import sys
import unittest
@@ -36,33 +44,33 @@ sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
from init_paths import init_test_paths
init_test_paths(False)
-from PySide2.QtCore import QDataStream, QByteArray, QIODevice, Qt
-from PySide2.QtGui import QPixmap, QColor
-
from helper.usesqapplication import UsesQApplication
-class QPixmapQDatastream(UsesQApplication):
- '''QDataStream <<>> QPixmap'''
+from PySide2.QtCore import QCoreApplication, QLibraryInfo, qVersion
+from PySide2.QtWidgets import QApplication, QMainWindow
+
+if sys.version_info[0] >= 3:
+ from __feature__ import snake_case
+
+from feature_with_uic.window import Ui_MainWindow
+
+
+class MainWindow(QMainWindow, Ui_MainWindow):
- def setUp(self):
- super(QPixmapQDatastream, self).setUp()
- self.source_pixmap = QPixmap(100, 100)
- self.source_pixmap.fill(Qt.red)
- self.output_pixmap = QPixmap()
- self.buffer = QByteArray()
- self.read_stream = QDataStream(self.buffer, QIODevice.ReadOnly)
- self.write_stream = QDataStream(self.buffer, QIODevice.WriteOnly)
+ def __init__(self):
+ super().__init__()
+ self.setupUi(self)
- def testStream(self):
- self.write_stream << self.source_pixmap
- self.read_stream >> self.output_pixmap
+class FeatureTest(UsesQApplication):
- image = self.output_pixmap.toImage()
- pixel = image.pixel(10,10)
- self.assertEqual(pixel, QColor(Qt.red).rgba())
- self.assertEqual(self.source_pixmap.toImage(), self.output_pixmap.toImage())
+ def testFeaturesWorkWithUIC(self):
+ window = MainWindow()
+ window.set_window_title(qVersion())
+ window.show()
+ while not window.window_handle().is_exposed():
+ QCoreApplication.process_events()
-if __name__ == '__main__':
+if __name__ == '__main__' and sys.version_info[0] >= 3:
unittest.main()
diff --git a/sources/pyside2/tests/QtCore/qflags_test.py b/sources/pyside2/tests/QtCore/qflags_test.py
index 08a7c55b..e1e989c1 100644
--- a/sources/pyside2/tests/QtCore/qflags_test.py
+++ b/sources/pyside2/tests/QtCore/qflags_test.py
@@ -30,6 +30,7 @@
'''Test cases for QFlags'''
+import operator
import os
import sys
import unittest
@@ -117,12 +118,13 @@ class QFlagsOnQVariant(unittest.TestCase):
class QFlagsWrongType(unittest.TestCase):
def testWrongType(self):
'''Wrong type passed to QFlags binary operators'''
+ for op in operator.or_, operator.and_, operator.xor:
+ for x in '43', 'jabba', QObject, object:
+ self.assertRaises(TypeError, op, Qt.NoItemFlags, x)
+ self.assertRaises(TypeError, op, x, Qt.NoItemFlags)
+ # making sure this actually does not fail all the time
+ self.assertEqual(operator.or_(Qt.NoItemFlags, 43), 43)
- self.assertRaises(TypeError, Qt.NoItemFlags | '43')
- self.assertRaises(TypeError, Qt.NoItemFlags & '43')
- self.assertRaises(TypeError, 'jabba' & Qt.NoItemFlags)
- self.assertRaises(TypeError, 'hut' & Qt.NoItemFlags)
- self.assertRaises(TypeError, Qt.NoItemFlags & QObject())
if __name__ == '__main__':
unittest.main()
diff --git a/sources/pyside2/tests/QtCore/qobject_parent_test.py b/sources/pyside2/tests/QtCore/qobject_parent_test.py
index 0a02fbc2..becc7c48 100644
--- a/sources/pyside2/tests/QtCore/qobject_parent_test.py
+++ b/sources/pyside2/tests/QtCore/qobject_parent_test.py
@@ -39,6 +39,16 @@ init_test_paths(False)
from PySide2.QtCore import *
+class TestObject1(QTimer):
+ def __init(self, parent):
+ super().__init__(parent)
+
+
+class TestObject2(TestObject1):
+ def __init(self, parent):
+ super().__init__(parent)
+
+
class ParentRefCountCase(unittest.TestCase):
'''Test case for the refcount changes of setParent'''
@@ -158,6 +168,26 @@ class ParentCase(unittest.TestCase):
child = QObject(parent)
self.assertEqual(parent, child.parent())
+ def testFindChildByType(self):
+ parent = QObject()
+ expected = TestObject2(parent)
+ actual = parent.findChild(TestObject2)
+ self.assertEqual(actual, expected)
+ actual = parent.findChild(TestObject1)
+ self.assertEqual(actual, expected)
+ actual = parent.findChild(QTimer)
+ self.assertEqual(actual, expected)
+
+ def testFindChildrenByType(self):
+ parent = QObject()
+ expected = [TestObject2(parent)]
+ actual = parent.findChildren(TestObject2)
+ self.assertEqual(actual, expected)
+ actual = parent.findChildren(TestObject1)
+ self.assertEqual(actual, expected)
+ actual = parent.findChildren(QTimer)
+ self.assertEqual(actual, expected)
+
class TestParentOwnership(unittest.TestCase):
'''Test case for Parent/Child object ownership'''
diff --git a/sources/pyside2/tests/QtCore/qsettings_test.py b/sources/pyside2/tests/QtCore/qsettings_test.py
index 639f6d27..d7e20373 100644
--- a/sources/pyside2/tests/QtCore/qsettings_test.py
+++ b/sources/pyside2/tests/QtCore/qsettings_test.py
@@ -38,7 +38,7 @@ init_test_paths(False)
from helper.helper import adjust_filename
import py3kcompat as py3k
-from PySide2.QtCore import QSettings
+from PySide2.QtCore import QDir, QSettings, QTemporaryDir, QByteArray
class TestQSettings(unittest.TestCase):
def testConversions(self):
@@ -57,9 +57,27 @@ class TestQSettings(unittest.TestCase):
r = settings.value('var2', type=list)
self.assertEqual(type(r), list)
+ # Test mixed conversions
+ if py3k.IS_PY3K:
+ ba = QByteArray("hello".encode("utf-8"))
+
+ r = settings.value("test", ba, type=QByteArray)
+ self.assertEqual(type(r), QByteArray)
+
+ r = settings.value("test", ba, type=str)
+ self.assertEqual(type(r), str)
+
+ # Test invalid conversions
+ with self.assertRaises(TypeError):
+ r = settings.value("test", ba, type=dict)
+
def testDefaultValueConversion(self):
- settings = QSettings('foo.ini', QSettings.IniFormat)
+ temp_dir = QDir.tempPath()
+ dir = QTemporaryDir('{}/qsettings_XXXXXX'.format(temp_dir))
+ self.assertTrue(dir.isValid())
+ file_name = dir.filePath('foo.ini')
+ settings = QSettings(file_name, QSettings.IniFormat)
settings.setValue('zero_value', 0)
settings.setValue('empty_list', [])
settings.setValue('bool1', False)
@@ -67,7 +85,7 @@ class TestQSettings(unittest.TestCase):
del settings
# Loading values already set
- settings = QSettings('foo.ini', QSettings.IniFormat)
+ settings = QSettings(file_name, QSettings.IniFormat)
# Getting value that doesn't exist
r = settings.value("variable")
diff --git a/sources/pyside2/tests/QtCore/snake_prop_feature_test.py b/sources/pyside2/tests/QtCore/snake_prop_feature_test.py
index 779b8a40..aea6a22a 100644
--- a/sources/pyside2/tests/QtCore/snake_prop_feature_test.py
+++ b/sources/pyside2/tests/QtCore/snake_prop_feature_test.py
@@ -88,6 +88,8 @@ class FeatureTest(unittest.TestCase):
window.modal
from __feature__ import snake_case, true_property
+ #PYSIDE-1548: Make sure that another import does not clear the features.
+ import sys
self.assertTrue(isinstance(QtWidgets.QWidget.modal, property))
self.assertTrue(isinstance(window.modal, bool))
diff --git a/sources/pyside2/tests/QtCore/translation_test.py b/sources/pyside2/tests/QtCore/translation_test.py
index 0f36067b..b2e674aa 100644
--- a/sources/pyside2/tests/QtCore/translation_test.py
+++ b/sources/pyside2/tests/QtCore/translation_test.py
@@ -59,6 +59,19 @@ class TranslationTest(UsesQCoreApplication):
obj = QObject()
obj.setObjectName(obj.tr('Hello World!'))
+ self.assertEqual(obj.objectName(), 'Orbis, te saluto!')
+
+ def testLatinDerived(self):
+ # PYSIDE-131: Test that derived classes work, too.
+ translator = QTranslator()
+ translator.load(os.path.join(self.trdir, 'trans_latin.qm'))
+ self.app.installTranslator(translator)
+
+ class Derived(QObject):
+ pass
+
+ obj = Derived()
+ obj.setObjectName(obj.tr('Hello World!'))
self.assertEqual(obj.objectName(), py3k.unicode_('Orbis, te saluto!'))
def testRussian(self):
diff --git a/sources/pyside2/tests/QtDataVisualization/datavisualization_test.py b/sources/pyside2/tests/QtDataVisualization/datavisualization_test.py
index af6e5f5d..32fd432e 100644
--- a/sources/pyside2/tests/QtDataVisualization/datavisualization_test.py
+++ b/sources/pyside2/tests/QtDataVisualization/datavisualization_test.py
@@ -88,5 +88,18 @@ class QtDataVisualizationTestCase(UsesQGuiApplication):
QTimer.singleShot(500, self.app.quit)
self.app.exec_()
+ def testBarDataProxy(self):
+ '''PSYSIDE-1438, crashes in QBarDataProxy.addRow()'''
+ items = [QtDataVisualization.QBarDataItem(v) for v in [1.0, 2.0]]
+ data_proxy = QtDataVisualization.QBarDataProxy()
+ data_proxy.addRow(items)
+ data_proxy.addRow(items, 'bla')
+ data_proxy.insertRow(0, items)
+ data_proxy.insertRow(0, items, 'bla')
+ data_proxy.setRow(0, items)
+ data_proxy.setRow(0, items, 'bla')
+ self.assertTrue(data_proxy.rowCount(), 4)
+
+
if __name__ == '__main__':
unittest.main()
diff --git a/sources/pyside2/tests/QtGui/qdatastream_gui_operators_test.py b/sources/pyside2/tests/QtGui/qdatastream_gui_operators_test.py
index c9b5c16a..4db0a0a6 100644
--- a/sources/pyside2/tests/QtGui/qdatastream_gui_operators_test.py
+++ b/sources/pyside2/tests/QtGui/qdatastream_gui_operators_test.py
@@ -47,7 +47,9 @@ class QPixmapQDatastream(UsesQApplication):
def setUp(self):
super(QPixmapQDatastream, self).setUp()
self.source_pixmap = QPixmap(100, 100)
- self.source_pixmap.fill(Qt.red)
+ # PYSIDE-1533: Use Qt.transparent to force Format_ARGB32_Premultiplied
+ # when converting to QImage in any case.
+ self.source_pixmap.fill(Qt.transparent)
self.output_pixmap = QPixmap()
self.buffer = QByteArray()
self.read_stream = QDataStream(self.buffer, QIODevice.ReadOnly)
@@ -60,8 +62,8 @@ class QPixmapQDatastream(UsesQApplication):
image = self.output_pixmap.toImage()
pixel = image.pixel(10,10)
- self.assertEqual(pixel, QColor(Qt.red).rgba())
- self.assertEqual(self.source_pixmap.toImage(), self.output_pixmap.toImage())
+ self.assertEqual(pixel, QColor(Qt.transparent).rgba())
+ self.assertEqual(self.source_pixmap.toImage(), image)
if __name__ == '__main__':
diff --git a/sources/pyside2/tests/QtGui/qrasterwindow_test.py b/sources/pyside2/tests/QtGui/qrasterwindow_test.py
index f18ceaaf..1776e5ef 100644
--- a/sources/pyside2/tests/QtGui/qrasterwindow_test.py
+++ b/sources/pyside2/tests/QtGui/qrasterwindow_test.py
@@ -40,27 +40,6 @@ from helper.usesqapplication import UsesQApplication
from PySide2.QtCore import QEvent, QPoint, QRect, QSize, QTimer, Qt
from PySide2.QtGui import QColor, QBackingStore, QPaintDevice, QPainter, QWindow, QPaintDeviceWindow, QRasterWindow, QRegion, QStaticText
-# QWindow rendering via QBackingStore
-class TestBackingStoreWindow(QWindow):
- def __init__(self):
- super(TestBackingStoreWindow, self).__init__()
- self.backingStore = QBackingStore(self)
- self.text = QStaticText("BackingStoreWindow")
-
- def event(self, event):
- if event.type() == QEvent.Resize:
- self.backingStore.resize(self.size())
- self.render()
- elif event.type() == QEvent.UpdateRequest or event.type() == QEvent.Expose:
- self.backingStore.flush(QRegion(QRect(QPoint(0, 0), self.size())))
-
- return QWindow.event(self, event)
-
- def render(self):
- clientRect = QRect(QPoint(0, 0), self.size())
- painter = QPainter(self.backingStore.paintDevice())
- painter.fillRect(clientRect, QColor(Qt.green))
- painter.drawStaticText(QPoint(10, 10), self.text)
# Window using convenience class QRasterWindow
class TestRasterWindow(QRasterWindow):
@@ -74,19 +53,16 @@ class TestRasterWindow(QRasterWindow):
painter.fillRect(clientRect, QColor(Qt.red))
painter.drawStaticText(QPoint(10, 10), self.text)
+
class QRasterWindowTest(UsesQApplication):
def test(self):
rasterWindow = TestRasterWindow()
rasterWindow.setFramePosition(QPoint(100, 100))
rasterWindow.resize(QSize(400, 400))
rasterWindow.show()
- backingStoreWindow = TestBackingStoreWindow()
- backingStoreWindow.setFramePosition(QPoint(600, 100))
- backingStoreWindow.resize(QSize(400, 400))
- backingStoreWindow.show()
-
QTimer.singleShot(100, self.app.quit)
self.app.exec_()
+
if __name__ == '__main__':
unittest.main()
diff --git a/sources/pyside2/tests/QtWidgets/signature_test.py b/sources/pyside2/tests/QtWidgets/signature_test.py
index 57fcf387..cacb576d 100644
--- a/sources/pyside2/tests/QtWidgets/signature_test.py
+++ b/sources/pyside2/tests/QtWidgets/signature_test.py
@@ -65,8 +65,9 @@ class PySideSignatureTest(unittest.TestCase):
for thing in obj.__signature__:
self.assertEqual(type(thing), inspect.Signature)
sm = PySide2.QtWidgets.QApplication.__dict__["palette"]
- self.assertFalse(callable(sm))
- self.assertEqual(sm.__func__, obj)
+ # PYSIDE-1436: staticmethod is a callable since Python 3.10
+ # Instead of checking callable(sm), we check the type:
+ self.assertEqual(type(sm), staticmethod)
self.assertTrue(hasattr(sm, "__signature__") and
sm.__signature__ is not None)
diff --git a/sources/pyside2/tests/pysidetest/constructor_properties_test.py b/sources/pyside2/tests/pysidetest/constructor_properties_test.py
index 139091fe..5d102704 100644
--- a/sources/pyside2/tests/pysidetest/constructor_properties_test.py
+++ b/sources/pyside2/tests/pysidetest/constructor_properties_test.py
@@ -47,11 +47,13 @@ init_test_paths(False)
from helper.usesqapplication import UsesQApplication
from PySide2.QtCore import Qt
-from PySide2.QtWidgets import QApplication, QLabel, QFrame
+from PySide2.QtGui import QColor
+from PySide2.QtWidgets import QAction, QApplication, QFrame, QLabel
class ConstructorPropertiesTest(UsesQApplication):
+ # PYSIDE-1019: First property extension was support by the constructor.
def testCallConstructor(self):
label = QLabel(
frameStyle=QFrame.Panel | QFrame.Sunken,
@@ -65,6 +67,34 @@ class ConstructorPropertiesTest(UsesQApplication):
))
+class DiverseKeywordsTest(UsesQApplication):
+
+ def testDuplicateKeyword(self):
+ r, g, b, a = 1, 2, 3, 4
+ with self.assertRaises(TypeError) as cm:
+ QColor(r, g, b, a, a=0)
+ self.assertTrue("multiple" in cm.exception.args[0])
+
+ # PYSIDE-1305: Handle keyword args correctly.
+ def testUndefinedKeyword(self):
+ r, g, b, a = 1, 2, 3, 4
+ # From the jira issue:
+ with self.assertRaises(AttributeError) as cm:
+ QColor(r, g, b, a, alpha=0)
+ self.assertTrue("unsupported" in cm.exception.args[0])
+
+ # PYSIDE-1305: Handle keyword args correctly.
+ def testUndefinedConstructorKeyword(self):
+ # make sure that the given attribute lands in the constructor
+ x = QAction(autoRepeat=False)
+ self.assertEqual(x.autoRepeat(), False)
+ x = QAction(autoRepeat=True)
+ self.assertEqual(x.autoRepeat(), True)
+ # QAction derives from QObject, and so the missing attributes
+ # in the constructor are reported as AttributeError.
+ with self.assertRaises(AttributeError):
+ QAction(some_other_name=42)
+
+
if __name__ == '__main__':
unittest.main()
-
diff --git a/sources/pyside2/tests/pysidetest/embedding_test.py b/sources/pyside2/tests/pysidetest/embedding_test.py
index 1960838f..57068692 100644
--- a/sources/pyside2/tests/pysidetest/embedding_test.py
+++ b/sources/pyside2/tests/pysidetest/embedding_test.py
@@ -65,16 +65,15 @@ class EmbeddingTest(unittest.TestCase):
# Unfortunately, I see no way how to shut things enough down
# to trigger a second initiatization. Therefore, only one test :-/
def test_pyside_embedding(self):
- import sys, os
+ import sys
self.assertFalse(hasattr(sys, "pyside_uses_embedding"))
sys.pyside_uses_embedding = "anything true"
import PySide2
# everything has to be imported
self.assertTrue("PySide2.support.signature" in sys.modules)
self.assertEqual(sys.pyside_uses_embedding, True)
- dn = os.path.dirname
- name = os.path.basename(dn(dn(dn(PySide2.support.signature.__file__))))
- self.assertTrue(name.startswith("embedded.") and name.endswith(".zip"))
+ # We no longer use a physical zip file.
+
if __name__ == '__main__':
unittest.main()
diff --git a/sources/pyside2/tests/pysidetest/enum_test.py b/sources/pyside2/tests/pysidetest/enum_test.py
index d179d624..a9396383 100644
--- a/sources/pyside2/tests/pysidetest/enum_test.py
+++ b/sources/pyside2/tests/pysidetest/enum_test.py
@@ -36,6 +36,7 @@ sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
from init_paths import init_test_paths
init_test_paths(True)
+from PySide2.QtCore import Qt
from testbinding import Enum1, TestObjectWithoutNamespace
class ListConnectionTest(unittest.TestCase):
@@ -46,6 +47,29 @@ class ListConnectionTest(unittest.TestCase):
self.assertEqual(TestObjectWithoutNamespace.Enum2.Option3, 3)
self.assertEqual(TestObjectWithoutNamespace.Enum2.Option4, 4)
+ def testFlagComparisonOperators(self): # PYSIDE-1696, compare to self
+ f1 = Qt.AlignHCenter | Qt.AlignBottom
+ f2 = Qt.AlignHCenter | Qt.AlignBottom
+ self.assertTrue(f1 == f1)
+ self.assertTrue(f1 <= f1)
+ self.assertTrue(f1 >= f1)
+ self.assertFalse(f1 != f1)
+ self.assertFalse(f1 < f1)
+ self.assertFalse(f1 > f1)
+
+ self.assertTrue(f1 == f2)
+ self.assertTrue(f1 <= f2)
+ self.assertTrue(f1 >= f2)
+ self.assertFalse(f1 != f2)
+ self.assertFalse(f1 < f2)
+ self.assertFalse(f1 > f2)
+
+ self.assertTrue(Qt.AlignHCenter < Qt.AlignBottom)
+ self.assertFalse(Qt.AlignHCenter > Qt.AlignBottom)
+ self.assertFalse(Qt.AlignBottom < Qt.AlignHCenter)
+ self.assertTrue(Qt.AlignBottom > Qt.AlignHCenter)
+
+
if __name__ == '__main__':
unittest.main()
diff --git a/sources/shiboken2/ApiExtractor/abstractmetabuilder.cpp b/sources/shiboken2/ApiExtractor/abstractmetabuilder.cpp
index d59147d5..d7ae45ae 100644
--- a/sources/shiboken2/ApiExtractor/abstractmetabuilder.cpp
+++ b/sources/shiboken2/ApiExtractor/abstractmetabuilder.cpp
@@ -575,7 +575,8 @@ void AbstractMetaBuilderPrivate::traverseDom(const FileModelItem &dom)
} else if (entry->isEnum() && entry->generateCode()) {
auto enumEntry = static_cast<const EnumTypeEntry *>(entry);
const QString name = enumEntry->targetLangQualifier();
- AbstractMetaClass *cls = AbstractMetaClass::findClass(m_metaClasses, name);
+ AbstractMetaClass *cls = AbstractMetaClass::findClass(m_metaClasses,
+ enumEntry->parent());
const bool enumFound = cls
? cls->findEnum(entry->targetLangEntryName()) != nullptr
@@ -1471,12 +1472,13 @@ bool AbstractMetaBuilderPrivate::setupInheritance(AbstractMetaClass *metaClass)
for (const auto &baseClassName : baseClasses) {
if (!types->isClassRejected(baseClassName)) {
- if (!types->findType(baseClassName)) {
+ auto typeEntry = types->findType(baseClassName);
+ if (typeEntry == nullptr || !typeEntry->isComplex()) {
qCWarning(lcShiboken, "%s",
qPrintable(msgUnknownBase(metaClass, baseClassName)));
return false;
}
- auto baseClass = AbstractMetaClass::findClass(m_metaClasses, baseClassName);
+ auto baseClass = AbstractMetaClass::findClass(m_metaClasses, typeEntry);
if (!baseClass) {
qCWarning(lcShiboken).noquote().nospace()
<< QStringLiteral("class not found for setup inheritance '%1'").arg(baseClassName);
@@ -2448,7 +2450,7 @@ QString AbstractMetaBuilderPrivate::fixDefaultValue(const ArgumentModelItem &ite
int /* argumentIndex */)
{
QString expr = item->defaultValueExpression();
- if (expr.isEmpty())
+ if (expr.isEmpty() || expr == u"{}")
return expr;
if (type) {
@@ -3086,8 +3088,11 @@ AbstractMetaClassList AbstractMetaBuilderPrivate::classesTopologicalSorted(const
// Member fields need to be initialized
const AbstractMetaFieldList &fields = clazz->fields();
for (AbstractMetaField *field : fields) {
- addClassDependency(field->type()->typeEntry(), clazz, classIndex,
- map, &graph);
+ auto typeEntry = field->type()->typeEntry();
+ if (typeEntry->isEnum()) // Enum defined in class?
+ typeEntry = typeEntry->parent();
+ if (typeEntry != nullptr)
+ addClassDependency(typeEntry, clazz, classIndex, map, &graph);
}
}
diff --git a/sources/shiboken2/ApiExtractor/abstractmetalang.cpp b/sources/shiboken2/ApiExtractor/abstractmetalang.cpp
index 3bdac909..723a1316 100644
--- a/sources/shiboken2/ApiExtractor/abstractmetalang.cpp
+++ b/sources/shiboken2/ApiExtractor/abstractmetalang.cpp
@@ -2123,6 +2123,12 @@ AbstractMetaField *AbstractMetaClass::findField(const QString &name) const
return AbstractMetaField::find(m_fields, name);
}
+bool AbstractMetaClass::hasStaticFields() const
+{
+ return std::any_of(m_fields.cbegin(), m_fields.cend(),
+ [](const AbstractMetaField *f) { return f->isStatic(); });
+}
+
AbstractMetaEnum *AbstractMetaClass::findEnum(const QString &enumName)
{
if (AbstractMetaEnum *e = findByName(m_enums, enumName))
@@ -2171,6 +2177,11 @@ void AbstractMetaClass::getFunctionsFromInvisibleNamespacesToBeGenerated(Abstrac
}
}
+QString AbstractMetaClass::fullName() const
+{
+ return package() + QLatin1Char('.') + m_typeEntry->targetLangName();
+}
+
static void addExtraIncludeForType(AbstractMetaClass *metaClass, const AbstractMetaType *type)
{
if (!type)
@@ -2520,28 +2531,18 @@ AbstractMetaEnum *AbstractMetaClass::findEnum(const AbstractMetaClassList &class
{
Q_ASSERT(entry->isEnum());
- QString qualifiedName = entry->qualifiedCppName();
- int pos = qualifiedName.lastIndexOf(QLatin1String("::"));
-
- QString enumName;
- QString className;
-
- if (pos > 0) {
- enumName = qualifiedName.mid(pos + 2);
- className = qualifiedName.mid(0, pos);
- } else {
- enumName = qualifiedName;
- className = TypeDatabase::globalNamespaceClassName(entry);
- }
-
- AbstractMetaClass *metaClass = AbstractMetaClass::findClass(classes, className);
+ auto scopeEntry = entry->parent();
+ AbstractMetaClass *metaClass = AbstractMetaClass::findClass(classes, scopeEntry);
if (!metaClass) {
qCWarning(lcShiboken).noquote().nospace()
<< QStringLiteral("AbstractMeta::findEnum(), unknown class '%1' in '%2'")
- .arg(className, entry->qualifiedCppName());
+ .arg(scopeEntry->qualifiedCppName(), entry->qualifiedCppName());
return nullptr;
}
+ QString qualifiedName = entry->qualifiedCppName();
+ const int pos = qualifiedName.lastIndexOf(QLatin1String("::"));
+ const QString enumName = pos > 0 ? qualifiedName.mid(pos + 2) : qualifiedName;
return metaClass->findEnum(enumName);
}
@@ -2752,4 +2753,3 @@ QString AbstractMetaEnum::package() const
{
return m_typeEntry->targetLangPackage();
}
-
diff --git a/sources/shiboken2/ApiExtractor/abstractmetalang.h b/sources/shiboken2/ApiExtractor/abstractmetalang.h
index c100c63a..8a0363f4 100644
--- a/sources/shiboken2/ApiExtractor/abstractmetalang.h
+++ b/sources/shiboken2/ApiExtractor/abstractmetalang.h
@@ -84,6 +84,7 @@ public:
Format fmt = Documentation::Native);
bool isEmpty() const;
+ bool hasBrief() const { return m_data.contains(Brief); }
QString value(Type t = Documentation::Detailed) const;
void setValue(const QString& value, Type t = Documentation::Detailed,
@@ -1424,6 +1425,8 @@ public:
AbstractMetaField *findField(const QString &name) const;
+ bool hasStaticFields() const;
+
const AbstractMetaEnumList &enums() const { return m_enums; }
void setEnums(const AbstractMetaEnumList &enums)
{
@@ -1442,10 +1445,7 @@ public:
void getFunctionsFromInvisibleNamespacesToBeGenerated(AbstractMetaFunctionList *funcList) const;
- QString fullName() const
- {
- return package() + QLatin1Char('.') + name();
- }
+ QString fullName() const;
/**
* Retrieves the class name without any namespace/scope information.
diff --git a/sources/shiboken2/ApiExtractor/clangparser/clangbuilder.cpp b/sources/shiboken2/ApiExtractor/clangparser/clangbuilder.cpp
index 73b1aca6..b7367090 100644
--- a/sources/shiboken2/ApiExtractor/clangparser/clangbuilder.cpp
+++ b/sources/shiboken2/ApiExtractor/clangparser/clangbuilder.cpp
@@ -245,8 +245,16 @@ bool BuilderPrivate::addClass(const CXCursor &cursor, CodeModel::ClassType t)
if (isClassCursor(semPar)) {
const CursorClassHash::const_iterator it = m_cursorClassHash.constFind(semPar);
if (it == m_cursorClassHash.constEnd()) {
- const QString message = QStringLiteral("Unable to find parent of inner class ") + className;
- const Diagnostic d(message, cursor, CXDiagnostic_Error);
+ QString message;
+ QTextStream(&message) << "Unable to find containing class \""
+ << getCursorSpelling(semPar) << "\" of inner class \""
+ << className << "\".";
+ // PYSIDE-1501: Has been observed to fail for inner class of
+ // template with separated implementation where a forward
+ // declaration of the outer template is reported (Boost).
+ const auto severity = semPar.kind == CXCursor_ClassTemplate
+ ? CXDiagnostic_Warning : CXDiagnostic_Error;
+ const Diagnostic d(message, cursor, severity);
qWarning() << d;
m_baseVisitor->appendDiagnostic(d);
return false;
@@ -887,8 +895,10 @@ static QString enumType(const CXCursor &cursor)
// PYSIDE-1228: For "typedef enum { v1, v2 } Foo;", type will return
// "Foo" as expected. Care must be taken to exclude real anonymous enums.
name = getTypeName(clang_getCursorType(cursor));
- if (name.contains(QLatin1String("(anonymous")))
+ if (name.contains(QLatin1String("(unnamed")) // Clang 12.0.1
+ || name.contains(QLatin1String("(anonymous"))) { // earlier
name.clear();
+ }
}
return name;
}
@@ -921,16 +931,17 @@ BaseVisitor::StartTokenResult Builder::startToken(const CXCursor &cursor)
case CXCursor_ClassDecl:
case CXCursor_UnionDecl:
case CXCursor_StructDecl:
- if (clang_isCursorDefinition(cursor) == 0)
+ if (clang_isCursorDefinition(cursor) == 0
+ || !d->addClass(cursor, codeModelClassTypeFromCursor(cursor.kind))) {
return Skip;
- if (!d->addClass(cursor, codeModelClassTypeFromCursor(cursor.kind)))
- return Error;
+ }
break;
case CXCursor_ClassTemplate:
case CXCursor_ClassTemplatePartialSpecialization:
- if (clang_isCursorDefinition(cursor) == 0)
+ if (clang_isCursorDefinition(cursor) == 0
+ || !d->addClass(cursor, CodeModel::Class)) {
return Skip;
- d->addClass(cursor, CodeModel::Class);
+ }
d->m_currentClass->setName(d->m_currentClass->name() + templateBrackets());
d->m_scope.back() += templateBrackets();
break;
diff --git a/sources/shiboken2/ApiExtractor/clangparser/clangutils.cpp b/sources/shiboken2/ApiExtractor/clangparser/clangutils.cpp
index 6bf2e3ab..57271ef7 100644
--- a/sources/shiboken2/ApiExtractor/clangparser/clangutils.cpp
+++ b/sources/shiboken2/ApiExtractor/clangparser/clangutils.cpp
@@ -139,8 +139,9 @@ QString getTypeName(const CXType &type)
}
Diagnostic::Diagnostic(const QString &m, const CXCursor &c, CXDiagnosticSeverity s)
- : message(m), location(getCursorLocation(c)), source(Other), severity(s)
+ : message(m), source(Other), severity(s)
{
+ setLocation(getCursorLocation(c));
}
Diagnostic Diagnostic::fromCXDiagnostic(CXDiagnostic cd)
@@ -151,7 +152,7 @@ Diagnostic Diagnostic::fromCXDiagnostic(CXDiagnostic cd)
result.message = QString::fromUtf8(clang_getCString(spelling));
clang_disposeString(spelling);
result.severity = clang_getDiagnosticSeverity(cd);
- result.location = getExpansionLocation(clang_getDiagnosticLocation(cd));
+ result.setLocation(getExpansionLocation(clang_getDiagnosticLocation(cd)));
CXDiagnosticSet childDiagnostics = clang_getChildDiagnostics(cd);
if (const unsigned childCount = clang_getNumDiagnosticsInSet(childDiagnostics)) {
@@ -169,6 +170,14 @@ Diagnostic Diagnostic::fromCXDiagnostic(CXDiagnostic cd)
return result;
}
+void Diagnostic::setLocation(const SourceLocation &sourceLocation)
+{
+ file = getFileName(sourceLocation.file);
+ line = sourceLocation.line;
+ column = sourceLocation.column;
+ offset = sourceLocation.offset;
+}
+
QVector<Diagnostic> getDiagnostics(CXTranslationUnit tu)
{
QVector<Diagnostic> result;
@@ -249,7 +258,7 @@ QDebug operator<<(QDebug s, const Diagnostic &d)
QDebugStateSaver saver(s);
s.nospace();
s.noquote();
- s << d.location << ": ";
+ s << d.file << ':'<< d.line << ':' << d.column << ": ";
switch (d.severity) {
case CXDiagnostic_Ignored:
s << "ignored";
diff --git a/sources/shiboken2/ApiExtractor/clangparser/clangutils.h b/sources/shiboken2/ApiExtractor/clangparser/clangutils.h
index 41d0af46..f7c230a6 100644
--- a/sources/shiboken2/ApiExtractor/clangparser/clangutils.h
+++ b/sources/shiboken2/ApiExtractor/clangparser/clangutils.h
@@ -68,7 +68,7 @@ struct SourceLocation
{
bool equals(const SourceLocation &rhs) const;
- CXFile file;
+ CXFile file = nullptr;
unsigned line = 0;
unsigned column = 0;
unsigned offset = 0;
@@ -96,10 +96,14 @@ struct Diagnostic {
static Diagnostic fromCXDiagnostic(CXDiagnostic cd);
// Other
explicit Diagnostic(const QString &m, const CXCursor &c, CXDiagnosticSeverity s = CXDiagnostic_Warning);
+ void setLocation(const SourceLocation &);
QString message;
QStringList childMessages;
- SourceLocation location;
+ QString file;
+ unsigned line = 0;
+ unsigned column = 0;
+ unsigned offset = 0;
Source source = Clang;
CXDiagnosticSeverity severity = CXDiagnostic_Warning;
};
diff --git a/sources/shiboken2/ApiExtractor/clangparser/compilersupport.cpp b/sources/shiboken2/ApiExtractor/clangparser/compilersupport.cpp
index dac51100..0b58cf5a 100644
--- a/sources/shiboken2/ApiExtractor/clangparser/compilersupport.cpp
+++ b/sources/shiboken2/ApiExtractor/clangparser/compilersupport.cpp
@@ -232,7 +232,9 @@ static QByteArray noStandardIncludeOption() { return QByteArrayLiteral("-nostdin
// should be picked up automatically by clang without specifying
// them implicitly.
-#if defined(Q_OS_UNIX) && !defined(Q_OS_DARWIN)
+// Besides g++/Linux, as of MSVC 19.28.29334, MSVC needs clang includes
+// due to PYSIDE-1433, LLVM-47099
+#if !defined(Q_OS_DARWIN)
# define NEED_CLANG_BUILTIN_INCLUDES 1
#else
# define NEED_CLANG_BUILTIN_INCLUDES 0
@@ -301,6 +303,24 @@ static QString compilerFromCMake(const QString &defaultCompiler)
}
#endif // Q_CC_CLANG, Q_CC_GNU
+#if NEED_CLANG_BUILTIN_INCLUDES
+static void appendClangBuiltinIncludes(HeaderPaths *p)
+{
+ const QString clangBuiltinIncludesDir =
+ QDir::toNativeSeparators(findClangBuiltInIncludesDir());
+ if (clangBuiltinIncludesDir.isEmpty()) {
+ qCWarning(lcShiboken, "Unable to locate Clang's built-in include directory "
+ "(neither by checking the environment variables LLVM_INSTALL_DIR, CLANG_INSTALL_DIR "
+ " nor running llvm-config). This may lead to parse errors.");
+ } else {
+ qCInfo(lcShiboken, "CLANG builtins includes directory: %s",
+ qPrintable(clangBuiltinIncludesDir));
+ p->append(HeaderPath{QFile::encodeName(clangBuiltinIncludesDir),
+ HeaderType::System});
+ }
+}
+#endif // NEED_CLANG_BUILTIN_INCLUDES
+
// Returns clang options needed for emulating the host compiler
QByteArrayList emulatedCompilerOptions()
{
@@ -311,26 +331,19 @@ QByteArrayList emulatedCompilerOptions()
result.append(QByteArrayLiteral("-Wno-microsoft-enum-value"));
// Fix yvals_core.h: STL1000: Unexpected compiler version, expected Clang 7 or newer (MSVC2017 update)
result.append(QByteArrayLiteral("-D_ALLOW_COMPILER_AND_STL_VERSION_MISMATCH"));
+# if NEED_CLANG_BUILTIN_INCLUDES
+ appendClangBuiltinIncludes(&headerPaths);
+# endif // NEED_CLANG_BUILTIN_INCLUDES
+
#elif defined(Q_CC_CLANG)
HeaderPaths headerPaths = gppInternalIncludePaths(compilerFromCMake(QStringLiteral("clang++")));
result.append(noStandardIncludeOption());
#elif defined(Q_CC_GNU)
HeaderPaths headerPaths;
-#if NEED_CLANG_BUILTIN_INCLUDES
- const QString clangBuiltinIncludesDir =
- QDir::toNativeSeparators(findClangBuiltInIncludesDir());
- if (clangBuiltinIncludesDir.isEmpty()) {
- qCWarning(lcShiboken, "Unable to locate Clang's built-in include directory "
- "(neither by checking the environment variables LLVM_INSTALL_DIR, CLANG_INSTALL_DIR "
- " nor running llvm-config). This may lead to parse errors.");
- } else {
- qCInfo(lcShiboken, "CLANG builtins includes directory: %s",
- qPrintable(clangBuiltinIncludesDir));
- headerPaths.append(HeaderPath{QFile::encodeName(clangBuiltinIncludesDir),
- HeaderType::System});
- }
-#endif // NEED_CLANG_BUILTIN_INCLUDES
+# if NEED_CLANG_BUILTIN_INCLUDES
+ appendClangBuiltinIncludes(&headerPaths);
+# endif // NEED_CLANG_BUILTIN_INCLUDES
// Append the c++ include paths since Clang is unable to find <list> etc
// on RHEL 7 with g++ 6.3 or CentOS 7.2.
diff --git a/sources/shiboken2/ApiExtractor/qtdocparser.cpp b/sources/shiboken2/ApiExtractor/qtdocparser.cpp
index d439b3fd..1aeab85e 100644
--- a/sources/shiboken2/ApiExtractor/qtdocparser.cpp
+++ b/sources/shiboken2/ApiExtractor/qtdocparser.cpp
@@ -41,6 +41,9 @@
#include <QtCore/QXmlStreamReader>
#include <QUrl>
+static inline QString briefStartElement() { return QStringLiteral("<brief>"); }
+static inline QString briefEndElement() { return QStringLiteral("</brief>"); }
+
Documentation QtDocParser::retrieveModuleDocumentation()
{
return retrieveModuleDocumentation(packageName());
@@ -206,6 +209,25 @@ QString QtDocParser::queryFunctionDocumentation(const QString &sourceFileName,
return result;
}
+// Extract the <brief> section from a WebXML (class) documentation and remove it
+// from the source.
+static QString extractBrief(QString *value)
+{
+ const auto briefStart = value->indexOf(briefStartElement());
+ if (briefStart < 0)
+ return {};
+ const auto briefEnd = value->indexOf(briefEndElement(),
+ briefStart + briefStartElement().size());
+ if (briefEnd < briefStart)
+ return {};
+ const auto briefLength = briefEnd + briefEndElement().size() - briefStart;
+ QString briefValue = value->mid(briefStart, briefLength);
+ briefValue.insert(briefValue.size() - briefEndElement().size(),
+ QLatin1String("<rst> More_...</rst>"));
+ value->remove(briefStart, briefLength);
+ return briefValue;
+}
+
void QtDocParser::fillDocumentation(AbstractMetaClass* metaClass)
{
if (!metaClass)
@@ -257,9 +279,17 @@ void QtDocParser::fillDocumentation(AbstractMetaClass* metaClass)
signedModifs.append(docModif);
}
- Documentation doc(getDocumentation(xquery, query, classModifs));
- if (doc.isEmpty())
- qCWarning(lcShibokenDoc, "%s", qPrintable(msgCannotFindDocumentation(sourceFileName, "class", className, query)));
+ QString docString = getDocumentation(xquery, query, classModifs);
+ if (docString.isEmpty()) {
+ qCWarning(lcShibokenDoc, "%s",
+ qPrintable(msgCannotFindDocumentation(sourceFileName, "class", className, query)));
+ }
+ const QString brief = extractBrief(&docString);
+
+ Documentation doc;
+ if (!brief.isEmpty())
+ doc.setValue(brief, Documentation::Brief);
+ doc.setValue(docString);
metaClass->setDocumentation(doc);
//Functions Documentation
diff --git a/sources/shiboken2/ApiExtractor/tests/testmodifydocumentation.cpp b/sources/shiboken2/ApiExtractor/tests/testmodifydocumentation.cpp
index 6acac41d..cf3982a1 100644
--- a/sources/shiboken2/ApiExtractor/tests/testmodifydocumentation.cpp
+++ b/sources/shiboken2/ApiExtractor/tests/testmodifydocumentation.cpp
@@ -72,13 +72,14 @@ R"(<typesystem package="Foo">
docParser.setDocumentationDataDirectory(tempDir.path());
docParser.fillDocumentation(classA);
- const QString actualDocSimplified = classA->documentation().value().simplified();
+ const Documentation &doc = classA->documentation();
+ const QString actualDocSimplified = doc.value(Documentation::Detailed).simplified();
+ const QString actualBriefSimplified = doc.value(Documentation::Brief).simplified();
QVERIFY(!actualDocSimplified.isEmpty());
const char expectedDoc[] =
R"(<?xml version="1.0"?>
<description>oi
-<brief>Modified Brief</brief>
<para>Paragraph number 1</para>
<para>Paragraph number 2</para>
<para>Some changed contents here</para>
@@ -86,7 +87,7 @@ R"(<?xml version="1.0"?>
)";
const QString expectedDocSimplified = QString::fromLatin1(expectedDoc).simplified();
// Check whether the first modification worked.
- QVERIFY(actualDocSimplified.contains(QLatin1String("Modified Brief")));
+ QVERIFY(actualBriefSimplified.contains(QLatin1String("Modified Brief")));
#ifndef HAVE_LIBXSLT
// QtXmlPatterns is unable to handle para[3] in style sheets,
diff --git a/sources/shiboken2/ApiExtractor/typesystemparser.cpp b/sources/shiboken2/ApiExtractor/typesystemparser.cpp
index d2648d0b..17195d9a 100644
--- a/sources/shiboken2/ApiExtractor/typesystemparser.cpp
+++ b/sources/shiboken2/ApiExtractor/typesystemparser.cpp
@@ -1286,7 +1286,7 @@ ContainerTypeEntry *
m_error = QLatin1String("no 'type' attribute specified");
return nullptr;
}
- const QStringRef typeName = attributes->takeAt(typeIndex).value();
+ const QStringRef typeName = attributes->at(typeIndex).value();
ContainerTypeEntry::ContainerKind containerType = containerTypeFromAttribute(typeName);
if (containerType == ContainerTypeEntry::NoContainer) {
m_error = QLatin1String("there is no container of type ") + typeName.toString();
@@ -1294,6 +1294,7 @@ ContainerTypeEntry *
}
auto *type = new ContainerTypeEntry(name, containerType, since, currentParentTypeEntry());
applyCommonAttributes(reader, type, attributes);
+ attributes->removeAt(typeIndex);
return type;
}
@@ -1359,7 +1360,7 @@ NamespaceTypeEntry *
}
result->setFilePattern(re);
} else if (attributeName == QLatin1String("extends")) {
- const auto extendsPackageName = attributes->takeAt(i).value();
+ const auto extendsPackageName = attributes->at(i).value();
auto allEntries = TypeDatabase::instance()->findNamespaceTypes(name);
auto extendsIt = std::find_if(allEntries.cbegin(), allEntries.cend(),
[extendsPackageName] (const NamespaceTypeEntry *e) {
@@ -1370,6 +1371,7 @@ NamespaceTypeEntry *
return nullptr;
}
result->setExtends(*extendsIt);
+ attributes->removeAt(i);
} else if (attributeName == visibleAttribute()) {
const auto attribute = attributes->takeAt(i);
visibility = visibilityFromAttribute(attribute.value());
@@ -1621,19 +1623,21 @@ bool TypeSystemParser::parseInjectDocumentation(const QXmlStreamReader &,
for (int i = attributes->size() - 1; i >= 0; --i) {
const QStringRef name = attributes->at(i).qualifiedName();
if (name == QLatin1String("mode")) {
- const QStringRef modeName = attributes->takeAt(i).value();
+ const QStringRef modeName = attributes->at(i).value();
mode = docModificationFromAttribute(modeName);
if (mode == TypeSystem::DocModificationInvalid) {
m_error = QLatin1String("Unknown documentation injection mode: ") + modeName;
return false;
}
+ attributes->removeAt(i);
} else if (name == formatAttribute()) {
- const QStringRef format = attributes->takeAt(i).value();
+ const QStringRef format = attributes->at(i).value();
lang = languageFromAttribute(format);
if (lang != TypeSystem::TargetLangCode && lang != TypeSystem::NativeCode) {
m_error = QStringLiteral("unsupported class attribute: '%1'").arg(format);
return false;
}
+ attributes->removeAt(i);
}
}
@@ -1797,12 +1801,13 @@ bool TypeSystemParser::parseCustomConversion(const QXmlStreamReader &,
for (int i = attributes->size() - 1; i >= 0; --i) {
const QStringRef name = attributes->at(i).qualifiedName();
if (name == classAttribute()) {
- const QStringRef languageAttribute = attributes->takeAt(i).value();
+ const QStringRef languageAttribute = attributes->at(i).value();
lang = languageFromAttribute(languageAttribute);
if (lang != TypeSystem::TargetLangCode && lang != TypeSystem::NativeCode) {
m_error = QStringLiteral("unsupported class attribute: '%1'").arg(languageAttribute);
return false;
}
+ attributes->removeAt(i);
} else if (name == QLatin1String("file")) {
sourceFile = attributes->takeAt(i).value().toString();
} else if (name == snippetAttribute()) {
@@ -1999,12 +2004,13 @@ bool TypeSystemParser::parseDefineOwnership(const QXmlStreamReader &,
for (int i = attributes->size() - 1; i >= 0; --i) {
const QStringRef name = attributes->at(i).qualifiedName();
if (name == classAttribute()) {
- const QStringRef className = attributes->takeAt(i).value();
+ const QStringRef className = attributes->at(i).value();
lang = languageFromAttribute(className);
if (lang != TypeSystem::TargetLangCode && lang != TypeSystem::NativeCode) {
m_error = QStringLiteral("unsupported class attribute: '%1'").arg(className);
return false;
}
+ attributes->removeAt(i);
} else if (name == ownershipAttribute()) {
ownership = attributes->takeAt(i).value().toString();
}
@@ -2067,7 +2073,7 @@ bool TypeSystemParser::parseRemoval(const QXmlStreamReader &,
TypeSystem::Language lang = TypeSystem::All;
const int classIndex = indexOfAttribute(*attributes, classAttribute());
if (classIndex != -1) {
- const QStringRef value = attributes->takeAt(classIndex).value();
+ const QStringRef value = attributes->at(classIndex).value();
lang = languageFromAttribute(value);
if (lang == TypeSystem::TargetLangCode) // "target" means TargetLangAndNativeCode here
lang = TypeSystem::TargetLangAndNativeCode;
@@ -2075,6 +2081,7 @@ bool TypeSystemParser::parseRemoval(const QXmlStreamReader &,
m_error = QStringLiteral("unsupported class attribute: '%1'").arg(value);
return false;
}
+ attributes->removeAt(classIndex);
}
m_contextStack.top()->functionMods.last().removal = lang;
return true;
@@ -2118,7 +2125,7 @@ bool TypeSystemParser::parseRename(const QXmlStreamReader &reader,
m_error = msgMissingAttribute(modifierAttribute());
return false;
}
- const QStringRef modifier = attributes->takeAt(modifierIndex).value();
+ const QStringRef modifier = attributes->at(modifierIndex).value();
modifierFlag = modifierFromAttribute(modifier);
if (modifierFlag == Modification::InvalidModifier) {
m_error = QStringLiteral("Unknown access modifier: '%1'").arg(modifier);
@@ -2128,6 +2135,7 @@ bool TypeSystemParser::parseRename(const QXmlStreamReader &reader,
qCWarning(lcShiboken, "%s",
qPrintable(msgUnimplementedAttributeValueWarning(reader, modifierAttribute(), modifier)));
}
+ attributes->removeAt(modifierIndex);
}
if (mod)
@@ -2497,12 +2505,13 @@ bool TypeSystemParser::parseParentOwner(const QXmlStreamReader &,
if (!parseArgumentIndex(index, &ao.index, &m_error))
return false;
} else if (name == actionAttribute()) {
- const QStringRef action = attributes->takeAt(i).value();
+ const QStringRef action = attributes->at(i).value();
ao.action = argumentOwnerActionFromAttribute(action);
if (ao.action == ArgumentOwner::Invalid) {
m_error = QLatin1String("Invalid parent actionr '") + action + QLatin1String("'.");
return false;
}
+ attributes->removeAt(i);
}
}
m_contextStack.top()->functionMods.last().argument_mods.last().owner = ao;
@@ -2569,19 +2578,21 @@ bool TypeSystemParser::parseInjectCode(const QXmlStreamReader &,
for (int i = attributes->size() - 1; i >= 0; --i) {
const QStringRef name = attributes->at(i).qualifiedName();
if (name == classAttribute()) {
- const QStringRef className = attributes->takeAt(i).value();
+ const QStringRef className = attributes->at(i).value();
lang = languageFromAttribute(className);
if (lang == TypeSystem::NoLanguage) {
m_error = QStringLiteral("Invalid class specifier: '%1'").arg(className);
return false;
}
+ attributes->removeAt(i);
} else if (name == positionAttribute()) {
- const QStringRef value = attributes->takeAt(i).value();
+ const QStringRef value = attributes->at(i).value();
position = codeSnipPositionFromAttribute(value);
if (position == TypeSystem::CodeSnipPositionInvalid) {
m_error = QStringLiteral("Invalid position: '%1'").arg(value);
return false;
}
+ attributes->removeAt(i);
}
}
diff --git a/sources/shiboken2/CMakeLists.txt b/sources/shiboken2/CMakeLists.txt
index 3de5d322..c6546021 100644
--- a/sources/shiboken2/CMakeLists.txt
+++ b/sources/shiboken2/CMakeLists.txt
@@ -144,7 +144,7 @@ endif()
# Build with Address sanitizer enabled if requested.
# This may break things, so use at your own risk.
if (SANITIZE_ADDRESS AND NOT MSVC)
- set_sanitize_address()
+ setup_sanitize_address()
endif()
# Detect if the python libs were compiled in debug mode
@@ -196,6 +196,35 @@ if(CMAKE_BUILD_TYPE STREQUAL "Debug")
set_debug_build()
endif()
+######################################################################
+## Define the Python files involved in the build process.
+##
+## They are installed into the file system (see shibokenmodule)
+## and embedded into the libshiboken binary through a .zip file.
+######################################################################
+
+set(shiboken_python_files
+ "signature/lib/__init__.py"
+ "signature/lib/enum_sig.py"
+ "signature/lib/tool.py"
+ "signature/__init__.py"
+ "signature/errorhandler.py"
+ "signature/importhandler.py"
+ "signature/layout.py"
+ "signature/loader.py"
+ "signature/mapping.py"
+ "signature/parser.py"
+ "__init__.py"
+ "feature.py"
+ )
+
+if (PYTHON_VERSION_MAJOR LESS 3)
+ list(APPEND shiboken_python_files
+ "backport_inspect.py"
+ "typing27.py"
+ )
+endif()
+
######################################################################
# Adding sub directories to build
######################################################################
diff --git a/sources/shiboken2/data/docgenerator.1 b/sources/shiboken2/data/docgenerator.1
deleted file mode 100644
index f5a61f13..00000000
--- a/sources/shiboken2/data/docgenerator.1
+++ /dev/null
@@ -1,76 +0,0 @@
-.TH GENERATORRUNNER 1 "SEPTEMBER 2009" Linux "User Manuals"
-.SH NAME
-generatorrunner - plugin-based binding source code generator
-.SH SYNOPSIS
-.B generatorrunner \-\-generator-set=<plugin name> [options] header-file typesystem-file
-.SH DESCRIPTION
-.B generatorrunner
-is a utility that uses the information taken from APIExtractor
-related to the provided C++ headers and typesystem files and execute
-generators using this information. Generators are plugins and you need
-to specify one using the \-\-generator-set parameter. At the moment there
-are two generators available:
-
-.B qtdoc
-\- Generates Sphinx-based documentation for C++ libraries documented using
-.B qdoc
-documentation syntax, using the XML files created by the documentation tool
-.B (qdoc).
-Can be called supplying
-.B \-\-generator-set=qtdoc
-to
-.B generatorrunner
-or by calling the convenience executable
-.B docgenerator.
-
-Other plugins can be used with
-.B generatorrunner,
-provided that they follow the generator front-end specifications,
-and can be written to generate code or documentation for any target
-languague you desire. For more information about the generator front-end
-architecture and current limitations, refer to http://www.pyside.org/home-binding.
-
-.SH OPTIONS
-.SS "General options"
-.IP \-\-api-version=<version>
-Specify the supported api version used to generate the bindings.
-.IP \-\-debug-level=[sparse|medium|full]
-The amount of messages displayed.
-.IP \-\-documentation-only
-Only generates the documentation.
-.IP \-\-drop-type-entries="<TypeEntry0>[;TypeEntry1;...]"
-Semicolon separated list of type system entries (classes, namespaces, global functions and enums) to be dropped from generation.
-.IP \-\-help \fR,\fP \-h \fR,\fP -?
-Prints the usage message.
-.IP \-\-project-file=<file>
-Text file containing a description of the binding project. Replaces and overrides command line arguments.
-.IP \-\-include\-paths=\fI<path>[:path:..]\fR
-The directories where the generator will search for the
-headers. Works like gcc's \-I flag.
-.IP \-\-license\-file=\fI[licensefile]\fR
-Template for copyright headers of generated files.
-.IP \-\-no\-supress\-warnings
-Show all warnings.
-.IP \-\-output\-directory=\fI[dir]\fR
-The directory where the generated files will be written.
-.IP \-\-silent
-Avoid printing any messages.
-.IP \-\-typesytem\-paths=\fI<path>[:path:..]\fR
-The directories where the generator will search for the
-external typesystems referred by the main one.
-.IP \-\-version
-Displays the current version.
-Drops support for named args.
-.SS "Specific to qtdoc plugin"
-.IP \-\-documentation\-code\-snippets\-dir
-Directory used to search code snippets used by the documentation
-.IP \-\-documentation\-data\-dir
-Directory with XML files generated by documentation tool (qdoc or Doxygen)
-.IP \-\-documentation\-out\-dir
-The directory where the generated documentation files will be written
-.IP \-\-library\-source\-dir
-Directory where library source code is located
-
-.SH AUTHORS
-Lauro Moura <lauro.neto at openbossa dot org>, Bruno Araujo <bruno.araujo at openbossa dot org>, Hugo Lima <hugo.lima at openbossa dot org>
-
diff --git a/sources/shiboken2/data/docgenerator.1 b/sources/shiboken2/data/docgenerator.1
new file mode 120000
index 00000000..c65282f9
--- /dev/null
+++ b/sources/shiboken2/data/docgenerator.1
@@ -0,0 +1 @@
+generatorrunner.1
\ No newline at end of file
diff --git a/sources/shiboken2/data/shiboken_helpers.cmake b/sources/shiboken2/data/shiboken_helpers.cmake
index 5e0c6ea7..ad32c3ed 100644
--- a/sources/shiboken2/data/shiboken_helpers.cmake
+++ b/sources/shiboken2/data/shiboken_helpers.cmake
@@ -39,7 +39,7 @@ macro(set_debug_build)
endif()
endmacro()
-macro(setup_sanitize_address)
+macro(set_sanitize_address)
# Currently this does not check that the clang / gcc version used supports Address sanitizer,
# so once again, use at your own risk.
add_compile_options("-fsanitize=address" "-g" "-fno-omit-frame-pointer")
diff --git a/sources/shiboken2/doc/typesystem_codeinjection.rst b/sources/shiboken2/doc/typesystem_codeinjection.rst
index b0d5f385..83660950 100644
--- a/sources/shiboken2/doc/typesystem_codeinjection.rst
+++ b/sources/shiboken2/doc/typesystem_codeinjection.rst
@@ -112,7 +112,8 @@ Below is the example C++ class for whom wrapper code will be generated.
.. code-block:: c++
- class InjectCode {
+ class InjectCode
+ {
public:
InjectCode();
double overloadedMethod(int arg);
@@ -124,6 +125,10 @@ From the C++ class, |project| will generate a ``injectcode_wrapper.cpp`` file
with the binding code. The next section will use a simplified version of the
generated wrapper code with the injection spots marked with comments.
+There are a number of placeholders indicated by a percent sign ``%``, which
+will be expanded when inserting the code. For a list, see
+:ref:`typesystemvariables`.
+
Noteworthy Cases
----------------
@@ -196,7 +201,7 @@ class is polymorphic.
int InjectCodeWrapper::virtualMethod(int arg)
{
- PyObject* method = BindingManager::instance().getOverride(this, "virtualMethod");
+ PyObject *method = BindingManager::instance().getOverride(this, "virtualMethod");
if (!py_override)
return this->InjectCode::virtualMethod(arg);
@@ -228,10 +233,9 @@ own ``beginning`` and ``end`` code injections.
.. code-block:: c++
- static PyObject*
- PyInjectCode_overloadedMethod(PyObject* self, PyObject* arg)
+ static PyObject *PyInjectCode_overloadedMethod(PyObject *self, PyObject *arg)
{
- PyObject* py_result = 0;
+ PyObject* py_result{};
if (PyFloat_Check(arg)) {
double cpp_arg0 = Shiboken::Converter<double >::toCpp(arg);
@@ -250,13 +254,13 @@ own ``beginning`` and ``end`` code injections.
} else goto PyInjectCode_overloadedMethod_TypeError;
if (PyErr_Occurred() || !py_result)
- return 0;
+ return {};
return py_result;
PyInjectCode_overloadedMethod_TypeError:
PyErr_SetString(PyExc_TypeError, "'overloadedMethod()' called with wrong parameters.");
- return 0;
+ return {};
}
@@ -371,7 +375,7 @@ to prevent bad custom code to pass unnoticed.
// INJECT-CODE: <typesystem><inject-code class="target" position="beginning">
// Uses: do something before the module is created.
- PyObject* module = Py_InitModule("MODULENAME", MODULENAME_methods);
+ PyObject *module = Py_InitModule("MODULENAME", MODULENAME_methods);
(... initialization of wrapped classes, namespaces, functions and enums ...)
diff --git a/sources/shiboken2/doc/typesystem_conversionrule.rst b/sources/shiboken2/doc/typesystem_conversionrule.rst
index 27e7a72d..fc87a85c 100644
--- a/sources/shiboken2/doc/typesystem_conversionrule.rst
+++ b/sources/shiboken2/doc/typesystem_conversionrule.rst
@@ -32,6 +32,10 @@ conversion-rule
</conversion-rule>
</value-type>
+ The code can be inserted directly, via ``add-conversion`` (providing snippet
+ functionality) or via ``insert-template`` (XML template,
+ see :ref:`using-code-templates`).
+
The example above show the structure of a complete conversion rule. Each of the
child tags comprising the conversion rule are described in their own sections
below.
diff --git a/sources/shiboken2/doc/typesystem_variables.rst b/sources/shiboken2/doc/typesystem_variables.rst
index 73d4dd12..3d463825 100644
--- a/sources/shiboken2/doc/typesystem_variables.rst
+++ b/sources/shiboken2/doc/typesystem_variables.rst
@@ -1,3 +1,5 @@
+.. _typesystemvariables:
+
*********************
Type System Variables
*********************
@@ -24,9 +26,9 @@ Variables
.. _arg_number:
-**%#**
+**%<number>**
- Replaced by the name of a C++ argument in the position indicated by ``#``.
+ Replaced by the name of a C++ argument in the position indicated by ``<number>``.
The argument counting starts with ``%1``, since ``%0`` represents the return
variable name. If the number indicates a variable that was removed in the
type system description, but there is a default value for it, this value will
@@ -214,13 +216,13 @@ Variables
.. _pyarg:
-**%PYARG_#**
+**%PYARG_<number>**
- Similar to ``%#``, but is replaced by the Python arguments (PyObjects)
+ Similar to ``%<number>``, but is replaced by the Python arguments (PyObjects)
received by the Python wrapper method.
If used in the context of a native code injection, i.e. in a virtual method
- override, ``%PYARG_#`` will be translated to one item of the Python tuple
+ override, ``%PYARG_<number>`` will be translated to one item of the Python tuple
holding the arguments that should be passed to the Python override for this
virtual method.
diff --git a/sources/shiboken2/generator/generator.cpp b/sources/shiboken2/generator/generator.cpp
index dd56ab7c..60282828 100644
--- a/sources/shiboken2/generator/generator.cpp
+++ b/sources/shiboken2/generator/generator.cpp
@@ -43,6 +43,8 @@
#include <QDebug>
#include <typedatabase.h>
+static const char ENABLE_PYSIDE_EXTENSIONS[] = "enable-pyside-extensions";
+
/**
* DefaultValue is used for storing default values of types for which code is
* generated in different contexts:
@@ -169,6 +171,7 @@ struct Generator::GeneratorPrivate
QVector<const AbstractMetaType *> instantiatedContainers;
QVector<const AbstractMetaType *> instantiatedSmartPointers;
AbstractMetaClassList m_invisibleTopNamespaces;
+ bool m_usePySideExtensions = false;
};
Generator::Generator() : m_d(new GeneratorPrivate)
@@ -276,24 +279,24 @@ void Generator::addInstantiatedContainersAndSmartPointers(const AbstractMetaType
return;
}
- QString typeName = getSimplifiedContainerTypeName(type);
if (isContainer) {
+ QString typeName = getSimplifiedContainerTypeName(type);
if (!m_d->instantiatedContainersNames.contains(typeName)) {
m_d->instantiatedContainersNames.append(typeName);
m_d->instantiatedContainers.append(type);
}
- } else {
- // Is smart pointer. Check if the (const?) pointee is already known
- auto pt = pointeeTypeEntry(type);
- const bool present =
- std::any_of(m_d->instantiatedSmartPointers.cbegin(), m_d->instantiatedSmartPointers.cend(),
- [pt] (const AbstractMetaType *t) {
- return pointeeTypeEntry(t) == pt;
- });
- if (!present)
- m_d->instantiatedSmartPointers.append(canonicalSmartPtrInstantiation(type));
+ return;
}
-
+ // Is smart pointer. Check if the (const?) pointee is already known for the given
+ // smart pointer type entry.
+ auto pt = pointeeTypeEntry(type);
+ const bool present =
+ std::any_of(m_d->instantiatedSmartPointers.cbegin(), m_d->instantiatedSmartPointers.cend(),
+ [typeEntry, pt] (const AbstractMetaType *t) {
+ return t->typeEntry() == typeEntry && pointeeTypeEntry(t) == pt;
+ });
+ if (!present)
+ m_d->instantiatedSmartPointers.append(canonicalSmartPtrInstantiation(type));
}
void Generator::collectInstantiatedContainersAndSmartPointers(const AbstractMetaFunction *func)
@@ -339,11 +342,17 @@ QVector<const AbstractMetaType *> Generator::instantiatedSmartPointers() const
Generator::OptionDescriptions Generator::options() const
{
- return OptionDescriptions();
+ return {
+ {QLatin1String(ENABLE_PYSIDE_EXTENSIONS),
+ QLatin1String("Enable PySide extensions, such as support for signal/slots,\n"
+ "use this if you are creating a binding for a Qt-based library.")}
+ };
}
-bool Generator::handleOption(const QString & /* key */, const QString & /* value */)
+bool Generator::handleOption(const QString & key, const QString & /* value */)
{
+ if (key == QLatin1String(ENABLE_PYSIDE_EXTENSIONS))
+ return ( m_d->m_usePySideExtensions = true);
return false;
}
@@ -615,6 +624,11 @@ bool Generator::isVoidPointer(const AbstractMetaType *type)
&& type->name() == QLatin1String("void");
}
+bool Generator::usePySideExtensions() const
+{
+ return m_d->m_usePySideExtensions;
+}
+
QString Generator::getFullTypeName(const TypeEntry *type) const
{
QString result = type->qualifiedCppName();
diff --git a/sources/shiboken2/generator/generator.h b/sources/shiboken2/generator/generator.h
index cf6df528..0cedbd25 100644
--- a/sources/shiboken2/generator/generator.h
+++ b/sources/shiboken2/generator/generator.h
@@ -244,6 +244,9 @@ public:
/// Returns the generator's name. Used for cosmetic purposes.
virtual const char *name() const = 0;
+ /// Returns true if the user enabled PySide extensions (command line option)
+ bool usePySideExtensions() const;
+
/**
* Retrieves the name of the currently processed module.
* While package name is a complete package idetification, e.g. 'PySide.QtCore',
diff --git a/sources/shiboken2/generator/main.cpp b/sources/shiboken2/generator/main.cpp
index 8d819c76..fa41cb62 100644
--- a/sources/shiboken2/generator/main.cpp
+++ b/sources/shiboken2/generator/main.cpp
@@ -109,7 +109,7 @@ static bool processProjectFile(QFile &projectFile, CommandLineArguments &args)
QByteArray key;
QString value;
if (split > 0) {
- key = line.left(split - 1).trimmed();
+ key = line.left(split).trimmed();
value = QString::fromUtf8(line.mid(split + 1).trimmed());
} else {
key = line;
@@ -612,8 +612,7 @@ int main(int argc, char *argv[])
extractor.setCppFileNames(cppFileNames);
extractor.setTypeSystem(typeSystemFileName);
- auto shibokenGenerator = dynamic_cast<const ShibokenGenerator *>(generators.constFirst().data());
- const bool usePySideExtensions = shibokenGenerator && shibokenGenerator->usePySideExtensions();
+ const bool usePySideExtensions = generators.constFirst().data()->usePySideExtensions();
if (!extractor.run(usePySideExtensions)) {
errorPrint(QLatin1String("Error running ApiExtractor."));
diff --git a/sources/shiboken2/generator/qtdoc/qtdocgenerator.cpp b/sources/shiboken2/generator/qtdoc/qtdocgenerator.cpp
index 5e75cbf8..1b7c786d 100644
--- a/sources/shiboken2/generator/qtdoc/qtdocgenerator.cpp
+++ b/sources/shiboken2/generator/qtdoc/qtdocgenerator.cpp
@@ -1588,30 +1588,6 @@ static void writeInheritedByList(QTextStream& s, const AbstractMetaClass* metaCl
s << classes.join(QLatin1String(", ")) << Qt::endl << Qt::endl;
}
-// Extract the <brief> section from a WebXML (class) documentation and remove it
-// from the source.
-static bool extractBrief(Documentation *sourceDoc, Documentation *brief)
-{
- if (sourceDoc->format() != Documentation::Native)
- return false;
- QString value = sourceDoc->value();
- const int briefStart = value.indexOf(briefStartElement());
- if (briefStart < 0)
- return false;
- const int briefEnd = value.indexOf(briefEndElement(), briefStart + briefStartElement().size());
- if (briefEnd < briefStart)
- return false;
- const int briefLength = briefEnd + briefEndElement().size() - briefStart;
- brief->setFormat(Documentation::Native);
- QString briefValue = value.mid(briefStart, briefLength);
- briefValue.insert(briefValue.size() - briefEndElement().size(),
- QLatin1String("<rst> More_...</rst>"));
- brief->setValue(briefValue);
- value.remove(briefStart, briefLength);
- sourceDoc->setValue(value);
- return true;
-}
-
void QtDocGenerator::generateClass(QTextStream &s, const GeneratorContext &classContext)
{
const AbstractMetaClass *metaClass = classContext.metaClass();
@@ -1630,9 +1606,8 @@ void QtDocGenerator::generateClass(QTextStream &s, const GeneratorContext &class
s << Pad('*', className.count()) << Qt::endl << Qt::endl;
auto documentation = metaClass->documentation();
- Documentation brief;
- if (extractBrief(&documentation, &brief))
- writeFormattedText(s, brief.value(), metaClass);
+ if (documentation.hasBrief())
+ writeFormattedText(s, documentation.value(Documentation::Brief), metaClass);
s << ".. inheritance-diagram:: " << metaClass->fullName() << Qt::endl
<< " :parts: 2" << Qt::endl << Qt::endl;
@@ -1659,7 +1634,7 @@ void QtDocGenerator::generateClass(QTextStream &s, const GeneratorContext &class
writeInjectDocumentation(s, TypeSystem::DocModificationPrepend, metaClass, nullptr);
if (!writeInjectDocumentation(s, TypeSystem::DocModificationReplace, metaClass, nullptr))
- writeFormattedText(s, documentation.value(), metaClass);
+ writeFormattedText(s, documentation.value(Documentation::Detailed), metaClass);
if (!metaClass->isNamespace())
writeConstructors(s, metaClass);
@@ -1972,7 +1947,7 @@ bool QtDocGenerator::writeInjectDocumentation(QTextStream& s,
continue;
doc.setValue(mod.code(), Documentation::Detailed, fmt);
- writeFormattedText(s, doc.value(), cppClass);
+ writeFormattedText(s, doc, cppClass);
didSomething = true;
}
}
@@ -2378,7 +2353,8 @@ bool QtDocGenerator::doSetup()
Generator::OptionDescriptions QtDocGenerator::options() const
{
- return OptionDescriptions()
+ OptionDescriptions result = Generator::options();
+ result
<< qMakePair(QLatin1String("doc-parser=<parser>"),
QLatin1String("The documentation parser used to interpret the documentation\n"
"input files (qdoc|doxygen)"))
@@ -2393,10 +2369,13 @@ Generator::OptionDescriptions QtDocGenerator::options() const
<< qMakePair(additionalDocumentationOption() + QLatin1String("=<file>"),
QLatin1String("List of additional XML files to be converted to .rst files\n"
"(for example, tutorials)."));
+ return result;
}
bool QtDocGenerator::handleOption(const QString &key, const QString &value)
{
+ if (Generator::handleOption(key, value))
+ return true;
if (key == QLatin1String("library-source-dir")) {
m_libSourceDir = value;
return true;
diff --git a/sources/shiboken2/generator/shiboken2/cppgenerator.cpp b/sources/shiboken2/generator/shiboken2/cppgenerator.cpp
index 05d9d97d..75b75d24 100644
--- a/sources/shiboken2/generator/shiboken2/cppgenerator.cpp
+++ b/sources/shiboken2/generator/shiboken2/cppgenerator.cpp
@@ -359,7 +359,6 @@ void CppGenerator::generateClass(QTextStream &s, const GeneratorContext &classCo
<< "#include <pyside.h>\n"
<< "#include <pysideqenum.h>\n"
<< "#include <feature_select.h>\n"
- << "#include <qapp_macro.h>\n\n"
<< "QT_WARNING_DISABLE_DEPRECATED\n\n";
}
@@ -763,6 +762,9 @@ void CppGenerator::generateClass(QTextStream &s, const GeneratorContext &classCo
writeConverterFunctions(s, metaClass, classContext);
writeClassRegister(s, metaClass, classContext, signatureStream);
+ if (metaClass->hasStaticFields())
+ writeStaticFieldInitialization(s, metaClass);
+
// class inject-code native/end
if (!metaClass->typeEntry()->codeSnips().isEmpty()) {
writeClassCodeSnips(s, metaClass->typeEntry()->codeSnips(),
@@ -1059,7 +1061,7 @@ void CppGenerator::writeVirtualMethodNative(QTextStream &s,
QString argConv;
QTextStream ac(&argConv);
- auto argType = static_cast<const PrimitiveTypeEntry *>(arg->type()->typeEntry());
+ const auto *argType = arg->type()->typeEntry();
bool convert = argType->isObject()
|| argType->isValue()
|| arg->type()->isValuePointer()
@@ -1068,11 +1070,11 @@ void CppGenerator::writeVirtualMethodNative(QTextStream &s,
|| argType->isEnum()
|| argType->isContainer()
|| arg->type()->referenceType() == LValueReference;
-
if (!convert && argType->isPrimitive()) {
- if (argType->basicReferencedTypeEntry())
- argType = argType->basicReferencedTypeEntry();
- convert = !m_formatUnits.contains(argType->name());
+ const auto *pte = static_cast<const PrimitiveTypeEntry *>(argType);
+ if (pte->basicReferencedTypeEntry())
+ pte = pte->basicReferencedTypeEntry();
+ convert = !m_formatUnits.contains(pte->name());
}
Indentor nested;
@@ -1831,6 +1833,11 @@ void CppGenerator::writeMethodWrapperPreamble(QTextStream &s, OverloadData &over
usesNamedArguments = rfunc->isCallOperator() || overloadData.hasArgumentWithDefaultValue();
}
+ s << INDENT << "PyObject *errInfo{};\n";
+ s << INDENT << "SBK_UNUSED(errInfo)\n";
+ s << INDENT << "static const char *fullName = \""
+ << fullPythonFunctionName(rfunc, true) << "\";\n";
+ s << INDENT << "SBK_UNUSED(fullName)\n";
if (maxArgs > 0) {
s << INDENT << "int overloadId = -1;\n";
s << INDENT << "PythonToCppFunc " << PYTHON_TO_CPP_VAR;
@@ -1845,9 +1852,6 @@ void CppGenerator::writeMethodWrapperPreamble(QTextStream &s, OverloadData &over
writeUnusedVariableCast(s, QLatin1String(PYTHON_TO_CPP_VAR));
}
- if (usesNamedArguments && !rfunc->isCallOperator())
- s << INDENT << "const Py_ssize_t numNamedArgs = (kwds ? PyDict_Size(kwds) : 0);\n";
-
if (initPythonArguments) {
s << INDENT << "const Py_ssize_t numArgs = ";
if (minArgs == 0 && maxArgs == 1 && !rfunc->isConstructor() && !pythonFunctionWrapperUsesListOfArguments(overloadData))
@@ -1869,28 +1873,8 @@ void CppGenerator::writeConstructorWrapper(QTextStream &s, const AbstractMetaFun
s << "static int\n";
s << cpythonFunctionName(rfunc) << "(PyObject *self, PyObject *args, PyObject *kwds)\n{\n";
- QSet<QString> argNamesSet;
- if (usePySideExtensions() && metaClass->isQObject()) {
- // Write argNames variable with all known argument names.
- const OverloadData::MetaFunctionList &overloads = overloadData.overloads();
- for (const AbstractMetaFunction *func : overloads) {
- const AbstractMetaArgumentList &arguments = func->arguments();
- for (const AbstractMetaArgument *arg : arguments) {
- if (arg->defaultValueExpression().isEmpty() || func->argumentRemoved(arg->argumentIndex() + 1))
- continue;
- argNamesSet << arg->name();
- }
- }
- QStringList argNamesList = argNamesSet.values();
- std::sort(argNamesList.begin(), argNamesList.end());
- if (argNamesList.isEmpty()) {
- s << INDENT << "const char **argNames{};\n";
- } else {
- s << INDENT << "const char *argNames[] = {\""
- << argNamesList.join(QLatin1String("\", \"")) << "\"};\n";
- }
+ if (usePySideExtensions() && metaClass->isQObject())
s << INDENT << "const QMetaObject *metaObject;\n";
- }
s << INDENT << "SbkObject *sbkSelf = reinterpret_cast<SbkObject *>(self);\n";
@@ -1916,6 +1900,10 @@ void CppGenerator::writeConstructorWrapper(QTextStream &s, const AbstractMetaFun
s << outdent(INDENT) << '\n';
}
+ // PYSIDE-1478: Switching must also happen at object creation time.
+ if (usePySideExtensions())
+ s << "PySide::Feature::Select(self);\n";
+
writeMethodWrapperPreamble(s, overloadData, classContext);
s << Qt::endl;
@@ -1930,6 +1918,8 @@ void CppGenerator::writeConstructorWrapper(QTextStream &s, const AbstractMetaFun
{
Indentation indent(INDENT);
s << INDENT << "delete cptr;\n";
+ if (overloadData.maxArgs() > 0)
+ s << INDENT << "Py_XDECREF(errInfo);\n";
s << INDENT << returnStatement(m_currentErrorCode) << Qt::endl;
}
s << INDENT << "}\n";
@@ -1950,19 +1940,24 @@ void CppGenerator::writeConstructorWrapper(QTextStream &s, const AbstractMetaFun
s << INDENT << "if (Shiboken::BindingManager::instance().hasWrapper(cptr)) {\n";
{
Indentation indent(INDENT);
- s << INDENT << "Shiboken::BindingManager::instance().releaseWrapper(Shiboken::BindingManager::instance().retrieveWrapper(cptr));\n";
+ s << INDENT << "Shiboken::BindingManager::instance().releaseWrapper("
+ "Shiboken::BindingManager::instance().retrieveWrapper(cptr));\n";
}
s << INDENT << "}\n";
s << INDENT << "Shiboken::BindingManager::instance().registerWrapper(sbkSelf, cptr);\n";
// Create metaObject and register signal/slot
+ bool errHandlerNeeded = overloadData.maxArgs() > 0;
if (metaClass->isQObject() && usePySideExtensions()) {
+ errHandlerNeeded = true;
s << Qt::endl << INDENT << "// QObject setup\n";
s << INDENT << "PySide::Signal::updateSourceObject(self);\n";
s << INDENT << "metaObject = cptr->metaObject(); // <- init python qt properties\n";
- s << INDENT << "if (kwds && !PySide::fillQtProperties(self, metaObject, kwds, argNames, "
- << argNamesSet.count() << "))\n" << indent(INDENT)
- << INDENT << returnStatement(m_currentErrorCode) << '\n' << outdent(INDENT);
+ s << INDENT << "if (errInfo && PyDict_Check(errInfo)) {\n" << indent(INDENT)
+ << INDENT << "if (!PySide::fillQtProperties(self, metaObject, errInfo))\n" << indent(INDENT)
+ << INDENT << "goto " << cpythonFunctionName(rfunc) << "_TypeError;\n" << outdent(INDENT)
+ << INDENT << "Py_DECREF(errInfo);\n" << outdent(INDENT)
+ << INDENT << "};\n";
}
// Constructor code injections, position=end
@@ -1990,7 +1985,8 @@ void CppGenerator::writeConstructorWrapper(QTextStream &s, const AbstractMetaFun
Indentation indent(INDENT);
writeCodeSnips(s, func->injectedCodeSnips(), TypeSystem::CodeSnipPositionEnd, TypeSystem::TargetLangCode, func);
}
- s << INDENT << "}\n";
+ s << INDENT << "}\n"
+ << INDENT << "break;\n";
break;
}
}
@@ -2000,7 +1996,7 @@ void CppGenerator::writeConstructorWrapper(QTextStream &s, const AbstractMetaFun
s << Qt::endl;
s << Qt::endl << INDENT << "return 1;\n";
- if (overloadData.maxArgs() > 0)
+ if (errHandlerNeeded)
writeErrorSection(s, overloadData);
s<< "}\n\n";
}
@@ -2149,11 +2145,14 @@ void CppGenerator::writeArgumentsInitializer(QTextStream &s, OverloadData &overl
bool ownerClassIsQObject = rfunc->ownerClass() && rfunc->ownerClass()->isQObject() && rfunc->isConstructor();
if (usesNamedArguments) {
if (!ownerClassIsQObject) {
- s << INDENT << "if (numArgs" << (overloadData.hasArgumentWithDefaultValue() ? " + numNamedArgs" : "") << " > " << maxArgs << ") {\n";
+ s << INDENT << "if (numArgs > " << maxArgs << ") {\n";
{
Indentation indent(INDENT);
- s << INDENT << "PyErr_SetString(PyExc_TypeError, \"" << fullPythonFunctionName(rfunc) << "(): too many arguments\");\n";
- s << INDENT << returnStatement(m_currentErrorCode) << Qt::endl;
+ s << INDENT << "static PyObject *const too_many = "
+ "Shiboken::String::createStaticString(\">\");\n";
+ s << INDENT << "errInfo = too_many;\n";
+ s << INDENT << "Py_INCREF(errInfo);\n";
+ s << INDENT << "goto " << cpythonFunctionName(rfunc) << "_TypeError;\n";
}
s << INDENT << '}';
}
@@ -2165,8 +2164,11 @@ void CppGenerator::writeArgumentsInitializer(QTextStream &s, OverloadData &overl
s << "if (numArgs < " << minArgs << ") {\n";
{
Indentation indent(INDENT);
- s << INDENT << "PyErr_SetString(PyExc_TypeError, \"" << fullPythonFunctionName(rfunc) << "(): not enough arguments\");\n";
- s << INDENT << returnStatement(m_currentErrorCode) << Qt::endl;
+ s << INDENT << "static PyObject *const too_few = "
+ "Shiboken::String::createStaticString(\"<\");\n";
+ s << INDENT << "errInfo = too_few;\n";
+ s << INDENT << "Py_INCREF(errInfo);\n";
+ s << INDENT << "goto " << cpythonFunctionName(rfunc) << "_TypeError;\n";
}
s << INDENT << '}';
}
@@ -2300,11 +2302,13 @@ void CppGenerator::writeErrorSection(QTextStream &s, OverloadData &overloadData)
const AbstractMetaFunction *rfunc = overloadData.referenceFunction();
s << Qt::endl << INDENT << cpythonFunctionName(rfunc) << "_TypeError:\n";
Indentation indentation(INDENT);
- QString funcName = fullPythonFunctionName(rfunc);
+ QString funcName = fullPythonFunctionName(rfunc, true);
QString argsVar = pythonFunctionWrapperUsesListOfArguments(overloadData)
? QLatin1String("args") : QLatin1String(PYTHON_ARG);
- s << INDENT << "Shiboken::setErrorAboutWrongArguments(" << argsVar << ", \"" << funcName << "\");\n";
+ s << INDENT << "Shiboken::setErrorAboutWrongArguments(" << argsVar
+ << ", fullName, errInfo);\n";
+ s << INDENT << "Py_XDECREF(errInfo);\n";
s << INDENT << "return " << m_currentErrorCode << ";\n";
}
@@ -2821,7 +2825,7 @@ void CppGenerator::writeOverloadedFunctionDecisorEngine(QTextStream &s, const Ov
if (isVarargs)
--numArgs;
typeChecks.prepend(QString::fromLatin1("numArgs %1 %2").arg(isVarargs ? QLatin1String(">=") : QLatin1String("==")).arg(numArgs));
- } else if (sequenceArgCount > 1) {
+ } else if (usePyArgs && sequenceArgCount > 0) {
typeChecks.prepend(QString::fromLatin1("numArgs >= %1").arg(startArg + sequenceArgCount));
} else if (refFunc->isOperatorOverload() && !refFunc->isCallOperator()) {
typeChecks.prepend(QString::fromLatin1("%1isReverse").arg(refFunc->isReverseOperator() ? QString() : QLatin1String("!")));
@@ -2908,7 +2912,7 @@ void CppGenerator::writeSingleFunctionCall(QTextStream &s,
bool usePyArgs = pythonFunctionWrapperUsesListOfArguments(overloadData);
// Handle named arguments.
- writeNamedArgumentResolution(s, func, usePyArgs);
+ writeNamedArgumentResolution(s, func, usePyArgs, overloadData);
bool injectCodeCallsFunc = injectedCodeCallsCppFunction(context, func);
bool mayHaveUnunsedArguments = !func->isUserAdded() && func->hasInjectedCode() && injectCodeCallsFunc;
@@ -3231,33 +3235,46 @@ void CppGenerator::writeAddPythonToCppConversion(QTextStream &s, const QString &
s << ");\n";
}
-void CppGenerator::writeNamedArgumentResolution(QTextStream &s, const AbstractMetaFunction *func, bool usePyArgs)
+void CppGenerator::writeNamedArgumentResolution(QTextStream &s, const AbstractMetaFunction *func,
+ bool usePyArgs, const OverloadData &overloadData)
{
const AbstractMetaArgumentList &args = OverloadData::getArgumentsWithDefaultValues(func);
- if (args.isEmpty())
+ if (args.isEmpty()) {
+ if (overloadData.hasArgumentWithDefaultValue()) {
+ s << INDENT << "if (kwds) {\n";
+ {
+ Indentation indent(INDENT);
+ s << INDENT << "errInfo = kwds;\n";
+ s << INDENT << "Py_INCREF(errInfo);\n";
+ s << INDENT << "goto " << cpythonFunctionName(func) << "_TypeError;\n";
+ }
+ s << INDENT << "}\n";
+ }
return;
-
- QString pyErrString(QLatin1String("PyErr_SetString(PyExc_TypeError, \"") + fullPythonFunctionName(func)
- + QLatin1String("(): got multiple values for keyword argument '%1'.\");"));
+ }
s << INDENT << "if (kwds) {\n";
{
Indentation indent(INDENT);
- s << INDENT << "PyObject *keyName = nullptr;\n";
- s << INDENT << "PyObject *value = nullptr;\n";
+ s << INDENT << "PyObject *value{};\n";
+ s << INDENT << "PyObject *kwds_dup = PyDict_Copy(kwds);\n";
for (const AbstractMetaArgument *arg : args) {
- int pyArgIndex = arg->argumentIndex() - OverloadData::numberOfRemovedArguments(func, arg->argumentIndex());
+ const int pyArgIndex = arg->argumentIndex()
+ - OverloadData::numberOfRemovedArguments(func, arg->argumentIndex());
QString pyArgName = usePyArgs ? pythonArgsAt(pyArgIndex) : QLatin1String(PYTHON_ARG);
- s << INDENT << "keyName = Py_BuildValue(\"s\",\"" << arg->name() << "\");\n";
- s << INDENT << "if (PyDict_Contains(kwds, keyName)) {\n";
+ QString pyKeyName = QLatin1String("key_") + arg->name();
+ s << INDENT << "static PyObject *const " << pyKeyName
+ << " = Shiboken::String::createStaticString(\"" << arg->name() << "\");\n";
+ s << INDENT << "if (PyDict_Contains(kwds, " << pyKeyName << ")) {\n";
{
Indentation indent(INDENT);
- s << INDENT << "value = PyDict_GetItem(kwds, keyName);\n";
+ s << INDENT << "value = PyDict_GetItem(kwds, " << pyKeyName << ");\n";
s << INDENT << "if (value && " << pyArgName << ") {\n";
{
Indentation indent(INDENT);
- s << INDENT << pyErrString.arg(arg->name()) << Qt::endl;
- s << INDENT << returnStatement(m_currentErrorCode) << Qt::endl;
+ s << INDENT << "errInfo = " << pyKeyName << ";\n";
+ s << INDENT << "Py_INCREF(errInfo);\n";
+ s << INDENT << "goto " << cpythonFunctionName(func) << "_TypeError;\n";
}
s << INDENT << "}\n";
s << INDENT << "if (value) {\n";
@@ -3265,7 +3282,8 @@ void CppGenerator::writeNamedArgumentResolution(QTextStream &s, const AbstractMe
Indentation indent(INDENT);
s << INDENT << pyArgName << " = value;\n";
s << INDENT << "if (!";
- writeTypeCheck(s, arg->type(), pyArgName, isNumber(arg->type()->typeEntry()), func->typeReplaced(arg->argumentIndex() + 1));
+ writeTypeCheck(s, arg->type(), pyArgName, isNumber(arg->type()->typeEntry()),
+ func->typeReplaced(arg->argumentIndex() + 1));
s << ")\n";
{
Indentation indent(INDENT);
@@ -3273,9 +3291,29 @@ void CppGenerator::writeNamedArgumentResolution(QTextStream &s, const AbstractMe
}
}
s << INDENT << "}\n";
+ s << INDENT << "PyDict_DelItem(kwds_dup, " << pyKeyName << ");\n";
}
s << INDENT << "}\n";
}
+ // PYSIDE-1305: Handle keyword args correctly.
+ // Normal functions handle their parameters immediately.
+ // For constructors that are QObject, we need to delay that
+ // until extra keyword signals and properties are handled.
+ s << INDENT << "if (PyDict_Size(kwds_dup) > 0) {\n";
+ {
+ Indentation indent(INDENT);
+ s << INDENT << "errInfo = kwds_dup;\n";
+ if (!(func->isConstructor() && func->ownerClass()->isQObject()))
+ s << INDENT << "goto " << cpythonFunctionName(func) << "_TypeError;\n";
+ else
+ s << INDENT << "// fall through to handle extra keyword signals and properties\n";
+ }
+ s << INDENT << "} else {\n";
+ {
+ Indentation indent(INDENT);
+ s << INDENT << "Py_DECREF(kwds_dup);\n";
+ }
+ s << INDENT << "}\n";
}
s << INDENT << "}\n";
}
@@ -4162,15 +4200,14 @@ void CppGenerator::writeClassDefinition(QTextStream &s,
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) {
tp_new = QLatin1String("SbkQAppTpNew"); // PYSIDE-571: need singleton app
}
else {
tp_new = QLatin1String("SbkObjectTpNew");
- tp_flags.append(QLatin1String("|Py_TPFLAGS_HAVE_GC"));
}
+ tp_flags.append(QLatin1String("|Py_TPFLAGS_HAVE_GC"));
QString tp_richcompare;
if (!metaClass->isNamespace() && metaClass->hasComparisonOperatorOverload())
@@ -4895,7 +4932,7 @@ void CppGenerator::writeSignatureInfo(QTextStream &s, const AbstractMetaFunction
{
OverloadData overloadData(overloads, this);
const AbstractMetaFunction *rfunc = overloadData.referenceFunction();
- QString funcName = fullPythonFunctionName(rfunc);
+ QString funcName = fullPythonFunctionName(rfunc, false);
int idx = overloads.length() - 1;
bool multiple = idx > 0;
@@ -5193,12 +5230,17 @@ void CppGenerator::writeFlagsBinaryOperator(QTextStream &s, const AbstractMetaEn
<< ">(int(PyLong_AsLong(self)));\n";
s << INDENT << "cppArg = static_cast<" << flagsEntry->originalName() << ">(int(PyLong_AsLong("
<< PYTHON_ARG << ")));\n";
+ // PYSIDE-1436: Need to error check self as well because operators are used
+ // sometimes with swapped args.
+ s << INDENT << "if (PyErr_Occurred())\n" << INDENT << "return nullptr;\n";
s << "#else\n";
s << INDENT << CPP_SELF_VAR << " = static_cast<::" << flagsEntry->originalName()
<< ">(int(PyInt_AsLong(self)));\n";
s << INDENT << "cppArg = static_cast<" << flagsEntry->originalName()
<< ">(int(PyInt_AsLong(" << PYTHON_ARG << ")));\n";
s << "#endif\n\n";
+ s << INDENT << "if (PyErr_Occurred())\n" << indent(INDENT)
+ << INDENT << "return nullptr;\n" << outdent(INDENT);
s << INDENT << "cppResult = " << CPP_SELF_VAR << " " << cppOpName << " cppArg;\n";
s << INDENT << "return ";
writeToPythonConversion(s, flagsType, nullptr, QLatin1String("cppResult"));
@@ -5245,6 +5287,12 @@ QString CppGenerator::getSimpleClassInitFunctionName(const AbstractMetaClass *me
return initFunctionName;
}
+QString CppGenerator::getSimpleClassStaticFieldsInitFunctionName(const AbstractMetaClass *metaClass) const
+{
+ return QLatin1String("init_") + getSimpleClassInitFunctionName(metaClass)
+ + QLatin1String("StaticFields");
+}
+
QString CppGenerator::getInitFunctionName(const GeneratorContext &context) const
{
return !context.forSmartPointer()
@@ -5447,18 +5495,6 @@ void CppGenerator::writeClassRegister(QTextStream &s,
if (metaClass->hasSignals())
writeSignalInitialization(s, metaClass);
- // Write static fields
- const AbstractMetaFieldList &fields = metaClass->fields();
- for (const AbstractMetaField *field : fields) {
- if (!field->isStatic())
- continue;
- s << INDENT << QLatin1String("PyDict_SetItemString(reinterpret_cast<PyTypeObject *>(") + cpythonTypeName(metaClass) + QLatin1String(")->tp_dict, \"");
- s << field->name() << "\", ";
- writeToPythonConversion(s, field->type(), metaClass, metaClass->qualifiedCppName() + QLatin1String("::") + field->name());
- s << ");\n";
- }
- s << Qt::endl;
-
// class inject-code target/end
if (!classTypeEntry->codeSnips().isEmpty()) {
s << Qt::endl;
@@ -5488,6 +5524,29 @@ void CppGenerator::writeClassRegister(QTextStream &s,
s << "}\n";
}
+void CppGenerator::writeStaticFieldInitialization(QTextStream &s,
+ const AbstractMetaClass *metaClass)
+{
+ s << "\nvoid " << getSimpleClassStaticFieldsInitFunctionName(metaClass)
+ << "()\n{\n" << INDENT << "auto dict = reinterpret_cast<PyTypeObject *>("
+ << cpythonTypeName(metaClass) << ")->tp_dict;\n";
+ const auto &fields = metaClass->fields();
+ for (const AbstractMetaField *field : fields) {
+ if (field->isStatic()) {
+ QString cppName = field->originalName();
+ if (cppName.isEmpty())
+ cppName = field->name();
+ const QString name = field->enclosingClass()->qualifiedCppName()
+ + QLatin1String("::") + cppName;
+ s << INDENT << "PyDict_SetItemString(dict, \"" << field->name()
+ << "\",\n" << INDENT << " ";
+ writeToPythonConversion(s, field->type(), metaClass, name);
+ s << ");\n";
+ }
+ }
+ s << "\n}\n";
+}
+
void CppGenerator::writeInitQtMetaTypeFunctionBody(QTextStream &s, const GeneratorContext &context) const
{
const AbstractMetaClass *metaClass = context.metaClass();
@@ -5898,11 +5957,18 @@ bool CppGenerator::finishGeneration()
}
const AbstractMetaClassList lst = classesTopologicalSorted(additionalDependencies);
+ QVector<const AbstractMetaClass *> classesWithStaticFields;
+
for (const AbstractMetaClass *cls : lst){
if (shouldGenerate(cls)) {
writeInitFunc(s_classInitDecl, s_classPythonDefines, INDENT,
getSimpleClassInitFunctionName(cls),
cls->typeEntry()->targetLangEnclosingEntry());
+ if (cls->hasStaticFields()) {
+ s_classInitDecl << "void "
+ << getSimpleClassStaticFieldsInitFunctionName(cls) << "();\n";
+ classesWithStaticFields.append(cls);
+ }
}
}
@@ -5936,7 +6002,6 @@ bool CppGenerator::finishGeneration()
s << "#include <pyside.h>\n";
s << "#include <pysideqenum.h>\n";
s << "#include <feature_select.h>\n";
- s << "#include <qapp_macro.h>\n";
}
s << "#include \"" << getModuleHeaderFileName() << '"' << Qt::endl << Qt::endl;
@@ -6205,6 +6270,14 @@ bool CppGenerator::finishGeneration()
s << INDENT << "Shiboken::Module::registerTypes(module, " << cppApiVariableName() << ");\n";
s << INDENT << "Shiboken::Module::registerTypeConverters(module, " << convertersVariableName() << ");\n";
+ // Static fields are registered last since they may use converter functions
+ // of the previously registered types (PYSIDE-1529).
+ if (!classesWithStaticFields.isEmpty()) {
+ s << "\n// Static field initialization\n";
+ for (auto cls : qAsConst(classesWithStaticFields))
+ s << getSimpleClassStaticFieldsInitFunctionName(cls) << "();\n";
+ }
+
s << '\n' << INDENT << "if (PyErr_Occurred()) {\n" << indent(INDENT)
<< INDENT << "PyErr_Print();\n"
<< INDENT << "Py_FatalError(\"can't initialize module " << moduleName() << "\");\n"
diff --git a/sources/shiboken2/generator/shiboken2/cppgenerator.h b/sources/shiboken2/generator/shiboken2/cppgenerator.h
index 41bd17f2..64396d61 100644
--- a/sources/shiboken2/generator/shiboken2/cppgenerator.h
+++ b/sources/shiboken2/generator/shiboken2/cppgenerator.h
@@ -247,7 +247,8 @@ private:
void writeAddPythonToCppConversion(QTextStream &s, const QString &converterVar, const QString &pythonToCppFunc, const QString &isConvertibleFunc);
- void writeNamedArgumentResolution(QTextStream &s, const AbstractMetaFunction *func, bool usePyArgs);
+ void writeNamedArgumentResolution(QTextStream &s, const AbstractMetaFunction *func,
+ bool usePyArgs, const OverloadData &overloadData);
/// Returns a string containing the name of an argument for the given function and argument index.
QString argumentNameFromIndex(const AbstractMetaFunction *func, int argIndex, const AbstractMetaClass **wrappedClass);
@@ -256,6 +257,7 @@ private:
QString getInitFunctionName(const GeneratorContext &context) const;
QString getSimpleClassInitFunctionName(const AbstractMetaClass *metaClass) const;
+ QString getSimpleClassStaticFieldsInitFunctionName(const AbstractMetaClass *metaClass) const;
void writeSignatureStrings(QTextStream &s, QTextStream &signatureStream,
const QString &arrayName,
@@ -264,6 +266,8 @@ private:
const AbstractMetaClass *metaClass,
const GeneratorContext &classContext,
QTextStream &signatureStream);
+ void writeStaticFieldInitialization(QTextStream &s,
+ const AbstractMetaClass *metaClass);
void writeClassDefinition(QTextStream &s,
const AbstractMetaClass *metaClass,
const GeneratorContext &classContext);
diff --git a/sources/shiboken2/generator/shiboken2/shibokengenerator.cpp b/sources/shiboken2/generator/shiboken2/shibokengenerator.cpp
index 5d8685b9..42850e87 100644
--- a/sources/shiboken2/generator/shiboken2/shibokengenerator.cpp
+++ b/sources/shiboken2/generator/shiboken2/shibokengenerator.cpp
@@ -46,7 +46,6 @@
static const char AVOID_PROTECTED_HACK[] = "avoid-protected-hack";
static const char PARENT_CTOR_HEURISTIC[] = "enable-parent-ctor-heuristic";
static const char RETURN_VALUE_HEURISTIC[] = "enable-return-value-heuristic";
-static const char ENABLE_PYSIDE_EXTENSIONS[] = "enable-pyside-extensions";
static const char DISABLE_VERBOSE_ERROR_MESSAGES[] = "disable-verbose-error-messages";
static const char USE_ISNULL_AS_NB_NONZERO[] = "use-isnull-as-nb_nonzero";
static const char WRAPPER_DIAGNOSTICS[] = "wrapper-diagnostics";
@@ -356,7 +355,7 @@ QString ShibokenGenerator::fullPythonClassName(const AbstractMetaClass *metaClas
return fullClassName;
}
-QString ShibokenGenerator::fullPythonFunctionName(const AbstractMetaFunction *func)
+QString ShibokenGenerator::fullPythonFunctionName(const AbstractMetaFunction *func, bool forceFunc)
{
QString funcName;
if (func->isOperatorOverload())
@@ -365,10 +364,14 @@ QString ShibokenGenerator::fullPythonFunctionName(const AbstractMetaFunction *fu
funcName = func->name();
if (func->ownerClass()) {
QString fullClassName = fullPythonClassName(func->ownerClass());
- if (func->isConstructor())
+ if (func->isConstructor()) {
funcName = fullClassName;
- else
+ if (forceFunc)
+ funcName.append(QLatin1String(".__init__"));
+ }
+ else {
funcName.prepend(fullClassName + QLatin1Char('.'));
+ }
}
else {
funcName = packageName() + QLatin1Char('.') + func->name();
@@ -2563,7 +2566,8 @@ AbstractMetaFunctionList ShibokenGenerator::getFunctionOverloads(const AbstractM
Generator::OptionDescriptions ShibokenGenerator::options() const
{
- return OptionDescriptions()
+ OptionDescriptions result = Generator::options();
+ result
<< qMakePair(QLatin1String(AVOID_PROTECTED_HACK),
QLatin1String("Avoid the use of the '#define protected public' hack."))
<< qMakePair(QLatin1String(DISABLE_VERBOSE_ERROR_MESSAGES),
@@ -2571,9 +2575,6 @@ Generator::OptionDescriptions ShibokenGenerator::options() const
"but safe few kB on the generated bindings."))
<< qMakePair(QLatin1String(PARENT_CTOR_HEURISTIC),
QLatin1String("Enable heuristics to detect parent relationship on constructors."))
- << qMakePair(QLatin1String(ENABLE_PYSIDE_EXTENSIONS),
- QLatin1String("Enable PySide extensions, such as support for signal/slots,\n"
- "use this if you are creating a binding for a Qt-based library."))
<< qMakePair(QLatin1String(RETURN_VALUE_HEURISTIC),
QLatin1String("Enable heuristics to detect parent relationship on return values\n"
"(USE WITH CAUTION!)"))
@@ -2582,14 +2583,15 @@ Generator::OptionDescriptions ShibokenGenerator::options() const
"the value of boolean casts"))
<< qMakePair(QLatin1String(WRAPPER_DIAGNOSTICS),
QLatin1String("Generate diagnostic code around wrappers"));
+ return result;
}
-bool ShibokenGenerator::handleOption(const QString &key, const QString & /* value */)
+bool ShibokenGenerator::handleOption(const QString &key, const QString &value)
{
+ if (Generator::handleOption(key, value))
+ return true;
if (key == QLatin1String(PARENT_CTOR_HEURISTIC))
return (m_useCtorHeuristic = true);
- if (key == QLatin1String(ENABLE_PYSIDE_EXTENSIONS))
- return (m_usePySideExtensions = true);
if (key == QLatin1String(RETURN_VALUE_HEURISTIC))
return (m_userReturnValueHeuristic = true);
if (key == QLatin1String(DISABLE_VERBOSE_ERROR_MESSAGES))
@@ -2691,11 +2693,6 @@ bool ShibokenGenerator::useReturnValueHeuristic() const
return m_userReturnValueHeuristic;
}
-bool ShibokenGenerator::usePySideExtensions() const
-{
- return m_usePySideExtensions;
-}
-
bool ShibokenGenerator::useIsNullAsNbNonZero() const
{
return m_useIsNullAsNbNonZero;
diff --git a/sources/shiboken2/generator/shiboken2/shibokengenerator.h b/sources/shiboken2/generator/shiboken2/shibokengenerator.h
index 6d36026c..c776ac8c 100644
--- a/sources/shiboken2/generator/shiboken2/shibokengenerator.h
+++ b/sources/shiboken2/generator/shiboken2/shibokengenerator.h
@@ -90,9 +90,6 @@ public:
/// Returns a list of all ancestor classes for the given class.
AbstractMetaClassList getAllAncestors(const AbstractMetaClass *metaClass) const;
- /// Returns true if the user enabled PySide extensions.
- bool usePySideExtensions() const;
-
protected:
bool doSetup() override;
@@ -234,7 +231,7 @@ protected:
QString wrapperName(const AbstractMetaClass *metaClass) const;
QString fullPythonClassName(const AbstractMetaClass *metaClass);
- QString fullPythonFunctionName(const AbstractMetaFunction *func);
+ QString fullPythonFunctionName(const AbstractMetaFunction *func, bool forceFunc);
bool wrapperDiagnostics() const { return m_wrapperDiagnostics; }
@@ -564,7 +561,6 @@ private:
bool m_useCtorHeuristic = false;
bool m_userReturnValueHeuristic = false;
- bool m_usePySideExtensions = false;
bool m_verboseErrorMessagesDisabled = false;
bool m_useIsNullAsNbNonZero = false;
bool m_avoidProtectedHack = false;
diff --git a/sources/shiboken2/libshiboken/CMakeLists.txt b/sources/shiboken2/libshiboken/CMakeLists.txt
index a209dc71..96effd28 100644
--- a/sources/shiboken2/libshiboken/CMakeLists.txt
+++ b/sources/shiboken2/libshiboken/CMakeLists.txt
@@ -29,13 +29,35 @@ configure_file("${CMAKE_CURRENT_SOURCE_DIR}/sbkversion.h.in"
configure_file("${CMAKE_CURRENT_SOURCE_DIR}/embed/signature_bootstrap.py"
"${CMAKE_CURRENT_BINARY_DIR}/embed/signature_bootstrap.py" @ONLY)
+# Variable from enclosing scope.
+# list(TRANSFORM shiboken_python_files
+# PREPEND "${CMAKE_CURRENT_SOURCE_DIR}/../shibokenmodule/files.dir/shibokensupport/"
+# OUTPUT_VARIABLE embedded_shiboken_files)
+# Replacement for CMake version < 3.12:
+set(embedded_shiboken_files "")
+foreach(item IN LISTS shiboken_python_files)
+ list(APPEND embedded_shiboken_files
+ "${CMAKE_CURRENT_SOURCE_DIR}/../shibokenmodule/files.dir/shibokensupport/${item}")
+endforeach()
+
+if (QUIET_BUILD)
+ set(embedding_option "--quiet")
+else()
+ set(embedding_option "")
+endif()
+
add_custom_command(
OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/embed/signature_bootstrap_inc.h"
OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/embed/signature_inc.h"
COMMAND ${PYTHON_EXECUTABLE} -E
"${CMAKE_CURRENT_SOURCE_DIR}/embed/embedding_generator.py"
--cmake-dir "${CMAKE_CURRENT_BINARY_DIR}/embed"
- --limited-api ${PYTHON_LIMITED_API})
+ --limited-api ${PYTHON_LIMITED_API}
+ ${embedding_option}
+ DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/embed/embedding_generator.py"
+ "${CMAKE_CURRENT_SOURCE_DIR}/embed/signature_bootstrap.py"
+ ${embedded_shiboken_files}
+ )
set(libshiboken_MAJOR_VERSION ${shiboken_MAJOR_VERSION})
set(libshiboken_MINOR_VERSION ${shiboken_MINOR_VERSION})
@@ -57,7 +79,6 @@ sbkstaticstrings.cpp
bindingmanager.cpp
threadstatesaver.cpp
shibokenbuffer.cpp
-qapp_macro.cpp
pep384impl.cpp
voidptr.cpp
typespec.cpp
@@ -142,7 +163,6 @@ install(FILES
shibokenbuffer.h
sbkpython.h
pep384impl.h
- qapp_macro.h
voidptr.h
typespec.h
bufferprocs_py37.h
diff --git a/sources/shiboken2/libshiboken/basewrapper.cpp b/sources/shiboken2/libshiboken/basewrapper.cpp
index d866d133..7ac7fada 100644
--- a/sources/shiboken2/libshiboken/basewrapper.cpp
+++ b/sources/shiboken2/libshiboken/basewrapper.cpp
@@ -56,7 +56,6 @@
#include <algorithm>
#include "threadstatesaver.h"
#include "signature.h"
-#include "qapp_macro.h"
#include "voidptr.h"
#include <iostream>
@@ -96,6 +95,13 @@ static void SbkObjectTypeDealloc(PyObject *pyObj);
static PyObject *SbkObjectTypeTpNew(PyTypeObject *metatype, PyObject *args, PyObject *kwds);
static SelectableFeatureHook SelectFeatureSet = nullptr;
+static DestroyQAppHook DestroyQApplication = nullptr;
+
+// PYSIDE-1470: Provide a hook to kill an Application from Shiboken.
+void setDestroyQApplication(DestroyQAppHook func)
+{
+ DestroyQApplication = func;
+}
static PyObject *Sbk_TypeGet___dict__(PyTypeObject *type, void *context); // forward
@@ -319,6 +325,11 @@ static int SbkObject_traverse(PyObject *self, visitproc visit, void *arg)
if (sbkSelf->ob_dict)
Py_VISIT(sbkSelf->ob_dict);
+
+#if PY_VERSION_HEX >= 0x03090000
+ // This was not needed before Python 3.9 (Python issue 35810 and 40217)
+ Py_VISIT(Py_TYPE(self));
+#endif
return 0;
}
@@ -422,9 +433,7 @@ static void SbkDeallocWrapperCommon(PyObject *pyObj, bool canDelete)
// be invoked and it trying to delete this object while it is still in
// progress from the first time around, resulting in a double delete and a
// crash.
- // PYSIDE-571: Some objects do not use GC, so check this!
- if (PyObject_IS_GC(pyObj))
- PyObject_GC_UnTrack(pyObj);
+ PyObject_GC_UnTrack(pyObj);
// Check that Python is still initialized as sometimes this is called by a static destructor
// after Python interpeter is shutdown.
@@ -536,6 +545,48 @@ void SbkObjectTypeDealloc(PyObject *pyObj)
}
}
+////////////////////////////////////////////////////////////////////////////
+//
+// Support for the qApp macro.
+//
+// qApp is a macro in Qt5. In Python, we simulate that a little by a
+// variable that monitors Q*Application.instance().
+// This variable is also able to destroy the app by qApp.shutdown().
+//
+
+PyObject *MakeQAppWrapper(PyTypeObject *type)
+{
+ static PyObject *qApp_last = nullptr;
+
+ // protecting from multiple application instances
+ if (!(type == nullptr || qApp_last == Py_None)) {
+ const char *res_name = qApp_last != nullptr
+ ? PepType_GetNameStr(Py_TYPE(qApp_last)) : "<Unknown>";
+ 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 nullptr;
+ }
+
+ // monitoring the last application state
+ PyObject *qApp_curr = type != nullptr ? PyObject_GC_New(PyObject, type) : Py_None;
+ static PyObject *builtins = PyEval_GetBuiltins();
+ if (PyDict_SetItem(builtins, Shiboken::PyName::qApp(), qApp_curr) < 0)
+ return nullptr;
+ qApp_last = qApp_curr;
+ // Note: This Py_INCREF would normally be wrong because the qApp
+ // object already has a reference from PyObject_GC_New. But this is
+ // exactly the needed reference that keeps qApp alive from alone!
+ Py_INCREF(qApp_curr);
+ // PYSIDE-1470: As a side effect, the interactive "_" variable tends to
+ // create reference cycles. It was found when using gc.collect(). But using
+ // PyGC_collect() inside the C code had no effect in the interactive shell.
+ // The cycle exists only in the eval loop of the interpreter!
+ if (PyDict_GetItem(builtins, Shiboken::PyName::underscore()))
+ PyDict_SetItem(builtins, Shiboken::PyName::underscore(), Py_None);
+ return qApp_curr;
+}
+
//////////////////////////////////////////////////////////////////////////////
//
// PYSIDE-1019: Support switchable extensions
@@ -550,9 +601,11 @@ void SbkObjectTypeDealloc(PyObject *pyObj)
// SbkObject_GenericSetAttr PyObject_GenericSetAttr
//
-void initSelectableFeature(SelectableFeatureHook func)
+SelectableFeatureHook initSelectableFeature(SelectableFeatureHook func)
{
+ auto ret = SelectFeatureSet;
SelectFeatureSet = func;
+ return ret;
}
static PyObject *mangled_type_getattro(PyTypeObject *type, PyObject *name)
@@ -574,7 +627,7 @@ static PyObject *Sbk_TypeGet___dict__(PyTypeObject *type, void *context)
* This is the override for getting a dict.
*/
auto dict = type->tp_dict;
- if (dict == NULL)
+ if (dict == nullptr)
Py_RETURN_NONE;
if (SelectFeatureSet != nullptr)
dict = SelectFeatureSet(type);
@@ -625,6 +678,13 @@ void SbkObjectType_SetPropertyStrings(PyTypeObject *type, const char **strings)
PepType_SOTP(reinterpret_cast<SbkObjectType *>(type))->propertyStrings = strings;
}
+// PYSIDE-1626: Enforcing a context switch without further action.
+void SbkObjectType_UpdateFeature(PyTypeObject *type)
+{
+ if (SelectFeatureSet != nullptr)
+ type->tp_dict = SelectFeatureSet(type);
+}
+
//
//////////////////////////////////////////////////////////////////////////////
@@ -718,10 +778,13 @@ static PyObject *SbkObjectTypeTpNew(PyTypeObject *metatype, PyObject *args, PyOb
sotp->d_func = nullptr;
sotp->is_user_type = 1;
+ // PYSIDE-1463: Prevent feature switching while in the creation process
+ auto saveFeature = initSelectableFeature(nullptr);
for (SbkObjectType *base : bases) {
if (PepType_SOTP(base)->subtype_init)
PepType_SOTP(base)->subtype_init(newType, args, kwds);
}
+ initSelectableFeature(saveFeature);
return reinterpret_cast<PyObject *>(newType);
}
@@ -744,39 +807,25 @@ static PyObject *_setupNew(SbkObject *self, PyTypeObject *subtype)
self->ob_dict = nullptr;
self->weakreflist = nullptr;
self->d = d;
+ PyObject_GC_Track(reinterpret_cast<PyObject *>(self));
return reinterpret_cast<PyObject *>(self);
}
PyObject *SbkObjectTpNew(PyTypeObject *subtype, PyObject *, PyObject *)
{
SbkObject *self = PyObject_GC_New(SbkObject, subtype);
- PyObject *res = _setupNew(self, subtype);
- PyObject_GC_Track(reinterpret_cast<PyObject *>(self));
- return res;
+ return _setupNew(self, subtype);
}
PyObject *SbkQAppTpNew(PyTypeObject *subtype, PyObject *, PyObject *)
{
- // PYSIDE-571:
- // For qApp, we need to create a singleton Python object.
- // We cannot track this with the GC, because it is a static variable!
-
- // 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
auto self = reinterpret_cast<SbkObject *>(MakeQAppWrapper(subtype));
- return self == nullptr ? nullptr : _setupNew(self, subtype);
+ if (self == nullptr)
+ return nullptr;
+ auto ret = _setupNew(self, subtype);
+ auto priv = self->d;
+ priv->isQAppSingleton = 1;
+ return ret;
}
PyObject *SbkDummyNew(PyTypeObject *type, PyObject *, PyObject *)
@@ -854,7 +903,7 @@ PyObject *FallbackRichCompare(PyObject *self, PyObject *other, int op)
opstrings[op],
self->ob_type->tp_name,
other->ob_type->tp_name);
- return NULL;
+ return nullptr;
}
Py_INCREF(res);
return res;
@@ -968,9 +1017,10 @@ void init()
}
// setErrorAboutWrongArguments now gets overload info from the signature module.
-void setErrorAboutWrongArguments(PyObject *args, const char *funcName)
+// Info can be nullptr and contains extra info.
+void setErrorAboutWrongArguments(PyObject *args, const char *funcName, PyObject *info)
{
- SetError_Argument(args, funcName);
+ SetError_Argument(args, funcName, info);
}
class FindBaseTypeVisitor : public HierarchyVisitor
@@ -1265,6 +1315,12 @@ bool wasCreatedByPython(SbkObject *pyObj)
void callCppDestructors(SbkObject *pyObj)
{
+ auto priv = pyObj->d;
+ if (priv->isQAppSingleton && DestroyQApplication) {
+ // PYSIDE-1470: Allow to destroy the application from Shiboken.
+ DestroyQApplication();
+ return;
+ }
PyTypeObject *type = Py_TYPE(pyObj);
SbkObjectTypePrivate *sotp = PepType_SOTP(type);
if (sotp->is_multicpp) {
@@ -1277,18 +1333,19 @@ void callCppDestructors(SbkObject *pyObj)
sotp->cpp_dtor(pyObj->d->cptr[0]);
}
+ if (priv->validCppObject && priv->containsCppWrapper) {
+ BindingManager::instance().releaseWrapper(pyObj);
+ }
+
/* invalidate needs to be called before deleting pointer array because
it needs to delete entries for them from the BindingManager hash table;
also release wrapper explicitly if object contains C++ wrapper because
invalidate doesn't */
invalidate(pyObj);
- if (pyObj->d->validCppObject && pyObj->d->containsCppWrapper) {
- BindingManager::instance().releaseWrapper(pyObj);
- }
- delete[] pyObj->d->cptr;
- pyObj->d->cptr = nullptr;
- pyObj->d->validCppObject = false;
+ delete[] priv->cptr;
+ priv->cptr = nullptr;
+ priv->validCppObject = false;
}
bool hasOwnership(SbkObject *pyObj)
diff --git a/sources/shiboken2/libshiboken/basewrapper.h b/sources/shiboken2/libshiboken/basewrapper.h
index 31083522..a79a9309 100644
--- a/sources/shiboken2/libshiboken/basewrapper.h
+++ b/sources/shiboken2/libshiboken/basewrapper.h
@@ -93,18 +93,25 @@ typedef void (*ObjectDestructor)(void *);
typedef void (*SubTypeInitHook)(SbkObjectType *, PyObject *, PyObject *);
-// PYSIDE-1019: Set the function to select the current feature.
+/// PYSIDE-1019: Set the function to select the current feature.
+/// Return value is the previous content.
typedef PyObject *(*SelectableFeatureHook)(PyTypeObject *);
-LIBSHIBOKEN_API void initSelectableFeature(SelectableFeatureHook func);
+LIBSHIBOKEN_API SelectableFeatureHook initSelectableFeature(SelectableFeatureHook func);
-// PYSIDE-1019: Get access to PySide reserved bits.
+/// PYSIDE-1019: Get access to PySide reserved bits.
LIBSHIBOKEN_API int SbkObjectType_GetReserved(PyTypeObject *type);
LIBSHIBOKEN_API void SbkObjectType_SetReserved(PyTypeObject *type, int value);
-// PYSIDE-1019: Get access to PySide property strings.
+/// PYSIDE-1626: Enforcing a context switch without further action.
+LIBSHIBOKEN_API void SbkObjectType_UpdateFeature(PyTypeObject *type);
+
+/// PYSIDE-1019: Get access to PySide property strings.
LIBSHIBOKEN_API const char **SbkObjectType_GetPropertyStrings(PyTypeObject *type);
LIBSHIBOKEN_API void SbkObjectType_SetPropertyStrings(PyTypeObject *type, const char **strings);
+/// PYSIDE-1470: Set the function to kill a Q*Application.
+typedef void(*DestroyQAppHook)();
+LIBSHIBOKEN_API void setDestroyQApplication(DestroyQAppHook func);
extern LIBSHIBOKEN_API PyTypeObject *SbkObjectType_TypeF(void);
extern LIBSHIBOKEN_API SbkObjectType *SbkObject_TypeF(void);
@@ -118,8 +125,12 @@ struct LIBSHIBOKEN_API SbkObjectType
};
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);
+
+/// The special case of a switchable singleton Q*Application.
+LIBSHIBOKEN_API PyObject *SbkQAppTpNew(PyTypeObject *subtype, PyObject *, PyObject *);
+
+/// Create a new Q*Application wrapper and monitor it.
+LIBSHIBOKEN_API PyObject *MakeQAppWrapper(PyTypeObject *type);
/**
* PYSIDE-832: Use object_dealloc instead of nullptr.
@@ -157,8 +168,10 @@ void callCppDestructor(void *cptr)
delete reinterpret_cast<T *>(cptr);
}
-// setErrorAboutWrongArguments now gets overload info from the signature module.
-LIBSHIBOKEN_API void setErrorAboutWrongArguments(PyObject *args, const char *funcName);
+// setErrorAboutWrongArguments now gets overload information from the signature module.
+// The extra info argument can contain additional data about the error.
+LIBSHIBOKEN_API void setErrorAboutWrongArguments(PyObject *args, const char *funcName,
+ PyObject *info);
namespace ObjectType {
diff --git a/sources/shiboken2/libshiboken/basewrapper_p.h b/sources/shiboken2/libshiboken/basewrapper_p.h
index 64f7941b..60fba13c 100644
--- a/sources/shiboken2/libshiboken/basewrapper_p.h
+++ b/sources/shiboken2/libshiboken/basewrapper_p.h
@@ -97,6 +97,9 @@ struct SbkObjectPrivate
unsigned int validCppObject : 1;
/// Marked as true when the object constructor was called
unsigned int cppObjectCreated : 1;
+ /// PYSIDE-1470: Marked as true if this is the Q*Application singleton.
+ /// This bit allows app deletion from shiboken?.delete() .
+ unsigned int isQAppSingleton : 1;
/// Information about the object parents and children, may be null.
Shiboken::ParentInfo *parentInfo;
/// Manage reference count of objects that are referred to but not owned from.
diff --git a/sources/shiboken2/libshiboken/bindingmanager.cpp b/sources/shiboken2/libshiboken/bindingmanager.cpp
index 78c03556..5d69e923 100644
--- a/sources/shiboken2/libshiboken/bindingmanager.cpp
+++ b/sources/shiboken2/libshiboken/bindingmanager.cpp
@@ -292,6 +292,9 @@ PyObject *BindingManager::getOverride(const void *cptr,
if (!wrapper || reinterpret_cast<const PyObject *>(wrapper)->ob_refcnt == 0)
return nullptr;
+ // PYSIDE-1626: Touch the type to initiate switching early.
+ SbkObjectType_UpdateFeature(Py_TYPE(wrapper));
+
int flag = currentSelectId(Py_TYPE(wrapper));
int propFlag = isdigit(methodName[0]) ? methodName[0] - '0' : 0;
if ((flag & 0x02) != 0 && (propFlag & 3) != 0) {
@@ -299,12 +302,13 @@ PyObject *BindingManager::getOverride(const void *cptr,
// They cannot be overridden (make that sure by the metaclass).
return nullptr;
}
- PyObject *pyMethodName = nameCache[(flag & 1) != 0]; // borrowed
+ bool is_snake = flag & 0x01;
+ PyObject *pyMethodName = nameCache[is_snake]; // borrowed
if (pyMethodName == nullptr) {
if (propFlag)
methodName += 2; // skip the propFlag and ':'
- pyMethodName = Shiboken::String::getSnakeCaseName(methodName, flag);
- nameCache[(flag & 1) != 0] = pyMethodName;
+ pyMethodName = Shiboken::String::getSnakeCaseName(methodName, is_snake);
+ nameCache[is_snake] = pyMethodName;
}
if (wrapper->ob_dict) {
diff --git a/sources/shiboken2/libshiboken/embed/embedding_generator.py b/sources/shiboken2/libshiboken/embed/embedding_generator.py
index 15f63649..a9a58ee0 100644
--- a/sources/shiboken2/libshiboken/embed/embedding_generator.py
+++ b/sources/shiboken2/libshiboken/embed/embedding_generator.py
@@ -82,7 +82,7 @@ def runpy(cmd, **kw):
subprocess.call([sys.executable, '-E'] + cmd.split(), **kw)
-def create_zipfile(limited_api):
+def create_zipfile(limited_api, quiet):
"""
Collect all Python files, compile them, create a zip file
and make a chunked base64 encoded file from it.
@@ -129,11 +129,28 @@ def create_zipfile(limited_api):
with open(inc_name, "w") as inc:
_embed_file(tmp, inc)
tmp.close()
+
# also generate a simple embeddable .pyc file for signature_bootstrap.pyc
boot_name = "signature_bootstrap.py" if limited_api else "signature_bootstrap.pyc"
with open(boot_name, "rb") as ldr, open("signature_bootstrap_inc.h", "w") as inc:
_embed_bytefile(ldr, inc, limited_api)
os.chdir(cur_dir)
+ if quiet:
+ return
+
+ # have a look at our populated folder unless quiet option
+ def list_files(startpath):
+ for root, dirs, files in os.walk(startpath):
+ level = root.replace(startpath, '').count(os.sep)
+ indent = ' ' * 4 * (level)
+ print('+ {}{}/'.format(indent, os.path.basename(root)))
+ subindent = ' ' * 4 * (level + 1)
+ for f in files:
+ print('+ {}{}'.format(subindent, f))
+
+ print("++++ Current contents of")
+ list_files(work_dir)
+ print("++++")
def _embed_file(fin, fout):
@@ -236,7 +253,8 @@ if __name__ == "__main__":
parser = argparse.ArgumentParser()
parser.add_argument('--cmake-dir', nargs="?")
parser.add_argument('--limited-api', type=str2bool)
+ parser.add_argument('--quiet', action='store_true')
args = parser.parse_args()
if args.cmake_dir:
work_dir = os.path.abspath(args.cmake_dir)
- create_zipfile(args.limited_api)
+ create_zipfile(args.limited_api, args.quiet)
diff --git a/sources/shiboken2/libshiboken/embed/signature_bootstrap.py b/sources/shiboken2/libshiboken/embed/signature_bootstrap.py
index b7d9d279..90286426 100644
--- a/sources/shiboken2/libshiboken/embed/signature_bootstrap.py
+++ b/sources/shiboken2/libshiboken/embed/signature_bootstrap.py
@@ -77,10 +77,11 @@ def bootstrap():
recursion_trap += 1
@contextmanager
- def ensure_shibokensupport(support_path):
+ def ensure_shibokensupport(target, support_path):
# Make sure that we always have the shibokensupport containing package first.
# Also remove any prior loaded module of this name, just in case.
- sys.path.insert(0, support_path)
+ # PYSIDE-1621: support_path can also be a finder instance.
+ target.insert(0, support_path)
sbks = "shibokensupport"
if sbks in sys.modules:
@@ -100,7 +101,7 @@ def bootstrap():
print(" " + p)
sys.stdout.flush()
sys.exit(-1)
- sys.path.remove(support_path)
+ target.remove(support_path)
try:
import shiboken2 as root
@@ -110,14 +111,15 @@ def bootstrap():
rp = os.path.realpath(os.path.dirname(root.__file__))
# This can be the shiboken2 directory or the binary module, so search.
look_for = os.path.join("files.dir", "shibokensupport", "signature", "loader.py")
- while len(rp) > 3 and not os.path.exists(os.path.join(rp, look_for)):
- rp = os.path.abspath(os.path.join(rp, ".."))
+ while not os.path.exists(os.path.join(rp, look_for)):
+ dir = os.path.dirname(rp)
+ if dir == rp: # Hit root, '/', 'C:\', '\\server\share'
+ break
+ rp = dir
# Here we decide if we work embedded or not.
embedding_var = "pyside_uses_embedding"
use_embedding = bool(getattr(sys, embedding_var, False))
- # We keep the zip file for inspection if the sys variable has been set.
- keep_zipfile = hasattr(sys, embedding_var)
loader_path = os.path.join(rp, look_for)
files_dir = os.path.abspath(os.path.join(loader_path, "..", "..", ".."))
assert files_dir.endswith("files.dir")
@@ -128,41 +130,54 @@ def bootstrap():
support_path = prepare_zipfile() if use_embedding else files_dir
setattr(sys, embedding_var, use_embedding)
+ if use_embedding:
+ target, support_path = prepare_zipfile()
+ else:
+ target, support_path = sys.path, files_dir
+
try:
- with ensure_shibokensupport(support_path):
+ with ensure_shibokensupport(target, support_path):
from shibokensupport.signature import loader
except Exception as e:
print('Exception:', e)
traceback.print_exc(file=sys.stdout)
- finally:
- if use_embedding and not keep_zipfile:
- # clear the temp zipfile
- try:
- os.remove(support_path)
- except OSError as e:
- print(e)
- print("Error deleting {support_path}, ignored".format(**locals()))
- return loader
+ return loader
+
# New functionality: Loading from a zip archive.
# There exists the zip importer, but as it is written, only real zip files are
# supported. Before I will start an own implementation, it is easiest to use
# a temporary zip file.
+# PYSIDE-1621: make zip file access totally virtual
def prepare_zipfile():
"""
Write the zip file to a real file and return its name.
It will be implicitly opened as such when we add the name to sys.path .
+
+ New approach (Python 3, only):
+
+ Use EmbeddableZipImporter and pass the zipfile structure directly.
+ The sys.path way does not work, instead we need to use sys.meta_path .
+ See https://docs.python.org/3/library/sys.html#sys.meta_path
"""
import base64
- import tempfile
- import os
+ import io
+ import sys
import zipfile
# 'zipstring_sequence' comes from signature.cpp
zipbytes = base64.b64decode(''.join(zipstring_sequence))
+ if sys.version_info[0] >= 3:
+ vzip = zipfile.ZipFile(io.BytesIO(zipbytes))
+ return sys.meta_path, EmbeddableZipImporter(vzip)
+
+ # Old version for Python 2.7, only.
+ import os
+ import tempfile
+
fd, fname = tempfile.mkstemp(prefix='embedded.', suffix='.zip')
os.write(fd, zipbytes)
os.close(fd)
@@ -175,6 +190,45 @@ def prepare_zipfile():
print('Broken Zip File:', e)
traceback.print_exc(file=sys.stdout)
finally:
- return fname
+ return sys.path, fname
+
+
+class EmbeddableZipImporter(object):
+
+ def __init__(self, zip_file):
+ def p2m(filename):
+ if filename.endswith("/__init__.py"):
+ return filename[:-12].replace("/", ".")
+ if filename.endswith(".py"):
+ return filename[:-3].replace("/", ".")
+ return None
+
+ self.zfile = zip_file
+ self._path2mod = {_.filename : p2m(_.filename) for _ in zip_file.filelist}
+ self._mod2path = {_[1] : _[0] for _ in self._path2mod.items()}
+
+ def find_module(self, fullname, path):
+ return self if self._mod2path.get(fullname) else None
+
+ def load_module(self, fullname):
+ import importlib
+ import sys
+
+ filename = self._mod2path.get(fullname)
+ if filename not in self._path2mod:
+ raise ImportError(fullname)
+ module_spec = importlib.machinery.ModuleSpec(fullname, None)
+ new_module = importlib.util.module_from_spec(module_spec)
+ with self.zfile.open(filename, "r") as f: # "rb" not for zipfile
+ exec(f.read(), new_module.__dict__)
+ new_module.__file__ = filename
+ new_module.__loader__ = self
+ if filename.endswith("/__init__.py"):
+ new_module.__path__ = []
+ new_module.__package__ = fullname
+ else:
+ new_module.__package__ = fullname.rpartition('.')[0]
+ sys.modules[fullname] = new_module
+ return new_module
# eof
diff --git a/sources/shiboken2/libshiboken/pep384impl.cpp b/sources/shiboken2/libshiboken/pep384impl.cpp
index cb804256..a7233034 100644
--- a/sources/shiboken2/libshiboken/pep384impl.cpp
+++ b/sources/shiboken2/libshiboken/pep384impl.cpp
@@ -751,14 +751,16 @@ _Pep_PrivateMangle(PyObject *self, PyObject *name)
#endif // IS_PY2
Shiboken::AutoDecRef privateobj(PyObject_GetAttr(
reinterpret_cast<PyObject *>(Py_TYPE(self)), Shiboken::PyMagicName::name()));
-#ifndef Py_LIMITED_API
+#if !defined(Py_LIMITED_API) && PY_VERSION_HEX < 0x03010000
return _Py_Mangle(privateobj, name);
#else
- // For some reason, _Py_Mangle is not in the Limited API. Why?
- size_t plen = PyUnicode_GET_LENGTH(privateobj);
+ // PYSIDE-1436: _Py_Mangle is no longer exposed; implement it always.
+ // The rest of this function is our own implementation of _Py_Mangle.
+ // Please compare the original function in compile.c .
+ size_t plen = PyUnicode_GET_LENGTH(privateobj.object());
/* Strip leading underscores from class name */
size_t ipriv = 0;
- while (PyUnicode_READ_CHAR(privateobj, ipriv) == '_')
+ while (PyUnicode_READ_CHAR(privateobj.object(), ipriv) == '_')
ipriv++;
if (ipriv == plen) {
Py_INCREF(name);
diff --git a/sources/shiboken2/libshiboken/pep384impl.h b/sources/shiboken2/libshiboken/pep384impl.h
index 7a6f57fc..eb65596c 100644
--- a/sources/shiboken2/libshiboken/pep384impl.h
+++ b/sources/shiboken2/libshiboken/pep384impl.h
@@ -40,6 +40,11 @@
#ifndef PEP384IMPL_H
#define PEP384IMPL_H
+// PYSIDE-1436: Adapt to Python 3.10
+#if PY_VERSION_HEX < 0x030900A4
+# define Py_SET_REFCNT(obj, refcnt) ((Py_REFCNT(obj) = (refcnt)), (void)0)
+#endif
+
extern "C"
{
@@ -327,7 +332,7 @@ LIBSHIBOKEN_API PyObject *PyRun_String(const char *, int, PyObject *, PyObject *
// But this is no problem as we check it's validity for every version.
#define PYTHON_BUFFER_VERSION_COMPATIBLE (PY_VERSION_HEX >= 0x03030000 && \
- PY_VERSION_HEX < 0x0309FFFF)
+ PY_VERSION_HEX < 0x030AFFFF)
#if !PYTHON_BUFFER_VERSION_COMPATIBLE
# error Please check the buffer compatibility for this python version!
#endif
diff --git a/sources/shiboken2/libshiboken/qapp_macro.cpp b/sources/shiboken2/libshiboken/qapp_macro.cpp
deleted file mode 100644
index 3ef3a51c..00000000
--- a/sources/shiboken2/libshiboken/qapp_macro.cpp
+++ /dev/null
@@ -1,100 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of Qt for Python.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "basewrapper.h"
-#include "autodecref.h"
-
-extern "C"
-{
-
-#include "qapp_macro.h"
-
-////////////////////////////////////////////////////////////////////////////
-//
-// Support for the qApp macro.
-//
-// qApp is a macro in Qt5. In Python, we simulate that a little by a
-// variable that monitors Q*Application.instance().
-// This variable is also able to destroy the app by qApp.shutdown().
-//
-
-static PyObject *qApp_var = nullptr;
-static PyObject *qApp_content = nullptr;
-
-static PyObject *
-monitor_qApp_var(PyObject *qApp)
-{
- static bool init_done;
- static PyObject *builtins = PyEval_GetBuiltins();
-
- if (!init_done) {
- qApp_var = Py_BuildValue("s", "qApp");
- if (qApp_var == nullptr)
- return nullptr;
- // This is a borrowed reference
- Py_INCREF(builtins);
- init_done = true;
- }
-
- if (PyDict_SetItem(builtins, qApp_var, qApp) < 0)
- return nullptr;
- qApp_content = qApp;
- Py_INCREF(qApp);
- return qApp;
-}
-
-PyObject *
-MakeQAppWrapper(PyTypeObject *type)
-{
- if (type == nullptr)
- type = Py_TYPE(Py_None);
- if (!(type == Py_TYPE(Py_None) || Py_TYPE(qApp_content) == Py_TYPE(Py_None))) {
- 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 nullptr;
- }
- PyObject *self = type != Py_TYPE(Py_None) ? PyObject_New(PyObject, type) : Py_None;
- return monitor_qApp_var(self);
-}
-
-} //extern "C"
-
-// end of module
diff --git a/sources/shiboken2/libshiboken/qapp_macro.h b/sources/shiboken2/libshiboken/qapp_macro.h
deleted file mode 100644
index 9abd17c1..00000000
--- a/sources/shiboken2/libshiboken/qapp_macro.h
+++ /dev/null
@@ -1,52 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of Qt for Python.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef QAPP_MACRO_H
-#define QAPP_MACRO_H
-
-#include "sbkpython.h"
-
-extern "C"
-{
-
-LIBSHIBOKEN_API PyObject *MakeQAppWrapper(PyTypeObject *type);
-
-} // extern "C"
-
-#endif // QAPP_MACRO_H
diff --git a/sources/shiboken2/libshiboken/sbkarrayconverter.cpp b/sources/shiboken2/libshiboken/sbkarrayconverter.cpp
index fd09efda..b828aa8e 100644
--- a/sources/shiboken2/libshiboken/sbkarrayconverter.cpp
+++ b/sources/shiboken2/libshiboken/sbkarrayconverter.cpp
@@ -90,7 +90,6 @@ SbkArrayConverter *createArrayConverter(IsArrayConvertibleToCppFunc toCppCheckFu
static PythonToCppFunc unimplementedArrayCheck(PyObject *, int, int)
{
- warning(PyExc_RuntimeWarning, 0, "SbkConverter: Unimplemented C++ array type.");
return nullptr;
}
diff --git a/sources/shiboken2/libshiboken/sbkconverter_p.h b/sources/shiboken2/libshiboken/sbkconverter_p.h
index d8716207..6febaa14 100644
--- a/sources/shiboken2/libshiboken/sbkconverter_p.h
+++ b/sources/shiboken2/libshiboken/sbkconverter_p.h
@@ -539,7 +539,7 @@ struct Primitive<std::nullptr_t> : TwoPrimitive<std::nullptr_t>
{
static PyObject *toPython(const void * /* cppIn */)
{
- return Py_None;
+ Py_RETURN_NONE;
}
static void toCpp(PyObject *, void *cppOut)
{
diff --git a/sources/shiboken2/libshiboken/sbkenum.cpp b/sources/shiboken2/libshiboken/sbkenum.cpp
index 369b264e..7dc73dfb 100644
--- a/sources/shiboken2/libshiboken/sbkenum.cpp
+++ b/sources/shiboken2/libshiboken/sbkenum.cpp
@@ -46,13 +46,13 @@
#include "sbkdbg.h"
#include "autodecref.h"
#include "sbkpython.h"
+#include "signature.h"
#include <string.h>
#include <cstring>
#include <vector>
-#define SBK_ENUM(ENUM) reinterpret_cast<SbkEnumObject *>(ENUM)
-#define SBK_TYPE_CHECK(o) (strcmp(Py_TYPE(Py_TYPE(o))->tp_name, "Shiboken.EnumType") == 0)
+#define SbkEnumType_Check(o) (Py_TYPE(Py_TYPE(o)) == SbkEnumType_TypeF())
typedef PyObject *(*enum_func)(PyObject *, PyObject *);
extern "C"
@@ -77,9 +77,11 @@ struct SbkEnumObject
PyObject *ob_name;
};
+static PyTypeObject *SbkEnum_TypeF(); // forward
+
static PyObject *SbkEnumObject_repr(PyObject *self)
{
- const SbkEnumObject *enumObj = SBK_ENUM(self);
+ const SbkEnumObject *enumObj = reinterpret_cast<SbkEnumObject *>(self);
if (enumObj->ob_name)
return Shiboken::String::fromFormat("%s.%s", (Py_TYPE(self))->tp_name, PyBytes_AS_STRING(enumObj->ob_name));
else
@@ -88,7 +90,7 @@ static PyObject *SbkEnumObject_repr(PyObject *self)
static PyObject *SbkEnumObject_name(PyObject *self, void *)
{
- auto *enum_self = SBK_ENUM(self);
+ auto *enum_self = reinterpret_cast<SbkEnumObject *>(self);
if (enum_self->ob_name == nullptr)
Py_RETURN_NONE;
@@ -103,6 +105,11 @@ static PyObject *SbkEnum_tp_new(PyTypeObject *type, PyObject *args, PyObject *)
if (!PyArg_ParseTuple(args, "|l:__new__", &itemValue))
return nullptr;
+ if (type == SbkEnum_TypeF()) {
+ PyErr_Format(PyExc_TypeError, "You cannot use %s directly", type->tp_name);
+ return nullptr;
+ }
+
SbkEnumObject *self = PyObject_New(SbkEnumObject, type);
if (!self)
return nullptr;
@@ -112,6 +119,11 @@ static PyObject *SbkEnum_tp_new(PyTypeObject *type, PyObject *args, PyObject *)
return reinterpret_cast<PyObject *>(self);
}
+static const char *SbkEnum_SignatureStrings[] = {
+ "Shiboken.Enum(self,itemValue:int=0)",
+ nullptr}; // Sentinel
+
+
void enum_object_dealloc(PyObject *ob)
{
auto self = reinterpret_cast<SbkEnumObject *>(ob);
@@ -129,12 +141,12 @@ static PyObject *enum_op(enum_func f, PyObject *a, PyObject *b) {
// We are not allowing floats
if (!PyFloat_Check(valA) && !PyFloat_Check(valB)) {
// Check if both variables are SbkEnumObject
- if (SBK_TYPE_CHECK(valA)) {
- valA = PyLong_FromLong(SBK_ENUM(valA)->ob_value);
+ if (SbkEnumType_Check(valA)) {
+ valA = PyLong_FromLong(reinterpret_cast<SbkEnumObject *>(valA)->ob_value);
enumA = true;
}
- if (SBK_TYPE_CHECK(valB)) {
- valB = PyLong_FromLong(SBK_ENUM(valB)->ob_value);
+ if (SbkEnumType_Check(valB)) {
+ valB = PyLong_FromLong(reinterpret_cast<SbkEnumObject *>(valB)->ob_value);
enumB = true;
}
}
@@ -152,7 +164,6 @@ static PyObject *enum_op(enum_func f, PyObject *a, PyObject *b) {
Py_DECREF(valA);
if (enumB)
Py_DECREF(valB);
-
return result;
}
@@ -166,7 +177,7 @@ static PyObject *enum_op(enum_func f, PyObject *a, PyObject *b) {
*/
static PyObject *enum_int(PyObject *v)
{
- return PyInt_FromLong(SBK_ENUM(v)->ob_value);
+ return PyInt_FromLong(reinterpret_cast<SbkEnumObject *>(v)->ob_value);
}
static PyObject *enum_and(PyObject *self, PyObject *b)
@@ -176,7 +187,7 @@ static PyObject *enum_and(PyObject *self, PyObject *b)
static PyObject *enum_or(PyObject *self, PyObject *b)
{
-return enum_op(PyNumber_Or, self, b);
+ return enum_op(PyNumber_Or, self, b);
}
static PyObject *enum_xor(PyObject *self, PyObject *b)
@@ -186,7 +197,7 @@ static PyObject *enum_xor(PyObject *self, PyObject *b)
static int enum_bool(PyObject *v)
{
- return (SBK_ENUM(v)->ob_value > 0);
+ return (reinterpret_cast<SbkEnumObject *>(v)->ob_value > 0);
}
static PyObject *enum_add(PyObject *self, PyObject *v)
@@ -201,7 +212,7 @@ static PyObject *enum_subtract(PyObject *self, PyObject *v)
static PyObject *enum_multiply(PyObject *self, PyObject *v)
{
-return enum_op(PyNumber_Multiply, self, v);
+ return enum_op(PyNumber_Multiply, self, v);
}
#ifndef IS_PY3K
@@ -223,12 +234,12 @@ static PyObject *enum_richcompare(PyObject *self, PyObject *other, int op)
if (!PyFloat_Check(valA) && !PyFloat_Check(valB)) {
// Check if both variables are SbkEnumObject
- if (SBK_TYPE_CHECK(valA)) {
- valA = PyLong_FromLong(SBK_ENUM(valA)->ob_value);
+ if (SbkEnumType_Check(valA)) {
+ valA = PyLong_FromLong(reinterpret_cast<SbkEnumObject *>(valA)->ob_value);
enumA = true;
}
- if (SBK_TYPE_CHECK(valB)) {
- valB = PyLong_FromLong(SBK_ENUM(valB)->ob_value);
+ if (SbkEnumType_Check(valB)) {
+ valB = PyLong_FromLong(reinterpret_cast<SbkEnumObject *>(valB)->ob_value);
enumB =true;
}
}
@@ -284,24 +295,6 @@ static PyObject *SbkEnumTypeTpNew(PyTypeObject *metatype, PyObject *args, PyObje
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
- {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_base, (void *)&PyType_Type},
{Py_tp_alloc, (void *)PyType_GenericAlloc},
{Py_tp_new, (void *)SbkEnumTypeTpNew},
@@ -312,7 +305,7 @@ static PyType_Slot SbkEnumType_Type_slots[] = {
{0, nullptr}
};
static PyType_Spec SbkEnumType_Type_spec = {
- "1:Shiboken.EnumType",
+ "1:Shiboken.EnumMeta",
0, // filled in later
sizeof(PyMemberDef),
Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE|Py_TPFLAGS_CHECKTYPES,
@@ -370,8 +363,6 @@ PyObject *SbkEnumTypeTpNew(PyTypeObject *metatype, PyObject *args, PyObject *kwd
//
extern "C" {
-static void init_enum(); // forward
-
static PyObject *enum_unpickler = nullptr;
// Pickling: reduce the Qt Enum object
@@ -441,16 +432,23 @@ static bool _init_enum()
PyErr_Clear();
mod = shibo.object();
}
+ // publish Shiboken.Enum so that the signature gets initialized
+ if (PyObject_SetAttrString(mod, "Enum", reinterpret_cast<PyObject *>(SbkEnum_TypeF())) < 0)
+ return false;
+ if (InitSignatureStrings(SbkEnum_TypeF(), SbkEnum_SignatureStrings) < 0)
+ return false;
enum_unpickler = PyObject_GetAttrString(mod, "_unpickle_enum");
if (enum_unpickler == nullptr)
return false;
return true;
}
-static void init_enum()
+void init_enum()
{
- if (!(enum_unpickler || _init_enum()))
+ static bool is_initialized = false;
+ if (!(is_initialized || enum_unpickler || _init_enum()))
Py_FatalError("could not load enum pickling helper function");
+ is_initialized = true;
}
static PyMethodDef SbkEnumObject_Methods[] = {
@@ -507,7 +505,6 @@ 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, flagsType);
@@ -520,7 +517,7 @@ static PyTypeObject *createEnum(const char *fullName, const char *cppName,
PyTypeObject *createGlobalEnum(PyObject *module, const char *name, const char *fullName, const char *cppName, PyTypeObject *flagsType)
{
- PyTypeObject *enumType = createEnum(fullName, cppName, name, flagsType);
+ PyTypeObject *enumType = createEnum(fullName, cppName, flagsType);
if (enumType && PyModule_AddObject(module, name, reinterpret_cast<PyObject *>(enumType)) < 0) {
Py_DECREF(enumType);
return nullptr;
@@ -535,7 +532,7 @@ 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);
+ PyTypeObject *enumType = createEnum(fullName, cppName, flagsType);
if (enumType && PyDict_SetItemString(reinterpret_cast<PyTypeObject *>(scope)->tp_dict, name,
reinterpret_cast<PyObject *>(enumType)) < 0) {
Py_DECREF(enumType);
@@ -625,7 +622,10 @@ newItem(PyTypeObject *enumType, long itemValue, const char *itemName)
return reinterpret_cast<PyObject *>(enumObj);
}
-static PyType_Slot SbkNewType_slots[] = {
+} // namespace Shiboken
+} // namespace Enum
+
+static PyType_Slot SbkNewEnum_slots[] = {
{Py_tp_repr, (void *)SbkEnumObject_repr},
{Py_tp_str, (void *)SbkEnumObject_repr},
{Py_tp_getset, (void *)SbkEnumGetSetList},
@@ -654,14 +654,22 @@ static PyType_Slot SbkNewType_slots[] = {
{Py_tp_dealloc, (void *)enum_object_dealloc},
{0, nullptr}
};
-static PyType_Spec SbkNewType_spec = {
- "missing Enum name", // to be inserted later
+static PyType_Spec SbkNewEnum_spec = {
+ "1:Shiboken.Enum",
sizeof(SbkEnumObject),
0,
- Py_TPFLAGS_DEFAULT|Py_TPFLAGS_CHECKTYPES,
- SbkNewType_slots,
+ Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE|Py_TPFLAGS_CHECKTYPES,
+ SbkNewEnum_slots,
};
+static PyTypeObject *SbkEnum_TypeF()
+{
+ static auto type = SbkType_FromSpec(&SbkNewEnum_spec);
+ return reinterpret_cast<PyTypeObject *>(type);
+}
+
+namespace Shiboken { namespace Enum {
+
static void
copyNumberMethods(PyTypeObject *flagsType,
PyType_Slot number_slots[],
@@ -727,20 +735,25 @@ newTypeWithName(const char *name,
PyType_Slot newslots[99] = {}; // enough but not too big for the stack
PyType_Spec newspec;
newspec.name = strdup(name);
- newspec.basicsize = SbkNewType_spec.basicsize;
- newspec.itemsize = SbkNewType_spec.itemsize;
- newspec.flags = SbkNewType_spec.flags;
+ newspec.basicsize = SbkNewEnum_spec.basicsize;
+ newspec.itemsize = SbkNewEnum_spec.itemsize;
+ newspec.flags = SbkNewEnum_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;
+ while (SbkNewEnum_slots[idx].slot) {
+ newslots[idx].slot = SbkNewEnum_slots[idx].slot;
+ newslots[idx].pfunc = SbkNewEnum_slots[idx].pfunc;
++idx;
}
if (numbers_fromFlag)
copyNumberMethods(numbers_fromFlag, newslots, &idx);
newspec.slots = newslots;
- auto *type = reinterpret_cast<PyTypeObject *>(SbkType_FromSpec(&newspec));
+ Shiboken::AutoDecRef bases(PyTuple_New(1));
+ static auto basetype = SbkEnum_TypeF();
+ Py_INCREF(basetype);
+ PyTuple_SetItem(bases, 0, reinterpret_cast<PyObject *>(basetype));
+ auto *type = reinterpret_cast<PyTypeObject *>(SbkType_FromSpecWithBases(&newspec, bases));
+ PyErr_Print();
Py_TYPE(type) = SbkEnumType_TypeF();
auto *enumType = reinterpret_cast<SbkEnumType *>(type);
diff --git a/sources/shiboken2/libshiboken/sbkenum.h b/sources/shiboken2/libshiboken/sbkenum.h
index c294c17d..236f4a15 100644
--- a/sources/shiboken2/libshiboken/sbkenum.h
+++ b/sources/shiboken2/libshiboken/sbkenum.h
@@ -46,6 +46,9 @@
extern "C"
{
+/// exposed for the signature module
+LIBSHIBOKEN_API void init_enum();
+
extern LIBSHIBOKEN_API PyTypeObject *SbkEnumType_TypeF(void);
struct SbkObjectType;
struct SbkConverter;
diff --git a/sources/shiboken2/libshiboken/sbkstaticstrings.cpp b/sources/shiboken2/libshiboken/sbkstaticstrings.cpp
index 5559d58d..58d32f21 100644
--- a/sources/shiboken2/libshiboken/sbkstaticstrings.cpp
+++ b/sources/shiboken2/libshiboken/sbkstaticstrings.cpp
@@ -58,7 +58,10 @@ STATIC_STRING_IMPL(fset, "fset")
STATIC_STRING_IMPL(loads, "loads")
STATIC_STRING_IMPL(multi, "multi")
STATIC_STRING_IMPL(name, "name")
+STATIC_STRING_IMPL(qApp, "qApp")
STATIC_STRING_IMPL(result, "result")
+STATIC_STRING_IMPL(select_id, "select_id")
+STATIC_STRING_IMPL(underscore, "_")
STATIC_STRING_IMPL(value, "value")
STATIC_STRING_IMPL(values, "values")
@@ -87,6 +90,7 @@ STATIC_STRING_IMPL(get, "__get__")
STATIC_STRING_IMPL(members, "__members__")
STATIC_STRING_IMPL(module, "__module__")
STATIC_STRING_IMPL(name, "__name__")
+STATIC_STRING_IMPL(property_methods, "__property_methods__")
STATIC_STRING_IMPL(qualname, "__qualname__")
STATIC_STRING_IMPL(self, "__self__")
diff --git a/sources/shiboken2/libshiboken/sbkstaticstrings.h b/sources/shiboken2/libshiboken/sbkstaticstrings.h
index b72fa989..4aaef814 100644
--- a/sources/shiboken2/libshiboken/sbkstaticstrings.h
+++ b/sources/shiboken2/libshiboken/sbkstaticstrings.h
@@ -58,6 +58,8 @@ LIBSHIBOKEN_API PyObject *loads();
LIBSHIBOKEN_API PyObject *multi();
LIBSHIBOKEN_API PyObject *name();
LIBSHIBOKEN_API PyObject *result();
+LIBSHIBOKEN_API PyObject *select_id();
+LIBSHIBOKEN_API PyObject *underscore();
LIBSHIBOKEN_API PyObject *value();
LIBSHIBOKEN_API PyObject *values();
} // namespace PyName
@@ -69,10 +71,12 @@ LIBSHIBOKEN_API PyObject *dict();
LIBSHIBOKEN_API PyObject *doc();
LIBSHIBOKEN_API PyObject *ecf();
LIBSHIBOKEN_API PyObject *file();
+LIBSHIBOKEN_API PyObject *func();
LIBSHIBOKEN_API PyObject *get();
LIBSHIBOKEN_API PyObject *members();
LIBSHIBOKEN_API PyObject *module();
LIBSHIBOKEN_API PyObject *name();
+LIBSHIBOKEN_API PyObject *property_methods();
LIBSHIBOKEN_API PyObject *qualname();
LIBSHIBOKEN_API PyObject *self();
} // namespace PyMagicName
diff --git a/sources/shiboken2/libshiboken/sbkstaticstrings_p.h b/sources/shiboken2/libshiboken/sbkstaticstrings_p.h
index c33fa029..419eeeb1 100644
--- a/sources/shiboken2/libshiboken/sbkstaticstrings_p.h
+++ b/sources/shiboken2/libshiboken/sbkstaticstrings_p.h
@@ -51,6 +51,7 @@ PyObject *marshal();
PyObject *method();
PyObject *mro();
PyObject *overload();
+PyObject *qApp();
PyObject *staticmethod();
} // namespace PyName
namespace PyMagicName
diff --git a/sources/shiboken2/libshiboken/sbkstring.cpp b/sources/shiboken2/libshiboken/sbkstring.cpp
index 918aae75..077fb531 100644
--- a/sources/shiboken2/libshiboken/sbkstring.cpp
+++ b/sources/shiboken2/libshiboken/sbkstring.cpp
@@ -247,7 +247,7 @@ static void finalizeStaticStrings()
{
auto &set = staticStrings();
for (PyObject *ob : set) {
- Py_REFCNT(ob) = 1;
+ Py_SET_REFCNT(ob, 1);
Py_DECREF(ob);
}
set.clear();
diff --git a/sources/shiboken2/libshiboken/shibokenbuffer.cpp b/sources/shiboken2/libshiboken/shibokenbuffer.cpp
index dd6e4632..8d44878a 100644
--- a/sources/shiboken2/libshiboken/shibokenbuffer.cpp
+++ b/sources/shiboken2/libshiboken/shibokenbuffer.cpp
@@ -74,6 +74,29 @@ void *Shiboken::Buffer::getPointer(PyObject *pyObj, Py_ssize_t *size)
return const_cast<void *>(buffer);
}
+void *Shiboken::Buffer::copyData(PyObject *pyObj, Py_ssize_t *sizeIn)
+{
+ void *result = nullptr;
+ Py_ssize_t size = 0;
+
+ Py_buffer view;
+ if (PyObject_GetBuffer(pyObj, &view, PyBUF_ND) == 0) {
+ size = view.len;
+ if (size) {
+ result = std::malloc(size);
+ if (result != nullptr)
+ std::memcpy(result, view.buf, size);
+ else
+ size = 0;
+ }
+ PyBuffer_Release(&view);
+ }
+
+ if (sizeIn != nullptr)
+ *sizeIn = size;
+ return result;
+}
+
PyObject *Shiboken::Buffer::newObject(void *memory, Py_ssize_t size, Type type)
{
if (size == 0)
diff --git a/sources/shiboken2/libshiboken/shibokenbuffer.h b/sources/shiboken2/libshiboken/shibokenbuffer.h
index dc9f8d89..512d9db4 100644
--- a/sources/shiboken2/libshiboken/shibokenbuffer.h
+++ b/sources/shiboken2/libshiboken/shibokenbuffer.h
@@ -79,6 +79,14 @@ namespace Buffer
*/
LIBSHIBOKEN_API void *getPointer(PyObject *pyObj, Py_ssize_t *size = nullptr);
+ /**
+ * Returns a copy of the buffer data which should be free'd.
+ *
+ * If the \p pyObj is a non-contiguous buffer a Python error is set.
+ * nullptr is returned for empty buffers.
+ */
+ LIBSHIBOKEN_API void *copyData(PyObject *pyObj, Py_ssize_t *size = nullptr);
+
} // namespace Buffer
} // namespace Shiboken
diff --git a/sources/shiboken2/libshiboken/signature.h b/sources/shiboken2/libshiboken/signature.h
index b77cc0f4..0459d866 100644
--- a/sources/shiboken2/libshiboken/signature.h
+++ b/sources/shiboken2/libshiboken/signature.h
@@ -45,7 +45,7 @@ extern "C"
LIBSHIBOKEN_API int InitSignatureStrings(PyTypeObject *, const char *[]);
LIBSHIBOKEN_API void FinishSignatureInitialization(PyObject *, const char *[]);
-LIBSHIBOKEN_API void SetError_Argument(PyObject *, const char *);
+LIBSHIBOKEN_API void SetError_Argument(PyObject *, const char *, PyObject *);
LIBSHIBOKEN_API PyObject *Sbk_TypeGet___signature__(PyObject *, PyObject *);
LIBSHIBOKEN_API PyObject *Sbk_TypeGet___doc__(PyObject *);
LIBSHIBOKEN_API PyObject *GetFeatureDict();
diff --git a/sources/shiboken2/libshiboken/signature/signature.cpp b/sources/shiboken2/libshiboken/signature/signature.cpp
index 085d751a..3051c50d 100644
--- a/sources/shiboken2/libshiboken/signature/signature.cpp
+++ b/sources/shiboken2/libshiboken/signature/signature.cpp
@@ -209,8 +209,12 @@ PyObject *GetSignature_Wrapper(PyObject *ob, PyObject *modifier)
if (dict == nullptr)
return nullptr;
PyObject *props = PyDict_GetItem(dict, func_name);
- if (props == nullptr)
+ if (props == nullptr) {
+ // handle `__init__` like the class itself
+ if (strcmp(String::toCString(func_name), "__init__") == 0)
+ return GetSignature_TypeMod(objclass, modifier);
Py_RETURN_NONE;
+ }
return _GetSignature_Cached(props, PyName::method(), modifier);
}
@@ -431,7 +435,86 @@ void FinishSignatureInitialization(PyObject *module, const char *signatures[])
}
}
-void SetError_Argument(PyObject *args, const char *func_name)
+static PyObject *adjustFuncName(const char *func_name)
+{
+ /*
+ * PYSIDE-1019: Modify the function name expression according to feature.
+ *
+ * - snake_case
+ * The function name must be converted.
+ * - full_property
+ * The property name must be used and "fset" appended.
+ *
+ * modname.subname.classsname.propname.fset
+ *
+ * Class properties must use the expression
+ *
+ * modname.subname.classsname.__dict__['propname'].fset
+ *
+ * Note that fget is impossible because there are no parameters.
+ */
+ static const char mapping_name[] = "shibokensupport.signature.mapping";
+ static PyObject *sys_modules = PySys_GetObject(const_cast<char *>("modules"));
+ static PyObject *mapping = PyDict_GetItemString(sys_modules, mapping_name);
+ static PyObject *ns = PyModule_GetDict(mapping);
+
+ char _path[200 + 1] = {};
+ const char *_name = strrchr(func_name, '.');
+ strncat(_path, func_name, _name - func_name);
+ ++_name;
+
+ // This is a very cheap call into `mapping.py`.
+ PyObject *update_mapping = PyDict_GetItemString(ns, "update_mapping");
+ AutoDecRef res(PyObject_CallFunctionObjArgs(update_mapping, nullptr));
+ if (res.isNull())
+ return nullptr;
+
+ // Run `eval` on the type string to get the object.
+ AutoDecRef obtype(PyRun_String(_path, Py_eval_input, ns, ns));
+ if (PyModule_Check(obtype.object())) {
+ // This is a plain function. Return the unmangled name.
+ return String::fromCString(func_name);
+ }
+ assert(PyType_Check(obtype)); // This was not true for __init__!
+
+ // Find the feature flags
+ auto type = reinterpret_cast<PyTypeObject *>(obtype.object());
+ auto dict = type->tp_dict;
+ int id = SbkObjectType_GetReserved(type);
+ id = id < 0 ? 0 : id; // if undefined, set to zero
+ auto lower = id & 0x01;
+ auto is_prop = id & 0x02;
+ bool is_class_prop = false;
+
+ // Compute all needed info.
+ PyObject *name = String::getSnakeCaseName(_name, lower);
+ PyObject *prop_name;
+ if (is_prop) {
+ PyObject *prop_methods = PyDict_GetItem(dict, PyMagicName::property_methods());
+ prop_name = PyDict_GetItem(prop_methods, name);
+ if (prop_name != nullptr) {
+ PyObject *prop = PyDict_GetItem(dict, prop_name);
+ is_class_prop = Py_TYPE(prop) != &PyProperty_Type;
+ }
+ }
+
+ // Finally, generate the correct path expression.
+ char _buf[250 + 1] = {};
+ if (is_prop) {
+ auto _prop_name = String::toCString(prop_name);
+ if (is_class_prop)
+ sprintf(_buf, "%s.__dict__['%s'].fset", _path, _prop_name);
+ else
+ sprintf(_buf, "%s.%s.fset", _path, _prop_name);
+ }
+ else {
+ auto _name = String::toCString(name);
+ sprintf(_buf, "%s.%s", _path, _name);
+ }
+ return String::fromCString(_buf);
+}
+
+void SetError_Argument(PyObject *args, const char *func_name, PyObject *info)
{
/*
* This function replaces the type error construction with extra
@@ -440,8 +523,24 @@ void SetError_Argument(PyObject *args, const char *func_name)
*/
init_module_1();
init_module_2();
- AutoDecRef res(PyObject_CallFunction(pyside_globals->seterror_argument_func,
- const_cast<char *>("(Os)"), args, func_name));
+
+ // PYSIDE-1305: Handle errors set by fillQtProperties.
+ if (PyErr_Occurred()) {
+ PyObject *e, *v, *t;
+ // Note: These references are all borrowed.
+ PyErr_Fetch(&e, &v, &t);
+ info = v;
+ }
+ // PYSIDE-1019: Modify the function name expression according to feature.
+ AutoDecRef new_func_name(adjustFuncName(func_name));
+ if (new_func_name.isNull()) {
+ PyErr_Print();
+ Py_FatalError("seterror_argument failed to call update_mapping");
+ }
+ if (info == nullptr)
+ info = Py_None;
+ AutoDecRef res(PyObject_CallFunctionObjArgs(pyside_globals->seterror_argument_func,
+ args, new_func_name.object(), info, nullptr));
if (res.isNull()) {
PyErr_Print();
Py_FatalError("seterror_argument did not receive a result");
diff --git a/sources/shiboken2/libshiboken/signature/signature_globals.cpp b/sources/shiboken2/libshiboken/signature/signature_globals.cpp
index 6af64682..81810280 100644
--- a/sources/shiboken2/libshiboken/signature/signature_globals.cpp
+++ b/sources/shiboken2/libshiboken/signature/signature_globals.cpp
@@ -48,6 +48,7 @@
#include "sbkstring.h"
#include "sbkstaticstrings.h"
#include "sbkstaticstrings_p.h"
+#include "sbkenum.h"
#include "signature_p.h"
@@ -109,7 +110,7 @@ static safe_globals_struc *init_phase_1(PyMethodDef *init_meth)
if (compile == nullptr)
goto error;
AutoDecRef code_obj(PyObject_CallFunction(compile, "Oss",
- bytes.object(), "(builtin)", "exec"));
+ bytes.object(), "signature_bootstrap.py", "exec"));
#else
AutoDecRef code_obj(PyObject_CallFunctionObjArgs(
loads, bytes.object(), nullptr));
@@ -289,6 +290,8 @@ void init_module_2(void)
// Therefore we set init_done prior to init_phase_2().
init_done = 1;
init_phase_2(pyside_globals, signature_methods);
+ // Enum must be initialized when signatures exist, not earlier.
+ init_enum();
}
}
diff --git a/sources/shiboken2/shiboken_version.py b/sources/shiboken2/shiboken_version.py
index 009db0bf..9ec9b0e7 100644
--- a/sources/shiboken2/shiboken_version.py
+++ b/sources/shiboken2/shiboken_version.py
@@ -39,7 +39,7 @@
major_version = "5"
minor_version = "15"
-patch_version = "2"
+patch_version = "7"
# For example: "a", "b", "rc"
# (which means "alpha", "beta", "release candidate").
diff --git a/sources/shiboken2/shibokenmodule/CMakeLists.txt b/sources/shiboken2/shibokenmodule/CMakeLists.txt
index b14de5c9..9b2b5852 100644
--- a/sources/shiboken2/shibokenmodule/CMakeLists.txt
+++ b/sources/shiboken2/shibokenmodule/CMakeLists.txt
@@ -42,37 +42,12 @@ install(FILES "${CMAKE_CURRENT_BINARY_DIR}/_config.py"
configure_file("${CMAKE_CURRENT_SOURCE_DIR}/__init__.py.in"
"${CMAKE_CURRENT_BINARY_DIR}/__init__.py" @ONLY)
-configure_file("${CMAKE_CURRENT_SOURCE_DIR}/files.dir/shibokensupport/__feature__.py"
- "${CMAKE_CURRENT_BINARY_DIR}/files.dir/shibokensupport/__feature__.py" COPYONLY)
-configure_file("${CMAKE_CURRENT_SOURCE_DIR}/files.dir/shibokensupport/__init__.py"
- "${CMAKE_CURRENT_BINARY_DIR}/files.dir/shibokensupport/__init__.py" COPYONLY)
-configure_file("${CMAKE_CURRENT_SOURCE_DIR}/files.dir/shibokensupport/signature/__init__.py"
- "${CMAKE_CURRENT_BINARY_DIR}/files.dir/shibokensupport/signature/__init__.py" COPYONLY)
-configure_file("${CMAKE_CURRENT_SOURCE_DIR}/files.dir/shibokensupport/signature/errorhandler.py"
- "${CMAKE_CURRENT_BINARY_DIR}/files.dir/shibokensupport/signature/errorhandler.py" COPYONLY)
-configure_file("${CMAKE_CURRENT_SOURCE_DIR}/files.dir/shibokensupport/signature/layout.py"
- "${CMAKE_CURRENT_BINARY_DIR}/files.dir/shibokensupport/signature/layout.py" COPYONLY)
-configure_file("${CMAKE_CURRENT_SOURCE_DIR}/files.dir/shibokensupport/signature/loader.py"
- "${CMAKE_CURRENT_BINARY_DIR}/files.dir/shibokensupport/signature/loader.py" COPYONLY)
-configure_file("${CMAKE_CURRENT_SOURCE_DIR}/files.dir/shibokensupport/signature/importhandler.py"
- "${CMAKE_CURRENT_BINARY_DIR}/files.dir/shibokensupport/signature/importhandler.py" COPYONLY)
-configure_file("${CMAKE_CURRENT_SOURCE_DIR}/files.dir/shibokensupport/signature/mapping.py"
- "${CMAKE_CURRENT_BINARY_DIR}/files.dir/shibokensupport/signature/mapping.py" COPYONLY)
-configure_file("${CMAKE_CURRENT_SOURCE_DIR}/files.dir/shibokensupport/signature/parser.py"
- "${CMAKE_CURRENT_BINARY_DIR}/files.dir/shibokensupport/signature/parser.py" COPYONLY)
-configure_file("${CMAKE_CURRENT_SOURCE_DIR}/files.dir/shibokensupport/signature/lib/__init__.py"
- "${CMAKE_CURRENT_BINARY_DIR}/files.dir/shibokensupport/signature/lib/__init__.py" COPYONLY)
-configure_file("${CMAKE_CURRENT_SOURCE_DIR}/files.dir/shibokensupport/signature/lib/enum_sig.py"
- "${CMAKE_CURRENT_BINARY_DIR}/files.dir/shibokensupport/signature/lib/enum_sig.py" COPYONLY)
-configure_file("${CMAKE_CURRENT_SOURCE_DIR}/files.dir/shibokensupport/signature/lib/tool.py"
- "${CMAKE_CURRENT_BINARY_DIR}/files.dir/shibokensupport/signature/lib/tool.py" COPYONLY)
-if (PYTHON_VERSION_MAJOR EQUAL 3)
-else()
- configure_file("${CMAKE_CURRENT_SOURCE_DIR}/files.dir/shibokensupport/backport_inspect.py"
- "${CMAKE_CURRENT_BINARY_DIR}/files.dir/shibokensupport/backport_inspect.py" COPYONLY)
- configure_file("${CMAKE_CURRENT_SOURCE_DIR}/files.dir/shibokensupport/typing27.py"
- "${CMAKE_CURRENT_BINARY_DIR}/files.dir/shibokensupport/typing27.py" COPYONLY)
-endif()
+# Variable from enclosing scope.
+foreach(item IN LISTS shiboken_python_files)
+ configure_file("${CMAKE_CURRENT_SOURCE_DIR}/files.dir/shibokensupport/${item}"
+ "${CMAKE_CURRENT_BINARY_DIR}/files.dir/shibokensupport/${item}" COPYONLY)
+endforeach()
+
install(DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/files.dir"
DESTINATION "${PYTHON_SITE_PACKAGES}/shiboken2")
diff --git a/sources/shiboken2/shibokenmodule/files.dir/shibokensupport/__feature__.py b/sources/shiboken2/shibokenmodule/files.dir/shibokensupport/feature.py
similarity index 95%
rename from sources/shiboken2/shibokenmodule/files.dir/shibokensupport/__feature__.py
rename to sources/shiboken2/shibokenmodule/files.dir/shibokensupport/feature.py
index ece3d2ed..e2edfe39 100644
--- a/sources/shiboken2/shibokenmodule/files.dir/shibokensupport/__feature__.py
+++ b/sources/shiboken2/shibokenmodule/files.dir/shibokensupport/feature.py
@@ -132,13 +132,10 @@ def _import(name, *args, **kwargs):
sys.modules["PySide2.QtCore"].__init_feature__()
return sys.modules["__feature__"]
- if name.split(".")[0] == "PySide2":
- # This is a module that imports PySide2.
- flag = existing if isinstance(existing, int) else 0
- else:
- # This is some other module. Ignore it in switching.
- flag = -1
- pyside_feature_dict[importing_module] = flag
+ if importing_module not in pyside_feature_dict:
+ # Ignore new modules if not from PySide.
+ default = 0 if name.split(".")[0] == "PySide2" else -1
+ pyside_feature_dict[importing_module] = default
return original_import(name, *args, **kwargs)
_is_initialized = False
diff --git a/sources/shiboken2/shibokenmodule/files.dir/shibokensupport/signature/errorhandler.py b/sources/shiboken2/shibokenmodule/files.dir/shibokensupport/signature/errorhandler.py
index 6ed4c0ed..352644f7 100644
--- a/sources/shiboken2/shibokenmodule/files.dir/shibokensupport/signature/errorhandler.py
+++ b/sources/shiboken2/shibokenmodule/files.dir/shibokensupport/signature/errorhandler.py
@@ -95,15 +95,33 @@ def matched_type(args, sigs):
return None
-def seterror_argument(args, func_name):
- update_mapping()
+def seterror_argument(args, func_name, info):
func = None
try:
func = eval(func_name, namespace)
except Exception as e:
- msg = "Internal error evaluating " + func_name + " :" + str(e)
+ msg = "Internal error evaluating {func_name}: {e}".format(**locals())
return TypeError, msg
+ if info and type(info) is str:
+ err = TypeError
+ if info == "<":
+ msg = "{func_name}(): not enough arguments".format(**locals())
+ elif info == ">":
+ msg = "{func_name}(): too many arguments".format(**locals())
+ elif info.isalnum():
+ msg = "{func_name}(): got multiple values for keyword argument '{info}'".format(**locals())
+ else:
+ msg = "{func_name}(): {info}".format(**locals())
+ err = AttributeError
+ return err, msg
+ if info and type(info) is dict:
+ keyword = tuple(info)[0]
+ msg = "{func_name}(): unsupported keyword '{keyword}'".format(**locals())
+ return AttributeError, msg
sigs = get_signature(func, "typeerror")
+ if not sigs:
+ msg = "{func_name}({args}) is wrong (missing signature)".format(**locals())
+ return TypeError, msg
if type(sigs) != list:
sigs = [sigs]
if type(args) != tuple:
@@ -144,7 +162,7 @@ def make_helptext(func):
sigs = [sigs]
try:
func_name = func.__name__
- except AttribureError:
+ except AttributeError:
func_name = func.__func__.__name__
sigtext = "\n".join(func_name + str(sig) for sig in sigs)
msg = sigtext + "\n\n" + existing_doc if check_string_type(existing_doc) else sigtext
diff --git a/sources/shiboken2/shibokenmodule/files.dir/shibokensupport/signature/lib/enum_sig.py b/sources/shiboken2/shibokenmodule/files.dir/shibokensupport/signature/lib/enum_sig.py
index 371b3ca4..088a93aa 100644
--- a/sources/shiboken2/shibokenmodule/files.dir/shibokensupport/signature/lib/enum_sig.py
+++ b/sources/shiboken2/shibokenmodule/files.dir/shibokensupport/signature/lib/enum_sig.py
@@ -50,8 +50,9 @@ by producing a lot of clarity.
"""
import sys
+import types
from shibokensupport.signature import inspect
-from shibokensupport.signature import get_signature
+from shibokensupport.signature import get_signature as get_sig
class ExactEnumerator(object):
@@ -64,19 +65,28 @@ class ExactEnumerator(object):
"""
def __init__(self, formatter, result_type=dict):
- global EnumType
+ global EnumMeta
try:
# Lazy import
from PySide2.QtCore import Qt
- EnumType = type(Qt.Key)
+ EnumMeta = type(Qt.Key)
except ImportError:
- EnumType = None
+ EnumMeta = None
self.fmt = formatter
self.result_type = result_type
self.fmt.level = 0
self.fmt.after_enum = self.after_enum
self._after_enum = False
+ self.fmt.is_method = self.is_method
+
+ def is_method(self):
+ """
+ Is this function a method?
+ We check if it is a simple function.
+ """
+ tp = type(self.func)
+ return tp not in (types.BuiltinFunctionType, types.FunctionType)
def after_enum(self):
ret = self._after_enum
@@ -93,8 +103,6 @@ class ExactEnumerator(object):
self.fmt.class_name = None
for class_name, klass in members:
ret.update(self.klass(class_name, klass))
- if isinstance(klass, EnumType):
- raise SystemError("implement enum instances at module level")
for func_name, func in functions:
ret.update(self.function(func_name, func))
return ret
@@ -129,10 +137,11 @@ class ExactEnumerator(object):
signature = getattr(thing, "__signature__", None)
if signature is not None:
functions.append((func_name, thing))
- elif type(type(thing)) is EnumType:
- enums.append((thing_name, thing))
+ elif type(type(thing)) is EnumMeta:
+ # take the real enum name, not what is in the dict
+ enums.append((thing_name, type(thing).__qualname__, thing))
init_signature = getattr(klass, "__signature__", None)
- enums.sort(key=lambda tup: tup[1]) # sort by enum value
+ enums.sort(key=lambda tup: tup[1 : 3]) # sort by class then enum value
self.fmt.have_body = bool(subclasses or functions or enums or init_signature)
with self.fmt.klass(class_name, class_str):
@@ -140,8 +149,8 @@ class ExactEnumerator(object):
self.fmt.class_name = class_name
if hasattr(self.fmt, "enum"):
# this is an optional feature
- for enum_name, value in enums:
- with self.fmt.enum(class_name, enum_name, int(value)):
+ for enum_name, enum_class_name, value in enums:
+ with self.fmt.enum(enum_class_name, enum_name, int(value)):
pass
for subclass_name, subclass in subclasses:
if klass == subclass:
@@ -154,18 +163,23 @@ class ExactEnumerator(object):
self.fmt.class_name = class_name
ret.update(self.function("__init__", klass))
for func_name, func in functions:
- ret.update(self.function(func_name, func))
+ if func_name != "__init__":
+ ret.update(self.function(func_name, func))
self.fmt.level -= 1
return ret
+ @staticmethod
+ def get_signature(func):
+ return func.__signature__
+
def function(self, func_name, func):
- self.fmt.level += 1
+ self.func = func # for is_method()
ret = self.result_type()
- signature = func.__signature__
+ signature = self.get_signature(func)
if signature is not None:
- with self.fmt.function(func_name, signature, modifier) as key:
+ with self.fmt.function(func_name, signature) as key:
ret[key] = signature
- self.fmt.level -= 1
+ del self.func
return ret
@@ -191,13 +205,14 @@ class SimplifyingEnumerator(ExactEnumerator):
def function(self, func_name, func):
ret = self.result_type()
- signature = get_signature(func, 'existence')
+ signature = get_sig(func, 'existence')
sig = stringify(signature) if signature is not None else None
if sig is not None and func_name not in ("next", "__next__", "__div__"):
with self.fmt.function(func_name, sig) as key:
ret[key] = sig
return ret
+
class HintingEnumerator(ExactEnumerator):
"""
HintingEnumerator enumerates all signatures in a module slightly changed.
@@ -206,11 +221,6 @@ class HintingEnumerator(ExactEnumerator):
hinting stubs. Only default values are replaced by "...".
"""
- def function(self, func_name, func):
- ret = self.result_type()
- signature = get_signature(func, 'hintingstub')
- if signature is not None:
- with self.fmt.function(func_name, signature) as key:
- ret[key] = signature
- return ret
-
+ @staticmethod
+ def get_signature(func):
+ return get_sig(func, "hintingstub")
diff --git a/sources/shiboken2/shibokenmodule/files.dir/shibokensupport/signature/lib/tool.py b/sources/shiboken2/shibokenmodule/files.dir/shibokensupport/signature/lib/tool.py
index 24e75e42..c8dbd51c 100644
--- a/sources/shiboken2/shibokenmodule/files.dir/shibokensupport/signature/lib/tool.py
+++ b/sources/shiboken2/shibokenmodule/files.dir/shibokensupport/signature/lib/tool.py
@@ -47,6 +47,7 @@ On the function with_metaclass see the answer from Martijn Pieters on
https://stackoverflow.com/questions/18513821/python-metaclass-understanding-the-with-metaclass
"""
+from inspect import currentframe
from textwrap import dedent
@@ -151,4 +152,11 @@ def with_metaclass(meta, *bases):
return meta.__prepare__(name, bases)
return type.__new__(metaclass, 'temporary_class', (), {})
+
+# A handy tool that shows the current line number and indents.
+def lno(level):
+ lineno = currentframe().f_back.f_lineno
+ spaces = level * " "
+ return "{}{}".format(lineno, spaces)
+
# eof
diff --git a/sources/shiboken2/shibokenmodule/files.dir/shibokensupport/signature/loader.py b/sources/shiboken2/shibokenmodule/files.dir/shibokensupport/signature/loader.py
index 6cee5468..02229939 100644
--- a/sources/shiboken2/shibokenmodule/files.dir/shibokensupport/signature/loader.py
+++ b/sources/shiboken2/shibokenmodule/files.dir/shibokensupport/signature/loader.py
@@ -101,8 +101,8 @@ def create_signature(props, key):
return layout.create_signature(props, key)
# name used in signature.cpp
-def seterror_argument(args, func_name):
- return errorhandler.seterror_argument(args, func_name)
+def seterror_argument(args, func_name, info):
+ return errorhandler.seterror_argument(args, func_name, info)
# name used in signature.cpp
def make_helptext(func):
@@ -114,7 +114,7 @@ def finish_import(module):
import signature_bootstrap
-from shibokensupport import signature, __feature__
+from shibokensupport import signature, feature as __feature__
signature.get_signature = signature_bootstrap.get_signature
# PYSIDE-1019: Publish the __feature__ dictionary.
__feature__.pyside_feature_dict = signature_bootstrap.pyside_feature_dict
@@ -195,8 +195,9 @@ def move_into_pyside_package():
try:
import PySide2.support
except ModuleNotFoundError:
- PySide2.support = types.ModuleType("PySide2.support")
- put_into_package(PySide2.support, __feature__)
+ # This can happen in the embedding case.
+ put_into_package(PySide2, shibokensupport, "support")
+ put_into_package(PySide2.support, __feature__, "__feature__")
put_into_package(PySide2.support, signature)
put_into_package(PySide2.support.signature, mapping)
put_into_package(PySide2.support.signature, errorhandler)
@@ -205,6 +206,7 @@ def move_into_pyside_package():
put_into_package(PySide2.support.signature, parser)
put_into_package(PySide2.support.signature, importhandler)
put_into_package(PySide2.support.signature.lib, enum_sig)
+ put_into_package(PySide2.support.signature.lib, tool)
put_into_package(None if orig_typing else PySide2.support.signature, typing)
put_into_package(PySide2.support.signature, inspect)
@@ -216,20 +218,23 @@ from shibokensupport.signature import lib
from shibokensupport.signature import parser
from shibokensupport.signature import importhandler
from shibokensupport.signature.lib import enum_sig
+from shibokensupport.signature.lib import tool
if "PySide2" in sys.modules:
# We publish everything under "PySide2.support.signature", again.
move_into_pyside_package()
+ # PYSIDE-1502: Make sure that support can be imported.
+ try:
+ import PySide2.support
+ except ModuleNotFoundError as e:
+ print("PySide2.support could not be imported. "
+ "This is a serious configuration error.", file=sys.stderr)
+ raise
# PYSIDE-1019: Modify `__import__` to be `__feature__` aware.
# __feature__ is already in sys.modules, so this is actually no import
- try:
- import PySide2.support.__feature__
- sys.modules["__feature__"] = PySide2.support.__feature__
- PySide2.support.__feature__.original_import = __builtins__["__import__"]
- __builtins__["__import__"] = PySide2.support.__feature__._import
- # Maybe we should optimize that and change `__import__` from C, instead?
- except ModuleNotFoundError:
- print("__feature__ could not be imported. "
- "This is an unsolved PyInstaller problem.", file=sys.stderr)
+ import PySide2.support.__feature__
+ sys.modules["__feature__"] = PySide2.support.__feature__
+ PySide2.support.__feature__.original_import = __builtins__["__import__"]
+ __builtins__["__import__"] = PySide2.support.__feature__._import
# end of file
diff --git a/sources/shiboken2/shibokenmodule/files.dir/shibokensupport/signature/mapping.py b/sources/shiboken2/shibokenmodule/files.dir/shibokensupport/signature/mapping.py
index 6fadd19d..69f1a326 100644
--- a/sources/shiboken2/shibokenmodule/files.dir/shibokensupport/signature/mapping.py
+++ b/sources/shiboken2/shibokenmodule/files.dir/shibokensupport/signature/mapping.py
@@ -300,6 +300,7 @@ type_map.update({
"zero(object)": None,
"zero(str)": "",
"zero(typing.Any)": None,
+ "zero(Any)": None,
})
type_map.update({
@@ -351,6 +352,10 @@ type_map.update({
"self" : "self",
})
+# PYSIDE-1538: We need to treat "std::optional" accordingly.
+type_map.update({
+ "std.optional": typing.Optional,
+ })
# The Shiboken Part
def init_Shiboken():
@@ -361,6 +366,8 @@ def init_Shiboken():
})
return locals()
+# side effect of different shiboken namings
+init_shiboken2 = init_shiboken2_shiboken2 = init_Shiboken
def init_minimal():
type_map.update({
diff --git a/sources/shiboken2/shibokenmodule/files.dir/shibokensupport/signature/parser.py b/sources/shiboken2/shibokenmodule/files.dir/shibokensupport/signature/parser.py
index 20c791cc..3e448d9e 100644
--- a/sources/shiboken2/shibokenmodule/files.dir/shibokensupport/signature/parser.py
+++ b/sources/shiboken2/shibokenmodule/files.dir/shibokensupport/signature/parser.py
@@ -43,10 +43,11 @@ import sys
import re
import warnings
import types
+import typing
import keyword
import functools
from shibokensupport.signature.mapping import (type_map, update_mapping,
- namespace, typing, _NotCalled, ResultVariable, ArrayLikeVariable)
+ namespace, _NotCalled, ResultVariable, ArrayLikeVariable)
from shibokensupport.signature.lib.tool import (SimpleNamespace,
build_brace_pattern)
@@ -196,7 +197,7 @@ def _resolve_value(thing, valtype, line):
if res is not None:
type_map[thing] = res
return res
- warnings.warn("""pyside_type_init:
+ warnings.warn("""pyside_type_init:_resolve_value
UNRECOGNIZED: {!r}
OFFENDING LINE: {!r}
@@ -222,7 +223,7 @@ def _resolve_arraytype(thing, line):
def to_string(thing):
if isinstance(thing, str):
return thing
- if hasattr(thing, "__name__"):
+ if hasattr(thing, "__name__") and thing.__module__ != "typing":
dot = "." in str(thing)
name = get_name(thing)
return thing.__module__ + "." + name if dot else name
@@ -239,16 +240,6 @@ def handle_matrix(arg):
return eval(result, namespace)
-debugging_aid = """
-from inspect import currentframe
-
-def lno(level):
- lineno = currentframe().f_back.f_lineno
- spaces = level * " "
- return "{lineno}{spaces}".format(**locals())
-"""
-
-
def _resolve_type(thing, line, level, var_handler):
# Capture total replacements, first. Happens in
# "PySide2.QtCore.QCborStreamReader.StringResult[PySide2.QtCore.QByteArray]"
@@ -277,7 +268,15 @@ def _resolve_type(thing, line, level, var_handler):
pieces.append(to_string(part))
thing = ", ".join(pieces)
result = "{contr}[{thing}]".format(**locals())
- return eval(result, namespace)
+ # PYSIDE-1538: Make sure that the eval does not crash.
+ try:
+ return eval(result, namespace)
+ except Exception as e:
+ warnings.warn("""pyside_type_init:_resolve_type
+
+ UNRECOGNIZED: {!r}
+ OFFENDING LINE: {!r}
+ """.format(result, line), RuntimeWarning)
return _resolve_value(thing, None, line)
@@ -380,7 +379,9 @@ def fix_variables(props, line):
if not isinstance(ann, ResultVariable):
continue
# We move the variable to the end and remove it.
- retvars.append(ann.type)
+ # PYSIDE-1409: If the variable was the first arg, we move it to the front.
+ # XXX This algorithm should probably be replaced by more introspection.
+ retvars.insert(0 if idx == 0 else len(retvars), ann.type)
deletions.append(idx)
del annos[name]
for idx in reversed(deletions):
diff --git a/sources/shiboken2/tests/samplebinding/time_test.py b/sources/shiboken2/tests/samplebinding/time_test.py
index f8b35e7b..3b8f232c 100644
--- a/sources/shiboken2/tests/samplebinding/time_test.py
+++ b/sources/shiboken2/tests/samplebinding/time_test.py
@@ -130,6 +130,7 @@ class TimeTest(unittest.TestCase):
result = time.somethingCompletelyDifferent(1, 2, ImplicitConv.CtorOne)
self.assertEqual(result, Time.ThreeArgs)
+ # PYSIDE-1436: These tests crash at shutdown due to `assert(Not)?Equal`.
def testCompareWithPythonTime(self):
time = Time(12, 32, 5)
py = datetime.time(12, 32, 5)
diff --git a/sources/shiboken2/tests/samplebinding/typesystem_sample.xml b/sources/shiboken2/tests/samplebinding/typesystem_sample.xml
index 595afb9a..70fabcf7 100644
--- a/sources/shiboken2/tests/samplebinding/typesystem_sample.xml
+++ b/sources/shiboken2/tests/samplebinding/typesystem_sample.xml
@@ -1953,6 +1953,7 @@
%PYARG_0 = Py_False;
else
%PYARG_0 = Py_True;
+ Py_INCREF(%PYARG_0);
}
</inject-code>
</add-function>
@@ -1970,6 +1971,7 @@
%PYARG_0 = Py_True;
else
%PYARG_0 = Py_False;
+ Py_INCREF(%PYARG_0);
}
</inject-code>
</add-function>
diff --git a/tools/create_changelog.py b/tools/create_changelog.py
index 8f5ea7ad..7fbff8be 100644
--- a/tools/create_changelog.py
+++ b/tools/create_changelog.py
@@ -196,12 +196,13 @@ def extract_change_log(commit_message: List[str]) -> Tuple[str, List[str]]:
result = []
component = 'pyside'
within_changelog = False
+ task_nr = ''
for line in commit_message:
if within_changelog:
if line:
result.append(' ' + line.strip())
else:
- break
+ within_changelog = False
else:
if line.startswith('[ChangeLog]'):
log_line = line[11:]
@@ -210,8 +211,16 @@ def extract_change_log(commit_message: List[str]) -> Tuple[str, List[str]]:
if end > 0:
component = log_line[1:end]
log_line = log_line[end + 1:]
- result.append(' * ' + log_line.strip())
+ result.append(log_line.strip())
within_changelog = True
+ elif line.startswith("Fixes: ") or line.startswith("Task-number: "):
+ task_nr = line.split(":")[1].strip()
+ if result:
+ first_line = ' - '
+ if task_nr:
+ first_line += "[{}] ".format(task_nr)
+ first_line += result[0]
+ result[0] = first_line
return (component, result)
diff --git a/tools/debug_renamer.py b/tools/debug_renamer.py
new file mode 100644
index 00000000..da5beb12
--- /dev/null
+++ b/tools/debug_renamer.py
@@ -0,0 +1,122 @@
+#############################################################################
+##
+## Copyright (C) 2020 The Qt Company Ltd.
+## Contact: https://www.qt.io/licensing/
+##
+## This file is part of the test suite of Qt for Python.
+##
+## $QT_BEGIN_LICENSE:GPL-EXCEPT$
+## Commercial License Usage
+## Licensees holding valid commercial Qt licenses may use this file in
+## accordance with the commercial license agreement provided with the
+## Software or, alternatively, in accordance with the terms contained in
+## a written agreement between you and The Qt Company. For licensing terms
+## and conditions see https://www.qt.io/terms-conditions. For further
+## information use the contact form at https://www.qt.io/contact-us.
+##
+## GNU General Public License Usage
+## Alternatively, this file may be used under the terms of the GNU
+## General Public License version 3 as published by the Free Software
+## Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+## included in the packaging of this file. Please review the following
+## information to ensure the GNU General Public License requirements will
+## be met: https://www.gnu.org/licenses/gpl-3.0.html.
+##
+## $QT_END_LICENSE$
+##
+#############################################################################
+
+"""
+debug_renamer.py
+================
+
+This script renames object addresses in debug protocols to useful names.
+Comparing output will produce minimal deltas.
+
+
+Problem:
+--------
+
+In the debugging output of PYSIDE-79, we want to study different output
+before and after applying some change to the implementation.
+
+We have support from the modified Python interpreter that creates full
+traces of every object creation and increment/decrement of refcounts.
+
+The comparison between "before" and "after" gets complicated because
+the addresses of objects do not compare well.
+
+
+Input format:
+-------------
+The Python output lines are of this format:
+
+mode filename:lineno funcname object_id typename object_refcount
+
+Mode can be "INC", "DEC", "XINC", XDEC", "NEW, "NEWV".
+
+On "NEW" or "NEWV", an object is created and the refcount is always 1.
+On "DEC" or "XDEC", when refcount is 0, the object is deleted.
+
+
+Operation
+---------
+
+The script reads from <stdin> until EOF. It produces output where the
+object_id field is removed and some text is combined with object_typename
+to produce a unique object name.
+
+
+Example
+-------
+
+You can create reference debugging output by using the modified interpreter at
+
+ https://github.com/ctismer/cpython/tree/3.9-refdebug
+
+and pipe the error output through this script.
+This is work in flux that might change quite often.
+
+
+To Do List
+----------
+
+The script should be re-worked to be more flexible, without relying on
+the number of coulumns but with some intelligent guessing.
+
+Names of objects which are already deleted should be monitored and
+not by chance be re-used.
+"""
+
+import sys
+from collections import OrderedDict
+
+
+def make_name(type_name, name_pos):
+ """
+ Build a name by using uppercase letters and numbers
+ """
+ if name_pos < 26:
+ name = chr(ord("A") + name_pos)
+ return f"{type_name}_{name}"
+ return f"{type_name}_{str(name_pos)}"
+
+
+mode_tokens = "NEW NEWV INC DEC XINC XDEC".split()
+known_types = {}
+
+while 1:
+ line = sys.stdin.readline()
+ if not line:
+ break
+ fields = line.split()
+ if len(fields) != 6 or fields[0] not in mode_tokens:
+ print(line.rstrip())
+ continue
+ mode, fname_lno, funcname, object_id, typename, refcount = fields
+ if typename not in known_types:
+ known_types[typename] = OrderedDict()
+ obj_store = known_types[typename]
+ if object_id not in obj_store:
+ obj_store[object_id] = make_name(typename, len(obj_store))
+ print(f"{mode} {fname_lno} {funcname} {obj_store[object_id]} {refcount}")
diff --git a/tools/leak_finder.py b/tools/leak_finder.py
new file mode 100644
index 00000000..5b510288
--- /dev/null
+++ b/tools/leak_finder.py
@@ -0,0 +1,196 @@
+#############################################################################
+##
+## Copyright (C) 2020 The Qt Company Ltd.
+## Contact: https://www.qt.io/licensing/
+##
+## This file is part of the test suite of Qt for Python.
+##
+## $QT_BEGIN_LICENSE:GPL-EXCEPT$
+## Commercial License Usage
+## Licensees holding valid commercial Qt licenses may use this file in
+## accordance with the commercial license agreement provided with the
+## Software or, alternatively, in accordance with the terms contained in
+## a written agreement between you and The Qt Company. For licensing terms
+## and conditions see https://www.qt.io/terms-conditions. For further
+## information use the contact form at https://www.qt.io/contact-us.
+##
+## GNU General Public License Usage
+## Alternatively, this file may be used under the terms of the GNU
+## General Public License version 3 as published by the Free Software
+## Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+## included in the packaging of this file. Please review the following
+## information to ensure the GNU General Public License requirements will
+## be met: https://www.gnu.org/licenses/gpl-3.0.html.
+##
+## $QT_END_LICENSE$
+##
+#############################################################################
+
+"""
+leak_finder.py
+==============
+
+This script finds memory leaks in Python.
+
+Usage:
+------
+
+Place one or more lines which should be tested for leaks in a loop:
+
+ from leak_finder import LeakFinder
+ ...
+ lf = LeakFinder()
+ for i in range(1000):
+ leaking_statement()
+ lf.find_leak()
+
+
+Theory
+------
+
+How to find a leak?
+
+We repeatedly perform an action and observe if that has an unexpected
+side effect. There are typically two observations:
+
+* one object is growing its refcount (a pseudo-leak)
+* we get many new objects of one type (a true leak)
+
+A difficulty in trying to get leak info is avoiding side effects
+of the measurement. Early attempts with lists of refcounts were
+unsuccessful. Using array.array for counting refcounts avoids that.
+
+
+Algorithm
+---------
+We record a snapshot of all objects in a list and a parallel array
+of refcounts.
+
+Then we do some computation and do the same snapshot again.
+
+The structure of a list of all objects is extending at the front for
+some reason. That makes the captured structures easy to compare.
+We reverse that list and array and have for the objects:
+
+ len(all2) >= len(all1)
+
+ all1[idx] == all2[idx] for idx in range(len(all1))
+
+When taking the second snapshot, the objects still have references from
+the first snapshot.
+For objects with no effect, the following relation is true:
+
+ refs1[idx] == refs2[idx] - 1 for idx in range(len(all1))
+
+All other objects are potential pseudo-leaks, because they waste
+references but no objects in the first place.
+
+Then we look at the newly created objects:
+These objects are real leaks if their number is growing with the probe
+size. For analysis, the number of new objects per type is counted.
+"""
+
+import sys
+import gc
+import array
+import unittest
+
+# this comes from Python, too
+from test import support
+
+try:
+ sys.getobjects
+ have_debug = True
+except AttributeError:
+ have_debug = False
+
+
+class LeakFinder(object):
+ def __init__(self):
+ self.all, self.refs = self._make_snapshot()
+
+ @staticmethod
+ def _make_snapshot():
+ gc.collect()
+ # get all objects
+ all = sys.getobjects(0)
+ # get an array with the refcounts
+ g = sys.getrefcount
+ refs = array.array("l", (g(obj) for obj in all))
+ # the lists have the same endind. Make comparison easier.
+ all.reverse()
+ refs.reverse()
+ return all, refs
+
+ @staticmethod
+ def _short_repr(x, limit=76):
+ s = repr(x)
+ if len(s) > limit:
+ s = s[:limit] + "..."
+ return s
+
+ def find_leak(self):
+ all1 = self.all
+ refs1 = self.refs
+ del self.all, self.refs
+ all2, refs2 = self._make_snapshot()
+ common = len(all1)
+ del all1
+
+ srepr = self._short_repr
+ # look into existing objects for increased refcounts
+ first = True
+ for idx in range(common):
+ ref = refs2[idx] - refs1[idx] - 1
+ if abs(ref) <= 10:
+ continue
+ obj = all2[idx]
+ if first:
+ print()
+ first = False
+ print(f"Fake Leak ref={ref} obj={srepr(obj)}")
+
+ # look at the extra objects by type size
+ types = {}
+ for idx in range(common, len(all2)):
+ obj = all2[idx]
+ typ = type(obj)
+ if typ not in types:
+ types[typ] = []
+ types[typ].append(obj)
+ first = True
+ for typ in types:
+ oblis = types[typ]
+ ref = len(oblis)
+ if ref <= 10:
+ continue
+ try:
+ oblis.sort()
+ except TypeError:
+ pass
+ if first:
+ print()
+ first = False
+ left, mid, right = oblis[0], oblis[ref // 2], oblis[-1]
+ print(f"True Leak ref={ref} typ={typ} left={left} mid={mid} right={right}")
+
+
+class TestDemo(unittest.TestCase):
+
+ @unittest.skipUnless(have_debug, 'You need a debug build with "--with-trace-refs"')
+ def test_demo(self):
+ # create a pseudo leak and a true leak
+ fake_leak_obj = []
+ true_leak_obj = []
+ lf = LeakFinder()
+ refs_before = sys.gettotalrefcount()
+ for idx in range(100):
+ fake_leak_obj.append("same string")
+ true_leak_obj.append(idx + 1000) # avoiding cached low numbers
+ refs_after = sys.gettotalrefcount()
+ lf.find_leak()
+ self.assertNotAlmostEqual(refs_after - refs_before, 0, delta=10)
+
+
+if __name__ == "__main__":
+ unittest.main()
diff --git a/tools/license_changer.py b/tools/license_changer.py
new file mode 100644
index 00000000..0c3443b8
--- /dev/null
+++ b/tools/license_changer.py
@@ -0,0 +1,85 @@
+#############################################################################
+##
+## Copyright (C) 2021 The Qt Company Ltd.
+## Contact: https://www.qt.io/licensing/
+##
+## This file is part of the Qt for Python project.
+##
+## $QT_BEGIN_LICENSE:COMM$
+##
+## 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.
+##
+## $QT_END_LICENSE$
+##
+#############################################################################
+
+from argparse import ArgumentParser, RawTextHelpFormatter
+import os
+from pathlib import Path
+import subprocess
+import sys
+
+
+DESC = """
+Tool to adapt licenses to a commercial LTS branch
+Requires the qtsdk/tqtc-qtsdk and qtqa repos to be checked out as siblings.
+"""
+
+
+REPO_DIR = Path(__file__).resolve().parents[1]
+
+
+EXCLUSIONS = ['/build_scripts/', '/coin/', '/doc/', '/examples/',
+ '/testing/', '/tests/',
+ '/coin_build_instructions.py', '/coin_test_instructions.py',
+ '/ez_setup.py', '/setup.py', '/testrunner.py']
+
+
+if __name__ == '__main__':
+ argument_parser = ArgumentParser(description=DESC,
+ formatter_class=RawTextHelpFormatter)
+ argument_parser.add_argument('--dry-run', '-d', action='store_true',
+ help='Dry run, print commands')
+ options = argument_parser.parse_args()
+ dry_run = options.dry_run
+
+ license_changer = (REPO_DIR.parent / 'tqtc-qtsdk' / 'packaging-tools'
+ / 'release_tools' / 'license_changer.pl')
+ print('Checking ', license_changer)
+ if not license_changer.is_file:
+ print('Not found, please clone the qtsdk/tqtc-qtsdk repo')
+ sys.exit(1)
+ template = (REPO_DIR.parent / 'qtqa' / 'tests' / 'prebuild'
+ / 'license' / 'templates' / 'header.COMM')
+ print('Checking ', template)
+ if not template.is_file():
+ print('Not found, please clone the qtqa repo')
+ sys.exit(1)
+
+ os.chdir(REPO_DIR)
+ fixed_cmd = [str(license_changer), '--path', str(REPO_DIR),
+ '--headerfile', str(template)]
+ for e in EXCLUSIONS:
+ fixed_cmd.append('--exclude')
+ fixed_cmd.append(e)
+
+ for license in ['GPL-EXCEPT', 'GPL', 'LGPL']:
+ log = f'license_{license.lower()}_log.txt'
+ cmd = fixed_cmd
+ cmd.extend(['--replacehdr', license, '--errorlog', log])
+ cmds = ' '.join(cmd)
+ print('Running: ', cmds)
+ if not dry_run:
+ ex = subprocess.call(cmd)
+ if ex != 0:
+ print('FAIL! ', cmds)
+ sys.exit(1)
+
+ if not dry_run:
+ subprocess.call(['git', 'diff'])
diff --git a/sources/pyside2/pyside_version.py b/tools/license_check.py
similarity index 69%
copy from sources/pyside2/pyside_version.py
copy to tools/license_check.py
index 009db0bf..052c41ca 100644
--- a/sources/pyside2/pyside_version.py
+++ b/tools/license_check.py
@@ -1,9 +1,9 @@
#############################################################################
##
-## Copyright (C) 2019 The Qt Company Ltd.
+## Copyright (C) 2021 The Qt Company Ltd.
## Contact: https://www.qt.io/licensing/
##
-## This file is part of Qt for Python.
+## This file is part of the Qt for Python project.
##
## $QT_BEGIN_LICENSE:LGPL$
## Commercial License Usage
@@ -37,19 +37,34 @@
##
#############################################################################
-major_version = "5"
-minor_version = "15"
-patch_version = "2"
+import os
+from pathlib import Path
+import subprocess
+import sys
-# For example: "a", "b", "rc"
-# (which means "alpha", "beta", "release candidate").
-# An empty string means the generated package will be an official release.
-release_version_type = ""
-# For example: "1", "2" (which means "beta1", "beta2", if type is "b").
-pre_release_version = ""
+"""Tool to run a license check
+
+Requires the qtqa repo to be checked out as sibling.
+"""
+
+
+REPO_DIR = Path(__file__).resolve().parents[1]
+
if __name__ == '__main__':
- # Used by CMake.
- print('{0};{1};{2};{3};{4}'.format(major_version, minor_version, patch_version,
- release_version_type, pre_release_version))
+ license_check = (REPO_DIR.parent / 'qtqa' / 'tests' / 'prebuild'
+ / 'license' / 'tst_licenses.pl')
+ print('Checking ', license_check)
+ if not license_check.is_file():
+ print('Not found, please clone the qtqa repo')
+ sys.exit(1)
+
+ os.environ['QT_MODULE_TO_TEST'] = str(REPO_DIR)
+ cmd = [str(license_check), '-m', 'pyside-setup']
+ cmds = ' '.join(cmd)
+ print('Running: ', cmds)
+ ex = subprocess.call(cmd)
+ if ex != 0:
+ print('FAIL! ', cmds)
+ sys.exit(1)
diff --git a/tools/uic_test.py b/tools/uic_test.py
new file mode 100644
index 00000000..6c1f2b88
--- /dev/null
+++ b/tools/uic_test.py
@@ -0,0 +1,123 @@
+#############################################################################
+##
+## Copyright (C) 2021 The Qt Company Ltd.
+## Contact: https://www.qt.io/licensing/
+##
+## This file is part of the Qt for Python project.
+##
+## $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$
+##
+#############################################################################
+
+import os
+import re
+import subprocess
+import sys
+import tempfile
+from argparse import ArgumentParser, RawTextHelpFormatter
+from pathlib import Path
+from textwrap import dedent
+from typing import Optional, Tuple
+
+
+VERSION = 2
+
+
+DESC = """Runs uic on a set of UI files and displays the resulting widgets."""
+
+
+TEMP_DIR = Path(tempfile.gettempdir())
+
+
+def get_class_name(file: Path) -> Tuple[Optional[str], Optional[str]]:
+ """Return class name and widget name of UI file."""
+ pattern = re.compile('^\s*<widget class="(\w+)" name="(\w+)"\s*>.*$')
+ for l in Path(file).read_text().splitlines():
+ match = pattern.match(l)
+ if match:
+ return (match.group(1), match.group(2))
+ return (None, None)
+
+
+def test_file(file: str, uic: bool=False) -> bool:
+ """Run uic on a UI file and show the resulting UI."""
+ path = Path(file)
+ (klass, name) = get_class_name(path)
+ if not klass:
+ print(f'{file} does not appear to be a UI file', file=sys.stderr)
+ return False
+ py_klass = f'Ui_{name}'
+ py_file_basename = py_klass.lower()
+ py_file = TEMP_DIR / (py_file_basename + '.py')
+ py_main = TEMP_DIR / 'main.py'
+ cmd = ['uic', '-g', 'python'] if uic else [f'pyside{VERSION}-uic']
+ cmd.extend(['-o', os.fspath(py_file), file])
+ try:
+ subprocess.call(cmd)
+ except FileNotFoundError as e:
+ print(str(e) + " (try -u for uic)", file=sys.stderr)
+ return False
+ main_source = dedent(f'''\
+ import sys
+ from PySide{VERSION}.QtWidgets import QApplication, {klass}
+ from {py_file_basename} import {py_klass}
+
+ if __name__ == "__main__":
+ app = QApplication(sys.argv)
+ ui = {py_klass}()
+ widget = {klass}()
+ ui.setupUi(widget)
+ widget.show()
+ sys.exit(app.exec_())''')
+ py_main.write_text(main_source)
+ exit_code = subprocess.call([sys.executable, os.fspath(py_main)])
+ py_main.unlink()
+ py_file.unlink()
+ return exit_code == 0
+
+
+if __name__ == '__main__':
+ argument_parser = ArgumentParser(description=DESC,
+ formatter_class=RawTextHelpFormatter)
+ argument_parser.add_argument('--uic', '-u', action='store_true',
+ help='Use uic instead of pyside-uic')
+ argument_parser.add_argument("files", help="UI Files",
+ nargs='+', type=str)
+ options = argument_parser.parse_args()
+ failed = 0
+ count = len(options.files)
+ for i, file in enumerate(options.files):
+ print(f'{i+1}/{count} {file}')
+ if not test_file(file, options.uic):
+ failed += 1
+ if failed != 0:
+ print(f'{failed}/{count} failed.')
+ sys.exit(failed)
More information about the Neon-commits
mailing list