Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 11 additions & 1 deletion mypy/subtypes.py
Original file line number Diff line number Diff line change
Expand Up @@ -1457,14 +1457,24 @@ def get_member_flags(name: str, itype: Instance, class_obj: bool = False) -> set
flags = {IS_VAR}
if not v.is_final:
flags.add(IS_SETTABLE)
if v.is_classvar:
# TODO: define cleaner rules for class vs instance variables.
if v.is_classvar and not is_descriptor(v.type):
flags.add(IS_CLASSVAR)
if class_obj and v.is_inferred:
flags.add(IS_CLASSVAR)
return flags
return set()


def is_descriptor(typ: Type | None) -> bool:
typ = get_proper_type(typ)
if isinstance(typ, Instance):
return typ.type.get("__get__") is not None
if isinstance(typ, UnionType):
return all(is_descriptor(item) for item in typ.relevant_items())
return False


def find_node_type(
node: Var | FuncBase,
itype: Instance,
Expand Down
26 changes: 26 additions & 0 deletions test-data/unit/check-protocols.test
Original file line number Diff line number Diff line change
Expand Up @@ -4602,3 +4602,29 @@ def deco(fn: Callable[[], T]) -> Callable[[], list[T]]: ...
@deco
def defer() -> int: ...
[builtins fixtures/list.pyi]

[case testProtocolClassValDescriptor]
from typing import Any, Protocol, overload, ClassVar, Type

class Desc:
@overload
def __get__(self, instance: None, owner: Any) -> Desc: ...
@overload
def __get__(self, instance: object, owner: Any) -> int: ...
def __get__(self, instance, owner):
pass

class P(Protocol):
x: ClassVar[Desc]

class C:
x = Desc()

t: P = C()
reveal_type(t.x) # N: Revealed type is "builtins.int"
tt: Type[P] = C
reveal_type(tt.x) # N: Revealed type is "__main__.Desc"

bad: P = C # E: Incompatible types in assignment (expression has type "type[C]", variable has type "P") \
# N: Following member(s) of "C" have conflicts: \
# N: x: expected "int", got "Desc"