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

Overlapping overload of __get__ method #1719

Closed
ermishechkin opened this issue Apr 3, 2021 · 2 comments
Closed

Overlapping overload of __get__ method #1719

ermishechkin opened this issue Apr 3, 2021 · 2 comments
Labels
addressed in next version Issue is fixed and will appear in next published version enhancement request New feature or request

Comments

@ermishechkin
Copy link

Describe the bug
I am trying to annotate a class that acts as a property when used with a specific container class and as a regular object elsewhere. According to python/typing#253 (comment) it is allowed to specify different return types, even for overlapping overloads. But pyright emits Overload 2 for "__get__" overlaps overload 3 and returns an incompatible type error for the following code (since 1.1.118).

There is also another error (since 1.1.117) that can be a duplicate of #1718:

Overloaded function implementation is not consistent with signature of overload 1
  Type "(self: Descriptor, owner: Any | None, inst: Type[Any]) -> (Descriptor | int)" cannot be assigned to type "(self: Descriptor, owner: None, inst: Type[Any]) -> Descriptor"
    Parameter 3: type "Type[Any]" cannot be assigned to type "Type[Any]"PylancereportGeneralTypeIssues

Screenshots or Code

from __future__ import annotations
from typing import Any, Literal, Optional, Type, TypeVar, Union, overload

TContainer = TypeVar('TContainer')

class Descriptor:
    @overload
    def __get__(self, owner: Literal[None], inst: Type[Any]) -> Descriptor:
        ...

    @overload
    def __get__(self, owner: Container, inst: Type[Container]) -> int:
        ...

    @overload
    def __get__(self, owner: TContainer, inst: Type[TContainer]) -> Descriptor:
        ...

    def __get__(self, owner: Optional[Any],
                inst: Type[Any]) -> Union[Descriptor, int]:
        if isinstance(owner, Container):
            return 7  # some special case
        return self


class Container:
    field = Descriptor()


class UnknownContainer:
    field = Descriptor()


reveal_type(Container.field)            # Type is "Descriptor"
reveal_type(Container().field)          # Type is "int"
reveal_type(UnknownContainer.field)     # Type is "Descriptor"
reveal_type(UnknownContainer().field)   # Type is "Descriptor"

VS Code extension or command-line
pyright 1.1.127

@erictraut
Copy link
Collaborator

It is odd that the __get__ method would be exempt from this check. The mypy documentation that you referenced doesn't provide any explanation for why this is the case. But in the interest of following precedent, I'll add the same special case in pyright. This change will be included in the next release.

@erictraut erictraut added addressed in next version Issue is fixed and will appear in next published version enhancement request New feature or request labels Apr 3, 2021
@erictraut
Copy link
Collaborator

This fix is included in pyright 1.1.128, which I just published. It will also be included in the next release of pylance.

heejaechang added a commit to heejaechang/pyright that referenced this issue Nov 3, 2021
* changelog for 2021.8.0

* added more thing in change log

* added single file mode in notable changes

* mention typeshed update in notable section

* updated NOTICE.txt

* change version to 8.0

* add url for huggingface fix

* PR feedbacks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
addressed in next version Issue is fixed and will appear in next published version enhancement request New feature or request
Projects
None yet
Development

No branches or pull requests

2 participants