Coder Social home page Coder Social logo

pyqt5-stubs's Introduction

mypy logo

PyPI version mypy checked Build Status Downloads Downloads

Mypy stubs for the PyQt5 framework

This repository holds the stubs of the PyQt5 framework. The stub files released within the PyQt5 packages have been modified to allow using them for type-checking via mypy. Improvements over the default stubs include:

  • Signals are properly typed as signals and not as methods
  • QFlags derived classes correctly support all combination operations
  • Many methods accepting an optional None have been annotated so
  • and more...

This repository can always be improved and the authors will appreciate any PRs or Issues that help making this stub-repository more reliable.

Installation

Simply install PyQt5-stubs with pip:

$ pip install PyQt5-stubs

Or clone the latest version from Github and install it via Python setuptools:

$ git clone https://github.com/python-qt-tools/PyQt5-stubs
$ python setup.py install

Supported Modules

The modules supported by PyQt5-stubs include modules from the PyQt5 package as well as modules from the other packages released by Riverbank Computing (PyQt3D, PyQtCharts, ...). Here is the full list of packages and modules:

  • package PyQt5:
    • QtBluetooth
    • QtCore
    • QtDBus
    • QtGui
    • QtLocation
    • QtMultimedia
    • QtNetwork
    • QtNfc
    • QtOpenGL
    • QtPositioning
    • QtPrintSupport
    • QtQml
    • QtQuick
    • QtQuickWidgets
    • QtRemoteObjects
    • QtSensors
    • QtSerialPort
    • QtSql
    • QtSvg
    • QtTest
    • QtWebChannel
    • QtWebSockets
    • QtWidgets
    • QtX11Extras
    • QtXml
    • QtXmlPatterns
    • sip
  • package PyQt3D:
    • Qt3DAnimation
    • Qt3DCore
    • Qt3DExtras
    • Qt3DInput
    • Qt3DLogic
    • Qt3DRender
  • package PyQtChart:
    • QtChart
  • package PyQtDataVisualization:
    • QtDataVisualization
  • package PyQtNetworkAuth:
    • QtNetworkAuth
  • package PyQtPurchasing:
    • QtPurchasing
  • package PyQtWebEngine:
    • QtWebEngine
    • QtWebEngineCore
    • QtWebEngineWidgets
  • package PyQtWebkit:
    • QtWebKit
    • QtWebKitWidgets

Authors

  • Stefan Lehmann
  • Kyle Altendorf
  • Bryce Beagle
  • Florian Bruhin
  • Philippe Fremy

pyqt5-stubs's People

Contributors

altendky avatar bluebird75 avatar brycebeagle avatar dependabot[bot] avatar djedouas avatar hexchain avatar karlch avatar kmolyuan avatar mkrieger1 avatar pfremy avatar powersnail avatar sanjacob avatar stlehmann avatar the-compiler avatar tilmank avatar welps avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar

pyqt5-stubs's Issues

Support PyQt5-commercial

As a PyQt5 licensee, the package we install is called PyQt5-commercial. This creates a bit of trouble installing this package as it depends on PyQt5; the non-commercial (but otherwise identical) variant of PyQt.

Is it feasible to simply drop PyQt5 from install_requires, or could we choose between commercial/GPL versions using extras_require?

Support signal parameter/argument types

So I don't know that this pans out but here's a very preliminary proof of concept that my initial thoughts were wrong and this is at least vaguely possible without a mypy plugin. It doesn't deal with the variadic nature of signal parameters nor does it make any attempt at #9. Anyways, I just wrote it up out of curiosity so figured I'd share it here. Though it may still require a mypy plugin to actually get it working right. Oh yeah, also doesn't cover connecting to a proper 'slot'.

Based on the signal classes in #56.

https://mypy-play.net/?mypy=latest&python=3.8&flags=strict&gist=fb8771c87a891edcfa30d522ae588638

import typing


TA = typing.TypeVar("TA")
TB = typing.TypeVar("TB")


class pyqtBoundSignal(typing.Generic[TA, TB]):
    signal: str = ""

    def emit(self, a: TA, b: TB) -> None: ...


class pyqtSignal(typing.Generic[TA, TB]):
    def __init__(self, a: typing.Type[TA], b: typing.Type[TB], *, name: str = ...) -> None: ...

    @typing.overload
    def __get__(self, instance: None, owner: object) -> "pyqtSignal": ...
    @typing.overload
    def __get__(self, instance: object, owner: object) -> pyqtBoundSignal[TA, TB]: ...
    
    def __get__(self, instance, owner):
        # mypy-play doesn't seem to offer a 'stub' option
        pass


class D:
    signal = pyqtSignal(int, str)


d = D()
d.signal.emit(1, "s")
d.signal.emit(1, 2)
main.py:33: error: Argument 2 to "emit" of "pyqtBoundSignal" has incompatible type "int"; expected "str"
Found 1 error in 1 file (checked 1 source file)

Widen PyQt5 dependency to 5.*

I understand that it is quite cumbersome to track all the releases (major and minor) of PyQt5 and keep this stub package up-to-date from a pip dependency point of view.

However, if you think about it :

  • all versions of PyQt5 and Qt5 are backward compatible.
  • so, a stub file valid for PyQt 5.13 will also be useful and valid for 5.12 . Maybe there are a few extra methods but that's a small issue
  • also, a stub file valid for PyQt 5.13 is certainly useful and valid for PyQt 5.14 and 5.15 . Same story, a few new methods or objects could be missing but that's about 0.01% of the codebase.

So my suggestion : declare PyQt5 5.* as a dependency.

This means that basically every user of PyQt5 can take advnatage of the stubs, whatever the version he is using. It means more potential contributors !

Plans for PyQt6?

PyQt6 snapshots just came out. Currently they're nothing more than PyQt5 with some deprecated features removed. But it begs the question: will PyQt5-stubs support PyQt6?

PyQt5 wheels will be shipped with stubs in the future

According to the PyQt mailinglist, the next PyQt release will ship wheels with its own stubs:

https://www.riverbankcomputing.com/pipermail/pyqt/2020-April/042854.html

My first thought was "hey, cool, so we don't need to build anything to get the stubs files!" (cc @BryceBeagle)... However, my second thought was "wait a minute... what will happen when people have both PyQt5 and PyQt5-stubs installed"? No idea which of the two will take precedence then, even after reading the relevant part of the PEP I don't understand what precedence stubs as part of the installed package (i.e. not inline types) have...

Missing attribute not detected and inheritance not followed ?

Hi,

Maybe this is not the right place to ask, if so thanks to redirect me...

Code:

from PyQt5.QtWidgets import QDialog
from PyQt5.QtCore import QObject

a = QDialog()
b = a.result()  # ok inferred type int
c = a.qsdf()  # should be error missing method but inferred type is any
d = a.isWidgetType()  # method of QObject, parent class of QDialog, a bool should be inferred but inferred tye is any

e = QObject()
f = e.isWidgetType()  # ok inferred type bool

class G:
    def yo(self) -> str:
        return "yo"

class H(G):
    pass

i = H()
j = i.yo()  # ok inferred type str
k = i.qsdf()  # ok error no attribute

reveal_locals()

mypy output is:

27:5: error: "H" has no attribute "qsdf"
29:1: note: Revealed local types are:
29:1: note:     a: PyQt5.QtWidgets.QDialog
29:1: note:     b: builtins.int
29:1: note:     c: Any
29:1: note:     d: Any
29:1: note:     e: PyQt5.QtCore.QObject
29:1: note:     f: builtins.bool
29:1: note:     i: test_module.H
29:1: note:     j: builtins.str
29:1: note:     k: Any

The question is: why does mypy does not detect these errors with PyQt objects?

I am using version 5.11.3.0 of PyQt5-stubs

Thanks

Upstream branch workflow now

Now that upstream has been properly merged into master, what's the workflow for dealing with the non-stub files in the master branch? If I want to update the README, would we change it in master and cherrypick into upstream? The otherway around?

I don't have much experience dealing with two parallel branches like this.

conda distribution

Would be nice if this package was available in a conda/anaconda distribution, preferably from the conda-forge channel.

Dealing with upstream PyQt upgrades

Hey! I wanted to start a project like this for a while (whoa, it's been two years already?!) but never got around to it. Now, as part of an university project I wanted to introduce mypy to qutebrowser and found this project.

This seems like a great start at making those stubs actually usable with mypy - thanks a lot for that!

I'll probably start contributing some pull requests over the next couple of days, for some issues I've seen when running mypy over qutebrowser.

I'm also wondering: What version of PyQt are those stubs based on? How do you intend to upgrade to newer versions? Maybe it'd be worthwhile to introduce an upstream branch with PyQt's files commited 1:1 for every PyQt release, and then those commits with the PyQt update can be cherry-picked to master in order to update the modified bindings?

Consider using pytest-mypy-plugins

Hi! Thanks for this awesome project!

I am TypedDjango team member, we maintain types for, well, django. And we do pretty much the same job.

For example, we also test our types the similar way as you do in tests/. We even created a tool called pytest-mypy-plugins (announcing post) to help us with this task. Maybe it will be also helpful to you as well.

That's how the simplest test looks like:

- case: compose_two_wrong_functions
  main: |
    from returns.functions import compose

    def first(num: int) -> float:
        return float(num)

    def second(num: float) -> str:
        return str(num)

    reveal_type(compose(first, second)(1))  # N: builtins.str*

Ask any questions you have!

P.S. This project was listed in awesome-python-stubs list.

Make a release? (after 5.15.2?)

It seems like it might be a reasonable idea to make a release. There are plenty of bits to still work on but there have been a lot of changes. Maybe after #113 makes it across with 5.15.2? I'm not presently doing anything where I need this but if nothing else it gives us a chance to figure out how releases have been happening. Any thoughts @stlehmann?

Problem with Qt methods that return pointers

I just stumbled over an issue, that I was well aware of, but that wasn't reported by MyPy since it's incorrectly annotated in the stubs. Nevertheless, I think this is more of a stub-wide problem. Here's a minimal example:


from PyQt5.QtWidgets import QTableWidget, QApplication

app = QApplication(sys.argv)

# create a QTableWidget with one row and one column
table_widget = QTableWidget()
table_widget.setRowCount(1)
table_widget.setColumnCount(1)

# Get the item in Cell(0,0)
item = table_widget.item(0, 0)

# will print: None
print(str(item))

sys.exit(app.exec())

QTableWidget.item() returns a QTableWidgetItem per annotation. Nevertheless, the C++ method returns a pointer which can (and is in the shown example) a null pointer or None in Python.

How can we take care of this? In QTableWidget alone there are about ten methods that return a pointer. Shouldn't every single one of them have an Optional around their return type? My C++ days are long gone, so I'm not sure: can all of those methods return a null pointer?

Deprecate the docker build process

Hi,

Now that the PyQt5 stubs are released as part of PyQt5 pypi package, do we really need to keep this build process in place ?

A few facts :

  • the build process is not documented. For somebody not familiar with docker, it might be difficult to grab. Adding a proper section in doc/developer_guide.md would be a very good idea
  • last time I checked, the pyi coming from the stubs are really the same as the one generated from the build process. I'll double-check that point though.
  • this build process is linux centric and fails to capture the specifics of the pyi for each platform. This won't be addressed in this issue directly but downloading the pyi from the different platforms allows us to capture the specifics of each platform

@The-Compiler shared in an email that PyQtWebkit pyi generation depends on the Docker file for its stubs generation. However, the Docker file does not contain anything related to PyQtWebkit and PyQt5 does not ship QtWebkit modules.

So, I am under the impression that the Docker file can be removed because pyi provides the same services.

For QtWebkit, if it's not shipped with PyQt5, it might be a good idea to create a dedicated stub project file on pypi (PyQtWebkit-stubs) else people are unlikely to find the corresponding stubs.

QMessageBox expects "StandardButtons" and fails

This code seems to fail with the stubs:

QMessageBox.question(self, "Confirm", "Are you sure?", QMessageBox.Yes | QMessageBox.No)

Tells me:

Argument 4 to "question" of "QMessageBox" has incompatible type "int"; expected "Union[StandardButtons, StandardButton]"

But the code should work, should it not?

Incomplete typing for QGraphicsItem.itemChange() ?

I wanted to clarify things before submitting a PR.

The current implementation in the stubs for QGraphicsItem.itemChange is as follows:
def itemChange(self, change: 'QGraphicsItem.GraphicsItemChange', value: typing.Any) -> typing.Any: ...

The Qt documentation defines type of value and the return value as QVariant:
https://doc.qt.io/qt-5/qgraphicsitem.html#itemChange

How are you handling QVariants in your code? I know that the usage of QVariant is a little strange (i.e. when putting a str into a QVariant, this returns a str).

PyQt dependency

It appears that this package depends on PyQt itself. Normally this would not be a problem, but when I pip install this package into a conda environment that already has PyQt5 (5.12.3), it does not recognize that distribution and starts to download it again from pypi.

I can install using --no-deps but it would be nicer if there was no explicit package dependency.

Handling of operation on WindowType and WindowFlags

Hi,

Thanks for the great work on PyQt5 stubs, it is a pleasure to use it.

In my code, I often disable the annoying help button of the window bar with the following code
dialog.setWindowFlags(dialog.windowFlags() & ~Qt.WindowContextHelpButtonHint)

Mypy fails on it with :
src\mg_dialog_run_git_cmd.py:29: error: Unsupported operand types for & ("WindowFlags" and "int")

I am trying to enhance type checking for this case. There are actually two issues :

  • Qt.WindowType (the class of Qt.WindowContextHelpButtonHint) is not typechecked for the operator ~
  • Qt.WindowFlags (the class of dialog.windowFlags()) is not typechecked for the operator &

I have "implemented" the solution by annotating additional operations for both types. Is it something worth adding to the official stubs ?

QApplication.instance() should return undocumented QApplication() instead of QCoreApplication

Hi,

According to Qt documentation QApplication.instance() is an inherited static method from QCoreApplication.instance() which returns a QCoreApplication.

However, in practice, it does return a QApplication wrapped object . But using QApplication specific methods (like palette() in my case) generates a typing error because this is not a QCoreApplication method.

If you agree with the issue, I'll submit a PR to fix it.

Example code to show the problem :

Python 3.8.8 (tags/v3.8.8:024d805, Feb 19 2021, 13:08:11) [MSC v.1928 32 bit (Intel)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> from PyQt5.QtWidgets import QApplication
>>> app = QApplication([])
>>> QApplication.instance()
<PyQt5.QtWidgets.QApplication object at 0x014DD3D0>

Release more often

Right now when I install mypy it shows me about 400 errors with my project, when I install the newest stable pip package it shows around 200 errors, when I use the newest master it shows around 50 errors. After merging #162 this is going change again. Currently I can't make mypy a part of my CI pipeline because the packages are simply too old. This also discourages me from contributing to the project knowing that it will take a few months until a potential fix lands on pypi.

Lock master and upstream branches

Do we have the master branch locked down? I like it to be locked both to avoid accidents and force PRs so there is review. Depending on the release workflow there can be conflicts, but... Opinions? Once we get CI passing we can require it to pass for merges as well. Oh, probably both master and upstream in the case of this repo.

Automated PyPI releases

It would be nice if we could automate releases to PyPI whenever master is committed to. Right now the PyPI release has not been updated since May and is still on 5.14.2.

Flags class should annotate __or__() function

When I write something like

file.open(QtCore.QFile.ReadOnly | QtCore.QFile.Text)

It just gives me a warning Unexpected type: int.

Flags like QIODevice.OpenModeFlag can be or-ed together. So I suggest annotating the __or__() function to suppress this warning.

According to the Qt documentation:
"The OpenMode type is a typedef for QFlags<OpenModeFlag>. It stores an OR combination of OpenModeFlag values."
We should annotate OpenModeFlag like this:

class QIODevice(QObject):
    class OpenModeFlag(int):
        def __or__(self, other: typing.Union['QIODevice.OpenModeFlag', 'QIODevice.OpenMode']) -> 'QIODevice.OpenMode': ...

And this should be done for OpenMode too.

class QIODevice(QObject):
    ...
    class OpenMode(sip.simplewrapper):
        ...
        def __or__(self, other: typing.Union['QIODevice.OpenModeFlag','QIODevice.OpenMode']) -> 'QIODevice.OpenMode': ...

Generate more modules?

PyQt5 has almost all the qt modules.
but PyQt5-stubs has just only 10 modules, which makes ide hint worse.

Can we genearte pyi for every module?

`QMessageBox.StandardButtons.__init__` issues

https://github.com/stlehmann/PyQt5-stubs/blob/a3b2eeba10cbd9db4a2840a3b2a53c15d31039c2/PyQt5-stubs/QtWidgets.pyi#L6575-L6580

There are a couple issues with the QMessageBox.StandardButtons constructor annotations.

Firstly, the second and third annotations are redundant; other than the args names, which I presume are both auto-generated and inaccurate. Neither are valid kwargs.

Secondly, it can also be constructed using int objects. As QMessageBox.StandardButton extends int, this annotation should just be replaced with using int objects.

>>> QtWidgets.QMessageBox.StandardButtons(0)
<PyQt5.QtWidgets.QMessageBox.StandardButtons object at 0x7f56c949dd60>

Concerning overridden methods. Example: the layout-method for QWidget when using QGridLayout

Since QWidget.layout() is type-hinted as QLayout, the returned layout object from the call if using QGridLayout and further use, e.g. by calling layout.addWidget(w, row, column), will produce an Unexpected Argument-error in IDEs such as PyCharm for the row and column parameters as these are not defined in QLayout.addWidget-method.

Minimum code example

from PyQt5.Qt import QWidget
from PyQt5.Qt import QGridLayout

class ExampleWidget(QWidget):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        
        layout = QGridLayout()
        self.setLayout(layout)

    def setup_some_child_widget(self):
        child = QWidget()
        layout = self.layout()
        row, column = 0, 0
        layout.addWidget(child, row, column)

    # def layout(self) -> QGridLayout:
    #     return super().layout()

Is this possible to solve in a satisfying way?

Currently I avoid cluttering the interface with semi-errors from PyCharms code inspections by simply subclassing QWidget to some MyWidget-class and overriding the QWidget.layout-method and type-hinting it to QGridLayout. However, this does not solve the core of the type hint issue and only push it to the level below, i.e. thesuper().layout()-call in such override.

Split Files

Is it possible to split the modules into more file? It's really hard to contribute and look into the file and it really takes a toll on PyCharm when I open the QtWidgets module and it can't offer proper checking anymore.

stubs 5.13 is incompatible with pyqt5 5.14.1

Hi, Guys

Hope you are very well.
I setup PYQT5 and then PYCHARM recomend me to setup pyqt5-stubs.
I think it was a good way for me. So setup automaticlly from pycharm
Then I open pycharm again, below picture show at pycharm top.

Could you please reply me the solution?
Maybe the different version, I guess:) Looking forward your update
error

QCoreApplication aboutToQuit not defined as signal

First of all thanks a bunch for your work on this!

When connecting to the aboutToQuit signal in QCoreApplication mypy complains with:

"Callable[[], None]" has no attribute "connect"

I suspect this is because it is simply defined as a function in the stub, not as a signal. Is there any reason for this or could this be changed?

Enumerations should inherit from enum.IntEnum not int

https://github.com/stlehmann/PyQt5-stubs/blob/811462b34ee151b898289ae8f1de8af30c690c55/PyQt5-stubs/QtBluetooth.pyi#L158-L160

Python 3.8.5 (default, Jul 29 2020, 21:06:26) 
[GCC 9.3.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> from PyQt5 import QtWidgets
>>> application = QtWidgets.QApplication([])
>>> from PyQt5 import QtBluetooth
>>> QtBluetooth.QBluetoothDeviceInfo.Field.__mro__
(<enum 'Field'>, <enum 'IntEnum'>, <class 'int'>, <enum 'Enum'>, <class 'object'>)

I presume this applies to many/most/all.

Add stubs for uic

Steps

Install PyQt5 package and type the import statement:
from PyQt5 import QtGui, uic
PyCharm will offer to install PyQt5-stubs. Agree.
Actual - uic submodule is marked as unresolved. The code runs.

Reported to JetBrains, and listed as an issue:
https://youtrack.jetbrains.com/issue/PY-47685

Handling self.parent()

I often use self.parent() knowing that the parent is of some specific type which has more logic than a simple QObject. In these cases mypy rightfully complains like so:

error: "QObject" has no attribute "width"  [attr-defined]

but of course in this case the parent is some type of QWidget which does have a width.

Solutions I thought of are:

  • Overriding parent in the child class just for the sake of type hinting with a cast
  • Explicitly keeping the parent as an attribute in the child

Both seem a bit redundant to me. Just adding # type: ignore to all of these calls is also somewhat sub-optimal.

Do you have any recommendations?

Thanks in advance and thanks once again for all the work you have done here!

Package looking for a new maintainer

I have created the PyQt5-stubs to add proper type annotations mainly for my personal PyQt5 applications without thinking much about a future-proof update strategy. It turns out that it is very cumbersome to take care of any version changes and keep the whole thing up-to-date with the upstream PyQt5 repository. Additionally I find myself using PySide2 more and more. PySide2 provides proper type annotations out of the box and has a more open licensing model. Because of this I decided to stop maintaining this package in the future. However, I would love to find a new maintainer that keeps this package alive. So if someone likes to take care of this package please contact me.

version 5.15.2.0 in pycharm didn't wok.

after I upgrade to pyqt5-stubs version 5.15.2.0, the XXX.clickked.XXX 's autocompletion in pycharm(2021.1) didn"t work.But in Vscode(with pylance) it works well.Then i downgrade to pyqt5-stubds version 5.14.2.2 ,the XXX.clickked.XXX 's autocompletion in pycharm(2021.1) starts working.

Does this repository have the correct license?

PyQt is licensed under the GPL (unless you have a commercial license).

Would the generated stubs not need to be distributed under the same license? I'm not sure the MIT license is valid to distribute them.

Connecting to a slot that returns something.

Mypy complains when connecting any signal to a slot, that would actually return something other than None/void.

A good example is QWidget.close() which returns a bool. When connecting a signal to this slot, mypy complains:

Argument 1 to "connect" of "pyqtSignal" has incompatible type "Callable[[], bool]"; expected "Union[Callable[..., None], pyqtBoundSignal]"

I guess return value should accept Callable[[], Any], no?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.