diff --git a/crates/ty_python_semantic/resources/mdtest/attributes.md b/crates/ty_python_semantic/resources/mdtest/attributes.md index 40a1841c67..e04c00f729 100644 --- a/crates/ty_python_semantic/resources/mdtest/attributes.md +++ b/crates/ty_python_semantic/resources/mdtest/attributes.md @@ -777,6 +777,30 @@ reveal_type(C.variable_with_class_default1) # revealed: str reveal_type(c_instance.variable_with_class_default1) # revealed: str ``` +#### Descriptor attributes as class variables + +Whether they are explicitly qualified as `ClassVar`, or just have a class level default, we treat +descriptor attributes as class variables. This test mainly makes sure that we do *not* treat them as +instance variables. This would lead to a different outcome, since the `__get__` method would not be +called (the descriptor protocol is not invoked for instance variables). + +```py +from typing import ClassVar + +class Descriptor: + def __get__(self, instance, owner) -> int: + return 42 + +class C: + a: ClassVar[Descriptor] + b: Descriptor = Descriptor() + c: ClassVar[Descriptor] = Descriptor() + +reveal_type(C().a) # revealed: int +reveal_type(C().b) # revealed: int +reveal_type(C().c) # revealed: int +``` + ### Inheritance of class/instance attributes #### Instance variable defined in a base class diff --git a/crates/ty_python_semantic/src/types/class.rs b/crates/ty_python_semantic/src/types/class.rs index da9ca6af97..4278fe0def 100644 --- a/crates/ty_python_semantic/src/types/class.rs +++ b/crates/ty_python_semantic/src/types/class.rs @@ -1738,9 +1738,15 @@ impl<'db> ClassLiteral<'db> { let declared_and_qualifiers = symbol_from_declarations(db, declarations); match declared_and_qualifiers { Ok(SymbolAndQualifiers { - symbol: declared @ Symbol::Type(declared_ty, declaredness), + symbol: mut declared @ Symbol::Type(declared_ty, declaredness), qualifiers, }) => { + // For the purpose of finding instance attributes, ignore `ClassVar` + // declarations: + if qualifiers.contains(TypeQualifiers::CLASS_VAR) { + declared = Symbol::Unbound; + } + // The attribute is declared in the class body. let bindings = use_def.public_bindings(symbol_id);