PyQt6: QEvent.type() returns int instead of QEvent.Type
Phil Thompson
phil at riverbankcomputing.com
Wed Apr 27 15:58:22 BST 2022
On 26/04/2022 20:49, Florian Bruhin wrote:
> On Tue, Apr 26, 2022 at 09:36:25PM +0200, Florian Bruhin wrote:
>> On Tue, Apr 26, 2022 at 09:19:05AM +0100, Phil Thompson wrote:
>> >
>> > On 21/04/2022 10:37, Florian Bruhin wrote:
>> > > Hey,
>> > >
>> > > With PyQt5:
>> > >
>> > > >>> evtype = QEvent(QEvent.Type.User).type()
>> > > >>> evtype
>> > > 1000
>> > > >>> type(evtype)
>> > > <class 'PyQt5.QtCore.QEvent.Type'>
>> > >
>> > > and even:
>> > >
>> > > >>> evtype = QEvent(QEvent.Type.User + 1).type()
>> > > >>> evtype
>> > > 1001
>> > > >>> type(evtype)
>> > > <class 'PyQt5.QtCore.QEvent.Type'>
>> > >
>> > > but with PyQt6, the type information gets lost:
>> > >
>> > > >>> evtype = QEvent(QEvent.Type.User).type()
>> > > >>> evtype
>> > > 1000
>> > > >>> type(evtype)
>> > > <class 'int'>
>> > >
>> > > From what I understand, it's not possible to convert arbitrary values
>> > > into an IntEnum:
>> > >
>> > > >>> QEvent.Type(QEvent.Type.User + 1)
>> > > [...]
>> > > ValueError: 1001 is not a valid QEvent.Type
>> > >
>> > > But least for types which are part of QEvent.Type, calling .type()
>> > > should perhaps return the IntEnum value again instead of falling back to
>> > > an int without any type information? Given that IntEnum is an int
>> > > subclass, this should be a backwards-compatible change too.
>> >
>> > I've been adopting a piecemeal approach to this sort of thing so far. For
>> > example having QEvent.type() return an int and adding an extra QEvent ctor
>> > that accepts an int, and similar with gesture types. However the issue you
>> > point out in your other email (new enum members in later versions of Qt) is
>> > something I hadn't considered.
>> >
>> > I think the solution is to take the approach you suggest above and apply it
>> > to all enums (no matter what their base type is). In other words, when
>> > converting from Python to a C++ enum both a Python enum and an int will be
>> > accepted. When converting from a C++ enum to Python then the corresponding
>> > enum member will be returned or an int if there is no such member.
>> >
>> > This would mean that there is no need for me to apply special treatment to
>> > individual methods (as the change is implemented in the sip module) and the
>> > approach should be future-proof.
>> >
>> > Thoughts?
>>
>> Hm, I don't really like the lost type safety when accepting ints.
>> However, at the same time I can't think of a proper way to solve the
>> "new enum members" problem.
>>
>> I tried coercing Python into having some kind of special
>> SomeEnum.missing(42) value instead, which acts like a member of the
>> enum, but can also hold an arbitrary value. enum.py sure is some crazy
>> black magic. I bet it would be possible somehow (custom enum metaclass
>> defining __instancecheck__ perhaps?), but at this point there is so
>> much
>> black magic involved I'm not sure it would be a better solution.
>
> I spoke too soon, here is something that seems to work, somehow.
> The point about "probably too much black magic" still stands, though.
Nice. The obvious problem is the knowledge of the enum internals.
IntFlags seems to work as you would want - it creates a pseudo-member
for any flags it doesn't recognise. It's a shame that IntEnum doesn't do
the same.
I'm still favouring the int approach. I can't think of a case that code
would start to break when a newer version of Qt was used with an older
PyQt (which is the main problem).
Phil
More information about the PyQt
mailing list