diff --git a/.github/workflows/cmake.yml b/.github/workflows/cmake.yml new file mode 100644 index 000000000..4eaf80f47 --- /dev/null +++ b/.github/workflows/cmake.yml @@ -0,0 +1,71 @@ +name: CMake CI + +on: + push: + branches: + - master + +jobs: + build-and-test: + runs-on: ${{ matrix.os }} + strategy: + matrix: + os: [ubuntu-latest, windows-latest] + qt_version: [5, 6] + python_version: ["3.8", "3.9", "3.10"] + fail-fast: false + + steps: + - name: Checkout code + uses: actions/checkout@v3 + + - name: Set up Python + uses: actions/setup-python@v4 + with: + python-version: ${{ matrix.python_version }} + + - name: Install dependencies (Linux) + if: runner.os == 'Linux' + run: | + sudo apt-get update + if [ "${{ matrix.qt_version }}" = "5" ]; then + sudo apt-get install -y qtbase5-dev qtbase5-private-dev qtchooser qt5-qmake qtbase5-dev-tools \ + libqt5svg5-dev qttools5-dev libqt5xmlpatterns5-dev qtmultimedia5-dev qtdeclarative5-dev \ + qtwebengine5-dev libqt5webkit5-dev + echo "QTDIR=/usr/lib/x86_64-linux-gnu/qt5" | tee -a $GITHUB_ENV + else + sudo apt-get install -y qt6-base-dev qt6-base-private-dev qt6-5compat-dev qt6-base-dev-tools \ + libqt6svg6-dev qt6-multimedia-dev qt6-declarative-dev qt6-webengine-dev + echo "QTDIR=/usr/lib/x86_64-linux-gnu/qt6" | tee -a $GITHUB_ENV + fi + + - name: Install dependencies (Windows) + if: runner.os == 'Windows' + run: | + if ("${{ matrix.qt_version }}" -eq "5") { + pip install aqtinstall + aqt install-qt windows desktop 5.15.2 win64_msvc2019 -m all + $Qt5Dir = "$env:USERPROFILE\Qt\5.15.2\msvc2019_64" + echo "Qt5Dir=$Qt5Dir" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append + echo "$Qt5Dir\bin" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append + echo "QTDIR=$Qt5Dir" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append + } else { + choco install -y qt6-base-dev qt6-base-private-dev qt6-5compat-dev qt6-base-dev-tools ` + libqt6svg6-dev qt6-multimedia-dev qt6-declarative-dev qt6-webengine-dev ` + --params "/InstallationFolder C:/Qt/${{ matrix.qt_version }}" + echo "C:/Qt/${{ matrix.qt_version }}/bin" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append + echo "QTDIR=C:/Qt/${{ matrix.qt_version }}" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append + } + + - name: Configure CMake + run: | + cmake -S . -B build -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=./install + + - name: Build project + run: | + cmake --build build --parallel --target all install + + - name: Run tests + run: | + cd build + ctest --output-on-failure diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 000000000..fc7a6d086 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,87 @@ +cmake_minimum_required(VERSION 3.27) + +project(PythonQt LANGUAGES CXX VERSION 3.5.6) + +#----------------------------------------------------------------------------- +# Set a default build type if none was specified +if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) + message(STATUS "Setting build type to 'Release' as none was specified.") + set(CMAKE_BUILD_TYPE Release CACHE STRING "Choose the type of build." FORCE) + mark_as_advanced(CMAKE_BUILD_TYPE) + # Set the possible values of build type for cmake-gui + set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS "Debug" "Release" "RelWithDebInfo") +endif() +#----------------------------------------------------------------------------- + +enable_testing() + +set(CMAKE_CXX_STANDARD 11) +set(CMAKE_CXX_STANDARD_REQUIRED ON) + +# Force errors for dangerous operations +add_compile_definitions( -DQT_NO_CAST_TO_ASCII ) + +option(PythonQt_NO_IMPLICIT_CASTING "Disable implicit casts related to dangerous implicit conversions" OFF) +if(PythonQt_NO_IMPLICIT_CASTING) # Definitions to force + # errors on dangerous implicit operations + # to be addressed at a later time +add_compile_definitions( -DQT_NO_CAST_FROM_ASCII + -DQT_NO_CAST_FROM_ASCII + -DQT_NO_CAST_TO_BYTEARRAY + -DQT_NO_CAST_FROM_BYTEARRAY + -DQT_NO_CAST_TO_QSTRING + -DQT_NO_CAST_FROM_QSTRING + -DQT_NO_CAST_TO_QSTRINGREF + -DQT_NO_CAST_FROM_QSTRINGREF + -DQT_NO_CAST_TO_QVARIANT + -DQT_NO_CAST_FROM_QVARIANT ) +endif() + +option(FORCE_BUILD_QT5 "Force Qt5 build instead of Qt6" OFF) + +if(FORCE_BUILD_QT5) + find_package(Qt5 NAMES Qt5 REQUIRED COMPONENTS Core Widgets Xml) + string(REPLACE "." ";" qt_version_list ${Qt5_VERSION}) +else() + find_package(Qt6 NAMES Qt6 REQUIRED COMPONENTS Core Widgets Xml Core5Compat) + string(REPLACE "." ";" qt_version_list ${Qt6_VERSION}) +endif() +list(GET qt_version_list 0 QT_VERSION_MAJOR) +list(GET qt_version_list 1 QT_VERSION_MINOR) +list(GET qt_version_list 1 QT_VERSION_PATCH) +message(STATUS "QT_VERSION_MAJOR = ${QT_VERSION_MAJOR}") + +find_package(Python3 COMPONENTS Development REQUIRED) + +# Set the environment as defined in Readme.md +# Set environment variables for Python +if(Python3_FOUND) + set(PYTHON_VERSION "${Python3_VERSION_MAJOR}.${Python3_VERSION_MINOR}") + set(PYTHON_PATH "${Python3_PREFIX}") + set(PYTHON_LIB "${Python3_PREFIX}/libs") + set(PYTHON_DIR "${Python3_PREFIX}") + set(ENV{PYTHON_VERSION} "${PYTHON_VERSION}") + set(ENV{PYTHON_PATH} "${PYTHON_PATH}") + set(ENV{PYTHON_LIB} "${PYTHON_LIB}") + set(ENV{PYTHON_DIR} "${PYTHON_DIR}") +endif() + +# Set QTDIR environment variable to Qt installation root +if(FORCE_BUILD_QT5) + if(DEFINED Qt5_DIR) + set(ENV{QTDIR} "${Qt5_DIR}") + endif() +else() + if(DEFINED Qt6_DIR) + set(ENV{QTDIR} "${Qt6_DIR}") + endif() +endif() + + +set(PYTHONQT_SUFFIX Qt${QT_VERSION_MAJOR}.${QT_VERSION_MINOR}-Python${Python3_VERSION_MAJOR}.${Python3_VERSION_MINOR}) +include_directories(src) +add_subdirectory(generator) +add_subdirectory(src) +add_subdirectory(extensions) +add_subdirectory(tests) +# add_subdirectory(examples) diff --git a/README.md b/README.md index 92aaaa100..c50639d9e 100644 --- a/README.md +++ b/README.md @@ -36,20 +36,22 @@ need to build and run the generator when you want to build additional wrappers or you want to upgrade/downgrade to another Qt version, but this requires updating the typesystems as well. -# Building +# Building -## General +## Using qmake and manual steps + +### General Building PythonQt requires a couple of steps. Follow these instructions in order to get a correctly built PythonQt runtime and Qt bindings. -### Recommendations +#### Recommendations It is recommended to build the Qt bindings yourself instead of using the pregenerated ones. This ensures the bindings are compatible with your Qt version. Do not build `PythonQt.pro` directly because it will only use the pregenerated bindings! -### Environment +#### Environment First, you need to set a couple of environment variables, which depend on your Python and Qt installation. @@ -74,7 +76,7 @@ First, you need to set a couple of environment variables, which depend on your P The absolute path to the root directory of your Qt installation. -### Binding Generator +#### Binding Generator 1. cd into the `generator` directory 2. Run qmake on `generator.pro` @@ -93,7 +95,7 @@ First, you need to set a couple of environment variables, which depend on your P ` qtscript_masterinclude.h build_all.txt` -### PythonQt Runtime +#### PythonQt Runtime Next, we need the PythonQt runtime. @@ -106,7 +108,7 @@ Next, we need the PythonQt runtime. Use `nmake` for MSVC (Visual Studio; make sure to have the environment variables set for Visual Studio beforehand). Otherwise, use `make`. -### Extensions +#### Extensions As a last step, we need to build the extensions. @@ -121,6 +123,60 @@ As a last step, we need to build the extensions. After all these steps, you should now have a fully working PythonQt runtime and Qt bindings for your Python/Qt installation 🎉. + +## The CMake Build System replaces the qmake manual proceedure defined above + +Get the source code from the GitHub. +```bash +git clone git@github.com:MeVisLab/PythonQt.git +cd PythonQt +git checkout +``` + +Build the PythonQt runtime and Qt bindings using CMake. +```bash +cmake -S $(pwd) -B ../PythonQt-build -GNinja -DCMAKE_EXPORT_COMPILE_COMMANDS:BOOL=ON -DCMAKE_BUILD_TYPE:STRING=Release +cmake --build ../PythonQt-build --config Release +``` + + +# Platform Notes ## MinGW It is possible to build PythonQt with MinGW on Windows instead of using MSVC. + +## Ubuntu 24.04 apt-get install QT6 +It is possible to build PythonQt on Ubuntu 24.04 using the `apt` package manager to install the required Qt6 packages. +``` bash +apt install qt6-base-dev qt6-tools-dev-tools libqt6* qt6-* qml6-module-qt* +``` + +## arm64 based MacOS +It is possible to build PythonQt on arm64 based MacOS systems. + +Download and install qt6 from https://www.qt.io/download. Install the desired Qt6. + +# Hints for developers + +## Upgrading Qt Versions + +### Use `clazy` for static analysis of Qt code +```bash +# NOTE: clazy uses the cmake output file generated when CMAKE_EXPORT_COMPILE_COMMANDS=ON +export CLAZY_TEST="use-static-qregularexpression" + +clazy-standalone -p ../PythonQt-build \ + --checks="${CLAZY_TEST}" \ + --only-qt \ + $(find . -name "*.cpp" |fgrep -v "/examples/") \ + 2>&1 \ + | fgrep -v "pragma-messages" \ + | tee ../logger.${CLAZY_TEST} +vim -q ../logger.${CLAZY_TEST} +``` + + +# List clazy tests available +```bash +clazy-standalone -p ../PythonQt-build --only-qt generator/main.cpp --list-checks >> ../MIGRATE_QT5_to_QT6 +``` \ No newline at end of file diff --git a/examples/PyLauncher/main.cpp b/examples/PyLauncher/main.cpp index c4db944f4..4e6496d73 100644 --- a/examples/PyLauncher/main.cpp +++ b/examples/PyLauncher/main.cpp @@ -78,7 +78,7 @@ int main( int argc, char **argv ) } PythonQtScriptingConsole console(NULL, mainContext); - Q_FOREACH(QString file, files) { + for( QString file : files ) { mainContext.evalFile(file); } if (showConsole || console.hadError()) { diff --git a/extensions/CMakeLists.txt b/extensions/CMakeLists.txt new file mode 100644 index 000000000..03577a7a2 --- /dev/null +++ b/extensions/CMakeLists.txt @@ -0,0 +1 @@ +add_subdirectory(PythonQt_QtAll) \ No newline at end of file diff --git a/extensions/PythonQt_QtAll/CMakeLists.txt b/extensions/PythonQt_QtAll/CMakeLists.txt new file mode 100644 index 000000000..a6a8504e3 --- /dev/null +++ b/extensions/PythonQt_QtAll/CMakeLists.txt @@ -0,0 +1,94 @@ +project(QtAll LANGUAGES CXX) + +set(CMAKE_AUTOMOC ON) + +file(GLOB SOURCES *.h *.cpp) + +if(BUILD_SHARED_LIBS) + add_library(${PROJECT_NAME} SHARED) + target_compile_definitions(${PROJECT_NAME} PRIVATE PYTHONQT_QTALL_EXPORTS) +else() + add_library(${PROJECT_NAME} STATIC) + target_compile_definitions(${PROJECT_NAME} PUBLIC PYTHONQT_QTALL_STATIC) +endif() + +target_sources(${PROJECT_NAME} PRIVATE ${SOURCES}) + +target_link_libraries(${PROJECT_NAME} PUBLIC Core) + +target_include_directories(${PROJECT_NAME} PUBLIC ${CMAKE_CURRENT_LIST_DIR}) + +list(APPEND QTMODULES Core Gui Svg Sql Network OpenGL Xml Multimedia Qml Quick UiTools WebEngineWidgets) +if(${QT_VERSION_MAJOR} EQUAL 5) #QT5 + list(APPEND QTMODULES XmlPatterns WebKit) +endif() +find_package(Qt${QT_VERSION_MAJOR} COMPONENTS ${QTMODULES}) + +foreach(QtModule IN LISTS QTMODULES) + if(NOT TARGET "Qt${QT_VERSION_MAJOR}::${QtModule}") + continue() + endif() + + string(TOUPPER ${QtModule} QTMODULE) + target_sources(${PROJECT_NAME} PRIVATE ${PYTHONQT_WRAPPER_${QTMODULE}_SOURCES}) + target_link_libraries(${PROJECT_NAME} PUBLIC Qt${QT_VERSION_MAJOR}::${QtModule}) + target_compile_definitions(${PROJECT_NAME} PRIVATE PYTHONQT_WITH_${QTMODULE}) +endforeach() + +if(TARGET "Qt${QT_VERSION_MAJOR}::Gui") + find_package(Qt${QT_VERSION_MAJOR} COMPONENTS Widgets PrintSupport REQUIRED) + target_link_libraries(${PROJECT_NAME} PUBLIC + Qt${QT_VERSION_MAJOR}::Widgets + Qt${QT_VERSION_MAJOR}::PrintSupport + ) +endif() + +if(TARGET "Qt${QT_VERSION_MAJOR}::Svg" AND QT_VERSION_MAJOR VERSION_GREATER_EQUAL 6) + find_package(Qt${QT_VERSION_MAJOR} COMPONENTS SvgWidgets REQUIRED) + target_link_libraries(${PROJECT_NAME} PUBLIC + Qt${QT_VERSION_MAJOR}::SvgWidgets + ) +endif() + +if(TARGET "Qt${QT_VERSION_MAJOR}::Multimedia") + find_package(Qt${QT_VERSION_MAJOR} COMPONENTS MultimediaWidgets REQUIRED) + target_link_libraries(${PROJECT_NAME} PUBLIC + Qt${QT_VERSION_MAJOR}::MultimediaWidgets + ) +endif() + +if(TARGET "Qt${QT_VERSION_MAJOR}::Quick") + find_package(Qt${QT_VERSION_MAJOR} COMPONENTS QuickWidgets REQUIRED) + target_link_libraries(${PROJECT_NAME} PUBLIC + Qt${QT_VERSION_MAJOR}::QuickWidgets + ) +endif() + +if(TARGET "Qt${QT_VERSION_MAJOR}::WebKit") + find_package(Qt${QT_VERSION_MAJOR} COMPONENTS WebKitWidgets REQUIRED) + target_link_libraries(${PROJECT_NAME} PUBLIC + Qt${QT_VERSION_MAJOR}::WebKitWidgets + ) +endif() + +file(GLOB PUBLIC_HEADER *.h) + +set_target_properties(${PROJECT_NAME} PROPERTIES + OUTPUT_NAME PythonQt-QtAll-${PYTHONQT_SUFFIX} + PUBLIC_HEADER "${PUBLIC_HEADER}" +) + +if(MSVC) + target_compile_options(${PROJECT_NAME} PRIVATE "/bigobj") +elseif(MINGW) + target_compile_options(${PROJECT_NAME} PRIVATE "-Wa,-mbig-obj") +endif() + +include(GNUInstallDirs) +install(TARGETS ${PROJECT_NAME} + BUNDLE DESTINATION . + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} + PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} +) diff --git a/extensions/PythonQt_QtAll/PythonQt_QtAll.h b/extensions/PythonQt_QtAll/PythonQt_QtAll.h index 689e2e83c..f4a5ff769 100644 --- a/extensions/PythonQt_QtAll/PythonQt_QtAll.h +++ b/extensions/PythonQt_QtAll/PythonQt_QtAll.h @@ -33,14 +33,16 @@ * */ -#ifdef WIN32 -#ifdef PYTHONQT_QTALL_EXPORTS -#define PYTHONQT_QTALL_EXPORT __declspec(dllexport) -#else -#define PYTHONQT_QTALL_EXPORT __declspec(dllimport) -#endif +#include + +#ifndef PYTHONQT_QTALL_STATIC +# if defined(PYTHONQT_QTALL_EXPORTS) +# define PYTHONQT_QTALL_EXPORT Q_DECL_EXPORT +# else +# define PYTHONQT_QTALL_EXPORT Q_DECL_IMPORT +# endif #else -#define PYTHONQT_QTALL_EXPORT +# define PYTHONQT_QTALL_EXPORT #endif namespace PythonQt_QtAll diff --git a/generator/CMakeLists.txt b/generator/CMakeLists.txt index 1d659dd87..b5f5b74b0 100644 --- a/generator/CMakeLists.txt +++ b/generator/CMakeLists.txt @@ -1,162 +1,158 @@ -cmake_minimum_required(VERSION 2.8) +project(PythonQtGenerator LANGUAGES CXX) -#----------------------------------------------------------------------------- -project(PythonQtGenerator) -#----------------------------------------------------------------------------- +add_subdirectory(parser) -include(CTestUseLaunchers OPTIONAL) +set(CMAKE_AUTOMOC ON) +set(CMAKE_AUTORCC ON) -#----------------------------------------------------------------------------- -# Setup Qt +file(GLOB SOURCES *.h *.cpp *.qrc simplecpp/*.h simplecpp/*.cpp ) +# Explicitly exclude qtscript_masterinclude.h +list(REMOVE_ITEM SOURCES "${CMAKE_CURRENT_LIST_DIR}/qtscript_masterinclude.h") -set(minimum_required_qt_version "4.6.2") +add_executable(${PROJECT_NAME}) +target_sources(${PROJECT_NAME} PRIVATE + ${SOURCES} +) + +set(QT5_COMPATIBILITY_LIBS "") +if (${QT_VERSION_MAJOR} VERSION_GREATER_EQUAL 6) + set(QT5_COMPATIBILITY_LIBS Qt${QT_VERSION_MAJOR}::Core5Compat) +endif() -find_package(Qt4) +target_link_libraries(${PROJECT_NAME} PUBLIC + Qt${QT_VERSION_MAJOR}::Core + Qt${QT_VERSION_MAJOR}::Widgets + Qt${QT_VERSION_MAJOR}::Xml + ${QT5_COMPATIBILITY_LIBS} + rxx +) -if(QT4_FOUND) +target_include_directories(${PROJECT_NAME} PRIVATE ${CMAKE_CURRENT_LIST_DIR}) +target_include_directories(${PROJECT_NAME} PRIVATE ${CMAKE_CURRENT_LIST_DIR}/simplecpp) - set(found_qt_version ${QT_VERSION_MAJOR}.${QT_VERSION_MINOR}.${QT_VERSION_PATCH}) +get_filename_component(PYTHONQT_GENERATED_PATH "${CMAKE_CURRENT_BINARY_DIR}" PATH) +# NOTE: 'generated_cpp' is hardcoded in setupgenerator.cpp, so do not add version suffix here. +set(PYTHONQT_GENERATED_PATH "${PYTHONQT_GENERATED_PATH}/generated_cpp") +#set(PYTHONQT_GENERATED_PATH "${PYTHONQT_GENERATED_PATH}/generated_cpp_${QT_VERSION_MAJOR}${QT_VERSION_MINOR}") - if(${found_qt_version} VERSION_LESS ${minimum_required_qt_version}) - message(FATAL_ERROR "error: PythonQt requires Qt >= ${minimum_required_qt_version} -- you cannot use Qt ${found_qt_version}.") - endif() - - set(QT_USE_QTXML ON) - - include(${QT_USE_FILE}) +if(WIN32) + set(LIBRARY_SEARCH_PATH PATH) else() - message(FATAL_ERROR "error: Qt4 was not found on your system. You probably need to set the QT_QMAKE_EXECUTABLE variable") + set(LIBRARY_SEARCH_PATH LD_LIBRARY_PATH) endif() -#----------------------------------------------------------------------------- -# Sources - -set(sources - parser/ast.cpp - parser/binder.cpp - parser/class_compiler.cpp - parser/codemodel.cpp - parser/codemodel_finder.cpp - parser/compiler_utils.cpp - parser/control.cpp - parser/declarator_compiler.cpp - parser/default_visitor.cpp - parser/dumptree.cpp - parser/lexer.cpp - parser/list.cpp - parser/name_compiler.cpp - parser/parser.cpp - parser/smallobject.cpp - parser/tokens.cpp - parser/type_compiler.cpp - parser/visitor.cpp - - abstractmetabuilder.cpp - abstractmetalang.cpp - asttoxml.cpp - customtypes.cpp - fileout.cpp - generator.cpp - generatorset.cpp - generatorsetqtscript.cpp - main.cpp - metajava.cpp - metaqtscriptbuilder.cpp - metaqtscript.cpp - prigenerator.cpp - reporthandler.cpp - setupgenerator.cpp - shellgenerator.cpp - shellheadergenerator.cpp - shellimplgenerator.cpp - typeparser.cpp - typesystem.cpp - ) - -#----------------------------------------------------------------------------- -# List headers. This list is used for the install command. - -set(headers - ) - -#----------------------------------------------------------------------------- -# Headers that should run through moc - -set(moc_sources - fileout.h - generator.h - generatorset.h - generatorsetqtscript.h - prigenerator.h - setupgenerator.h - shellgenerator.h - shellheadergenerator.h - shellimplgenerator.h - ) - -#----------------------------------------------------------------------------- -# UI files - -set(ui_sources ) - -#----------------------------------------------------------------------------- -# Resources - -set(qrc_sources - generator.qrc - ) - -#----------------------------------------------------------------------------- -# Do wrapping -qt4_wrap_cpp(gen_moc_sources ${moc_sources}) -qt4_wrap_ui(gen_ui_sources ${ui_sources}) -qt4_add_resources(gen_qrc_sources ${qrc_sources}) - -#----------------------------------------------------------------------------- -# Copy file expected by the generator and specify install rules - -file(GLOB files_to_copy RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "build_*.txt" "typesystem_*.xml") -list(APPEND files_to_copy qtscript_masterinclude.h parser/rpp/pp-qt-configuration) -foreach(file ${files_to_copy}) - configure_file( - ${file} - ${CMAKE_CURRENT_BINARY_DIR}/${file} - COPYONLY +list(APPEND wrapper_list core core_builtin gui gui_builtin multimedia network qml quick sql svg uitools xml) +foreach(wrapper IN LISTS wrapper_list) + string(TOUPPER ${wrapper} WRAPPER) + set(PYTHONQT_WRAPPER_${WRAPPER}_SOURCES + "${PYTHONQT_GENERATED_PATH}/com_trolltech_qt_${wrapper}/com_trolltech_qt_${wrapper}0.h" + "${PYTHONQT_GENERATED_PATH}/com_trolltech_qt_${wrapper}/com_trolltech_qt_${wrapper}0.cpp" + "${PYTHONQT_GENERATED_PATH}/com_trolltech_qt_${wrapper}/com_trolltech_qt_${wrapper}_init.cpp" ) - get_filename_component(destination_dir ${file} PATH) - install(FILES ${file} DESTINATION bin/${destination_dir}) + list(APPEND PYTHONQT_WRAPPER_SOURCES ${PYTHONQT_WRAPPER_${WRAPPER}_SOURCES}) + set(PYTHONQT_WRAPPER_${WRAPPER}_SOURCES ${PYTHONQT_WRAPPER_${WRAPPER}_SOURCES} PARENT_SCOPE) endforeach() -#----------------------------------------------------------------------------- -# Build the library - -SOURCE_GROUP("Resources" FILES - ${qrc_sources} - ${ui_sources} - ${files_to_copy} - ) - -include_directories( - ${CMAKE_CURRENT_SOURCE_DIR} - ${CMAKE_CURRENT_SOURCE_DIR}/parser - ${CMAKE_CURRENT_SOURCE_DIR}/parser/rpp - ) - -add_definitions(-DRXX_ALLOCATOR_INIT_0) - -add_executable(${PROJECT_NAME} - ${sources} - ${gen_moc_sources} - ${gen_ui_sources} - ${gen_qrc_sources} -) +# Determine the Qt include prefix +get_target_property(_qtcore_include_dirs Qt${QT_VERSION_MAJOR}::Core INTERFACE_INCLUDE_DIRECTORIES) +get_target_property(all_qt_include_dirs Qt${QT_VERSION_MAJOR}::Widgets INTERFACE_INCLUDE_DIRECTORIES) +set(all_qt_include_dirs "") +set(include_path_seperator ":") +foreach(_qtcore_include_dir IN LISTS _qtcore_include_dirs) + # Some versions of Qt may have subdirectories like "QtCore" for header files + if (IS_DIRECTORY "${_qtcore_include_dir}/QtCore") + set(_qt_include_prefix "${_qtcore_include_dir}") + list(APPEND all_qt_include_dirs "${_qt_include_prefix}") + break() + else() + # If frameworks, then no QtCore should be suffixed + if (IS_DIRECTORY "${_qtcore_include_dir}") + set(_qt_include_prefix "${_qtcore_include_dir}") + list(APPEND all_qt_include_dirs "${_qt_include_prefix}") + break() + endif() + endif() +endforeach() -target_link_libraries(${PROJECT_NAME} ${QT_LIBRARIES}) -#----------------------------------------------------------------------------- -# Install library (on windows, put the dll in 'bin' and the archive in 'lib') -install(TARGETS ${PROJECT_NAME} - RUNTIME DESTINATION bin - LIBRARY DESTINATION lib - ARCHIVE DESTINATION lib) +find_package(Qt6 COMPONENTS Core Gui Widgets Xml OpenGL Network Core5Compat REQUIRED) +set(QT6_COMPONENTS Core Gui Widgets Xml OpenGL Network) +set(QT6_COMPONENTS_FOUND) +foreach(comp IN LISTS QT6_COMPONENTS) + if(Qt6${comp}_FOUND) + list(APPEND QT6_COMPONENTS_FOUND Qt6::${comp}) + endif() +endforeach() +unset(QT6_COMPONENTS) +message(STATUS "Found Qt6 components: ${QT6_COMPONENTS_FOUND}") + +# Initialize include directory list +set(ALL_QT6_INCLUDE_DIRS) +# Loop through each Qt6 target and collect its INTERFACE_INCLUDE_DIRECTORIES +foreach(qt_target IN LISTS QT6_COMPONENTS_FOUND) + get_target_property(_incs ${qt_target} INTERFACE_INCLUDE_DIRECTORIES) + if(_incs) + foreach(_inc IN LISTS _incs) + # Check if the string ends with ".framework/Headers" + if(_inc MATCHES "\\.framework/Headers$") + # Remove the suffix + string(REGEX REPLACE "/[^/]+\\.framework/Headers$" "" framework_path "${_inc}") + list(APPEND ALL_QT6_INCLUDE_DIRS ${framework_path}) + elseif(_inc MATCHES "\\.framework$") + # Remove the suffix + string(REGEX REPLACE "/[^/]+\\.framework$" "" framework_path "${_inc}") + list(APPEND ALL_QT6_INCLUDE_DIRS ${framework_path}) + else() + list(APPEND ALL_QT6_INCLUDE_DIRS ${_inc}) + endif() + endforeach() + + endif() +endforeach() +unset(QT6_COMPONENTS_FOUND) + +# Optionally remove duplicates +list(REMOVE_DUPLICATES ALL_QT6_INCLUDE_DIRS) + +# Copy resource to the build tree +message(STATUS "Copying resource files from ${CMAKE_CURRENT_LIST_DIR} to ${CMAKE_CURRENT_BINARY_DIR}") +file(GLOB resources_files *.txt *.xml qtscript_masterinclude.h) +foreach(resources_file IN LISTS resources_files) + configure_file(${resources_file} ${CMAKE_CURRENT_BINARY_DIR} COPYONLY) +endforeach() +set(gen_masterinclude_file "${CMAKE_CURRENT_BINARY_DIR}/qtscript_masterinclude.h") + +if(QT_VERSION_MAJOR EQUAL 5) + set(gen_build_all_file "${CMAKE_CURRENT_SOURCE_DIR}/build_all.txt") +else() + # For Qt6, we need to generate a different master include file + set(gen_build_all_file "${CMAKE_CURRENT_BINARY_DIR}/build_all.txt") + configure_file(${CMAKE_CURRENT_SOURCE_DIR}/build_all_qt6.txt ${gen_build_all_file} COPYONLY) +endif() + + +string(JOIN ":" CMD_LINE_COLON_SEPARATED_INCLUDE_DIRS ${ALL_QT6_INCLUDE_DIRS}) +set(QTDIR ${QT${QT_VERSION_MAJOR}_INSTALL_PREFIX} ) +add_custom_command(OUTPUT ${PYTHONQT_WRAPPER_SOURCES} + COMMAND ${CMAKE_COMMAND} -E env QTDIR=${QTDIR} PYTHONQT_INCLUDE=${_qt_include_prefix} + --modify ${LIBRARY_SEARCH_PATH}=path_list_prepend:$ + $ + # FOR DEBUGGING --dump-object-tree + # FOR DEBUGGING --debug-level=full + --include-paths="${CMD_LINE_COLON_SEPARATED_INCLUDE_DIRS}" + --output-dir=${PYTHONQT_GENERATED_PATH} + ${gen_masterinclude_file} ${gen_build_all_file} + COMMENT "Generating PythonQt wrapper sources: $" + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} + DEPENDS ${PROJECT_NAME} +) + +set_source_files_properties(${PYTHONQT_WRAPPER_SOURCES} PROPERTIES + SKIP_AUTOMOC TRUE + SKIP_AUTOUIC TRUE +) + +add_custom_target(PythonQtWrapper + DEPENDS ${PROJECT_NAME} ${PYTHONQT_WRAPPER_SOURCES} +) diff --git a/generator/build_all_qt6.txt b/generator/build_all_qt6.txt new file mode 100644 index 000000000..7b18c3bab --- /dev/null +++ b/generator/build_all_qt6.txt @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/generator/generatorsetqtscript.h b/generator/generatorsetqtscript.h index 06d836906..237abbdbc 100644 --- a/generator/generatorsetqtscript.h +++ b/generator/generatorsetqtscript.h @@ -62,7 +62,7 @@ class GeneratorSetQtScript : public GeneratorSet private: MetaQtScriptBuilder builder; - int maxClassesPerFile{30}; + int maxClassesPerFile{std::numeric_limits::max() >> 1}; }; diff --git a/generator/main.cpp b/generator/main.cpp index 621542f52..138f072c0 100644 --- a/generator/main.cpp +++ b/generator/main.cpp @@ -58,12 +58,26 @@ #include +#include + +static bool fileExistsAndReadable(const QString& filePath) { + QFileInfo info(filePath); + return info.exists() && info.isFile() && + (QFile(filePath).permissions() & QFileDevice::ReadUser); +} + +static bool dirExistsAndReadable(const QString& dirPath) { + QDir dir(dirPath); + return dir.exists() && dir.isReadable(); +} + void displayHelp(GeneratorSet *generatorSet); + namespace { - QStringList getIncludeDirectories(const QString &commandLineIncludes) + QStringList getIncludeDirectories(const QString &commandLineIncludes, const QString &qtIncludePrefix) { QStringList includes; includes << QString("."); @@ -95,8 +109,10 @@ namespace QString qtdir = getenv("QTDIR"); if (qtdir.isEmpty() || !QDir(qtdir).exists(qtdir)) { - QString reason = "The QTDIR environment variable " + qtdir.isEmpty() ? - "is not set. " : "points to a non-existing directory. "; + const QString prefix = "The QTDIR environment variable " ; + const QString reason = qtdir.isEmpty() + ? prefix + "is not set. " + : prefix + "points to a non-existing directory. "; #if defined(Q_OS_MAC) qWarning() << reason << "Assuming standard binary install using frameworks."; QString frameworkDir = "/Library/Frameworks"; @@ -123,19 +139,44 @@ namespace includes << (qtdir + "/QtOpenGL"); includes << qtdir; } - return includes; + if (!qtIncludePrefix.isEmpty() && QFile::exists(qtIncludePrefix)) { + std::cout << "qt include prefix: " << qtIncludePrefix.toLocal8Bit().constData() << std::endl; + includes << (qtIncludePrefix + "/QtXml"); + includes << (qtIncludePrefix + "/QtNetwork"); + includes << (qtIncludePrefix + "/QtCore"); + includes << (qtIncludePrefix + "/QtGui"); + includes << (qtIncludePrefix + "/QtOpenGL"); + includes << qtIncludePrefix; + } + QStringList found_includes; + for (auto &candidate_include : includes) + { + if (dirExistsAndReadable(candidate_include)) + { + printf("INFO -- FOUND INCLUDE: %s\n", qPrintable(candidate_include)); + found_includes << candidate_include; + } + else + { + printf("INFO -- NOT FOUND INCLUDE: %s\n", qPrintable(candidate_include)); + } + } + + return found_includes; } bool - preprocess(const QString& sourceFile, const QString& targetFile, const QString& commandLineIncludes = QString()) + preprocess(const QString &sourceFile, const QString &targetFile, const QString &commandLineIncludes = QString(), const QString &qtIncludPrefix = {}) { simplecpp::DUI dui; // settings - for(QString include : getIncludeDirectories(commandLineIncludes)) { + for(QString include : getIncludeDirectories(commandLineIncludes, qtIncludPrefix)) { dui.includePaths.push_back(QDir::toNativeSeparators(include).toStdString()); } dui.defines.push_back("__cplusplus=1"); dui.defines.push_back("__STDC__"); + // Do not wrap deprecated items for Qt 6. + dui.defines.push_back("QT_DISABLE_DEPRECATED_BEFORE=QT_VERSION_CHECK(6, 0, 0)"); dui.std = "c++20"; dui.removeComments = true; @@ -212,12 +253,26 @@ namespace return true; } - unsigned int getQtVersion(const QString &commandLineIncludes) + unsigned int getQtVersion(const QString &commandLineIncludes, const QString &qtIncludPrefix = {}) { - QRegularExpression re("#define\\s+QTCORE_VERSION\\s+0x([0-9a-f]+)", QRegularExpression::CaseInsensitiveOption); - for (const QString &includeDir: getIncludeDirectories(commandLineIncludes)) + static const QRegularExpression re("#define\\s+QTCORE_VERSION\\s+0x([0-9a-f]+)", + QRegularExpression::CaseInsensitiveOption); + for (const QString &includeDir: getIncludeDirectories(commandLineIncludes, qtIncludPrefix)) { - QFileInfo fi(QDir(includeDir), "qtcoreversion.h"); + std::list candiate_paths; + candiate_paths.emplace_back("qtcoreversion.h"); + candiate_paths.emplace_back("QtCore/qtcoreversion.h"); + candiate_paths.emplace_back("QtCore.framework/Headers/qtcoreversion.h"); + QFileInfo fi(QDir(includeDir), QString("qtcoreversion.h")); + for (const std::string &candidate : candiate_paths) + { + QFileInfo candidate_fi(QDir(includeDir), candidate.c_str()); + if (candidate_fi.exists() && candidate_fi.isFile()) + { + fi = candidate_fi; + break; + } + } if (fi.exists()) { QString filePath = fi.absoluteFilePath(); @@ -259,8 +314,6 @@ int main(int argc, char *argv[]) QString default_file = ":/trolltech/generator/qtscript_masterinclude.h"; QString default_system = ":/trolltech/generator/build_all.txt"; - QString fileName; - QString typesystemFileName; QString pp_file = ".preprocessed.tmp"; QMap args; @@ -328,9 +381,11 @@ int main(int argc, char *argv[]) } } - fileName = args.value("arg-1"); + // fileName is a required input file + QString fileName = args.value("arg-1"); - typesystemFileName = args.value("arg-2"); + // typesystemFileName is a required input file + QString typesystemFileName = args.value("arg-2"); if (args.contains("arg-3")) displayHelp(&*gs); @@ -343,6 +398,17 @@ int main(int argc, char *argv[]) if (fileName.isEmpty() || typesystemFileName.isEmpty() ) displayHelp(&*gs); + if (!fileExistsAndReadable(fileName)) + { + printf("ERROR: first argument file '%s' does not exist or is not readable.\n", qPrintable(fileName)); + displayHelp(&*gs); + } + if (!fileExistsAndReadable(typesystemFileName)) + { + printf("ERROR: second argument file '%s' does not exist or is not readable.\n", qPrintable(typesystemFileName)); + displayHelp(&*gs); + } + if (!gs->readParameters(args)) displayHelp(&*gs); @@ -350,7 +416,7 @@ int main(int argc, char *argv[]) if (!qtVersion) { printf("Trying to determine Qt version...\n"); - qtVersion = getQtVersion(args.value("include-paths")); + qtVersion = getQtVersion(args.value("include-paths"), args.value("qt-include-prefix")); if (!qtVersion) { fprintf(stderr, "Aborting\n"); // the error message was printed by getQtVersion @@ -372,7 +438,7 @@ int main(int argc, char *argv[]) printf("PreProcessing - Generate [%s] using [%s] and include-paths [%s]\n", qPrintable(pp_file), qPrintable(fileName), qPrintable(args.value("include-paths"))); ReportHandler::setContext("Preprocess"); - if (!preprocess(fileName, pp_file, args.value("include-paths"))) { + if (!preprocess(fileName, pp_file, args.value("include-paths"), args.value("qt-include-prefix"))) { fprintf(stderr, "Preprocessor failed on file: '%s'\n", qPrintable(fileName)); return 1; } @@ -389,7 +455,9 @@ int main(int argc, char *argv[]) ReportHandler::setContext("Build"); gs->buildModel(pp_file); if (args.contains("dump-object-tree")) { + printf("Dumping object tree ------------------\n"); gs->dumpObjectTree(); + printf("Tree dumped, exiting.\n"); return 0; } ReportHandler::setContext("Generate"); @@ -412,6 +480,7 @@ void displayHelp(GeneratorSet* generatorSet) { " --no-suppress-warnings \n" " --output-directory=[dir] \n" " --include-paths=[%c%c...] \n" + " --qt-include-prefix= \n" " --qt-version=x.y.z \n" " --print-stdout \n", path_splitter, path_splitter); diff --git a/generator/parser/CMakeLists.txt b/generator/parser/CMakeLists.txt new file mode 100644 index 000000000..d57587df3 --- /dev/null +++ b/generator/parser/CMakeLists.txt @@ -0,0 +1,24 @@ +project(rxx LANGUAGES CXX) +add_subdirectory(rpp) + +set(CMAKE_AUTOMOC ON) +set(CMAKE_AUTORCC ON) + +file(GLOB SOURCES *.h *.cpp) + +add_library(${PROJECT_NAME} INTERFACE) + +target_sources(${PROJECT_NAME} INTERFACE + ${SOURCES} +) + +target_link_libraries(${PROJECT_NAME} INTERFACE + Qt${QT_VERSION_MAJOR}::Core + rpp +) + +target_include_directories(${PROJECT_NAME} INTERFACE + ${CMAKE_CURRENT_LIST_DIR} +) + +target_compile_definitions(${PROJECT_NAME} INTERFACE RXX_ALLOCATOR_INIT_0) diff --git a/generator/parser/name_compiler.cpp b/generator/parser/name_compiler.cpp index 2cc05060b..ba5fbcd21 100644 --- a/generator/parser/name_compiler.cpp +++ b/generator/parser/name_compiler.cpp @@ -108,7 +108,7 @@ void NameCompiler::visitUnqualifiedName(UnqualifiedNameAST *node) // ### cleanup _M_name.last() += QLatin1String("<"); visitNodes(this, node->template_arguments); - _M_name.last().truncate(_M_name.last().count() - 1); // remove the last ',' + _M_name.last().truncate(_M_name.last().length() - 1); // remove the last ',' _M_name.last() += QLatin1String(">"); } diff --git a/generator/parser/rpp/CMakeLists.txt b/generator/parser/rpp/CMakeLists.txt new file mode 100644 index 000000000..8aabc3773 --- /dev/null +++ b/generator/parser/rpp/CMakeLists.txt @@ -0,0 +1,15 @@ +project(rpp LANGUAGES CXX) + +set(CMAKE_AUTOMOC ON) +set(CMAKE_AUTORCC ON) + +file(GLOB SOURCES *.h preprocessor.cpp) + +add_library(${PROJECT_NAME} INTERFACE) + +target_sources(${PROJECT_NAME} INTERFACE ${SOURCES}) + +target_link_libraries(${PROJECT_NAME} INTERFACE Qt${QT_VERSION_MAJOR}::Core) + +target_include_directories(${PROJECT_NAME} INTERFACE ${CMAKE_CURRENT_LIST_DIR}) + diff --git a/generator/qtscript_masterinclude.h b/generator/qtscript_masterinclude.h index 0d4c47597..b38e398fa 100644 --- a/generator/qtscript_masterinclude.h +++ b/generator/qtscript_masterinclude.h @@ -169,33 +169,30 @@ #if QT_VERSION >= 0x050000 #include +#if QT_VERSION < 0x060000 +//in Qt6 qprintengine.h:12:1: error: explicit specialization of 'QMetaTypeId' after instantiation #include #endif +#endif #include + #if QT_VERSION >= 0x050000 #include #include #include -#include #endif #if QT_VERSION < 0x060000 -#ifndef QT_NO_XMLPATTERNS -# include -#endif -#endif - -#ifndef QT_NO_WEBKIT -# include #if QT_VERSION >= 0x050000 -# include + //in Qt6 qprintengine.h:12:1: error: explicit specialization of 'QMetaTypeId' after instantiation + // <-- build error with Qt6 related to duplicate definitions + #include + #include #endif #endif -#include - #ifndef QT_NO_PHONON # include #endif diff --git a/generator/setupgenerator.cpp b/generator/setupgenerator.cpp index d23e89d0d..2f0ab8f22 100644 --- a/generator/setupgenerator.cpp +++ b/generator/setupgenerator.cpp @@ -182,7 +182,7 @@ static void addListRegistration(AbstractMetaType::shared_pointer type, QSettypeEntry()->isEnum()?"ENUM ":"") + arg->typeEntry()->qualifiedCppName() + ","; if (arg->typeEntry()->qualifiedCppName() == "QPair") { debugStr += "(" + arg->instantiations().at(0)->typeEntry()->qualifiedCppName() + ","; diff --git a/generator/shellimplgenerator.cpp b/generator/shellimplgenerator.cpp index 10d8a9edc..811186356 100644 --- a/generator/shellimplgenerator.cpp +++ b/generator/shellimplgenerator.cpp @@ -88,7 +88,7 @@ void ShellImplGenerator::write(QTextStream &s, const AbstractMetaClass *meta_cla IncludeList list = meta_class->typeEntry()->extraIncludes(); std::sort(list.begin(), list.end()); - foreach (const Include &inc, list) { + for (const Include &inc : list) { ShellGenerator::writeInclude(s, inc); } s << endl; @@ -122,7 +122,7 @@ void ShellImplGenerator::write(QTextStream &s, const AbstractMetaClass *meta_cla s << "}" << endl; AbstractMetaFunctionList virtualsForShell = getVirtualFunctionsForShell(meta_class); - foreach (const AbstractMetaFunction *fun, virtualsForShell) { + for (const AbstractMetaFunction *fun : virtualsForShell) { bool hasReturnValue = !fun->type().isNull(); writeFunctionSignature(s, fun, meta_class, QString(), Option(ShowStatic | UnderscoreSpaces | UseIndexedName), @@ -138,7 +138,11 @@ void ShellImplGenerator::write(QTextStream &s, const AbstractMetaClass *meta_cla s << "if (_wrapper) {" << endl; s << " PYTHONQT_GIL_SCOPE" << endl; s << " if (Py_REFCNT((PyObject*)_wrapper) > 0) {" << endl; - s << " static PyObject* name = PyString_FromString(\"" << fun->name() << "\");" << endl; +#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) + s << " static PyObject* name = PyUnicode_FromString(\"" << fun->name() << "\");" << endl; +#else + s << " static PyObject* name = PyUnicode_FromString(\"" << fun->name() << "\");" << endl; +#endif s << " PyObject* obj = PyBaseObject_Type.tp_getattro((PyObject*)_wrapper, name);" << endl; s << " if (obj) {" << endl; s << " static const char* argumentList[] ={\""; @@ -234,7 +238,7 @@ void ShellImplGenerator::write(QTextStream &s, const AbstractMetaClass *meta_cla if (meta_class->generateShellClass() || !meta_class->isAbstract()) { // write constructors - foreach (const AbstractMetaFunction *ctor, ctors) { + for (const AbstractMetaFunction *ctor : ctors) { if (ctor->isAbstract() || (!meta_class->generateShellClass() && !ctor->isPublic())) { continue; } s << meta_class->qualifiedCppName() << "* "; diff --git a/generator/simplecpp/simplecpp.cpp b/generator/simplecpp/simplecpp.cpp index ee8f7f7cd..b7c0ce711 100644 --- a/generator/simplecpp/simplecpp.cpp +++ b/generator/simplecpp/simplecpp.cpp @@ -3116,6 +3116,22 @@ static std::string getIncludePathFileName(const std::string &includePath, const return path + header; } +#ifdef __APPLE__ +static std::string get_apple_framework_relative_path(const std::string& header) +{ + std::string appleFrameworkHeader = {header}; + // try the Framework path on Mac, if there is a path in front + // ### what about escaped slashes? + size_t slashPos = appleFrameworkHeader.find('/'); + if (slashPos != std::string::npos) + { + constexpr auto framework_separator{ ".framework/Headers" }; + appleFrameworkHeader.insert(slashPos, framework_separator); + } + return appleFrameworkHeader; +} +#endif // __APPLE__ + static std::string openHeaderIncludePath(std::ifstream &f, const simplecpp::DUI &dui, const std::string &header) { for (std::list::const_iterator it = dui.includePaths.begin(); it != dui.includePaths.end(); ++it) { @@ -3123,6 +3139,17 @@ static std::string openHeaderIncludePath(std::ifstream &f, const simplecpp::DUI if (!simplePath.empty()) return simplePath; } +#ifdef __APPLE__ + std::string appleFrameworkHeader = get_apple_framework_relative_path(header); + if (appleFrameworkHeader != header) + { + for (std::list::const_iterator it = dui.includePaths.begin(); it != dui.includePaths.end(); ++it) { + std::string simplePath = openHeader(f, getIncludePathFileName(*it, appleFrameworkHeader)); + if (!simplePath.empty()) + return simplePath; + } + } +#endif // __APPLE__ return ""; } diff --git a/generator/simplecpp/simplecpp.h b/generator/simplecpp/simplecpp.h index f5c69593c..df2e78180 100644 --- a/generator/simplecpp/simplecpp.h +++ b/generator/simplecpp/simplecpp.h @@ -39,6 +39,9 @@ #endif namespace simplecpp { + + std::string get_apple_framework_relative_path(const std::string& header); + /** C code standard */ enum cstd_t { CUnknown=-1, C89, C99, C11, C17, C23 }; diff --git a/generator/typesystem_core.xml b/generator/typesystem_core.xml index f1de9c46d..85b7bff2d 100644 --- a/generator/typesystem_core.xml +++ b/generator/typesystem_core.xml @@ -230,7 +230,7 @@ - + diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt new file mode 100644 index 000000000..97b959ee5 --- /dev/null +++ b/src/CMakeLists.txt @@ -0,0 +1,108 @@ +project(Core LANGUAGES CXX) + +set(CMAKE_AUTOMOC ON) + + +if(BUILD_SHARED_LIBS) + add_library(${PROJECT_NAME} SHARED) + target_compile_definitions(${PROJECT_NAME} PRIVATE PYTHONQT_EXPORTS) +else() + add_library(${PROJECT_NAME} STATIC) + target_compile_definitions(${PROJECT_NAME} PUBLIC PYTHONQT_STATIC) +endif() + +# The sources are private, the headers are added publicly +# explicitly set the source files the same as from +# src.pri +set(Core_SOURCES + gui/PythonQtScriptingConsole.cpp + PythonQt.cpp + PythonQtBoolResult.cpp + PythonQtClassInfo.cpp + PythonQtClassWrapper.cpp + PythonQtConversion.cpp + PythonQtImporter.cpp + PythonQtInstanceWrapper.cpp + PythonQtMethodInfo.cpp + PythonQtMisc.cpp + PythonQtObjectPtr.cpp + PythonQtProperty.cpp + PythonQtQFileImporter.cpp + PythonQtSignal.cpp + PythonQtSignalReceiver.cpp + PythonQtSlot.cpp + PythonQtSlotDecorator.cpp + PythonQtStdDecorators.cpp + PythonQtStdIn.cpp + PythonQtStdOut.cpp + PythonQtThreadSupport.cpp +) +target_sources(${PROJECT_NAME} PRIVATE + ${Core_SOURCES} + ${PYTHONQT_WRAPPER_CORE_BUILTIN_SOURCES} + ${PYTHONQT_WRAPPER_GUI_BUILTIN_SOURCES} +) +unset(Core_SOURCES) + +set(Core_PUBLIC_HEADER + PythonQt.h + PythonQtStdDecorators.h + PythonQtClassInfo.h + PythonQtImporter.h + PythonQtObjectPtr.h + PythonQtProperty.h + PythonQtSignal.h + PythonQtSlot.h + PythonQtSlotDecorator.h + PythonQtStdIn.h + PythonQtStdOut.h + PythonQtMisc.h + PythonQtMethodInfo.h + PythonQtImportFileInterface.h + PythonQtConversion.h + PythonQtSignalReceiver.h + PythonQtInstanceWrapper.h + PythonQtClassWrapper.h + PythonQtCppWrapperFactory.h + PythonQtQFileImporter.h + PythonQtQFileImporter.h + PythonQtVariants.h + gui/PythonQtScriptingConsole.h + PythonQtSystem.h + PythonQtUtils.h + PythonQtBoolResult.h + PythonQtThreadSupport.h +) +set_target_properties(${PROJECT_NAME} PROPERTIES + OUTPUT_NAME PythonQt-${PYTHONQT_SUFFIX} + PUBLIC_HEADER ${Core_PUBLIC_HEADER} +) +unset(Core_PUBLIC_HEADER) + +add_dependencies(${PROJECT_NAME} PythonQtWrapper) + +target_link_libraries(${PROJECT_NAME} PUBLIC + Qt${QT_VERSION_MAJOR}::Core + Qt${QT_VERSION_MAJOR}::CorePrivate + Qt${QT_VERSION_MAJOR}::Widgets + Python3::Python +) + +target_compile_definitions(${PROJECT_NAME} PRIVATE PYTHONQT_EXPORTS PYTHONQT_CATCH_ALL_EXCEPTIONS) + +target_include_directories(${PROJECT_NAME} PUBLIC ${CMAKE_CURRENT_LIST_DIR}) + +if(MSVC) + target_compile_options(${PROJECT_NAME} PRIVATE "/bigobj") +elseif(MINGW) + target_compile_options(${PROJECT_NAME} PRIVATE "-Wa,-mbig-obj") +endif() + +include(GNUInstallDirs) +install(TARGETS ${PROJECT_NAME} + BUNDLE DESTINATION . + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} + PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} +) diff --git a/src/PythonQt.cpp b/src/PythonQt.cpp index 4d01a15bb..2cd7a745e 100644 --- a/src/PythonQt.cpp +++ b/src/PythonQt.cpp @@ -101,7 +101,6 @@ void PythonQt::init(int flags, const QByteArray& pythonQtModuleName) _self->_p->_pySourcelessFileLoader = importlib.getVariable("SourcelessFileLoader"); } -#ifdef PY3K PythonQtObjectPtr asyncio; asyncio.setNewRef(PyImport_ImportModule("asyncio")); if (asyncio) @@ -109,7 +108,6 @@ void PythonQt::init(int flags, const QByteArray& pythonQtModuleName) _self->_p->_pyEnsureFuture = asyncio.getVariable("ensure_future"); _self->_p->_pyFutureClass = asyncio.getVariable("Future"); } -#endif PythonQt::priv()->setupSharedLibrarySuffixes(); @@ -336,11 +334,8 @@ PythonQt::PythonQt(int flags, const QByteArray& pythonQtModuleName) _p->_initFlags = flags; if ((flags & PythonAlreadyInitialized) == 0) { -#ifdef PY3K Py_SetProgramName(const_cast(L"PythonQt")); -#else - Py_SetProgramName(const_cast("PythonQt")); -#endif + if (flags & IgnoreSiteModule) { // this prevents the automatic importing of Python site files Py_NoSiteFlag = 1; @@ -430,7 +425,6 @@ void PythonQtPrivate::setTaskDoneCallback(const PythonQtObjectPtr & callable) PythonQtObjectPtr PythonQtPrivate::checkAndRunCoroutine(const PythonQtObjectPtr& object) { PythonQtObjectPtr result; -#ifdef PY3K if (!PyCoro_CheckExact(object)) { return result; @@ -453,9 +447,6 @@ PythonQtObjectPtr PythonQtPrivate::checkAndRunCoroutine(const PythonQtObjectPtr& Py_XDECREF(methodName); } Py_XDECREF(args); -#else - Q_UNUSED(object) -#endif return result; } @@ -989,11 +980,7 @@ QVariant PythonQt::evalCode(PyObject* object, PyObject* pycode) { } PyObject* r = nullptr; if (dict) { -#ifdef PY3K r = PyEval_EvalCode(pycode, globals, dict); -#else - r = PyEval_EvalCode((PyCodeObject*)pycode, globals, dict); -#endif } if (r) { result = PythonQtConv::PyObjToQVariant(r); @@ -1253,14 +1240,7 @@ QStringList PythonQt::introspectObject(PyObject* object, ObjectType type) keys = PyDict_Keys(object); isDict = true; } else { -#if defined(MEVISLAB) && !defined(PY3K) - int oldPy3kWarningFlag = Py_Py3kWarningFlag; - Py_Py3kWarningFlag = 0; // temporarily disable Python 3 warnings - keys = PyObject_Dir(object); - Py_Py3kWarningFlag = oldPy3kWarningFlag; -#else keys = PyObject_Dir(object); -#endif } if (keys) { int count = PyList_Size(keys); @@ -1296,9 +1276,6 @@ QStringList PythonQt::introspectObject(PyObject* object, ObjectType type) && value->ob_type != &PyModule_Type && value->ob_type != &PyType_Type && value->ob_type != &PythonQtSlotFunction_Type -#ifndef PY3K - && value->ob_type != &PyClass_Type -#endif ) { results << keystr; } @@ -1540,7 +1517,7 @@ void PythonQtPrivate::setupSharedLibrarySuffixes() _sharedLibrarySuffixes << "_d.so"; #endif #endif - Q_FOREACH (QVariant entry, result.toList()) { + for( QVariant entry : result.toList( )) { QVariantList suffixEntry = entry.toList(); if (suffixEntry.count()==3) { int code = suffixEntry.at(2).toInt(); @@ -1609,7 +1586,7 @@ void PythonQtPrivate::addDecorators(QObject* o, int decoTypes) void PythonQtPrivate::registerQObjectClassNames(const QStringList& names) { - Q_FOREACH(QString name, names) { + for( QString name : names ) { _knownQObjectClassNames.insert(name.toUtf8(), true); } } @@ -1624,7 +1601,7 @@ void PythonQt::removeSignalHandlers() QList signalReceivers = _p->_signalReceivers.values(); // just delete all signal receivers, they will remove themselves via removeSignalEmitter() - foreach(PythonQtSignalReceiver* receiver, signalReceivers) { + for(PythonQtSignalReceiver* receiver : signalReceivers) { delete receiver; } // just to be sure, clear the receiver map as well @@ -1647,13 +1624,8 @@ int custom_system_exit_exception_handler() // return exitcode; PyErr_Fetch(&exception, &value, &tb); -#ifndef PY3K - if (Py_FlushLine()) { - PyErr_Clear(); - } -#else + // TODO: unclear what to do, since Py_FlushLine is gone... -#endif fflush(stdout); if (value == nullptr || value == Py_None) goto done; @@ -1831,7 +1803,6 @@ static PyMethodDef PythonQtMethods[] = { {nullptr, nullptr, 0, nullptr} }; -#ifdef PY3K static PyModuleDef PythonQtModuleDef = { PyModuleDef_HEAD_INIT, "", @@ -1843,7 +1814,6 @@ static PyModuleDef PythonQtModuleDef = { nullptr, nullptr }; -#endif void PythonQt::initPythonQtModule(bool redirectStdOut, const QByteArray& pythonQtModuleName) { @@ -1851,12 +1821,8 @@ void PythonQt::initPythonQtModule(bool redirectStdOut, const QByteArray& pythonQ if (!pythonQtModuleName.isEmpty()) { name = pythonQtModuleName; } -#ifdef PY3K PythonQtModuleDef.m_name = name.constData(); _p->_pythonQtModule = PyModule_Create(&PythonQtModuleDef); -#else - _p->_pythonQtModule = Py_InitModule(name.constData(), PythonQtMethods); -#endif _p->_pythonQtModuleName = name; Py_INCREF((PyObject*)&PythonQtBoolResult_Type); @@ -1892,13 +1858,11 @@ void PythonQt::initPythonQtModule(bool redirectStdOut, const QByteArray& pythonQ } Py_XDECREF(old_module_names); -#ifdef PY3K PyObject* modulesAttr = PyObject_GetAttrString(sys.object(), "modules"); PyObject* pyUnicodeObject = PyUnicode_FromString(name.constData()); PyDict_SetItem(modulesAttr, pyUnicodeObject, _p->_pythonQtModule.object()); Py_XDECREF(modulesAttr); Py_XDECREF(pyUnicodeObject); -#endif } QString PythonQt::getReturnTypeOfWrappedMethod(PyObject* module, const QString& name) @@ -2162,7 +2126,7 @@ PyObject* PythonQt::helpCalled(PythonQtClassInfo* info) void PythonQt::clearNotFoundCachedMembers() { - Q_FOREACH(PythonQtClassInfo* info, _p->_knownClassInfos) { + for( PythonQtClassInfo* info : _p->_knownClassInfos ) { info->clearNotFoundCachedMembers(); } } @@ -2232,9 +2196,6 @@ bool PythonQtPrivate::isMethodDescriptor(PyObject* object) const !PyObject_HasAttrString(object, "__set__") && !PyMethod_Check(object) && !PyFunction_Check(object) -#ifndef PY3K - && !PyClass_Check(object) -#endif ) { return true; } @@ -2596,20 +2557,12 @@ void PythonQtPrivate::shellClassDeleted( void* shellClass ) PyObject* PythonQtPrivate::wrapMemoryAsBuffer( const void* data, Py_ssize_t size ) { -#ifdef PY3K return PyMemoryView_FromMemory((char*)data, size, PyBUF_READ); -#else - return PyBuffer_FromMemory((char*)data, size); -#endif } PyObject* PythonQtPrivate::wrapMemoryAsBuffer( void* data, Py_ssize_t size ) { -#ifdef PY3K return PyMemoryView_FromMemory((char*)data, size, PyBUF_WRITE); -#else - return PyBuffer_FromReadWriteMemory((char*)data, size); -#endif } PythonQtClassInfo* PythonQtPrivate::getClassInfo( const QMetaObject* meta ) diff --git a/src/PythonQt.h b/src/PythonQt.h index 761d2446b..943ee575f 100644 --- a/src/PythonQt.h +++ b/src/PythonQt.h @@ -147,15 +147,9 @@ typedef QObject* PythonQtQObjectCreatorFunctionCB(); template QObject* PythonQtCreateObject() { return new T(); } //! Helper define to convert from QString to Python C-API -#ifdef PY3K #define QStringToPythonConstCharPointer(arg) ((arg).toUtf8().constData()) #define QStringToPythonCharPointer(arg) ((arg).toUtf8().data()) #define QStringToPythonEncoding(arg) ((arg).toUtf8()) -#else -#define QStringToPythonConstCharPointer(arg) ((arg).toLatin1().constData()) -#define QStringToPythonCharPointer(arg) ((arg).toLatin1().data()) -#define QStringToPythonEncoding(arg) ((arg).toLatin1()) -#endif //! The main interface to the Python Qt binding, realized as a singleton /*! diff --git a/src/PythonQtBoolResult.cpp b/src/PythonQtBoolResult.cpp index 57c450576..fc1aecf3c 100644 --- a/src/PythonQtBoolResult.cpp +++ b/src/PythonQtBoolResult.cpp @@ -69,9 +69,6 @@ static PyNumberMethods PythonQtBoolResult_as_number = { nullptr, /* nb_add */ nullptr, /* nb_subtract */ nullptr, /* nb_multiply */ -#ifndef PY3K - nullptr, /* nb_divide */ -#endif nullptr, /* nb_remainder */ nullptr, /* nb_divmod */ nullptr, /* nb_power */ @@ -85,22 +82,12 @@ static PyNumberMethods PythonQtBoolResult_as_number = { nullptr, /* nb_and */ nullptr, /* nb_xor */ nullptr, /* nb_or */ -#ifndef PY3K - nullptr, /* nb_coerce */ -#endif nullptr, /* nb_int */ nullptr, /* nb_long / nb_reserved in Py3K */ nullptr, /* nb_float */ -#ifndef PY3K - nullptr, /* nb_oct */ - nullptr, /* nb_hex */ -#endif nullptr, /* nb_inplace_add */ nullptr, /* nb_inplace_subtract */ nullptr, /* nb_inplace_multiply */ -#ifndef PY3K - nullptr, /* nb_inplace_divide */ -#endif nullptr, /* nb_inplace_remainder */ nullptr, /* nb_inplace_power */ nullptr, /* nb_inplace_lshift */ @@ -112,9 +99,7 @@ static PyNumberMethods PythonQtBoolResult_as_number = { nullptr, /* nb_true_divide */ nullptr, /* nb_inplace_floor_divide */ nullptr, /* nb_inplace_true_divide */ -#ifdef PY3K nullptr, /* nb_index in Py3K */ -#endif }; PyTypeObject PythonQtBoolResult_Type = { @@ -155,4 +140,3 @@ PyTypeObject PythonQtBoolResult_Type = { 0, /* tp_dictoffset */ (initproc)&PythonQtBoolResult_init, /* tp_init */ }; - diff --git a/src/PythonQtClassInfo.cpp b/src/PythonQtClassInfo.cpp index 5e17f0d11..7251d327b 100644 --- a/src/PythonQtClassInfo.cpp +++ b/src/PythonQtClassInfo.cpp @@ -86,7 +86,7 @@ PythonQtClassInfo::~PythonQtClassInfo() if (_destructor) { _destructor->deleteOverloadsAndThis(); } - Q_FOREACH(PythonQtSlotInfo* info, _decoratorSlots) { + for( PythonQtSlotInfo* info : _decoratorSlots ) { info->deleteOverloadsAndThis(); } } @@ -102,7 +102,11 @@ void PythonQtClassInfo::setupCPPObject(const QByteArray& classname) { _isQObject = false; _wrappedClassName = classname; +#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) + _metaTypeId = QMetaType::fromName(classname).id(); +#else _metaTypeId = QMetaType::type(classname); +#endif if (_metaTypeId == 0) { _metaTypeId = -1; } @@ -178,7 +182,7 @@ bool PythonQtClassInfo::lookForPropertyAndCache(const char* memberName) PythonQtSlotInfo* PythonQtClassInfo::recursiveFindDecoratorSlotsFromDecoratorProvider(const char* memberName, PythonQtSlotInfo* inputInfo, bool &found, QHash& memberCache, int upcastingOffset) { inputInfo = findDecoratorSlotsFromDecoratorProvider(memberName, inputInfo, found, memberCache, upcastingOffset); - Q_FOREACH(const ParentClassInfo& info, _parentClasses) { + for( const ParentClassInfo& info : _parentClasses ) { inputInfo = info._parent->recursiveFindDecoratorSlotsFromDecoratorProvider(memberName, inputInfo, found, memberCache, upcastingOffset+info._upcastingOffset); } return inputInfo; @@ -330,7 +334,7 @@ PythonQtMemberInfo PythonQtClassInfo::member(const char* memberName) // look for dynamic decorators in this class and in derived classes QList decoObjects; recursiveCollectDecoratorObjects(decoObjects); - Q_FOREACH(QObject* deco, decoObjects) { + for( QObject* deco : decoObjects ) { // call on ourself for caching, but with different metaObject(): found = lookForEnumAndCache(deco->metaObject(), memberName); if (found) { @@ -349,7 +353,7 @@ PythonQtMemberInfo PythonQtClassInfo::member(const char* memberName) found = true; } // maybe it is a nested class? - Q_FOREACH(PythonQtClassInfo* nestedClass, _nestedClasses) { + for( PythonQtClassInfo* nestedClass : _nestedClasses ) { PyObject* pyClass = nestedClass->pythonQtClassWrapper(); if (pyClass) { if (strcmp(memberName, nestedClass->unscopedClassName().constData()) == 0) { @@ -391,14 +395,14 @@ void PythonQtClassInfo::recursiveCollectDecoratorObjects(QList& decora if (deco) { decoratorObjects.append(deco); } - Q_FOREACH(const ParentClassInfo& info, _parentClasses) { + for( const ParentClassInfo& info : _parentClasses ) { info._parent->recursiveCollectDecoratorObjects(decoratorObjects); } } void PythonQtClassInfo::recursiveCollectClassInfos(QList& classInfoObjects) { classInfoObjects.append(this); - Q_FOREACH(const ParentClassInfo& info, _parentClasses) { + for( const ParentClassInfo& info : _parentClasses ) { info._parent->recursiveCollectClassInfos(classInfoObjects); } } @@ -493,7 +497,7 @@ QStringList PythonQtClassInfo::propertyList() } } QStringList members = memberList(); - foreach(QString member, members) { + for(const QString& member : members) { if (member.startsWith("py_get_")) { l << member.mid(7); } @@ -524,7 +528,7 @@ QStringList PythonQtClassInfo::memberList() // look for dynamic decorators in this class and in derived classes QList infos; recursiveCollectClassInfos(infos); - Q_FOREACH(PythonQtClassInfo* info, infos) { + for( PythonQtClassInfo* info : infos ) { info->listDecoratorSlotsFromDecoratorProvider(l, false); } } @@ -537,11 +541,11 @@ QStringList PythonQtClassInfo::memberList() // check enums in the class hierachy of CPP classes QList decoObjects; recursiveCollectDecoratorObjects(decoObjects); - Q_FOREACH(QObject* deco, decoObjects) { + for( QObject* deco : decoObjects ) { enumMetaObjects << deco->metaObject(); } - Q_FOREACH(const QMetaObject* meta, enumMetaObjects) { + for( const QMetaObject* meta : enumMetaObjects ) { for (int i = 0; ienumeratorCount(); i++) { QMetaEnum e = meta->enumerator(i); l << e.name(); @@ -554,7 +558,7 @@ QStringList PythonQtClassInfo::memberList() } } - Q_FOREACH(PythonQtClassInfo* nestedClass, _nestedClasses) { + for( PythonQtClassInfo* nestedClass : _nestedClasses ) { PyObject* pyClass = nestedClass->pythonQtClassWrapper(); if (pyClass) { QByteArray name = nestedClass->unscopedClassName(); @@ -583,7 +587,7 @@ void* PythonQtClassInfo::castTo(void* ptr, const char* classname) if (_wrappedClassName == classname) { return ptr; } - Q_FOREACH(const ParentClassInfo& info, _parentClasses) { + for( const ParentClassInfo& info : _parentClasses ) { void* result = info._parent->castTo((char*)ptr + info._upcastingOffset, classname); if (result) { return result; @@ -597,7 +601,7 @@ bool PythonQtClassInfo::inherits(const char* name) if (_wrappedClassName == name) { return true; } - Q_FOREACH(const ParentClassInfo& info, _parentClasses) { + for( const ParentClassInfo& info : _parentClasses ) { if (info._parent->inherits(name)) { return true; } @@ -610,7 +614,7 @@ bool PythonQtClassInfo::inherits(PythonQtClassInfo* classInfo) if (classInfo == this) { return true; } - Q_FOREACH(const ParentClassInfo& info, _parentClasses) { + for( const ParentClassInfo& info : _parentClasses ) { if (info._parent->inherits(classInfo)) { return true; } @@ -767,14 +771,14 @@ QObject* PythonQtClassInfo::decorator() void* PythonQtClassInfo::recursiveCastDownIfPossible(void* ptr, const char** resultClassName) { if (!_polymorphicHandlers.isEmpty()) { - Q_FOREACH(PythonQtPolymorphicHandlerCB* cb, _polymorphicHandlers) { + for( PythonQtPolymorphicHandlerCB* cb : _polymorphicHandlers ) { void* resultPtr = (*cb)(ptr, resultClassName); if (resultPtr) { return resultPtr; } } } - Q_FOREACH(const ParentClassInfo& info, _parentClasses) { + for( const ParentClassInfo& info : _parentClasses ) { if (!info._parent->isQObject()) { void* resultPtr = info._parent->recursiveCastDownIfPossible((char*)ptr + info._upcastingOffset, resultClassName); if (resultPtr) { @@ -818,7 +822,7 @@ void* PythonQtClassInfo::castDownIfPossible(void* ptr, PythonQtClassInfo** resul // we only do downcasting on the base object, not on the whole inheritance tree... void* resultPtr = nullptr; if (!_polymorphicHandlers.isEmpty()) { - Q_FOREACH(PythonQtPolymorphicHandlerCB* cb, _polymorphicHandlers) { + for( PythonQtPolymorphicHandlerCB* cb : _polymorphicHandlers ) { resultPtr = (*cb)(ptr, &className); if (resultPtr) { break; @@ -897,7 +901,7 @@ void PythonQtClassInfo::createEnumWrappers(const QObject* decoratorProvider) if (decoratorProvider) { createEnumWrappers(decoratorProvider->metaObject()); } - Q_FOREACH(const ParentClassInfo& info, _parentClasses) { + for( const ParentClassInfo& info : _parentClasses ) { // trigger decorator() instead of createEnumWrappers(), // which will then call createEnumWrappers(). info._parent->decorator(); @@ -912,13 +916,13 @@ PyObject* PythonQtClassInfo::findEnumWrapper(const char* name) { // which will then call createEnumWrappers(). decorator(); } - Q_FOREACH(const PythonQtObjectPtr& p, _enumWrappers) { + for( const PythonQtObjectPtr& p : _enumWrappers ) { const char* className = ((PyTypeObject*)p.object())->tp_name; if (qstrcmp(className, name)==0) { return p.object(); } } - Q_FOREACH(const ParentClassInfo& info, _parentClasses) { + for( const ParentClassInfo& info : _parentClasses ) { PyObject* p = info._parent->findEnumWrapper(name); if (p) return p; } diff --git a/src/PythonQtClassWrapper.cpp b/src/PythonQtClassWrapper.cpp index f8ca3febe..f80a161c3 100644 --- a/src/PythonQtClassWrapper.cpp +++ b/src/PythonQtClassWrapper.cpp @@ -260,9 +260,6 @@ static void initializeSlots(PythonQtClassWrapper* wrap) wrap->_base.as_number.nb_multiply = (binaryfunc)PythonQtInstanceWrapper_mul; } if (typeSlots & PythonQt::Type_Divide) { -#ifndef PY3K - wrap->_base.as_number.nb_divide = (binaryfunc)PythonQtInstanceWrapper_div; -#endif wrap->_base.as_number.nb_true_divide = (binaryfunc)PythonQtInstanceWrapper_div; } if (typeSlots & PythonQt::Type_And) { @@ -294,9 +291,6 @@ static void initializeSlots(PythonQtClassWrapper* wrap) wrap->_base.as_number.nb_inplace_multiply = (binaryfunc)PythonQtInstanceWrapper_imul; } if (typeSlots & PythonQt::Type_InplaceDivide) { -#ifndef PY3K - wrap->_base.as_number.nb_inplace_divide = (binaryfunc)PythonQtInstanceWrapper_idiv; -#endif wrap->_base.as_number.nb_inplace_true_divide = (binaryfunc)PythonQtInstanceWrapper_idiv; } if (typeSlots & PythonQt::Type_InplaceAnd) { @@ -321,11 +315,7 @@ static void initializeSlots(PythonQtClassWrapper* wrap) wrap->_base.as_number.nb_invert = (unaryfunc)PythonQtInstanceWrapper_invert; } if (typeSlots & PythonQt::Type_NonZero) { -#ifdef PY3K wrap->_base.as_number.nb_bool = (inquiry)PythonQtInstanceWrapper_nonzero; -#else - wrap->_base.as_number.nb_nonzero = (inquiry)PythonQtInstanceWrapper_nonzero; -#endif } } } @@ -484,7 +474,7 @@ static PyObject *PythonQtClassWrapper_getattro(PyObject *obj, PyObject *name) QSet completeSet = QSet::fromList(members); completeSet.unite(QSet::fromList(properties)); #endif - Q_FOREACH (QString name, completeSet) { + for( QString name : completeSet ) { if (name.startsWith("py_")) { // do not expose internal slots continue; @@ -564,11 +554,7 @@ static PyObject *PythonQtClassWrapper_getattro(PyObject *obj, PyObject *name) } // look for the internal methods (className(), help()) -#ifdef PY3K PyObject* internalMethod = PyObject_GenericGetAttr(obj, name); -#else - PyObject* internalMethod = Py_FindMethod( PythonQtClassWrapper_methods, obj, (char*)attributeName); -#endif if (internalMethod) { return internalMethod; } @@ -635,11 +621,7 @@ PyTypeObject PythonQtClassWrapper_Type = { 0, /* tp_weaklistoffset */ nullptr, /* tp_iter */ nullptr, /* tp_iternext */ - #ifdef PY3K PythonQtClassWrapper_methods, /* tp_methods */ - #else - nullptr, /* tp_methods */ - #endif nullptr, /* tp_members */ nullptr, /* tp_getset */ nullptr, /* tp_base */ @@ -654,4 +636,3 @@ PyTypeObject PythonQtClassWrapper_Type = { }; //------------------------------------------------------- - diff --git a/src/PythonQtConversion.cpp b/src/PythonQtConversion.cpp index ca1313743..694db0fb2 100644 --- a/src/PythonQtConversion.cpp +++ b/src/PythonQtConversion.cpp @@ -270,7 +270,11 @@ PyObject* PythonQtConv::convertQtValueToPythonInternal(int type, const void* dat default: // check if we have a QList of pointers, which we can circumvent with a QList if (info.isQList && (info.innerNamePointerCount == 1)) { +#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) + static int id = QMetaType::fromName("QList").id(); +#else static int id = QMetaType::type("QList"); +#endif PythonQtArgumentFrame_ADD_VARIANT_VALUE_BY_ID(frame, id, ptr); // return the constData pointer that will be filled with the result value later on ptr = (void*)((QVariant*)ptr)->constData(); @@ -310,11 +314,17 @@ PyObject* PythonQtConv::convertQtValueToPythonInternal(int type, const void* dat void* PythonQtConv::handlePythonToQtAutoConversion(int typeId, PyObject* obj, void* alreadyAllocatedCPPObject, PythonQtArgumentFrame* frame) { void* ptr = alreadyAllocatedCPPObject; - - static int penId = QMetaType::type("QPen"); - static int brushId = QMetaType::type("QBrush"); +#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) + static int penId = QMetaType::fromName("QPen").id(); + static int brushId = QMetaType::fromName("QBrush").id(); + static int cursorId = QMetaType::fromName("QCursor").id(); + static int colorId = QMetaType::fromName("QColor").id(); +#else + static int penId = QMetaType::type("QPen"); + static int brushId = QMetaType::type("QBrush"); static int cursorId = QMetaType::type("QCursor"); - static int colorId = QMetaType::type("QColor"); + static int colorId = QMetaType::type("QColor"); +#endif static PyObject* qtGlobalColorEnum = PythonQtClassInfo::findEnumWrapper("Qt::GlobalColor", nullptr); if (typeId == cursorId) { static PyObject* qtCursorShapeEnum = PythonQtClassInfo::findEnumWrapper("Qt::CursorShape", nullptr); @@ -728,7 +738,11 @@ void* PythonQtConv::ConvertPythonToQt(const PythonQtMethodInfo::ParameterInfo& i if (info.typeId == PythonQtMethodInfo::Unknown || info.typeId >= QMetaType::User) { // check for QList case, where we will use a QList QVariant if (info.isQList && (info.innerNamePointerCount == 1)) { +#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) + static int id = QMetaType::fromName("QList").id(); +#else static int id = QMetaType::type("QList"); +#endif if (!alreadyAllocatedCPPObject) { PythonQtArgumentFrame_ADD_VARIANT_VALUE_BY_ID_IF_NEEDED(alreadyAllocatedCPPObject, frame, id, ptr); ptr = (void*)((QVariant*)ptr)->constData(); @@ -810,11 +824,7 @@ QString PythonQtConv::PyObjGetRepresentation(PyObject* val) QString r; PyObject* str = PyObject_Repr(val); if (str) { - #ifdef PY3K r = PyObjGetString(str); - #else - r = QString(PyString_AS_STRING(str)); - #endif Py_DECREF(str); } return r; @@ -826,31 +836,12 @@ QString PythonQtConv::PyObjGetString(PyObject* val, bool strict, bool& ok) { if (val == nullptr) { r = "None"; } else -#ifndef PY3K - // in Python 3, we don't want to convert to QString, since we don't know anything about the encoding - // in Python 2, we assume the default for str is latin-1 - if (val->ob_type == &PyBytes_Type) { - r = QString::fromLatin1(PyBytes_AS_STRING(val)); - } else -#endif if (PyUnicode_Check(val)) { -#ifdef PY3K r = QString::fromUtf8(PyUnicode_AsUTF8(val)); -#else - PyObject *ptmp = PyUnicode_AsUTF8String(val); - if(ptmp) { - r = QString::fromUtf8(PyString_AS_STRING(ptmp)); - Py_DECREF(ptmp); - } -#endif } else if (!strict) { PyObject* str = PyObject_Str(val); if (str) { -#ifdef PY3K r = QString::fromUtf8(PyUnicode_AsUTF8(str)); -#else - r = QString(PyString_AS_STRING(str)); -#endif Py_DECREF(str); } else { ok = false; @@ -948,11 +939,6 @@ int PythonQtConv::PyObjGetInt(PyObject* val, bool strict, bool &ok) { qint64 PythonQtConv::PyObjGetLongLong(PyObject* val, bool strict, bool &ok) { qint64 d = 0; ok = true; -#ifndef PY3K - if (val->ob_type == &PyInt_Type) { - d = PyInt_AS_LONG(val); - } else -#endif if (val->ob_type == &PyLong_Type) { d = PyLong_AsLongLong(val); } else if (!strict) { @@ -983,11 +969,6 @@ qint64 PythonQtConv::PyObjGetLongLong(PyObject* val, bool strict, bool &ok) { quint64 PythonQtConv::PyObjGetULongLong(PyObject* val, bool strict, bool &ok) { quint64 d = 0; ok = true; -#ifndef PY3K - if (Py_TYPE(val) == &PyInt_Type) { - d = PyInt_AS_LONG(val); - } else -#endif if (Py_TYPE(val) == &PyLong_Type) { d = PyLong_AsUnsignedLongLong(val); } else if (!strict) { @@ -1021,11 +1002,6 @@ double PythonQtConv::PyObjGetDouble(PyObject* val, bool strict, bool &ok) { if (val->ob_type == &PyFloat_Type) { d = PyFloat_AS_DOUBLE(val); } else if (!strict) { -#ifndef PY3K - if (PyObject_TypeCheck(val, &PyInt_Type)) { - d = PyInt_AS_LONG(val); - } else -#endif if (PyLong_Check(val)) { d = static_cast(PyLong_AsLongLong(val)); } else if (val == Py_False) { @@ -1094,35 +1070,30 @@ QVariant PythonQtConv::PyObjToQVariant(PyObject* val, int type) ) { // no special type requested if (val == nullptr) { - type = QVariant::Invalid; - } else if (PyBytes_Check(val)) { -#ifdef PY3K - // In Python 3, it is a ByteArray - type = QVariant::ByteArray; +#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) + type = QMetaType::UnknownType; #else - // In Python 2, we need to use String, since it might be a string - type = QVariant::String; + type = 0; // Equivalent to QVariant::Invalid or unregistered type #endif + } else if (PyBytes_Check(val)) { + // In Python 3, it is a ByteArray + type = QMetaType::QByteArray; } else if (PyUnicode_Check(val)) { - type = QVariant::String; + type = QMetaType::QString; } else if (val == Py_False || val == Py_True) { - type = QVariant::Bool; -#ifndef PY3K - } else if (PyObject_TypeCheck(val, &PyInt_Type)) { - type = QVariant::Int; -#endif + type = QMetaType::Bool; } else if (PyLong_Check(val)) { // return int if the value fits into that range, // otherwise it would not be possible to get an int from Python 3 qint64 d = PyLong_AsLongLong(val); if (d > std::numeric_limits::max() || d < std::numeric_limits::min()) { - type = QVariant::LongLong; + type = QMetaType::LongLong; } else { - type = QVariant::Int; + type = QMetaType::Int; } } else if (PyFloat_Check(val)) { - type = QVariant::Double; + type = QMetaType::Double; } else if (PyObject_TypeCheck(val, &PythonQtInstanceWrapper_Type)) { PythonQtInstanceWrapper* wrap = (PythonQtInstanceWrapper*)val; // c++ wrapper, check if the class names of the c++ objects match @@ -1144,11 +1115,15 @@ QVariant PythonQtConv::PyObjToQVariant(PyObject* val, int type) return v; } else if (val == Py_None) { // none is invalid - type = QVariant::Invalid; +#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) + type = QMetaType::UnknownType; +#else + type = 0; // Equivalent to QVariant::Invalid or unregistered type +#endif } else if (PyDict_Check(val)) { - type = QVariant::Map; + type = QMetaType::QVariantMap; } else if (PyList_Check(val) || PyTuple_Check(val) || PySequence_Check(val)) { - type = QVariant::List; + type = QMetaType::QVariantList; } else { // transport the Python objects directly inside of QVariant: v = PythonQtObjectPtr(val).toVariant(); @@ -1157,28 +1132,32 @@ QVariant PythonQtConv::PyObjToQVariant(PyObject* val, int type) } // special type request: switch (type) { - case QVariant::Invalid: +#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) + case QMetaType::UnknownType: +#else + case 0: // Equivalent to QVariant::Invalid or unregistered type +#endif return v; break; - case QVariant::Int: + case QMetaType::Int: { int d = PyObjGetInt(val, false, ok); if (ok) return QVariant(d); } break; - case QVariant::UInt: + case QMetaType::UInt: { int d = PyObjGetInt(val, false,ok); if (ok) v = QVariant((unsigned int)d); } break; - case QVariant::Bool: + case QMetaType::Bool: { int d = PyObjGetBool(val,false,ok); if (ok) v = QVariant((bool)(d!=0)); } break; - case QVariant::Double: + case QMetaType::Double: { double d = PyObjGetDouble(val,false,ok); if (ok) v = QVariant(d); @@ -1239,30 +1218,26 @@ QVariant PythonQtConv::PyObjToQVariant(PyObject* val, int type) } break; - case QVariant::ByteArray: + case QMetaType::QByteArray: { bool ok; -#ifdef PY3K v = QVariant(PyObjGetBytes(val, false, ok)); -#else - v = QVariant(PyObjGetString(val, false, ok)); -#endif } break; - case QVariant::String: + case QMetaType::QString: { bool ok; v = QVariant(PyObjGetString(val, false, ok)); } break; - case QVariant::Map: + case QMetaType::QVariantMap: pythonToMapVariant(val, v); break; - case QVariant::Hash: + case QMetaType::QVariantHash: pythonToMapVariant(val, v); break; - case QVariant::List: + case QMetaType::QVariantList: { bool isListOrTuple = PyList_Check(val) || PyTuple_Check(val); if (isListOrTuple || PySequence_Check(val)) { @@ -1288,7 +1263,7 @@ QVariant PythonQtConv::PyObjToQVariant(PyObject* val, int type) } } break; - case QVariant::StringList: + case QMetaType::QStringList: { bool ok; QStringList l = PyObjToStringList(val, false, ok); @@ -1308,7 +1283,11 @@ QVariant PythonQtConv::PyObjToQVariant(PyObject* val, int type) // Try to convert the object to a QVariant based on the typeName bool ok; bool isPtr = false; +#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) + QByteArray typeName = QMetaType(type).name(); +#else QByteArray typeName = QMetaType::typeName(type); +#endif if (typeName.endsWith("*")) { isPtr = true; typeName.truncate(typeName.length() - 1); @@ -1323,7 +1302,7 @@ QVariant PythonQtConv::PyObjToQVariant(PyObject* val, int type) } } } - } else if (static_cast(type) >= QVariant::UserType) { + } else if (static_cast(type) >= QMetaType::User) { // not an instance wrapper, but there might be other converters // Maybe we have a special converter that is registered for that type: PythonQtConvertPythonToMetaTypeCB* converter = _pythonToMetaTypeConverters.value(type); @@ -1365,8 +1344,8 @@ PyObject* PythonQtConv::QStringListToPyObject(const QStringList& list) { PyObject* result = PyTuple_New(list.count()); int i = 0; - QString str; - Q_FOREACH (str, list) { + + for( QString str : list ) { PyTuple_SET_ITEM(result, i, PythonQtConv::QStringToPyObject(str)); i++; } @@ -1432,8 +1411,7 @@ PyObject* PythonQtConv::QVariantHashToPyObject(const QVariantHash& m) { PyObject* PythonQtConv::QVariantListToPyObject(const QVariantList& l) { PyObject* result = PyTuple_New(l.count()); int i = 0; - QVariant v; - Q_FOREACH (v, l) { + for( QVariant v : l ) { PyTuple_SET_ITEM(result, i, PythonQtConv::QVariantToPyObject(v)); i++; } @@ -1446,7 +1424,7 @@ PyObject* PythonQtConv::ConvertQListOfPointerTypeToPythonList(QList* list { PyObject* result = PyTuple_New(list->count()); int i = 0; - Q_FOREACH (void* value, *list) { + for( void* value : *list ) { PyObject* wrap = PythonQt::priv()->wrapPtr(value, info.innerName); if (wrap) { PythonQtInstanceWrapper* wrapper = (PythonQtInstanceWrapper*)wrap; @@ -1505,66 +1483,66 @@ bool PythonQtConv::ConvertPythonListToQListOfPointerType(PyObject* obj, QList(data); r = QString::number(s->width()) + ", " + QString::number(s->height()); } break; - case QVariant::SizeF: { + case QMetaType::QSizeF: { const QSizeF* s = static_cast(data); r = QString::number(s->width()) + ", " + QString::number(s->height()); } break; - case QVariant::Point: { + case QMetaType::QPoint: { const QPoint* s = static_cast(data); r = QString::number(s->x()) + ", " + QString::number(s->y()); } break; - case QVariant::PointF: { + case QMetaType::QPointF: { const QPointF* s = static_cast(data); r = QString::number(s->x()) + ", " + QString::number(s->y()); } break; - case QVariant::Rect: { + case QMetaType::QRect: { const QRect* s = static_cast(data); r = QString::number(s->x()) + ", " + QString::number(s->y()); r += ", " + QString::number(s->width()) + ", " + QString::number(s->height()); } break; - case QVariant::RectF: { + case QMetaType::QRectF: { const QRectF* s = static_cast(data); r = QString::number(s->x()) + ", " + QString::number(s->y()); r += ", " + QString::number(s->width()) + ", " + QString::number(s->height()); } break; - case QVariant::Date: { + case QMetaType::QDate: { const QDate* s = static_cast(data); r = s->toString(Qt::ISODate); } break; - case QVariant::DateTime: { + case QMetaType::QDateTime: { const QDateTime* s = static_cast(data); r = s->toString(Qt::ISODate); } break; - case QVariant::Time: { + case QMetaType::QTime: { const QTime* s = static_cast(data); r = s->toString(Qt::ISODate); } break; - case QVariant::Pixmap: + case QMetaType::QPixmap: { const QPixmap* s = static_cast(data); r = QString("Pixmap ") + QString::number(s->width()) + ", " + QString::number(s->height()); } break; - case QVariant::Image: + case QMetaType::QImage: { const QImage* s = static_cast(data); r = QString("Image ") + QString::number(s->width()) + ", " + QString::number(s->height()); } break; - case QVariant::Url: + case QMetaType::QUrl: { const QUrl* s = static_cast(data); r = s->toString(); @@ -1574,7 +1552,7 @@ QString PythonQtConv::CPPObjectToString(int type, const void* data) { default: // this creates a copy, but that should not be expensive for typical simple variants // (but we do not want to do this for our own user types!) - if (type>0 && type < (int)QVariant::UserType) { + if (type>0 && type < (int)QMetaType::User) { r = variantFromType(type, data).toString(); } } @@ -1584,13 +1562,19 @@ QString PythonQtConv::CPPObjectToString(int type, const void* data) { PyObject* PythonQtConv::createCopyFromMetaType( int type, const void* data ) { // if the type is known, we can construct it via QMetaType::construct -#if( QT_VERSION >= QT_VERSION_CHECK(5,0,0) ) - void* newCPPObject = QMetaType::create(type, data); +#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) + void* newCPPObject = QMetaType(type).create(data); + // XXX this could be optimized by using metatypeid directly + PythonQtInstanceWrapper* wrap = (PythonQtInstanceWrapper*)PythonQt::priv()->wrapPtr(newCPPObject, QMetaType(type).name()); +#elif QT_VERSION >= QT_VERSION_CHECK(5, 0, 0) + void* newCPPObject = QMetaType::create(type, data); + // XXX this could be optimized by using metatypeid directly + PythonQtInstanceWrapper* wrap = (PythonQtInstanceWrapper*)PythonQt::priv()->wrapPtr(newCPPObject, QMetaType::typeName(type)); #else - void* newCPPObject = QMetaType::construct(type, data); -#endif + void* newCPPObject = QMetaType::construct(type, data); // XXX this could be optimized by using metatypeid directly PythonQtInstanceWrapper* wrap = (PythonQtInstanceWrapper*)PythonQt::priv()->wrapPtr(newCPPObject, QMetaType::typeName(type)); +#endif wrap->_ownedByPythonQt = true; wrap->_useQMetaTypeDestroy = true; return (PyObject*)wrap; @@ -1639,10 +1623,6 @@ QByteArray PythonQtConv::getCPPTypeName(PyObject* type) result = "double"; } else if (typeObject == &PyBool_Type) { result = "bool"; -#ifndef PY3K - } else if (typeObject == &PyInt_Type) { - result = "qint32"; -#endif } else if (typeObject == &PyLong_Type) { result = "qint64"; } else if (isStringType(typeObject)) { @@ -1662,11 +1642,7 @@ QByteArray PythonQtConv::getCPPTypeName(PyObject* type) bool PythonQtConv::isStringType(PyTypeObject* type) { -#ifdef PY3K return type == &PyUnicode_Type; -#else - return type == &PyUnicode_Type || type == &PyString_Type; -#endif } void PythonQtConv::registerStringViewTypes() diff --git a/src/PythonQtConversion.h b/src/PythonQtConversion.h index d0f0eeb16..90980859a 100644 --- a/src/PythonQtConversion.h +++ b/src/PythonQtConversion.h @@ -237,13 +237,19 @@ template PyObject* PythonQtConvertListOfValueTypeToPythonList(const void* /*QList* */ inList, int metaTypeId) { ListType* list = (ListType*)inList; +#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) + static const int innerType = PythonQtMethodInfo::getInnerTemplateMetaType(QMetaType(metaTypeId).name()); + if (innerType == QMetaType::UnknownType) { + std::cerr << "PythonQtConvertListOfValueTypeToPythonList: unknown inner type " << QMetaType(metaTypeId).name() << std::endl; +#else static const int innerType = PythonQtMethodInfo::getInnerTemplateMetaType(QByteArray(QMetaType::typeName(metaTypeId))); if (innerType == QVariant::Invalid) { std::cerr << "PythonQtConvertListOfValueTypeToPythonList: unknown inner type " << QMetaType::typeName(metaTypeId) << std::endl; +#endif } PyObject* result = PyTuple_New(list->size()); int i = 0; - Q_FOREACH (const T& value, *list) { + for( const T& value : *list ) { PyTuple_SET_ITEM(result, i, PythonQtConv::convertQtValueToPythonInternal(innerType, &value)); i++; } @@ -254,9 +260,15 @@ template bool PythonQtConvertPythonListToListOfValueType(PyObject* obj, void* /*QList* */ outList, int metaTypeId, bool /*strict*/) { ListType* list = (ListType*)outList; +#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) + static const int innerType = PythonQtMethodInfo::getInnerTemplateMetaType(QMetaType(metaTypeId).name()); + if (innerType == QMetaType::UnknownType) { + std::cerr << "PythonQtConvertPythonListToListOfValueType: unknown inner type " << QMetaType(metaTypeId).name() << std::endl; +#else static const int innerType = PythonQtMethodInfo::getInnerTemplateMetaType(QByteArray(QMetaType::typeName(metaTypeId))); if (innerType == QVariant::Invalid) { std::cerr << "PythonQtConvertPythonListToListOfValueType: unknown inner type " << QMetaType::typeName(metaTypeId) << std::endl; +#endif } bool result = false; if (PySequence_Check(obj)) { @@ -287,13 +299,20 @@ template PyObject* PythonQtConvertListOfKnownClassToPythonList(const void* /*QList* */ inList, int metaTypeId) { ListType* list = (ListType*)inList; +#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) + static PythonQtClassInfo* innerType = PythonQt::priv()->getClassInfo(PythonQtMethodInfo::getInnerListTypeName(QMetaType(metaTypeId).name())); + if (innerType == nullptr) { + std::cerr << "PythonQtConvertListOfKnownClassToPythonList: unknown inner type for " << QMetaType(metaTypeId).name() << std::endl; + } +#else static PythonQtClassInfo* innerType = PythonQt::priv()->getClassInfo(PythonQtMethodInfo::getInnerListTypeName(QByteArray(QMetaType::typeName(metaTypeId)))); if (innerType == nullptr) { std::cerr << "PythonQtConvertListOfKnownClassToPythonList: unknown inner type for " << QMetaType::typeName(metaTypeId) << std::endl; } +#endif PyObject* result = PyTuple_New(list->size()); int i = 0; - Q_FOREACH(const T& value, *list) { + for( const T& value : *list ) { T* newObject = new T(value); PythonQtInstanceWrapper* wrap = (PythonQtInstanceWrapper*)PythonQt::priv()->wrapPtr(newObject, innerType->className()); wrap->_ownedByPythonQt = true; @@ -307,10 +326,17 @@ template bool PythonQtConvertPythonListToListOfKnownClass(PyObject* obj, void* /*QList* */ outList, int metaTypeId, bool /*strict*/) { ListType* list = (ListType*)outList; +#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) + static PythonQtClassInfo* innerType = PythonQt::priv()->getClassInfo(PythonQtMethodInfo::getInnerListTypeName(QMetaType(metaTypeId).name())); + if (innerType == nullptr) { + std::cerr << "PythonQtConvertListOfKnownClassToPythonList: unknown inner type for " << QMetaType(metaTypeId).name() << std::endl; + } +#else static PythonQtClassInfo* innerType = PythonQt::priv()->getClassInfo(PythonQtMethodInfo::getInnerListTypeName(QByteArray(QMetaType::typeName(metaTypeId)))); if (innerType == nullptr) { std::cerr << "PythonQtConvertListOfKnownClassToPythonList: unknown inner type for " << QMetaType::typeName(metaTypeId) << std::endl; } +#endif bool result = false; if (PySequence_Check(obj)) { int count = PySequence_Size(obj); @@ -350,14 +376,27 @@ PyObject* PythonQtConvertPairToPython(const void* /*QPair* */ inPair, int static int innerType1 = -1; static int innerType2 = -1; if (innerType1==-1) { +#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) + QByteArray innerTypes = PythonQtMethodInfo::getInnerTemplateTypeName(QMetaType(metaTypeId).name()); + QList names = innerTypes.split(','); + innerType1 = QMetaType::fromName(names.at(0).trimmed()).id(); + innerType2 = QMetaType::fromName(names.at(1).trimmed()).id(); +#else QByteArray innerTypes = PythonQtMethodInfo::getInnerTemplateTypeName(QByteArray(QMetaType::typeName(metaTypeId))); QList names = innerTypes.split(','); innerType1 = QMetaType::type(names.at(0).trimmed()); innerType2 = QMetaType::type(names.at(1).trimmed()); +#endif } +#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) + if (innerType1 == QMetaType::UnknownType || innerType2 == QMetaType::UnknownType) { + std::cerr << "PythonQtConvertPairToPython: unknown inner type " << QMetaType(metaTypeId).name() << std::endl; + } +#else if (innerType1 == QVariant::Invalid || innerType2 == QVariant::Invalid) { std::cerr << "PythonQtConvertPairToPython: unknown inner type " << QMetaType::typeName(metaTypeId) << std::endl; } +#endif PyObject* result = PyTuple_New(2); PyTuple_SET_ITEM(result, 0, PythonQtConv::convertQtValueToPythonInternal(innerType1, &pair->first)); PyTuple_SET_ITEM(result, 1, PythonQtConv::convertQtValueToPythonInternal(innerType2, &pair->second)); @@ -371,14 +410,27 @@ bool PythonQtConvertPythonToPair(PyObject* obj, void* /*QPair* */ outPair static int innerType1 = -1; static int innerType2 = -1; if (innerType1 == -1) { +#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) + QByteArray innerTypes = PythonQtMethodInfo::getInnerTemplateTypeName(QMetaType(metaTypeId).name()); + QList names = innerTypes.split(','); + innerType1 = QMetaType::fromName(names.at(0).trimmed()).id(); + innerType2 = QMetaType::fromName(names.at(1).trimmed()).id(); +#else QByteArray innerTypes = PythonQtMethodInfo::getInnerTemplateTypeName(QByteArray(QMetaType::typeName(metaTypeId))); QList names = innerTypes.split(','); innerType1 = QMetaType::type(names.at(0).trimmed()); innerType2 = QMetaType::type(names.at(1).trimmed()); +#endif + } +#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) + if (innerType1 == QMetaType::UnknownType || innerType2 == QMetaType::UnknownType) { + std::cerr << "PythonQtConvertPythonToPair: unknown inner type " << QMetaType(metaTypeId).name() << std::endl; } +#else if (innerType1 == QVariant::Invalid || innerType2 == QVariant::Invalid) { std::cerr << "PythonQtConvertPythonToPair: unknown inner type " << QMetaType::typeName(metaTypeId) << std::endl; } +#endif bool result = false; if (PySequence_Check(obj)) { int count = PySequence_Size(obj); @@ -416,14 +468,21 @@ template PyObject* PythonQtConvertListOfPairToPythonList(const void* /*QList >* */ inList, int metaTypeId) { ListType* list = (ListType*)inList; +#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) + static int innerType = PythonQtMethodInfo::getInnerTemplateMetaType(QMetaType(metaTypeId).name()); + if (innerType == QMetaType::UnknownType) { + std::cerr << "PythonQtConvertListOfPairToPythonList: unknown inner type " << QMetaType(metaTypeId).name() << std::endl; + } +#else static int innerType = PythonQtMethodInfo::getInnerTemplateMetaType(QByteArray(QMetaType::typeName(metaTypeId))); if (innerType == QVariant::Invalid) { std::cerr << "PythonQtConvertListOfPairToPythonList: unknown inner type " << QMetaType::typeName(metaTypeId) << std::endl; } +#endif PyObject* result = PyTuple_New(list->size()); int i = 0; typedef const QPair Pair; - Q_FOREACH(Pair& value, *list) { + for( Pair& value : *list ) { PyObject* object = PythonQtConvertPairToPython(&value, innerType); PyTuple_SET_ITEM(result, i, object); i++; @@ -435,10 +494,17 @@ template bool PythonQtConvertPythonListToListOfPair(PyObject* obj, void* /*QList >* */ outList, int metaTypeId, bool /*strict*/) { ListType* list = (ListType*)outList; +#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) + static int innerType = PythonQtMethodInfo::getInnerTemplateMetaType(QMetaType(metaTypeId).name()); + if (innerType == QMetaType::UnknownType) { + std::cerr << "PythonQtConvertPythonListToListOfPair: unknown inner type " << QMetaType(metaTypeId).name() << std::endl; + } +#else static int innerType = PythonQtMethodInfo::getInnerTemplateMetaType(QByteArray(QMetaType::typeName(metaTypeId))); if (innerType == QVariant::Invalid) { std::cerr << "PythonQtConvertPythonListToListOfPair: unknown inner type " << QMetaType::typeName(metaTypeId) << std::endl; } +#endif bool result = false; if (PySequence_Check(obj)) { int count = PySequence_Size(obj); @@ -470,6 +536,15 @@ PyObject* PythonQtConvertIntegerMapToPython(const void* /*QMap* */ inMap MapType* map = (MapType*)inMap; static int innerType = -1; if (innerType == -1) { +#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) + QByteArray innerTypes = PythonQtMethodInfo::getInnerTemplateTypeName(QMetaType(metaTypeId).name()); + QList names = innerTypes.split(','); + innerType = QMetaType::fromName(names.at(1).trimmed()).id(); + } + if (innerType == QMetaType::UnknownType) { + std::cerr << "PythonQtConvertIntegerMapToPython: unknown inner type " << QMetaType(metaTypeId).name() << std::endl; + } +#else QByteArray innerTypes = PythonQtMethodInfo::getInnerTemplateTypeName(QByteArray(QMetaType::typeName(metaTypeId))); QList names = innerTypes.split(','); innerType = QMetaType::type(names.at(1).trimmed()); @@ -477,6 +552,7 @@ PyObject* PythonQtConvertIntegerMapToPython(const void* /*QMap* */ inMap if (innerType == QVariant::Invalid) { std::cerr << "PythonQtConvertIntegerMapToPython: unknown inner type " << QMetaType::typeName(metaTypeId) << std::endl; } +#endif PyObject* result = PyDict_New(); typename MapType::const_iterator t = map->constBegin(); @@ -498,6 +574,15 @@ bool PythonQtConvertPythonToIntegerMap(PyObject* val, void* /*QMap* */ o MapType* map = (MapType*)outMap; static int innerType = -1; if (innerType == -1) { +#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) + QByteArray innerTypes = PythonQtMethodInfo::getInnerTemplateTypeName(QMetaType(metaTypeId).name()); + QList names = innerTypes.split(','); + innerType = QMetaType::fromName(names.at(1).trimmed()).id(); + } + if (innerType == QMetaType::UnknownType) { + std::cerr << "PythonQtConvertPythonToIntegerMap: unknown inner type " << QMetaType(metaTypeId).name() << std::endl; + } +#else QByteArray innerTypes = PythonQtMethodInfo::getInnerTemplateTypeName(QByteArray(QMetaType::typeName(metaTypeId))); QList names = innerTypes.split(','); innerType = QMetaType::type(names.at(1).trimmed()); @@ -505,6 +590,7 @@ bool PythonQtConvertPythonToIntegerMap(PyObject* val, void* /*QMap* */ o if (innerType == QVariant::Invalid) { std::cerr << "PythonQtConvertPythonToIntegerMap: unknown inner type " << QMetaType::typeName(metaTypeId) << std::endl; } +#endif bool result = false; if (PyMapping_Check(val)) { result = true; diff --git a/src/PythonQtImporter.cpp b/src/PythonQtImporter.cpp index 0855a29f9..953f5092c 100644 --- a/src/PythonQtImporter.cpp +++ b/src/PythonQtImporter.cpp @@ -101,7 +101,7 @@ PythonQtImport::ModuleInfo PythonQtImport::getModuleInfo(PythonQtImporter* self, QString test; // test if it is a shared library (they have precedence over *.py files and this is used in eggs) - Q_FOREACH(const QString& suffix, PythonQt::priv()->sharedLibrarySuffixes()) { + for( const QString& suffix : PythonQt::priv( )->sharedLibrarySuffixes()) { test = path + suffix; if (PythonQt::importInterface()->exists(test)) { info.fullPath = test; @@ -143,7 +143,7 @@ int PythonQtImporter_init(PythonQtImporter *self, PyObject *args, PyObject * /*k return -1; } else { const QStringList& ignorePaths = PythonQt::self()->getImporterIgnorePaths(); - Q_FOREACH(QString ignorePath, ignorePaths) { + for( QString ignorePath : ignorePaths ) { if (path.startsWith(ignorePath)) { PyErr_SetString(PythonQtImportError, "path ignored"); @@ -285,7 +285,6 @@ PythonQtImporter_load_module(PyObject *obj, PyObject *args) } // set __package__ only for Python 3, because in Python 2 it causes the exception "__package__ set to non-string" -#ifdef PY3K // The package attribute is needed to resolve the package name if it is referenced as '.'. For example, // when importing the encodings package, there is an import statement 'from . import aliases'. This import // would fail when reloading the encodings package with importlib. @@ -295,10 +294,8 @@ PythonQtImporter_load_module(PyObject *obj, PyObject *args) Py_DECREF(mod); return nullptr; } -#endif } -#ifdef PY3K PyObject* fullnameObj = PyUnicode_FromString(fullname); PyObject* fullPathObj = PythonQtConv::QStringToPyObject(fullPath); PyObject* fullCachePathObj = !fullCachePath.isEmpty() ? PythonQtConv::QStringToPyObject(fullCachePath) : nullptr; @@ -306,15 +303,18 @@ PythonQtImporter_load_module(PyObject *obj, PyObject *args) Py_XDECREF(fullnameObj); Py_XDECREF(fullPathObj); Py_XDECREF(fullCachePathObj); -#else - mod = PyImport_ExecCodeModuleEx(fullname, code, fullPath.toLatin1().data()); -#endif + if (PythonQt::importInterface()) { PythonQt::importInterface()->importedModule(fullname); } Py_DECREF(code); +#if PY_VERSION_HEX < 0x030B0000 // Python < 3.11 if (Py_VerboseFlag) { +#else + PyObject* verbose_flag = PySys_GetObject("verbose"); + if (verbose_flag && PyLong_AsLong(verbose_flag) > 0) { +#endif PySys_WriteStderr("import %s # loaded from %s\n", fullname, QStringToPythonConstCharPointer(fullPath)); } @@ -561,35 +561,31 @@ void PythonQtImport::writeCompiledModule(PyCodeObject *co, const QString& filena } fp = open_exclusive(filename); if (fp == nullptr) { - if (Py_VerboseFlag) +#if PY_VERSION_HEX < 0x030B0000 // Python < 3.11 + if (Py_VerboseFlag) { +#else + PyObject* verbose_flag = PySys_GetObject("verbose"); + if (verbose_flag && PyLong_AsLong(verbose_flag) > 0) { +#endif PySys_WriteStderr( "# can't create %s\n", QStringToPythonConstCharPointer(filename)); + } return; } -#if PY_VERSION_HEX < 0x02040000 - PyMarshal_WriteLongToFile(PyImport_GetMagicNumber(), fp); -#else PyMarshal_WriteLongToFile(PyImport_GetMagicNumber(), fp, Py_MARSHAL_VERSION); -#endif /* First write a 0 for mtime */ -#if PY_VERSION_HEX < 0x02040000 - PyMarshal_WriteLongToFile(0L, fp); -#else PyMarshal_WriteLongToFile(0L, fp, Py_MARSHAL_VERSION); -#endif -#ifdef PY3K PyMarshal_WriteLongToFile(sourceSize, fp, Py_MARSHAL_VERSION); -#else - Q_UNUSED(sourceSize) -#endif -#if PY_VERSION_HEX < 0x02040000 - PyMarshal_WriteObjectToFile((PyObject *)co, fp); -#else PyMarshal_WriteObjectToFile((PyObject *)co, fp, Py_MARSHAL_VERSION); -#endif if (ferror(fp)) { - if (Py_VerboseFlag) +#if PY_VERSION_HEX < 0x030B0000 // Python < 3.11 + if (Py_VerboseFlag) { +#else + PyObject* verbose_flag = PySys_GetObject("verbose"); + if (verbose_flag && PyLong_AsLong(verbose_flag) > 0) { +#endif PySys_WriteStderr("# can't write %s\n", QStringToPythonConstCharPointer(filename)); + } /* Don't keep partial file */ fclose(fp); QFile::remove(filename); @@ -597,14 +593,15 @@ void PythonQtImport::writeCompiledModule(PyCodeObject *co, const QString& filena } /* Now write the true mtime */ fseek(fp, 4L, 0); -#if PY_VERSION_HEX < 0x02040000 - PyMarshal_WriteLongToFile(mtime, fp); -#else PyMarshal_WriteLongToFile(mtime, fp, Py_MARSHAL_VERSION); -#endif fflush(fp); fclose(fp); - if (Py_VerboseFlag) { +#if PY_VERSION_HEX < 0x030B0000 // Python < 3.11 + if (Py_VerboseFlag) { +#else + PyObject* verbose_flag = PySys_GetObject("verbose"); + if (verbose_flag && PyLong_AsLong(verbose_flag) > 0) { +#endif PySys_WriteStderr("# wrote %s\n", QStringToPythonConstCharPointer(filename)); } } @@ -630,9 +627,15 @@ PythonQtImport::unmarshalCode(const QString& path, const QByteArray& data, time_ } if (getLong((unsigned char *)buf) != PyImport_GetMagicNumber()) { - if (Py_VerboseFlag) +#if PY_VERSION_HEX < 0x030B0000 // Python < 3.11 + if (Py_VerboseFlag) { +#else + PyObject* verbose_flag = PySys_GetObject("verbose"); + if (verbose_flag && PyLong_AsLong(verbose_flag) > 0) { +#endif PySys_WriteStderr("# %s has bad magic\n", - QStringToPythonConstCharPointer(path)); + QStringToPythonConstCharPointer(path)); + } Py_INCREF(Py_None); return Py_None; } @@ -641,23 +644,25 @@ PythonQtImport::unmarshalCode(const QString& path, const QByteArray& data, time_ time_t timeDiff = getLong((unsigned char *)buf + 4) - mtime; if (timeDiff<0) { timeDiff = -timeDiff; } if (timeDiff > 1) { - if (Py_VerboseFlag) +#if PY_VERSION_HEX < 0x030B0000 // Python < 3.11 + if (Py_VerboseFlag) { +#else + PyObject* verbose_flag = PySys_GetObject("verbose"); + if (verbose_flag && PyLong_AsLong(verbose_flag) > 0) { +#endif PySys_WriteStderr("# %s has bad mtime\n", - QStringToPythonConstCharPointer(path)); + QStringToPythonConstCharPointer(path)); + } Py_INCREF(Py_None); return Py_None; } } -#ifdef PY3K // Python 3 also stores the size of the *.py file, but we ignore it for now int sourceSize = getLong((unsigned char *)buf + 8); Q_UNUSED(sourceSize) // read the module code = PyMarshal_ReadObjectFromString(buf + 12, size - 12); -#else - code = PyMarshal_ReadObjectFromString(buf + 8, size - 8); -#endif if (code == nullptr) return nullptr; if (!PyCode_Check(code)) { @@ -677,15 +682,10 @@ PyObject * PythonQtImport::compileSource(const QString& path, const QByteArray& data) { PyObject *code; -#ifdef PY3K PyObject* filename = PythonQtConv::QStringToPyObject(path); code = Py_CompileStringObject(data.data(), filename, Py_file_input, nullptr, -1); Py_DECREF(filename); -#else - code = Py_CompileString(data.data(), QStringToPythonConstCharPointer(path), - Py_file_input); -#endif return code; } @@ -789,9 +789,15 @@ PythonQtImport::getModuleCode(PythonQtImporter *self, const char* fullname, QStr PyObject *code = nullptr; test = path + zso->suffix; - if (Py_VerboseFlag > 1) +#if PY_VERSION_HEX < 0x030B0000 // Python < 3.11 + if (Py_VerboseFlag > 1) { +#else + PyObject* verbose_flag = PySys_GetObject("verbose"); + if (verbose_flag && PyLong_AsLong(verbose_flag) > 1) { +#endif PySys_WriteStderr("# trying %s\n", QStringToPythonConstCharPointer(test)); + } if (PythonQt::importInterface()->exists(test)) { time_t mtime = 0; int ispackage = zso->type & IS_PACKAGE; @@ -812,14 +818,10 @@ PythonQtImport::getModuleCode(PythonQtImporter *self, const char* fullname, QStr } if (code != nullptr) { modpath = test; -#ifdef PY3K if (isbytecode) { cachemodpath = modpath; modpath = getSourceFilename(modpath); } -#else - Q_UNUSED(cachemodpath) -#endif } return code; } @@ -873,7 +875,6 @@ PyObject* PythonQtImport::getCodeFromPyc(const QString& file) PyDoc_STRVAR(mlabimport_doc, "Imports python files into PythonQt, completely replaces internal python import"); -#ifdef PY3K static struct PyModuleDef PythonQtImport_def = { PyModuleDef_HEAD_INIT, "PythonQtImport", /* m_name */ @@ -885,7 +886,6 @@ static struct PyModuleDef PythonQtImport_def = { nullptr, /* m_clear */ nullptr /* m_free */ }; -#endif void PythonQtImport::init() { @@ -904,7 +904,24 @@ void PythonQtImport::init() mlab_searchorder[0].suffix[0] = SEP; mlab_searchorder[1].suffix[0] = SEP; mlab_searchorder[2].suffix[0] = SEP; - if (Py_OptimizeFlag) { +#if PY_VERSION_HEX < 0x030B0000 // Python < 3.11 + if (Py_OptimizeFlag) { +#else + const bool do_optimize = []() -> bool + { + PyObject* flags = PySys_GetObject("flags"); + if (flags) { + PyObject* optimize = PyObject_GetAttrString(flags, "optimize"); + if (optimize && PyLong_AsLong(optimize) > 0) + { + return true; + } + Py_XDECREF(optimize); + } + return false; + } (); + if (do_optimize) { +#endif /* Reverse *.pyc and *.pyo */ struct st_mlab_searchorder tmp; tmp = mlab_searchorder[0]; @@ -915,12 +932,7 @@ void PythonQtImport::init() mlab_searchorder[4] = tmp; } -#ifdef PY3K mod = PyModule_Create(&PythonQtImport_def); -#else - mod = Py_InitModule4("PythonQtImport", NULL, mlabimport_doc, - NULL, PYTHON_API_VERSION); -#endif PythonQtImportError = PyErr_NewException(const_cast("PythonQtImport.PythonQtImportError"), PyExc_ImportError, nullptr); diff --git a/src/PythonQtInstanceWrapper.cpp b/src/PythonQtInstanceWrapper.cpp index c560810ab..eeee4818b 100644 --- a/src/PythonQtInstanceWrapper.cpp +++ b/src/PythonQtInstanceWrapper.cpp @@ -70,7 +70,11 @@ static void PythonQtInstanceWrapper_deleteObject(PythonQtInstanceWrapper* self, int type = self->classInfo()->metaTypeId(); if (self->_useQMetaTypeDestroy && type>=0) { // use QMetaType to destroy the object - QMetaType::destroy(type, self->_wrappedPtr); +#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) + QMetaType(type).destroy(self->_wrappedPtr); +#else + QMetaType::destroy(type, self->_wrappedPtr); +#endif } else { PythonQtSlotInfo* slot = self->classInfo()->destructor(); if (slot) { @@ -82,7 +86,11 @@ static void PythonQtInstanceWrapper_deleteObject(PythonQtInstanceWrapper* self, } else { if (type>=0) { // use QMetaType to destroy the object +#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) + QMetaType(type).destroy(self->_wrappedPtr); +#else QMetaType::destroy(type, self->_wrappedPtr); +#endif } else { // TODO: warn about not being able to destroy the object? } @@ -390,7 +398,7 @@ static PyObject *PythonQtInstanceWrapper_getattro(PyObject *obj,PyObject *name) if (wrapper->_obj) { // we need to replace the properties with their real values... QStringList l = wrapper->classInfo()->propertyList(); - Q_FOREACH (QString name, l) { + for( QString name : l ) { PyObject* o = PyObject_GetAttrString(obj, QStringToPythonConstCharPointer(name)); if (o) { PyDict_SetItemString(dict, QStringToPythonConstCharPointer(name), o); @@ -401,7 +409,7 @@ static PyObject *PythonQtInstanceWrapper_getattro(PyObject *obj,PyObject *name) } QList dynamicProps = wrapper->_obj->dynamicPropertyNames(); - Q_FOREACH (QByteArray name, dynamicProps) { + for( QByteArray name : dynamicProps ) { PyObject* o = PyObject_GetAttrString(obj, name.data()); if (o) { PyDict_SetItemString(dict, name.data(), o); @@ -482,8 +490,11 @@ static PyObject *PythonQtInstanceWrapper_getattro(PyObject *obj,PyObject *name) switch (member._type) { case PythonQtMemberInfo::Property: if (wrapper->_obj) { +#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) + if (member._property.userType() != QMetaType::UnknownType) { +#else if (member._property.userType() != QVariant::Invalid) { - +#endif PythonQt::ProfilingCB* profilingCB = PythonQt::priv()->profilingCB(); if (profilingCB) { QString methodName = "getProperty('"; @@ -575,11 +586,7 @@ static PyObject *PythonQtInstanceWrapper_getattro(PyObject *obj,PyObject *name) } // look for the internal methods (className(), help()) -#ifdef PY3K PyObject* internalMethod = PyObject_GenericGetAttr(obj, name); -#else - PyObject* internalMethod = Py_FindMethod( PythonQtInstanceWrapper_methods, obj, (char*)attributeName); -#endif if (internalMethod) { return internalMethod; } @@ -762,9 +769,12 @@ static PyObject * PythonQtInstanceWrapper_str(PyObject * obj) PythonQtInstanceWrapper* wrapper = (PythonQtInstanceWrapper*)obj; // QByteArray should be directly returned as a str - if (wrapper->classInfo()->metaTypeId()==QVariant::ByteArray) { +#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) + if (wrapper->classInfo()->metaTypeId() == QMetaType::QByteArray) { +#else + if (wrapper->classInfo()->metaTypeId() == QVariant::ByteArray) { +#endif QByteArray* b = (QByteArray*) wrapper->_wrappedPtr; -#ifdef PY3K // Note: In Python 2, this was used to access the data() of a byte array. // Since in Python 3 str() will return a unicode, this is no longer possible. // The user needs to call .data() to get access to the data as bytes. @@ -776,13 +786,6 @@ static PyObject * PythonQtInstanceWrapper_str(PyObject * obj) } else { return PyUnicode_New(0, 0); } -#else - if (b->data()) { - return PyString_FromStringAndSize(b->data(), b->size()); - } else { - return PyString_FromString(""); - } -#endif } const char* typeName = obj->ob_type->tp_name; @@ -851,9 +854,7 @@ static PyNumberMethods PythonQtInstanceWrapper_as_number = { nullptr, /* nb_add */ nullptr, /* nb_subtract */ nullptr, /* nb_multiply */ -#ifndef PY3K - nullptr, /* nb_divide */ -#endif + nullptr, /* nb_remainder */ nullptr, /* nb_divmod */ nullptr, /* nb_power */ @@ -867,22 +868,15 @@ static PyNumberMethods PythonQtInstanceWrapper_as_number = { nullptr, /* nb_and */ nullptr, /* nb_xor */ nullptr, /* nb_or */ -#ifndef PY3K - nullptr, /* nb_coerce */ -#endif + nullptr, /* nb_int */ nullptr, /* nb_long / nb_reserved in Py3K */ nullptr, /* nb_float */ -#ifndef PY3K - nullptr, /* nb_oct */ - nullptr, /* nb_hex */ -#endif + nullptr, /* nb_inplace_add */ nullptr, /* nb_inplace_subtract */ nullptr, /* nb_inplace_multiply */ -#ifndef PY3K - nullptr, /* nb_inplace_divide */ -#endif + nullptr, /* nb_inplace_remainder */ nullptr, /* nb_inplace_power */ nullptr, /* nb_inplace_lshift */ @@ -894,9 +888,7 @@ static PyNumberMethods PythonQtInstanceWrapper_as_number = { nullptr, /* nb_true_divide */ nullptr, /* nb_inplace_floor_divide */ nullptr, /* nb_inplace_true_divide */ -#ifdef PY3K nullptr, /* nb_index in Py3K */ -#endif }; PyTypeObject PythonQtInstanceWrapper_Type = { @@ -919,11 +911,7 @@ PyTypeObject PythonQtInstanceWrapper_Type = { PythonQtInstanceWrapper_getattro, /*tp_getattro*/ PythonQtInstanceWrapper_setattro, /*tp_setattro*/ nullptr, /*tp_as_buffer*/ - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE -#ifndef PY3K - | Py_TPFLAGS_CHECKTYPES -#endif - , /*tp_flags*/ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/ "PythonQtInstanceWrapper object", /* tp_doc */ nullptr, /* tp_traverse */ nullptr, /* tp_clear */ @@ -931,11 +919,8 @@ PyTypeObject PythonQtInstanceWrapper_Type = { 0, /* tp_weaklistoffset */ nullptr, /* tp_iter */ nullptr, /* tp_iternext */ -#ifdef PY3K - PythonQtInstanceWrapper_methods, -#else - 0, /* tp_methods */ -#endif + PythonQtInstanceWrapper_methods, + nullptr, /* tp_members */ nullptr, /* tp_getset */ nullptr, /* tp_base */ diff --git a/src/PythonQtMethodInfo.cpp b/src/PythonQtMethodInfo.cpp index f428ce5f2..7e9ca6e78 100644 --- a/src/PythonQtMethodInfo.cpp +++ b/src/PythonQtMethodInfo.cpp @@ -62,7 +62,7 @@ PythonQtMethodInfo::PythonQtMethodInfo(const QMetaMethod& meta, PythonQtClassInf fillParameterInfo(type, QByteArray(meta.typeName()), classInfo); _parameters.append(type); QList names = meta.parameterTypes(); - Q_FOREACH (const QByteArray& name, names) { + for( const QByteArray& name : names ) { fillParameterInfo(type, name, classInfo); _parameters.append(type); } @@ -75,7 +75,7 @@ PythonQtMethodInfo::PythonQtMethodInfo(const QByteArray& typeName, const QList= QT_VERSION_CHECK(6, 0, 0) + type.typeId = QMetaType::fromName(name.constData()).id(); +#else type.typeId = QMetaType::type(name.constData()); +#endif #if( QT_VERSION >= QT_VERSION_CHECK(5,0,0) ) if (type.typeId == QMetaType::UnknownType) { #else @@ -234,7 +238,11 @@ int PythonQtMethodInfo::getInnerTemplateMetaType(const QByteArray& typeName) int idx2 = typeName.lastIndexOf(">"); if (idx2 > 0) { QByteArray innerType = typeName.mid(idx + 1, idx2 - idx - 1).trimmed(); +#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) + return QMetaType::fromName(innerType.constData()).id(); +#else return QMetaType::type(innerType.constData()); +#endif } } return QMetaType::Void; @@ -442,7 +450,11 @@ const PythonQtMethodInfo::ParameterInfo& PythonQtMethodInfo::getParameterInfoFor return it.value(); } ParameterInfo info; - fillParameterInfo(info, QMetaType::typeName(type)); +#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) + fillParameterInfo(info, QMetaType(type).name()); +#else + fillParameterInfo(info, QMetaType::typeName(type)); +#endif _cachedParameterInfos.insert(type, info); return _cachedParameterInfos[type]; } @@ -622,7 +634,7 @@ QStringList PythonQtSlotInfo::overloads(bool skipReturnValue) const } if (slotsWithSameArgs.size() > 1) { results << maxArgSlot->fullSignature(skipReturnValue, minSameArgs); - foreach(const PythonQtSlotInfo* o, slotsWithSameArgs) { + for(const PythonQtSlotInfo* o : slotsWithSameArgs) { list.removeOne(o); } } else { diff --git a/src/PythonQtMisc.h b/src/PythonQtMisc.h index c13eddee1..db79907fa 100644 --- a/src/PythonQtMisc.h +++ b/src/PythonQtMisc.h @@ -75,7 +75,7 @@ #else #define PythonQtArgumentFrame_ADD_VARIANT_VALUE_BY_ID(store, id, ptr) \ - PythonQtArgumentFrame_ADD_VARIANT_VALUE(store, QVariant::Type(id), ptr) + PythonQtArgumentFrame_ADD_VARIANT_VALUE(store, QMetaType::Type(id), ptr) #endif @@ -94,7 +94,7 @@ #else #define PythonQtArgumentFrame_ADD_VARIANT_VALUE_BY_ID_IF_NEEDED(alreadyAllocatedPtr,store, id, ptr) \ - PythonQtArgumentFrame_ADD_VARIANT_VALUE_IF_NEEDED(alreadyAllocatedPtr,store, QVariant::Type(id), ptr) + PythonQtArgumentFrame_ADD_VARIANT_VALUE_IF_NEEDED(alreadyAllocatedPtr,store, QMetaType::Type(id), ptr) #endif diff --git a/src/PythonQtSignal.cpp b/src/PythonQtSignal.cpp index 04e19fee2..3d9a42b9d 100644 --- a/src/PythonQtSignal.cpp +++ b/src/PythonQtSignal.cpp @@ -151,13 +151,6 @@ static PyObject * meth_get__self__(PythonQtSignalFunctionObject *m, void * /*closure*/) { PyObject *self; -#ifndef PY3K - if (PyEval_GetRestricted()) { - PyErr_SetString(PyExc_RuntimeError, - "method.__self__ not accessible in restricted mode"); - return NULL; - } -#endif self = m->m_self; if (self == nullptr) self = Py_None; @@ -410,11 +403,7 @@ PyTypeObject PythonQtSignalFunction_Type = { 0, /* tp_vectorcall_offset */ nullptr, /* tp_getattr */ nullptr, /* tp_setattr */ -#ifdef PY3K nullptr, -#else - (cmpfunc)meth_compare, /* tp_compare */ -#endif (reprfunc)meth_repr, /* tp_repr */ nullptr, /* tp_as_number */ nullptr, /* tp_as_sequence */ diff --git a/src/PythonQtSignalReceiver.cpp b/src/PythonQtSignalReceiver.cpp index d2a04efea..61629fcc8 100644 --- a/src/PythonQtSignalReceiver.cpp +++ b/src/PythonQtSignalReceiver.cpp @@ -266,7 +266,7 @@ int PythonQtSignalReceiver::qt_metacall(QMetaObject::Call c, int id, void **argu } bool shouldDelete = false; - for(const PythonQtSignalTarget& t : qAsConst(_targets)) { + for(const PythonQtSignalTarget& t : std::as_const(_targets)) { if (t.slotId() == id) { const int sigId = t.signalId(); t.call(arguments); diff --git a/src/PythonQtSlot.cpp b/src/PythonQtSlot.cpp index 084df8706..8dfcbcfd7 100644 --- a/src/PythonQtSlot.cpp +++ b/src/PythonQtSlot.cpp @@ -553,7 +553,7 @@ meth_get__doc__(PythonQtSlotFunctionObject * m, void * /*closure*/) } else if (returnType.startsWith("QHash<") || returnType.startsWith("QMap<") || returnType == "QVariantMap" || returnType == "QVariantHash") { pyReturnType = "dict"; - } else if (returnTypeId == QVariant::Bool) { + } else if (returnTypeId == QMetaType::Bool) { pyReturnType = "bool"; } else if (returnTypeId == PythonQtMethodInfo::Variant) { pyReturnType = "object"; @@ -609,13 +609,6 @@ static PyObject * meth_get__self__(PythonQtSlotFunctionObject *m, void * /*closure*/) { PyObject *self; -#ifndef PY3K - if (PyEval_GetRestricted()) { - PyErr_SetString(PyExc_RuntimeError, - "method.__self__ not accessible in restricted mode"); - return NULL; - } -#endif self = m->m_self; if (self == nullptr) self = Py_None; @@ -828,11 +821,7 @@ PyTypeObject PythonQtSlotFunction_Type = { 0, /* tp_vectorcall_offset */ nullptr, /* tp_getattr */ nullptr, /* tp_setattr */ -#ifdef PY3K nullptr, -#else - (cmpfunc)meth_compare, /* tp_compare */ -#endif (reprfunc)meth_repr, /* tp_repr */ nullptr, /* tp_as_number */ nullptr, /* tp_as_sequence */ diff --git a/src/PythonQtStdOut.cpp b/src/PythonQtStdOut.cpp index 4069bd8ea..1c3dac450 100644 --- a/src/PythonQtStdOut.cpp +++ b/src/PythonQtStdOut.cpp @@ -61,27 +61,13 @@ static PyObject *PythonQtStdOutRedirect_write(PyObject *self, PyObject *args) if (PyTuple_GET_SIZE(args)>=1) { PyObject* obj = PyTuple_GET_ITEM(args,0); if (PyUnicode_Check(obj)) { -#ifdef PY3K output = QString::fromUtf8(PyUnicode_AsUTF8(obj)); -#else - PyObject *tmp = PyUnicode_AsUTF8String(obj); - if(tmp) { - output = QString::fromUtf8(PyString_AS_STRING(tmp)); - Py_DECREF(tmp); - } else { - return NULL; - } -#endif } else { char *string; if (!PyArg_ParseTuple(args, "s", &string)) { return nullptr; } -#ifdef PY3K output = QString::fromUtf8(string); -#else - output = QString::fromLatin1(string); -#endif } } diff --git a/src/PythonQtSystem.h b/src/PythonQtSystem.h index d49345eeb..dc0bfd0e6 100644 --- a/src/PythonQtSystem.h +++ b/src/PythonQtSystem.h @@ -42,21 +42,17 @@ */ //---------------------------------------------------------------------------------- +#include -#if defined(WIN32) - #ifdef PYTHONQT_EXPORTS - #define PYTHONQT_EXPORT __declspec(dllexport) - #else - #define PYTHONQT_EXPORT __declspec(dllimport) - #endif +#ifndef PYTHONQT_STATIC +# if defined(PYTHONQT_EXPORTS) +# define PYTHONQT_EXPORT Q_DECL_EXPORT +# else +# define PYTHONQT_EXPORT Q_DECL_IMPORT +# endif #else - #ifdef PYTHONQT_EXPORTS - #define PYTHONQT_EXPORT __attribute__((__visibility__("default"))) - #else - #define PYTHONQT_EXPORT - #endif +# define PYTHONQT_EXPORT #endif - #endif diff --git a/src/PythonQtUtils.h b/src/PythonQtUtils.h index 50692d47b..90d90b789 100644 --- a/src/PythonQtUtils.h +++ b/src/PythonQtUtils.h @@ -84,12 +84,7 @@ namespace PythonQtUtils //! Returns of the python object is a class type inline bool isPythonClassType(PyObject* obj) { -#ifdef PY3K return PyType_Check(obj); -#else - // support old-style classes and new style classes - return (obj->ob_type == &PyClass_Type || obj->ob_type == &PyType_Type); -#endif } } diff --git a/src/gui/PythonQtScriptingConsole.cpp b/src/gui/PythonQtScriptingConsole.cpp index 6e2218454..3fc5030cb 100644 --- a/src/gui/PythonQtScriptingConsole.cpp +++ b/src/gui/PythonQtScriptingConsole.cpp @@ -300,7 +300,7 @@ void PythonQtScriptingConsole::handleTabCompletion() compareText = compareText.toLower(); QStringList found; QStringList l = PythonQt::self()->introspection(_context, lookup, PythonQt::Anything); - Q_FOREACH (QString n, l) { + for( QString n : l ) { if (n.toLower().startsWith(compareText)) { found << n; } diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt new file mode 100644 index 000000000..aa42f672c --- /dev/null +++ b/tests/CMakeLists.txt @@ -0,0 +1,35 @@ +project(PythonQtTest LANGUAGES CXX) + +set(CMAKE_AUTOMOC ON) + +find_package(Qt${QT_VERSION_MAJOR} COMPONENTS Core Widgets Test REQUIRED) + +file(GLOB SOURCES *.h *.cpp) + +add_executable(${PROJECT_NAME}) + +target_sources(${PROJECT_NAME} PRIVATE + ${SOURCES} +) + +target_link_libraries(${PROJECT_NAME} PRIVATE + Qt${QT_VERSION_MAJOR}::Widgets + Qt${QT_VERSION_MAJOR}::Test + Core + QtAll +) + +add_test(NAME ${PROJECT_NAME} + COMMAND $ + WORKING_DIRECTORY $ +) + +if(WIN32) + set(LIBRARY_SEARCH_PATH PATH) +else() + set(LIBRARY_SEARCH_PATH LD_LIBRARY_PATH) +endif() + +set_tests_properties(${PROJECT_NAME} PROPERTIES + ENVIRONMENT_MODIFICATION "${LIBRARY_SEARCH_PATH}=path_list_prepend:$" +) diff --git a/tests/PythonQtTests.cpp b/tests/PythonQtTests.cpp index bd440812a..f4b34ffa5 100644 --- a/tests/PythonQtTests.cpp +++ b/tests/PythonQtTests.cpp @@ -567,7 +567,7 @@ void PythonQtTestApi::testVariables() QSet s; // check that at least these three variables are set s << "obj" << "someObject" << "someValue"; - Q_FOREACH (QString value, s) { + for( QString value : s ) { QVERIFY(l.indexOf(value)!=-1); }