Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Type Hinting and Type Checking for IntEnum custom types

Qt has several IntEnum's that support custom , user-specified types or roles. A few examples are:

  • QtCore.Qt.ItemDataRole.UserRole
  • QtCore.QEvent.Type.User

In both cases, a user type/role is created by choosing an integer >= the User type/role

myType = QtCore.QEvent.Type.User + 1

The problem is that all of the functions that deal with these type/roles expect an instance of the IntEnum, not an int, and mypy will report an error.

from PySide6.QtCore import QEvent

class MyEvent(QEvent):

    def __init__(self) -> None:
        super().__init__(QEvent.Type.User + 1)

Mypy error:

No overload variant of "__init__" of "QEvent" matches argument type "int"

Integrated type checking in VS code with Pylance gives a similar error:

No overloads for "__init__" match the provided arguments PylancereportCallIssue
QtCore.pyi(2756, 9): Overload 2 is the closest match
Argument of type "int" cannot be assigned to parameter "type" of type "Type" in function "__init__"
  "int" is not assignable to "Type" PylancereportArgumentType

What type hinting can I do from my end to satisfy mypy? Is this something that needs to be changed in Qt type hinting?

like image 474
Brendan Abel Avatar asked Jan 26 '26 21:01

Brendan Abel


1 Answers

In PySide6/PyQt6, the type of a user-defined int enum member should be preserved by using the constructor of the enum:

from PySide6.QtCore import QEvent

class MyEvent(QEvent):
    def __init__(self) -> None:
        super().__init__(QEvent.Type(QEvent.Type.User + 1))

Assuming the latest PySide6 stubs are installed, a file with the above contents will produce no errors when checked with the mypy command-line tool.

NB: the implementation defines _missing_ to handle unknown members, and this works for all enums that subclass IntEnum, regardless of whether the values make any sense:

>>> QEvent.Type.User
<Type.User: 1000>
>>> QEvent.Type(QEvent.Type.User + 1)
<Type.1001: 1001>
>>> QEvent.Type.MaxUser
<Type.MaxUser: 65535>
>>> QEvent.Type(QEvent.Type.MaxUser + 10)
<Type.65545: 65545>
>>>
>>> QFrame.Shape.__members__
mappingproxy({'NoFrame': <Shape.NoFrame: 0>, 'Box': <Shape.Box: 1>, 'Panel': <Shape.Panel: 2>, 'WinPanel': <Shape.WinPanel: 3>, 'HLine': <Shape.HLine: 4>, 'VLine': <Shape.VLine: 5>, 'StyledPanel': <Shape.StyledPanel: 6>})
>>> QFrame.Shape(42)
<Shape.42: 42>
like image 112
ekhumoro Avatar answered Jan 28 '26 11:01

ekhumoro