Skip to content

Descriptor changing its class return type when object sets something to it #2698

Closed

Description

Considering this self-contained example:

from typing import TypeVar, overload

_S = TypeVar("_S", bound="Descriptor")
_M = TypeVar("_M", bound="Model")


class Descriptor:
    @overload
    def __get__(self: _S, obj: None, objtype: type[_M]) -> _S:
        ...

    @overload
    def __get__(self, obj: _M, objtype: type[_M]) -> str:
        ...

    def __set__(self, obj, value: str):
        ...


class Model:
    foo = Descriptor()
    foo2 = Descriptor()

    def some_method_that_sets_foo2(self):
        self.foo2 = "abc"


reveal_type(Model.foo)
reveal_type(Model.foo2)

Running pyright gives the following

> pyright foobar.py 
No configuration file found.
No pyproject.toml file found.
stubPath /tmp/typings is not a valid directory.
Assuming Python platform Linux
Searching for source files
Found 1 source file
/tmp/foobar.py
  /tmp/foobar.py:28:13 - info: Type of "Model.foo" is "Descriptor"
  /tmp/foobar.py:29:13 - info: Type of "Model.foo2" is "Descriptor | str"
1 error, 0 warnings, 4 infos 
Completed in 0.558sec

The fact that there exists a method that sets foo2 makes the typing for the descriptor being retrieved from the class to consider that now he can return that too, which is wrong since I'm setting it through object and not class. Also, setting it by class (i.e. Model.foo = <something else> would change it to something else and not call __set__).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Assignees

No one assigned

    Labels

    as designedNot a bug, working as intended

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions