Details
Description
As part of our build process for our Python bindings, a custom script creates a .pyi file for our module. Part of this is invoking PySide2.support.signature.lib.enum_sig.HintingEnumerator(formatter).module(module_name) with the name of our module as argument.
Since our update to v5.15.2, this call raises a SystemError with the error message being implement enum instances at module level.
The error is caused by four enums in a bog-standard C++ header file. I cannot share the complete file, but I've included a shortened version that includes examples of everything included to be an accurate representation. You'll find the enums close to the bottom.
#ifndef DEFAULTS_H #define DEFAULTS_H #include <QList> class QString; class QBitArray; class QVariant; class QByteArray; typedef QList<QByteArray> ArrayList; #define PING_PERIOD 120000 #define DEFAULT_DOMAIN "client.tld" #define DEFAULT_SYSAP_NAME "foo" #define DEFAULT_LANGUAGE "en" #define MAX_STRING_SIZE_IN_BYTE 51 //!< without terminating symbol #define ELLIPSIS_CHARACTER 0x2026 //!< three dots as one symbol in utf-8 #define RF_AUTO_UPDATE_SOFTWARE_ID (0x0253U) #define RF_BATTERY_AUTO_UPDATE_SOFTWARE_ID (0x0A7F) #define RF_JABIL_AUTO_UPDATE_KEYPAD_SOFTWARE_ID (0x0D07U) #define RF_JABIL_AUTO_UPDATE_RTC_SOFTWARE_ID (0x0106FU) #ifndef SOFTWARE_VERSION #define SOFTWARE_VERSION "2.4.0" #endif #ifndef BUILD_REVISION #define BUILD_REVISION "1" #endif const int EMULATED_DEVICE_FILE_VERSION = 1; #define EMULATED_DEVICE_FILE_MAGIC "EDEV" const int PROJECT_DATA_VERSION = 2; #define RF_DEFAULT_HEARTBEAT_INTERVAL (5 * 60) #define RF_NORMAL_HEARTBEAT_INTERVAL (10 * 60) #define RF_UPDATE_HEARTBEAT_INTERVAL (60 * 60) #define RF_MINUMUM_HEARTBEAT_INTERVAL (60) #define TASK_SUCCESS 0 #define TASK_ERROR 1 #define TASK_TIMEOUT 2 #define TASK_XMLERROR 3 #define TASK_SUPERFLUOUS 4 #define TASK_SUCCESS_REBOOT 5 #define TASK_TRY_AGAIN 6 #define TASK_NEED_UPDATE 7 #define TASK_REALLY_DEFECT 8 #define SIZE_AS_STRING(A) (QString("size:")+QString::number((A).size())) #if QT_VERSION < QT_VERSION_CHECK(5, 1, 0) #define MANUFACTURER_FROM_SERIALNR(S, OK) \ (ushort)((S).left(4).toUInt(&(OK), 16)) #define PRODUCTIONNR_FROM_SERIALNR(S, OK) \ (uint)((S).right(8).toUInt(&(OK), 16)) #else #define MANUFACTURER_FROM_SERIALNR(S, OK) \ (ushort)((S).leftRef(4).toUInt(&(OK), 16)) #define PRODUCTIONNR_FROM_SERIALNR(S, OK) \ (uint)((S).rightRef(8).toUInt(&(OK), 16)) #endif enum UartTransportMode{ LL_MODE, LTL_MODE, APL_MODE }; enum UartPriority { UART_PRIORITY_HIGH, UART_PRIORITY_LOW, UART_PRIORITY_SYSTEM }; enum UserPermissions { up_invalid = 0, up_vbus = (1U << 0), up_timer = (1U << 1), up_monitor = (1U << 2), up_setdp = (1U << 3), up_config = (1U << 4), up_action = (1U << 5), up_myclient = (1U << 6), up_network = (1U << 7), up_users = (1U << 8), up_safety = (1U << 9), up_install = (1U << 10), up_hasChanged = (1U << 31) }; /* tx power tables channel 11 to 26 */ #define TX_POWERTABLE_DEFAULT "09 09 09 09 09 09 09 09 09 09 09 09 09 09 09 09" #define TX_POWERTABLE_USA "00 00 00 00 00 00 00 00 00 00 00 00 00 00 07 0C" #define INVALID_DEPENDENCY_INDEX static_cast<unsigned short>(0xFFFFu) /* LED palette indices - the actual color definitions are in system/Led.cpp, colorPalette */ enum class LedColor : quint8 { Black = 0, Red, Green, Blue, Orange, Cyan, Purple, White, _NumEntries }; constexpr LedColor ACCESS_COLOR_REMOVABLE_MEDIA = LedColor::Green; // datapoint direction indicator for better readability than a random "true" or "false" in a call enum class DPDirection { Input, Output }; #endif // DEFAULTS_H
Our code defines heaps of other enums, none of which cause an error. However, these five seem to be the only ones to not be defined inside any namespace.
Removing these enums from our typesystem rids us of the error, but is not an acceptable workaround. The relevant excerpt from the typesystem:
<!-- sublib/sublibcommon/defines.h --> <enum-type name="UartTransportMode"/> <enum-type name="UartPriority"/> <enum-type name="UserPermissions"/> <enum-type name="LedColor"/> <enum-type name="DPDirection"/>
For reference, here is the important bit of the custom script:
def main(): args = parseCmdLineArgs() if args.add_ld_library_path and not args.internal: add_ld_library_paths(args) module_name = "fooBindings" tmp_out_file = args.out + ".tmp" temporary_dir = None try: with open(tmp_out_file, "w") as outfile: outfile.write("# -*- coding: utf-8 -*-\n") outfile.write("\n") outfile.write("# WARNING: This file is auto-generated, all modifications will be overwritten\n") outfile.write("\n") outfile.write("import PySide2\n") outfile.write("import PySide2.QtCore\n") outfile.write("import shiboken2 as Shiboken\n") outfile.write("import typing\n") formatter = Formatter(outfile=outfile) temporary_dir = tempfile.mkdtemp(dir=args.input_dir) library_dir = temporary_dir bindings_path = os.path.join(temporary_dir, 'fooBindings.so') if platform.system() == 'Darwin': addLocalRpathToPythonBindings(input_path=os.path.join(args.input_dir, 'fooBindings.so'), output_path=bindings_path) else: shutil.copyfile(os.path.join(args.input_dir, 'fooBindings.so'), bindings_path) # Force importing from --input-dir, not from an installed location, otherwise we may catch # an old file. # NOTE: This must occur AFTER all import statements, but BEFORE the call to module() before, # which imports the specified module (only) orig_sys_path = sys.path sys.path = [library_dir] PySide2.support.signature.lib.enum_sig.HintingEnumerator(formatter).module(module_name) sys.path = orig_sys_path outfile.write("\n") finally: if temporary_dir: shutil.rmtree(temporary_dir) if not os.path.exists(args.out) or not filecmp.cmp(args.out, tmp_out_file): if os.path.exists(args.out): os.remove(args.out) os.rename(tmp_out_file, args.out) else: os.remove(tmp_out_file)
add_ld_library_paths and addLocalRpathToPythonBindings are helpers to add necessary information into the binary and shouldn't be of relevance. If you do need them, tell me. The Formatter class mentioned is also part of this script, same deal.
Attachments
For Gerrit Dashboard: PYSIDE-1519 | ||||||
---|---|---|---|---|---|---|
# | Subject | Branch | Project | Status | CR | V |
339698,2 | enum: implement enums on module level | dev | pyside/pyside-setup | Status: MERGED | +2 | 0 |
339727,3 | enum: implement enums on module level | tqtc/lts-5.15 | pyside/tqtc-pyside-setup | Status: MERGED | +2 | 0 |
341000,1 | enum: implement enums on module level | tqtc/lts-5.15 | pyside/tqtc-pyside-setup | Status: ABANDONED | +2 | 0 |