Closed 17Reset closed 1 month ago
This is very unlikely to be a bug in pyright. It's probably a bug in the library or type stubs you're using. I'd be happy to help you diagnose if further if you'd provide a self-contained code sample that demonstrates the problem you're seeing. The code sample you've posted above refers to a bunch of symbols that are not defined and are not builtins.
I'm going to close the issue since it's probably not a bug, but feel free to post additional details, and I'll help you diagnose the problem.
This is a minimal example of the source code:
import sys
from PyQt6.QtWidgets import QApplication
from PyQt6.QtCore import Qt
from PyQt6.QtWidgets import QWidget, QTabWidget
class Compiler(QWidget):
def __init__(self, parent=None):
super().__init__(parent)
self.canvas_tabwidget = QTabWidget(self)
if self.canvas_tabwidget.tabBar() is not None:
self.canvas_tabwidget.tabBar().setContextMenuPolicy(
Qt.ContextMenuPolicy.NoContextMenu
)
if __name__ == '__main__':
app = QApplication(sys.argv)
window = Compiler()
window.show()
sys.exit(app.exec())
Here is the use of Pyright and the results:
C:\Users\xlab>pyright D:\Job\Programming\python\xTest\xPyQt6\pyright_demo\demo1.py
d:\Job\Programming\python\xTest\xPyQt6\pyright_demo\demo1.py
d:\Job\Programming\python\xTest\xPyQt6\pyright_demo\demo1.py:14:44 - error: "setContextMenuPolicy" is not a known attribute of "None" (reportOptionalMemberAccess)
1 error, 0 warnings, 0 informations
Add a line to print out the object:
import sys
from PyQt6.QtWidgets import QApplication
from PyQt6.QtCore import Qt
from PyQt6.QtWidgets import QWidget, QTabWidget
class Compiler(QWidget):
def __init__(self, parent=None):
super().__init__(parent)
self.canvas_tabwidget = QTabWidget(self)
if self.canvas_tabwidget.tabBar() is not None:
print(self.canvas_tabwidget.tabBar())
self.canvas_tabwidget.tabBar().setContextMenuPolicy(
Qt.ContextMenuPolicy.NoContextMenu
)
if __name__ == '__main__':
app = QApplication(sys.argv)
window = Compiler()
window.show()
sys.exit(app.exec())
result
<PyQt6.QtWidgets.QTabBar object at 0x000001B809C79270>
The problem is that the tabBar
method returns a value of type QTabBar | None
. Type checkers cannot assume that calling a method twice will return the same value, so the check you're doing in the if
statement has no bearing on the type returned by the second call to the same method. If you want this to type check without errors, you should assign the value to a variable and use that value in both the test and the subsequent dereference.
class Compiler(QWidget):
def __init__(self, parent=None):
super().__init__(parent)
self.canvas_tabwidget = QTabWidget(self)
tab_bar = self.canvas_tabwidget.tabBar()
if tab_bar is not None:
tab_bar.setContextMenuPolicy(Qt.ContextMenuPolicy.NoContextMenu)
Doesn't that make the code redundant?
I think this is not the best way to design PyQt6 code, for the above example, QTabWidget
call method tabBar()
, is sure to return a QTabBar
object, can't be None
, so this detection is meaningless.
The code has been modified to add a type judgement if statement, why does pyright still detect the error?
Source Code:
pyright detection error: