Skip to content

Commit e236664

Browse files
authored
Fix descriptor access for dynamic base classes (#5458)
Fixes #5456
1 parent f47bc23 commit e236664

File tree

2 files changed

+38
-0
lines changed

2 files changed

+38
-0
lines changed

mypy/subtypes.py

+6
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,12 @@ def visit_deleted_type(self, left: DeletedType) -> bool:
141141

142142
def visit_instance(self, left: Instance) -> bool:
143143
if left.type.fallback_to_any:
144+
if isinstance(self.right, NoneTyp):
145+
# NOTE: `None` is a *non-subclassable* singleton, therefore no class
146+
# can by a subtype of it, even with an `Any` fallback.
147+
# This special case is needed to treat descriptors in classes with
148+
# dynamic base classes correctly, see #5456.
149+
return False
144150
return True
145151
right = self.right
146152
if isinstance(right, TupleType) and right.fallback.type.is_enum:

test-data/unit/check-classes.test

+32
Original file line numberDiff line numberDiff line change
@@ -4584,3 +4584,35 @@ reveal_type(x) # E: Revealed type is 'builtins.list[__main__.B*[Any]]'
45844584
A = B
45854585
[builtins fixtures/list.pyi]
45864586
[out]
4587+
4588+
[case testNoneAnyFallback]
4589+
from typing import Any
4590+
dynamic: Any
4591+
class C(dynamic): pass
4592+
x: None = C() # E: Incompatible types in assignment (expression has type "C", variable has type "None")
4593+
[out]
4594+
4595+
[case testNoneAnyFallbackDescriptor]
4596+
from typing import Any
4597+
from d import Descr
4598+
4599+
dynamic: Any
4600+
class C(dynamic):
4601+
id = Descr(int)
4602+
name = Descr(str)
4603+
4604+
c: C
4605+
reveal_type(c.id) # E: Revealed type is 'builtins.int*'
4606+
reveal_type(C.name) # E: Revealed type is 'd.Descr[builtins.str*]'
4607+
4608+
[file d.pyi]
4609+
from typing import Any, overload, Generic, TypeVar, Type
4610+
4611+
T = TypeVar('T')
4612+
class Descr(Generic[T]):
4613+
def __init__(self, tp: Type[T]) -> None: ...
4614+
@overload
4615+
def __get__(self, inst: None, owner: Any) -> Descr[T]: ...
4616+
@overload
4617+
def __get__(self, inst: object, owner: Any) -> T: ...
4618+
[out]

0 commit comments

Comments
 (0)