Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. Qt for Python
  4. PySide2 typing stubs are available

PySide2 typing stubs are available

Scheduled Pinned Locked Moved Qt for Python
3 Posts 1 Posters 821 Views
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • Bluebird75B Offline
    Bluebird75B Offline
    Bluebird75
    wrote on last edited by
    #1

    Hi,

    If you are into using type annotations for your python programs, you have certainly been disappointed by the typing stubs delivered by Qt. The official version fails to detect many errors and reports many errors for perfectly valid code.

    But things are changing: I have started a PySide2-stubs package. The first version is already available at pypi (https://pypi.org/project/PySide2-stubs/ ).

    The package provides updated typing information for all of PySide2. It fixes some very basic typing issues:

    • fix Signal with method emit()
    • fix qVersion() returning string, not bytes
    • fix QMessageBox.warning, information, critical, question, about, aboutQt to accept None as parent argument
    • fix QAction.setShortcut() to accept string as argument
    • fix QTreeWidgetItem comparison with <
    • fix QTimer.timeout undeclared signal
    • fix QLineEdit.setText() to accept None

    The current version is already useful but still has many wrong types declared (all QFlags are declared with a wrong type for example). I'll continue working on it until I get something reasonably usable.

    Don't hesitate to join the effort if you like typed python code.

    Have a nice day,

    Philippe

    1 Reply Last reply
    3
    • Bluebird75B Offline
      Bluebird75B Offline
      Bluebird75
      wrote on last edited by
      #2

      I have just uploaded a new version of the stubs. They are now quite good : they will help any project to correctly use the PySide2/Qt5 API and provide full static typing capabilities with mypy.

      Don't hesitate to try them at https://pypi.org/project/PySide2-stubs/

      Have a nice day,

      Philippe

      1 Reply Last reply
      0
      • Bluebird75B Offline
        Bluebird75B Offline
        Bluebird75
        wrote on last edited by
        #3

        Let's see an example in practice.

        See what happens if I run mypy on one of my PySide2 project without extra package:

        (.env-pyside) c:\work\Multigit\Dev>mypy .
        src\mg_const.py:88: error: On Python 3 formatting "b'abc'" with "%s" produces "b'abc'", not "abc"; use "%r" if this is desired behavior
        src\mg_config.py:108: error: No overload variant of "warning" of "QMessageBox" matches argument types "None", "str", "str"
        src\mg_config.py:108: note: Possible overload variants:
        src\mg_config.py:108: note:     def warning(parent: QWidget, title: str, text: str, button0: StandardButton, button1: StandardButton) -> int
        src\mg_config.py:108: note:     def warning(parent: QWidget, title: str, text: str, buttons: StandardButtons = ..., defaultButton: StandardButton = ...) -> StandardButton
        src\mg_config.py:117: error: No overload variant of "warning" of "QMessageBox" matches argument types "None", "str", "str"
        src\mg_config.py:117: note: Possible overload variants:
        src\mg_config.py:117: note:     def warning(parent: QWidget, title: str, text: str, button0: StandardButton, button1: StandardButton) -> int
        src\mg_config.py:117: note:     def warning(parent: QWidget, title: str, text: str, buttons: StandardButtons = ..., defaultButton: StandardButton = ...) -> StandardButton
        src\mg_config.py:129: error: No overload variant of "warning" of "QMessageBox" matches argument types "None", "str", "str"
        src\mg_config.py:129: note: Possible overload variants:
        src\mg_config.py:129: note:     def warning(parent: QWidget, title: str, text: str, button0: StandardButton, button1: StandardButton) -> int
        src\mg_config.py:129: note:     def warning(parent: QWidget, title: str, text: str, buttons: StandardButtons = ..., defaultButton: StandardButton = ...) -> StandardButton
        src\mg_button_history.py:59: error: "Signal" has no attribute "emit"
        idemia\gui\ui_gitflow_release_tag.py:12: error: Incompatible import of "Object" (imported name has type "Type[PySide2.QtGui.Object]", local name has type "Type[PySide2.QtCore.Object]")
        idemia\gui\ui_gitflow_release_tag.py:13: error: Incompatible import of "Object" (imported name has type "Type[PySide2.QtWidgets.Object]", local name has type "Type[PySide2.QtCore.Object]")
        idemia\gui\ui_gitflow_merge.py:12: error: Incompatible import of "Object" (imported name has type "Type[PySide2.QtGui.Object]", local name has type "Type[PySide2.QtCore.Object]")
        idemia\gui\ui_gitflow_merge.py:13: error: Incompatible import of "Object" (imported name has type "Type[PySide2.QtWidgets.Object]", local name has type "Type[PySide2.QtCore.Object]")
        [...]
        idemia\gui\ui_gitflow_init.py:12: error: Incompatible import of "Object" (imported name has type "Type[PySide2.QtGui.Object]", local name has type "Type[PySide2.QtCore.Object]")
        idemia\gui\ui_gitflow_init.py:13: error: Incompatible import of "Object" (imported name has type "Type[PySide2.QtWidgets.Object]", local name has type "Type[PySide2.QtCore.Object]")
        idemia\gui\ui_gitflow_init.py:114: error: Argument 1 to "translate" of "QCoreApplication" has incompatible type "str"; expected "bytes"
        [...]
        idemia\gui\ui_gitflow_init.py:124: error: Argument 1 to "translate" of "QCoreApplication" has incompatible type "str"; expected "bytes"
        idemia\gui\ui_gitflow_init.py:124: error: Argument 2 to "translate" of "QCoreApplication" has incompatible type "str"; expected "bytes"
        [...]
        idemia\gui\ui_gitflow_create_branch.py:12: error: Incompatible import of "Object" (imported name has type "Type[PySide2.QtGui.Object]", local name has type "Type[PySide2.QtCore.Object]")
        idemia\gui\ui_gitflow_create_branch.py:13: error: Incompatible import of "Object" (imported name has type "Type[PySide2.QtWidgets.Object]", local name has type "Type[PySide2.QtCore.Object]")
        idemia\gui\ui_gitflow_create_branch.py:236: error: Argument 1 to "translate" of "QCoreApplication" has incompatible type "str"; expected "bytes"
        idemia\gui\ui_gitflow_create_branch.py:236: error: Argument 2 to "translate" of "QCoreApplication" has incompatible type "str"; expected "bytes"[...]
        
        idemia\gui\ui_gitflow_advance_int_branch.py:12: error: Incompatible import of "Object" (imported name has type "Type[PySide2.QtGui.Object]", local name has type "Type[PySide2.QtCore.Object]")
        idemia\gui\ui_gitflow_advance_int_branch.py:13: error: Incompatible import of "Object" (imported name has type "Type[PySide2.QtWidgets.Object]", local name has type "Type[PySide2.QtCore.Object]")
        idemia\gui\ui_gitflow_advance_int_branch.py:169: error: Argument 1 to "translate" of "QCoreApplication" has incompatible type "str"; expected "bytes"
        idemia\gui\ui_gitflow_advance_int_branch.py:169: error: Argument 2 to "translate" of "QCoreApplication" has incompatible type "str"; expected "bytes"
        [...]
        src\mg_tools.py:408: error: "Signal" has no attribute "emit"
        src\mg_tools.py:502: error: No overload variant of "int" matches argument type "ExitStatus"
        src\mg_tools.py:502: note: Possible overload variants:
        src\mg_tools.py:502: note:     def int(cls, Union[str, bytes, SupportsInt, SupportsIndex, SupportsTrunc] = ...) -> int
        src\mg_tools.py:502: note:     def int(cls, Union[str, bytes], base: SupportsIndex) -> int
        src\mg_tools.py:541: error: No overload variant of "warning" of "QMessageBox" matches argument types "None", "str", "str"
        src\mg_tools.py:541: note: Possible overload variants:
        src\mg_tools.py:541: note:     def warning(parent: QWidget, title: str, text: str, button0: StandardButton, button1: StandardButton) -> int
        src\mg_tools.py:541: note:     def warning(parent: QWidget, title: str, text: str, buttons: StandardButtons = ..., defaultButton: StandardButton = ...) -> StandardButton
        src\mg_repo_info.py:144: error: "Signal" has no attribute "connect"
        src\mg_repo_info.py:327: error: "Signal" has no attribute "emit"
        src\mg_repo_info.py:374: error: "Signal" has no attribute "emit"
        src\mg_repo_info.py:507: error: No overload variant of "warning" of "QMessageBox" matches argument types "None", "str", "str"
        src\mg_repo_info.py:507: note: Possible overload variants:
        src\mg_repo_info.py:507: note:     def warning(parent: QWidget, title: str, text: str, button0: StandardButton, button1: StandardButton) -> int
        src\mg_repo_info.py:507: note:     def warning(parent: QWidget, title: str, text: str, buttons: StandardButtons = ..., defaultButton: StandardButton = ...) -> StandardButton
        src\mg_repo_info.py:535: error: No overload variant of "warning" of "QMessageBox" matches argument types "None", "str", "str"
        src\mg_repo_info.py:535: note: Possible overload variants:
        src\mg_repo_info.py:535: note:     def warning(parent: QWidget, title: str, text: str, button0: StandardButton, button1: StandardButton) -> int
        src\mg_repo_info.py:535: note:     def warning(parent: QWidget, title: str, text: str, buttons: StandardButtons = ..., defaultButton: StandardButton = ...) -> StandardButton
        src\mg_repo_info.py:629: error: No overload variant of "warning" of "QMessageBox" matches argument types "None", "str", "str"
        src\mg_repo_info.py:629: note: Possible overload variants:
        src\mg_repo_info.py:629: note:     def warning(parent: QWidget, title: str, text: str, button0: StandardButton, button1: StandardButton) -> int
        src\mg_repo_info.py:629: note:     def warning(parent: QWidget, title: str, text: str, buttons: StandardButtons = ..., defaultButton: StandardButton = ...) -> StandardButton
        src\mg_repo_info.py:666: error: "Signal" has no attribute "emit"
        src\mg_repo_info.py:680: error: No overload variant of "warning" of "QMessageBox" matches argument types "None", "str", "str"
        src\mg_repo_info.py:680: note: Possible overload variants:
        src\mg_repo_info.py:680: note:     def warning(parent: QWidget, title: str, text: str, button0: StandardButton, button1: StandardButton) -> int
        src\mg_repo_info.py:680: note:     def warning(parent: QWidget, title: str, text: str, buttons: StandardButtons = ..., defaultButton: StandardButton = ...) -> StandardButton
        src\mg_repo_info.py:869: error: No overload variant of "warning" of "QMessageBox" matches argument types "None", "str", "str"
        src\mg_repo_info.py:869: note: Possible overload variants:
        src\mg_repo_info.py:869: note:     def warning(parent: QWidget, title: str, text: str, button0: StandardButton, button1: StandardButton) -> int
        src\mg_repo_info.py:869: note:     def warning(parent: QWidget, title: str, text: str, buttons: StandardButtons = ..., defaultButton: StandardButton = ...) -> StandardButton
        src\mg_repo_info.py:985: error: No overload variant of "warning" of "QMessageBox" matches argument types "None", "str", "str"
        src\mg_repo_info.py:985: note: Possible overload variants:
        src\mg_repo_info.py:985: note:     def warning(parent: QWidget, title: str, text: str, button0: StandardButton, button1: StandardButton) -> int
        src\mg_repo_info.py:985: note:     def warning(parent: QWidget, title: str, text: str, buttons: StandardButtons = ..., defaultButton: StandardButton = ...) -> StandardButton
        src\mg_repo_info.py:1033: error: No overload variant of "warning" of "QMessageBox" matches argument
        types "None", "str", "str"
        src\mg_repo_info.py:1033: note: Possible overload variants:
        src\mg_repo_info.py:1033: note:     def warning(parent: QWidget, title: str, text: str, button0: StandardButton, button1: StandardButton) -> int
        src\mg_repo_info.py:1033: note:     def warning(parent: QWidget, title: str, text: str, buttons: StandardButtons = ..., defaultButton: StandardButton = ...) -> StandardButton
        src\mg_git_exec_window.py:116: error: "Signal" has no attribute "emit"
        src\mg_git_exec_window.py:188: error: "Signal" has no attribute "connect"
        src\mg_git_exec_window.py:392: error: "Signal" has no attribute "connect"
        src\mg_ensure_info_available.py:30: error: Argument 1 to "setCancelButton" of "QProgressDialog" has
        incompatible type "None"; expected "QPushButton"
        src\mg_ensure_info_available.py:68: error: "Signal" has no attribute "emit"
        src\mg_ensure_info_available.py:137: error: "Signal" has no attribute "emit"
        src\mg_repo_tree_item.py:39: error: "Signal" has no attribute "connect"
        src\mg_repo_tree_item.py:40: error: "Signal" has no attribute "connect"
        src\mg_repo_tree_item.py:41: error: "Signal" has no attribute "connect"
        src\mg_dialog_utils.py:149: error: "Signal" has no attribute "emit"
        src\mg_dialog_select_repo.py:160: error: Unused "type: ignore" comment
        src\mg_dialog_export_mgit.py:40: error: "Signal" has no attribute "connect"
        src\mg_dialog_git_switch_delete_branch.py:276: error: "Signal" has no attribute "connect"
        src\mg_dialog_git_revert.py:23: error: "Signal" has no attribute "connect"
        src\mg_dialog_clone_from_mgit.py:88: error: "Signal" has no attribute "connect"
        src\mg_dialog_clone_from_mgit.py:89: error: "Signal" has no attribute "connect"
        src\mg_dialog_clone_from_mgit.py:90: error: "Signal" has no attribute "connect"
        src\mg_dialog_clone_from_mgit.py:215: error: No overload variant of "warning" of "QMessageBox" matches argument types "None", "str", "str"
        src\mg_dialog_clone_from_mgit.py:215: note: Possible overload variants:
        src\mg_dialog_clone_from_mgit.py:215: note:     def warning(parent: QWidget, title: str, text: str,
        button0: StandardButton, button1: StandardButton) -> int
        src\mg_dialog_clone_from_mgit.py:215: note:     def warning(parent: QWidget, title: str, text: str,
        buttons: StandardButtons = ..., defaultButton: StandardButton = ...) -> StandardButton
        src\mg_dialog_clone_from_mgit.py:221: error: No overload variant of "warning" of "QMessageBox" matches argument types "None", "str", "str"
        src\mg_dialog_clone_from_mgit.py:221: note: Possible overload variants:
        src\mg_dialog_clone_from_mgit.py:221: note:     def warning(parent: QWidget, title: str, text: str,
        button0: StandardButton, button1: StandardButton) -> int
        src\mg_dialog_clone_from_mgit.py:221: note:     def warning(parent: QWidget, title: str, text: str,
        buttons: StandardButtons = ..., defaultButton: StandardButton = ...) -> StandardButton
        src\mg_dialog_clone_from_mgit.py:230: error: No overload variant of "warning" of "QMessageBox" matches argument types "None", "str", "str"
        src\mg_dialog_clone_from_mgit.py:230: note: Possible overload variants:
        src\mg_dialog_clone_from_mgit.py:230: note:     def warning(parent: QWidget, title: str, text: str,
        button0: StandardButton, button1: StandardButton) -> int
        src\mg_dialog_clone_from_mgit.py:230: note:     def warning(parent: QWidget, title: str, text: str,
        buttons: StandardButtons = ..., defaultButton: StandardButton = ...) -> StandardButton
        src\mg_dialog_clone_from_mgit.py:275: error: No overload variant of "warning" of "QMessageBox" matches argument types "None", "str", "str"
        src\mg_dialog_clone_from_mgit.py:275: note: Possible overload variants:
        src\mg_dialog_clone_from_mgit.py:275: note:     def warning(parent: QWidget, title: str, text: str,
        button0: StandardButton, button1: StandardButton) -> int
        src\mg_dialog_clone_from_mgit.py:275: note:     def warning(parent: QWidget, title: str, text: str,
        buttons: StandardButtons = ..., defaultButton: StandardButton = ...) -> StandardButton
        src\mg_dialog_clone_from_mgit.py:280: error: No overload variant of "warning" of "QMessageBox" matches argument types "None", "str", "str"
        src\mg_dialog_clone_from_mgit.py:280: note: Possible overload variants:
        src\mg_dialog_clone_from_mgit.py:280: note:     def warning(parent: QWidget, title: str, text: str,
        button0: StandardButton, button1: StandardButton) -> int
        src\mg_dialog_clone_from_mgit.py:280: note:     def warning(parent: QWidget, title: str, text: str,
        buttons: StandardButtons = ..., defaultButton: StandardButton = ...) -> StandardButton
        src\mg_dialog_apply_mgit_file.py:82: error: "Signal" has no attribute "connect"
        src\mg_dialog_apply_mgit_file.py:83: error: "Signal" has no attribute "connect"
        src\mg_dialog_apply_mgit_file.py:197: error: No overload variant of "warning" of "QMessageBox" matches argument types "None", "str", "str"
        src\mg_dialog_apply_mgit_file.py:197: note: Possible overload variants:
        src\mg_dialog_apply_mgit_file.py:197: note:     def warning(parent: QWidget, title: str, text: str,
        button0: StandardButton, button1: StandardButton) -> int
        src\mg_dialog_apply_mgit_file.py:197: note:     def warning(parent: QWidget, title: str, text: str,
        buttons: StandardButtons = ..., defaultButton: StandardButton = ...) -> StandardButton
        src\mg_dialog_apply_mgit_file.py:203: error: No overload variant of "warning" of "QMessageBox" matches argument types "None", "str", "str"
        src\mg_dialog_apply_mgit_file.py:203: note: Possible overload variants:
        src\mg_dialog_apply_mgit_file.py:203: note:     def warning(parent: QWidget, title: str, text: str,
        button0: StandardButton, button1: StandardButton) -> int
        src\mg_dialog_apply_mgit_file.py:203: note:     def warning(parent: QWidget, title: str, text: str,
        buttons: StandardButtons = ..., defaultButton: StandardButton = ...) -> StandardButton
        src\mg_dialog_apply_mgit_file.py:212: error: No overload variant of "warning" of "QMessageBox" matches argument types "None", "str", "str"
        src\mg_dialog_apply_mgit_file.py:212: note: Possible overload variants:
        src\mg_dialog_apply_mgit_file.py:212: note:     def warning(parent: QWidget, title: str, text: str,
        button0: StandardButton, button1: StandardButton) -> int
        src\mg_dialog_apply_mgit_file.py:212: note:     def warning(parent: QWidget, title: str, text: str,
        buttons: StandardButtons = ..., defaultButton: StandardButton = ...) -> StandardButton
        idemia\mg_dialog_gitflow_init.py:27: error: "Signal" has no attribute "connect"
        idemia\mg_dialog_gitflow_advance_int_branch.py:74: error: "Signal" has no attribute "connect"
        src\mg_repo_tree.py:140: error: Argument 1 to "setShortcut" of "QAction" has incompatible type "str"; expected "QKeySequence"
        [...]
        src\mg_repo_tree.py:321: error: Argument 1 to "setShortcut" of "QAction" has incompatible type "str"; expected "QKeySequence"
        src\mg_repo_tree.py:477: error: Unused "type: ignore" comment
        src\mg_repo_tree.py:665: error: "Signal" has no attribute "connect"
        src\mg_dialog_git_tag.py:19: error: Unused "type: ignore" comment
        src\mg_dialog_git_tag.py:23: error: Unused "type: ignore" comment
        src\mg_dialog_git_push_tag.py:19: error: Unused "type: ignore" comment
        src\mg_dialog_git_push_tag.py:22: error: Unused "type: ignore" comment
        src\mg_dialog_git_push_tag.py:23: error: "Signal" has no attribute "connect"
        src\mg_dialog_git_commit.py:17: error: Unused "type: ignore" comment
        src\mg_dialog_git_commit.py:21: error: Unused "type: ignore" comment
        src\mg_dialog_git_commit.py:24: error: "Signal" has no attribute "connect"
        src\mg_window.py:148: error: "Signal" has no attribute "connect"
        src\mg_window.py:558: error: No overload variant of "warning" of "QMessageBox" matches argument types "None", "str", "str"
        src\mg_window.py:558: note: Possible overload variants:
        src\mg_window.py:558: note:     def warning(parent: QWidget, title: str, text: str, button0: StandardButton, button1: StandardButton) -> int
        src\mg_window.py:558: note:     def warning(parent: QWidget, title: str, text: str, buttons: StandardButtons = ..., defaultButton: StandardButton = ...) -> StandardButton
        multigit.py:34: error: No overload variant of "critical" of "QMessageBox" matches argument types "None", "str", "str"
        multigit.py:34: note: Possible overload variants:
        multigit.py:34: note:     def critical(parent: QWidget, title: str, text: str, button0: StandardButton, button1: StandardButton) -> int
        multigit.py:34: note:     def critical(parent: QWidget, title: str, text: str, buttons: StandardButtons = ..., defaultButton: StandardButton = ...) -> StandardButton
        multigit.py:180: error: Unsupported operand types for + ("str" and "bytes")
        multigit.py:196: error: On Python 3 formatting "b'abc'" with "%s" produces "b'abc'", not "abc"; use
        "%r" if this is desired behavior
        Found 310 errors in 30 files (checked 72 source files)
        

        Tons of errors, eventhough my project is working fine. The default stubs are useless for mypy. Let's fix that.

        (.env-pyside) c:\work\Multigit\Dev>pip install pyside2-stubs
        Collecting pyside2-stubs
          Downloading PySide2_stubs-5.15.2.1.2-py3-none-any.whl (542 kB)
             |████████████████████████████████| 542 kB 819 kB/s
        Requirement already satisfied: mypy>=0.940 in c:\work\multigit\dev\.env-pyside\lib\site-packages (from pyside2-stubs) (0.940)
        Requirement already satisfied: PySide2>=5.11.0 in c:\work\multigit\dev\.env-pyside\lib\site-packages (from pyside2-stubs) (5.15.2.1)
        Requirement already satisfied: tomli>=1.1.0 in c:\work\multigit\dev\.env-pyside\lib\site-packages (from mypy>=0.940->pyside2-stubs) (2.0.1)
        Requirement already satisfied: mypy-extensions>=0.4.3 in c:\work\multigit\dev\.env-pyside\lib\site-packages (from mypy>=0.940->pyside2-stubs) (0.4.3)
        Requirement already satisfied: typing-extensions>=3.10 in c:\work\multigit\dev\.env-pyside\lib\site-packages (from mypy>=0.940->pyside2-stubs) (4.2.0)
        Requirement already satisfied: shiboken2==5.15.2.1 in c:\work\multigit\dev\.env-pyside\lib\site-packages (from PySide2>=5.11.0->pyside2-stubs) (5.15.2.1)
        Installing collected packages: pyside2-stubs
        Successfully installed pyside2-stubs-5.15.2.1.2
        WARNING: You are using pip version 21.1.1; however, version 22.2 is available.
        You should consider upgrading via the 'c:\work\multigit\dev\.env-pyside\scripts\python.exe -m pip install --upgrade pip' command.
        

        Installation is pretty straightforward.

        And now:

        (.env-pyside) c:\work\Multigit\Dev>mypy .
        src\mg_repo_tree.py:665: error: Argument 1 to "append" of "list" has incompatible type "bool"; expected "Connection"
        Found 1 error in 1 file (checked 72 source files)
        
        (.env-pyside) c:\work\Multigit\Dev>
        

        Only one error reported. Let's check that! The code looke like :

                self.menuCopyConnections = []    # type: List[QMetaObject.Connection]
        
                [...]
        
                self.menuCopyConnections.append(       
                         repoInfo.repo_info_available.connect(local_set_head) )
        
        

        First I am declaring the type of menuCopyConnections to be a list of QMetaObject.Connection items. Then I am filling the list with the result of a signal connection call. And mypy tell me that I am filling the list incorrectly with bool.

        After verification, this is a pyside2 incompabilitity with Qt5. The connect() call returns bool instead of Connection objects. So my code in this context is buggy, I will get an exception when I try to use the content of the list, assuming it is a Connection object while it is a bool.

        Mypy and the correct stubs have helped me to find a bug!

        Note: the bug has been reported and the Qt folks were already aware of it because in PySide6, connect() returns a Connection object like in Qt.

        1 Reply Last reply
        0

        • Login

        • Login or register to search.
        • First post
          Last post
        0
        • Categories
        • Recent
        • Tags
        • Popular
        • Users
        • Groups
        • Search
        • Get Qt Extensions
        • Unsolved