[PyQt] Inconsistent handling of QFlags?

Shaheed Haque srhaque at theiet.org
Tue Aug 8 22:15:28 BST 2017

On 8 August 2017 at 16:46, Phil Thompson <phil at riverbankcomputing.com> wrote:
> On 30 Jul 2017, at 7:13 pm, Shaheed Haque <srhaque at theiet.org> wrote:
>> Hi,
>> I'd like to understand the rules about how function arguments are
>> encoded by SIP. For example, I have these two uses of QFlags in one
>> module:
>> ==============
>>        void setCompatibility(QFlags<KAlarmCal::KACalendar::Compatibility>c)
>>            [void (QFlags<KAlarmCal::KACalendar::Compatibility> c)];
>>        void set(const KDateTime &dt, const QString &text, const
>> QColor &bg, const QColor &fg, const QFont &font,
>> KAlarmCal::KAEvent::SubAction action, int lateCancel,
>> QFlags<KAlarmCal::KAEvent::Flag>flags, bool changesPending = false)
>>            [void (const KDateTime &dt, const QString &text, const
>> QColor &bg, const QColor &fg, const QFont &font,
>> KAlarmCal::KAEvent::SubAction action, int lateCancel,
>> QFlags<KAlarmCal::KAEvent::Flag> flags, bool changesPending = false)];
>> ===============
>> Both have %MethodCode as needed. Also, in case it is relevant, the
>> second (problematic) method also has this overload:
>>        void set(KCalCore::Event *__0)
>>            [void (const QSharedPointer<KCalCore::Event> &__0)];
>> In the first case, the QFlags-based argument a0 is declared as a plain
>> QFlags value and passed as follows:
>> ===============
>>        QFlags<KAlarmCal::KACalendar::Compatibility> a0;
>>        ...
>>        if (sipParseArgs(&sipParseErr, sipArgs, "B", &sipSelf,
>> sipType_KAlarmCal_KAEvent, &sipCpp))
>> ===============
>> In the second case, SIP generate a pointer-to-a-typedef-to-QFlags for
>> a7 like this:
>> ===============
>>        const  ::KDateTime* a0;
>>        const  ::QString* a1;
>>        int a1State = 0;
>>        const  ::QColor* a2;
>>        int a2State = 0;
>>        const  ::QColor* a3;
>>        int a3State = 0;
>>        const  ::QFont* a4;
>>         ::KAlarmCal::KAEvent::SubAction a5;
>>        int a6;
>>         ::KAlarmCal::KAEvent::Flags* a7;
>>        int a7State = 0;
>>        bool a8 = 0;
>>         ::KAlarmCal::KAEvent *sipCpp;
>>        if (sipParseArgs(&sipParseErr, sipArgs, "BJ9J1J1J1J9EiJ1|b",
>> &sipSelf, sipType_KAlarmCal_KAEvent, &sipCpp, sipType_KDateTime, &a0,
>> sipType_QString,&a1, &a1State, sipType_QColor, &a2, &a2State,
>> sipType_QColor, &a3, &a3State, sipType_QFont, &a4,
>> sipType_KAlarmCal_KAEvent_SubAction, &a5, &a6,
>> sipType_KAlarmCal_KAEvent_Flags, &a7, &a7State, &a8))
>> ===============
>> Now it turns out that thee in indeed a typedef of the form of a7 in
>> place, but it does not introduce a pointer "typedef
>> QFlags<KAlarmCal::KAEvent::Flag> Flags;". And in any case, that's not
>> what I wrote into the function definition given to SIP.
>> So why does this second case (a) use the typedef and (b) introduce the
>> "*"? The only difference I can see is that the enum inside the QFlags
>> in the first case does not have a definition in SIP (it is only in the
>> .h file) whereas the enum in the second case does have a SIP
>> definition, though it seems counter-intuitive that would change the
>> way QFlags is handled.
>> Any clues welcome.
> SIP can't handle template arguments in a Python signature and so asks you to provide %MethodCode and a C++ signature. However you also need to replace the template argument type with something that is valid in a Python signature. In the current version of SIP it then (wrongly) ignores that argument when generating the argument parser. Tonight's snapshot will be fixed so that it is treated as a fatal error.
> Applying this to your two examples, the first one will now trigger an error. The second one will continue to work as now. Even though it still has a template argument, SIP knows (because of the typedef) how to convert it to a valid Python type. Therefore (unless there is another reason for it) there is no need to provide a separate C++ signature and %MethodCode.

Sounds fair. I'll ponder on what to do...

> Phil

More information about the PyQt mailing list