Search code examples
pythonqtpython-typingpyside6pyright

Pylance complaining on self.tr() method


I'm developing an application with PySide6 6.6.2 and Python 3.11.8. Everything is working fine and mypy is happy. However, as I demonstrated on the following image, Pylance (on VSCode) keeps complaining that self.tr() cannot be accessed, though it actually should be acessible for any QtCore.QObject (and hence, QtWidgets.QWidget). In fact, the application runs with no errors and pyside6-lupdate or pyside6-lrelease are happy too.

Pylance complaining: "Cannot access member 'tr' for type 'TestWidget*'. Member 'tr' is unknown.

Here the example code:

from PySide6 import QtWidgets


class TestWidget(QtWidgets.QWidget):

    def __init__(self):
        super(TestWidget, self).__init__()
        self.setLayout(QtWidgets.QVBoxLayout())
        self.layout().addWidget(QtWidgets.QLabel(self.tr("Hello World!")))

AFAIK, Qt stubs are bundled with the library. Is there any reason why only this particular method isn't working? Why I would need to manually add stubs for a single method, while the entirety of the package is correctly type checked (note, for example, that self.setLayout and self.layout() are correctly typechecked)? This leads me to think something is wrong in the way I'm using QTranslator, and not with the library itself.

I tried to manually implement self.tr() this way:

from PySide6 import QtWidgets, QtCore


class TestWidget(QtWidgets.QWidget):

    def __init__(self):
        super(TestWidget, self).__init__()
        self.setLayout(QtWidgets.QVBoxLayout())
        self.layout().addWidget(QtWidgets.QLabel(self.tr("Hello World!")))

    def tr(self, text: str) -> str:
        return QtCore.QCoreApplication.translate("TestWidget", text)

This makes Pylance happy and the application still works. However, it's rather weird that I need to manually implement this method, while the documentation itself uses them (and if I just download that example, same errors show up).

Someone can help me understand what's going on?


Solution

  • As pointed out by @musicamante in replies, QObject.tr() is a C++ static method for QObjects, and the docs says explicitly:

    Unfortunately, because of the way Qt implements tr() it is not possible for PyQt6 to exactly reproduce its behaviour. [...] The PyQt6 behaviour is unsatisfactory and may be changed in the future. It is recommended that translate() be used in preference to tr(). This is guaranteed to work with current and future versions of PyQt6 and makes it much easier to share message files between Python and C++ code.

    Therefore, the implementation I wrote maybe is the way to go, using QtCore.QCoreApplication.translate() and, if wanted, manually implementing self.tr() for your classes.

    Here the example from the link above:

    from PySide6 import QtCore
    class A(QtCore.QObject):
        def hello(self):
            return QtCore.QCoreApplication.translate('A', "Hello")
    
    a = A()
    a.hello() # Correctly translated