Suprising enum difference in PyQt 6 from PyQt 5

Phil Thompson phil at riverbankcomputing.com
Sun Apr 17 13:01:25 BST 2022


On 16/04/2022 18:38, Florian Bruhin wrote:
> Hi,
> 
> On Tue, Apr 12, 2022 at 07:02:19PM -0700, Greg Couch wrote:
>> So I have a QTreeWidgetItem, and in PyQt 5, I was able to use:
>> 
>> > if item.checkState(0):
>> to check if the item was checked or not.  The return value is a
>> QtCore.Qt.CheckState enum.   That fails in PyQt 6 because
>> QtCore.Qt.CheckState.Unchecked evaluates as True.  If 
>> QtCore.Qt.CheckState
>> were changed to subclass from enum.IntEnum, instead of enum.Enum, this 
>> would
>> not be a porting problem.
> 
> I see similar issues in other boolean-but-not-quite enums.
> 
> With PyQt 5:
> 
>     >>> full_match = QKeySequence.fromString("a,
> b").matches(QKeySequence.fromString("a, b"))
>     >>> partial_match =
> QKeySequence.fromString("a").matches(QKeySequence.fromString("a, b"))
>     >>> no_match =
> QKeySequence.fromString("x").matches(QKeySequence.fromString("a, b"))
>     >>> full_match, partial_match, no_match
>     (2, 1, 0)
>     >>> bool(full_match), bool(partial_match), bool(no_match)
>     (True, True, False)
> 
> but PyQt 6:
> 
>     >>> full_match, partial_match, no_match
>     (<SequenceMatch.ExactMatch: 2>, <SequenceMatch.PartialMatch: 1>,
> <SequenceMatch.NoMatch: 0>)
>     >>> bool(full_match), bool(partial_match), bool(no_match)
>     (True, True, True)
> 
> so a "if seq.matches(other):" now silently is true even for
> QKeySequence.SequenceMatch.PartialMatch.
> 
> I'm not sure if "just make it an IntEnum" is a suitable fix. I like the
> idea of having a strict separation between ints and enums, and a match
> (or a check state) clearly isn't a number (that's just an 
> implementation
> detail of old-style C++ enums essentially).

Agreed.

> I also think it would be good to be explicit about this matching in
> code: Should a PartialMatch be true or false?. Or in your case, should
> partially checked really count as checked?

Agreed. I tend to use 'is' when testing the value of enums rather than 
'=='. Also 'in' a tuple of multiple values.

> However, this is tricky, as it's a slient breakage, and those are 
> rather
> hard to spot... Maybe those kind of enums shuold instead have some
> annotation in the .sip file which overrides their __bool__ to raise a
> TypeError instead?

Wouldn't it apply to all enums that sub-class Enum (rather than 
IntEnum)? It surprises me that this isn't the default behaviour.

I'm happy to consider adding such a __bool__ method, however doing so 
departs from standard Python behaviour and the main motivation for 
moving to using Python enums in PyQt6 was to make it more Pythonic.

Phil


More information about the PyQt mailing list