I had tried the abc.ABCMeta with sip wrapper type, and it works well when subclass with abc.ABC.
class QABCMeta(wrappertype, ABCMeta):
pass
class WidgetBase(QWidget, metaclass=QABCMeta):
...
class InterfaceWidget(WidgetBase, ABC):
...
class MainWidget(InterfaceWidget):
...
But it is not works on typing.Generic.
class QGenericMeta(wrappertype, GenericMeta):
pass
class WidgetBase(QWidget, Generic[T], metaclass=QGenericMeta):
...
class GenericWidget(WidgetBase[float]):
...
It raised:
line 980, in __new__
self if not origin else origin._gorg)
TypeError: can't apply this __setattr__ to sip.wrappertype object
I expected it to use generic subclass as usual:
class TableBase(QTableWidget, Generic[T]):
@abstractmethod
def raw_item(self, row: int) -> T:
...
def data(self) -> Iterator[T]:
yield from (self.raw_item(row) for row in range(self.rowCount()))
class MainTable(TableBase[float]):
def raw_item(self, row: int) -> float:
return float(self.item(row, 1).text()) # implementation
table = MainTable()
for data in table.data():
data: float
But the data is still Any when without inherit Generic[T].
Can it solved with PEP 560 to do type checking?
Well, I found the answer.
Since the metaclass of typing.Generic is abc.ABC, it should based on abc.ABCMeta too. But this is only works with Python 3.7 or above.
And then, just use type(QObject) instead of sip.wrappertype:
# -*- coding: utf-8 -*-
from abc import abstractmethod, ABC, ABCMeta
from typing import TypeVar, Generic, Iterator
from PyQt5.QtCore import QObject
from PyQt5.QtWidgets import QTableWidget
QObjectType = type(QObject)
T = TypeVar('T')
class QABCMeta(QObjectType, ABCMeta):
pass
class BaseWidget(QTableWidget, Generic[T], metaclass=QABCMeta):
@abstractmethod
def raw_item(self, row: int) -> T:
...
def data(self) -> Iterator[T]:
yield from (self.raw_item(row) for row in range(self.rowCount()))
class TestWidget(BaseWidget[float], ABC): # optional inherit ABC.
def raw_item(self, row: int) -> float:
return float(self.item(row, 1).text())
if __name__ == '__main__':
w = TestWidget()
for f in w.data():
pass
This code is works for PyCharm IDE, the annotation of variable f is float.
When change PyQt5 to PySide2, it also works!
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With