From db96c09268474bc0142cca94f59ed4e68cb86a5e Mon Sep 17 00:00:00 2001 From: Audrow Nash Date: Mon, 28 Nov 2022 13:46:12 -0600 Subject: [PATCH 01/63] [rolling] Update maintainers - 2022-11-07 (#120) * Add Shane Loretz to CODEOWNERs file * Update maintainers to Shane Loretz Signed-off-by: Audrow Nash --- CODEOWNERS | 2 ++ package.xml | 5 ++++- 2 files changed, 6 insertions(+), 1 deletion(-) create mode 100644 CODEOWNERS diff --git a/CODEOWNERS b/CODEOWNERS new file mode 100644 index 0000000..2a976b9 --- /dev/null +++ b/CODEOWNERS @@ -0,0 +1,2 @@ +# This file was generated by https://github.com/audrow/update-ros2-repos +* @sloretz diff --git a/package.xml b/package.xml index 55a4a67..5cb03b5 100644 --- a/package.xml +++ b/package.xml @@ -14,13 +14,16 @@ independent of which binding provider was actually used which makes it very easy to switch between these. + Shane Loretz + BSD http://ros.org/wiki/python_qt_binding + Dave Hershberger - Dorian Scholz Dirk Thomas + Dorian Scholz Stephen Brawner ament_cmake From 899a9a057d1b7faed5a118753ac4c2c36263ec09 Mon Sep 17 00:00:00 2001 From: Chris Lalancette Date: Tue, 14 Feb 2023 16:26:47 +0000 Subject: [PATCH 02/63] Changelog. Signed-off-by: Chris Lalancette --- CHANGELOG.rst | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 5367465..29b2711 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -2,6 +2,11 @@ Changelog for package python_qt_binding ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Forthcoming +----------- +* [rolling] Update maintainers - 2022-11-07 (`#120 `_) +* Contributors: Audrow Nash + 1.2.0 (2022-05-10) ------------------ From bb9375d6005a263b848479f64cb1fbe383fe71f0 Mon Sep 17 00:00:00 2001 From: Chris Lalancette Date: Tue, 14 Feb 2023 16:26:54 +0000 Subject: [PATCH 03/63] 1.2.1 --- CHANGELOG.rst | 4 ++-- package.xml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 29b2711..0e2c405 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -2,8 +2,8 @@ Changelog for package python_qt_binding ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -Forthcoming ------------ +1.2.1 (2023-02-14) +------------------ * [rolling] Update maintainers - 2022-11-07 (`#120 `_) * Contributors: Audrow Nash diff --git a/package.xml b/package.xml index 5cb03b5..defc9f0 100644 --- a/package.xml +++ b/package.xml @@ -1,6 +1,6 @@ python_qt_binding - 1.2.0 + 1.2.1 This stack provides Python bindings for Qt. There are two providers: pyside and pyqt. PySide2 is available under From 77aafb5237fe57865213cd924daba8d7b4079569 Mon Sep 17 00:00:00 2001 From: Scott K Logan Date: Thu, 23 Feb 2023 15:53:55 -0800 Subject: [PATCH 04/63] Demote missing SIP message from WARNING to STATUS (#122) It's becoming increasingly normal to use Shiboken instead of SIP, so it shouldn't be a warning when it isn't found. Signed-off-by: Scott K Logan --- cmake/sip_helper.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake/sip_helper.cmake b/cmake/sip_helper.cmake index c589899..3266e31 100644 --- a/cmake/sip_helper.cmake +++ b/cmake/sip_helper.cmake @@ -22,7 +22,7 @@ if(SIP_EXECUTABLE) message(STATUS "SIP binding generator available at: ${SIP_EXECUTABLE}") set(sip_helper_FOUND TRUE) else() - message(WARNING "SIP binding generator NOT available.") + message(STATUS "SIP binding generator NOT available.") set(sip_helper_NOTFOUND TRUE) endif() From 75bc2dfe2bb10344bebc4b003914fa6e8bf61efe Mon Sep 17 00:00:00 2001 From: Chris Lalancette Date: Fri, 24 Feb 2023 20:07:30 +0000 Subject: [PATCH 05/63] Changelog. Signed-off-by: Chris Lalancette --- CHANGELOG.rst | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 0e2c405..5924475 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -2,6 +2,11 @@ Changelog for package python_qt_binding ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Forthcoming +----------- +* Demote missing SIP message from WARNING to STATUS (`#122 `_) +* Contributors: Scott K Logan + 1.2.1 (2023-02-14) ------------------ * [rolling] Update maintainers - 2022-11-07 (`#120 `_) From fab9b3efcc33aa08b0e8815ce1a37081b0a417e4 Mon Sep 17 00:00:00 2001 From: Chris Lalancette Date: Fri, 24 Feb 2023 20:07:35 +0000 Subject: [PATCH 06/63] 1.2.2 --- CHANGELOG.rst | 4 ++-- package.xml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 5924475..cea9b3c 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -2,8 +2,8 @@ Changelog for package python_qt_binding ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -Forthcoming ------------ +1.2.2 (2023-02-24) +------------------ * Demote missing SIP message from WARNING to STATUS (`#122 `_) * Contributors: Scott K Logan diff --git a/package.xml b/package.xml index defc9f0..123ff3d 100644 --- a/package.xml +++ b/package.xml @@ -1,6 +1,6 @@ python_qt_binding - 1.2.1 + 1.2.2 This stack provides Python bindings for Qt. There are two providers: pyside and pyqt. PySide2 is available under From cacbd7b31645218a6a786318d6d380fd02fa2832 Mon Sep 17 00:00:00 2001 From: Rhys Mainwaring Date: Wed, 1 Mar 2023 15:04:41 +0000 Subject: [PATCH 07/63] Remove pyqt from default binding order for macOS (#118) - Suppress debug messages - Remove pyqt from default binding order Signed-off-by: Rhys Mainwaring --- src/python_qt_binding/binding_helper.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/python_qt_binding/binding_helper.py b/src/python_qt_binding/binding_helper.py index 603e1e2..0cb904f 100644 --- a/src/python_qt_binding/binding_helper.py +++ b/src/python_qt_binding/binding_helper.py @@ -36,6 +36,7 @@ # since the 'future' package provides a 'builtins' module in Python 2 # this must not be checked second import builtins +import platform import os import sys import traceback @@ -50,7 +51,11 @@ def _select_qt_binding(binding_name=None, binding_order=None): global QT_BINDING, QT_BINDING_VERSION # order of default bindings can be changed here - DEFAULT_BINDING_ORDER = ['pyqt', 'pyside'] + if platform.system() == 'Darwin': + DEFAULT_BINDING_ORDER = ['pyside'] + else: + DEFAULT_BINDING_ORDER = ['pyqt', 'pyside'] + binding_order = binding_order or DEFAULT_BINDING_ORDER # determine binding preference From 0a7f68ec8cb219233c9a640ca8517af73510949d Mon Sep 17 00:00:00 2001 From: Christoph Hellmann Santos <51296695+ipa-cmh@users.noreply.github.com> Date: Wed, 1 Mar 2023 16:40:21 +0100 Subject: [PATCH 08/63] Add windows support for pyside helper (#116) --- CMakeLists.txt | 1 + cmake/pyside_config.py | 415 ++++++++++++++++++++++++++++++++++++ cmake/shiboken_helper.cmake | 66 +++++- 3 files changed, 477 insertions(+), 5 deletions(-) create mode 100644 cmake/pyside_config.py diff --git a/CMakeLists.txt b/CMakeLists.txt index 919969e..e3ddec5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -11,6 +11,7 @@ install(FILES cmake/shiboken_helper.cmake cmake/sip_configure.py cmake/sip_helper.cmake + cmake/pyside_config.py DESTINATION share/${PROJECT_NAME}/cmake) if(BUILD_TESTING) diff --git a/cmake/pyside_config.py b/cmake/pyside_config.py new file mode 100644 index 0000000..df6be15 --- /dev/null +++ b/cmake/pyside_config.py @@ -0,0 +1,415 @@ +# Copyright (C) 2022 The Qt Company Ltd. +# 2022 Christoph Hellmann Santos +# SPDX-License-Identifier: BSD-3-Clause + +import sysconfig +from enum import Enum +import glob +import os +import re +import sys + + +PYSIDE = "pyside2" +PYSIDE_MODULE = "PySide2" +SHIBOKEN = "shiboken2" + + +class Package(Enum): + SHIBOKEN_MODULE = 1 + SHIBOKEN_GENERATOR = 2 + PYSIDE_MODULE = 3 + + +generic_error = ( + "Did you forget to activate your virtualenv? Or perhaps" + f" you forgot to build / install {PYSIDE_MODULE} into your currently active Python" + " environment?" +) +pyside_error = f"Unable to locate {PYSIDE_MODULE}. {generic_error}" +shiboken_module_error = f"Unable to locate {SHIBOKEN}-module. {generic_error}" +shiboken_generator_error = f"Unable to locate shiboken-generator. {generic_error}" +pyside_libs_error = f"Unable to locate the PySide shared libraries. {generic_error}" +python_link_error = "Unable to locate the Python library for linking." +python_include_error = "Unable to locate the Python include headers directory." + +options = [] + +# option, function, error, description +options.append( + ( + "--shiboken-module-path", + lambda: find_shiboken_module(), + shiboken_module_error, + "Print shiboken module location", + ) +) +options.append( + ( + "--shiboken-generator-path", + lambda: find_shiboken_generator(), + shiboken_generator_error, + "Print shiboken generator location", + ) +) +options.append( + ( + "--pyside-path", + lambda: find_pyside(), + pyside_error, + f"Print {PYSIDE_MODULE} location", + ) +) + +options.append( + ( + "--python-include-path", + lambda: get_python_include_path(), + python_include_error, + "Print Python include path", + ) +) +options.append( + ( + "--shiboken-generator-include-path", + lambda: get_package_include_path(Package.SHIBOKEN_GENERATOR), + pyside_error, + "Print shiboken generator include paths", + ) +) +options.append( + ( + "--pyside-include-path", + lambda: get_package_include_path(Package.PYSIDE_MODULE), + pyside_error, + "Print PySide6 include paths", + ) +) + +options.append( + ( + "--python-link-flags-qmake", + lambda: python_link_flags_qmake(), + python_link_error, + "Print python link flags for qmake", + ) +) +options.append( + ( + "--python-link-flags-cmake", + lambda: python_link_flags_cmake(), + python_link_error, + "Print python link flags for cmake", + ) +) + +options.append( + ( + "--shiboken-module-qmake-lflags", + lambda: get_package_qmake_lflags(Package.SHIBOKEN_MODULE), + pyside_error, + "Print shiboken6 shared library link flags for qmake", + ) +) +options.append( + ( + "--pyside-qmake-lflags", + lambda: get_package_qmake_lflags(Package.PYSIDE_MODULE), + pyside_error, + "Print PySide6 shared library link flags for qmake", + ) +) + +options.append( + ( + "--shiboken-module-shared-libraries-qmake", + lambda: get_shared_libraries_qmake(Package.SHIBOKEN_MODULE), + pyside_libs_error, + "Print paths of shiboken shared libraries (.so's, .dylib's, .dll's) for qmake", + ) +) +options.append( + ( + "--shiboken-module-shared-libraries-cmake", + lambda: get_shared_libraries_cmake(Package.SHIBOKEN_MODULE), + pyside_libs_error, + "Print paths of shiboken shared libraries (.so's, .dylib's, .dll's) for cmake", + ) +) + +options.append( + ( + "--pyside-shared-libraries-qmake", + lambda: get_shared_libraries_qmake(Package.PYSIDE_MODULE), + pyside_libs_error, + "Print paths of f{PYSIDE_MODULE} shared libraries (.so's, .dylib's, .dll's) for qmake", + ) +) +options.append( + ( + "--pyside-shared-libraries-cmake", + lambda: get_shared_libraries_cmake(Package.PYSIDE_MODULE), + pyside_libs_error, + f"Print paths of {PYSIDE_MODULE} shared libraries (.so's, .dylib's, .dll's) for cmake", + ) +) + +options_usage = "" +for i, (flag, _, _, description) in enumerate(options): + options_usage += f" {flag:<45} {description}" + if i < len(options) - 1: + options_usage += "\n" + +usage = f""" +Utility to determine include/link options of shiboken/PySide and Python for qmake/CMake projects +that would like to embed or build custom shiboken/PySide bindings. + +Usage: pyside_config.py [option] +Options: +{options_usage} + -a Print all options and their values + --help/-h Print this help +""" + +option = sys.argv[1] if len(sys.argv) == 2 else "-a" +if option == "-h" or option == "--help": + print(usage) + sys.exit(0) + + +def clean_path(path): + return path if sys.platform != "win32" else path.replace("\\", "/") + + +def shared_library_suffix(): + if sys.platform == "win32": + return "lib" + elif sys.platform == "darwin": + return "dylib" + # Linux + else: + return "so.*" + + +def import_suffixes(): + import importlib.machinery + + return importlib.machinery.EXTENSION_SUFFIXES + + +def is_debug(): + debug_suffix = "_d.pyd" if sys.platform == "win32" else "_d.so" + return any([s.endswith(debug_suffix) for s in import_suffixes()]) + + +def shared_library_glob_pattern(): + glob = "*." + shared_library_suffix() + return glob if sys.platform == "win32" else "lib" + glob + + +def filter_shared_libraries(libs_list): + def predicate(lib_name): + basename = os.path.basename(lib_name) + if "shiboken" in basename or "pyside6" in basename: + return True + return False + + result = [lib for lib in libs_list if predicate(lib)] + return result + + +# Return qmake link option for a library file name +def link_option(lib): + # On Linux: + # Since we cannot include symlinks with wheel packages + # we are using an absolute path for the libpyside and libshiboken + # libraries when compiling the project + baseName = os.path.basename(lib) + link = " -l" + if sys.platform in [ + "linux", + "linux2", + ]: # Linux: 'libfoo.so' -> '/absolute/path/libfoo.so' + link = lib + elif sys.platform in ["darwin"]: # Darwin: 'libfoo.so' -> '-lfoo' + link += os.path.splitext(baseName[3:])[0] + else: # Windows: 'libfoo.dll' -> 'libfoo.dll' + link += os.path.splitext(baseName)[0] + return link + + +# Locate PySide6 via sys.path package path. +def find_pyside(): + return find_package_path(PYSIDE_MODULE) + + +def find_shiboken_module(): + return find_package_path(SHIBOKEN) + + +def find_shiboken_generator(): + return find_package_path(f"{SHIBOKEN}_generator") + + +def find_package(which_package): + if which_package == Package.SHIBOKEN_MODULE: + return find_shiboken_module() + if which_package == Package.SHIBOKEN_GENERATOR: + return find_shiboken_generator() + if which_package == Package.PYSIDE_MODULE: + return find_pyside() + return None + + +def find_package_path(dir_name): + for p in sys.path: + if "site-" in p: + package = os.path.join(p, dir_name) + if os.path.exists(package): + return clean_path(os.path.realpath(package)) + return None + + +# Return version as "3.6" +def python_version(): + return str(sys.version_info[0]) + "." + str(sys.version_info[1]) + + +def get_python_include_path(): + return sysconfig.get_path("include") + + +def python_link_flags_qmake(): + flags = python_link_data() + if sys.platform == "win32": + libdir = flags["libdir"] + # This will add the "~1" shortcut for directories that + # contain white spaces + # e.g.: "Program Files" to "Progra~1" + for d in libdir.split("\\"): + if " " in d: + libdir = libdir.replace(d, d.split(" ")[0][:-1] + "~1") + lib_flags = flags["lib"] + return f"-L{libdir} -l{lib_flags}" + elif sys.platform == "darwin": + libdir = flags["libdir"] + lib_flags = flags["lib"] + return f"-L{libdir} -l{lib_flags}" + else: + # Linux and anything else + libdir = flags["libdir"] + lib_flags = flags["lib"] + return f"-L{libdir} -l{lib_flags}" + + +def python_link_flags_cmake(): + flags = python_link_data() + libdir = flags["libdir"] + lib = re.sub(r".dll$", ".lib", flags["lib"]) + return f"{libdir};{lib}" + + +def python_link_data(): + # @TODO Fix to work with static builds of Python + libdir = sysconfig.get_config_var("LIBDIR") + if libdir is None: + libdir = os.path.abspath( + os.path.join(sysconfig.get_config_var("LIBDEST"), "..", "libs") + ) + version = python_version() + version_no_dots = version.replace(".", "") + + flags = {} + flags["libdir"] = libdir + if sys.platform == "win32": + suffix = "_d" if is_debug() else "" + flags["lib"] = f"python{version_no_dots}{suffix}" + + elif sys.platform == "darwin": + flags["lib"] = f"python{version}" + + # Linux and anything else + else: + flags["lib"] = f"python{version}{sys.abiflags}" + + return flags + + +def get_package_include_path(which_package): + package_path = find_package(which_package) + if package_path is None: + return None + + includes = f"{package_path}/include" + + return includes + + +def get_package_qmake_lflags(which_package): + package_path = find_package(which_package) + if package_path is None: + return None + + link = f"-L{package_path}" + glob_result = glob.glob(os.path.join(package_path, shared_library_glob_pattern())) + for lib in filter_shared_libraries(glob_result): + link += " " + link += link_option(lib) + return link + + +def get_shared_libraries_data(which_package): + package_path = find_package(which_package) + if package_path is None: + return None + + glob_result = glob.glob(os.path.join(package_path, shared_library_glob_pattern())) + filtered_libs = filter_shared_libraries(glob_result) + libs = [] + if sys.platform == "win32": + for lib in filtered_libs: + libs.append(os.path.realpath(lib)) + else: + for lib in filtered_libs: + libs.append(lib) + return libs + + +def get_shared_libraries_qmake(which_package): + libs = get_shared_libraries_data(which_package) + if libs is None: + return None + + if sys.platform == "win32": + if not libs: + return "" + dlls = "" + for lib in libs: + dll = os.path.splitext(lib)[0] + ".dll" + dlls += dll + " " + + return dlls + else: + libs_string = "" + for lib in libs: + libs_string += lib + " " + return libs_string + + +def get_shared_libraries_cmake(which_package): + libs = get_shared_libraries_data(which_package) + result = ";".join(libs) + return result + + +print_all = option == "-a" +for argument, handler, error, _ in options: + if option == argument or print_all: + handler_result = handler() + if handler_result is None: + sys.exit(error) + + line = handler_result + if print_all: + line = f"{argument:<40}: {line}" + print(line) diff --git a/cmake/shiboken_helper.cmake b/cmake/shiboken_helper.cmake index 5b96d9f..acd9b9a 100644 --- a/cmake/shiboken_helper.cmake +++ b/cmake/shiboken_helper.cmake @@ -8,6 +8,31 @@ set(__PYTHON_QT_BINDING_SHIBOKEN_HELPER_INCLUDED TRUE) set(PYTHON_SUFFIX ".cpython-${PYTHON_VERSION_MAJOR}${PYTHON_VERSION_MINOR}m") set(PYTHON_EXTENSION_SUFFIX "${PYTHON_SUFFIX}-${CMAKE_CXX_LIBRARY_ARCHITECTURE}") +find_package(python_qt_binding REQUIRED) + +macro(pyside_config option output_var) + if(${ARGC} GREATER 2) + set(is_list ${ARGV2}) + else() + set(is_list "") + endif() + + execute_process( + COMMAND ${Python3_EXECUTABLE} "${python_qt_binding_DIR}/pyside_config.py" + ${option} + OUTPUT_VARIABLE ${output_var} + OUTPUT_STRIP_TRAILING_WHITESPACE) + + if("${${output_var}}" STREQUAL "") + message(FATAL_ERROR "Error: Calling pyside_config.py ${option} returned no output.") + endif() + if(is_list) + string(REPLACE " " ";" ${output_var} "${${output_var}}") + endif() +endmacro() + + + find_package(Shiboken2 QUIET) if(Shiboken2_FOUND) message(STATUS "Found Shiboken2 version ${Shiboken2_VERSION}") @@ -16,10 +41,22 @@ if(Shiboken2_FOUND) get_property(SHIBOKEN_LIBRARY TARGET Shiboken2::libshiboken PROPERTY LOCATION) set(SHIBOKEN_BINARY Shiboken2::shiboken2) endif() - message(STATUS "Using SHIBOKEN_INCLUDE_DIR: ${SHIBOKEN_INCLUDE_DIR}") - message(STATUS "Using SHIBOKEN_LIBRARY: ${SHIBOKEN_LIBRARY}") - message(STATUS "Using SHIBOKEN_BINARY: ${SHIBOKEN_BINARY}") +else() + if(WIN32) + pyside_config(--shiboken-generator-path shiboken_generator_path) + pyside_config(--shiboken-generator-include-path shiboken_include_dir 1) + pyside_config(--shiboken-module-shared-libraries-cmake shiboken_shared_libraries 0) + + set(SHIBOKEN_BINARY "${shiboken_generator_path}/shiboken2${CMAKE_EXECUTABLE_SUFFIX}") + set(SHIBOKEN_LIBRARY ${shiboken_shared_libraries}) + set(SHIBOKEN_INCLUDE_DIR ${shiboken_include_dir}) + endif() endif() + +message(STATUS "Using SHIBOKEN_INCLUDE_DIR: ${SHIBOKEN_INCLUDE_DIR}") +message(STATUS "Using SHIBOKEN_LIBRARY: ${SHIBOKEN_LIBRARY}") +message(STATUS "Using SHIBOKEN_BINARY: ${SHIBOKEN_BINARY}") + set(PYTHON_BASENAME "${PYTHON_SUFFIX}-${CMAKE_CXX_LIBRARY_ARCHITECTURE}") find_package(PySide2 QUIET) @@ -31,7 +68,16 @@ if(PySide2_FOUND) endif() message(STATUS "Using PYSIDE_INCLUDE_DIR: ${PYSIDE_INCLUDE_DIR}") message(STATUS "Using PYSIDE_LIBRARY: ${PYSIDE_LIBRARY}") +else() + if(WIN32) + pyside_config(--pyside-include-path pyside_include_dir 1) + pyside_config(--pyside-shared-libraries-cmake pyside_shared_libraries 0) + set(PYSIDE_INCLUDE_DIR ${pyside_include_dir}) + set(PYSIDE_LIBRARY ${pyside_shared_libraries}) + endif() endif() +message(STATUS "Using PYSIDE_INCLUDE_DIR: ${PYSIDE_INCLUDE_DIR}") +message(STATUS "Using PYSIDE_LIBRARY: ${PYSIDE_LIBRARY}") set(Python_ADDITIONAL_VERSIONS "${PYTHON_VERSION_MAJOR}.${PYTHON_VERSION_MINOR}") find_package(PythonLibs "${PYTHON_VERSION_MAJOR}.${PYTHON_VERSION_MINOR}") @@ -71,7 +117,8 @@ macro(_shiboken_generator_command VAR GLOBAL TYPESYSTEM INCLUDE_PATH BUILD_DIR) --enable-pyside-extensions --include-paths=${INCLUDE_PATH_WITH_COLONS}${SHIBOKEN_HELPER_INCLUDE_DIRS_WITH_COLONS} --typesystem-paths=${PYSIDE_TYPESYSTEMS} - --output-directory=${BUILD_DIR} ${GLOBAL} ${TYPESYSTEM}) + --output-directory=${BUILD_DIR} ${GLOBAL} ${TYPESYSTEM} + --language-level=c++17) endmacro() @@ -107,7 +154,16 @@ function(shiboken_generator PROJECT_NAME GLOBAL TYPESYSTEM WORKING_DIR GENERATED ) endfunction() - +function(shiboken_generator_ext PROJECT_NAME GLOBAL TYPESYSTEM WORKING_DIR GENERATED_SRCS INCLUDE_PATH BUILD_DIR) + _shiboken_generator_command(COMMAND "${GLOBAL}" "${TYPESYSTEM}" "${INCLUDE_PATH}" "${BUILD_DIR}") + add_custom_command( + OUTPUT ${GENERATED_SRCS} + COMMAND ${COMMAND} + DEPENDS ${GLOBAL} ${TYPESYSTEM} + WORKING_DIRECTORY ${WORKING_DIR} + COMMENT "Running Shiboken generator for ${PROJECT_NAME} Python bindings..." + ) +endfunction() # # Add the Shiboken/PySide specific include directories. # From d8fc6179f0dbb87f464aa18f69588da4b58f1daf Mon Sep 17 00:00:00 2001 From: Michael Carroll Date: Wed, 1 Mar 2023 13:31:27 -0600 Subject: [PATCH 09/63] Revert "Add windows support for pyside helper (#116)" (#124) This reverts commit 0a7f68ec8cb219233c9a640ca8517af73510949d. --- CMakeLists.txt | 1 - cmake/pyside_config.py | 415 ------------------------------------ cmake/shiboken_helper.cmake | 66 +----- 3 files changed, 5 insertions(+), 477 deletions(-) delete mode 100644 cmake/pyside_config.py diff --git a/CMakeLists.txt b/CMakeLists.txt index e3ddec5..919969e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -11,7 +11,6 @@ install(FILES cmake/shiboken_helper.cmake cmake/sip_configure.py cmake/sip_helper.cmake - cmake/pyside_config.py DESTINATION share/${PROJECT_NAME}/cmake) if(BUILD_TESTING) diff --git a/cmake/pyside_config.py b/cmake/pyside_config.py deleted file mode 100644 index df6be15..0000000 --- a/cmake/pyside_config.py +++ /dev/null @@ -1,415 +0,0 @@ -# Copyright (C) 2022 The Qt Company Ltd. -# 2022 Christoph Hellmann Santos -# SPDX-License-Identifier: BSD-3-Clause - -import sysconfig -from enum import Enum -import glob -import os -import re -import sys - - -PYSIDE = "pyside2" -PYSIDE_MODULE = "PySide2" -SHIBOKEN = "shiboken2" - - -class Package(Enum): - SHIBOKEN_MODULE = 1 - SHIBOKEN_GENERATOR = 2 - PYSIDE_MODULE = 3 - - -generic_error = ( - "Did you forget to activate your virtualenv? Or perhaps" - f" you forgot to build / install {PYSIDE_MODULE} into your currently active Python" - " environment?" -) -pyside_error = f"Unable to locate {PYSIDE_MODULE}. {generic_error}" -shiboken_module_error = f"Unable to locate {SHIBOKEN}-module. {generic_error}" -shiboken_generator_error = f"Unable to locate shiboken-generator. {generic_error}" -pyside_libs_error = f"Unable to locate the PySide shared libraries. {generic_error}" -python_link_error = "Unable to locate the Python library for linking." -python_include_error = "Unable to locate the Python include headers directory." - -options = [] - -# option, function, error, description -options.append( - ( - "--shiboken-module-path", - lambda: find_shiboken_module(), - shiboken_module_error, - "Print shiboken module location", - ) -) -options.append( - ( - "--shiboken-generator-path", - lambda: find_shiboken_generator(), - shiboken_generator_error, - "Print shiboken generator location", - ) -) -options.append( - ( - "--pyside-path", - lambda: find_pyside(), - pyside_error, - f"Print {PYSIDE_MODULE} location", - ) -) - -options.append( - ( - "--python-include-path", - lambda: get_python_include_path(), - python_include_error, - "Print Python include path", - ) -) -options.append( - ( - "--shiboken-generator-include-path", - lambda: get_package_include_path(Package.SHIBOKEN_GENERATOR), - pyside_error, - "Print shiboken generator include paths", - ) -) -options.append( - ( - "--pyside-include-path", - lambda: get_package_include_path(Package.PYSIDE_MODULE), - pyside_error, - "Print PySide6 include paths", - ) -) - -options.append( - ( - "--python-link-flags-qmake", - lambda: python_link_flags_qmake(), - python_link_error, - "Print python link flags for qmake", - ) -) -options.append( - ( - "--python-link-flags-cmake", - lambda: python_link_flags_cmake(), - python_link_error, - "Print python link flags for cmake", - ) -) - -options.append( - ( - "--shiboken-module-qmake-lflags", - lambda: get_package_qmake_lflags(Package.SHIBOKEN_MODULE), - pyside_error, - "Print shiboken6 shared library link flags for qmake", - ) -) -options.append( - ( - "--pyside-qmake-lflags", - lambda: get_package_qmake_lflags(Package.PYSIDE_MODULE), - pyside_error, - "Print PySide6 shared library link flags for qmake", - ) -) - -options.append( - ( - "--shiboken-module-shared-libraries-qmake", - lambda: get_shared_libraries_qmake(Package.SHIBOKEN_MODULE), - pyside_libs_error, - "Print paths of shiboken shared libraries (.so's, .dylib's, .dll's) for qmake", - ) -) -options.append( - ( - "--shiboken-module-shared-libraries-cmake", - lambda: get_shared_libraries_cmake(Package.SHIBOKEN_MODULE), - pyside_libs_error, - "Print paths of shiboken shared libraries (.so's, .dylib's, .dll's) for cmake", - ) -) - -options.append( - ( - "--pyside-shared-libraries-qmake", - lambda: get_shared_libraries_qmake(Package.PYSIDE_MODULE), - pyside_libs_error, - "Print paths of f{PYSIDE_MODULE} shared libraries (.so's, .dylib's, .dll's) for qmake", - ) -) -options.append( - ( - "--pyside-shared-libraries-cmake", - lambda: get_shared_libraries_cmake(Package.PYSIDE_MODULE), - pyside_libs_error, - f"Print paths of {PYSIDE_MODULE} shared libraries (.so's, .dylib's, .dll's) for cmake", - ) -) - -options_usage = "" -for i, (flag, _, _, description) in enumerate(options): - options_usage += f" {flag:<45} {description}" - if i < len(options) - 1: - options_usage += "\n" - -usage = f""" -Utility to determine include/link options of shiboken/PySide and Python for qmake/CMake projects -that would like to embed or build custom shiboken/PySide bindings. - -Usage: pyside_config.py [option] -Options: -{options_usage} - -a Print all options and their values - --help/-h Print this help -""" - -option = sys.argv[1] if len(sys.argv) == 2 else "-a" -if option == "-h" or option == "--help": - print(usage) - sys.exit(0) - - -def clean_path(path): - return path if sys.platform != "win32" else path.replace("\\", "/") - - -def shared_library_suffix(): - if sys.platform == "win32": - return "lib" - elif sys.platform == "darwin": - return "dylib" - # Linux - else: - return "so.*" - - -def import_suffixes(): - import importlib.machinery - - return importlib.machinery.EXTENSION_SUFFIXES - - -def is_debug(): - debug_suffix = "_d.pyd" if sys.platform == "win32" else "_d.so" - return any([s.endswith(debug_suffix) for s in import_suffixes()]) - - -def shared_library_glob_pattern(): - glob = "*." + shared_library_suffix() - return glob if sys.platform == "win32" else "lib" + glob - - -def filter_shared_libraries(libs_list): - def predicate(lib_name): - basename = os.path.basename(lib_name) - if "shiboken" in basename or "pyside6" in basename: - return True - return False - - result = [lib for lib in libs_list if predicate(lib)] - return result - - -# Return qmake link option for a library file name -def link_option(lib): - # On Linux: - # Since we cannot include symlinks with wheel packages - # we are using an absolute path for the libpyside and libshiboken - # libraries when compiling the project - baseName = os.path.basename(lib) - link = " -l" - if sys.platform in [ - "linux", - "linux2", - ]: # Linux: 'libfoo.so' -> '/absolute/path/libfoo.so' - link = lib - elif sys.platform in ["darwin"]: # Darwin: 'libfoo.so' -> '-lfoo' - link += os.path.splitext(baseName[3:])[0] - else: # Windows: 'libfoo.dll' -> 'libfoo.dll' - link += os.path.splitext(baseName)[0] - return link - - -# Locate PySide6 via sys.path package path. -def find_pyside(): - return find_package_path(PYSIDE_MODULE) - - -def find_shiboken_module(): - return find_package_path(SHIBOKEN) - - -def find_shiboken_generator(): - return find_package_path(f"{SHIBOKEN}_generator") - - -def find_package(which_package): - if which_package == Package.SHIBOKEN_MODULE: - return find_shiboken_module() - if which_package == Package.SHIBOKEN_GENERATOR: - return find_shiboken_generator() - if which_package == Package.PYSIDE_MODULE: - return find_pyside() - return None - - -def find_package_path(dir_name): - for p in sys.path: - if "site-" in p: - package = os.path.join(p, dir_name) - if os.path.exists(package): - return clean_path(os.path.realpath(package)) - return None - - -# Return version as "3.6" -def python_version(): - return str(sys.version_info[0]) + "." + str(sys.version_info[1]) - - -def get_python_include_path(): - return sysconfig.get_path("include") - - -def python_link_flags_qmake(): - flags = python_link_data() - if sys.platform == "win32": - libdir = flags["libdir"] - # This will add the "~1" shortcut for directories that - # contain white spaces - # e.g.: "Program Files" to "Progra~1" - for d in libdir.split("\\"): - if " " in d: - libdir = libdir.replace(d, d.split(" ")[0][:-1] + "~1") - lib_flags = flags["lib"] - return f"-L{libdir} -l{lib_flags}" - elif sys.platform == "darwin": - libdir = flags["libdir"] - lib_flags = flags["lib"] - return f"-L{libdir} -l{lib_flags}" - else: - # Linux and anything else - libdir = flags["libdir"] - lib_flags = flags["lib"] - return f"-L{libdir} -l{lib_flags}" - - -def python_link_flags_cmake(): - flags = python_link_data() - libdir = flags["libdir"] - lib = re.sub(r".dll$", ".lib", flags["lib"]) - return f"{libdir};{lib}" - - -def python_link_data(): - # @TODO Fix to work with static builds of Python - libdir = sysconfig.get_config_var("LIBDIR") - if libdir is None: - libdir = os.path.abspath( - os.path.join(sysconfig.get_config_var("LIBDEST"), "..", "libs") - ) - version = python_version() - version_no_dots = version.replace(".", "") - - flags = {} - flags["libdir"] = libdir - if sys.platform == "win32": - suffix = "_d" if is_debug() else "" - flags["lib"] = f"python{version_no_dots}{suffix}" - - elif sys.platform == "darwin": - flags["lib"] = f"python{version}" - - # Linux and anything else - else: - flags["lib"] = f"python{version}{sys.abiflags}" - - return flags - - -def get_package_include_path(which_package): - package_path = find_package(which_package) - if package_path is None: - return None - - includes = f"{package_path}/include" - - return includes - - -def get_package_qmake_lflags(which_package): - package_path = find_package(which_package) - if package_path is None: - return None - - link = f"-L{package_path}" - glob_result = glob.glob(os.path.join(package_path, shared_library_glob_pattern())) - for lib in filter_shared_libraries(glob_result): - link += " " - link += link_option(lib) - return link - - -def get_shared_libraries_data(which_package): - package_path = find_package(which_package) - if package_path is None: - return None - - glob_result = glob.glob(os.path.join(package_path, shared_library_glob_pattern())) - filtered_libs = filter_shared_libraries(glob_result) - libs = [] - if sys.platform == "win32": - for lib in filtered_libs: - libs.append(os.path.realpath(lib)) - else: - for lib in filtered_libs: - libs.append(lib) - return libs - - -def get_shared_libraries_qmake(which_package): - libs = get_shared_libraries_data(which_package) - if libs is None: - return None - - if sys.platform == "win32": - if not libs: - return "" - dlls = "" - for lib in libs: - dll = os.path.splitext(lib)[0] + ".dll" - dlls += dll + " " - - return dlls - else: - libs_string = "" - for lib in libs: - libs_string += lib + " " - return libs_string - - -def get_shared_libraries_cmake(which_package): - libs = get_shared_libraries_data(which_package) - result = ";".join(libs) - return result - - -print_all = option == "-a" -for argument, handler, error, _ in options: - if option == argument or print_all: - handler_result = handler() - if handler_result is None: - sys.exit(error) - - line = handler_result - if print_all: - line = f"{argument:<40}: {line}" - print(line) diff --git a/cmake/shiboken_helper.cmake b/cmake/shiboken_helper.cmake index acd9b9a..5b96d9f 100644 --- a/cmake/shiboken_helper.cmake +++ b/cmake/shiboken_helper.cmake @@ -8,31 +8,6 @@ set(__PYTHON_QT_BINDING_SHIBOKEN_HELPER_INCLUDED TRUE) set(PYTHON_SUFFIX ".cpython-${PYTHON_VERSION_MAJOR}${PYTHON_VERSION_MINOR}m") set(PYTHON_EXTENSION_SUFFIX "${PYTHON_SUFFIX}-${CMAKE_CXX_LIBRARY_ARCHITECTURE}") -find_package(python_qt_binding REQUIRED) - -macro(pyside_config option output_var) - if(${ARGC} GREATER 2) - set(is_list ${ARGV2}) - else() - set(is_list "") - endif() - - execute_process( - COMMAND ${Python3_EXECUTABLE} "${python_qt_binding_DIR}/pyside_config.py" - ${option} - OUTPUT_VARIABLE ${output_var} - OUTPUT_STRIP_TRAILING_WHITESPACE) - - if("${${output_var}}" STREQUAL "") - message(FATAL_ERROR "Error: Calling pyside_config.py ${option} returned no output.") - endif() - if(is_list) - string(REPLACE " " ";" ${output_var} "${${output_var}}") - endif() -endmacro() - - - find_package(Shiboken2 QUIET) if(Shiboken2_FOUND) message(STATUS "Found Shiboken2 version ${Shiboken2_VERSION}") @@ -41,22 +16,10 @@ if(Shiboken2_FOUND) get_property(SHIBOKEN_LIBRARY TARGET Shiboken2::libshiboken PROPERTY LOCATION) set(SHIBOKEN_BINARY Shiboken2::shiboken2) endif() -else() - if(WIN32) - pyside_config(--shiboken-generator-path shiboken_generator_path) - pyside_config(--shiboken-generator-include-path shiboken_include_dir 1) - pyside_config(--shiboken-module-shared-libraries-cmake shiboken_shared_libraries 0) - - set(SHIBOKEN_BINARY "${shiboken_generator_path}/shiboken2${CMAKE_EXECUTABLE_SUFFIX}") - set(SHIBOKEN_LIBRARY ${shiboken_shared_libraries}) - set(SHIBOKEN_INCLUDE_DIR ${shiboken_include_dir}) - endif() + message(STATUS "Using SHIBOKEN_INCLUDE_DIR: ${SHIBOKEN_INCLUDE_DIR}") + message(STATUS "Using SHIBOKEN_LIBRARY: ${SHIBOKEN_LIBRARY}") + message(STATUS "Using SHIBOKEN_BINARY: ${SHIBOKEN_BINARY}") endif() - -message(STATUS "Using SHIBOKEN_INCLUDE_DIR: ${SHIBOKEN_INCLUDE_DIR}") -message(STATUS "Using SHIBOKEN_LIBRARY: ${SHIBOKEN_LIBRARY}") -message(STATUS "Using SHIBOKEN_BINARY: ${SHIBOKEN_BINARY}") - set(PYTHON_BASENAME "${PYTHON_SUFFIX}-${CMAKE_CXX_LIBRARY_ARCHITECTURE}") find_package(PySide2 QUIET) @@ -68,16 +31,7 @@ if(PySide2_FOUND) endif() message(STATUS "Using PYSIDE_INCLUDE_DIR: ${PYSIDE_INCLUDE_DIR}") message(STATUS "Using PYSIDE_LIBRARY: ${PYSIDE_LIBRARY}") -else() - if(WIN32) - pyside_config(--pyside-include-path pyside_include_dir 1) - pyside_config(--pyside-shared-libraries-cmake pyside_shared_libraries 0) - set(PYSIDE_INCLUDE_DIR ${pyside_include_dir}) - set(PYSIDE_LIBRARY ${pyside_shared_libraries}) - endif() endif() -message(STATUS "Using PYSIDE_INCLUDE_DIR: ${PYSIDE_INCLUDE_DIR}") -message(STATUS "Using PYSIDE_LIBRARY: ${PYSIDE_LIBRARY}") set(Python_ADDITIONAL_VERSIONS "${PYTHON_VERSION_MAJOR}.${PYTHON_VERSION_MINOR}") find_package(PythonLibs "${PYTHON_VERSION_MAJOR}.${PYTHON_VERSION_MINOR}") @@ -117,8 +71,7 @@ macro(_shiboken_generator_command VAR GLOBAL TYPESYSTEM INCLUDE_PATH BUILD_DIR) --enable-pyside-extensions --include-paths=${INCLUDE_PATH_WITH_COLONS}${SHIBOKEN_HELPER_INCLUDE_DIRS_WITH_COLONS} --typesystem-paths=${PYSIDE_TYPESYSTEMS} - --output-directory=${BUILD_DIR} ${GLOBAL} ${TYPESYSTEM} - --language-level=c++17) + --output-directory=${BUILD_DIR} ${GLOBAL} ${TYPESYSTEM}) endmacro() @@ -154,16 +107,7 @@ function(shiboken_generator PROJECT_NAME GLOBAL TYPESYSTEM WORKING_DIR GENERATED ) endfunction() -function(shiboken_generator_ext PROJECT_NAME GLOBAL TYPESYSTEM WORKING_DIR GENERATED_SRCS INCLUDE_PATH BUILD_DIR) - _shiboken_generator_command(COMMAND "${GLOBAL}" "${TYPESYSTEM}" "${INCLUDE_PATH}" "${BUILD_DIR}") - add_custom_command( - OUTPUT ${GENERATED_SRCS} - COMMAND ${COMMAND} - DEPENDS ${GLOBAL} ${TYPESYSTEM} - WORKING_DIRECTORY ${WORKING_DIR} - COMMENT "Running Shiboken generator for ${PROJECT_NAME} Python bindings..." - ) -endfunction() + # # Add the Shiboken/PySide specific include directories. # From 1e2994c122572912793004de65ab14711c827099 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Crist=C3=B3bal=20Arroyo?= Date: Thu, 2 Mar 2023 09:31:38 -0500 Subject: [PATCH 10/63] Fix flake8 linter regression (#125) Signed-off-by: Crola1702 --- src/python_qt_binding/binding_helper.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/python_qt_binding/binding_helper.py b/src/python_qt_binding/binding_helper.py index 0cb904f..b7e0658 100644 --- a/src/python_qt_binding/binding_helper.py +++ b/src/python_qt_binding/binding_helper.py @@ -36,8 +36,8 @@ # since the 'future' package provides a 'builtins' module in Python 2 # this must not be checked second import builtins -import platform import os +import platform import sys import traceback From ade88c56e27bcb74732e8bd8475fbda00d722355 Mon Sep 17 00:00:00 2001 From: Michael Carroll Date: Fri, 3 Mar 2023 08:40:26 -0600 Subject: [PATCH 11/63] Fix to allow ninja to use make for generators (#123) Signed-off-by: Michael Carroll Co-authored-by: Chris Lalancette --- cmake/sip_helper.cmake | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/cmake/sip_helper.cmake b/cmake/sip_helper.cmake index 3266e31..edb4c26 100644 --- a/cmake/sip_helper.cmake +++ b/cmake/sip_helper.cmake @@ -93,7 +93,9 @@ function(build_sip_binding PROJECT_NAME SIP_FILE) if(WIN32) set(MAKE_EXECUTABLE NMake.exe) else() - set(MAKE_EXECUTABLE "\$(MAKE)") + find_program(MAKE_PROGRAM NAMES make) + message(STATUS "Found required make: ${MAKE_PROGRAM}") + set(MAKE_EXECUTABLE ${MAKE_PROGRAM}) endif() add_custom_command( From 0b4e832cff75e43c351f199877c8c45ec50b6fbe Mon Sep 17 00:00:00 2001 From: Chris Lalancette Date: Tue, 11 Apr 2023 14:37:43 +0000 Subject: [PATCH 12/63] Changelog. Signed-off-by: Chris Lalancette --- CHANGELOG.rst | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index cea9b3c..b10f9e3 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -2,6 +2,13 @@ Changelog for package python_qt_binding ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Forthcoming +----------- +* Fix to allow ninja to use make for generators (`#123 `_) +* Fix flake8 linter regression (`#125 `_) +* Remove pyqt from default binding order for macOS (`#118 `_) +* Contributors: Christoph Hellmann Santos, Cristóbal Arroyo, Michael Carroll, Rhys Mainwaring + 1.2.2 (2023-02-24) ------------------ * Demote missing SIP message from WARNING to STATUS (`#122 `_) From ae0c68db584a88b56cffc1485d1dd8b776729602 Mon Sep 17 00:00:00 2001 From: Chris Lalancette Date: Tue, 11 Apr 2023 14:37:49 +0000 Subject: [PATCH 13/63] 1.2.3 --- CHANGELOG.rst | 4 ++-- package.xml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index b10f9e3..439931e 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -2,8 +2,8 @@ Changelog for package python_qt_binding ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -Forthcoming ------------ +1.2.3 (2023-04-11) +------------------ * Fix to allow ninja to use make for generators (`#123 `_) * Fix flake8 linter regression (`#125 `_) * Remove pyqt from default binding order for macOS (`#118 `_) diff --git a/package.xml b/package.xml index 123ff3d..c1c6ce3 100644 --- a/package.xml +++ b/package.xml @@ -1,6 +1,6 @@ python_qt_binding - 1.2.2 + 1.2.3 This stack provides Python bindings for Qt. There are two providers: pyside and pyqt. PySide2 is available under From 5bd7233d50799a1c802d867ad46c20eb232e35c5 Mon Sep 17 00:00:00 2001 From: Chris Lalancette Date: Fri, 28 Apr 2023 16:45:53 +0000 Subject: [PATCH 14/63] Changelog Signed-off-by: Chris Lalancette --- CHANGELOG.rst | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 439931e..33c6770 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -2,6 +2,9 @@ Changelog for package python_qt_binding ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Forthcoming +----------- + 1.2.3 (2023-04-11) ------------------ * Fix to allow ninja to use make for generators (`#123 `_) From 6c8f9e3d7a7a06d3b315f90a92fd13764c43b623 Mon Sep 17 00:00:00 2001 From: Chris Lalancette Date: Fri, 28 Apr 2023 16:46:16 +0000 Subject: [PATCH 15/63] 1.3.0 --- CHANGELOG.rst | 4 ++-- package.xml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 33c6770..521cb2a 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -2,8 +2,8 @@ Changelog for package python_qt_binding ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -Forthcoming ------------ +1.3.0 (2023-04-28) +------------------ 1.2.3 (2023-04-11) ------------------ diff --git a/package.xml b/package.xml index c1c6ce3..4a04221 100644 --- a/package.xml +++ b/package.xml @@ -1,6 +1,6 @@ python_qt_binding - 1.2.3 + 1.3.0 This stack provides Python bindings for Qt. There are two providers: pyside and pyqt. PySide2 is available under From e78372fd63eda527c9fad5fcdab8ca31eb3f36d2 Mon Sep 17 00:00:00 2001 From: Chris Lalancette Date: Thu, 7 Dec 2023 13:37:13 -0500 Subject: [PATCH 16/63] Update the SIP support so we can deal with a broken RHEL-9. (#129) There is more information in the patch. With this in place, we can use SIP to build rqt_gui_cpp plugins for RHEL-9. Signed-off-by: Chris Lalancette --- cmake/sip_configure.py | 49 +++++++++++++++++++++++++++++++++--------- 1 file changed, 39 insertions(+), 10 deletions(-) diff --git a/cmake/sip_configure.py b/cmake/sip_configure.py index 708b04c..a0bb315 100644 --- a/cmake/sip_configure.py +++ b/cmake/sip_configure.py @@ -2,8 +2,10 @@ from distutils.spawn import find_executable import os import re +import shutil import subprocess import sys +import tempfile import PyQt5 from PyQt5 import QtCore @@ -111,16 +113,43 @@ def get_sip_dir_flags(config): if sys.platform == 'win32' and os.path.isdir(sip_bin): sip_bin += '.exe' -cmd = [ - sip_bin, - '-c', build_dir, - '-b', os.path.join(build_dir, build_file), - '-I', sip_dir, - '-w' -] -cmd += sip_flags.split(' ') -cmd.append(sip_file) -subprocess.check_call(cmd) +# SIP4 has an incompatibility with Qt 5.15.6. In particular, Qt 5.15.6 uses a new SIP directive +# called py_ssize_t_clean in QtCoremod.sip that SIP4 does not understand. +# +# Unfortunately, the combination of SIP4 and Qt 5.15.6 is common. Archlinux, Ubuntu 22.04 +# and RHEL-9 all have this combination. On Ubuntu 22.04, there is a custom patch to SIP4 +# to make it understand the py_ssize_t_clean tag, so the combination works. But on most +# other platforms, it fails. +# +# To workaround this, copy all of the SIP files into a temporary directory, remove the offending +# line, and then use that temporary directory as the include path. This is unnecessary on +# Ubuntu 22.04, but shouldn't hurt anything there. +with tempfile.TemporaryDirectory() as tmpdirname: + shutil.copytree(sip_dir, tmpdirname, dirs_exist_ok=True) + + output = '' + with open(os.path.join(tmpdirname, 'QtCore', 'QtCoremod.sip'), 'r') as infp: + for line in infp: + if line.startswith('%Module(name='): + result = re.sub(r', py_ssize_t_clean=True', '', line) + output += result + else: + output += line + + with open(os.path.join(tmpdirname, 'QtCore', 'QtCoremod.sip'), 'w') as outfp: + outfp.write(output) + + cmd = [ + sip_bin, + '-c', build_dir, + '-b', os.path.join(build_dir, build_file), + '-I', tmpdirname, + '-w' + ] + cmd += sip_flags.split(' ') + cmd.append(sip_file) + + subprocess.check_call(cmd) # Create the Makefile. The QtModuleMakefile class provided by the # pyqtconfig module takes care of all the extra preprocessor, compiler and From ee4d43bcdb0c5c5d40f81dea3de6185298ab34a7 Mon Sep 17 00:00:00 2001 From: Chris Lalancette Date: Fri, 8 Dec 2023 12:46:47 -0500 Subject: [PATCH 17/63] Cleanup of the sip_configure.py file. (#131) This is to do 2 main things: 1. Move away from distutils.find_executable, which is deprecated. 2. Take a bunch of error handling out of an exception handler. This just makes the code easier to follow if another exception occurs. Signed-off-by: Chris Lalancette --- cmake/sip_configure.py | 52 +++++++++++++++++++++++------------------- 1 file changed, 28 insertions(+), 24 deletions(-) diff --git a/cmake/sip_configure.py b/cmake/sip_configure.py index a0bb315..b35ab00 100644 --- a/cmake/sip_configure.py +++ b/cmake/sip_configure.py @@ -1,5 +1,4 @@ -from copy import copy -from distutils.spawn import find_executable +import copy import os import re import shutil @@ -17,9 +16,9 @@ class Configuration(sipconfig.Configuration): def __init__(self): - env = copy(os.environ) + env = copy.copy(os.environ) env['QT_SELECT'] = '5' - qmake_exe = 'qmake-qt5' if find_executable('qmake-qt5') else 'qmake' + qmake_exe = 'qmake-qt5' if shutil.which('qmake-qt5') else 'qmake' qtconfig = subprocess.check_output( [qmake_exe, '-query'], env=env, universal_newlines=True) qtconfig = dict(line.split(':', 1) for line in qtconfig.splitlines()) @@ -45,7 +44,7 @@ def __init__(self): macros = sipconfig._default_macros.copy() macros['INCDIR_QT'] = qtconfig['QT_INSTALL_HEADERS'] macros['LIBDIR_QT'] = qtconfig['QT_INSTALL_LIBS'] - macros['MOC'] = 'moc-qt5' if find_executable('moc-qt5') else 'moc' + macros['MOC'] = 'moc-qt5' if shutil.which('moc-qt5') else 'moc' self.set_build_macros(macros) @@ -61,25 +60,30 @@ def get_sip_dir_flags(config): sip_flags = config.pyqt_sip_flags return sip_dir, sip_flags except AttributeError: - # sipconfig.Configuration does not have a pyqt_sip_dir or pyqt_sip_flags AttributeError - sip_flags = QtCore.PYQT_CONFIGURATION['sip_flags'] - - # Archlinux installs sip files here by default - default_sip_dir = os.path.join(PyQt5.__path__[0], 'bindings') - if os.path.exists(default_sip_dir): - return default_sip_dir, sip_flags - - # sip4 installs here by default - default_sip_dir = os.path.join(sipconfig._pkg_config['default_sip_dir'], 'PyQt5') - if os.path.exists(default_sip_dir): - return default_sip_dir, sip_flags - - # Homebrew installs sip files here by default - default_sip_dir = os.path.join(sipconfig._pkg_config['default_sip_dir'], 'Qt5') - if os.path.exists(default_sip_dir): - return default_sip_dir, sip_flags - raise FileNotFoundError('The sip directory for PyQt5 could not be located. Please ensure' + - ' that PyQt5 is installed') + pass + + # We didn't find the sip_dir and sip_flags from the config, continue looking + + # sipconfig.Configuration does not have a pyqt_sip_dir or pyqt_sip_flags AttributeError + sip_flags = QtCore.PYQT_CONFIGURATION['sip_flags'] + + candidate_sip_dirs = [] + + # Archlinux installs sip files here by default + candidate_sip_dirs.append(os.path.join(PyQt5.__path__[0], 'bindings')) + + # sip4 installs here by default + candidate_sip_dirs.append(os.path.join(sipconfig._pkg_config['default_sip_dir'], 'PyQt5')) + + # Homebrew installs sip files here by default + candidate_sip_dirs.append(os.path.join(sipconfig._pkg_config['default_sip_dir'], 'Qt5')) + + for sip_dir in candidate_sip_dirs: + if os.path.exists(sip_dir): + return sip_dir, sip_flags + + raise FileNotFoundError('The sip directory for PyQt5 could not be located. Please ensure' + + ' that PyQt5 is installed') if len(sys.argv) != 8: From 2ef9d95e87c7fe6564f757490332e35302b12f9d Mon Sep 17 00:00:00 2001 From: Chris Lalancette Date: Tue, 26 Dec 2023 18:03:01 +0000 Subject: [PATCH 18/63] Changelog. Signed-off-by: Chris Lalancette --- CHANGELOG.rst | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 521cb2a..aa2055e 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -2,6 +2,12 @@ Changelog for package python_qt_binding ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Forthcoming +----------- +* Cleanup of the sip_configure.py file. (`#131 `_) +* Update the SIP support so we can deal with a broken RHEL-9. (`#129 `_) +* Contributors: Chris Lalancette + 1.3.0 (2023-04-28) ------------------ From 150477ff8f71b7090a174ad831e29dbdcef45f0f Mon Sep 17 00:00:00 2001 From: Chris Lalancette Date: Tue, 26 Dec 2023 18:03:10 +0000 Subject: [PATCH 19/63] 2.0.0 --- CHANGELOG.rst | 4 ++-- package.xml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index aa2055e..38bc807 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -2,8 +2,8 @@ Changelog for package python_qt_binding ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -Forthcoming ------------ +2.0.0 (2023-12-26) +------------------ * Cleanup of the sip_configure.py file. (`#131 `_) * Update the SIP support so we can deal with a broken RHEL-9. (`#129 `_) * Contributors: Chris Lalancette diff --git a/package.xml b/package.xml index 4a04221..4494ef5 100644 --- a/package.xml +++ b/package.xml @@ -1,6 +1,6 @@ python_qt_binding - 1.3.0 + 2.0.0 This stack provides Python bindings for Qt. There are two providers: pyside and pyqt. PySide2 is available under From 01070af2d4cd47a1e90e91d4e162ea7b761ee905 Mon Sep 17 00:00:00 2001 From: Chris Lalancette Date: Sun, 7 Jan 2024 19:23:17 -0500 Subject: [PATCH 20/63] Switch to FindPython3 in the shiboken_helper.cmake. (#132) While we are in here, remove some of the old code that deals with older versions of CMake that we no longer have to worry about. Signed-off-by: Chris Lalancette --- cmake/shiboken_helper.cmake | 89 +++++++++++++++---------------------- 1 file changed, 37 insertions(+), 52 deletions(-) diff --git a/cmake/shiboken_helper.cmake b/cmake/shiboken_helper.cmake index 5b96d9f..d2e03e7 100644 --- a/cmake/shiboken_helper.cmake +++ b/cmake/shiboken_helper.cmake @@ -1,13 +1,10 @@ -find_package(PythonInterp "3.3" REQUIRED) +find_package(Python3 REQUIRED COMPONENTS Interpreter Development) if(__PYTHON_QT_BINDING_SHIBOKEN_HELPER_INCLUDED) return() endif() set(__PYTHON_QT_BINDING_SHIBOKEN_HELPER_INCLUDED TRUE) -set(PYTHON_SUFFIX ".cpython-${PYTHON_VERSION_MAJOR}${PYTHON_VERSION_MINOR}m") -set(PYTHON_EXTENSION_SUFFIX "${PYTHON_SUFFIX}-${CMAKE_CXX_LIBRARY_ARCHITECTURE}") - find_package(Shiboken2 QUIET) if(Shiboken2_FOUND) message(STATUS "Found Shiboken2 version ${Shiboken2_VERSION}") @@ -20,7 +17,6 @@ if(Shiboken2_FOUND) message(STATUS "Using SHIBOKEN_LIBRARY: ${SHIBOKEN_LIBRARY}") message(STATUS "Using SHIBOKEN_BINARY: ${SHIBOKEN_BINARY}") endif() -set(PYTHON_BASENAME "${PYTHON_SUFFIX}-${CMAKE_CXX_LIBRARY_ARCHITECTURE}") find_package(PySide2 QUIET) if(PySide2_FOUND) @@ -33,20 +29,9 @@ if(PySide2_FOUND) message(STATUS "Using PYSIDE_LIBRARY: ${PYSIDE_LIBRARY}") endif() -set(Python_ADDITIONAL_VERSIONS "${PYTHON_VERSION_MAJOR}.${PYTHON_VERSION_MINOR}") -find_package(PythonLibs "${PYTHON_VERSION_MAJOR}.${PYTHON_VERSION_MINOR}") - -if(Shiboken2_FOUND AND PySide2_FOUND AND PYTHONLIBS_FOUND) - if(${CMAKE_VERSION} VERSION_LESS "3.14") - # the shiboken invocation needs CMAKE_CXX_IMPLICIT_INCLUDE_DIRECTORIES - # which is broken before CMake 3.14 - # see https://gitlab.kitware.com/cmake/cmake/issues/18394 - message(STATUS "Shiboken binding generator available but CMake version is older than 3.14.") - set(shiboken_helper_NOTFOUND TRUE) - else() - message(STATUS "Shiboken binding generator available.") - set(shiboken_helper_FOUND TRUE) - endif() +if(Shiboken2_FOUND AND PySide2_FOUND) + message(STATUS "Shiboken binding generator available.") + set(shiboken_helper_FOUND TRUE) else() message(STATUS "Shiboken binding generator NOT available.") set(shiboken_helper_NOTFOUND TRUE) @@ -97,14 +82,14 @@ endmacro() # :type BUILD_DIR: string # function(shiboken_generator PROJECT_NAME GLOBAL TYPESYSTEM WORKING_DIR GENERATED_SRCS HDRS INCLUDE_PATH BUILD_DIR) - _shiboken_generator_command(COMMAND "${GLOBAL}" "${TYPESYSTEM}" "${INCLUDE_PATH}" "${BUILD_DIR}") - add_custom_command( - OUTPUT ${GENERATED_SRCS} - COMMAND ${COMMAND} - DEPENDS ${GLOBAL} ${TYPESYSTEM} ${HDRS} - WORKING_DIRECTORY ${WORKING_DIR} - COMMENT "Running Shiboken generator for ${PROJECT_NAME} Python bindings..." - ) + _shiboken_generator_command(COMMAND "${GLOBAL}" "${TYPESYSTEM}" "${INCLUDE_PATH}" "${BUILD_DIR}") + add_custom_command( + OUTPUT ${GENERATED_SRCS} + COMMAND ${COMMAND} + DEPENDS ${GLOBAL} ${TYPESYSTEM} ${HDRS} + WORKING_DIRECTORY ${WORKING_DIR} + COMMENT "Running Shiboken generator for ${PROJECT_NAME} Python bindings..." + ) endfunction() @@ -117,19 +102,19 @@ endfunction() # :type QT_COMPONENTS: list of strings # function(shiboken_include_directories PROJECT_NAME QT_COMPONENTS) - set(shiboken_INCLUDE_DIRECTORIES - ${PYTHON_INCLUDE_DIR} - ${SHIBOKEN_INCLUDE_DIR} - ${PYSIDE_INCLUDE_DIR} - ${PYSIDE_INCLUDE_DIR}/QtCore - ${PYSIDE_INCLUDE_DIR}/QtGui - ) - - foreach(component ${QT_COMPONENTS}) - set(shiboken_INCLUDE_DIRECTORIES ${shiboken_INCLUDE_DIRECTORIES} ${PYSIDE_INCLUDE_DIR}/${component}) - endforeach() - - include_directories(${PROJECT_NAME} ${shiboken_INCLUDE_DIRECTORIES}) + set(shiboken_INCLUDE_DIRECTORIES + ${Python3_INCLUDE_DIRS} + ${SHIBOKEN_INCLUDE_DIR} + ${PYSIDE_INCLUDE_DIR} + ${PYSIDE_INCLUDE_DIR}/QtCore + ${PYSIDE_INCLUDE_DIR}/QtGui + ) + + foreach(component ${QT_COMPONENTS}) + set(shiboken_INCLUDE_DIRECTORIES ${shiboken_INCLUDE_DIRECTORIES} ${PYSIDE_INCLUDE_DIR}/${component}) + endforeach() + + include_directories(${PROJECT_NAME} ${shiboken_INCLUDE_DIRECTORIES}) endfunction() @@ -142,16 +127,16 @@ endfunction() # :type QT_COMPONENTS: list of strings # function(shiboken_target_link_libraries PROJECT_NAME QT_COMPONENTS) - set(shiboken_LINK_LIBRARIES - ${SHIBOKEN_PYTHON_LIBRARIES} - ${SHIBOKEN_LIBRARY} - ${PYSIDE_LIBRARY} - ) - - foreach(component ${QT_COMPONENTS}) - string(TOUPPER ${component} component) - set(shiboken_LINK_LIBRARIES ${shiboken_LINK_LIBRARIES} ${QT_${component}_LIBRARY}) - endforeach() - - target_link_libraries(${PROJECT_NAME} ${shiboken_LINK_LIBRARIES}) + set(shiboken_LINK_LIBRARIES + ${SHIBOKEN_PYTHON_LIBRARIES} + ${SHIBOKEN_LIBRARY} + ${PYSIDE_LIBRARY} + ) + + foreach(component ${QT_COMPONENTS}) + string(TOUPPER ${component} component) + set(shiboken_LINK_LIBRARIES ${shiboken_LINK_LIBRARIES} ${QT_${component}_LIBRARY}) + endforeach() + + target_link_libraries(${PROJECT_NAME} ${shiboken_LINK_LIBRARIES}) endfunction() From 9752e01ffe8d4ec3c4d07b6674ce6d4fe826705d Mon Sep 17 00:00:00 2001 From: Chris Lalancette Date: Wed, 24 Jan 2024 14:39:49 +0000 Subject: [PATCH 21/63] Changelog. Signed-off-by: Chris Lalancette --- CHANGELOG.rst | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 38bc807..c9936e7 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -2,6 +2,11 @@ Changelog for package python_qt_binding ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Forthcoming +----------- +* Switch to FindPython3 in the shiboken_helper.cmake. (`#132 `_) +* Contributors: Chris Lalancette + 2.0.0 (2023-12-26) ------------------ * Cleanup of the sip_configure.py file. (`#131 `_) From d13f31fa4cfcb35730c71969d9664b809d3a8668 Mon Sep 17 00:00:00 2001 From: Chris Lalancette Date: Wed, 24 Jan 2024 14:39:55 +0000 Subject: [PATCH 22/63] 2.1.0 --- CHANGELOG.rst | 4 ++-- package.xml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index c9936e7..2df53eb 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -2,8 +2,8 @@ Changelog for package python_qt_binding ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -Forthcoming ------------ +2.1.0 (2024-01-24) +------------------ * Switch to FindPython3 in the shiboken_helper.cmake. (`#132 `_) * Contributors: Chris Lalancette diff --git a/package.xml b/package.xml index 4494ef5..b03373c 100644 --- a/package.xml +++ b/package.xml @@ -1,6 +1,6 @@ python_qt_binding - 2.0.0 + 2.1.0 This stack provides Python bindings for Qt. There are two providers: pyside and pyqt. PySide2 is available under From e0f21d1cf19e9581406e83069fc462548c73647a Mon Sep 17 00:00:00 2001 From: Chris Lalancette Date: Fri, 26 Jan 2024 10:54:08 -0500 Subject: [PATCH 23/63] Remove unnecessary parentheses around assert. (#133) This makes newer flake8 happy. Signed-off-by: Chris Lalancette --- src/python_qt_binding/binding_helper.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/python_qt_binding/binding_helper.py b/src/python_qt_binding/binding_helper.py index b7e0658..27c3237 100644 --- a/src/python_qt_binding/binding_helper.py +++ b/src/python_qt_binding/binding_helper.py @@ -134,7 +134,7 @@ def _register_binding_module(module_name, module): def _named_import(name): parts = name.split('.') - assert(len(parts) >= 2) + assert len(parts) >= 2 module = builtins.__import__(name) for m in parts[1:]: module = module.__dict__[m] From 03ccb56d200ef92922d3ddac8c925ef6b956e5f2 Mon Sep 17 00:00:00 2001 From: Chris Lalancette Date: Wed, 7 Feb 2024 14:20:10 +0000 Subject: [PATCH 24/63] Changelog. Signed-off-by: Chris Lalancette --- CHANGELOG.rst | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 2df53eb..06d7a86 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -2,6 +2,11 @@ Changelog for package python_qt_binding ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Forthcoming +----------- +* Remove unnecessary parentheses around assert. (`#133 `_) +* Contributors: Chris Lalancette + 2.1.0 (2024-01-24) ------------------ * Switch to FindPython3 in the shiboken_helper.cmake. (`#132 `_) From 180f42738aca63d17561338b2b11056c08a48bc9 Mon Sep 17 00:00:00 2001 From: Chris Lalancette Date: Wed, 7 Feb 2024 14:20:17 +0000 Subject: [PATCH 25/63] 2.1.1 --- CHANGELOG.rst | 4 ++-- package.xml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 06d7a86..547ae82 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -2,8 +2,8 @@ Changelog for package python_qt_binding ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -Forthcoming ------------ +2.1.1 (2024-02-07) +------------------ * Remove unnecessary parentheses around assert. (`#133 `_) * Contributors: Chris Lalancette diff --git a/package.xml b/package.xml index b03373c..9972462 100644 --- a/package.xml +++ b/package.xml @@ -1,6 +1,6 @@ python_qt_binding - 2.1.0 + 2.1.1 This stack provides Python bindings for Qt. There are two providers: pyside and pyqt. PySide2 is available under From 5408ecf63cfbeb0dbc11393b2c34df9c05b21f70 Mon Sep 17 00:00:00 2001 From: Chris Lalancette Date: Tue, 20 Feb 2024 11:35:30 -0500 Subject: [PATCH 26/63] Set hints to find the python version we actually want. (#134) The comment in the commit explains the reasoning behind it. Signed-off-by: Chris Lalancette --- cmake/shiboken_helper.cmake | 16 ++++++++++++++++ cmake/sip_helper.cmake | 16 ++++++++++++++++ 2 files changed, 32 insertions(+) diff --git a/cmake/shiboken_helper.cmake b/cmake/shiboken_helper.cmake index d2e03e7..b71d2be 100644 --- a/cmake/shiboken_helper.cmake +++ b/cmake/shiboken_helper.cmake @@ -1,3 +1,19 @@ +# By default, without the settings below, find_package(Python3) will attempt +# to find the newest python version it can, and additionally will find the +# most specific version. For instance, on a system that has +# /usr/bin/python3.10, /usr/bin/python3.11, and /usr/bin/python3, it will find +# /usr/bin/python3.11, even if /usr/bin/python3 points to /usr/bin/python3.10. +# The behavior we want is to prefer the "system" installed version unless the +# user specifically tells us othewise through the Python3_EXECUTABLE hint. +# Setting CMP0094 to NEW means that the search will stop after the first +# python version is found. Setting Python3_FIND_UNVERSIONED_NAMES means that +# the search will prefer /usr/bin/python3 over /usr/bin/python3.11. And that +# latter functionality is only available in CMake 3.20 or later, so we need +# at least that version. +cmake_minimum_required(VERSION 3.20) +cmake_policy(SET CMP0094 NEW) +set(Python3_FIND_UNVERSIONED_NAMES FIRST) + find_package(Python3 REQUIRED COMPONENTS Interpreter Development) if(__PYTHON_QT_BINDING_SHIBOKEN_HELPER_INCLUDED) diff --git a/cmake/sip_helper.cmake b/cmake/sip_helper.cmake index edb4c26..a5ac3c2 100644 --- a/cmake/sip_helper.cmake +++ b/cmake/sip_helper.cmake @@ -5,6 +5,22 @@ set(__PYTHON_QT_BINDING_SIP_HELPER_INCLUDED TRUE) set(__PYTHON_QT_BINDING_SIP_HELPER_DIR ${CMAKE_CURRENT_LIST_DIR}) +# By default, without the settings below, find_package(Python3) will attempt +# to find the newest python version it can, and additionally will find the +# most specific version. For instance, on a system that has +# /usr/bin/python3.10, /usr/bin/python3.11, and /usr/bin/python3, it will find +# /usr/bin/python3.11, even if /usr/bin/python3 points to /usr/bin/python3.10. +# The behavior we want is to prefer the "system" installed version unless the +# user specifically tells us othewise through the Python3_EXECUTABLE hint. +# Setting CMP0094 to NEW means that the search will stop after the first +# python version is found. Setting Python3_FIND_UNVERSIONED_NAMES means that +# the search will prefer /usr/bin/python3 over /usr/bin/python3.11. And that +# latter functionality is only available in CMake 3.20 or later, so we need +# at least that version. +cmake_minimum_required(VERSION 3.20) +cmake_policy(SET CMP0094 NEW) +set(Python3_FIND_UNVERSIONED_NAMES FIRST) + find_package(Python3 ${Python3_VERSION} REQUIRED COMPONENTS Interpreter Development) execute_process( From ef7b38b2b78bd3392900f08269119640877945d4 Mon Sep 17 00:00:00 2001 From: Christophe Bedard Date: Fri, 23 Feb 2024 12:46:56 -0800 Subject: [PATCH 27/63] Switch to C++17 for SIP and Shiboken (#135) Signed-off-by: Christophe Bedard --- cmake/shiboken_helper.cmake | 1 + cmake/sip_configure.py | 6 +++--- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/cmake/shiboken_helper.cmake b/cmake/shiboken_helper.cmake index b71d2be..14dae5e 100644 --- a/cmake/shiboken_helper.cmake +++ b/cmake/shiboken_helper.cmake @@ -70,6 +70,7 @@ macro(_shiboken_generator_command VAR GLOBAL TYPESYSTEM INCLUDE_PATH BUILD_DIR) set(${VAR} ${SHIBOKEN_BINARY} --generatorSet=shiboken --enable-pyside-extensions + -std=c++17 --include-paths=${INCLUDE_PATH_WITH_COLONS}${SHIBOKEN_HELPER_INCLUDE_DIRS_WITH_COLONS} --typesystem-paths=${PYSIDE_TYPESYSTEMS} --output-directory=${BUILD_DIR} ${GLOBAL} ${TYPESYSTEM}) diff --git a/cmake/sip_configure.py b/cmake/sip_configure.py index b35ab00..5210ee5 100644 --- a/cmake/sip_configure.py +++ b/cmake/sip_configure.py @@ -209,14 +209,14 @@ def split_paths(paths): # redirect location of generated library makefile._target = '"%s"' % os.path.join(output_dir, makefile._target) -# Force c++14 +# Force c++17 if sys.platform == 'win32': - makefile.extra_cxxflags.append('/std:c++14') + makefile.extra_cxxflags.append('/std:c++17') # The __cplusplus flag is not properly set on Windows for backwards # compatibilty. This flag sets it correctly makefile.CXXFLAGS.append('/Zc:__cplusplus') else: - makefile.extra_cxxflags.append('-std=c++14') + makefile.extra_cxxflags.append('-std=c++17') # Finalise the Makefile, preparing it to be saved to disk makefile.finalise() From 29ea65c5c6712fe3dade9fcfb841e49a9d2806e2 Mon Sep 17 00:00:00 2001 From: "Marco A. Gutierrez" Date: Thu, 28 Mar 2024 10:04:22 +0000 Subject: [PATCH 28/63] Changelog. Signed-off-by: Marco A. Gutierrez --- CHANGELOG.rst | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 547ae82..ca3a0b3 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -2,6 +2,12 @@ Changelog for package python_qt_binding ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Forthcoming +----------- +* Switch to C++17 for SIP and Shiboken (`#135 `_) +* Set hints to find the python version we actually want. (`#134 `_) +* Contributors: Chris Lalancette, Christophe Bedard + 2.1.1 (2024-02-07) ------------------ * Remove unnecessary parentheses around assert. (`#133 `_) From 480c8d2756f5be376733eb2c8a9b0a162199a651 Mon Sep 17 00:00:00 2001 From: "Marco A. Gutierrez" Date: Thu, 28 Mar 2024 10:05:01 +0000 Subject: [PATCH 29/63] 2.2.0 Signed-off-by: Marco A. Gutierrez --- CHANGELOG.rst | 4 ++-- package.xml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index ca3a0b3..1df89ec 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -2,8 +2,8 @@ Changelog for package python_qt_binding ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -Forthcoming ------------ +2.2.0 (2024-03-28) +------------------ * Switch to C++17 for SIP and Shiboken (`#135 `_) * Set hints to find the python version we actually want. (`#134 `_) * Contributors: Chris Lalancette, Christophe Bedard diff --git a/package.xml b/package.xml index 9972462..0993696 100644 --- a/package.xml +++ b/package.xml @@ -1,6 +1,6 @@ python_qt_binding - 2.1.1 + 2.2.0 This stack provides Python bindings for Qt. There are two providers: pyside and pyqt. PySide2 is available under From e6b881ee5028e601a2f8aa844ec12b770831d38f Mon Sep 17 00:00:00 2001 From: Chris Lalancette Date: Wed, 24 Apr 2024 15:18:31 -0400 Subject: [PATCH 30/63] Suppress warning from Shiboken2. (#137) The comment has more information on why we are doing this. Signed-off-by: Chris Lalancette --- cmake/shiboken_helper.cmake | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/cmake/shiboken_helper.cmake b/cmake/shiboken_helper.cmake index 14dae5e..0575d63 100644 --- a/cmake/shiboken_helper.cmake +++ b/cmake/shiboken_helper.cmake @@ -21,6 +21,10 @@ if(__PYTHON_QT_BINDING_SHIBOKEN_HELPER_INCLUDED) endif() set(__PYTHON_QT_BINDING_SHIBOKEN_HELPER_INCLUDED TRUE) +# In CMake 3.27 and later, FindPythonInterp and FindPythonLibs are deprecated. +# However, Shiboken2 as packaged in Ubuntu 24.04 still use them, so set CMP0148 to +# "OLD" to silence this warning. +cmake_policy(SET CMP0148 OLD) find_package(Shiboken2 QUIET) if(Shiboken2_FOUND) message(STATUS "Found Shiboken2 version ${Shiboken2_VERSION}") From 4fe5bceb353f5dfcef4f78f9266c0983521bd7ac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alejandro=20Hern=C3=A1ndez=20Cordero?= Date: Thu, 25 Apr 2024 14:25:54 +0200 Subject: [PATCH 31/63] Only suppress Python warnings on new enough CMake (#139) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Older CMake doesn't have the policy, so skip it there. Signed-off-by: Alejandro Hernández Cordero --- cmake/shiboken_helper.cmake | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/cmake/shiboken_helper.cmake b/cmake/shiboken_helper.cmake index 0575d63..7624157 100644 --- a/cmake/shiboken_helper.cmake +++ b/cmake/shiboken_helper.cmake @@ -24,7 +24,9 @@ set(__PYTHON_QT_BINDING_SHIBOKEN_HELPER_INCLUDED TRUE) # In CMake 3.27 and later, FindPythonInterp and FindPythonLibs are deprecated. # However, Shiboken2 as packaged in Ubuntu 24.04 still use them, so set CMP0148 to # "OLD" to silence this warning. -cmake_policy(SET CMP0148 OLD) +if(CMAKE_VERSION VERSION_GREATER_EQUAL "3.27.0") + cmake_policy(SET CMP0148 OLD) +endif() find_package(Shiboken2 QUIET) if(Shiboken2_FOUND) message(STATUS "Found Shiboken2 version ${Shiboken2_VERSION}") From 2fcd33d82b5610c7573c6f72bcd3fc3ec5b735cc Mon Sep 17 00:00:00 2001 From: "Marco A. Gutierrez" Date: Fri, 26 Apr 2024 12:00:58 +0000 Subject: [PATCH 32/63] Changelog. Signed-off-by: Marco A. Gutierrez --- CHANGELOG.rst | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 1df89ec..0555724 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -2,6 +2,14 @@ Changelog for package python_qt_binding ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Forthcoming +----------- +* Only suppress Python warnings on new enough CMake (`#139 `_) + * Older CMake doesn't have the policy, so skip it there. +* Suppress warning from Shiboken2. (`#137 `_) + The comment has more information on why we are doing this. +* Contributors: Alejandro Hernández Cordero, Chris Lalancette + 2.2.0 (2024-03-28) ------------------ * Switch to C++17 for SIP and Shiboken (`#135 `_) From 1fbfb441b86dfc9df252fb7e4a7c0d736a5d1cbe Mon Sep 17 00:00:00 2001 From: "Marco A. Gutierrez" Date: Fri, 26 Apr 2024 12:01:01 +0000 Subject: [PATCH 33/63] 2.3.0 --- CHANGELOG.rst | 4 ++-- package.xml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 0555724..beca44f 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -2,8 +2,8 @@ Changelog for package python_qt_binding ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -Forthcoming ------------ +2.3.0 (2024-04-26) +------------------ * Only suppress Python warnings on new enough CMake (`#139 `_) * Older CMake doesn't have the policy, so skip it there. * Suppress warning from Shiboken2. (`#137 `_) diff --git a/package.xml b/package.xml index 0993696..34703d6 100644 --- a/package.xml +++ b/package.xml @@ -1,6 +1,6 @@ python_qt_binding - 2.2.0 + 2.3.0 This stack provides Python bindings for Qt. There are two providers: pyside and pyqt. PySide2 is available under From 9cae8fd524fa2e9388bfde0c383fc21944b09990 Mon Sep 17 00:00:00 2001 From: Chris Lalancette Date: Mon, 24 Jun 2024 07:34:48 -0400 Subject: [PATCH 34/63] Skip running the tests on Windows Debug. (#142) * Skip running the tests on Windows Debug. When we run CI on Windows Debug, Python expects to be able to find compiled libraries with an extra _d in their filename that contains the debugging ABI. However, we don't currently have a debug library available for PyQt5, and thus when running under Windows Debug, the tests cannot succeed. While we could build a debug library for PyQt5, that is actually a massive undertaking. Instead, just skip these tests when we are on Windows Debug. While that loses us a bit of coverage, it won't matter much; we are still testing this on Windows (Release) and on Linux. The way in which this patch determines that this is a Windows Debug interpreter is a little chintzy. It just uses the fact that the binary is named python_d.exe to discover that. I couldn't find another way to tell if this was a debug interpreter, but I am open to other ideas. Signed-off-by: Chris Lalancette * Update to using importlib.machinery. Thanks to Shane for figuring out this way to tell if we are in a debug interpreter. Signed-off-by: Chris Lalancette --------- Signed-off-by: Chris Lalancette --- test/test_imports.py | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/test/test_imports.py b/test/test_imports.py index 92ba3ca..9fc9d27 100644 --- a/test/test_imports.py +++ b/test/test_imports.py @@ -12,22 +12,39 @@ # See the License for the specific language governing permissions and # limitations under the License. +import importlib.machinery +import sys +import pytest + + +# If this is running on a Python Windows interpreter built in debug mode, skip running tests +# because we do not have the debug libraries available for PyQt. It is surprisingly tricky to +# discover whether the current interpreter was built in debug mode (note that this is different +# than running the interpreter in debug mode, i.e. PYTHONDEBUG=1). The only non-deprecated way +# we've found is to look for _d.pyd in the extension suffixes, so that is what we do here. +is_windows_debug = sys.platform == 'win32' and '_d.pyd' in importlib.machinery.EXTENSION_SUFFIXES + + +@pytest.mark.skipif(is_windows_debug, reason='Skipping test on Windows Debug') def test_import_qtcore(): from python_qt_binding import QtCore assert QtCore is not None +@pytest.mark.skipif(is_windows_debug, reason='Skipping test on Windows Debug') def test_import_qtgui(): from python_qt_binding import QtGui assert QtGui is not None +@pytest.mark.skipif(is_windows_debug, reason='Skipping test on Windows Debug') def test_import_qtwidgets(): from python_qt_binding import QtWidgets assert QtWidgets is not None +@pytest.mark.skipif(is_windows_debug, reason='Skipping test on Windows Debug') def test_import_qtobject(): from python_qt_binding.QtCore import QObject assert QObject is not None From 6855bd41dbdab95cad6301cf76eacbb283fba4ae Mon Sep 17 00:00:00 2001 From: Chris Lalancette Date: Tue, 25 Jun 2024 18:02:03 +0000 Subject: [PATCH 35/63] Changelog. Signed-off-by: Chris Lalancette --- CHANGELOG.rst | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index beca44f..aa7e0ea 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -2,6 +2,11 @@ Changelog for package python_qt_binding ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Forthcoming +----------- +* Skip running the tests on Windows Debug. (`#142 `_) +* Contributors: Chris Lalancette + 2.3.0 (2024-04-26) ------------------ * Only suppress Python warnings on new enough CMake (`#139 `_) From d68d3d4221dd4dcbb0d37046a1dac3a6742f49e3 Mon Sep 17 00:00:00 2001 From: Chris Lalancette Date: Tue, 25 Jun 2024 18:02:08 +0000 Subject: [PATCH 36/63] 2.3.1 --- CHANGELOG.rst | 4 ++-- package.xml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index aa7e0ea..4f7e5ad 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -2,8 +2,8 @@ Changelog for package python_qt_binding ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -Forthcoming ------------ +2.3.1 (2024-06-25) +------------------ * Skip running the tests on Windows Debug. (`#142 `_) * Contributors: Chris Lalancette diff --git a/package.xml b/package.xml index 34703d6..08fa8ab 100644 --- a/package.xml +++ b/package.xml @@ -1,6 +1,6 @@ python_qt_binding - 2.3.0 + 2.3.1 This stack provides Python bindings for Qt. There are two providers: pyside and pyqt. PySide2 is available under From f6b4d9a9d57e543d6ca3b3386d2c1e30096de9c7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alejandro=20Hern=C3=A1ndez=20Cordero?= Date: Mon, 2 Dec 2024 18:05:44 +0100 Subject: [PATCH 37/63] Remove CODEOWNERS (#144) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Alejandro Hernández Cordero --- CODEOWNERS | 2 -- 1 file changed, 2 deletions(-) delete mode 100644 CODEOWNERS diff --git a/CODEOWNERS b/CODEOWNERS deleted file mode 100644 index 2a976b9..0000000 --- a/CODEOWNERS +++ /dev/null @@ -1,2 +0,0 @@ -# This file was generated by https://github.com/audrow/update-ros2-repos -* @sloretz From 454aadef8e7832ca2e2194e1d154615482a91958 Mon Sep 17 00:00:00 2001 From: Chris Lalancette Date: Mon, 2 Dec 2024 14:35:10 -0500 Subject: [PATCH 38/63] Remove the mirror-rolling-to-main workflow. (#145) We no longer need to keep the main branch up-to-date, so drop the workflow. Signed-off-by: Chris Lalancette --- .github/workflows/mirror-rolling-to-main.yaml | 13 ------------- 1 file changed, 13 deletions(-) delete mode 100644 .github/workflows/mirror-rolling-to-main.yaml diff --git a/.github/workflows/mirror-rolling-to-main.yaml b/.github/workflows/mirror-rolling-to-main.yaml deleted file mode 100644 index 7b0b92e..0000000 --- a/.github/workflows/mirror-rolling-to-main.yaml +++ /dev/null @@ -1,13 +0,0 @@ -name: Mirror rolling to main - -on: - push: - branches: [ rolling ] - -jobs: - mirror-to-main: - runs-on: ubuntu-latest - steps: - - uses: zofrex/mirror-branch@v1 - with: - target-branch: main From 9b7fc175ff9891fe649f307a02aaf18230c98e67 Mon Sep 17 00:00:00 2001 From: Scott K Logan Date: Mon, 28 Apr 2025 16:22:51 -0500 Subject: [PATCH 39/63] 2.4.0 --- CHANGELOG.rst | 6 ++++++ package.xml | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 4f7e5ad..f37f392 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -2,6 +2,12 @@ Changelog for package python_qt_binding ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +2.4.0 (2025-04-28) +------------------ +* Remove the mirror-rolling-to-main workflow (`#145 `_) +* Remove CODEOWNERS (`#144 `_) +* Contributors: Alejandro Hernández Cordero, Chris Lalancette + 2.3.1 (2024-06-25) ------------------ * Skip running the tests on Windows Debug. (`#142 `_) diff --git a/package.xml b/package.xml index 08fa8ab..b30f4d0 100644 --- a/package.xml +++ b/package.xml @@ -1,6 +1,6 @@ python_qt_binding - 2.3.1 + 2.4.0 This stack provides Python bindings for Qt. There are two providers: pyside and pyqt. PySide2 is available under From 19eee00ecc5bb7e7e943175f04404c9087a3c864 Mon Sep 17 00:00:00 2001 From: mosfet80 <10235105+mosfet80@users.noreply.github.com> Date: Fri, 3 Oct 2025 09:57:08 +0200 Subject: [PATCH 40/63] fix cmake deprecation (#150) cmake version < then 3.10 is deprecated --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 919969e..9c00505 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.5) +cmake_minimum_required(VERSION 3.20) project(python_qt_binding) find_package(ament_cmake REQUIRED) From 7a013569b355b4b4e04c138dedb075ce4b7bcab1 Mon Sep 17 00:00:00 2001 From: mosfet80 <10235105+mosfet80@users.noreply.github.com> Date: Mon, 6 Oct 2025 10:00:58 +0200 Subject: [PATCH 41/63] fix setuptools deprecation (#151) Signed-off-by: Alejandro Hernandez Cordero Co-authored-by: Alejandro Hernandez Cordero --- setup.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/setup.py b/setup.py index 5fd3c3b..0a9e28b 100755 --- a/setup.py +++ b/setup.py @@ -38,10 +38,8 @@ 'Operating System :: OS Independent', 'Programming Language :: Python', 'Topic :: Software Development :: Libraries :: Python Modules', - 'License :: OSI Approved :: BSD License', - 'License :: OSI Approved :: GNU Library or Lesser General Public License (LGPL)', - 'License :: OSI Approved :: GNU General Public License (GPL)', ], + license: ['BSD'], }) setup(**d) From 65847a99e728fee8f1448ebce8d0d69ef1879170 Mon Sep 17 00:00:00 2001 From: Alejandro Hernandez Cordero Date: Wed, 8 Oct 2025 15:57:07 +0200 Subject: [PATCH 42/63] Changelog Signed-off-by: Alejandro Hernandez Cordero --- CHANGELOG.rst | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index f37f392..0836aa9 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -2,6 +2,12 @@ Changelog for package python_qt_binding ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +2.4.1 (2025-10-08) +------------------ +* fix setuptools deprecation (`#151 `_) +* fix cmake deprecation (`#150 `_) +* Contributors: mosfet80 + 2.4.0 (2025-04-28) ------------------ * Remove the mirror-rolling-to-main workflow (`#145 `_) From 20bcb5f7bf314f225dd9f5295de0e72ecca8bae2 Mon Sep 17 00:00:00 2001 From: Alejandro Hernandez Cordero Date: Wed, 8 Oct 2025 15:57:11 +0200 Subject: [PATCH 43/63] 2.4.1 --- package.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.xml b/package.xml index b30f4d0..df2b169 100644 --- a/package.xml +++ b/package.xml @@ -1,6 +1,6 @@ python_qt_binding - 2.4.0 + 2.4.1 This stack provides Python bindings for Qt. There are two providers: pyside and pyqt. PySide2 is available under From 17b0b88021e4a320885fd21e9097ed9dc08cc4ba Mon Sep 17 00:00:00 2001 From: Shane Loretz Date: Sat, 11 Apr 2026 16:52:04 -0700 Subject: [PATCH 44/63] Use sip-build and python3_add_library for Qt5/Qt6 (#157) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Try using sip-build and Python3_add_library for Qt5/Qt6 Signed-off-by: Shane Loretz * Progress, but I shouldn't touch this Signed-off-by: Shane Loretz * Closer, but compile errors from generated sip C++ code Signed-off-by: Shane Loretz * Get SIP ABI from PyQt5 bindings Signed-off-by: Shane Loretz * Refactor Signed-off-by: Shane Loretz * Got it working, mostly b/c I forgot about sip_DEPENDENCIES arg Signed-off-by: Shane Loretz * Newline at end of file Signed-off-by: Shane Loretz * Lint CMake Signed-off-by: Shane Loretz * Adding sip-build to python3-qt5-bindings rosdep key Signed-off-by: Shane Loretz * Support Qt5 and Qt6 Signed-off-by: Shane Loretz * Include all generated sip c/c++ files Signed-off-by: Shane Loretz * Forced to use pyqtbuilder, but sip API conflict Signed-off-by: Shane Loretz * Generate pyproject.toml using configure_file Signed-off-by: Shane Loretz * Update python_qt_binding-extras.cmake * use new python3-qt-bindings key Signed-off-by: Shane Loretz * Choose Qt version Signed-off-by: Alejandro Hernandez Cordero * Choose Qt version Signed-off-by: Alejandro Hernandez Cordero * Search for qmake-qt5, and don't add a target dep on a configure-time generated file Signed-off-by: Shane Loretz * line-length Signed-off-by: Shane Loretz --------- Signed-off-by: Shane Loretz Signed-off-by: Alejandro Hernandez Cordero Co-authored-by: Alejandro Hernández Cordero --- CMakeLists.txt | 19 +- cmake/pyproject.toml.in | 28 +++ cmake/sip_configure.py | 231 ------------------------ cmake/sip_helper.cmake | 174 +++++++++++------- package.xml | 6 +- python_qt_binding-extras.cmake | 9 + src/python_qt_binding/binding_helper.py | 50 ++--- 7 files changed, 192 insertions(+), 325 deletions(-) create mode 100644 cmake/pyproject.toml.in delete mode 100644 cmake/sip_configure.py create mode 100644 python_qt_binding-extras.cmake diff --git a/CMakeLists.txt b/CMakeLists.txt index 9c00505..61850b1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -4,12 +4,23 @@ project(python_qt_binding) find_package(ament_cmake REQUIRED) find_package(ament_cmake_python REQUIRED) +# Copy python package into binary directory +file(COPY src/${PROJECT_NAME} DESTINATION ${CMAKE_CURRENT_BINARY_DIR}) + +include(python_qt_binding-extras.cmake) + +# Generate a version.py file inside the copied package directory +file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}/version.py + "QT_MAJOR_VERSION = ${python_qt_binding_QT_MAJOR_VERSION}\n" +) + +# Install the package from the binary directory ament_python_install_package(${PROJECT_NAME} - PACKAGE_DIR src/${PROJECT_NAME}) + PACKAGE_DIR ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}) install(FILES + cmake/pyproject.toml.in cmake/shiboken_helper.cmake - cmake/sip_configure.py cmake/sip_helper.cmake DESTINATION share/${PROJECT_NAME}/cmake) @@ -27,4 +38,6 @@ if(BUILD_TESTING) TIMEOUT 90) endif() -ament_package() +ament_package( + CONFIG_EXTRAS "python_qt_binding-extras.cmake" +) diff --git a/cmake/pyproject.toml.in b/cmake/pyproject.toml.in new file mode 100644 index 0000000..cbb51a6 --- /dev/null +++ b/cmake/pyproject.toml.in @@ -0,0 +1,28 @@ +[build-system] +requires = ["sip >=6, <7"] +build-backend = "sipbuild.api" + +[project] +name = "@PROJECT_NAME@" +version = "1.0.0" + +[tool.sip] +project-factory = "pyqtbuild:PyQtProject" + +[tool.sip.builder] +qmake = "@python_qt_binding_QMAKE_EXECUTABLE@" + +[tool.sip.project] +build-dir = "@SIP_BUILD_DIR@" +sip-files-dir = "@sip_SOURCE_DIR@" +sip-include-dirs = ["@__PYQT_BINDINGS_DIR@"] +abi-version = "@__QT_SIP_ABI_VERSION@" + +[tool.sip.bindings.@PROJECT_NAME@] +sip-file = "@SIP_FILE_NAME@" + +[tool.sip.metadata] +name = "@PROJECT_NAME@" +version = "1.0.0" +summary = "This stack provides Python bindings for Qt" +home-page = "https://github.com/ros-visualization/python_qt_binding" \ No newline at end of file diff --git a/cmake/sip_configure.py b/cmake/sip_configure.py deleted file mode 100644 index 5210ee5..0000000 --- a/cmake/sip_configure.py +++ /dev/null @@ -1,231 +0,0 @@ -import copy -import os -import re -import shutil -import subprocess -import sys -import tempfile - -import PyQt5 -from PyQt5 import QtCore -import sipconfig - -libqt5_rename = False - - -class Configuration(sipconfig.Configuration): - - def __init__(self): - env = copy.copy(os.environ) - env['QT_SELECT'] = '5' - qmake_exe = 'qmake-qt5' if shutil.which('qmake-qt5') else 'qmake' - qtconfig = subprocess.check_output( - [qmake_exe, '-query'], env=env, universal_newlines=True) - qtconfig = dict(line.split(':', 1) for line in qtconfig.splitlines()) - pyqtconfig = { - 'qt_archdata_dir': qtconfig['QT_INSTALL_DATA'], - 'qt_data_dir': qtconfig['QT_INSTALL_DATA'], - 'qt_dir': qtconfig['QT_INSTALL_PREFIX'], - 'qt_inc_dir': qtconfig['QT_INSTALL_HEADERS'], - 'qt_lib_dir': qtconfig['QT_INSTALL_LIBS'], - 'qt_threaded': 1, - 'qt_version': QtCore.QT_VERSION, - 'qt_winconfig': 'shared exceptions', - } - if sys.platform == 'darwin': - if os.path.exists(os.path.join(qtconfig['QT_INSTALL_LIBS'], 'QtCore.framework')): - pyqtconfig['qt_framework'] = 1 - else: - global libqt5_rename - libqt5_rename = True - - sipconfig.Configuration.__init__(self, [pyqtconfig]) - - macros = sipconfig._default_macros.copy() - macros['INCDIR_QT'] = qtconfig['QT_INSTALL_HEADERS'] - macros['LIBDIR_QT'] = qtconfig['QT_INSTALL_LIBS'] - macros['MOC'] = 'moc-qt5' if shutil.which('moc-qt5') else 'moc' - self.set_build_macros(macros) - - -def get_sip_dir_flags(config): - """ - Get the extra SIP flags needed by the imported qt module, and locate PyQt5 sip install files. - - Note that this normally only includes those flags (-x and -t) that relate to SIP's versioning - system. - """ - try: - sip_dir = config.pyqt_sip_dir - sip_flags = config.pyqt_sip_flags - return sip_dir, sip_flags - except AttributeError: - pass - - # We didn't find the sip_dir and sip_flags from the config, continue looking - - # sipconfig.Configuration does not have a pyqt_sip_dir or pyqt_sip_flags AttributeError - sip_flags = QtCore.PYQT_CONFIGURATION['sip_flags'] - - candidate_sip_dirs = [] - - # Archlinux installs sip files here by default - candidate_sip_dirs.append(os.path.join(PyQt5.__path__[0], 'bindings')) - - # sip4 installs here by default - candidate_sip_dirs.append(os.path.join(sipconfig._pkg_config['default_sip_dir'], 'PyQt5')) - - # Homebrew installs sip files here by default - candidate_sip_dirs.append(os.path.join(sipconfig._pkg_config['default_sip_dir'], 'Qt5')) - - for sip_dir in candidate_sip_dirs: - if os.path.exists(sip_dir): - return sip_dir, sip_flags - - raise FileNotFoundError('The sip directory for PyQt5 could not be located. Please ensure' + - ' that PyQt5 is installed') - - -if len(sys.argv) != 8: - print('usage: %s build-dir sip-file output_dir include_dirs libs lib_dirs ldflags' % - sys.argv[0]) - sys.exit(1) - -# The SIP build folder, the SIP file, the output directory, the include -# directories, the libraries, the library directories and the linker -# flags. -build_dir, sip_file, output_dir, include_dirs, libs, lib_dirs, ldflags = sys.argv[1:] - -# The name of the SIP build file generated by SIP and used by the build system. -build_file = 'pyqtscripting.sbf' - -# Get the PyQt configuration information. -config = Configuration() - -sip_dir, sip_flags = get_sip_dir_flags(config) - -try: - os.makedirs(build_dir) -except OSError: - pass - -# Run SIP to generate the code. Note that we tell SIP where to find the qt -# module's specification files using the -I flag. - -sip_bin = config.sip_bin -# Without the .exe, this might actually be a directory in Windows -if sys.platform == 'win32' and os.path.isdir(sip_bin): - sip_bin += '.exe' - -# SIP4 has an incompatibility with Qt 5.15.6. In particular, Qt 5.15.6 uses a new SIP directive -# called py_ssize_t_clean in QtCoremod.sip that SIP4 does not understand. -# -# Unfortunately, the combination of SIP4 and Qt 5.15.6 is common. Archlinux, Ubuntu 22.04 -# and RHEL-9 all have this combination. On Ubuntu 22.04, there is a custom patch to SIP4 -# to make it understand the py_ssize_t_clean tag, so the combination works. But on most -# other platforms, it fails. -# -# To workaround this, copy all of the SIP files into a temporary directory, remove the offending -# line, and then use that temporary directory as the include path. This is unnecessary on -# Ubuntu 22.04, but shouldn't hurt anything there. -with tempfile.TemporaryDirectory() as tmpdirname: - shutil.copytree(sip_dir, tmpdirname, dirs_exist_ok=True) - - output = '' - with open(os.path.join(tmpdirname, 'QtCore', 'QtCoremod.sip'), 'r') as infp: - for line in infp: - if line.startswith('%Module(name='): - result = re.sub(r', py_ssize_t_clean=True', '', line) - output += result - else: - output += line - - with open(os.path.join(tmpdirname, 'QtCore', 'QtCoremod.sip'), 'w') as outfp: - outfp.write(output) - - cmd = [ - sip_bin, - '-c', build_dir, - '-b', os.path.join(build_dir, build_file), - '-I', tmpdirname, - '-w' - ] - cmd += sip_flags.split(' ') - cmd.append(sip_file) - - subprocess.check_call(cmd) - -# Create the Makefile. The QtModuleMakefile class provided by the -# pyqtconfig module takes care of all the extra preprocessor, compiler and -# linker flags needed by the Qt library. -makefile = sipconfig.SIPModuleMakefile( - dir=build_dir, - configuration=config, - build_file=build_file, - qt=['QtCore', 'QtGui'] -) - -# hack to override makefile behavior which always prepend -l to libraries -# which is wrong for absolute paths -default_platform_lib_function = sipconfig.SIPModuleMakefile.platform_lib - - -def custom_platform_lib_function(self, clib, framework=0): - if not clib or clib.isspace(): - return None - # Only add '-l' if a library doesn't already start with '-l' and is not an absolute path - if os.path.isabs(clib) or clib.startswith('-l'): - return clib - - global libqt5_rename - # sip renames libs to Qt5 automatically on Linux, but not on macOS - if libqt5_rename and not framework and clib.startswith('Qt') and not clib.startswith('Qt5'): - return '-lQt5' + clib[2:] - - return default_platform_lib_function(self, clib, framework) - - -sipconfig.SIPModuleMakefile.platform_lib = custom_platform_lib_function - - -# split paths on whitespace -# while dealing with whitespaces within the paths if they are escaped with backslashes -def split_paths(paths): - paths = re.split('(?<=[^\\\\]) ', paths) - return paths - - -for include_dir in split_paths(include_dirs): - include_dir = include_dir.replace('\\', '') - makefile.extra_include_dirs.append(include_dir) -for lib in split_paths(libs): - makefile.extra_libs.append(lib) -for lib_dir in split_paths(lib_dirs): - lib_dir = lib_dir.replace('\\', '') - makefile.extra_lib_dirs.append(lib_dir) -for ldflag in ldflags.split('\\ '): - makefile.LFLAGS.append(ldflag) - -# redirect location of generated library -makefile._target = '"%s"' % os.path.join(output_dir, makefile._target) - -# Force c++17 -if sys.platform == 'win32': - makefile.extra_cxxflags.append('/std:c++17') - # The __cplusplus flag is not properly set on Windows for backwards - # compatibilty. This flag sets it correctly - makefile.CXXFLAGS.append('/Zc:__cplusplus') -else: - makefile.extra_cxxflags.append('-std=c++17') - -# Finalise the Makefile, preparing it to be saved to disk -makefile.finalise() - -# Replace Qt variables from libraries -libs = makefile.LIBS.as_list() -for i in range(len(libs)): - libs[i] = libs[i].replace('$$[QT_INSTALL_LIBS]', config.build_macros()['LIBDIR_QT']) -makefile.LIBS.set(libs) - -# Generate the Makefile itself -makefile.generate() diff --git a/cmake/sip_helper.cmake b/cmake/sip_helper.cmake index a5ac3c2..f5c2a4c 100644 --- a/cmake/sip_helper.cmake +++ b/cmake/sip_helper.cmake @@ -5,47 +5,97 @@ set(__PYTHON_QT_BINDING_SIP_HELPER_INCLUDED TRUE) set(__PYTHON_QT_BINDING_SIP_HELPER_DIR ${CMAKE_CURRENT_LIST_DIR}) -# By default, without the settings below, find_package(Python3) will attempt -# to find the newest python version it can, and additionally will find the -# most specific version. For instance, on a system that has -# /usr/bin/python3.10, /usr/bin/python3.11, and /usr/bin/python3, it will find -# /usr/bin/python3.11, even if /usr/bin/python3 points to /usr/bin/python3.10. -# The behavior we want is to prefer the "system" installed version unless the -# user specifically tells us othewise through the Python3_EXECUTABLE hint. -# Setting CMP0094 to NEW means that the search will stop after the first -# python version is found. Setting Python3_FIND_UNVERSIONED_NAMES means that -# the search will prefer /usr/bin/python3 over /usr/bin/python3.11. And that -# latter functionality is only available in CMake 3.20 or later, so we need -# at least that version. cmake_minimum_required(VERSION 3.20) cmake_policy(SET CMP0094 NEW) set(Python3_FIND_UNVERSIONED_NAMES FIRST) find_package(Python3 ${Python3_VERSION} REQUIRED COMPONENTS Interpreter Development) +# Find the directory containing the SIP bindings shipped by PyQt. +# +# :param python_qt_binding_QT_MAJOR_VERSION: The major version of Qt (e.g., 5 or 6). +# +# :out __PYQT_BINDINGS_DIR: Path to the directory containing QT*.sip files. +# :out __PYQT_BINDINGS_FOUND: Boolean indicating if the bindings were located. +# +function(__find_qt_sip_files python_qt_binding_QT_MAJOR_VERSION) + set(MODULE_NAME "PyQt${python_qt_binding_QT_MAJOR_VERSION}") + + execute_process( + COMMAND ${Python3_EXECUTABLE} -c "import ${MODULE_NAME}.bindings as pb; print(pb.__path__[0])" + OUTPUT_VARIABLE BINDINGS_DIR + OUTPUT_STRIP_TRAILING_WHITESPACE + ERROR_QUIET + RESULT_VARIABLE _res + ) + + if(_res EQUAL 0 AND IS_DIRECTORY "${BINDINGS_DIR}") + set(__PYQT_BINDINGS_DIR "${BINDINGS_DIR}" PARENT_SCOPE) + set(__PYQT_BINDINGS_FOUND TRUE PARENT_SCOPE) + message(STATUS "Found ${MODULE_NAME} SIP bindings at: ${BINDINGS_DIR}") + else() + set(__PYQT_BINDINGS_FOUND FALSE PARENT_SCOPE) + message(WARNING "Could not determine ${MODULE_NAME} bindings directory.") + endif() +endfunction() + +# Extract the sip-abi-version from PyQt's configuration +# +# :param BINDINGS_DIR: Path to the directory containing QT*.sip files. +# :out __QT_SIP_ABI_VERSION: The detected ABI version (defaults to 12). +function(__find_qt_sip_abi BINDINGS_DIR) + # Default to 12 if detection fails + set(DETECTED_ABI "12") + set(TOML_FILE "${BINDINGS_DIR}/QtCore/QtCore.toml") + + if(EXISTS "${TOML_FILE}") + file(READ "${TOML_FILE}" TOML_CONTENT_STR) + if(TOML_CONTENT_STR MATCHES "sip-abi-version[ \t]*=[ \t]*\"([^\"]+)\"") + set(DETECTED_ABI ${CMAKE_MATCH_1}) + message(STATUS "Detected SIP ABI version: ${DETECTED_ABI}") + endif() + else() + message(STATUS "QtCore.toml not found at ${TOML_FILE}, defaulting SIP ABI to 12") + endif() + + set(__QT_SIP_ABI_VERSION "${DETECTED_ABI}" PARENT_SCOPE) +endfunction() + +# Check if modern sipbuild is available via python module execute_process( - COMMAND ${Python3_EXECUTABLE} -c "import sipconfig; print(sipconfig.Configuration().sip_bin)" - OUTPUT_VARIABLE PYTHON_SIP_EXECUTABLE + COMMAND ${Python3_EXECUTABLE} -c "import sipbuild" + RESULT_VARIABLE _sipbuild_res ERROR_QUIET) -if(PYTHON_SIP_EXECUTABLE) - string(STRIP ${PYTHON_SIP_EXECUTABLE} SIP_EXECUTABLE) -else() - find_program(SIP_EXECUTABLE sip) -endif() - -if(SIP_EXECUTABLE) - message(STATUS "SIP binding generator available at: ${SIP_EXECUTABLE}") +if(_sipbuild_res EQUAL 0) + message(STATUS "Modern SIP binding generator (sip-build) is available.") set(sip_helper_FOUND TRUE) else() - message(STATUS "SIP binding generator NOT available.") + message(STATUS "Modern SIP binding generator NOT available.") set(sip_helper_NOTFOUND TRUE) endif() +# Find Qt's installed SIP files +__find_qt_sip_files(${python_qt_binding_QT_MAJOR_VERSION}) +if(NOT __PYQT_BINDINGS_FOUND) + message(FATAL_ERROR "PyQt${python_qt_binding_QT_MAJOR_VERSION} SIP bindings are required but were not found.") +endif() + +# Extract the sip-abi-version from PyQt +__find_qt_sip_abi("${__PYQT_BINDINGS_DIR}") + +# Find qmake +find_program(python_qt_binding_QMAKE_EXECUTABLE + NAMES + qmake${python_qt_binding_QT_MAJOR_VERSION} + qmake-qt${python_qt_binding_QT_MAJOR_VERSION} + qmake + REQUIRED) + # # Run the SIP generator and compile the generated code into a library. # -# .. note:: The target lib${PROJECT_NAME} is created. +# .. note:: Creates a target named lib${PROJECT_NAME} # # :param PROJECT_NAME: The name of the sip project # :type PROJECT_NAME: string @@ -53,17 +103,14 @@ endif() # :type SIP_FILE: string # # The following options can be used to override the default behavior: -# SIP_CONFIGURE: the used configure script for SIP -# (default: sip_configure.py in the same folder as this file) +# SIP_CONFIGURE: (IGNORED) Retained for CMake API compatibility only. # SOURCE_DIR: the source dir (default: ${PROJECT_SOURCE_DIR}/src) # LIBRARY_DIR: the library dir (default: ${PROJECT_SOURCE_DIR}/src) # BINARY_DIR: the binary dir (default: ${PROJECT_BINARY_DIR}) # # The following keywords arguments can be used to specify: -# DEPENDS: depends for the custom command -# (should list all sip and header files) +# DEPENDS: depends for the custom command (should list all sip and header files) # DEPENDENCIES: target dependencies -# (should list the library for which SIP generates the bindings) # function(build_sip_binding PROJECT_NAME SIP_FILE) cmake_parse_arguments(sip "" "SIP_CONFIGURE;SOURCE_DIR;LIBRARY_DIR;BINARY_DIR" "DEPENDS;DEPENDENCIES" ${ARGN}) @@ -71,11 +118,11 @@ function(build_sip_binding PROJECT_NAME SIP_FILE) message(WARNING "build_sip_binding(${PROJECT_NAME}) called with unused arguments: ${sip_UNPARSED_ARGUMENTS}") endif() - # set default values for optional arguments - if(NOT sip_SIP_CONFIGURE) - # default to sip_configure.py in this directory - set(sip_SIP_CONFIGURE ${__PYTHON_QT_BINDING_SIP_HELPER_DIR}/sip_configure.py) + if(sip_SIP_CONFIGURE) + message(WARNING "SIP_CONFIGURE argument is deprecated and ignored. CMake now handles configuration natively.") endif() + + # set default values for optional arguments if(NOT sip_SOURCE_DIR) set(sip_SOURCE_DIR ${PROJECT_SOURCE_DIR}/src) endif() @@ -88,43 +135,42 @@ function(build_sip_binding PROJECT_NAME SIP_FILE) set(SIP_BUILD_DIR ${sip_BINARY_DIR}/sip/${PROJECT_NAME}) - set(INCLUDE_DIRS ${${PROJECT_NAME}_INCLUDE_DIRS} ${Python3_INCLUDE_DIRS}) - set(LIBRARIES ${${PROJECT_NAME}_LIBRARIES}) - set(LIBRARY_DIRS ${${PROJECT_NAME}_LIBRARY_DIRS}) - set(LDFLAGS_OTHER ${${PROJECT_NAME}_LDFLAGS_OTHER}) + # Extract the filename from the SIP_FILE path + get_filename_component(SIP_FILE_NAME ${SIP_FILE} NAME) - add_custom_command( - OUTPUT ${SIP_BUILD_DIR}/Makefile - COMMAND ${Python3_EXECUTABLE} ${sip_SIP_CONFIGURE} ${SIP_BUILD_DIR} ${SIP_FILE} ${sip_LIBRARY_DIR} - \"${INCLUDE_DIRS}\" \"${LIBRARIES}\" \"${LIBRARY_DIRS}\" \"${LDFLAGS_OTHER}\" - DEPENDS ${sip_SIP_CONFIGURE} ${SIP_FILE} ${sip_DEPENDS} - WORKING_DIRECTORY ${sip_SOURCE_DIR} - COMMENT "Running SIP generator for ${PROJECT_NAME} Python bindings..." - ) + # Generate a pyproject.toml to be given to sip-build + file(MAKE_DIRECTORY ${SIP_BUILD_DIR}) - if(NOT EXISTS "${sip_LIBRARY_DIR}") - file(MAKE_DIRECTORY ${sip_LIBRARY_DIR}) - endif() + set(PYPROJECT_TOML "${SIP_BUILD_DIR}/pyproject.toml") + configure_file( + "${__PYTHON_QT_BINDING_SIP_HELPER_DIR}/pyproject.toml.in" + "${PYPROJECT_TOML}" + @ONLY + ) - if(WIN32) - set(MAKE_EXECUTABLE NMake.exe) - else() - find_program(MAKE_PROGRAM NAMES make) - message(STATUS "Found required make: ${MAKE_PROGRAM}") - set(MAKE_EXECUTABLE ${MAKE_PROGRAM}) - endif() + # Find all generated C/C++ files + set(GENERATED_CPP + "${SIP_BUILD_DIR}/lib${PROJECT_NAME}/siplib${PROJECT_NAME}part0.cpp" + ) + # Generate code for a cPython extension using sip-build add_custom_command( - OUTPUT ${sip_LIBRARY_DIR}/lib${PROJECT_NAME}${CMAKE_SHARED_LIBRARY_SUFFIX} - COMMAND ${MAKE_EXECUTABLE} - DEPENDS ${SIP_BUILD_DIR}/Makefile + OUTPUT ${GENERATED_CPP} + COMMAND ${Python3_EXECUTABLE} -m sipbuild.tools.build --no-compile --concatenate 1 + DEPENDS ${SIP_FILE} ${sip_DEPENDS} WORKING_DIRECTORY ${SIP_BUILD_DIR} - COMMENT "Compiling generated code for ${PROJECT_NAME} Python bindings..." + COMMENT "Generating C++ code for ${PROJECT_NAME} Python bindings using sip-build..." ) - add_custom_target(lib${PROJECT_NAME} ALL - DEPENDS ${sip_LIBRARY_DIR}/lib${PROJECT_NAME}${CMAKE_SHARED_LIBRARY_SUFFIX} - COMMENT "Meta target for ${PROJECT_NAME} Python bindings..." - ) - add_dependencies(lib${PROJECT_NAME} ${sip_DEPENDENCIES}) + # Build the cPython extension natively using CMake + python3_add_library(lib${PROJECT_NAME} MODULE ${GENERATED_CPP}) + + # Link project dependencies against this target + target_include_directories(lib${PROJECT_NAME} PRIVATE ${${PROJECT_NAME}_INCLUDE_DIRS} ${SIP_BUILD_DIR}) + target_link_libraries(lib${PROJECT_NAME} PRIVATE ${${PROJECT_NAME}_LIBRARIES} ${sip_DEPENDENCIES}) + target_link_directories(lib${PROJECT_NAME} PRIVATE ${${PROJECT_NAME}_LIBRARY_DIRS}) + + if(${PROJECT_NAME}_LDFLAGS_OTHER) + target_link_options(lib${PROJECT_NAME} PRIVATE ${${PROJECT_NAME}_LDFLAGS_OTHER}) + endif() endfunction() diff --git a/package.xml b/package.xml index df2b169..0547cdc 100644 --- a/package.xml +++ b/package.xml @@ -28,10 +28,8 @@ ament_cmake - qtbase5-dev - python3-qt5-bindings - - python3-qt5-bindings + qt6-base-dev + python3-qt-bindings ament_cmake_pytest ament_lint_auto diff --git a/python_qt_binding-extras.cmake b/python_qt_binding-extras.cmake new file mode 100644 index 0000000..8fbfc12 --- /dev/null +++ b/python_qt_binding-extras.cmake @@ -0,0 +1,9 @@ +# Avoid find_package(QT NAMES Qt6 Qt5 ...) due to CMake's default ascending path resolution +find_package(Qt6 QUIET COMPONENTS Widgets Core) +if(Qt6_FOUND) + set(QT_VERSION_MAJOR 6) +else() + find_package(Qt5 REQUIRED COMPONENTS Widgets Core) + set(QT_VERSION_MAJOR 5) +endif() +set(python_qt_binding_QT_MAJOR_VERSION "${QT_VERSION_MAJOR}" CACHE STRING "The major version of Qt to use (5 or 6)") diff --git a/src/python_qt_binding/binding_helper.py b/src/python_qt_binding/binding_helper.py index 27c3237..86913fe 100644 --- a/src/python_qt_binding/binding_helper.py +++ b/src/python_qt_binding/binding_helper.py @@ -41,6 +41,8 @@ import sys import traceback +from .version import QT_MAJOR_VERSION + QT_BINDING = None QT_BINDING_MODULES = {} @@ -155,9 +157,9 @@ def _load_pyqt(required_modules, optional_modules): # register required and optional PyQt modules for module_name in required_modules: - _named_import('PyQt5.%s' % module_name) + _named_import(f'PyQt{QT_MAJOR_VERSION}.{module_name}') for module_name in optional_modules: - _named_optional_import('PyQt5.%s' % module_name) + _named_optional_import(f'PyQt{QT_MAJOR_VERSION}.{module_name}') # set some names for compatibility with PySide sys.modules['QtCore'].Signal = sys.modules['QtCore'].pyqtSignal @@ -166,30 +168,38 @@ def _load_pyqt(required_modules, optional_modules): # try to register Qwt module try: - import PyQt5.Qwt5 - _register_binding_module('Qwt', PyQt5.Qwt5) + Qwt = builtins.__import__(f'PyQt{QT_MAJOR_VERSION}.Qwt{QT_MAJOR_VERSION}', fromlist=['*']) + _register_binding_module('Qwt', Qwt) except ImportError: pass global _loadUi def _loadUi(uifile, baseinstance=None, custom_widgets_=None): - from PyQt5 import uic + uic = builtins.__import__(f'PyQt{QT_MAJOR_VERSION}.uic', fromlist=['*']) return uic.loadUi(uifile, baseinstance=baseinstance) - import PyQt5.QtCore - return PyQt5.QtCore.PYQT_VERSION_STR + QtCore = builtins.__import__(f'PyQt{QT_MAJOR_VERSION}.QtCore', fromlist=['*']) + return QtCore.PYQT_VERSION_STR def _load_pyside(required_modules, optional_modules): # set environment variable QT_API for matplotlib os.environ['QT_API'] = 'pyside' + # Determine the PySide module based on the Qt version + if str(QT_MAJOR_VERSION) == '6': + pyside_module = 'PySide6' + elif str(QT_MAJOR_VERSION) == '5': + pyside_module = 'PySide2' + else: + raise RuntimeError('Only Qt5 and Qt6 are supported') + # register required and optional PySide modules for module_name in required_modules: - _named_import('PySide2.%s' % module_name) + _named_import(f'{pyside_module}.{module_name}') for module_name in optional_modules: - _named_optional_import('PySide2.%s' % module_name) + _named_optional_import(f'{pyside_module}.{module_name}') # set some names for compatibility with PyQt sys.modules['QtCore'].pyqtSignal = sys.modules['QtCore'].Signal @@ -198,7 +208,7 @@ def _load_pyside(required_modules, optional_modules): # try to register PySideQwt module try: - import PySideQwt + PySideQwt = builtins.__import__(f'{pyside_module}Qwt', fromlist=['*']) _register_binding_module('Qwt', PySideQwt) except ImportError: pass @@ -206,8 +216,10 @@ def _load_pyside(required_modules, optional_modules): global _loadUi def _loadUi(uifile, baseinstance=None, custom_widgets=None): - from PySide2.QtUiTools import QUiLoader - from PySide2.QtCore import QMetaObject + QtUiTools = builtins.__import__(f'{pyside_module}.QtUiTools', fromlist=['*']) + QtCore = builtins.__import__(f'{pyside_module}.QtCore', fromlist=['*']) + QUiLoader = QtUiTools.QUiLoader + QMetaObject = QtCore.QMetaObject class CustomUiLoader(QUiLoader): class_aliases = { @@ -241,25 +253,17 @@ def createWidget(self, class_name, parent=None, name=''): loader = CustomUiLoader(baseinstance, custom_widgets) - # instead of passing the custom widgets, they should be registered using - # QUiLoader.registerCustomWidget(), - # but this does not work in PySide 1.0.6: it simply segfaults... - # loader = CustomUiLoader(baseinstance) - # custom_widgets = custom_widgets or {} - # for custom_widget in custom_widgets.values(): - # loader.registerCustomWidget(custom_widget) - ui = loader.load(uifile) QMetaObject.connectSlotsByName(ui) return ui - import PySide2 - return PySide2.__version__ + pyside = builtins.__import__(pyside_module, fromlist=['*']) + return pyside.__version__ def loadUi(uifile, baseinstance=None, custom_widgets=None): """ - Load a provided UI file chosen Python Qt 5 binding. + Load a provided UI file chosen Python Qt binding. @type uifile: str @param uifile: Absolute path of .ui file From 848c051a6683a32d99eb3a3aa6af2759cdaaaaac Mon Sep 17 00:00:00 2001 From: Alejandro Hernandez Cordero Date: Mon, 13 Apr 2026 12:46:34 +0200 Subject: [PATCH 45/63] Changelog Signed-off-by: Alejandro Hernandez Cordero --- CHANGELOG.rst | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 0836aa9..2b5b8ab 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -2,6 +2,11 @@ Changelog for package python_qt_binding ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +2.5.0 (2026-04-13) +------------------ +* Use sip-build and python3_add_library for Qt5/Qt6 (`#157 `_) +* Contributors: Shane Loretz, Alejandro Hernández Cordero + 2.4.1 (2025-10-08) ------------------ * fix setuptools deprecation (`#151 `_) From b6d78eaa5a8c59be0f48f0478c766008ba3240e4 Mon Sep 17 00:00:00 2001 From: Alejandro Hernandez Cordero Date: Mon, 13 Apr 2026 12:46:44 +0200 Subject: [PATCH 46/63] 2.5.0 --- package.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.xml b/package.xml index 0547cdc..2a9554c 100644 --- a/package.xml +++ b/package.xml @@ -1,6 +1,6 @@ python_qt_binding - 2.4.1 + 2.5.0 This stack provides Python bindings for Qt. There are two providers: pyside and pyqt. PySide2 is available under From 84fcb85dae6bca67e8fb89a8c3b274c6a904f92d Mon Sep 17 00:00:00 2001 From: Shane Loretz Date: Tue, 21 Apr 2026 13:17:31 -0700 Subject: [PATCH 47/63] Depend on python3-dev (#158) Signed-off-by: Shane Loretz --- package.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/package.xml b/package.xml index 2a9554c..06650e9 100644 --- a/package.xml +++ b/package.xml @@ -30,6 +30,7 @@ qt6-base-dev python3-qt-bindings + python3-dev ament_cmake_pytest ament_lint_auto From 12446b153dcd375db077884a92294266313021e6 Mon Sep 17 00:00:00 2001 From: Shane Loretz Date: Tue, 21 Apr 2026 20:41:47 +0000 Subject: [PATCH 48/63] Changelogs Signed-off-by: Shane Loretz --- CHANGELOG.rst | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 2b5b8ab..a8775eb 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -2,6 +2,11 @@ Changelog for package python_qt_binding ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Forthcoming +----------- +* Depend on python3-dev (`#158 `_) +* Contributors: Shane Loretz + 2.5.0 (2026-04-13) ------------------ * Use sip-build and python3_add_library for Qt5/Qt6 (`#157 `_) From 69f1c5432c5d077f21d0c3775314b8c7525a9b27 Mon Sep 17 00:00:00 2001 From: Shane Loretz Date: Tue, 21 Apr 2026 20:42:01 +0000 Subject: [PATCH 49/63] 2.5.1 --- CHANGELOG.rst | 4 ++-- package.xml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index a8775eb..bf7e7ea 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -2,8 +2,8 @@ Changelog for package python_qt_binding ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -Forthcoming ------------ +2.5.1 (2026-04-21) +------------------ * Depend on python3-dev (`#158 `_) * Contributors: Shane Loretz diff --git a/package.xml b/package.xml index 06650e9..bf453ba 100644 --- a/package.xml +++ b/package.xml @@ -1,6 +1,6 @@ python_qt_binding - 2.5.0 + 2.5.1 This stack provides Python bindings for Qt. There are two providers: pyside and pyqt. PySide2 is available under From daa9c2f808290fdba0afc6b0c96e842a53ce61e1 Mon Sep 17 00:00:00 2001 From: Shane Loretz Date: Tue, 21 Apr 2026 16:20:23 -0700 Subject: [PATCH 50/63] Remove qt6-base-dev from package.xml (#159) Signed-off-by: Shane Loretz --- package.xml | 1 - 1 file changed, 1 deletion(-) diff --git a/package.xml b/package.xml index bf453ba..f2b3b9b 100644 --- a/package.xml +++ b/package.xml @@ -28,7 +28,6 @@ ament_cmake - qt6-base-dev python3-qt-bindings python3-dev From 59c4bc9edb78688517332f5f98f95a2dd219a544 Mon Sep 17 00:00:00 2001 From: Shane Loretz Date: Tue, 21 Apr 2026 23:21:05 +0000 Subject: [PATCH 51/63] Changelogs Signed-off-by: Shane Loretz --- CHANGELOG.rst | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index bf7e7ea..d315a83 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -2,6 +2,11 @@ Changelog for package python_qt_binding ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Forthcoming +----------- +* Remove qt6-base-dev from package.xml (`#159 `_) +* Contributors: Shane Loretz + 2.5.1 (2026-04-21) ------------------ * Depend on python3-dev (`#158 `_) From e65986946a899e6040be0029276fade5979cf98e Mon Sep 17 00:00:00 2001 From: Shane Loretz Date: Tue, 21 Apr 2026 23:21:20 +0000 Subject: [PATCH 52/63] 2.5.2 --- CHANGELOG.rst | 4 ++-- package.xml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index d315a83..7f7b755 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -2,8 +2,8 @@ Changelog for package python_qt_binding ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -Forthcoming ------------ +2.5.2 (2026-04-21) +------------------ * Remove qt6-base-dev from package.xml (`#159 `_) * Contributors: Shane Loretz diff --git a/package.xml b/package.xml index f2b3b9b..8d97e9a 100644 --- a/package.xml +++ b/package.xml @@ -1,6 +1,6 @@ python_qt_binding - 2.5.1 + 2.5.2 This stack provides Python bindings for Qt. There are two providers: pyside and pyqt. PySide2 is available under From 345093f2d71efa9cf11a09cfdc4336c5ee230db2 Mon Sep 17 00:00:00 2001 From: Shane Loretz Date: Mon, 27 Apr 2026 12:26:56 -0700 Subject: [PATCH 53/63] Re-add exec depend on python3 qt bindings rosdep key (#160) * Re-add exec depend on python3 qt bindings rosdep key Signed-off-by: Shane Loretz * Also make it a build_export_depend Signed-off-by: Shane Loretz --------- Signed-off-by: Shane Loretz --- package.xml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/package.xml b/package.xml index 8d97e9a..f00305e 100644 --- a/package.xml +++ b/package.xml @@ -29,8 +29,11 @@ ament_cmake python3-qt-bindings + python3-qt-bindings python3-dev + python3-qt-bindings + ament_cmake_pytest ament_lint_auto ament_lint_common From 41ed4d91179cdfe15050a801404a9fb7906a13e1 Mon Sep 17 00:00:00 2001 From: Shane Loretz Date: Mon, 27 Apr 2026 19:27:40 +0000 Subject: [PATCH 54/63] changelogs Signed-off-by: Shane Loretz --- CHANGELOG.rst | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 7f7b755..f643318 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -2,6 +2,11 @@ Changelog for package python_qt_binding ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Forthcoming +----------- +* Re-add exec depend on python3 qt bindings rosdep key (`#160 `_) +* Contributors: Shane Loretz + 2.5.2 (2026-04-21) ------------------ * Remove qt6-base-dev from package.xml (`#159 `_) From 73bb7513f6a45556094a14bc1e1319da3a325f39 Mon Sep 17 00:00:00 2001 From: Shane Loretz Date: Mon, 27 Apr 2026 19:27:48 +0000 Subject: [PATCH 55/63] 2.5.3 --- CHANGELOG.rst | 4 ++-- package.xml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index f643318..c6c3049 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -2,8 +2,8 @@ Changelog for package python_qt_binding ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -Forthcoming ------------ +2.5.3 (2026-04-27) +------------------ * Re-add exec depend on python3 qt bindings rosdep key (`#160 `_) * Contributors: Shane Loretz diff --git a/package.xml b/package.xml index f00305e..c83e724 100644 --- a/package.xml +++ b/package.xml @@ -1,6 +1,6 @@ python_qt_binding - 2.5.2 + 2.5.3 This stack provides Python bindings for Qt. There are two providers: pyside and pyqt. PySide2 is available under From 6d91bc93b7c8013241a6342ab996c63b24ad0506 Mon Sep 17 00:00:00 2001 From: Shane Loretz Date: Mon, 27 Apr 2026 20:24:34 -0700 Subject: [PATCH 56/63] Pick Qt version at build time, not install time (#161) Signed-off-by: Shane Loretz --- CMakeLists.txt | 12 ++++++++++-- python_qt_binding-extras.cmake | 9 --------- python_qt_binding-extras.cmake.in | 1 + 3 files changed, 11 insertions(+), 11 deletions(-) delete mode 100644 python_qt_binding-extras.cmake create mode 100644 python_qt_binding-extras.cmake.in diff --git a/CMakeLists.txt b/CMakeLists.txt index 61850b1..8686914 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -7,7 +7,15 @@ find_package(ament_cmake_python REQUIRED) # Copy python package into binary directory file(COPY src/${PROJECT_NAME} DESTINATION ${CMAKE_CURRENT_BINARY_DIR}) -include(python_qt_binding-extras.cmake) +# Avoid find_package(QT NAMES Qt6 Qt5 ...) due to CMake's default ascending path resolution +find_package(Qt6 QUIET COMPONENTS Widgets Core) +if(Qt6_FOUND) + set(QT_VERSION_MAJOR 6) +else() + find_package(Qt5 REQUIRED COMPONENTS Widgets Core) + set(QT_VERSION_MAJOR 5) +endif() +set(python_qt_binding_QT_MAJOR_VERSION "${QT_VERSION_MAJOR}" CACHE STRING "The major version of Qt to use (5 or 6)") # Generate a version.py file inside the copied package directory file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}/version.py @@ -39,5 +47,5 @@ if(BUILD_TESTING) endif() ament_package( - CONFIG_EXTRAS "python_qt_binding-extras.cmake" + CONFIG_EXTRAS "python_qt_binding-extras.cmake.in" ) diff --git a/python_qt_binding-extras.cmake b/python_qt_binding-extras.cmake deleted file mode 100644 index 8fbfc12..0000000 --- a/python_qt_binding-extras.cmake +++ /dev/null @@ -1,9 +0,0 @@ -# Avoid find_package(QT NAMES Qt6 Qt5 ...) due to CMake's default ascending path resolution -find_package(Qt6 QUIET COMPONENTS Widgets Core) -if(Qt6_FOUND) - set(QT_VERSION_MAJOR 6) -else() - find_package(Qt5 REQUIRED COMPONENTS Widgets Core) - set(QT_VERSION_MAJOR 5) -endif() -set(python_qt_binding_QT_MAJOR_VERSION "${QT_VERSION_MAJOR}" CACHE STRING "The major version of Qt to use (5 or 6)") diff --git a/python_qt_binding-extras.cmake.in b/python_qt_binding-extras.cmake.in new file mode 100644 index 0000000..ea85bbc --- /dev/null +++ b/python_qt_binding-extras.cmake.in @@ -0,0 +1 @@ +set(python_qt_binding_QT_MAJOR_VERSION "@python_qt_binding_QT_MAJOR_VERSION@" CACHE STRING "The major version of Qt to use (5 or 6)") \ No newline at end of file From 3ee94ea058be3d7b3134cc958b92d3ecf4f2f6b2 Mon Sep 17 00:00:00 2001 From: Shane Loretz Date: Tue, 28 Apr 2026 03:25:57 +0000 Subject: [PATCH 57/63] changelogs Signed-off-by: Shane Loretz --- CHANGELOG.rst | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index c6c3049..e9f95d8 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -2,6 +2,11 @@ Changelog for package python_qt_binding ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Forthcoming +----------- +* Pick Qt version at build time, not install time (`#161 `_) +* Contributors: Shane Loretz + 2.5.3 (2026-04-27) ------------------ * Re-add exec depend on python3 qt bindings rosdep key (`#160 `_) From dd11c666400f9191893667d43253c72ff7eed76f Mon Sep 17 00:00:00 2001 From: Shane Loretz Date: Tue, 28 Apr 2026 03:26:11 +0000 Subject: [PATCH 58/63] 2.5.4 --- CHANGELOG.rst | 4 ++-- package.xml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index e9f95d8..c27606c 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -2,8 +2,8 @@ Changelog for package python_qt_binding ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -Forthcoming ------------ +2.5.4 (2026-04-28) +------------------ * Pick Qt version at build time, not install time (`#161 `_) * Contributors: Shane Loretz diff --git a/package.xml b/package.xml index c83e724..ab44d28 100644 --- a/package.xml +++ b/package.xml @@ -1,6 +1,6 @@ python_qt_binding - 2.5.3 + 2.5.4 This stack provides Python bindings for Qt. There are two providers: pyside and pyqt. PySide2 is available under From 69009b3c2edc8c6c4ca1c6210592b39af47faa65 Mon Sep 17 00:00:00 2001 From: Chris Lalancette Date: Wed, 6 May 2026 18:59:36 +0000 Subject: [PATCH 59/63] Changelog. Signed-off-by: Chris Lalancette --- CHANGELOG.rst | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index c27606c..dcfb331 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -2,6 +2,9 @@ Changelog for package python_qt_binding ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Forthcoming +----------- + 2.5.4 (2026-04-28) ------------------ * Pick Qt version at build time, not install time (`#161 `_) From 6d021dfdb5fd21283424982ee1298892f43d604a Mon Sep 17 00:00:00 2001 From: Chris Lalancette Date: Wed, 6 May 2026 18:59:43 +0000 Subject: [PATCH 60/63] 2.6.0 --- CHANGELOG.rst | 4 ++-- package.xml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index dcfb331..e5f7f81 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -2,8 +2,8 @@ Changelog for package python_qt_binding ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -Forthcoming ------------ +2.6.0 (2026-05-06) +------------------ 2.5.4 (2026-04-28) ------------------ diff --git a/package.xml b/package.xml index ab44d28..fc1b37f 100644 --- a/package.xml +++ b/package.xml @@ -1,6 +1,6 @@ python_qt_binding - 2.5.4 + 2.6.0 This stack provides Python bindings for Qt. There are two providers: pyside and pyqt. PySide2 is available under From ac2a54072f6e398eca207910d59d4e08a37d3c6d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alejandro=20Hern=C3=A1ndez=20Cordero?= Date: Tue, 16 Jun 2026 09:26:19 +0200 Subject: [PATCH 61/63] Removed Python2 references (#163) Signed-off-by: Alejandro Hernandez Cordero --- src/python_qt_binding/binding_helper.py | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/src/python_qt_binding/binding_helper.py b/src/python_qt_binding/binding_helper.py index 86913fe..cb6b835 100644 --- a/src/python_qt_binding/binding_helper.py +++ b/src/python_qt_binding/binding_helper.py @@ -30,12 +30,7 @@ # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE # POSSIBILITY OF SUCH DAMAGE. -try: - import __builtin__ as builtins -except ImportError: - # since the 'future' package provides a 'builtins' module in Python 2 - # this must not be checked second - import builtins +import builtins import os import platform import sys From ef0b284a31eff4a2dc8cba71b492ef32650a0c7d Mon Sep 17 00:00:00 2001 From: Alejandro Hernandez Cordero Date: Tue, 14 Jul 2026 13:04:33 +0200 Subject: [PATCH 62/63] Changelog Signed-off-by: Alejandro Hernandez Cordero --- CHANGELOG.rst | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index e5f7f81..2bfa4e2 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -2,6 +2,11 @@ Changelog for package python_qt_binding ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +2.6.1 (2026-07-14) +------------------ +* Removed Python2 references (`#163 `_) +* Contributors: Alejandro Hernández Cordero + 2.6.0 (2026-05-06) ------------------ From d64c737b7ffc8cbe3eeb9ccd9ec758ddadf2401d Mon Sep 17 00:00:00 2001 From: Alejandro Hernandez Cordero Date: Tue, 14 Jul 2026 13:04:36 +0200 Subject: [PATCH 63/63] 2.6.1 --- package.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.xml b/package.xml index fc1b37f..1eb4466 100644 --- a/package.xml +++ b/package.xml @@ -1,6 +1,6 @@ python_qt_binding - 2.6.0 + 2.6.1 This stack provides Python bindings for Qt. There are two providers: pyside and pyqt. PySide2 is available under