Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

pyqtProperty setter always raises an error #9911

Open
BoboTiG opened this issue Jan 14, 2021 · 3 comments
Open

pyqtProperty setter always raises an error #9911

BoboTiG opened this issue Jan 14, 2021 · 3 comments
Labels
bug mypy got something wrong topic-descriptors Properties, class vs. instance attributes

Comments

@BoboTiG
Copy link
Contributor

BoboTiG commented Jan 14, 2021

Bug Report

It seems that Mypy is not enjoying pyqtProperty setters. Someone already asked on the Qt mailing-list.

To Reproduce

from PyQt5.QtCore import QObject, pyqtProperty, pyqtSignal


class FeatureModel(QObject):

    stateChanged = pyqtSignal()

    def __init__(self, enabled: bool, /) -> None:
        super().__init__()
        self._enabled = enabled

    @pyqtProperty(bool, notify=stateChanged)
    def enabled(self):
        return self._enabled

    @enabled.setter
    def enabled(self, enabled):
        self._enabled = enabled
        self.stateChanged.emit()

Expected Behavior

Mypy should be happy.

Actual Behavior

$ python -m mypy file.py
file.py:16: error: Name 'enabled' already defined on line 12
Found 1 error in 1 file (checked 1 source file)

Your Environment

  • Mypy version used: 0.790
  • Mypy command-line flags: None
  • Mypy configuration options from mypy.ini (and other config files): None
  • Python version used: 3.8.6
  • Operating system and version: macOS Big Sur (arm64) and Windows 10.
@BoboTiG BoboTiG added the bug mypy got something wrong label Jan 14, 2021
@BoboTiG BoboTiG changed the title pyqtProperty setter always raise an error pyqtProperty setter always raises an error Jan 14, 2021
@freundTech
Copy link
Contributor

freundTech commented Jan 15, 2021

On the Qt mailing-list someone already posted these two links to the mypy source-code:
https://github.com/python/mypy/blob/v0.782/mypy/semanal.py#L964-L973
https://github.com/python/mypy/blob/v0.782/mypy/semanal.py#L842-L869

mypy has some special casing to make pythons @property (and a few other decorators) work.
The easy solution would probably be to add a special case for @pyqtProperty.
Cleaner solutions would be to either somehow make it possible to annotate that a decorator creates a property (This could be problematic, as I don't know if existing type annotations can handle this) or write a mypy plugin. I only took a quick look at the plugin interface and think it should be possible to do this. The problem here would be that the plugin API is unstable (See #6617).

EDIT:
Looks like writing a plugin for this isn't that easy after all. There is a "get_class_decorator_hook", but no corresponding hook for methods and functions. If such hooks would be added writing a plugin would be possible.

@gvanrossum
Copy link
Member

The way to do that without baking knowledge of qt into mypy is to write a mypy extension.

@freundTech
Copy link
Contributor

Should the plugin hook I suggested in #9915 get added to mypy you could solve this using the following mypy plugin (function and class names subject to change):

from typing import Callable, Optional
from typing import Type

from mypy.plugin import (
    Plugin, DecoratorContext,
)


def plugin(version: str) -> Type[Plugin]:
    return PyQt5Plugin


class PyQt5Plugin(Plugin):
    """PyQt5 Plugin"""

    def get_decorator_hook(self, fullname: str
                           ) -> Optional[Callable[[DecoratorContext], None]]:
        if fullname == 'PyQt5.QtCore.pyqtProperty':
            return pyqt_property_callback
        return None


def pyqt_property_callback(ctx: DecoratorContext):
    ctx.decorator.func.is_property = True

@AlexWaygood AlexWaygood added the topic-descriptors Properties, class vs. instance attributes label Apr 4, 2022
djhoese pushed a commit to ssec/sift that referenced this issue May 9, 2023
Get rid of

uwsift/control/qml_utils.py:87: error: Name "layerModel" already defined on line 83  [no-redef]
uwsift/control/qml_utils.py:96: error: Name "convFuncModel" already defined on line 92  [no-redef]
uwsift/control/qml_utils.py:132: error: Name "layerToDisplay" already defined on line 127  [no-redef]
uwsift/control/qml_utils.py:144: error: Name "dateToDisplay" already defined on line 137  [no-redef]
uwsift/control/qml_utils.py:221: error: Property "timestamps" defined in "TimebaseModel" is read-only  [misc]
uwsift/control/qml_utils.py:222: error: Cannot assign to a method  [assignment]
uwsift/control/qml_utils.py:222: error: Incompatible types in assignment (expression has type "None", variable has type "Callable[..., Any]")  [assignment]
uwsift/control/qml_utils.py:243: error: Name "currentTimestamp" already defined on line 239  [no-redef]
uwsift/control/qml_utils.py:261: error: Name "timestamps" already defined on line 248  [no-redef]
uwsift/control/qml_utils.py:261: error: "Callable[[TimebaseModel], Any]" has no attribute "setter"  [attr-defined]

by
- ignoring false positives for pyqtProperty setters, see
  python/mypy#9911
- Avoiding to initialize variable with None which can also be
  initialized with something more useful right away.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug mypy got something wrong topic-descriptors Properties, class vs. instance attributes
Projects
None yet
Development

No branches or pull requests

4 participants