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